Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- -------------------------------------------------------------------------------
- MSX Image to VRAM converter
- Genera desde una imagen las tablas de PATTERN, COLOR & NAME
- para usarlas en el modo SCREEN 2.
- (c)2015 by Cesar Rincon "NightFox"
- http://www.nightfoxandco.com
- Version 0.1 Alpha
- -------------------------------------------------------------------------------
- */
- /*
- -------------------------------------------------------------------------------
- Includes
- -------------------------------------------------------------------------------
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- /*
- -------------------------------------------------------------------------------
- Definicion de tipos
- -------------------------------------------------------------------------------
- */
- typedef signed char s8;
- typedef unsigned char u8;
- typedef signed short s16;
- typedef unsigned short u16;
- typedef signed int s32;
- typedef unsigned int u32;
- /*
- -------------------------------------------------------------------------------
- Variables globales
- -------------------------------------------------------------------------------
- */
- typedef struct {
- u32 width; // Ancho de la imagen
- u32 height; // Alto de la imagen
- u8* data; // Datos de la imagen
- u8* raw[3]; // Tiles en bruto
- u8* patterns[3]; // Buffer para los patterns
- u8* colors[3]; // Buffer para los colores
- u8* names[3]; // Buffer para los nombres (mapa)
- u32 tiles[3]; // Tiles en cada "banco" (3)
- u32 map_pos[3]; // Posicion en el mapa
- } img_info;
- img_info img; // Guarda la imagen cargada y su informacion
- void CleanBuffers(void) {
- free(img.data);
- img.data = NULL;
- int n = 0;
- for (n = 0; n < 3; n ++) {
- free(img.raw[n]);
- img.raw[n] = NULL;
- free(img.patterns[n]);
- img.patterns[n] = NULL;
- free(img.colors[n]);
- img.colors[n] = NULL;
- free(img.names[n]);
- img.names[n] = NULL;
- }
- }
- /*
- -------------------------------------------------------------------------------
- Carga el archivo BIPMAP y conviertelo a RAW
- -------------------------------------------------------------------------------
- */
- // Funcion NF_LoadBMP();
- s32 LoadBitmap(const char* file) {
- // Buffers locales
- u8* buffer; // Buffer temporal
- buffer = NULL;
- u8* palette; // Paleta (requerida por algun modo)
- palette = NULL;
- // Magic ID
- char magic_id[4];
- memset(magic_id, 0, 4);
- // Define la estructura para almacenar la cabecera del BMP
- typedef struct {
- u32 bmp_size; // Tamaño en bytes del BMP
- u16 res_a; // Reservado
- u16 res_b; // Reservado
- u32 offset; // Offset donde empiezan los datos
- u32 header_size; // Tamaño de la cabecera (40 bytes)
- u32 bmp_width; // Ancho de la imagen en pixeles
- u32 bmp_height; // Altura de la imagen en pixeles
- u16 color_planes; // Numero de planos de color
- u16 bpp; // Numero de bits por pixel
- u32 compression; // Compresion usada
- u32 raw_size; // Tamaño de los datos en RAW despues de la cabecera
- u32 dpi_hor; // Puntos por pulgada (horizontal)
- u32 dpi_ver; // Puntos por pulgada (vertical)
- u32 pal_colors; // Numero de colores en la paleta
- u32 imp_colors; // Colores importantes
- } bmp_header_info;
- bmp_header_info bmp_header;
- // Pon todos los bytes de la estructura a 0
- memset(&bmp_header, 0, sizeof(bmp_header));
- // Declara los punteros a los ficheros
- FILE* file_id;
- // Carga el archivo .BMP
- file_id = fopen(file, "rb");
- if (file_id) { // Si el archivo existe...
- // Posicionate en el byte 0
- fseek(file_id, 0, SEEK_SET);
- // Lee el Magic String del archivo BMP (2 primeros Bytes, "BM") / (0x00 - 0x01)
- fread(magic_id, 1, 2, file_id);
- // Si es un archivo BMP... (Magic string == "BM")
- if (strcmp(magic_id, "BM") == 0) {
- // Posicionate en el byte 2
- fseek(file_id, 2, SEEK_SET);
- // Lee la cabecera del archivo BMP (0x02 - 0x36)
- fread((void*)&bmp_header, 1, sizeof(bmp_header), file_id);
- /////////////////////////////////////////////////////////////
- // Es un archivo BMP valido, cargalo en un buffer temporal //
- /////////////////////////////////////////////////////////////
- // Crea un buffer temporal
- buffer = (u8*) calloc (bmp_header.raw_size, sizeof(u8));
- if (buffer == NULL) {
- printf("No se ha podido crear el buffer temporal para la imagen.\nError critico.\n");
- free(buffer);
- buffer = NULL;
- free(palette);
- palette = NULL;
- return -1;
- }
- // Si se ha creado con exito, carga el archivo al buffer
- fseek(file_id, bmp_header.offset, SEEK_SET);
- fread(buffer, 1, bmp_header.raw_size, file_id);
- } else {
- // No es un archivo BMP valido
- printf("El archivo %s no es un BMP valido.\nError critico.\n", file);
- free(buffer);
- buffer = NULL;
- free(palette);
- palette = NULL;
- return -1;
- }
- } else {
- // El archivo no existe
- printf("El archivo %s no existe.\nError critico.\n", file);
- free(buffer);
- buffer = NULL;
- free(palette);
- palette = NULL;
- return -1;
- }
- // Cierra el archivo
- fclose(file_id);
- // Variables que se usaran a partir de aqui
- u32 x = 0; // Coordemada X
- u32 y = 0; // Coordenada Y
- u32 idx = 0; // Indice en el buffer temporal
- u32 offset = 0; // Indice en el buffer de destino
- u16 colors = 0; // En 8 bits, numero de colores
- u32 size = 0; // Tamaño del buffer (en bytes)
- // Guarda el tamaño de la imagen
- img.width = bmp_header.bmp_width;
- img.height = bmp_header.bmp_height;
- if ((img.width != 256) || (img.height != 192)) {
- printf("Tamaño ilegal de archivo.\nSe requiere una imagen de 256x192 pixeles.\n");
- free(buffer);
- buffer = NULL;
- free(palette);
- palette = NULL;
- return -1;
- }
- // Habilita el buffer de destino (u8 de alto x ancho del tamaño de imagen)
- size = (bmp_header.bmp_width * bmp_header.bmp_height);
- img.data = (u8*) calloc (size, sizeof(u8));
- if (img.data == NULL) {
- printf("No se ha podido crear el buffer de datos para la imagen.\nError critico.\n");
- free(buffer);
- buffer = NULL;
- free(palette);
- palette = NULL;
- return -1;
- }
- // Segun los BITS por Pixel (8, 16, 24)
- switch (bmp_header.bpp) {
- case 8: // 8 bits por pixel
- // Calcula el tamaño de la paleta
- colors = ((bmp_header.offset - 0x36) >> 2);
- palette = (u8*) calloc ((colors << 2), sizeof(u8));
- if (palette == NULL) {
- printf("No se ha podido crear el buffer para la paleta.\nError critico.\n");
- free(buffer);
- buffer = NULL;
- free(palette);
- palette = NULL;
- return -1;
- }
- // Abre de nuevo el archivo y carga la paleta
- file_id = fopen(file, "rb");
- if (!file_id) {
- printf("El archivo %s no existe.\nError critico.\n", file);
- free(buffer);
- buffer = NULL;
- free(palette);
- palette = NULL;;
- return -1;
- }
- fseek(file_id, 0x36, SEEK_SET);
- fread(palette, 1, (colors << 2), file_id);
- fclose(file_id);
- // Convierte el archivo a RAW de 8 bits
- for (y = 0; y < bmp_header.bmp_height; y ++) {
- for (x = 0; x < bmp_header.bmp_width; x ++) {
- // Calcula los offsets
- offset = ((((bmp_header.bmp_height - 1) - y) * bmp_header.bmp_width) + x);
- // Guarda el pixel del buffer en img_data
- img.data[offset] = buffer[idx];
- // Siguiente pixel
- idx ++;
- }
- // Ajusta la alineacion a 4 bytes al final de linea
- while ((idx % 4) != 0) idx ++;
- }
- // Elimina la paleta de la RAM
- free(palette);
- palette = NULL;
- break;
- default:
- printf("La imagen no esta indexada.\nError critico.\n");
- free(buffer);
- buffer = NULL;
- free(palette);
- palette = NULL;
- return -1;
- break;
- }
- // Libera el buffer temporal
- free(buffer);
- buffer = NULL;
- // Devuelve el puntero al buffer de datos
- return 0;
- }
- /*
- -------------------------------------------------------------------------------
- Analiza los datos y genera el archivo tileset
- -------------------------------------------------------------------------------
- */
- s32 GenerateTileset(const char* filename) {
- // Buffers temporales para los tiles
- u8* tile_pattern = (u8*) calloc(64, sizeof(u8));
- u8* test_pattern = (u8*) calloc(64, sizeof(u8));
- // Verifica si se han creado todos los buffers
- if (
- (tile_pattern == NULL)
- ||
- (test_pattern == NULL)
- ) {
- printf("Error creando los buffers internos.\nError critico.\n");
- free(tile_pattern);
- tile_pattern = NULL;
- free(test_pattern);
- test_pattern = NULL;
- return -1;
- }
- // Crea los buffers para las tablas de pattern y color
- // (Asume que todos los tiles son unicos)
- u32 n = 0;
- for (n = 0; n < 3; n ++) {
- img.raw[n] = (u8*) calloc(16384, sizeof(u8)); // Tiles diferentes de 8x8 x 256
- img.patterns[n] = (u8*) calloc(2048, sizeof(u8)); // 8 bytes por tile (8 filas de 8 pixeles)
- img.colors[n] = (u8*) calloc(2048, sizeof(u8)); // Cada fila de pixeles tiene dos colores de 4 bits
- img.names[n] = (u8*) calloc(256, sizeof(u8)); // Tabla de nombres de cada banco (mapa)
- if ((img.raw[n] == NULL) || (img.patterns[n] == NULL) || (img.colors[n] == NULL || img.names[n] == NULL)) {
- printf("Error creando los buffers internos.\nError critico.\n");
- free(tile_pattern);
- tile_pattern = NULL;
- free(test_pattern);
- test_pattern = NULL;
- return -1;
- }
- }
- // Analisis del RAW
- u32 main_offset = 0;
- u32 local_offset = 0;
- u32 b = 0;
- s32 match = 0;
- s32 exist = -1;
- // Analiza el archivo en pasos de 8x8 pixeles
- printf("Generando banco de tiles:\n\n");
- u32 pos_y = 0, pos_x = 0, temp_y = 0, temp_x = 0, t = 0;
- for (pos_y = 0; pos_y < img.height; pos_y += 8) {
- // Calcula el banco
- b = (int)(pos_y / 64);
- for (pos_x = 0; pos_x < img.width; pos_x += 8) {
- // Copia los datos al tile
- for (temp_y = 0; temp_y < 8; temp_y ++) {
- for (temp_x = 0; temp_x < 8; temp_x ++) {
- local_offset = (temp_y << 3) + temp_x;
- main_offset = ((pos_y + temp_y) * img.width) + (pos_x + temp_x);
- tile_pattern[local_offset] = img.data[main_offset];
- }
- }
- // Borra la asignacion de tile existente
- exist = -1;
- // Ahora verifica si ya hay algun tile registrado
- if (img.tiles[b] > 0) {
- // Verifica si el tile es nuevo o ya existe
- for (n = 0; n < img.tiles[b]; n ++) {
- // Flag de repeticion
- match = 0;
- // Compara la info con la almacenada en el buffer de tiles
- for (t = 0; t < 64; t ++) {
- local_offset = (n * 64) + t;
- // Si los pixeles son iguales...
- if (tile_pattern[t] == img.raw[b][local_offset]) {
- match ++;
- }
- // Si todos los pixeles eran iguales, indicalo
- if (match == 64) {
- exist = n;
- n = img.tiles[b]; // Sal
- }
- }
- }
- // Si el tile ya existe...
- if (exist != -1) {
- // Indicador
- img.names[b][img.map_pos[b]] = exist;
- // Indicador
- printf(".");
- img.map_pos[b] ++;
- } else { // SI no existe, agregalo a los buffers
- // Indicador
- //printf("B:%01d.P%03d.M%03d", b, img.tiles[b], img.map_pos[b]);
- // Actualiza los buffers
- memcpy(img.raw[b] + (img.tiles[b] * 64), tile_pattern, 64); // Copia la informacion del tile
- img.names[b][img.map_pos[b]] = img.tiles[b]; // Indica al mapa que tile es
- // Indicador
- printf("%01d", b);
- // Actualiza los contadores
- img.map_pos[b] ++;
- img.tiles[b] ++;
- }
- } else {
- // Si el el primero, registralo
- memcpy(img.raw[b], tile_pattern, 64); // Copia la informacion del tile
- img.names[b][img.map_pos[b]] = img.tiles[b]; // Indica al mapa que tile es
- // Indicador
- printf("%01d", b);
- // Actualiza los contadores
- img.map_pos[b] ++;
- img.tiles[b] ++;
- }
- }
- }
- // Resumen
- printf("\n\nBanco de tiles creado con exito.\n\n");
- printf("Banco 1: %03d tiles.\n", img.tiles[0]);
- printf("Banco 2: %03d tiles.\n", img.tiles[1]);
- printf("Banco 3: %03d tiles.\n\n", img.tiles[2]);
- // Fase 2, genera las tablas de pattern y color para cada banco
- u32 l = 0;
- u32 i = 0;
- u8 bg_color = 0;
- u8 pixel_color = 0;
- u32 encode = 0;
- u32 tbl = 0;
- printf("Codificando los tiles a filas de patterns...\n\n");
- for (b = 0; b < 3; b ++) {
- tbl = 0;
- // Analiza los tiles de ese banco
- for (n = 0; n < img.tiles[b]; n ++) {
- // Paso 1, analiza cada linea y calcula su valor en binario
- printf("B: %01d T: %03d LINES: ", b, n);
- for (l = 0; l < 8; l ++) { // Linea del tile
- // Guarda el primer color de la fila
- local_offset = (n * 64) + (l * 8);
- bg_color = img.raw[b][local_offset];
- pixel_color = bg_color;
- encode = 0;
- for (i = 0; i < 8; i ++) { // Pixel
- local_offset = (n * 64) + (l * 8) + i; // Calcula el offset del pixel en el buffer
- if (bg_color != img.raw[b][local_offset]) {
- // Si el color no es el de fondo, codifica el bit
- encode |= (1 << (7 - i));
- pixel_color = img.raw[b][local_offset];
- }
- }
- // Guarda la fila
- img.patterns[b][tbl] = encode;
- img.colors[b][tbl] = ((((pixel_color + 1) << 4) & 0xf0)| ((bg_color + 1) & 0x0f));
- printf("$%02x ", img.patterns[b][tbl]);
- tbl ++;
- }
- printf("\n");
- }
- }
- printf("\n\n");
- // Fase 3, genera el archivo codificado
- char fnam[256];
- char output[256];
- char txt[32];
- sprintf(fnam, "%s.asm", filename);
- FILE* file = fopen(fnam, "wb");
- // Si se puede crear el archivo...
- if (file != NULL) {
- // Cabecera del archivo
- sprintf(output, "; Imagen convertida para MSX SCREEN 2\n");
- fwrite(output, strlen(output), 1, file);
- sprintf(output, "; Archivo de origen: %s\n", filename);
- fwrite(output, strlen(output), 1, file);
- sprintf(output, "; Tamaño: %03dx%03d pixeles\n", img.width, img.height);
- fwrite(output, strlen(output), 1, file);
- sprintf(output, "; Informacion:\n");
- fwrite(output, strlen(output), 1, file);
- for (b = 0; b < 3; b ++) {
- sprintf(output, "; Banco %01d: %03d patterns (%d bytes) [$%04x bytes]\n", b, img.tiles[b], (img.tiles[b] * 8), (img.tiles[b] * 8));
- fwrite(output, strlen(output), 1, file);
- }
- sprintf(output, "\n\n\n");
- fwrite(output, strlen(output), 1, file);
- // Genera los patterns
- printf("Grabando datos CHR ");
- for (b = 0; b < 3; b ++) {
- tbl = 0;
- // Genera la etiqueta
- sprintf(output, "_CHR_%01d:\n", b);
- fwrite(output, strlen(output), 1, file);
- for (n = 0; n < img.tiles[b]; n ++) {
- // Tiles
- sprintf(output, "db ");
- // Lineas
- for (l = 0; l < 8; l ++) { // Linea
- if (l != 7) {
- sprintf(txt, "$%02x, ", img.patterns[b][tbl]);
- } else {
- sprintf(txt, "$%02x\n", img.patterns[b][tbl]);
- }
- strcat(output, txt);
- tbl ++;
- }
- // Guarda la info
- printf(".");
- fwrite(output, strlen(output), 1, file);
- }
- // Genera un espacio entre bancos
- sprintf(output, "\n\n");
- fwrite(output, strlen(output), 1, file);
- }
- printf(" ok\n\n");
- // Genera los colores
- printf("Grabando datos CLR ");
- for (b = 0; b < 3; b ++) {
- tbl = 0;
- // Genera la etiqueta
- sprintf(output, "_CLR_%01d:\n", b);
- fwrite(output, strlen(output), 1, file);
- for (n = 0; n < img.tiles[b]; n ++) {
- // Tiles
- sprintf(output, "db ");
- // Lineas
- for (l = 0; l < 8; l ++) { // Linea
- if (l != 7) {
- sprintf(txt, "$%02x, ", img.colors[b][tbl]);
- } else {
- sprintf(txt, "$%02x\n", img.colors[b][tbl]);
- }
- strcat(output, txt);
- tbl ++;
- }
- // Guarda la info
- printf(".");
- fwrite(output, strlen(output), 1, file);
- }
- // Genera un espacio entre bancos
- sprintf(output, "\n\n");
- fwrite(output, strlen(output), 1, file);
- }
- printf(" ok\n\n");
- // Genera la tabla de nombres
- printf("Grabando datos NAME ");
- for (b = 0; b < 3; b ++) {
- // Genera la etiqueta
- sprintf(output, "_NAM_%01d:\n", b);
- fwrite(output, strlen(output), 1, file);
- l = 0; i = 0;
- sprintf(output, "db ");
- for (n = 0; n < img.map_pos[b]; n ++) {
- // Lineas
- if (i != 31) {
- sprintf(txt, "$%02x, ", img.names[b][n]);
- } else {
- sprintf(txt, "$%02x\n", img.names[b][n]);
- }
- strcat(output, txt);
- // Ajuste de indice
- i ++;
- if (i > 31) {
- i = 0;
- // Guarda la info de la linea
- printf(".");
- fwrite(output, strlen(output), 1, file);
- sprintf(output, "db ");
- }
- }
- // Genera un espacio entre bancos
- sprintf(output, "\n\n");
- fwrite(output, strlen(output), 1, file);
- }
- } else {
- printf("No se puede generar el archivo.\n");
- free(tile_pattern);
- tile_pattern = NULL;
- free(test_pattern);
- test_pattern = NULL;
- return -1;
- }
- // Cierra el archivo
- fclose(file);
- printf(" ok\n\n");
- return 0;
- }
- /*
- -------------------------------------------------------------------------------
- Archivo MAIN
- -------------------------------------------------------------------------------
- */
- int main(int argc, char *argv[]) {
- printf("\n\nConversor de imagenes BMP a formato MSX.\nVersion 0.1 alpha.\n(c)2015 por Cesar Rincon.\n\n\n");
- // Inicializa las estructuras
- memset(&img, 0, sizeof(img));
- // Analiza el numero de argumentos
- if (argc != 2) {
- printf("Uso: %s archivo.bmp\n", argv[0]);
- CleanBuffers();
- return -1;
- }
- // Carga el archivo BITMAP
- if (LoadBitmap(argv[1]) == -1) {
- printf("Error al procesar el archivo BITMAP.\n");
- CleanBuffers();
- return -1;
- }
- // Guarda un archivo de prueba
- //FILE* file = fopen("bindata.raw", "wb");
- //fwrite(img.data, (img.width * img.height), 1, file);
- //fclose(file);
- printf("\nProcesando archivo BITMAP...\n\nNombre: %s\nTamaño: %dx%d pixeles.\n\n", argv[1], img.width, img.height);
- if (GenerateTileset(argv[1]) == -1) {
- printf("Error al procesar los datos.\n");
- CleanBuffers();
- return -1;
- }
- // Sal del programa
- printf("Archivo ASM generado con exito.\n");
- CleanBuffers();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement