esta es la quinta sección del {tutorial de uxn}! aquí introducimos el dispositivo de ratón varvara para explorar más posibles interacciones y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo mantener.
el dispositivo del ratón en el ordenador varvara es similar al dispositivo controlador en varios aspectos: tiene un vector que es llamado con cualquier evento del ratón (cambio de estado de los botones, movimiento, movimiento de desplazamiento) y un par de bytes para comprobar su estado.
adicionalmente, tiene un par de cortos correspondientes a las coordenadas x,y del puntero del ratón.
vemos este dispositivo definido en uxntal de la siguiente manera:
recuerda que podemos utilizar las máscaras AND, tal y como se introdujo en el {tutorial de uxn día 3}, para aislar y evaluar por separado cualquiera de estos bits.
despy indicará un desplazamiento vertical con un valor "positivo" cuando se mueve hacia arriba (o en realidad, "lejos del usuario") y un valor "negativo" cuando se mueve hacia abajo (o "hacia el usuario")
=> ./img/screenshot_uxn-draw-with-mouse.png captura de pantalla que muestra un dibujo realizado con el programa: líneas onduladas compuestas por cuadrados superpuestos de dos colores diferentes
tal vez hayas notado que, antes de hoy, el puntero del ratón ha desaparecido al entrar en la ventana de uxnemu.
¿cómo podríamos programar y replicar su comportamiento en uxntal?
podríamos utilizar una estrategia similar a la que hicimos para animar un sprite:
* borrar el sprite de la posición anterior
* actualizar la posición
* dibujar el sprite en la nueva posición
este procedimiento puede ocurrir cada vez que se dispara el vector del ratón.
podemos utilizar un conjunto de variables en la página cero para almacenar la posición del puntero, de forma que tengamos una forma de limpiar el sprite en las coordenadas anteriores del ratón.
adicionalmente, aquí tenemos los datos de un sprite de 1bpp de un puntero de ratón, tomados de los ejemplos de uxn:
```
@puntero_icn [ 80c0 e0f0 f8e0 1000 ]
```
### el programa
este es un programa que logra dibujar el puntero en la pantalla
nótese que dibuja el puntero en primer plano y que utiliza 'a' en el nibble bajo del byte del sprite: esto implica que utilizará el color 2 para dibujar la forma del puntero y dibujará con transparencia el resto del tile. (ver dibujar sprites de 1bpp en el {tutorial de uxn día 2})
¡dibuja algunas cosas en el fondo y ve cómo se ve el puntero, tal y como está ahora. luego reemplaza el byte del sprite del puntero con, por ejemplo, 42 para ver la diferencia!
¿tal vez podríamos tener un JMP a otra sección del programa, que al final tiene otro JMP para c vnm a la posición correspondiente en la subrutina en-ratón?
¡conozcamos una alternativa, la instrucción "saltar y almacenar"!
# salta y almacena o "jump and stash"
la instrucción de salto y stash, JSR, hace lo mismo que JMP (saltar incondicionalmente a la dirección presente en la pila de trabajo), con la acción adicional de empujar hacia abajo en la pila de retorno la dirección absoluta de lo que sería la siguiente instrucción en memoria después de JSR.
en el modo normal, JSR toma una dirección relativa (un byte) de la pila de trabajo, y en el modo corto, JSR2 toma una dirección absoluta.
en ambos casos, JSR empujará una dirección absoluta (2 bytes) hacia abajo en la pila de retorno.
## salto relativo
por ejemplo, nuestros saltos podrían reescribirse de la siguiente manera. en el caso de un salto relativo:
JSR está empujando la "dirección de retorno" hacia la pila de retorno.
ahora la pregunta es: ¿cómo tomamos la dirección de esa pila, para saltar allí?
¡tendríamos que usar el "modo de retorno"!
# el modo de retorno
similar al modo corto, el modo de retorno en uxn consiste en activar una bandera binaria en el byte que codifica una instrucción.
el modo de retorno se codifica en el 7mo bit de un byte de instrucción, contando de derecha a izquierda.
siempre que se active esta bandera, uxn realizará la instrucción dada pero utilizando como fuentes el contenido de la pila de retorno en lugar del contenido de la pila de trabajo.
en uxntal, indicamos que queremos activar esta bandera añadiendo la letra 'r' al final de un mnemónico de instrucción.
como cada uno de los modos es un bit independiente, es posible combinarlos, por ejemplo, activando el modo de retorno y el modo corto utilizando el sufijo '2r'.
por ejemplo, el siguiente código empujaría dos números hacia abajo en la pila de retorno, los sumaría y empujaría el resultado de nuevo en la pila de retorno:
JSR o JSR2 empujan hacia abajo en la pila de retorno la dirección absoluta de la siguiente instrucción, un corto, para que eventualmente podamos retornar allí.
observe que la etiqueta dibuja-puntero va acompañada de la notación de estado de la pila ( -- ) para indicar que, en este caso, no consume ni produce contenidos desde o hacia la pila de trabajo.
también note como esta subrutina termina con un RTN (JMP2r) que indica que el flujo del programa volverá a la posición posterior a la llamada de la subrutina.
habiendo introducido la pila de retorno y el modo de retorno, se nos abre otro mundo de posibilidades: también podemos utilizar la pila de retorno como una pila adicional y temporal, para almacenar algunos valores mientras operamos con otros.
se trata de una subrutina que dibuja una línea horizontal de una longitud dada (de 1 a 255 píxeles, es decir, utilizando un byte), partiendo de una coordenada x dada (corto) y utilizando una coordenada `y` dada (corto).
el estado de las pilas de trabajo (pt) y de retorno (pr) se muestra en los comentarios después de casi cada paso. la parte superior de las pilas se encuentra a su derecha.
nota que en esta subrutina específica, el uso de STH2 y STH2r después de la subetiqueta &bucle no es realmente necesario: las operaciones entre estas instrucciones sí tocan la pila de trabajo pero después la dejan como estaba.
en uxntal, indicamos que queremos activar esta bandera añadiendo la letra 'k' al final de un mnemónico de instrucción.
siempre que se active esta bandera, uxn realizará la instrucción dada pero "manteniendo" los valores originales en la pila correspondiente.
en otras palabras, en el modo mantener los elementos no serán consumidos de la pila, pero los resultados correspondientes serán empujados hacia abajo en la pila.
el modo mantener puede combinarse con los otros modos, para un total de ocho combinaciones posibles de modos.
sabemos lo que hace el siguiente código uxntal; empuja 01 y 02 hacia abajo en la pila, suma ambos elementos y empuja el resultado (03) hacia abajo en la pila:
en primer lugar, analicemos lo que ocurre con MOD. está calculando lo que se escribiría en notación infija de la siguiente manera, suponiendo que la barra (/) indica una división entera:
si te fijas bien, verás que el DUP2 está ahí para no perder los valores originales en la división y así poder realizar la multiplicación y la resta después.
dibujar un sprite formado por varios tiles es un proceso que puede beneficiarse del uso de subrutinas: ten una subrutina que reciba un par de coordenadas x,y en la pila de trabajo cuando sea llamada y úsala para dibujar los tiles en las posiciones correspondientes relativas a esas coordenadas.
puedes tener diferentes "modos" seleccionables: tal vez cambien el pincel que estás usando, la forma en que el pincel se comporta (por ejemplo, ¿en espejo, caleidoscopio?) o las formas que se dibujan.
ten en cuenta que puedes cambiar el vector de un dispositivo durante el tiempo de ejecución: podrías tener una subrutina en-ratón diferente dependiendo del modo que hayas seleccionado :)
algunas cosas pueden parecer difíciles de construir, pero afortunadamente, por ahora no hay nada más en el funcionamiento de la máquina que no hayamos cubierto ya.
puedes ir poco a poco, paso a paso, practicando tu manejo de la pila y ejercitando el cerebro postfijo, y llegarás a donde quieras :)
* JSR: salta incondicionalmente a la dirección de la pila de trabajo, empujando hacia abajo en la pila de retorno la dirección de la siguiente instrucción en memoria
* STH: toma un valor de la pila de trabajo y lo empuja hacia abajo en la pila de retorno. en el modo de retorno, hace lo contrario.
# día 6
en el {tutorial de uxn día 6} hablamos de cómo podemos integrar todo lo que hemos cubierto para crear subrutinas y programas aún más complejos para el ordenador varvara.
además de utilizar estrategias y fragmentos de código anteriores, cubrimos estrategias para dibujar y controlar los sprites de varios tiles y para comprobar las colisiones.