Scroll por hardware con CPCtelera

Programando el Amstrad en BASIC, C, etc.
Avatar de Usuario
Mister_Knee
Lechoncillo
Lechoncillo
Mensajes: 10
Registrado: Mié 09 Dic , 2015 2:07 am
Contactar:

Scroll por hardware con CPCtelera

Mensajepor Mister_Knee » Mié 09 Dic , 2015 2:46 am

Buenas gente, estoy haciendo pruebas con la cpctelera, y estoy intentando hacer un scroll horizontal por hardware, lo he intentado por software con el cpct_memcpy, pero va extremadamente lento, y me gustaría evitar el doble buffer siempre que sea posible.

Para hacer este scroll, de momento, lo que estoy intentando es mover el fondo creado con un tilemap, con la función cpct_setVideoMemoryOffset, aumentando en 1 el offset cada iteración, hasta llegar a 40 (En este punto, la memoria de vídeo ha dado "la vuelta"), en este punto vuelvo a poner el offset a 0. También voy moviendo y repintando al player, y llegado a offset == 40 lo pongo a la posición inicial.

Con este sistema, medio funciona, y va muy rápido, pero me salen un par de problemas:

El primero, es que el cpct_setVideoMemoryOffset me mueve dos bytes a la vez, no se muy bien porqué, ya que cada vez que aumento en uno el offset, me mueve un tile (que miden 2x4 bytes), tengo que mover al player dos bytes para que no se desplace en la pantalla y permanezca en el centro, esto no es un problema grave, solo que es algo que no entiendo porqué es así, si se supone que estoy desplazando la memoria solo un byte.

El otro problema que tengo, es que evidentemente, por la esquina inferior derecha, aparecen cuadros blancos al desplazar la memoria de vídeo, y los tiles que se van por la izquierda, aparecen por la derecha en la linea superior. Esto lo entiendo, ya que se debe a la forma en la que esta distribuida la memoria de vídeo, el problema viene al intentar solucionarlo, intento pintar la columna de tiles del final de la derecha, pero no consigo acertar en el punto exacto en el que tengo que dibujar los tiles (estoy usando la función cpct_etm_drawTileBox2x4 ). Además, como tengo que dibujar 50 tiles (lo que ocupa todo el alto de la pantalla), no va muy rapido...

Por último, mi idea respecto al resto de elementos del juego, sería molerlos a mano cada vez que el jugador se desplace (los enemigos, además, se moverían por su cuenta), y dibujar solo aquellos que se fueran a ver, pero no se hasta que punto, manejar la posición de todos los elementos del nivel es viable para un Z80, aunque supongo que lo más costoso, es el pintado, así que quizá si que sea viable.



En definitiva, me gustaría que alguien me ayudase con los dos problemas que tengo, o en caso de que este haciéndolo muy mal, y hayan formas mejores de hacer un scroll por hardware, que se me explicarais como hacerlo correctamente.

Un saludo.

Avatar de Usuario
ronaldo
Forum Addict
Forum Addict
Mensajes: 358
Registrado: Sab 14 Sep , 2013 9:31 pm
Ubicación: Alicante
Contactar:

Re: Scroll por hardware con CPCtelera

Mensajepor ronaldo » Mié 09 Dic , 2015 11:59 am

Muy buenas, @Mister_Knee. Ya veo que te pones directamente con cosas algo más elaboradas. No está nada mal: a ver con qué nos sorprendes ;).

