https://www.segasaturno.com/portal/viewtopic.php?f=33&t=3970&p=26822#p26822
-----------------------------------
FacundoARG
09 Agosto 2009, 12:02 PM

[Homebrew] [VDP1] - Controlando Sprites.
-----------------------------------
Tomando en cuenta lo básico para alimentar el espíritu, vamos a ver los ansiados Sprites. 

[align=center][youtube]EK0gXahhWic[/youtube][/align]

Para comenzar:

[list]
    [*] Nivel de dificultad: fácil.
    [*] Lenguaje: ANSI C/C++.
    [*] Herramientas: SaturnOrbit, 3Deditor
[/list]


Copiamos el ejemplo [b]S_2_2 [/b]de la carpeta [b]C:SaturnOrbitSGL_302jSAMPLE[/b] en la raiz del disco [b]C:[/b] ó donde quieran.

Cambiamos las rutas necesarias para que compile, si no sabes como hacerlo [url=http://www.segasaturno.com/portal/viewtopic.php?f=4&t=3932]aca podes ver el como. 

[hr]

Lo que tenemos que saber, es que existen dos formas de tomar datos en Sega Saturn, ó lo hacemos levantando un binario desde el directorio del CD ó 
lo incluimos dentro del [b]main.c[/b] . Nosotros vamos a ver la segunda opción. 

En Sega Saturn, las texturas y los sprites son considerados la misma cosa. 

Vamos a prepartar los datos necesarios.

Utilizando la herramienta [b]3Deditor[/b] dentro del [b]SegaSaturnSDK (C:SaturnOrbitTOOLSSSSDK)[/b] .
La abrimos, vamos a View  y tildamos texture list.

[img]http://www.segasaturno.com/portal/files/images/1077/vdp1_1.png[/img]

Antes debemos saber que todas las imagenes deben ser multipo de 8, tanto en x como en y. En mi caso son todas de 48x48. 

Normalmente los estandares para estas consolas son de 16x16,32x32 ó 64x64. 
El color usado como transparencia, es el [b]0x0000[/b] osea el negro. Por lo tanto todo sprite que tenga este color lo debes cambiar por [b]0x8000[/b] así de esta forma se verá.

Como mis sprites tiene este color los voy a reemplazar uno por uno por [b]0x8000[/b], usen algun editor de texto, sino va a largar todo por la ventana  :P .
Luego para obtener las tranparencias, yo utilize el Magenta (es horrible) que es el color [b]0xfc1f[/b] a este lo cambio por el [b]0x0000 [/b](que es el que Saturn no pinta).


Vamos a [b]File[/b],[b] Import[/b] y seleccionamos las imagenes que queremos.

[img]http://www.segasaturno.com/portal/files/images/1077/vdp1_2.png[/img]

Guardamos el archivo con formato [b].TXR[/b]; en mi caso [b]SonicX.TXR[/b]

Un Archito TXR tiene las siguientes estructuras:
[list]
 [*][b]Uint16 texture_SonicX000[][/b] : Son los datos de los colores, pixel por pixel en 15bits.

[*][b]TEXTURE	tex_SonicX[] [/b]: Es la tabla con las sprites/texturas medidas en bytes.

[*][b]PICTURE	pic_SonicX[][/b]: Es la tabla sprites/texturas determinando el color de cada uno de los sprites. Podemos utilizar distintos tipos de colores por cada uno.

[*][b]SPR_ATTR attr_SonicX[] [/b]: Aca van los atriburos de los sprites, esta tabla la tenemos que escribir a mano, todos los sprites son llamados desde esta tabla, ademas podemos especificar si tiene flip, grourad y paleteado.
[/list]

[hr]

En mi caso tengo dos tablas, una con los [b]Datos originales[/b], y otra con los invertidos (con [b]flip horizontal[/b])

Les dejo las talbas que deben pegar donde quiera, yo las pegue junto al [b]SonicX.TXR[/b]


[codeblock]
Uint16	texture_SonicX000[] = {}
	
........
Uint16	texture_SonicX010[] = {}

TEXTURE	tex_SonicX[] = {}

	TEXTBL( 48, 48, CGADDRESS+0),
	TEXTBL( 48, 48, CGADDRESS+4608),
        ..............
	TEXTBL( 48, 48, CGADDRESS+46080),
};

PICTURE	pic_SonicX[] = {
	PICTBL(  0, COL_32K, texture_SonicX000),
        ...........
	PICTBL( 10, COL_32K, texture_SonicX010),
};

