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.
el dispositivo del ratón tiene un par de cortos para indicar si el ratón se está desplazando.
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")
* 0001 cuando se desplaza hacia arriba
* ffff cuando se desplaza hacia abajo
* 0000 cuando no se desplaza
del mismo modo, despx indicará un desplazamiento horizontal
combinado con un condicional y el dibujo de un sprite.
dibuja nuestro cuadrado en la posición del ratón, cambiando su color cuando se pulsa cualquier botón del ratón.
=> ./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
( dibujar sprite usando el color 2 y 0 en el fondo )
#02 .Pantalla/sprite DEO
BRK
&presionado
( dibujar sprite usando el color 1 y 0 en el fondo )
#01 .Pantalla/sprite DEO
BRK
@cuadrado [ ff81 8181 8181 81ff ]
```
## hola puntero
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} )
este modo de mezcla te permitiría dibujar cosas en el plano de fondo y que el puntero las cubra sólo con su forma, y no con todo el cuadrado del tile.
¡te invito a que lo pruebes!
¡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!
### algunos problemas
ahora, podemos ver que el programa funciona, pero está inundando la subrutina en-raton con mucho código.
eso es aun mas cierto si consideramos que solo estamos dibujando el puntero, y no tomando ninguna otra acción, como responder a los botones.
crear una macro para todo este código podría ser posible, pero también poco práctico debido a la cantidad de código.
¿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-raton?
¡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'.
## un breve ejemplo de pila de retorno
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:
```
LITr 01 LITr 02 ADDr
```
o, combinando los modos corto y de retorno en la instrucción LIT:
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.
## notas sobre subrutinas como "funciones"
tengamos en cuenta que una posible forma de enviar "argumentos" a una subrutina sería empujarlos hacia abajo en la pila de trabajo antes de llamarla.
además, una posible forma de que una subrutina "devuelva" sus resultados sería que los empujara hacia abajo en la pila de trabajo.
estos elementos pueden entonces ser consumidos desde la pila de trabajo después de regresar de la subrutina.
puede haber otros casos en los que el uso de "variables" tendría un sentido más lógico y/o legible para pasar argumentos y resultados.
# almacena, no saltes
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 sub-etiqueta &bucle no es realmente necesario: las operaciones entre estas instrucciones sí tocan la pila de trabajo pero después la dejan como estaba.
sin embargo, muestra cómo podemos usar estas instrucciones para tener una pila de trabajo limpia sin que otros valores interfieran.
### posibles ejercicios
* hacer que la subrutina dibuje una línea hecha de sprites en lugar de píxeles individuales
* modificar la subrutina para que pueda recibir como argumento (en la pila de trabajo) el color de los sprites o píxeles
* modificar la subrutina para que pueda recibir como argumento (en la pila de trabajo) la dirección del sprite a dibujar
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.
## modo mantener en aritmética
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:
```
#01 #02 ( pt: 01 02 )
ADD ( pt: 03 )
```
compáralo con lo que ocurre al usar ADDk en su lugar:
```
#01 #02 ( pt: 01 02 )
ADDk ( pt: 01 02 03 )
```
la suma se realiza y el resultado es empujado, pero los operandos se dejan en la pila.
puede ser difícil pensar en general en un uso para esto, ¡pero "mantenlo" en mente!
### módulo
en realidad, si recuerdas, en el {tutorial de uxn día 4} compartí contigo un par de macros para realizar una operación de módulo:
```
%MOD { DUP2 DIV MUL SUB } ( a b -- a%b )
%MOD2 { OVR2 OVR2 DIV2 MUL2 SUB2 } ( a b -- a%b )
```
dije entonces que había un conjunto más optimizado, y que lo discutiríamos más adelante.
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:
¿ves la posibilidad de introducir el modo mantener?
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.
pero entonces, ¿cómo podemos realizar la división sin perder sus operandos y sin usar DUP2?
¡así es!
DUP2 DIV es equivalente a... ¡DIVk! ¡una división que no pierde sus operandos!
( duplicar longitud y el conteo, comparar, y saltar )
DUP2 ( pt: longitud conteo longitud conteo / pr: )
NEQ ( pt: longitud conteo bandera / pr: )
,&bucle JCN ( pt: longitud conteo / pr: )
```
verás que aquí, como en el caso DIVk anterior, el DUP2 está ahí sólo para asegurarse de que la longitud y el recuento no se pierden al realizar NEQ.
por lo tanto, podríamos reemplazar DUP2 NEQ con NEQk:
```
( duplicar la longitud y el conteo, comparar, y saltar )
NEQk ( pt: longitud conteo bandera / pr: )
,&bucle JCN ( pt: longitud conteo / pr: )
```
## el modo mantener y la pila de retorno
a veces queremos almacenar una copia de un valor que usaremos en el momento.
sin el modo mantener, escribiríamos:
```
DUP STH ( duplicar y almacenar )
```
con el modo mantener, podemos escribir:
```
STHk ( almacenar y mantener )
```
del mismo modo, habrá ocasiones en las que queramos recuperar una copia de un valor de la pila de retorno.
para ello, podemos escribir:
```
STHkr ( recuperar una copia de la pila de retorno )
```
## más y más modo mantener
se siguen encontrando nuevos e interesantes usos para el modo mantener :)
¡no dudes en compartirlos con nosotres!
# más ejercicios
con lo que ya hemos cubierto, y en caso de que quieras algunas ideas, aquí hay algunas cosas que ahora deberían ser más fáciles de intentar construir:
## sprites de varios tiles
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.
## herramienta de dibujo
¡muchas posibilidades aquí!
tal vez comienza con dibujar sólo cuando se presiona un botón. cambia el color y/o el "pincel" dependiendo del botón que se presiona.
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?), y/o las formas que se dibujan.
considera cómo seleccionarías esos modos: ¿botones en pantalla? ¿teclas del teclado? ¿acordes con los botones del ratón?
ten en cuenta que puedes cambiar el vector de un dispositivo durante el tiempo de ejecución: podrías tener una subrutina en-raton diferente dependiendo del modo que hayas seleccionado :)
¿cómo podrías utilizar la rueda del ratón como ayuda para dibujar?
## y más...
básicamente, las puertas para las aplicaciones visuales interactivas en el ordenador varvara están completamente abiertas ahora para ti :)
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.
¡basamos nuestra discusión en una recreación del clásico juego pong!
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.