Te respondo a lo que preguntas.
Buenas gente, estoy haciendo pruebas con la cpctelera, y estoy intentando hacer un scroll horizontal por hardware, lo he intentado por software con el cpct_memcpy, pero va extremadamente lento, y me gustaría evitar el doble buffer siempre que sea posible.
En realidad no es "extremadamente lento", si lo comparas con lo que el Z80 es capaz de hacer. Ten en cuenta que llenar la pantalla de ceros, para borrar el fondo, es algo que ya cuesta en torno a 2/50 s (2 frames completos, funcionando a 50fps). Este es el motivo principal por el que verás que muchos juegos con scroll en CPC (la mayoría lo hacen por software) tienen zonas de juego más pequeñas, usan doble buffer y van a 12.5 FPS como mucho.
El primero, es que el cpct_setVideoMemoryOffset me mueve dos bytes a la vez, no se muy bien porqué, ya que cada vez que aumento en uno el offset, me mueve un tile (que miden 2x4 bytes), tengo que mover al player dos bytes para que no se desplace en la pantalla y permanezca en el centro, esto no es un problema grave, solo que es algo que no entiendo porqué es así, si se supone que estoy desplazando la memoria solo un byte.
Tienes la explicación en la documentación de cpct_setVideoMemoryOffset. La posición de la memoria de vídeo está controlada por 2 registros del CRTC: R12 y R13. En estos 2 registros se almacenan sólo los 14 bits más significativos de la posición de memoria, dejando los 2 últimos bits a 0. Esto significa que no puedes elegir cualquier posición de memoria, sino que eliges posiciones alienadas a 4. Cada vez que se aumenta en 1 el offset, en realidad se está aumentando en 4 la posición del puntero.
El otro problema que tengo, es que evidentemente, por la esquina inferior derecha, aparecen cuadros blancos al desplazar la memoria de vídeo, y los tiles que se van por la izquierda, aparecen por la derecha en la linea superior. Esto lo entiendo, ya que se debe a la forma en la que esta distribuida la memoria de vídeo, el problema viene al intentar solucionarlo, intento pintar la columna de tiles del final de la derecha, pero no consigo acertar en el punto exacto en el que tengo que dibujar los tiles (estoy usando la función cpct_etm_drawTileBox2x4 ). Además, como tengo que dibujar 50 tiles (lo que ocupa todo el alto de la pantalla), no va muy rapido...
Te pueden estar sucediendo varias cosas, según lo hayas implementado. De todas formas, lo más sencillo es borrar los tiles de la izquierda antes de hacer scroll, y dibujar los de la derecha después de hacer scroll (o viceversa). Por otra parte, si mezclas el scroll con las funciones de easytilemap, tienes que controlar bien los punteros y posiciones del tilemap para que no se descuadre. Imagino que esto lo tienes en cuenta. Por último, ten cuidado a la hora de usar la pantalla completa con scroll y dibujar sprites. Al hacer scroll de pantalla aparece un problema que afecta a las funciones de dibujado de sprites: en la zona de wrapping the la pantalla, el siguiente byte a dibujar no es byteanterior+1, sino byteanterior-0x800+1 (Esto sucede, exactamente, cuando tienes un offset superior a 40, ya que estás desplazándote 0x100 bytes, que es el ancho de la zona no visible de pantalla (spare)). Las funciones de dibujado de sprites de CPCtelera no están pensadas para tener en cuenta esto, porque serían mucho más lentas (tendrían que comprobar en cada byte que escriben si están en zona de wrapping). En la lista de tareas está realizar una solución eficiente para esto, pero aún no está hecha. De momento, tiene que ser el programador el que tenga cuidado con esa zona de pantalla y no dibuje ahí con funciones de sprites. De todas formas, si no tienes un offset superior a 40, esto no debe sucederte.

Échale un ojo a esto que te comento y, si necesitas más ayuda, hará falta algún detalle más de tu implementación concreta para saber qué más decirte :).

Avatar de Usuario
Mister_Knee
Lechoncillo
Lechoncillo
Mensajes: 10
Registrado: Mié 09 Dic , 2015 2:07 am
Contactar:

Re: Scroll por hardware con CPCtelera

Mensajepor Mister_Knee » Jue 10 Dic , 2015 4:13 am