SPR_ATTR attr_SonicX[] = {
	SPR_ATTRIBUTE(0,No_Palet,No_Gouraud,CL32KRGB|SPenb|ECdis,sprNoflip),	
	............
	SPR_ATTRIBUTE(10,No_Palet,No_Gouraud,CL32KRGB|SPenb|ECdis,sprNoflip),
};

SPR_ATTR attr_SonicX_flip[] = {
	SPR_ATTRIBUTE(0,No_Palet,No_Gouraud,CL32KRGB|SPenb|ECdis,sprHflip),	
        .............
	SPR_ATTRIBUTE(10,No_Palet,No_Gouraud,CL32KRGB|SPenb|ECdis,sprHflip),
};

[/codeblock]

Una vez que tenmos todo esto listo, vamos a comenzar con el codigo
primero debemos inlcuir en nuestro [b]main.c[/b] el archivo [b]SonicX.TXR [/b]   
 
[b]#include    "SonicX.txr"[/b]

Ahora necesitamos inicializar la lista con los sprites/texturas. 

[b]slInitSystem(TV_320x240, tex_SonicX , 1);[/b]

Luego necesitamos copiar los sprites/texturas a la memoria del [b]VDP1[/b]. 
Con la siguiente función (la extraje de un ejemplo) copiamos los sprites a la memoria, asi que debemos incluirla en el [b]main.c[/b] .


[b]static void set_sprite(PICTURE *pcptr, Uint32 NbPicture, TEXTURE *texptr)
{
	TEXTURE *txptr;
 
	for(; NbPicture-- > 0; pcptr++){
		txptr = texptr + pcptr->texno;
		slDMACopy((void *)pcptr->pcsrc,
			(void *)(SpriteVRAM + ((txptr->CGadr) << 3)),
			(Uint32)((txptr->Hsize * txptr->Vsize * 4) >> (pcptr->cmode)));
	}
}[/b]

Para llamar a esta funcion le pasamos los parametros correspondientes
[b]
set_sprite(pic_SonicX, 11, tex_SonicX);[/b]

El segundo parametro indica, la cantidad de sprites/texturas que tenemos, si te equivocas, el sistema va a leer una posición erronea y se va a corromper algun sprite (lo vas a ver feo).


Ahora vamos a mostrar dentro del bucle [b]while [/b]los sprites. Los sprites se deben mostrar siempre y debe existir la función 	[b]slSynch() [/b]para sincronizar con el sistema.

Según los manuales hay varias funciones para mostrar sprite, vamos a ver la más simple.

[b]
slDispSprite(FIXED pos, SPR_ATTR *atr, ANGLE Zrot);[/b]

El primer parametro es un vector, de cuatro componentes que indican, X,Y,Z y S que es la escala.
El segundo es la tabla que tuvimos que escribir a mano, le tenemos que pasar la variable más el número de sprite que queremos mostrar. 
El Tercero, es el angulo de rotación en la que se va a mostrar.

Por ejemplo para ver el escudo re [b]River Plate[/b]  :twisted:  :

El Sprite de River es el numero 11, pero como comienza de 0, entonces es el 10.

[b]FIXED pos_river[XYZS] = {toFIXED(60.0), toFIXED(60.0), toFIXED(169), toFIXED(1.0)};
ANGLE ang_river = DEGtoANG(0.0);
slDispSprite(pos_river, attr_SonicX + 10, ang_river);[/b]


Ahora ponemos una variable para que paresca un sprite y no una imagen estática.

[b]Uint32 sprite_walk_ID=0;
Uint32 sprite_running_ID=6;[/b]

Estas son para Sonic caminando y corriendo respectivamente. En cada ciclo debemos incrementar el número, pero también controlar que no se pase, sino va a mostrar otros sprites y no queremos eso  :wink:  .

Entonces cada vez que se pase, lo volvemos al inicio:
[b]
   if(sprite_walk_ID>=5)
        {    sprite_walk_ID=0;
        }     	
        if(sprite_running_ID>=9)
        {    sprite_running_ID=6;
        }[/b]


Con Sonic caminando muestro los sprites usando la primera trabla que creé.

[b] slDispSprite(pos1, attr_SonicX + sprite_walk_ID, ang1);[/b]

Con Sonic corriendo muestro los sprites usando la segunda trabla (la invertida).

