Página 2 de 6

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Vie, 06 Dic 2013, 18:50
por antoniovillena
Pues sí, he dicho lo mismo que propuso na_th_an, no me había dado cuenta. Yo también tengo por ahí una rutinilla rápida, es para tiles pero te valdría también. Pero vamos, que la mejor rutina es la que se te ocurra a tí.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Vie, 06 Dic 2013, 19:18
por radastan
Hombre, evidentemente preferiría hacer la rutina yo para entenderla mejor. Si ya veo que me apuro de tiempo te pido ayuda directamente, pero creo que no hay prisa en sacar el tutorial. Lo estoy haciendo en tiempos muertos, cuando me canso de los otros proyectos.

Otra cosa son las rutinas pixel a pixel, que ahí ya directamente veremos lo que hago porque el tutorial va a ser con sprites caracter a caracter por narices (por sencillez). Lo mismo le dedico un anexo o algo, no se.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Vie, 06 Dic 2013, 22:15
por antoniovillena
Me acabo de encontrar esta perla por internet. Aquí te lo explican todo sobre los sprites, incluso cómo calcular la dirección mediante una tabla.

http://www.bobs-stuff.co.uk/sprites.rtf

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Vie, 06 Dic 2013, 23:15
por radastan
Vale, ya está más optimizado:

