Presentation and some questions regarding very detailed tilemaps

SGDK only sub forum

Moderator: Stef

Post Reply
masteries
Very interested
Posts: 53
Joined: Thu Jul 30, 2020 3:33 pm

Presentation and some questions regarding very detailed tilemaps

Post by masteries » Mon Aug 17, 2020 10:39 am

Greetings friends using SGDK,

I am Masteries, a new user to SGDK.
At first I want to give thanks for the existence of this C language based programming environment for MD / Genesis.

I am using SGDK as a porting tool for some Atari STE targeted games I am working on,
as an example, these sort of things are possible on an Atari STE; using 16+16 dualfield based colouring, at 50 frames per second:

https://www.youtube.com/watch?v=wdH8C8oQQYw

Obviously, MD doesn´t have enough VRAM to use two framebuffers as dualfield requires; but on MD you can split each map in two parts in order to display up to 30 or 32 colours (if you dont care of transparent colour) for background displaying.



Regarding some questions I have...

The maps I am designing are very detailed ones (there is no problem on take 256 KB per map on tile imformation; such 2000 different tiles per map... I managed to use a single framebuffer for map displaying, and update columns by replacing tile data dinamically. Currently only horizontal scrolling is used.


Also, how to change the memory layout to use a 328x200 (intended for 320x200 visible screen plus one virtual column to be updated outside the screen) VRAM space for map tiles? I suppose I need also to change the sprite tiles start address.

And probably I dont need the 96 tiles dedicated to system font in a near future.


But I encounter severe problems exporting tile data; embedded resource compiler uses full images, and tries to load all tiles into memory at once, that is not possible. Mappy generates tile data intended for Game Boy Advance usage, and these are displayed distorted on the screen. And Genitile tries to optimize them in order to minimize the amount of them and the appearence of orginal tiles are greatly distorted.

Are there any map tile editor that can export tile data without any distortion?


Genitile produces weird results:
Image


The early prototype code in use:

Code: Select all


#include <genesis.h>

#include "gfx.h"
#include "sprite.h"


#include "testfm.h"
#include "testft.h"



#define PLAN_A  BG_A
#define PLAN_B  BG_B

//animacion de Sonic
#define ANIM_STAND      0
#define ANIM_RUN        3

//definicion de funciones
static void handleInput();
static void updateCamera();
static void updatePhysic();
static void show_debug();


//definicion de variables

    //pulsacion DPAD
    s16 Xorder;                 //pulsacion derecha
    s16 Yorder;                 //pulsacion izquierda

    //scroll
    s16 cuentaPixels = 0;       //detecta cambios de tile, se resetea cada 8px (de 0 a 7)
    s16 offset = 0;             //scroll en pixels, de 0 a 1023 px
    s16 column_to_update = 0;   //scroll en TILES,  de 0 a 127 tiles

    //control de tiles del fondo
    u16 ind;

    //sprites
    Sprite *sonic_spr;          //sonic sprite
    s16 SonicX;
    s16 SonicY;

	
	
volatile unsigned char Pos_col = 0;
volatile unsigned short Next_col = 41;
volatile unsigned short World_Pos_col = 0;

unsigned int map_width = 1024;
unsigned int map_height = 200;



//FUNCION PRINCIPAL
int main()
{
	unsigned char aux;
	unsigned char aux2;
	unsigned short tile_ind;
	unsigned int tile;
	
	VDP_setPlanSize(64, 32);
	
    //disable interrup
    SYS_disableInts();

    //320x224px
    VDP_setScreenWidth320();
    VDP_setScreenHeight224();

    //motor sprites
    SPR_init();

    //background
    VDP_setPalette(PAL0, dummy_image.palette->data);
    ind = 1;
    //VDP_drawImageEx(PLAN_B, &dummy_image, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, ind), 0, 0, FALSE, TRUE);
	
	//Leer los tiles por columnas
	tile_ind = 1;
	for(aux = 0; aux < 40; aux++)
	{
		for(aux2 = 0; aux2 < 25; aux2++)
		{	
		tile = testfm[aux+(128*aux2)];//40  128  
		if(tile == 0)
			tile = 4;
		tile = tile*32;
		VDP_loadTileData((void*)&testft[tile],tile_ind,1,DMA);//1
		tile_ind++;
		//DMA_waitCompletion();
		}
	}//Parece que ya carga los 1000 tiles, bien lo guarda en forma de columnas ->
	
	
    //we load our unique tile data at position 1 on VRAM
	//for(aux = 0; aux < 25; aux++)
	//{	
	//	VDP_loadTileData( (void*)test3_tiles+(aux*128), 1+(40*aux), 40, DMA);//Si cargan
	//	ind += 40;
	//}
	
	
	//Dibujar una pantalla, utiliza sólo los 1000 tiles cargados; y los coge de ahí
	aux = 0;
	aux2 = 0;
	tile = 1;
	for(aux = 0; aux < 40; aux++)
	{
		//tile = 1+(aux*aux2);
		for(aux2 = 0; aux2 < 25; aux2++)
		{
		//tile = (1+aux)+(40*aux2);
        VDP_fillTileMapRect(PLAN_B,TILE_ATTR_FULL(PAL0,1,FALSE,FALSE,tile),aux,aux2,1,1);
        tile++;		
		}
	}//Parece que ya carga los 1000 tiles
	
    //VDP_fillTileMap(VDP_PLAN_B,TILE_ATTR_FULL(PAL0,1,FALSE,FALSE,1),0,40);	
	
    
	
	/*
	//Dibujar la pantalla la primera vez
	for(aux = 0; aux < 42; aux++)
	{
		column_to_update = aux;      //tilemap
		VDP_setMapEx(PLAN_B, bg_image.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, TILE_USERINDEX),
                     column_to_update, 0, column_to_update, 0, 1, 28);
	}
	*/

    //sprite
    VDP_setPalette(PAL1, sonic_sprite.palette->data);
    SonicX = SonicY = 160;
    sonic_spr= SPR_addSprite(&sonic_sprite, SonicX, SonicY, TILE_ATTR(PAL1, TRUE, FALSE, FALSE));

    // VDP process done, we can re enable interrupts
    SYS_enableInts();
	


    //Scroll por planos
    VDP_setScrollingMode(HSCROLL_PLANE  ,VSCROLL_PLANE);

    while(TRUE)
    {
        handleInput();
        updatePhysic();
        show_debug();
        SPR_update();

        VDP_waitVSync();
		
    }

    return 0;
}


//Muestra variables en pantalla
static void show_debug()
{
    char integer_string[32];
    VDP_setTextPalette(PAL0);
    sprintf(integer_string, "%4d", offset);
    VDP_drawText("offset          :", 12, 12);
    VDP_drawText(integer_string,      30, 12);
    sprintf(integer_string, "%4d", cuentaPixels);
    VDP_drawText("cuentaPixels    :", 12, 14);
    VDP_drawText(integer_string,      30, 14);
    sprintf(integer_string, "%4d", Pos_col);//column_to_update
    VDP_drawText("column_to_overwrite:", 12, 16);
    VDP_drawText(integer_string,      30, 16);
	sprintf(integer_string, "%4d", Next_col);//column_to_update
    VDP_drawText("column_to_draw:", 12, 18);
    VDP_drawText(integer_string,      30, 18);
    }


//control del scroll
static void updatePhysic()
{
    if (Xorder > 0)         //PULSO DERECHA
    {
        offset++; cuentaPixels++;  //if(cuentaPixels>7) cuentaPixels=0;  //del 0 al 7 son 8px=1 TILE
        SPR_setAnim(sonic_spr, ANIM_RUN);
        SPR_setHFlip(sonic_spr, FALSE);
    }
    else if (Xorder < 0)    //PULSO IZQUIERDA
    {
        offset--; cuentaPixels--;  //if(cuentaPixels<-7) cuentaPixels=0;
        SPR_setAnim(sonic_spr, ANIM_RUN);
        SPR_setHFlip(sonic_spr, TRUE);
    }
    else SPR_setAnim(sonic_spr, ANIM_STAND);

    updateCamera();
}



static void updateCamera()
{
	static unsigned char aux;
	static unsigned char aux2;
	static unsigned short tile_ind;
	static unsigned int tile;
	
    //cada vez que nos 'salimos' de la imagen, volvemos al principio
    //if(offset>1023) offset=0;
    //if(offset<0) offset=184;

    //solo actualizamos el tile que va a mostrarse a continuación,
    //justo ANTES de mostrarse (de zona no visible a zona visible)
	
    if(cuentaPixels > 7)  //==0   Se está moviendo hacia la derecha
    {
		cuentaPixels = 0;
		
		if(offset + 320 < map_width)
		{
		
		//Escribir nuevos tiles en VRAM
		
		//Posicionarte en la VRAM, para sobreescribir los tiles de una columna
		//aux = Pos_col;
		tile_ind = 1 + (Pos_col*25);//Cambiarlo por World_Pos_col
		aux = tile_ind;
		Next_col = World_Pos_col + 40;
		
		if( Pos_col > 39 )//Reposicionar el tile a sobreescribir
		{
			Pos_col = 0;
			tile_ind = 1;
		}
		
		//Tiene el problema de que debe poder funcionar usando sólo 40 / 4º columnas y no 64, porque machaca todos los datos
		//hay que hacer que los datos de las columnas futuras apunten a columnas previas
		
		//Borrar los tiles, es posible que no haga falta
		//VDP_fillTileData(0,tile_ind,25,TRUE); 	
		
		//aux = 35;//Forzado
		for(aux2 = 0; aux2 < 25; aux2++)
		{	
		tile = testfm[Next_col+(128*aux2)];//aux 40  128  
		//if(tile == 0)
		//	tile = 4;
		tile = tile*32;
		VDP_loadTileData((void*)&testft[tile],tile_ind,1,DMA);//1
		tile_ind++;
		DMA_waitCompletion();
		}
		
		
		//Dibujar la nueva columna
		tile = 1 + (Pos_col*25);
		//tile = 1+(aux*aux2);
		for(aux2 = 0; aux2 < 25; aux2++)
		{
		//tile = (1+aux)+(40*aux2);
        VDP_fillTileMapRect(PLAN_B,TILE_ATTR_FULL(PAL0,1,FALSE,FALSE,tile),Next_col,aux2,1,1);
        tile++;		
		}
		
		
		//Pos_col = (Pos_col + 1) & 40;
		
		Pos_col++;
		World_Pos_col++;
		

		}
		
		
        //column_to_update = (((offset + 320) >> 3)+ 1) & 40;//+23 &127
		
                        // 320=screen_width
                        // valor_px >> 3 = valor_tiles ===> de Pixels a Tiles,">>3" equivale a dividir entre 8
                        // valor_tiles + 23 = nuevo_valor_tiles ===> para apuntar a la tile correcta a actualizar
                        // nuevo_valor_tiles & 127              ===> se asegura de devolver un numero de 0 a 127
        //VDP_setMapEx(PLAN_B, bg_image.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, TILE_USERINDEX),
        //             column_to_update, 0, column_to_update, 0, 1, 25);//bg_image.tilemap 28
    }
    if(cuentaPixels < -7) //-7 ==-1  Se está moviendo hacia la izquierda
    {
		cuentaPixels = 0;
		
		if(offset > 0)
		{
		
		//Escribir nuevos tiles en VRAM
		
		//Posicionarte en la VRAM, para sobreescribir los tiles de una columna
		//aux = Pos_col;
		tile_ind = 1 + (Pos_col*25);//Cambiarlo por World_Pos_col
		aux = tile_ind;
		Next_col = World_Pos_col - 1;
		

		//Tiene el problema de que debe poder funcionar usando sólo 40 / 4º columnas y no 64, porque machaca todos los datos
		//hay que hacer que los datos de las columnas futuras apunten a columnas previas
		
		//Borrar los tiles, es posible que no haga falta
		//VDP_fillTileData(0,tile_ind,25,TRUE); 	
		
		//aux = 35;//Forzado
		for(aux2 = 0; aux2 < 25; aux2++)
		{	
		tile = testfm[Next_col+(128*aux2)];//aux 40  128  
		//if(tile == 0)
		//	tile = 4;
		tile = tile*32;
		VDP_loadTileData((void*)&testft[tile],tile_ind,1,DMA);//1
		tile_ind++;
		DMA_waitCompletion();
		}
		
		
		//Dibujar la nueva columna
		tile = 1 + (Pos_col*25);
		//tile = 1+(aux*aux2);
		for(aux2 = 0; aux2 < 25; aux2++)
		{
		//tile = (1+aux)+(40*aux2);
        VDP_fillTileMapRect(PLAN_B,TILE_ATTR_FULL(PAL0,1,FALSE,FALSE,tile),Next_col,aux2,1,1);
        tile++;		
		}
		
		
		//Pos_col = (Pos_col + 1) & 40;
		
		Pos_col--;
		World_Pos_col--;
		
		if( Pos_col == 0 )//Reposicionar el tile a sobreescribir
		{
			Pos_col = 39;
			tile_ind = 975;
		}
		

		}		
		
		
        //column_to_update = (((offset + 320) >> 3)+ 88) & 40;//&127
                        // valor_tiles + 88 = nuevo_valor_tiles ===> para apuntar a la tile correcta a actualizar
        //VDP_setMapEx(PLAN_B, bg_image.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, TILE_USERINDEX),
        //             column_to_update, 0, column_to_update, 0, 1, 25);//bg_image.tilemap 28
    }

    //hacemos scroll
    //VDP_setHorizontalScroll(PLAN_B, -offset);
	//offset += Xorder;
	
	//Límites del scroll
	if(offset < 0)//Límite por la izquierda
	{
		offset = 0;
		cuentaPixels = 0;
	}else if( offset > (map_width - 320) )//Límite por la derecha
	{
		offset = map_width - 320;
		cuentaPixels = 0;
	}
	

	
	VDP_setHorizontalScroll(PLAN_B, -offset);

}


static void handleInput()
{
    u16 value = JOY_readJoypad(JOY_1);

    if (value & BUTTON_LEFT) Xorder = -1;
    else if (value & BUTTON_RIGHT) Xorder = +1;
        else Xorder = 0;
		
		//offset = offset + Xorder;
}


masteries
Very interested
Posts: 53
Joined: Thu Jul 30, 2020 3:33 pm

Re: Presentation and some questions regarding very detailed tilemaps

Post by masteries » Wed Sep 02, 2020 12:19 pm

I solved the problem with very high detailed tilemaps using Retro Graphics Toolkit and Matlab,

Post Reply