[b] slDispSprite(pos2, attr_SonicX_flip + sprite_running_ID, ang1);[/b]

Todo esto me sirve para ahorrar memoria y no tener que cargar los sprites invertidos.

[hr]

Les paso el código del [b]main.c[/b]


[codeblock]
#include	"sgl.h"
#include    "SonicX.txr"

static void set_sprite(PICTURE *pcptr, Uint32 NbPicture, TEXTURE *texptr)
{
	TEXTURE *txptr;
 
	for(; NbPicture-- > 0; pcptr++){
		txptr = texptr + pcptr->texno;
		slDMACopy((void *)pcptr->pcsrc,
			(void *)(SpriteVRAM + ((txptr->CGadr) << 3)),
			(Uint32)((txptr->Hsize * txptr->Vsize * 4) >> (pcptr->cmode)));
	}
}

void ss_main(void)
{
	static ANGLE	ang[XYZ];
	static FIXED	pos[XYZ];
    //Inicializamos el sistema con los sprites---------------------------- 
	slInitSystem(TV_320x240, tex_SonicX , 1);
	
    //Pintamos el fondo de color azul, asi comprobamos que el negro se ve.
    slBack1ColSet((void *)BACK_CRAM, CD_Blue);
    
    //Cargamos al VDP1 los sprites----------------------------------------
        set_sprite(pic_SonicX, 11, tex_SonicX);    
	slPrint("VDP1 - Sprite Manipulation", slLocate(9,2));
	slPrint("www.segasaturno.com", slLocate(9,3));
        slPrint("Jano Dev Team - FacundoARG",slLocate(12,28));
    
    FIXED pos1[XYZS] = {toFIXED(-60.0), toFIXED(0.0), toFIXED(169), toFIXED(1.0)};
    ANGLE ang1 = DEGtoANG(0.0);
    
    FIXED pos2[XYZS] = {toFIXED(60.0), toFIXED(0.0), toFIXED(169), toFIXED(1.0)};
    
    FIXED pos_river[XYZS] = {toFIXED(0.0), toFIXED(0.0), toFIXED(169), toFIXED(1.0)};
    ANGLE ang_river = DEGtoANG(0.0);
    
    //Para usar con el escudo de River Plate
	pos[X] = toFIXED(  0.0);
	pos[Y] = toFIXED(  0.0);

    Uint32 sprite_walk_ID=0;
    Uint32 sprite_running_ID=6;
    
	while(-1){
	
		if((Per_Connect1) == 0)
            {slPrint("No conectaste el PAD",slLocate(2,20));}
       
        //Pintamos los sprites.----------------------------------------
        slDispSprite(pos1, attr_SonicX + sprite_walk_ID, ang1);        
        slDispSprite(pos2, attr_SonicX_flip + sprite_running_ID, ang1);        	
        slDispSprite(pos_river, attr_SonicX + 10, ang_river);
        	
        //Incrementamos la posicion en la tabla-------------------------
        sprite_walk_ID++;
        sprite_running_ID++;
        	
        if(sprite_walk_ID>=5)
        {    sprite_walk_ID=0;}     	

        if(sprite_running_ID>=9)
        {    sprite_running_ID=6;}   		
        
        Uint8 index=0;
         //Controlando KEY-PAD------------------------------
        if( (Smpc_Peripheral[index].data & PER_DGT_KU) == 0)
            {   pos[Y] = pos[Y] - toFIXED(  5.0);
                pos_river[Y] = pos[Y];
            }
        if( (Smpc_Peripheral[index].data & PER_DGT_KR) == 0)
            {  pos[X] = pos[X] + toFIXED(  5.0);
                pos_river[X] = pos[X];
            }
        if( (Smpc_Peripheral[index].data & PER_DGT_KD) == 0)
            {  pos[Y] = pos[Y] + toFIXED(  5.0);
                pos_river[Y] = pos[Y];
            }
        if( (Smpc_Peripheral[index].data & PER_DGT_KL) == 0)
            {  pos[X] = pos[X] - toFIXED(  5.0);
                pos_river[X] = pos[X]; }

        if( (Smpc_Peripheral[index].data & PER_DGT_TL) == 0)
            {ang_river = ang_river - DEGtoANG(5.0);}

        if( (Smpc_Peripheral[index].data & PER_DGT_TR) == 0)
            {ang_river = ang_river + DEGtoANG(5.0);}
                		      		
		slSynch();
	}
}
[/codeblock]