Muy buenas, @Mister_Knee. Ya veo que te pones directamente con cosas algo más elaboradas. No está nada mal: a ver con qué nos sorprendes ;).
Bueno, bueno, de momento estoy intentando hacer un scroll pasable, para ver hasta donde puedo llevar al limite el Z80 en número de elementos por pantalla, tamaño del nivel... antes de ponerme a diseñar juegos. Voy a ver si puedo hacer un scroll decente, y si no, tirare del socorrido truco de cambiar de área al acercarte al borde de la pantalla. Que sin ser muy elegante, al menos es efectivo.
En realidad no es "extremadamente lento", si lo comparas con lo que el Z80 es capaz de hacer. Ten en cuenta que llenar la pantalla de ceros, para borrar el fondo, es algo que ya cuesta en torno a 2/50 s (2 frames completos, funcionando a 50fps). Este es el motivo principal por el que verás que muchos juegos con scroll en CPC (la mayoría lo hacen por software) tienen zonas de juego más pequeñas, usan doble buffer y van a 12.5 FPS como mucho.
Uff, ese es el problema, demasiados handicaps para decidirme por el, ¿He de suponer pues que el IOTZM, por ejemplo, tiene scroll de hardware?
[youtube]https://www.youtube.com/watch?v=6gUEqk3ie_4[/youtube]
Tienes la explicación en la documentación de cpct_setVideoMemoryOffset. La posición de la memoria de vídeo está controlada por 2 registros del CRTC: R12 y R13. En estos 2 registros se almacenan sólo los 14 bits más significativos de la posición de memoria, dejando los 2 últimos bits a 0. Esto significa que no puedes elegir cualquier posición de memoria, sino que eliges posiciones alienadas a 4. Cada vez que se aumenta en 1 el offset, en realidad se está aumentando en 4 la posición del puntero.
#-o Estuve mirando la documentación, pero no llegué a profundizar tanto como para llegar a esa parte, tendré que empezar a fijarme más en los manuales :oops:
Te pueden estar sucediendo varias cosas, según lo hayas implementado. De todas formas, lo más sencillo es borrar los tiles de la izquierda antes de hacer scroll, y dibujar los de la derecha después de hacer scroll (o viceversa). Por otra parte, si mezclas el scroll con las funciones de easytilemap, tienes que controlar bien los punteros y posiciones del tilemap para que no se descuadre. Imagino que esto lo tienes en cuenta. Por último, ten cuidado a la hora de usar la pantalla completa con scroll y dibujar sprites. Al hacer scroll de pantalla aparece un problema que afecta a las funciones de dibujado de sprites: en la zona de wrapping the la pantalla, el siguiente byte a dibujar no es byteanterior+1, sino byteanterior-0x800+1 (Esto sucede, exactamente, cuando tienes un offset superior a 40, ya que estás desplazándote 0x100 bytes, que es el ancho de la zona no visible de pantalla (spare)). Las funciones de dibujado de sprites de CPCtelera no están pensadas para tener en cuenta esto, porque serían mucho más lentas (tendrían que comprobar en cada byte que escriben si están en zona de wrapping). En la lista de tareas está realizar una solución eficiente para esto, pero aún no está hecha. De momento, tiene que ser el programador el que tenga cuidado con esa zona de pantalla y no dibuje ahí con funciones de sprites. De todas formas, si no tienes un offset superior a 40, esto no debe sucederte.
El offset nunca llego a sobrepasar a 40, ya que una vez llegado a ese punto, le reinicio a 0. El problema que tengo es que al desplazar la memoria, el tilemap se me descuadra, y no se muy bien donde tengo que redibujar los tiles para evitar ese problema.

Este es el código (simplificado) en el que hago el scroll e intento redibujar los tiles de la derecha:

Código: Seleccionar todo

#define VMEM (u8*)0xC000
u8 posView = 0;

cpct_etm_setTileset2x4(g_tile_tileset);
cpct_etm_drawTilemap2x4_f(MAP_WIDTH, MAP_HEIGHT, VMEM, g_tilemap);

while (1) {
cpct_scanKeyboard_f();
if (cpct_isKeyPressed(Key_CursorRight)) {
posView++;
if (posView >= 40) {
posView = 0;
}

//Problema para redibujar
cpct_etm_drawTileBox2x4(MAP_WIDTH - 1, 0, 1, MAP_HEIGHT, MAP_WIDTH, VMEM + (posView * 2), g_tilemap);
}
}

Avatar de Usuario
ronaldo
Forum Addict
Forum Addict
Mensajes: 358
Registrado: Sab 14 Sep , 2013 9:31 pm
Ubicación: Alicante
Contactar:

Re: Scroll por hardware con CPCtelera

Mensajepor ronaldo » Jue 10 Dic , 2015 8:57 pm

