Zx Spectrum: rutina en ensamblador para manejar SPRITES

Foro dedicado a la programación en todo tipo de sistemas clásicos.
Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES

Mensajepor Bubu » 17 Nov 2018, 02:05

Estoy avanzando, y ya puedo modificar la imagen de los sprites "on the fly", pero obsérvese que se produce cierto parpaeo (flicker) el cual nu sé evitar:


https://www.youtube.com/watch?v=vTYiipVP-bE

Lo que hago es dibujar la mariposa, dibujar encima el fondo, dibujar encima la mariposa con las alas más plegadas, dibujar encima el fondo, dibujar encima la mariposa con las alas aún más plegadas, etc, y creo que el parpadeo se produce por estar tol rato dibujando el fondo encima del sprite, y el sprite encima del fondo.
¿Creéis que esto se puede evitar con el tema de pintar cuando la ULA no esté pintando la pantalla? Es que nu sé hacer eso, a ver si alguien me asesora.
Otra solución que me se ocurre es pintar el fondo y encima el sprite pero no en pantalla, si no en otro buffer, y pasar el buffer a la pantalla.
¿Qué pensáis al respesto?
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
jltursan
Amiga 2500
Amiga 2500
Mensajes: 4028
Registrado: 13 Oct 2006, 19:45
Sistema Favorito: MSX
primer_sistema: Dragon
Ubicación: Serracines, Madrid, España
Gracias dadas: 57 veces
Gracias recibidas: 157 veces
Contactar:

Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES

Mensajepor jltursan » 17 Nov 2018, 17:43

Pues que hay mil maneras de abordar las rutinas de sprites... :)

Lo primero es corregir efectivamente lo que indicas. Con un simple HALT sincronizas la ejecución con el comienzo de la generación del cuadro de pantalla. Es decir, tras el HALT, el haz de electrones se encuentra algo por encima del border (no recuerdo las cifras exactas), si comienzas a dibujar y hasta que el haz baje lo suficiente para pillarte, podrás hacer lo que quieras sin que se vea.

El problema de lo anterior es que una vez que el haz entra en el área visible es una carrera entre él y tu dibujado; cuando te pille aparecerá el "tearing", a esto se le conoce como "racing the beam" y normalmente acaba mal, te pilla rápido :evil:
Esto se puede solucionar de diversas formas (dejando aparte que la rutina de volcado del sprite sea ultrarápida, que eso es una ciencia aparte); por ejemplo, puedes ganar algo de tiempo si la parte de arriba no contiene nunca sprites: un marcador, un marco, etc., con ello ganas algo de tiempo. También puedes ordenar la lista de sprites a dibujar en base a su coordenada Y, empezando primero por los que la tengan menor y acabando con los de Y mayor, así te vas quitando primero los sprites que antes van a ser "pillados"
Más cosas, también puedes evitar el borrar todo el sprite de golpe y luego dibujar el nuevo. Si lo vas haciendo línea a línea (borras línea, pintas nueva, bajas a la siguiente linea y repites) reduces bastante el feo efecto a costa de perder algo de velocidad e incrementando la complejidad de la rutina.

Me dejo para el final la mejor de las soluciones: el doble buffer. Emplea un área de memoria (reducida a lo que realmente sea el área de dibujado, ganarás memoria y velocidad) diferente a la pantalla del Spectrum y dibuja sobre ella lo que te venga en gana. Obviamente no verás nada. Cuando acabes, debes de volcarla a la zona visible en 16384; sincroniza con HALT y vuelca lo más rápido que puedas. Con esta técnica obtendrás 0 parpadeos y sólo la velocidad del Z80 limitará lo que hagas en pantalla hasta que el juego se arrastre.

La mejor técnica para mover un gran bloque de memoria puede pasar por usar un LDIR; pero eso no te dará la velocidad necesaria, puedes usar también un chorro de LDIs, que mejora bastante el asunto; pero lo que es definitivo es un stack-blasting usando POP-PUSH para mover dos bytes cada vez. Esta última es la técnica más rápida; pero es complicadilla ya que hay que cambiar de sitio la pila (con lo que las interrupciones peligran) y hacer malabarismos con todos los registros del Z80 que puedas para poder encadenar todos los POP-PUSH que puedas.

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES

