Tutorial programacion Megadrive - SGDK

13, 4, 5, 6, 7
Hola, me pillas ahora mismo pillando la wifi de la estación de autobuses de Buenos Aires xD

Pero vamos, que si, desde imágenesis te crea el mapa optimizado, exportas el tileset y ya puedes montarlo, no puse un ejemplo de dibujar mapas?
Lucho te vemos liado cuando tengas un hueco lo miras con más detenimiento,...

A ver; yo exporto el mapa de tiles optimizado ... de una imagen por ejemplo de 320*224 (1120 tiles) lo optimizo y me crea un tile data de 129 pero claro, ahora no se como montarlo en orden y tal.... tambien el imagenesis te da la opción de exportar tile map en vez de tile data nose si habrá que utilizar eso... (nose que diferencia hay entre tiledata y tilemap)

ya te digo cuando tengas un huequillo le hechas un ojo y nos explicas un poco lo de los mapas a ver cm va...

pocket_lucho escribió:no puse un ejemplo de dibujar mapas?


Se quedó pendiente por lo que veo no pusiste el ejemplo al final xD, nos lo debes jajajaja.

pocket_lucho escribió:Lo único que no hemos visto es la función para dibujar mapas de tiles usada para dibujar el escenario de la que tratará un futuro tutorial.
Sería un puntazo la verdad porque el tema fondos...
Creo que he aprendido y conseguido saber cómo se usan los mapas. Si aún sigues interesado te puedo explicar un poco, aunque será de aquella manera poco pro XD, si prefieres que te lo explique pocket_lucho que lo hará en condiciones lo comprenderé perfectamente [+risas]
Manveru Ainu escribió:Creo que he aprendido y conseguido saber cómo se usan los mapas. Si aún sigues interesado te puedo explicar un poco, aunque será de aquella manera poco pro XD, si prefieres que te lo explique pocket_lucho que lo hará en condiciones lo comprenderé perfectamente [+risas]


Cuenta amigo ;) aqui estamos para aprender [oki]
Di todo lo que sepas, y no te dejes ni lo más minimo jajajaja.

Si lo pones con ejemplos.... mejor que mejor pa q se entienda.
Oks jejeje gracias, explicaré lo mejor que pueda lo que he aprendido estos días:

