7 - Programación de Demos (Ricardo Cabello Torres)
Aqui os muestro unas betas de capitulos de lo que deseo que sea mi libro de gráficos (-Todavia no tengo decidido el nombre, pero puede que le ponga: 'El esqueleto de una demo' - Acepto sugerencias....).
No me considero ningun especialista en el tema y hay aspectos en los que no entro, ni quiero entrar. Tan solo escribo estas paginas para que gente que le ponga un 'poquirrin' de ganas y entusiasmo se pueda adentrar en el fascinante mundo de los gráficos.
Ricardo Cabello Torres
Barracuda // Shivan
CAPITULO 0: UNA FORMA DIFERENTE DE TRABAJO
Introduccion
Deshagamos las ilusiones de los lectores que creen que este libro va a ser facil. Tambien las de aquellos informaticos que esperan que este compendio de paginas acabe en todas las librerias. No, nunca el tema de los graficos será de interes popular, y tampoco llegara el dia en que los libros de gráficos sean un negocio para las distribuidoras.
Ahora bien, esta publicacion, ayudara a aquellos que esten interesados en el fascinante mundo de los gráficos.
Lo que se considerará necesario
No, no me refiero a el equipo informatico, lo cual considero obvio en cualquer persona que tenga la delicadeza de 'acariciarme' ;), sino a algo mucho mas importante, la base de conocimientos del individuo. Esta claro que un muchacho/a de menos de 15 años, no tiene la capacidad matematica necesaria para entender los conceptos que se trataran en esta publicacion.
- Capacidad de desarrollo: Es decir que sepa programar, aunque sea por encima algun lenguaje.
- Conocimientos ligeros de Graficos: Me refiro a saber manejar algun programa, tipo Animator, o Paint-brush.
- Conocimientos ligeros de Graficos 3d: 3D STUDIO (o similares)
- Conocimientos basicos de Matematicas: Ecuacion de la recta, Plano, Giros, matrices, Sist. Ecuaciones.
¿ Por que crear este libro ?
En mi opinion, no hay libros en castellano, y casi ni en ingles que expliquen con claridad el tema de los graficos, de lo que podemos hacer, que no es un sueño imposible crear una demo. Culpa de Escribano, su libro de 'Graficos en 3D', me ayudo a decidirme en escribir esta obra, ya que considero su libro como el ejemplo idoneo de lo que no debe ser un libro de graficos. Desde el comienzo, donde ya dice que es para todos los publicos, hasta en cualquier tema, donde con la necesidad de abarcar mucho, no se para a explicar y desarrollar lo mencionado. La ultima razon de crear esta publicacion se debe a 2 compañeros de la universidad (Fernado y Alfonso), que me pidieron una introducion a los graficos. Pues bien, ahi va esa introduccion del dia 15/12/96.
Una filosofia de trabajo
En este apartado, escribo lo que será una constante a lo largo del libro. Mi intencion no es crear un libro de teoria, donde halla que aprenderse de memoria los metodos a usar, ni un libro donde el usuario realice el metodo "Cut & Place" (Cojer y pegar) con los algoritmos de esta obra. Todo lo contrario, considero que son 2 malisimos metodos para aprender. El primero, porque es la anti-informatica, en informatica, las cosas hay que entenderlas, nunca aprenderselas de memoria. El segundo, porque aunque se obtienen resultados rapidamente, cuando te encuentras ante un problema mas complicado eres incapaz de resolverlo, te atascas, y como no has aprendido lo basico nunca pasaras de un nivel mediocre. Es el ejemplo de usar una libreria ya hecha, con una orden Tipo Dibuja_Ventana(), te sale una ventana en la pantalla con tropecientos botones, pero, si tu quieres que esa ventana, por ejemplo, gire. Es decir, añadirle 2 puertas que se abran en 3D, ¿Que orden de la libreria te permite hacerlo? Si has comprendido este ejemplo, puedes haber entendido la filosofia de trabajo a seguir en este libro.
Consejos de programacion
Os pongo 10 consejos a la hora de implementar las cosas:
- Nunca copieis algoritmos que no habeis entendido.
- No hagais los programas en papel, ya que en programacion, si no ve uno mismo resultados, se vuelve una materia muy pesada, monotona y aburrida.
- Usad representacion en papel para partes del programa de dificil comprension. Podeis hacer diagramas de flujo, o diagramas de bloques (es una forma de indicar la conexion entre modulos).
- Nombrar a las unidades con una letra que las identifique:
- Ej: u_modo13; {Unidad Modo 13}
- m_triangulos; {Mapeado de triangulos}
- Poned comentarios a vuestros programas, hasta al mas tonto que tengais.
- Usar variables significativas.
- Apoyarse en el uso de Break-Points (Puntos de ruptura) y Watches (ventana de contenido de variables) a la hora de depurar vuestros programas.
- Procurar que vuestros modulos no superen la 200 lineas de codigo.
- Usar las ordenes de Cojer y Pegar (CTRL +INS // SH + INS) a la hora de programar, para evitarse repetir lineas de codigo, y cojer velocidad de codificacion.
- No os desespereis si no sale algo, mas adelante seguro que lo conseguis.
OJO, LAS MARCADAS CON ASTERISCO, LAS CONSIDERO, A MI MODESTA OPINION, IMPRESCINDIBLES EN LA CREACCION DE 'SOFTWARE'.
CAPITULO 1(A) : PRINCIPIOS BASICOS PARA LA PROGRAMACION GRAFICA
Ejemplo inicial de distribucion de la memoria
Despues de escribir la introduccion de abajo, y pensar en la tipica persona que no sabe nada de hard, crei oportuno añadir esta parte, donde explico lo que es una memoria, como estaá colocada y como se direcciona.
Supongamos una resolucion de : 5 * 3 * 16 = 240
ancho alto tamaño
Esto va a suponer 5 * 3= 15 celdillas, y en cada una podemos insertar dominios comprendidos entre 0 y 15.
M1: 0 1 2 3 4 5
0 * * * * *
1 * K * * *
2 * * * R *
3
Podemos entender la memoria como una matriz de programacion, aunque este ejemplo no se ve claro si no sabemos como es en realidad una matriz en bajo nivel. Quiza se pueda ver mas claro en no se que ... {NO SE ME OCURRE NADA }...
La memoria M1 se puede entender como:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
* * * * * * K * * * * * * R *
En realidad, es asi como estan almacenados los datos en cualquier dispositivo, secuencialmente o como se dice en estos casos "linealmente". Esto significa que si queremos insertar un valor en la posicion indicada por el simbolo R, deberiamos hacer:
M1[13]:=6 -- En realidad, podemos insertar valores comprendidos entre 0 y 15, al tener un tamaño de 16 la celdilla.
Si consideramos como constante de cambio de linea, la longitud de esta, o sea 5, tenemos que multiplicando el n∫ de fila (Coordenada y) por esta constante, y sumandole el n∫ de columna (Coordenada x), obtenemos la posicion donde deberiamos escribir.
LONGITUD_linea:=5
M1[2 * longitud_linea + 3 ] = M1[10+3]= M1[13] .
Como puede ver el lector, se accede rapidamente y facilmente a la celdilla a modificar. Pues bien, todos los dispositivos de almacenamiento, usan este formato. ¿Por que? Se me ocurren 2 razones:
- Para acercarse mas al funcionamiento externo del dispositivo.
- Ej: Si tu quieres escribir algo en la posicion 16,42 de una pantalla, es mucho mas significativo hacer escribir (16,42) que tener que estar escribiendo (1322).
- Para ofrecer al usuario, una implementacion de uso transparente al funcionamiento interno del dispositivo.
Introduccion MODO 13:
Nos referimos a uno de los modos graficos de cualquier VGA. Su formato permite el direccionamiento directo para cualquiera de sus posiciones, sin tener que hacer mascaras ni otros cambios como en los MODOS VESA.
320 * 200 * 256
I I I
I I -------> 256 Colores posibles por cada pixel
I -------------> ALTO (Dimension vertical de la pantalla)
-------------------> ANCHO (Dimension horizontal de la pantalla)
Dibujemos una pantalla para explicar su direccionamiento:
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
---------------------------------------------------------------
0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
5 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
9 * * * * * * * * R * * * * * * * * * * * * * * * * * * * * * * *
0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
5 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7 * * * * * * * * * * * * * * * * * * * * * * * * * * * * S * * *
8 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
9 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Como comprobara el lector, esta pantalla tiene el formato:32 * 20 * 256, el cual es muy similar al del modo 13 y nos valdraá para explicar el direccionamiento.
Supongamos que queremos pintar la posicion indicada por el simbolo "R". Pensemos que tenemos definada una funcion pintar son la siguiente sintaxis:
Pintar (posicion_horizontal, posicion_vertical , color )
Pintar R == Pintar (8 , 9 ,color)
Hasta aqui todo claro, pero vallamos al fin de todo esto. Nuestro objetivo es programar en ASM, y por tanto usando directamente los recursos aportados por la maquina. Pues bien, la memoria en un ordenador, no esta colocada con el formato de un tablero, como el de la figura, sino que la memoria es lineal, es decir, que si queremos acceder a la posicion "R" tenemos que desplazarnos 296 posiciones. Me explico, la formula de direccionamiento del Modo 13 responde a la formula:
Posicion:= y * 320 + x
y la de nuestro modo virtual:
Posicion:= y * 32 + x
Ahora ya podeis entender lo de 296 = 9 * 32 + 8
S:=17 * 32 + 28
Pero basta ya de teoria, ya vamos a pintar puntitos
Rapidamente, voy a poner los procedimientos en Pascal para escribir un punto, para lo cual tendremos que inicializar el modo 13.
PROGRAM PUNTO1;
USES CRT;
VAR
reg:registers; {Es un tipo interno de pascal}
begin
{Iniciamos modo 13}
reg.ax:=$13; {El $ es para poner formato hexadecimal en pascal}
intr ($10,reg);
{Ponemos el punto en la posicion 100,100, de color azul.}
mem[$a000:100*320*100]:=3; {El segmento de la VGA es el 0A000H}
delay(5000) ; {Esperamos 5 segundos }
{Volvemos a modo texto}
reg.ax:=$3; {El $ es para pones formato hexadecimal en pascal}
intr ($10,reg);
end.
Explicamos el programa:
La primera sentencia que usamos es "USES crt", donde le indicamos al compilador que importe dicha libreria, ya que la necesitamos para la orden "delay()".
Despues declaramos una variable de tipo REGISTERS, para que el pascal interactue con ella al llamar a el procedimiento "INTR". Se trata de una variable, que contiene todos los valores de los registros usados por el 80x86.
Empezamos el programa iniciaziando el modo 13:
reg.AX:=$13 {Entiende ahora lo del modo 13}
intr ($10,reg) {llamamos a la interrupcion 10 del DOS, pasandole a los registros internos los valores de la variable reg}
Ahora ha llegado el momento, de al menos, explicar esta orden:
FORMATO : intr ( N∫ Interrupcion, Variable tipo REGISTERS)
Luego , escribimos el punto, usamos un formato de :
MEM[segmento, desplazamiento] := valor
El resto del programa carece de importancia comentarlo.
A estas alturas, el lector avanzado, podraá pensar, ¿y para que cojones me ha estado liando este tio con todo lo anterior, si con una linea ya escribo en pantalla?. Bien, esto tiene facil respuesta, buscamos la velocidad de ejecucion y la eficiencia en el codigo, ya que, como el propio lector comprobar, cuando realizemos operaciones de rellenado de poligonos y otras de complejidad mas avanzada, bien sea un sombreado Phong o un Voxel 3D, se dara cuenta que una implementacion en alto nivel (Pascal,C, etc...) relentiza los procesos, eliminando toda su vistosidad y estableciendo tiempos de ejecucion mas de 10 veces mayores que si se implementan en ASM. Pero bueno, como dijo un famoso periodista, el tiempo daráy quitaráopiniones, je, je.
Pasemos a realizar la funcion de ponerpunto en ensamblador:
Function Ponerpunto(x,y:word; c:byte);
- X -> Va a variar entre 0 y 319, al ser este valor (319) mayor que lo maximo posible abarcado por una variable de tipo BYTE = Octeto = 8 pixels = 2^8 posibilidades = 256, la declaramos de tipo WORD = 16 pixels= 2 bytes = 65536 = 1 segmento.
- Y -> Va a variar entre 0 y 199.
- C -> Va a variar entre 0 y 255.
Mirar, sin ni siquiera empezar a implementarlo, hemos aprendido muchas mas cosas que en el ejemplo anterior, por un lado, nos fijamos en el tamaño de las variables, y nos damos cuenta que necesitamos una WORD para poder direccionar el "eje X". Por otro, hemos visto que 1 segmento es el maximo valor direccionable con una WORD, lo que significa que usando una variable de tipo word, por muchas burradas que queramos meter en ella, nunca nos saldremos del segmento de Video (Ventaja INTEL). Por otro lado, fijese que el producto de 320 * 200 = 64000 == 1 segmento, por tanto, ahora entiende que se direccione directamente, ya que no hay cambios de segmento.
Bien, comencemos a implementarlo. En pascal hay 2 formas de introducir codigo ensamblador, bien sea mediante la sentencia ASM ... END, o incluyendo un modulo objeto (lo que permite introducir codigo de 32 bits, al contrario de lo que se decia en PC AL LIMITE, si se puede <Se vera mas adelante>). Tambien hay 2 formas de declarar pocedimientos con codigo ASM, una de de ellas totalmente ligada a la primera.
1) PROCEDURE PONER_PUNTO(X,Y:word; C:byte);
begin
<Posible codigo pascal>
asm
<codigo asm>
end
<Posible codigo pascal>
end;
2) PROCEDURE PONER_PUNTO(X,Y:word; C:byte);ASSEMBLER
begin
<codigo asm>
end;
La primera permite mezclar ASM y PASCAL. Mientras que la segunda solo permite ensamblador.
Comenzemos a programar...
A partir de ahora, vamos a organizar un poco las cosas. Vamos a imponer una metodologia de programacion modular, donde cada metodo estara incluido en un PROCEDIMIENTO y este pertenecera a una unidad.
Yo les recomiendo una nomenclatura cojida de un tal Luis Van Gaales:
EJ Unidades : u_modo13, u_giros, u_paleta, u_3d_poligonos...
Como pascal coje los 8 primeros caracteres, como cualquier otro lenguaje que trabaje bajo DOS, fijese bien a la hora de escribir el nombre.
Supongamos que tenemos 2 procedimientos para cargar el MODO 13 y para volver al modo TEXTO. (Mas adelante los detallaremos en la unidad u_ryfasm) <Llámaremos asi a la 1° unidad que realizemos en modo 13>, el nombre fue el primero que se me ocurrio cuando mi hermano me explicaba algunos conceptos de graficos.
El nombre biene de "ryf" -> Ricardo y Francisco, "asm" -> ASM =>Ensamblador
El nombre viene de "baja" -> Es en baja Resolucion,
"256" -> Permite 256 colores.
Estos son:
baja256; "baja" -> Es en baja Resolucion,
"256" -> Permite 256 colores.
Modotxt; Sin comentarios.
PROCEDURE PONER_PUNTO(X,Y:word; C:byte);
BEGIN asm
mov ax, $a000
mov es, ax ;{Colocamos el segmento en es}
mov ax,320 ;
mul y ;{ Multimplicamos y * 320}
add ax,x ;{ Sumamos x}
mov cl,c
mov bx,ax
mov es:[bx],cl
end END;
¿Por que tanto mov?, expliquemos, el Intel se deseño con una dependencia del ACUMULADOR barbara, por tanto, la mayoria de las ordenes necesitan de este para funcionar. No me voy a detener en explicar los formatos permitidos por este procesador, ya que hay libros que los explican y detallan muy bien todas las posibles maneras, pero si lo que atañe al ejemplo
mov ax, $a000 -> No esta permitido la operacion de MOV con operando destino un registro de segmento (DS,ES,SS). Ve ahora el lector como este libro no puede ser para cualquier persona, fijese, estoy intentando pasar lo mas deprisa por este tema, y me doy cuenta de la cantidad de detalles que es necesario considerar a la hora de programar Graficos. Bien, me veo un 'poquirrin' generoso:
FORMATO :
Mover: MOV operando_destino, operando_origen
Sumar: ADD operando_destino, operando_origen
Multiplicar: MUL argumento
Ej:
AX:=AX+7 -> ADD AX,7
AX:=AX*8 -> MUL AX, 8
AX:=BX*8 -> MOV AX,8
MUL BX --> La orden mul, solo permite como argumentos
registros o variables, sin permitir un dato in-
mediato.
ES:[45]:=5 -> No podemos hacerlo con:
mov ES:[45],5 -> ya que dicho direccionamiento
no esta permitido.
Debemos hacer:
mov bl,5
mov ES:[45],bl
No entro en cosideraciones sobre error en tipo (Ej mov ah,bx), ni
otros errores de formato, ya que entonces necesitaria otro libro para
ello. Propongo a los lectores que se derijan a obras como
UNIVERSO DIGITAL
PC INTERNO
... <Colocar aqui nombres de libros que traten
sobre ASM >
Bueno eso es todo por este numero, mas que nada por espacio ;) este texto a sido cedido por Ricardo Cabello Torres, al que agredecemos muchisimo su colaboracion para con nuestra revista, esperamos no tener que dejar este curso colgado, pero tranquilos, por nosotros no va a quedar ;).
Comments