Aprovechando que preguntas y dado que no tengo muy claro qué partes del código has eliminado o cuál puede ser exactamente el fallo, me he entretenido en elaborar un ejemplo de scroll por hardware usando un easytilemap. Está subido a la rama master de CPCtelera. Aquí tienes un vídeo para que veas el resultado, y el links para quien quiera ver el código en el navegador tranquilamente:
Confío en que puedas ver cómo lo hago en este ejemplo y te ayude a entender mejor qué puede estar pasando en el tuyo. Así, de paso, también servirá para que más gente pueda tener un ejemplo de cómo hacer scroll por hardware de forma sencilla con un tilemap.

Si hay algo que no esté claro, pregunta que para eso estamos :).

Avatar de Usuario
Mister_Knee
Lechoncillo
Lechoncillo
Mensajes: 10
Registrado: Mié 09 Dic , 2015 2:07 am
Contactar:

Re: Scroll por hardware con CPCtelera

Mensajepor Mister_Knee » Jue 10 Dic , 2015 9:13 pm

Madre mía Fran, estás hecho un sol. Voy a echarle un vistazo, y teniendo un ejemplo exacto de lo que quiero hacer, supongo que ya, si que si, voy a conseguirlo (mi orgullo de programador está en juego).

La verdad es que se ve de lujo, ahora si que no hay excusas para hacer cosas guays. Ya subiré un vídeo o algo cuando tenga alguna cosita decente que enseñar \:D/

Avatar de Usuario
AmstradGamer
Forero habitual
Forero habitual
Mensajes: 189
Registrado: Dom 08 Jun , 2014 10:08 am

Re: Scroll por hardware con CPCtelera

Mensajepor AmstradGamer » Vie 11 Dic , 2015 9:57 am

La verdad es que viendo el código del ejemplo parece súper sencillo, pero le hace plantearse a uno el por qué no es capaz de llegar por uno mismo a esas conclusiones. :-k

Gracias Fran por el ejemplo, creo que me voy a animar a implementar un scroll así en lo que tengo entre manos.

Un saludo.

Avatar de Usuario
ronaldo
Forum Addict
Forum Addict
Mensajes: 358
Registrado: Sab 14 Sep , 2013 9:31 pm
Ubicación: Alicante
Contactar:

Re: Scroll por hardware con CPCtelera

Mensajepor ronaldo » Vie 11 Dic , 2015 12:58 pm

@Mister_Knee: Ánimo, a ver si nos enseñas cositas chulas :).

@AmstradGamer: A mi tampoco me salen así a la primera, hago varios rediseños. De todas formas, procuro que los ejemplos estén bien ordenados y explicados para que se entiendan. Quizá por eso llego a soluciones distintas: porque estoy pensando más en quienes van a leer el código que en el propio código. Eso sí, me alegro de que os sean útiles, ya que para eso son :).

Tened en cuenta, eso sí, que las soluciones estas son ilustrativas. Cuando queráis hacer cosas serias con ellas tendréis que adaptarlas y pelearos con los detalles de bajo nivel. Por ejemplo, un detalle importante es el tema de la no linealidad de la memoria al hacer loop. Por ejemplo, la fila 0 de pantalla (que abarca todas las filas 0 de los 25 caracteres de la pantalla), empieza en 0xC000 y termina en 0xC7FF (con una zona no visible inicial de 0xC7D0 a 0xC000). Si dibujamos un sprite con cpct_drawSprite con de ancho 4 bytes empezando en 0xC7FE, se dibujará en los bytes 0xC7FE, 0xC7FF, 0xC800 y 0xC801. Esto hará que los 2 bytes de la derecha estén 1 fila más abajo en pantalla (0xC800 pertenece a la fila 1, no a la fila 0). El dibujado correcto sería en 0xC7FE, 0xC7FF, 0xC000, 0xC001. Esto no lo tienen en cuenta las funciones de easytilemap ni cpct_drawSprite, ya que no están pensadas para condiciones de Scroll. Por el momento, esto tenéis que gestionarlo vosotros, mientras diseñamos alguna forma adecuada de hacer esto más llevadero, sin que suponga un coste prohibitivo en las funciones de dibujado de tiles y sprites.


¿Quién está conectado?

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


La Comunidad Española
ESP Soft, juegos para tu CPC Foro de Amstrad CPC Todos los juegos para CPC en un CD Web dedicada al Amstrad CPC (utilidades) Información útil para el CPC (talleres) Selección de juegos de Amstrad CPC Mundo CPC Pree Play then any Key CPC Basic