He empezado a partir del magnífico tutorial de theelf que hay en este subforo (http://www.elotrolado.net/hilo_tutorial-programacion-megadrive-basico_1371287). He seguido las intrucciones para generar el mapa de una imagen con el Imagenesis, por ejemplo del típico fondo donde se repiten muchos tiles. Abrimos el Imagenesis, cargarmos la imágen, elegimos "Mode -> 15color,4bpp,Optimized", luego "Enable transparency" y elegimos el color asociado a la transparencia*, y por último "actions-> Quantize Now".

*El Imagenesis parece tener un bug y a veces no coge bien el color de la transparencia por defecto. Cuando te sale bien por defecto el color que corresponde a la transparencia recomiendo elegir otro cualquiera y luego volver a poner el correcto, si no hay veces que no genera bien el array de tiles.


Una vez hecho esto, tenemos la imagen lista para obtener el código necesario. Generamos la paleta y el array con los tiles, como se indica en los tutoriales de pocket_lucho. Además tenemos que generar el mapa con "actions -> Export tile map". Elegimos como lenguaje de programación C y copiamos y pegamos el array* generado en nuestro código, al igual que el del array de tiles (BASIC + megagfx) y el de la paleta.

*Normalmente nos da un array con un tamaño erróneo ya que el correcto es el número de tiles de la imagen. Lo podéis obtener multiplicando los valores del campo "Picture size in tiles", que si es por ejemplo un fondo a pantalla completa sería 40 x 28 = 1120.


El mapa generado no es más que un array con las direcciones de memoria correspondientes a cada uno de los tiles que componen la imagen. Es decir, si hay 20 valores del array que apuntan a la dirección de memoria 0x000A, cuando se vaya a dibujar cada uno de esos 20 puntos se accede al mismo tile guardado en la posición 10 de la VRAM. Sin ésto tendríamos que guardar el mismo tile 20 veces en la memoria agotándola rápidamente, con lo que los mapas es algo muy útil e indispensable.

Tenemos que cargar el array de tiles en la VRAM, como siempre, y cargar nuestra paleta en una de las 4 disponibles. Con ésto ya lo único que nos queda es dibujar la imágen a través del mapa, lo hacemos con este código (supone la carga de una imagen de 40x28 tiles):

int main()
{
  //bg_pal: paleta de la imagen.
  VDP_setPalette(PAL0, (const u16 *)bg_pal);

  //bg_tiles: tiles de la imagen.
  //bg_vram: posición inicial donde se guardan los tiles de la imagen.
  //bg_num_tiles: número de tiles(únicos) de la imagen.
  VDP_loadTileData( (const u32 *)bg_tiles, bg_vram, bg_num_tiles, 1);

  //h: coordenada horizontal de la imagen, de 0 a 39.
  //v: coordenada vertical de la imagen, de 0 a 27.
  //pos: posición en el array del mapa al recorrer cada fila y cada columna de la imagen.
  u16 h, v, pos;

  //Recorro primero filas porque es como guardamos el array en el Imagenesis, sólo por comodidad.
  for(v = 0; v < 28; v++)
    for(h = 0; h < 40; h++)
    {
      //pos: convierte las coordenadas bidimensionales de la imagen en la posición de memoria correspondiente del mapa.
      pos = h + (40 * v);
      if (bg_map[pos]) VDP_setTileMap(APLAN, TILE_ATTR_FULL(PAL0, 0, 0, 0, bg_map[pos] + bg_vram), h, v);
    }

  while(1)
   {
    VDP_waitVSync();
   }
   return 0;
}



Aclararé un poco la línea principal que hace todo el trabajo:
if (bg_map[pos]) VDP_setTileMap(APLAN, TILE_ATTR_FULL(PAL0, 0, 0, 0, bg_map[pos] + bg_vram), h, v);

Primero decir que "if (bg_map[pos])" se pone para comprobar si esa posición de memoria es la 0x0000, es decir, la primera, donde se guarda el "tile transparente", si se puede llamar así. Si es cero, osea falso, no ejecuta la sentencia ya que al ser transparente no es necesario dibujar nada. Si es cierto, es decir que hay algo a dibujar, entonces se ejecuta la función VDP_setTileMap, con los ya conocidos argumentos pero con la peculiaridad de que a la macro TILE_ATTR_FULL no le pasamos una dirección de memoria concreta con el tile a dibujar, sino que le pasamos la posición de memoria indicada en el mapa, correspondiente a las actuales coordenadas h x v de la imagen.

Es importante observar el detalle de que a la posición de memoria en el mapa hay que sumarle la posición inicial de los tiles en memoria, ¿por qué? Porque el Imagéneis genera un mapa con las direcciones de memoria que van de la 0 hasta el total de tiles únicos menos 1. Entonces si por ejemplo guardamos los tiles de nuestra imagen a partir de la posición 150 de la VRAM, entonces debemos sumar 150 a cada valor de nuestro mapa. Recordad que la VRAM empieza en la posición 1, no en la 0, así que siempre habrá que sumar al menos 1 a los valores de memoria en mapa de cada imagen.



Y nada creo que esto es todo, cualquier duda me la podéis preguntar y os intentaré ayudar lo mejor que pueda, y por supuesto cualquier cosa que haya que corregir o que añadir me lo decís con total confianza, que como digo yo no soy un pro de esto ni mucho menos :-|
Gracias nene, voy a seguir con lo que pretendía empezar cuando tenga hasta donde quiero pulido te pregunto por el scroll que no consigo que me funcione con lo que me explicaste pero la verdad es que tampoco me he puesto a fondo porque quería primero entender bien eso. Si veo algo que se pueda mejorar o lo que sea cuando me ponga a probarlo te lo digo...
Lo del tema del scroll que puse es un poco complicado y no me extrañaría que hubiera algún error. Con la última versión del SGDK hay funciones que lo hacen todo muchísimo más fácil y automáticamente.

Edito para aportar un poco de ayuda sobre cómo manejar el tema de los scrolls con SGDK, que la otra vez lo puse sin usar las nuevas funciones y estaba bastante confuso y era demasiado complejo sin necesidad. Como siempre, añadir y corregir lo que haga falta.


Antes de enseñaros las funciones necesitamos saber que estas funciones se añadieron en la versión 0,94 del SGDK, si tenéis una versión anterior debéis actualizarla. Además de las funciones, en esta versión añadieron dos nuevas constantes para referirse a los planos A y B, en concreto VDP_PLAN_A y VDP_PLAN_B respectivamente. Decir que APLAN y BPLAN siguen estando presentes y que se puede usar cualquier par sin problema.
La funciones necesarias para hacer movimientos de scroll son las siguientes:

  • void VDP_setScrollingMode(u16 hscroll, u16 vscroll);
    Establece el modo de scroll horizontal y vertical. Para cada tipo concreto de scroll tenemos una función distinta por lo que hay que cerciorarse de que se ha establecido el tipo de scroll correcto antes de usar una función concreta, si no no se obtendrán los resultados deseados.

    Sus dos parámetros pueden tomar estos valores:
    hscroll puede tomar los valores según la división del plano a la hora de moverlo:
    • HSCROLL_PLANE : todo el plano como un único bloque.
    • HSCROLL_TILE : cada fila de tiles (8 píxeles).
    • HSCROLL_LINE : cada línea del plano (1 píxel).
    vscroll tiene estas dos posibilidades:
    • VSCROLL_PLANE : afecta a todo el plano.
    • VSCROLL_2TILE : divide el plano en franjas de dos tiles de ancho (16 píxeles).
    Si no se ejecuta esta función, los valores por defecto del tipo de scroll son HSCROLL_PLANE y VSCROLL_PLANE.


  • void VDP_setHorizontalScroll(u16 plan, u16 value);
    Mueve el plano plan un número value de píxeles hacia la derecha si value es positivo o a la izquierda si value es negativo. plan puede tomar los valores VDP_PLAN_A si queremos mover el plano A o VDP_PLAN_B si queremos mover el plano B.


  • void VDP_setHorizontalScrollTile(u16 plan, u16 tile, u16* values, u16 len, u16 use_dma);
    Los parámetros de esta función tienen el siguiente significado:
    • plan: plano al que afecta el scroll, VDP_PLAN_A o VDP_PLAN_B.
    • tile: número (en tiles) del tile al que afectará el scroll.
    • *values: array de tamaño len con los valores de desplazamiento de cada uno de los len tiles.
    • len: número de tiles empezando por tile al que afecta el movimiento del scroll. Si len vale 1, el scroll sólo afectará al tile tile, si vale más de 1 afectará a tile y a los len - 1 tiles siguientes a tile.
    • use_dma: indica si se activa (1) o no (0) el uso de DMA.

  • void VDP_setHorizontalScrollLine(u16 plan, u16 line, u16* values, u16 len, u16 use_dma);
    Los parámetros de esta función tienen el siguiente significado:
    • plan: plano al que afecta el scroll, VDP_PLAN_A o VDP_PLAN_B.
    • line: número (en líneas) de la línea a la que afectará el scroll.
    • *values: array de tamaño len con los valores de desplazamiento de cada una de las len líneas.
    • len: número de líneas empezando por line al que afecta el movimiento del scroll. Si len vale 1, el scroll sólo afectará a la línea line, si vale más de 1 afectará a line y a las len - 1 líneas siguientes a line.
    • use_dma: indica si se activa (1) o no (0) el uso de DMA.

  • void VDP_setVerticalScroll(u16 plan, u16 value);
    Mueve el plano plan un número value de píxeles hacia arriba si value es positivo o hacia abajo si value es negativo. plan puede tomar los valores VDP_PLAN_A si queremos mover el plano A o VDP_PLAN_B si queremos mover el plano B.


  • void VDP_setVerticalScrollTile(u16 plan, u16 tile, u16* values, u16 len, u16 use_dma);
    Los parámetros de esta función tienen el siguiente significado:
    • plan: plano al que afecta el scroll, VDP_PLAN_A o VDP_PLAN_B.
    • tile: número (en 2 x tiles, 16 píxeles) de la pareja de tiles a la que afectará el scroll.
    • *values: array de tamaño len con los valores de desplazamiento de cada una de las len parejas de tiles.
    • len: número de parejas de tiles empezando por la tile al que afecta el movimiento del scroll. Si len vale 1, el scroll sólo afectará a la pareja tile, si vale más de 1 afectará a la pareja tile y a las len - 1 parejas de tiles siguientes a tile.
    • use_dma: indica si se activa (1) o no (0) el uso de DMA.
Aún no lo he probado por falta de tiempo pero gracias de ante mano por la currada seguro q con eso puedo seguir un pasito más.

EDITO:

Mueve el plano plan un número value de píxeles hacia la derecha si value es positivo o a la izquierda si value es negativo


Corregidme si me equivoco pero un u16 es un entero de 16 bits sin signo que puede almacenar valores del 0 al 65535. por lo que nunca podría ir hacia la izquierda ya que no tomaría un valor negativo.

- Para hacer scroll hacia la izquierda habría que ir disminuyendo el valor de value en cada vuelta de un for ; teniendo en cuenta que si value = 0 el plano no se movería ni un pixel de su posición original y que cuando el plano sobresalga por el lado izquierdo volverá a aparecer por la derecha automaticamente.

Para saber cuanto mide de ancho el PLANO y saber así con que valor el plano volverá a parecer por el otro lado se utiliza la función VDP_getPlanWidth(); para el scroll vertical VDP_getPlanHeight(); hace lo propio.

Nota: VDP_getPlanWidth(); de vuelve el tamaño del PLANO en tiles así que hay que multiplicarlo por 8 para utilizarlo en la funcion de scroll que maneja pixeles.

Os dejo un ejemplo de como mover todo el PLANO A hacia la izquierda de forma infinita:
int main ()
{
    u16 i;

    VDP_setScrollingMode(HSCROLL_PLANE, VSCROLL_PLANE);
// BUCLE FOR sin condicion de parada
    for (i=(VDP_getPlanWidth()*8); ; i--)
    {
        VDP_setHorizontalScroll(APLAN, i);
        VDP_waitVSync();

        if (i==0) // SE HABRIA REALIZADO EL SCROLL ENTERO
            i=(VDP_getPlanWidth()*8); // VOLVEMOS A EMPEZAR DE NUEVO

    }
}


void VDP_setHorizontalScrollTile(u16 plan, u16 tile, u16* values, u16 len, u16 use_dma);


Os dejo un ejemplo donde se mueve el solo la última fila de tiles (TILEs Nº 27) de forma infinita hacia la izquierda:

int main ()
{
    u16 valores[1];

    VDP_setScrollingMode(HSCROLL_TILE, VSCROLL_PLANE);
    for (i=(VDP_getPlanWidth()*8); ; i--)
    {

        valores [0] = i;

        VDP_setHorizontalScrollTile(APLAN, 26, (u16*) valores, 1, 0);
        VDP_waitVSync();

        if (i==0)
            i=(VDP_getPlanWidth()*8);
    }
}
Es cierto que u16 no toma valores negativos. Para mover hacia la izquierda lo que hago es disminuir el valor de value y claro llega un momento que baja de cero y he suspuesto que toma valores negativos, pero por alguna razón funciona igualmente. Lo curioso es que cambiando u16 por s16 sigue funcionando igual XD. A ver si alguien nos lo explica.

El movimiento básico del scroll lo tengo hecho de esta manera:
u16 v[4] = {0,0,0,0};

while(1)
{
  u8 i;
  for(i = 0; i < 4; i++) v[i] = (i % 2 ? v[i] - 1 : v[i] - 2);

  VDP_setHorizontalScrollTile(BPLAN , 0, v, 4, 1);
}

Este código lo que hace es mover un píxel hacia la izquierda la fila de tiles 1 y 3 y dos píxeles hacia la izquierda la fila de tiles 0 y 2, en cada iteración del while.
Buenas, tenia ganas de compilar alguna cosilla, para probar el sdk, pero yo ni papa de C

Como se mete codigo asm? estuve echando un vistaso rapido y no encontre como

saludos
La verdad es que no tengo ni idea pero mirando los ejemplos de la web oficial parece que basta con llamar a la función asm pasándole el código, como por ejemplo (copio-pego):
// assert reset
void assert_reset()
{
    asm("reset\n\t");
}

// soft reset
void reset()
{
    asm("move   #0x2700,%sr\n\t"
        "move.l (0),%a7\n\t"
        "move.l (4),%a0\n\t"
        "jmp    (%a0)");
}
Hay dos opciones para usar ensamblador con el compilador GCC, o bien usas la sintaxis inline (como el ejemplo de Manveru) o bien creas tu código en un fichero separado y exportas las funciones para su uso desde C en un fichero de encabezado .h
En este enlace hay una explicación mucho mejor:

http://bus-error.nokturnal.pl/tiki-read_article.php?articleId=2
Tengo que decir, que en el manual parecía mas divertido hacer videojuegos.... x'D

Imagen


PD: Manveru no me olvido de lo que te dije por privado sobre los fadein y fadeout se que lo tengo pendiente
A raíz de una mijita por la mala conciencia de haber dejado los tutos abandonados os dejo una pequeña demo que aúna rasters y uso del modo hilight/shadow para "simular iluminación".

Dicho efecto se puede ver por ejemplo en Castlevania Bloodlines:
http://youtu.be/zLeVlsuf0vs?t=22m37s

No sé si Lucho comentó más atrás que medio hemos dado de lado a las SGDK, a lo mejor puede que haya que darle un ligero retoque al código para que tire con ellas pero será mínimo supongo.

/***********************************************************************************
  TEST DE SIMULACION DE HACES DE LUZ COMBINANDO MODO SHADOW CON RASTER DE LINEAS
 
***********************************************************************************/
#include "mini_lib.h"

// CONSTANTES Y MACROS /////////////////////////////////////////////////////////////
#define VRAM_POS_TILE1             1
#define VRAM_POS_LADRILLO_A       1
#define VRAM_POS_LADRILLO_B       2
#define VRAM_POS_TILE_TRANSPARENTE   3

#define NUM_COLUMNAS 40
#define NUM_FILAS    28
#define NUM_LINEAS   NUM_FILAS * 8

#define NUM_TILES_TILESET   3

#define ANCHO_HAZ   8
#define NUM_HACES   NUM_COLUMNAS / ANCHO_HAZ


// TILEMAP ====================================================================

// TILESET ====================================================================
const u32 fondo_tileset[NUM_TILES_TILESET*8] =
{
   0x11211111, 0x12222222, 0x12422222, 0x12242222, 0x12422222, 0x12222222, 0x12222222, 0x33333333,
   0x11111113, 0x22222223, 0x22222223, 0x22222223, 0x22222223, 0x22222223, 0x22222223, 0x32333333,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
};


// PALETA =====================================================================
const u16 fondo_paleta[16] = {
   0x0000,0x06CE,0x044E,0x0008,0x008C,0x0000,0x0000,0x0000,
   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
};


// OTROS DATOS GLOBALES =======================================================
fix32 planoA_scroll;
const fix32 planoA_velocidad_scroll = FIX32(0.075);

// DECLARACION DE FUNCIONES ===================================================


// MACROS =====================================================================

#define DibujarMuro(); \
    for(fila=0; fila<NUM_FILAS; fila+=2) \
    for(columna=0; columna<NUM_COLUMNAS; columna+=2) \
    { \
       VDP_setTileMap( BPLAN, VRAM_POS_LADRILLO_A, columna,   fila); \
       VDP_setTileMap( BPLAN, VRAM_POS_LADRILLO_B, columna+1, fila); \
       VDP_setTileMap( BPLAN, VRAM_POS_LADRILLO_B, columna,   fila+1); \
       VDP_setTileMap( BPLAN, VRAM_POS_LADRILLO_A, columna+1, fila+1); \
    }

#define DibujarHaces(); \
    for(fila=0; fila<NUM_FILAS; fila++) \
    for(columna=0; columna<NUM_HACES; columna++) \
    for(tile_haz=0; tile_haz<ANCHO_HAZ; tile_haz++) \
    { \
       VDP_setTileMap( APLAN, TILE_ATTR_FULL(PAL0, columna%2, 0, 0, VRAM_POS_TILE_TRANSPARENTE), \
          (columna * ANCHO_HAZ) + tile_haz, fila); \
    }

#define InicializarTablaScroll(); \
    for(linea=0; linea<NUM_LINEAS; linea++) scroll_lineas[linea] = FIX16(0);

#define InicializarVelocidadesScroll(); \
    velocidad_scroll_lineas[0] = FIX16(0.05); \
    for(linea=1; linea<NUM_LINEAS; linea++) \
       velocidad_scroll_lineas[linea] = fix16Add(velocidad_scroll_lineas[linea-1], FIX16(0.1));

//=============================================================================
// MAIN
//=============================================================================
int main()
{
    // Variables locales ______________________________________________________

    // Indices
    u8 fila, columna, tile_haz, linea, i;               

    // Buffer de valores de scroll y tabla de velocidad de cada linea
    fix16 scroll_lineas[NUM_LINEAS];         
    fix16 velocidad_scroll_lineas[NUM_LINEAS];

    // Proceso ________________________________________________________________

   // Mandar tiles y paleta a VRAM/CRAM
    VDP_setPalette((u16 *) fondo_paleta, 0,16);
    VDP_loadTileData( (const u32 *) fondo_tileset, VRAM_POS_TILE1, NUM_TILES_TILESET, 1);

    // Configurar la pantalla
    VDP_setReg(16, 0x11);   // Establecer tamaño del plano scrolleable a 64x64 tiles
    VDP_setReg(11, 0x03);   // Activacion del scroll horizontal por líneas
    VDP_setHilightShadow(1);// Activacion del modo hilight/shadow

    // Preparar la tabla de velocidades de scroll para cada una de las lineas
    InicializarTablaScroll();
    InicializarVelocidadesScroll();

    // Dibujar el fondo y los haces de luz
    DibujarMuro();
    DibujarHaces();

    // BUCLE PRINCIPAL ________________________________________________________
    while(1)
    {
       for(linea = 0; linea < NUM_LINEAS;  linea++)
        {
           VDP_setHorizontalScroll(APLAN, linea, fix16ToInt(scroll_lineas[linea]) );

            // Aplicamos la velocidad
            scroll_lineas[linea] = fix16Add(scroll_lineas[linea], velocidad_scroll_lineas[linea]);

            // Rebotamos el movimiento en cuanto la linea inferior alcance
            // su tope izquierdo o derecho
            if(scroll_lineas[NUM_LINEAS-1] >= FIX16(60) || scroll_lineas[NUM_LINEAS-1] <= FIX16(-60))
               velocidad_scroll_lineas[linea] *= -1;
       }
      
      // Ralentizamos el movimiento
        for(i=0; i<8; i++) VDP_waitVSync();
    }

    return 1;

} // fin main()



Binario + fuente
Muchas gracias realbrucest, muy chulo ese efecto. He tenido que tocar un par de cosas para que vaya con la última version del SGDK pero va de lujo [oki]
realbrucest te importa explicar un poco por encima en que consiste el modo hightlit shadow para los mortales como yo que hacen los juegos utilizando el "hola mundo" jajajaja.

Manveru si no es molestia podrías subir el codigo corregido conlos comandos del sgdk nuevo?
Ufff.. esto mereciera que lo plantease en plan tuto pero a ver si consigo sacar algo comprensible a botepronto:

El modo hilight/shadow viene a ser un recurso hardware que tiene la mega para duplicar el rango de colores obedeciendo unas ciertas convenciones.

- Ha de entenderse "modo hilight" como el método con el cual se duplica la intensidad de los colores (que se solapen)
- "Modo shadow" reduce la intensidad de los valores de color que se hayan dispuesto en la CRAM

Hilight duplica el brillo, shadow lo reduce a la mitad.

-------------------------------

Para usar ambos, el recurso común (voy a omitir algún caso muy específico) es solapar un plano que se ha dibujado con una intensidad de color "normal".

Vamos, que dibujaremos el plano B como normalmente sin preocuparnos de nada SÓLO de indicar la prioridad de dibujo de los tiles como "baja prioridad":

O bien así (si no se indica es baja):

VDP_setTileMap( BPLAN, VRAM_POS_LADRILLO_A, columna, fila);

O bien así:

VDP_setTileMap( BPLAN, TILE_ATTR_FULL(PAL0, 0, 0, 0, VRAM_POS_LADRILLO_A), columna, fila);

--------------------------

Las SGDK tienen una función para activar el modo hilight/shadow cosa que haremos:

VDP_setHilightShadow(1); // Pasándole 0 lo volveríamos a desactivar.

---------------------------

Pasaríamos a dibujar el plano A que va a solapar al B.

Y para este efecto vamos a rellenar el plano A de tiles "transparentes" (que sólo usan color 0)

----------------------------

Pues bien, ahora entran en juego las características de este peculiar sistema hilight/shadow en base a las prioridades de los tiles.

- Si colocamos un tile "transparente" en el plano A con prioridad BAJA (0) sobre un tile del plano B con prioridad BAJA (0), veremos el tile del plano B "en modo shadow".

- Si colocamos un tile "transparente" en el plano A con prioridad ALTA (0) sobre un tile del plano B con prioridad BAJA (0), veremos el tile del plano B "en modo normal".

------------------------------

Para sacar el modo "HILIGHT" (obtener más brillo en base a los colores del fondo) sí o sí nos veremos obligados a solaparlos con SPRITES que usen la ÚLTIMA PALETA y el color del pixel "hilighteador" tiene que ser el COLOR 14 (0xE).

------------------------------

- Shadow:
-- Disponer tiles con baja prioridad en el planto A sobre tiles con baja prioridad en el plano B
-- Disponer sprites que usen la última paleta sobre con color 0xF

- Hilight:
-- Disponer sprites que usen la última paleta sobre con color 0xE

------------------------------

Bueno, ya cachárreais y vais contando qué tal.

Lo del highlight es un pelín más coñazo por obligar a realizarlo con sprites pero termina por salir ;)