Mensajepor Bubu » 17 Nov 2018, 18:49

Meraviglioso, jltursan. Procedo a estudiar tu mensaje.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES

Mensajepor Bubu » 18 Nov 2018, 21:27

OK, ya.

:D

Voy a optar por el doble buffer. Creo que la cosa es así: tengo 4 zonas de memoria donde dibujar:

(1) La VRAM, es la pantalla en sí. Hay que pintar ahí el mínimo número de veces pues es lenta, y además es una carrera contra el raster del TV como tú bien dices.
(2) Los sprites en RAM. Aquí estarían los dibujos de los sprites puros y duros
(3) Un buffer para el fondo. Aquí tendríamos el trozo de fondo que va debajo de cada sprite.
(4) Un segundo buffer : el área de mezcla. En este buffer voy a pintar el fondo y encima el sprite (con OR), y cuando haga el HALT volcaré esa zona direstamente en pantalla.

Lo que había yo hecho hasta ahora esta pintar (3) en (1), y tórrápido pintar (2) en (1) con OR. Ahora lo que voy a hacer es mezclar (2) con (3) en (4), y pintar (4) en (1) tras el HALT.
A ver si así evito el parpadeo, y muchas gracias, jltursan
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
explorer
MSX Turbo R
MSX Turbo R
Mensajes: 398
Registrado: 11 May 2014, 17:10
Sistema Favorito: Atari ST
primer_sistema: Atari 800XL/600XL
consola_favorita: Atari 2600
Primera consola: Atari 2600
Ubicación: Valladolid, España
Gracias dadas: 2 veces
Gracias recibidas: 138 veces
Contactar:

Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES

Mensajepor explorer » 19 Nov 2018, 03:45

Bubu escribió:(1) La VRAM, es la pantalla en sí. Hay que pintar ahí el mínimo número de veces pues es lenta, y además es una carrera contra el raster del TV como tú bien dices.
(2) Los sprites en RAM. Aquí estarían los dibujos de los sprites puros y duros
(3) Un buffer para el fondo. Aquí tendríamos el trozo de fondo que va debajo de cada sprite.
(4) Un segundo buffer : el área de mezcla. En este buffer voy a pintar el fondo y encima el sprite (con OR), y cuando haga el HALT volcaré esa zona direstamente en pantalla.

(5) Rehacer el fondo en el búfer a partir de los datos de la pantalla para borrar los sprites de la presentación o cuadro anterior.
Bubu escribió:Lo que había yo hecho hasta ahora esta pintar (3) en (1), y tórrápido pintar (2) en (1) con OR. Ahora lo que voy a hacer es mezclar (2) con (3) en (4), y pintar (4) en (1) tras el HALT.
A ver si así evito el parpadeo.

Hay... ciertas cosas que hay que saber para usar el HALT. Si vas a realizar un proceso que ocupa menos de 1/50 de segundo, entonces al hacer el HALT te garantiza que siempre se dibujarán todos los elementos, y con muy poco retraso. Pero si tu proceso ocupa un poco más de 2/50 de segundo, tendrás un juego que se está actualizando a 25 cuadros por segundo. Aún peor: si tu proceso ocupa un "poquito" más de 1/50 de segundo, al ejecutar halt el programa estará esperando un montón de tiempo hasta que se produzca la interrupción del 2/50 de segundo. Algo que podrías dedicar a hacer otras cosas.

Es mucho trabajo el mover toda la pantalla... Fácil, sencillo, pero es como el lado oscuro de la fuerza. Y la razón por la cual los videojuegos terminaban con aquellos "marcos" tan grandes, para reducir la cantidad de memoria ocupada/por mover. Aquí hay un artículo interesante que comenta dos técnicas para hacer ese volcado lo más rápido posible.

Otra opción es calcular las zonas "dirty" (sucias) y repintarlas desde el búfer. Eso incluye todas las posiciones donde estaban, y todas las posiciones donde están ahora los sprites.

