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?
Zx Spectrum: rutina en ensamblador para manejar SPRITES
- Bubu
- Atari 1040 STf
- Mensajes: 895
- 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: 21 veces
- Gracias recibidas: 67 veces
Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!
- jltursan
- 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
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
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.

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

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.
- Bubu
- Atari 1040 STf
- Mensajes: 895
- 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: 21 veces
- Gracias recibidas: 67 veces
Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES
Meraviglioso, jltursan. Procedo a estudiar tu mensaje.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!
- Bubu
- Atari 1040 STf
- Mensajes: 895
- 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: 21 veces
- Gracias recibidas: 67 veces
Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES
OK, ya.

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

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!!
- explorer
- MSX Turbo R
- Mensajes: 443
- 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: 162 veces
- Contactar:
Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES
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.
- Bubu
- Atari 1040 STf
- Mensajes: 895
- 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: 21 veces
- Gracias recibidas: 67 veces
Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES
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!!
- Bubu
- Atari 1040 STf
- Mensajes: 895
- 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: 21 veces
- Gracias recibidas: 67 veces
Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES
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...
Jop...
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!
- Namek
- Atari 1040 STf
- Mensajes: 840
- Registrado: 11 Jul 2011, 13:13
- Gracias dadas: 18 veces
- Gracias recibidas: 63 veces
Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES
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.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.
- Bubu
- Atari 1040 STf
- Mensajes: 895
- 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: 21 veces
- Gracias recibidas: 67 veces
Re: Zx Spectrum: rutina en ensamblador para manejar SPRITES
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!!
- jltursan
- 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
¿Ves como cuando se habla de motores de sprites conviene plantearse reutilizar algo ya implementado y optimizado?
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.

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.
¿Quién está conectado?
Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 4 invitados