Saludos y disculpad el abandono de los tutos. A ver si con esta demo que toca palos que dejamos colgados os de lugar para trastear cosillas nuevas.

---------------------------------

EDIT: si queréis haceros una idea rápida sobre las posibilidades de estos modos echaros unas partidillas a cualquiera de los dos Vectorman porque le sacan chicha a lo grande.
realbrucest escribió:Ufff.. esto mereciera que lo plantease en plan tuto


Jajaja algun día con más tiempo, apuntatelo que no se olvide y gracias por esa explicación nene.
Gracias por la explicación realbrucest, a ver si luego trasteo un poco a ver cómo me sale. Lo que no había visto nunca son los tipos Fix16/32, si puedes explicarlos un poco y por qué hay que usarlos te lo agradecería.

nolddor escribió:Manveru si no es molestia podrías subir el codigo corregido conlos comandos del sgdk nuevo?

A ver si me acuerdo, he cambiado:
  • #include "mini_lib.h" por #include <genesis.h>
  • VDP_setPalette((u16 *) fondo_paleta, 0,16); por VDP_setPalette(PAL0, (u16 *) fondo_paleta);
  • // BUCLE PRINCIPAL ________________________________________________________
      while(1)
      {
        for(linea = 0; linea < NUM_LINEAS;  linea++)
        {
          VDP_setHorizontalScroll(APLAN, linea, fix16ToInt(scroll_lineas[linea]) );
    ....................

    por
    VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_PLANE);

    // BUCLE PRINCIPAL ________________________________________________________
      while(1)
      {
        u16 aux[NUM_LINEAS], n;
        for(n = 0; n < NUM_LINEAS; n++) aux[n] = fix16ToInt(scroll_lineas[n]);

        VDP_setHorizontalScrollLine(APLAN, 0, aux, NUM_LINEAS, 1 );

        for(linea = 0; linea < NUM_LINEAS;  linea++)
        {
    ...........................
Okis, pero me disculpáis aquí que no me explaye mucho.

Los "fixed point" o valores "en coma flotante" vienen a ser un sustitutivo para los valores decimales sin recurrir a auténticos datos de tipo "float" (por ejemplo).

En otras palabras, simular decimales cuando realmente estamos usando enteros.

Pensemos en base 10 que va a ser más fácil:

- Queremos un valor 0.1 por ejemplo para un incremento (que algo se mueva un pixel cada diez frames).
- Lo convertiríamos a nuestra "coma flotante en base 10" tal que así "valor_flotante = FLOTANTE10(0.1)"
- Usando el siguiente define: #define FLOTANTE(v) v*10000
- En ese momento ya tenemos un valor entero auténtico que es con el que realizaremos realmente las operaciones. Ejemplo flotante_suma = FLOTANTE(0.3) + FLOTANTE(0.5); suma = FLOTANTE_A_ENTERO(flotante_suma); Habiendo para el caso: #define FLOTANTE_A_ENTERO(v) v/10000

- A la hora de asignarse el "fixed point" a una coordenada de pantalla que requiere un entero hay siempre que reconvertir: fix16ToInt()

Vamos, que estamos operando realmente con valores multiplicados por n. Esa "n" con la que al multiplicar "convertimos" el entero normal en "fixed point" siempre viene a ser un múltiplo de 8 dado que tanto para dividir como para multiplicar se puede recurrir a operaciones de desplazamientos de bits que son muuuuuuucho más rápidas que las multiplicaciones y divisiones.

valor * 2 ======> valor << 1
valor * 4 ======> valor << 2
valor * 8 ======> valor << 3
valor * 16 ======> valor << 4

valor / 2 ======> valor >> 1
valor / 4 ======> valor >> 2
valor / 8 ======> valor >> 3
valor / 16 ======> valor >> 4

Hazte a la idea de que multiplicamos el valor entero por 1024 (<<10) para convertirlo en "fixed point", operamos en base a valores enteros multiplicados por 1024 que nos den resultados enteros, y al final, para ser aplicados dichos valores a coordenadas de pantalla definitivas dividimos el cómputo que hayamos obtenidos entre 1024 (>>10).

En líneas muy generales es algo así. Para más información tirad de google si no es mucho pedir :P
Buscad por "fixed point" que salen cosas como esta por ejemplo:
http://gameprogrammer.com/4-fixed.html
Perfecto realbrucest, estaba un poco confuso con el tema de por qué usar un nuevo tipo teniendo double o float, pero leyendo tu explicación y el inicio del artículo al que enlazas (es un poco tocho, luego lo leeré entero [+risas] ) creo que ya lo entiendo. Lo que me creo que no me queda claro es el tema de usar un múltiplo de 2. Entiendo que multiplicando por 10000 transformamos un decimal en entero, pero multiplicando por 1024 por ejemplo no siempre obtendremos un entero.
Acabo de ver en la propia web de las SGDK esta explicación de los fix16/32:

https://code.google.com/p/sgdk/wiki/SGDK_Math

Échale el ojo que es mucho más ligerita que el tocho enlazado y muy posiblemente te ahorre su lectura.

EDIT:

Manveru Ainu escribió:Lo que me creo que no me queda claro es el tema de usar un múltiplo de 2. Entiendo que multiplicando por 10000 transformamos un decimal en entero, pero multiplicando por 1024 por ejemplo no siempre obtendremos un entero.

Aissss ... entonces se me escapó hacer especial reseña en un dato crucial. No sé si hará falta una vez visto el enlace que he puesto en este post pero lo comento de todo modos:

Tanto los fix16 como fix32 son variables enteras. Por tanto da igual que la multiplicación diese decimales, al almacenarse el dato se discriminarían. El caso es "multiplicar" el dato base y "dividir" el resultado por un valor tan alto como sea posible para que la perdida de precisión sea mínima.

Te copypasteo los typedef de las SGDK (include/types.h):

typedef s16 fix16;
typedef s32 fix32;


En maths.h:
#define FIX16_INT_BITS 10
#define FIX16_FRAC_BITS (16 - FIX16_INT_BITS)

#define FIX16_INT_MASK (((1 << FIX16_INT_BITS) - 1) << FIX16_FRAC_BITS)
#define FIX16_FRAC_MASK ((1 << FIX16_FRAC_BITS) - 1)

/**
* \def FIX16
* Convert specified value to fix16
*
* Ex : f16 v = FIX16(-27.12);
*/
#define FIX16(value) ((fix16) ((value) * (1 << FIX16_FRAC_BITS)))

/**
* \def intToFix16
* Convert integer to fix16.
*/
#define intToFix16(value) ((value) << FIX16_FRAC_BITS)
/**
* \def fix16ToInt
* Convert fix16 to integer.
*/
#define fix16ToInt(value) ((value) >> FIX16_FRAC_BITS)
realbrucest escribió:Tanto los fix16 como fix32 son variables enteras. Por tanto da igual que la multiplicación diese decimales, al almacenarse el dato se discriminarían. El caso es "multiplicar" el dato base y "dividir" el resultado por un valor tan alto como sea posible para que la perdida de precisión sea mínima.

Ese es el dato que me faltaba. Sabía que fix16 y fix32 eran enteras pero no me encajaba lo de multiplicar por un número no múltiplo de 10, pero ahora veo lo de minimizar la pérdida de precisión ya que compensa en términos de eficiencia perder un poco de precisión a cambio de usar múltiplos de 2. Si no me equivoco, por el math.h, veo que para fix16 se multiplica/divide por 64 y para fix32 por 1024.

He estado toqueteando un poco el código y creo que ya sé bien como va, a ver si lo puedo integrar más adelante en algún juego que tenga medio montado, gracias de nuevo realbrucest.
Estoy tratando de compilar el ejemplo y tengo un problema haber si me echais una mano.
-Cuando pulso f9 me aparece este mensaje:
if seems that this project has not been built yet. Do you want built it now

Le doy que si y me aparece este mensaje en el compilador

-------------- Build: Debug in Prueba2 (compiler: Sega Megadrive)---------------

Running command: make.exe -f c:\sgdk\makefile.gen Debug
make: *** No rule to make target `Debug'.  Stop.
Process terminated with status 2 (0 minutes, 0 seconds)
0 errors, 0 warnings (0 minutes, 0 seconds)


He comprobado que las opciones de compilación son las correctas y no me crea los archivos de salida ni las carpetas, creo que esta fallando el make pero no veo donde
Comprueba que esté el SGDK bien instalado y el proyecto bien configurado siguiendo los tutos de pocket_lucho. De todas formas con F9 a mí me sale también lo de build the project aunque como estoy acostumbrado a usar ctrl+F11 y no me había dado cuenta, pero en cualquier caso me funciona.
He visto en el log debugger este mensaje
Building to ensure sources are up-to-date
Selecting target:
Debug
ERROR: You need to specify a debugger program in the debuggers's settings.
(For MinGW compilers, it's 'gdb.exe' (without the quotes))
(For MSVC compilers, it's 'cdb.exe' (without the quotes))


He ido a las opciones de global compiler settings y en debugger no puedo poner el que dice el tutorial solo permite invalid debugger o gdb/cdb default, estoy utilizando la version 12.11
A mí me pasó eso antes pero no recuerdo cómo lo resolví, creo que con poner el debugger por defecto bastaba.
Pues sí, el tutorial fue escrito en base a la anterior versión de Code:Blocks y a la hora de configurar cosas como el debugger no coinciden. Creo que lo que comenta Manveru Ainu viene a ser la solución sin más.

Os dejo la versión del código de la demo del efecto de los focos de luz que he adaptado a las sgdk (y "traducido" al inglés) para que Stef la pueda incluir a los ejemplos de su librería.

/******************************************************************************
  DEMO TEST SPOTLIGHT EFFECT (LINE SCROLL + SHADOW MODE)

******************************************************************************/
#include <genesis.h>

// CONSTANTS ==================================================================

// Some data to deal with graphical data
#define NUM_COLUMNS     40
#define NUM_ROWS        28
#define NUM_LINES       NUM_ROWS * 8

#define NUM_TILES_TILESET   3

// Places where we place tiles at Genesis VRAM
#define VRAM_POS_TILE1              1
#define VRAM_POS_BRICK_A            1
#define VRAM_POS_BRICK_B            2
#define VRAM_POS_TILE_VOID          3

// How many pixels bottom line is going to swing
#define SPOTLIGHT_SWING_RANGE       50

// Some other data
#define SPOTLIGHT_WIDTH             8
#define NUM_SPOTLIGHTS              NUM_COLUMNS / SPOTLIGHT_WIDTH

// TILESET ====================================================================
const u32 background_tileset[NUM_TILES_TILESET*8] =
{
    // TILE 1: brick left half
   0x11211111, 0x12222222, 0x12422222, 0x12242222, 0x12422222, 0x12222222, 0x12222222, 0x33333333,
   // TILE 2: brick right half
    0x11111113, 0x22222223, 0x22222223, 0x22222223, 0x22222223, 0x22222223, 0x22222223, 0x32333333,
   // TILE 3: empty/transparent tile
    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
};


// PALETTE ====================================================================
const u16 background_palette[16] = {
   0x0000,0x06CE,0x044E,0x0008,0x008C,0x0000,0x0000,0x0000,
   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
};


// MACROS =====================================================================
#define DrawWall(); \
    for(row = 0; row < NUM_ROWS; row += 2) \
    for(column = 0; column < NUM_COLUMNS; column += 2) \
    { \
       VDP_setTileMap( BPLAN, VRAM_POS_BRICK_A, column,   row); \
       VDP_setTileMap( BPLAN, VRAM_POS_BRICK_B, column+1, row); \
       VDP_setTileMap( BPLAN, VRAM_POS_BRICK_B, column,   row+1); \
       VDP_setTileMap( BPLAN, VRAM_POS_BRICK_A, column+1, row+1); \
    }

#define DrawSpotlights(); \
    for(row = 0; row < NUM_ROWS; row++) \
    for(column = 0; column < NUM_SPOTLIGHTS; column++) \
    for(tile_spotlight = 0; tile_spotlight < SPOTLIGHT_WIDTH; tile_spotlight++) \
    { \
       VDP_setTileMap( APLAN, TILE_ATTR_FULL(PAL0, column%2, 0, 0, VRAM_POS_TILE_VOID), \
          (column * SPOTLIGHT_WIDTH) + tile_spotlight, row); \
    }

#define InitializeScrollTable(); \
    for(line = 0; line < NUM_LINES; line++) line_scroll_data[line] = FIX16(0);

#define InitializeSpeedTable(); \
    line_speed_data[0] = FIX16(0.05); \
    for(line = 1; line < NUM_LINES; line++) \
       line_speed_data[line] = fix16Add(line_speed_data[line-1], FIX16(0.04));

//=============================================================================
// MAIN =======================================================================
//=============================================================================
int main()
{
    // Local data _____________________________________________________________

    // Indexes
    u8 row, column;     // Horizontal and vertical tile placement index/coords
    u8 line;            // Pixel line/row index
    u8 tile_spotlight;  // Horizontal tile counter for drawing spotlights
    u8 i;               // Auxiliar loop index

    // Line scroll buffers
    fix16 line_scroll_data[NUM_LINES];  // Current line scroll values
    fix16 line_speed_data[NUM_LINES];   // Line scroll speeds
    s16 aux[NUM_LINES];                 // Needed for VDP_setHorizontalScrollLine


    // Initialization lot _____________________________________________________

    // Scroll
    InitializeScrollTable();
    InitializeSpeedTable();


    // Process ________________________________________________________________

    // Screen setting
    VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_PLANE);
    VDP_setHilightShadow(1);    // Hilight/shadow activation

    // Loading tile stuff and color data into VRAM/CRAM
    VDP_setPalette(PAL0, (u16 *) background_palette);
    VDP_loadTileData( (const u32 *) background_tileset, VRAM_POS_TILE1, NUM_TILES_TILESET, 1);

    // Drawing
    DrawWall();
    DrawSpotlights();


    // MAIN LOOP ______________________________________________________________
    while(1)
    {
       for(line = 0; line < NUM_LINES;  line++)
        {
            // Sum the speed value
            line_scroll_data[line] = fix16Add(line_scroll_data[line], line_speed_data[line]);

            // Rebound when movement of bottom line reaches its left or right boundary
            if(line_scroll_data[NUM_LINES-1] >= FIX16(SPOTLIGHT_SWING_RANGE)
            || line_scroll_data[NUM_LINES-1] <= FIX16(-SPOTLIGHT_SWING_RANGE))
               line_speed_data[line] *= -1;

            // An auxiliar "regular integer" buffer is needed for VDP_setHorizontalScrollLine
            aux[line] = fix16ToInt(line_scroll_data[line]);

       }// end for(NUM_LINES)

        // Set Horizontal Scroll
        VDP_setHorizontalScrollLine(APLAN, 0, aux, NUM_LINES, 1);

      // Drawing/movement speed down
        for(i=0; i<4; i++) VDP_waitVSync();

    } // end main loop

    return 0;   // Ok ... we'll return something

} // end main()
Bueno he seguido investigando y para cambiar el debugger es en setting/debugger/default
pero el gdb.exe no se distribuye con el sgdk me he bajado otro y marca este error


Changing directory to: C:/DOCUME~1/yo/MYDOCU~1/Sega/Prueba2/.
Set variable: PATH=.;C:\sgdk\bin;C:\sgdk\bin\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\system32\wbem
Starting debugger: C:\MinGW\bin\gdb.exe -nx -fullname  -quiet  -args "C:/Documents and Settings/yo/My Documents/Sega/Prueba2/bin/Debug/Prueba2.exe"
done
Registered new type: wxString
Registered new type: STL String
Registered new type: STL Vector
Setting breakpoints
Debugger name and version: GNU gdb (GDB) 7.4
Starting the debuggee failed: No executable specified, use `target exec'.
Debugger finished with status 0
¿Me equivoco o el GDB que te has descargado es para arquitecturas x86?.
Date cuenta que en el log te dice que estás intentando depurar el programa "prueba2.exe", cuando tú lo que has compilado es un binario en formato Motorola 68k. De todas formas no tiene sentido intentar depurar usando el GDB cuando vas a ejecutar la rom en un emulador, para eso sería necesario tener conectada la consola al PC de algún modo y depurar de modo remoto. Si no puedes compilar la rom prueba a copiar el fichero makefile en el directorio donde tengas los fuentes y ejecutar el comando make desde línea de comandos en ese directorio, ya que el depurador en realidad no lo vas a usar.

De todos modos, si quieres tener el depurador para arquitecturas motorola te recomiendo que vayas a está página http://gnutoolchains.com/m68k-elf/ y te descargues el último toolchain de GCC actualizado para windows (El de las SGDK debe tener un porrón de años). Para usarlo hay que añadir el directorio donde se instalaron los binarios al path, y modificar el makefile para usar las herramientas actualizadas, simplemente añadiendo "m68k-elf-" al nombre del compilador y demás (p. ej: gcc -> m68k-elf-gcc, as-> m68-elf-as ...)
Pues seguramente no te equivoques pero porque no me crea el archivo bin sera que sgdk que me bajado es también de pc???, seguiré investigando
Una vez hayas indicado en "Compiler's intalation directory" ----> C:\SGDK\

... indica el gdb y los demás ejecutalbles marcándolos a partir de la ruta c:\sgdk\bin Ahí tienes el gdb.exe y todos los demás.

Edit: vale, me lo acabo de bajar y no [tomaaa] He subido la carpeta bin de mi instalación para que puedas echar mano de lo que te falte:

https://www.dropbox.com/s/ghro1aqoy8esnh6/sgdk-bin.zip
Yo también probé a poner el minGW cuando me daba ese fallo pero no me funcionó y no es necesario para que funcione. Siento no recordar cómo lo hice, pero me suena a ponerle al SGDK el debugger por defecto o algo así y con eso fue suficiente.
realbrucest, no viene en el archivo que has puesto el gdb.
Dios como odio el software libre!!!!!!!!!!!!! [buuuaaaa] [buuuaaaa] [buuuaaaa]
Karaculo escribió:realbrucest, no viene en el archivo que has puesto el gdb.
Dios como odio el software libre!!!!!!!!!!!!! [buuuaaaa] [buuuaaaa] [buuuaaaa]

No está tampoco en el zip que he subido a dropbox??

Si no, mañana te lo busco y te lo paso que ya me he quedado con el móvil sólo.
Acabo de hacer una búsqueda de archivos y efectivamente ... no tengo el gdb.exe por ningún lado.

Sin embargo no tengo ningún problema para compilar usando las sgdk.
A saber ...
:-?

Uso la versión 10.05 de Code:Blocks por cierto, pero el caso es que las sgdk salvo para cosas muy puntuales dejé de tocarlas así que tampoco sé decirte ahora cualquier cosa respecto a la configuración con total seguridad.
Chicos lo dejo compilar compila pero no me va, me voy con el de basic total me da igual el lenguaje y el proyecto que voy ha realizar no necesito mucha velocidad.
Os doy las gracias y lamento haber sido tan pesado.
Karaculo escribió:Chicos lo dejo compilar compila pero no me va, me voy con el de basic total me da igual el lenguaje y el proyecto que voy ha realizar no necesito mucha velocidad.
Os doy las gracias y lamento haber sido tan pesado.

¿Sabes que hay que compilarlo con el Code Blocks y luego ejecutarlo con un emulador no?
compilar compila pero no genera el binario, pero que da igual cuando tenga un poco de tiempo volveré al sgdk mientras tanto le doy caña al otro que ya lo prove y me iba bien
karaculo, no se bien q ejemplo querias compilar, pero si era el de highlight shadows, tengo en basic dl codigo basico para generar los efectos, si t interesa

Lo escribi hace unos meses para hacer un tutorial, y nunca tuve tiempo
Por si alguno de los presentes encuentra tiempo y le echa valor al asunto ... ;)

NEO Summer Retro Coding Contest 2013 for all retro platform announcement

News from Neoflash:

NEO Summer Retro Coding Contest 2013 for all retro platform announcement
*** Close time: Aug.20th 2013 ***
more info: http://www.neoflash.com/forum/index.php ... 624.0.html

* Homebrew Game division
There are top 3 winners for all platform

* Homebrew APP division
There are top 3 winners for all platform

Note: The platform just specify to the retro console, something like NES/PC-E/MD/SNES/N64/GBA/NDS/PSP/Wii ......

The rules of NEO Summer retro coding contest 2013:

[1] All original entries will get +5 "original score " , but the second entry (same project from last contest but improved, and just enter one more time again ) will don't get any "original score" in this contest.

[2] If your production have enter other contest before, you can use it to enter this NEO contest still.

[3] The No.1 winner from last Neo contest can't use their same project (even it come with many updated) to enter this contest again.

[4] You can submit more than one project for any platform at the same time, without any limit.

[5] You must put the NEO Retro Compo badge and NEO website link to your program and show it in the first page.


The top 3 prize list for the winners:
The No.1 : US$500 cash , OR choose any items from the NEO online shop, just not over U$800 total value.
The No.2 : US$300 cash , OR choose any items from the NEO online shop, just not over U$500 total value.
The No.3 : US$200 cash , OR choose any items from the NEO online shop, just not over U$300 total value.


Fuente: http://www.dcemu.co.uk/vbulletin/thread ... nouncement
theelf, que va era el hola mundo, compilar compilaba pero no generaba la rom, total era para aprender como funcionan los title así que iré primero a por el otro tutorial, intentare hacer el buscaminas cuando tenga un poco de tiempo (siempre estoy liado) para luego ir a palabras mayores. Y perdona por tardar tanto en contestar esta semana he estado en el inframundo
Bueno, otro regalito cocinado en la sala de máquinas de 1985alternativo para celebrar la pérdida de la chincheta xD

En este caso unos fuentes para las sgdk en donde se puede ver cómo simular sprites a cascoporro empleando scroll parallax.

Tómese como elemento didáctico. A la hora de meter tralla habría que ponerse a optimizar el código que es funcional para mostrar el efecto pero poco más.

Imagen

Proyecto de codeblcoks (src+bin)
Sólo rom

Nota: todo el código y comentarios están en en inglés porque lo creé para postearlo en spritesmind. Y como que estaba feo no traérselo para acá.

Gracias a doragasu por la solución al tearing.
tiene buen pinta, felicidades. :)
Muchas gracias realbrucest, se agradece un montón este tipo de ayuda.

Es una pena que estos hilos no tengan más actividad y nos quiten la chincheta, pero bueno con un poco de aquí y otro del oficial hay info muy útil para los que nos interesamos por este mundillo.
Muchas gracias!!!
No hay mejor tuto de programacion que un codigo fuente comentado!!! ;)
Hola estoy teniendo problemas con los gráficos...

Veamos con photoshop he creado una imagen con 15 colores distintos en modo indexado y guardado en bmp 4bits. Al pasarlo con el Imagénesis para sacarle la paleta resulta que me crea una paleta incorrecta y además me cambia los colores del dibujo original...

¿Sabéis que puede estar pasando y como solucionarlo?


--------------Antes ----------------------------------- Después--------------------

Imagen
343 respuestas
13, 4, 5, 6, 7