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:
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;
}