Pintando sprites de 16x16 en ensamblador
Publicado: Jue, 05 Dic 2013, 20:55
Estoy trabajando en una rutina para imprimir sprites de 16x16 pixels a color (si, para movimiento a caracter).
El sprite estarÃa representado de forma lineal, byte a byte, desde la esquina superior izquierda a la inferior derecha, y luego los cuatro bytes de color en el mismo orden.
La rutina en concreto es la de mi curso de ensamblador, y la versión para Z88DK es:
$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
push de ; salvamos los valores vertical y horizontal
push de ; salvamos los valores vertical y horizontal
push de ; salvamos los valores vertical y horizontal
call cdrw ; calculamos dirección de pantalla
ld b, 8
call draw
pop de ; recuperamos el valor horizontal
inc d ; incrementamos una lÃnea
call cdrw
ld b, 8
call draw
; Ahora imprimimos los atributos
pop de ; recuperamos el valor horizontal
call cdrw
call catr
call colr
pop de ; recuperamos el valor horizontal
inc d ; incrementamos una lÃnea
call cdrw
call catr
call colr
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
.cdrw
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
ret
.catr
ld a,d
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
#endasm
}
')
La cuestión es que la veo lenta, y querÃa preguntaros que mejoras se le podrÃa hacer.
Por cierto, ¿cómo demonios se puede trabajar con puertos desde Z88DK y ensamblador? Es que la instrucción out no la reconoce (o no se como ponerla para que la reconozca).
El sprite estarÃa representado de forma lineal, byte a byte, desde la esquina superior izquierda a la inferior derecha, y luego los cuatro bytes de color en el mismo orden.
La rutina en concreto es la de mi curso de ensamblador, y la versión para Z88DK es:
$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
push de ; salvamos los valores vertical y horizontal
push de ; salvamos los valores vertical y horizontal
push de ; salvamos los valores vertical y horizontal
call cdrw ; calculamos dirección de pantalla
ld b, 8
call draw
pop de ; recuperamos el valor horizontal
inc d ; incrementamos una lÃnea
call cdrw
ld b, 8
call draw
; Ahora imprimimos los atributos
pop de ; recuperamos el valor horizontal
call cdrw
call catr
call colr
pop de ; recuperamos el valor horizontal
inc d ; incrementamos una lÃnea
call cdrw
call catr
call colr
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
.cdrw
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
ret
.catr
ld a,d
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
#endasm
}
')
La cuestión es que la veo lenta, y querÃa preguntaros que mejoras se le podrÃa hacer.
Por cierto, ¿cómo demonios se puede trabajar con puertos desde Z88DK y ensamblador? Es que la instrucción out no la reconoce (o no se como ponerla para que la reconozca).