$this->bbcode_second_pass_code('', '
void put_sprite_x16 (unsigned char *posicion, unsigned int x, unsigned int y)
{
// -------------------------------------------
// RUTINA DE IMPRESION DE UN SPRITE 16x16 PIXELS
// CON ATRIBUTOS EN CUALQUIER POSICION DE CARACTER
// ENTRADAS:
// D será la posición del cursor vertical en caracteres
// E será la posición del cursor horizontal en caracteres
// HL es la posición de memoria donde tenemos el sprite
// SALIDAS: se escribe en el mapa de pantalla
// ADVERTENCIAS: no comprueba límites de pantalla
// -------------------------------------------
#asm
ld hl,2 ;pasamos la variable de entrada al acumulador
add hl,sp
ld d, (hl)
inc hl
inc hl
ld e, (hl)
inc hl
inc hl
ld a, (hl)
inc hl
ld h, (hl)
ld l, a
ld a, d ; recuperamos el valor vertical
and 7 ; nos quedamos con la posición en el tercio
rrca
rrca
rrca ; rotamos para dejar su valor en múltiplos de 32 (linea)
and 224 ; borramos el resto de bits por si las moscas
or e ; sumamos el valor horizontal
ld e, a ; e preparado
ld a, d
and 24 ; modificamos según el tercio de pantalla
or 64 ; nos posicionamos a partir de 16384 (16384=64+0 en dos bytes)
ld d, a ; d preparado, ya tenemos la posición en pantalla
push de ; guardamos DE (la posición de pantalla)
push de
ld b, 8
call draw
pop de ; recuperamos DE
ld a,e ; incrementamos una línea de caracteres (+32 bytes)
add 32
ld e,a
ld a,d
adc 0 ; aquí finaliza la suma de 32 a DE
ld d,a
ld b, 8
call draw
; Ahora imprimimos los atributos
pop de ; recuperamos el valor horizontal
ld a,d ; calculamos el valor de posición en la pantalla
rra
rra
rra ; multiplicamos por 32
and 3 ; nos quedamos con los tres bits bajos
or 88 ; apuntamos al comienzo del mapa de atributos
ld d,a ; ya tenemos d listo, e no hay que cambiarlo
push de ; guardamos la posición en pantalla
call colr ; imprimimos los colores de arriba
pop de ; recuperamos la posición de pantalla
ld a,e ; incrementamos una línea de caracteres (+32 bytes)
add 32
ld e,a
ld a,d
adc 0 ; aquí finaliza la suma de 32 a DE
call colr ; ponemos los colores de abajo
ret

.draw
ld a, (hl) ; HL indica la posición del sprite en memoria
ld (de),a ; de indica la posición de pantalla
inc hl
inc e
ld a,(hl) ; esta parte imprime el segundo byte
ld (de),a
inc hl
dec e
inc d
djnz draw ; decrementa B y si es cero deja de saltar a draw
ret

.colr
ld a,(hl)
ld (de),a
inc e
inc hl
ld a,(hl)
ld (de),a
dec e
inc hl
ret

#endasm
}
')

He echo que sólo se calcule una vez la posición en pantalla en los dos submapas de pantalla, cambiando el recálculo por sumar 32 (que es lo lógico) para calcular la siguiente línea. De paso he recolocado las dos subrutinas de cálculo directamente a su sitio (para evitar saltos).

¿Algún consejo más que no suponga uso de tablas?

Ya se que con una tabla iría aún más rápido, pero quiero evitar complicaciones innecesarias de momento en el código.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Vie, 06 Dic 2013, 23:19
por radastan
$this->bbcode_second_pass_quote('antoniovillena', 'M')e acabo de encontrar esta perla por internet. Aquí te lo explican todo sobre los sprites, incluso cómo calcular la dirección mediante una tabla.

http://www.bobs-stuff.co.uk/sprites.rtf


:lol:

Lo he visto, pero me parece lioso. Como lo estamos haciendo en este hilo es lo correcto, poco a poco y comprendiendo el porqué de cada optimización.

Se que usando una tabla de 48 bytes optimizo algo más, pero prefiero dejarlo para el final y sólo si veo que realmente marca una gran diferencia.

Por cierto, he modificado el fichero que subí, para que puedas volver a medirlo.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Vie, 06 Dic 2013, 23:58
por antoniovillena
Sugerencia, cambia los call colr por ldi / ldi. Y haz también algo parecido en los draw.

$this->bbcode_second_pass_code('', '
push de ; guardamos la posición en pantalla
ldi
ldi
pop de ; recuperamos la posición de pantalla
ld a,e ; incrementamos una línea de caracteres (+32 bytes)
add 32
ld e,a
ld a,d
adc 0 ; aquí finaliza la suma de 32 a DE
ldi
ldi
ret
')

Usa hexadecimal siempre que quede más claro que decimal, por ejemplo yo veo más claro $58 que 88. Normalmente en hexadecimal son más fáciles de recordar las direcciones, $5800 es más fácil que 22528.

Y otra cosa, aunque tu ensamblador se lo trague, trata de usar siempre instrucciones normalizadas para que la gente pueda usar tu código sin problemas. Add 32 no existe como instrucción, lo correcto sería add a,32

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 00:33
por radastan
$this->bbcode_second_pass_quote('antoniovillena', 'S')ugerencia, cambia los call colr por ldi / ldi.


Se me acaban de caer los cojones al suelo... :shock:

Ni se me había pasado por la cabeza, oiga. Es lo que tiene estar con el ensamblador a ratos, se me olvida la potencia del LDI y del LDD.

Por cierto, he cambiado la parte de DRAW por:

$this->bbcode_second_pass_code('', '
.draw
ldi
ldi
dec e
dec e
inc d
djnz draw ; decrementa B y si es cero deja de saltar a draw
ret
')

Pero me salen algunos sprites raros, los demás perfectos. ¿en qué he metido la pata?

Es decir, LDI decrementa BC, pero si hago C = 255 al principio de la rutina por mucho que decremente ni de coña debería afecta a B.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 00:40
por antoniovillena
El tiempo que me da es 1571 ciclos, 49 ciclos/byte. Lo mejor es que lo midas con Ticks. Al final del make.bat pon algo como esto (antes de borrar juego.bin):

$this->bbcode_second_pass_code('', '
copy /b comi.txt+juego.bin ticks.bin
Ticks ticks.bin -pc 5e88 -s 60f6 -e 60f9
')

El comi.txt bájatelo de aquí (es binario pero lo he renombrado porque el foro no me permite subir la extensión .bin)

Nota: Quizás te parezca una tontería, puesto que esto mismo se puede medir con un emulador y puntos de ruptura, pero una vez le coges el truco a esto del Ticks el tiempo que te ahorras en contar ciclos mientras optimizas una rutina es brutal.

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 00:54
por radastan
Vale, fallo mío, decrementaba E y tenía que decrementar DE:

$this->bbcode_second_pass_code('', '
.draw
ldi
ldi
dec de
dec de
inc d
djnz draw ; decrementa B y si es cero deja de saltar a draw
ret
')

El código completo optimizado:

$this->bbcode_second_pass_code('', '
void put_sprite_x16 (unsigned char *posicion, unsigned int x, unsigned int y)
{
// -------------------------------------------
// RUTINA DE IMPRESION DE UN SPRITE 16x16 PIXELS
// CON ATRIBUTOS EN CUALQUIER POSICION DE CARACTER
// ENTRADAS:
// D será la posición del cursor vertical en caracteres
// E será la posición del cursor horizontal en caracteres
// HL es la posición de memoria donde tenemos el sprite
// SALIDAS: se escribe en el mapa de pantalla
// ADVERTENCIAS: no comprueba límites de pantalla
// -------------------------------------------
#asm
ld hl,2 ;pasamos la variable de entrada al acumulador
add hl,sp
ld d, (hl)
inc hl
inc hl
ld e, (hl)
inc hl
inc hl
ld a, (hl)
inc hl
ld h, (hl)
ld l, a
ld a, d ; recuperamos el valor vertical
and 7 ; nos quedamos con la posición en el tercio
rrca
rrca
rrca ; rotamos para dejar su valor en múltiplos de 32 (linea)
and 224 ; borramos el resto de bits por si las moscas
or e ; sumamos el valor horizontal
ld e, a ; e preparado
ld a, d
and 24 ; modificamos según el tercio de pantalla
or 64 ; nos posicionamos a partir de 16384 (16384=64+0 en dos bytes)
ld d, a ; d preparado, ya tenemos la posición en pantalla
push de ; guardamos DE (la posición de pantalla)
push de
ld b, 8
ld c,255 ; cargamos C con 255 para no afectar B con LDI
call draw
pop de ; recuperamos DE
ld a,e ; incrementamos una línea de caracteres (+32 bytes)
add a,32
ld e,a
ld a,d
adc a,0 ; aquí finaliza la suma de 32 a DE
ld d,a
ld b, 8
call draw
; Ahora imprimimos los atributos
pop de ; recuperamos el valor horizontal
ld a,d ; calculamos el valor de posición en la pantalla
rra
rra
rra ; multiplicamos por 32
and 3 ; nos quedamos con los tres bits bajos
or 88 ; apuntamos al comienzo del mapa de atributos
ld d,a ; ya tenemos d listo, e no hay que cambiarlo
push de ; guardamos la posición en pantalla
ldi ; imprimimos los colores de arriba
ldi
pop de ; recuperamos la posición de pantalla
ld a,e ; incrementamos una línea de caracteres (+32 bytes)
add a,32
ld e,a
ld a,d
adc a,0 ; aquí finaliza la suma de 32 a DE
ldi ; ponemos los colores de abajo
ldi
ret

.draw
ldi
ldi
dec de
dec de
inc d
djnz draw ; decrementa B y si es cero deja de saltar a draw
ret

#endasm
}
')

Re: Pintando sprites de 16x16 en ensamblador

Publicado: Sab, 07 Dic 2013, 00:56
por radastan
$this->bbcode_second_pass_quote('antoniovillena', 'E')l tiempo que me da es 1571 ciclos, 49 ciclos/byte.


Vamos, que con unas pocas optimizaciones hemos casi duplicado la rapidez de la rutina.

:corchoneta: :corchoneta: :corchoneta:

Gracias por la ayuda, tanto la tuya como la de na_th_an, se ha quedado cojonudo.