El bucle principal puede hacer todos esos cálculos, ordenando además los "dirty rectangles" de arriba a abajo, y meterlo todo en un arreglo o vector. Y ponerse a hacer otras cosas. Cuando ocurra la interrupción, su misión será recorrer esa lista, hacer los trabajos que se le piden, y ponerla a 0.

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES

Mensajepor Bubu » 19 Nov 2018, 15:25

Y entóns, pa no estar atado a la efestividad o no de la pausa provocada por HALT, ¿no sería mejón colocar la rutina que pinta direstamente en la rutina de interrursión? Esa sí que se ejecuta 1 vez cá 1/50 segundos.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES

Mensajepor Bubu » 19 Nov 2018, 18:01

Y hay algo más que no lo había tenido en cuén pero va a ser que sí, y es que los sprites de A de ancho por B de alto, en realidad ocupan A+1 de ancho por B de alto, debido a que en horizontal los sprites están preshifted, y en vertical se shiftean online.
Jop...
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Namek
Atari 1040 STf
Atari 1040 STf
Mensajes: 838
Registrado: 11 Jul 2011, 13:13
Gracias dadas: 18 veces
Gracias recibidas: 63 veces

Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES

Mensajepor Namek » 19 Nov 2018, 20:22

Bubu escribió:Y entóns, pa no estar atado a la efestividad o no de la pausa provocada por HALT, ¿no sería mejón colocar la rutina que pinta direstamente en la rutina de interrursión? Esa sí que se ejecuta 1 vez cá 1/50 segundos.
El problema lo tendrías si tardas mas en pintar los sprites de lo que tardaría en producirse una nueva interrupción, aunque esto se podría evitar desactivando las interrupciones hasta que termines de pintar sprites, pero al final seguirias viendo parpadeos.

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES

Mensajepor Bubu » 19 Nov 2018, 20:27

OK, voy a intentar asimilar todo esto y a picar código, a ver qué sale.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
jltursan
Amiga 2500
Amiga 2500
Mensajes: 4028
Registrado: 13 Oct 2006, 19:45
Sistema Favorito: MSX
primer_sistema: Dragon
Ubicación: Serracines, Madrid, España
Gracias dadas: 57 veces
Gracias recibidas: 157 veces
Contactar:

Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES

Mensajepor jltursan » 19 Nov 2018, 20:37

¿Ves como cuando se habla de motores de sprites conviene plantearse reutilizar algo ya implementado y optimizado? :D

Es un auténtico jardín; como te decía, sólo la rutina de pintado del sprite ya tiene enjundia. ¿Te has planteado que si sacrificas ciertas capacidades y haces un XOR del propio sprite contra el fondo vas a restaurarlo y ahorrarte así el tener que preservarlo y restaurarlo específicamente?, esa técnica es rapidísima y es la que emplea el A.G.D. o clásicos como el Manic Miner, la reconocerás porque produce ese "emborronamiento" de los sprites al pasar por encima de un decorado. Ese efecto siempre he pensado que no está del todo mal para destacar el sprite sobre el fondo ya que si no, vas a estar obligado (o no, depende de hasta donde quieras llegar) a emplear una mascara con contorno que haga que el sprite se distinga un poco más.

Con el doble buffer se puede tirar por donde comenta Explorer, empleando los "dirty rectangles" tener una lista de las áreas rectangulares en las que has pintado algo y sólo volcar eso.

Como verás, conseguir la rutina perfecta puede acabar siendo un berenjenal... :)

La página en la que se discute sobre el halt me ha parecido muy interesante. Normalmente recuerdo emplear el truco del cambio del color del borde para tener una estimación de lo que se tarda en cada rutina y buscar por todos los medios el no superar el tiempo del cuadro. Ahora bien, mi experiencia se reduce al MSX y normalmente las herramientas que provee (sprites hardware por ejemplo) son menos costosas que lo que hay que hacer con el ZX. Y aun así, exactamente esa sincronización que se menciona en el artículo es la empleada por los famosos turbo-fixes desarrollados para muchos juegos de MSX Konami, que precisamente sufrían de ese problema del "desbordamiento" de cuadro.


Volver a “Programación”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 10 invitados