Las primitivas son dibujos básicos

39
 Las primitivas son dibujos básicos, ya sean líneas, círculos, rectángulos, etc.  Todas las funciones que vayamos a crear, hacen uso de la rutina de poner pixeles PutPixel(), por lo que será esta la rutina que deberá estar mejor optimizada. Círculos Razón de aspecto y resoluciones cuadradas Líneas Rectángulos Ejemplos Círculos Ahora vamos a empezar con una de las rutinas de uso mas frecuente, la de poner círculos en la pantalla. Para poder realizar esto usaremos las ecuaciones de la circunferencia en coordenadas polares que son: Estas ecuaciones serán las que ocuparemos para calcular cada punto (x,y) del círculo, donde el r será obviamente el radio de círculo y q será el angulo que forma el radio con la parte positiva del eje x. En forma gráfica sería así:  El ángulo deberá estar en radianes ya que las funciones de seno y coseno que incluye C , trabajan son los ángulos en radianes. La fórmula para transformar grados a radianes es la siguiente:  Entonces para dibujar el círculo de un radio determinado, solamente tenemos que hacer un ciclo desde 0 hasta 360, pero con incrementos pequeños, calcular cada punto con las ecuaciones en coordenadas polares e ir dibujando cada punto. El ciclo en vez de ir de 0 a 360 ira de 0 a 6.28 (360*3.14/180=6.28) ya que el ángulo debe estar en radianes. Como dijimos el ciclo de 0 a 6.28 debe hacerse con incrementos pequeños, no contando de uno en uno, ya que para un circulo de radio muy grande, podrían aparecer huecos entre un punto y el siguiente, por lo tanto tenemos que usar 

Transcript of Las primitivas son dibujos básicos

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 139

Las primitivas son dibujos baacutesicos ya sean liacuteneas ciacuterculos rectaacutengulos etc Todas las funciones que vayamos a crear hacen uso de la rutina de poner pixeles PutPixel() por lo que seraacute esta la rutina que deberaacute estar mejor optimizada

bull Ciacuterculosbull Razoacuten de aspecto y resoluciones cuadradasbull Liacuteneasbull Rectaacutengulosbull Ejemplos

Ciacuterculos Ahora vamos a empezar con una de las rutinas de uso mas frecuente la deponer ciacuterculos en la pantalla Para poder realizar esto usaremos las ecuacionesde la circunferencia en coordenadas polares que son

Estas ecuaciones seraacuten las que ocuparemos para calcular cada punto (xy) delciacuterculo donde el r seraacute obviamente el radio de ciacuterculo y q seraacute el angulo queforma el radio con la parte positiva del eje x En forma graacutefica seriacutea asiacute

El aacutengulo deberaacute estar en radianes ya que las funciones de seno y coseno queincluye C trabajan son los aacutengulos en radianes La foacutermula para transformar grados a radianes es la siguiente

Entonces para dibujar el ciacuterculo de un radio determinado solamente tenemosque hacer un ciclo desde 0 hasta 360 pero con incrementos pequentildeoscalcular cada punto con las ecuaciones en coordenadas polares e ir dibujandocada punto El ciclo en vez de ir de 0 a 360 ira de 0 a 628 (360314180=628)ya que el aacutengulo debe estar en radianes Como dijimos el ciclo de 0 a 628 debe hacerse con incrementos pequentildeos nocontando de uno en uno ya que para un circulo de radio muy grande podriacuteanaparecer huecos entre un punto y el siguiente por lo tanto tenemos que usar

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 239

un incremento fraccionario El valor 0005 produce buenos resultados Dibujar el ciacuterculo punto a punto es una tarea un poco lento debido a que se debecalcular en cada punto el seno y el coseno del angulo y estas funcionas sonmuy lentas Para solucionar esto se deben crear tablas predefinidas oprecalculadas pero esto lo podraacutes ver en la seccioacuten correspondiente

Ahora veremos como nos quedariacutea una rutina en lenguaje C para dibujar unciacuterculo en pantalla

void Circle(int cx int cy int radio unsigned char color)

float angulo=0 int x y do

x = cx + radio cos(angulo) y = cy + radio sin(angulo) if((xgt=0) ampamp (ygt=0) ampamp (xlt320) ampamp (ylt200))

PutPixel(x y color) angulo+=0005

while(angulolt628)

Noacutetese que al calcular las coordenadas x e y estamos sumaacutendoles lascoordenadas cx e cy Esto se hace para trasladar el centro del ciacuterculo acualquier punto que queramos De esta forma para dibujar un ciacuterculosolamente tenemos que especificar las coordenadas del centro el radio y elcolor del ciacuterculo La condicioacuten que se encuentre antes del PutPixel nos sirve para verificar quelas coordenadas que se calculan no se salgan de los bordes de la pantallaEsta verificacioacuten hace que la rutina vaya un poco maacutes lenta Acueacuterdense quelas funciones cos() sin() se encuentran en mathh

Volver

Razoacuten de aspecto y resoluciones cuadradas Algo que se puede observar es que nuestros ciacuterculos no son exactamentecirculares es decir estaacuten un poco ldquoalargadosrdquo Esto se debe a que no estamosutilizando una resolucioacuten cuadrada Una resolucioacuten cuadrada es aquella en la que la resolucioacuten (o nuacutemero depixeles) en X es 43 de la resolucioacuten en Y ya que esto corresponde con lasmedidas fiacutesicas de la pantalla y ocasiona que los pixeles sean cuadradosEjemplos de resoluciones ldquocuadradasrdquo son 640x480 o 320x240 y 800x600 Pero nuestra resolucioacuten de 320x200 no produce pixeles cuadrados sino

rectaacutengulos que son un poco alargados en el sentido del eje Y

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 339

Si queremos dibujar un ciacuterculo perfecto en el modo 320x200 tendriacuteamos quedividir el radio de la coordenada Y por un factor de 12 ya que

Podemos modificar nuestra funcioacuten para colocar un ciacuterculo ara que dibujeciacuterculos bien proporcionados solo hay que cambiar la liacutenea que dice y = cy + radio sin(angulo) por una que diga

y = cy + radio sin(angulo) 12 De esta forma podemos dibujar ciacuterculos maacutes ldquoperfectosrdquo aunque sea un pocomaacutes lento ya que se hace una divisioacuten extra por cada punto

Volver

Liacuteneas Muchos pensaran que dibujar liacuteneas es mucho maacutes faacutecil que hacer un ciacuterculopero estaacuten muy equivocados Las liacuteneas son maacutes difiacuteciles de dibujar que losciacuterculos y aun mas difiacutecil es dibujarlas raacutepido La razoacuten principal es que para los ciacuterculos ya teniacuteamos las funciones de seno ycoseno precalculadas y el resto es simplemente un ciclo Para las liacuteneas es diferente Primero tenemos que calcular la pendiente de larecta ver si es positiva o negativa ver si es mayor o menor que 1 y hasta quetengamos toda esa informacioacuten podremos dibujar una liacutenea Si las liacuteneas son horizontales o verticales no hay ninguacuten problema Para dibujar una liacutenea horizontal la funcioacuten seriacutea asiacute

void LineH(int x int y int ancho unsigned char color)

int i for(i=x ilt=x+ancho i++)

PutPixel(i y color)

Y para hacer la liacutenea vertical

void LineV(int x int y int alto unsigned char color)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 439

int i for(i=y ilt=y+alto i++)

PutPixel(x i color)

Ahora veremos como dibujar un liacutenea si esta tiene cualquier pendiente es decir esta inclinada hacia alguacuten lado Para solucionar esto podemos utilizar laecuacioacuten de la recta que es y = pendiente x pero nosotros veremos un algoritmo que es muchiacutesimo maacutes eficaz y se conocecon el nombre de ALGORITMO DE BRESENHAM Este algoritmo se basa enque cuando vamos a colocar un punto solo hay tres posibles soluciones (x+1y) o (x+1 y-1) o (x+1 y+1) El objetivo es trazar una liacutenea entre los puntos (xy) e (x1 y1) Veamos un ejemplo si x2 e y2 sin mayores que x1 e y1 entonces

calculamos longitud_x = abs(x2 - x1) longitud_y = abs(y2 ndash y1) (Nota la funcioacuten abs() se refiere al valor absoluto de un nuacutemero) entonces tenemos que longitud_x es mayor o igual a longitud_y Asiacute medianteotras dos variables que representen el punto actual a poner inicializaremos losvalores x1 para x e y1 para y Como hemos dicho este algoritmo se basa en ir tomando decisiones por eso tambieacuten tendremos que tener otra variable quenos indique la decisioacuten tomada para saber hacia que posicion nos correspondeir asiacute sabremos cuando tendremos que sumas uno a la variablePunto_actual_y Decision = (longitud_y + longitud_x) ndash longitud_x Punto_actual_x = x1 Punto_actual_y = y1 Y lo que tendremos que hacer ahora es tan solo ir repitiendo desde x1 a x2 elciclo Deberemos poder adaptar el algoritmo a todos los casos ya que sepuede dar que x1 e y1 sean mayores que x2 e y2 de manera que restaremosen uno en cada paso en vez de sumar Como esta es muy poro enredadoveremos como nos quedariacutea la funcion realizada en lenguaje C Pero antesharemos una funcioacuten que nos seraacute muy util en la rutina para colocar una liacuteneay es la siguiente

int sgn(int x)

if(xgt0) return(1) if(xlt0) return(-1) return (0)

la cual nos devuelve simplemente el signo de un nuacutemero o bien cero

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 539

void Line(int x1 int y1 int x2 int y2 unsigned char color)

int i s u v dx1 dx2 dy1 dy2 m n u=x2-x1 v=y2-y1 dx1=sgn(u) dy1=sgn(v) dx2=sgn(u) dy2=0 m=abs(u) n=abs(v) if((mgtn))

dx2=0 dy2=sgn(v) m=abs(v) n=abs(u)

s=mgtgt2 s=m2 for(i=0 ilt=m i++)

PutPixel(x1 y1 color) s=s+n if ((sltm)) s=s-m x1=x1+dx1 y1=y1+dy1

else

x1=x1+dx2 y1=y1+dy2

Volver

Rectaacutengulos Dibujar un rectaacutengulo es lo maacutes simple que hay simplemente se trazan dosliacuteneas horizontales y dos verticales Veamos entonces como nos quedariacutea elcoacutedigo

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 639

void Box(int x1 int y1 int x2 int y2 unsigned char color)

LineV(x2 y1 y2-y1 color)LineV(x1 y1 y2-y1 color) LineH(x1 y1 x2-x1 color)LineH(x1 y2 x2-x1 color)

Tambieacuten se pueden crear cuadros rellenos de alguacuten color esto tambieacuten essimple veamos como nos queda

void FillBox(int x int y int ancho int alto unsigned char color)

int px py for(px=x pxlt=x+ancho px++)

for(py=y pylt=y+alto py++) PutPixel(px py color)

Volver

Ejemplos A continuacioacuten encontraraacutes varios ejemplos usando las rutinas que vimos Libreriacutea graacutefica vgalibh

bull Dibujo de liacuteneas horizontales y verticales bull Dibujo de un circulo bull Liacuteneas que rotan bull Movimiento de un cuadrado bull Dibuja una figura geomeacutetrica denominada Toro mediante varios ciacuterculos bull Dibuja todas la primitivas vistas en forma aleatoria

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

PantallasVirtuales

Sprites

TablasPrefedifinidas

Efectos

Texto

Formatos graacuteficos

Ahora veremos como funciona la paleta de colores para poder cambiar nosotros mismos los colores y asiacute poder personalizarnosun programa o por ejemplo cuando cargamos una imagen quetambieacuten es necesario poner la paleta de esa imagen Vamos empezar viendo como funciona lo de la paleta de coloresque control un chip llamado DAC (Digital Analog Converter) paraasiacute conseguir hacer efectos de paleta pero estos lo encontrarasen la seccioacuten de efectos (hacer link)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 739

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Como ya sabemos en el modo 13h disponemos de una paleta de8 bits o sea 256 colores Cada color se consigue a basa demezclar tres componentes para ir consiguiendo asiacute diferentestonalidades Asiacute tenemos que un color estaacute formado por tres

colores baacutesicos el rojo verde y azul Estos tres colores puedentener un maacuteximo de 64 tonalidades desde el 0 (maacutes oscuro)hasta el 63 (maacutes claro) Esto es asiacute porque el sistema que seutiliza es el denominado RGB (Red Green Blue) que es el queel monitor utiliza para representar el color de un pixel ya que esteposee tres haces de luz una haz rojo otro verde y uno azul loscuales apuntan a una sola posicioacuten que es lo que conocemoscomo el haz de electrones y mezclaacutendose se consigue crear elcolor deseado Si queremos conseguir un color gris bastaraacute conponer los valores RGB a la misma intensidad cada uno Veamosun ejemplo si queremos que el color 0 sea negro entonces

utilizamos los valores (0 0 0) o si queremos que sea blancocolocamos los valores (63 63 63) Y si lo que queremos es quesea de color rojo intenso ponemos (63 0 0) y asiacute se puede jugar con los valores A continuacioacuten les muestro los valores de algunos colorescomunes

Con unos caacutelculos podemos ver que el numero total detonalidades disponibles es de 264 144 (64^3) diferentes perosolo podremos representar simultaacuteneamente 256 ya que la

profundidad es de 8 bits y lo maacuteximo que podemos representar enun byte es el valor 255 (0-255) Pero como podemos cambiar loscolores bueno como dije antes el chip encargado de esta tarea esel DAC o Digital Analog Converter cuya misioacuten es la detransformas las sentildeales digitales del computador a sentildealesanaloacutegicas que utiliza el monitor Para acceder a este chip yolvidarnos de la BIOS la cual dispone de funciones para trabajar con la paleta nosotros usaremos tres puertos a traveacutes de loscuales podremos leer y escribir las diferentes componentes de loscolores Estos registros son el 03C7h el 03C8h y el 03C9h En elsiguiente cuadro podraacutes encontrar la descripcioacuten detallada decada uno

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 839

Como vemos para leer el valor actual de un color lo quetendriacuteamos que hacer es primero enviar al puerto 3C7h elnuacutemero de color del que queremos obtener los 3 valores y luegoobtener y leer tres valores del puerto 3C9h que corresponderaacuten a

los valores RGB del color nuacutemero x que indicamos en el puerto3C7h Y si lo que queremos es cambiar los valores RGB de undeterminado color lo que haremos seraacute primero enviar al puerto3C8h el nuacutemero del color a cambiar y despueacutes enviar los valoresRGB al puerto 3C9h A continuacioacuten veremos las rutinascorrespondientes en C para cambiar y leer los valores RGB de uncolor determinado Cambiar los valores RGB de un color

void SetColor(unsigned char color char r char g char b)

outportb(0x3C8 color) outportb(0x3C9 r)outportb(0x3C9 g)outportb(0x3C9 b)

Y para leer los valores RGB de un color se hariacutea asiacute

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 939

void GetColor(unsigned char color char r char g char b)

outportb(0x3C7 color) r=inportb(0x3C9)g=inportb(0x3C9)b=inportb(0x3C9)

Ya sabemos cambiar los colores ahora veremos como seriacutean lasrutinas para cambiar o obtener una paleta Antes de estodebemos crear una estructura que nos permita guardar las paletaesto simplemente se puede hacer utilizando un arreglo de tamantildeo

768 (2563) y se podriacutea declarar de la siguiente manera char paleta[768] o incluso se podriacutea crear un tipo de dato llamado t_paleta paraasiacute hacer mas faacutecil las declaraciones de paletas en los programasque realicemos esto seriacutea asiacute typedef char t_paleta[768] de esta forma cuando queramos crear una variable que guarde lapaleta en este caso llamada pal simplemente la declarariacuteamosasiacute t_paleta pal La rutina modificar la paleta seriacutea asiacute

void SetPal(t_paleta pal) int i for(i=0 ilt256 i++)

SetColor(i pal[i3] pal[(i3)+1] pal[(i3)+2])

Lo que se hace aquiacute es recorrer los 256 colores y por cada uno ir cambiando las intensidades RGB correspondientes Y por uacuteltimo la rutina para obtener una paleta

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1039

void GetPal(t_paleta pal)

int i for(i=0 ilt256 i++) GetColor(i amppal[i3] amppal[(i3)+1] amppal[(i3)+2])

En esta rutina se hace simplemente lo contrario a la rutina SetPalNuevamente recorremos los 256 colores y por cada uno vamosobteniendo las intensidades RGB de cada color Cuandollamamos a la rutina GetColor debemos pasarle los valores RGBpor referencia es decir la direccioacuten para que de esta formasalgan modificados Lo que hariacutea en realidad la rutina GetPalseriacutea obtener la paleta activa que se encuentra en el sistema Ejemplos Libreriacutea graacutefica vgalibh

bull

Creacioacuten de distntos colores modificando las intensidadesRGB bull Cambio de los colores de la paleta

PantallasVirtuales

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirvenbull iquestCoacutemo se hace una pantalla virtualbull iquestCoacutemo dibujar en la pantalla virtualbull iquestCoacutemo copiamos una pantalla virtual a la VGAbull Ejemplo

iquestQueacute son y para queacute sirven Alguna vez habraacuten visto alguna demo o por lo menos un juegocomercial y se habraacuten dado cuenta que se hacen muchasanimaciones y efectos y no se ve ni el maacutes miacutenimo parpadeoen la pantalla Si por ejemplo nosotros realizamos una animacioacuten simple como

puede ser el movimiento de un cuadrado por la pantallanotaremos que el movimiento no es suave sino que la figuraparpadea constantemente y a veces puede pasar que no se vea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 239

un incremento fraccionario El valor 0005 produce buenos resultados Dibujar el ciacuterculo punto a punto es una tarea un poco lento debido a que se debecalcular en cada punto el seno y el coseno del angulo y estas funcionas sonmuy lentas Para solucionar esto se deben crear tablas predefinidas oprecalculadas pero esto lo podraacutes ver en la seccioacuten correspondiente

Ahora veremos como nos quedariacutea una rutina en lenguaje C para dibujar unciacuterculo en pantalla

void Circle(int cx int cy int radio unsigned char color)

float angulo=0 int x y do

x = cx + radio cos(angulo) y = cy + radio sin(angulo) if((xgt=0) ampamp (ygt=0) ampamp (xlt320) ampamp (ylt200))

PutPixel(x y color) angulo+=0005

while(angulolt628)

Noacutetese que al calcular las coordenadas x e y estamos sumaacutendoles lascoordenadas cx e cy Esto se hace para trasladar el centro del ciacuterculo acualquier punto que queramos De esta forma para dibujar un ciacuterculosolamente tenemos que especificar las coordenadas del centro el radio y elcolor del ciacuterculo La condicioacuten que se encuentre antes del PutPixel nos sirve para verificar quelas coordenadas que se calculan no se salgan de los bordes de la pantallaEsta verificacioacuten hace que la rutina vaya un poco maacutes lenta Acueacuterdense quelas funciones cos() sin() se encuentran en mathh

Volver

Razoacuten de aspecto y resoluciones cuadradas Algo que se puede observar es que nuestros ciacuterculos no son exactamentecirculares es decir estaacuten un poco ldquoalargadosrdquo Esto se debe a que no estamosutilizando una resolucioacuten cuadrada Una resolucioacuten cuadrada es aquella en la que la resolucioacuten (o nuacutemero depixeles) en X es 43 de la resolucioacuten en Y ya que esto corresponde con lasmedidas fiacutesicas de la pantalla y ocasiona que los pixeles sean cuadradosEjemplos de resoluciones ldquocuadradasrdquo son 640x480 o 320x240 y 800x600 Pero nuestra resolucioacuten de 320x200 no produce pixeles cuadrados sino

rectaacutengulos que son un poco alargados en el sentido del eje Y

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 339

Si queremos dibujar un ciacuterculo perfecto en el modo 320x200 tendriacuteamos quedividir el radio de la coordenada Y por un factor de 12 ya que

Podemos modificar nuestra funcioacuten para colocar un ciacuterculo ara que dibujeciacuterculos bien proporcionados solo hay que cambiar la liacutenea que dice y = cy + radio sin(angulo) por una que diga

y = cy + radio sin(angulo) 12 De esta forma podemos dibujar ciacuterculos maacutes ldquoperfectosrdquo aunque sea un pocomaacutes lento ya que se hace una divisioacuten extra por cada punto

Volver

Liacuteneas Muchos pensaran que dibujar liacuteneas es mucho maacutes faacutecil que hacer un ciacuterculopero estaacuten muy equivocados Las liacuteneas son maacutes difiacuteciles de dibujar que losciacuterculos y aun mas difiacutecil es dibujarlas raacutepido La razoacuten principal es que para los ciacuterculos ya teniacuteamos las funciones de seno ycoseno precalculadas y el resto es simplemente un ciclo Para las liacuteneas es diferente Primero tenemos que calcular la pendiente de larecta ver si es positiva o negativa ver si es mayor o menor que 1 y hasta quetengamos toda esa informacioacuten podremos dibujar una liacutenea Si las liacuteneas son horizontales o verticales no hay ninguacuten problema Para dibujar una liacutenea horizontal la funcioacuten seriacutea asiacute

void LineH(int x int y int ancho unsigned char color)

int i for(i=x ilt=x+ancho i++)

PutPixel(i y color)

Y para hacer la liacutenea vertical

void LineV(int x int y int alto unsigned char color)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 439

int i for(i=y ilt=y+alto i++)

PutPixel(x i color)

Ahora veremos como dibujar un liacutenea si esta tiene cualquier pendiente es decir esta inclinada hacia alguacuten lado Para solucionar esto podemos utilizar laecuacioacuten de la recta que es y = pendiente x pero nosotros veremos un algoritmo que es muchiacutesimo maacutes eficaz y se conocecon el nombre de ALGORITMO DE BRESENHAM Este algoritmo se basa enque cuando vamos a colocar un punto solo hay tres posibles soluciones (x+1y) o (x+1 y-1) o (x+1 y+1) El objetivo es trazar una liacutenea entre los puntos (xy) e (x1 y1) Veamos un ejemplo si x2 e y2 sin mayores que x1 e y1 entonces

calculamos longitud_x = abs(x2 - x1) longitud_y = abs(y2 ndash y1) (Nota la funcioacuten abs() se refiere al valor absoluto de un nuacutemero) entonces tenemos que longitud_x es mayor o igual a longitud_y Asiacute medianteotras dos variables que representen el punto actual a poner inicializaremos losvalores x1 para x e y1 para y Como hemos dicho este algoritmo se basa en ir tomando decisiones por eso tambieacuten tendremos que tener otra variable quenos indique la decisioacuten tomada para saber hacia que posicion nos correspondeir asiacute sabremos cuando tendremos que sumas uno a la variablePunto_actual_y Decision = (longitud_y + longitud_x) ndash longitud_x Punto_actual_x = x1 Punto_actual_y = y1 Y lo que tendremos que hacer ahora es tan solo ir repitiendo desde x1 a x2 elciclo Deberemos poder adaptar el algoritmo a todos los casos ya que sepuede dar que x1 e y1 sean mayores que x2 e y2 de manera que restaremosen uno en cada paso en vez de sumar Como esta es muy poro enredadoveremos como nos quedariacutea la funcion realizada en lenguaje C Pero antesharemos una funcioacuten que nos seraacute muy util en la rutina para colocar una liacuteneay es la siguiente

int sgn(int x)

if(xgt0) return(1) if(xlt0) return(-1) return (0)

la cual nos devuelve simplemente el signo de un nuacutemero o bien cero

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 539

void Line(int x1 int y1 int x2 int y2 unsigned char color)

int i s u v dx1 dx2 dy1 dy2 m n u=x2-x1 v=y2-y1 dx1=sgn(u) dy1=sgn(v) dx2=sgn(u) dy2=0 m=abs(u) n=abs(v) if((mgtn))

dx2=0 dy2=sgn(v) m=abs(v) n=abs(u)

s=mgtgt2 s=m2 for(i=0 ilt=m i++)

PutPixel(x1 y1 color) s=s+n if ((sltm)) s=s-m x1=x1+dx1 y1=y1+dy1

else

x1=x1+dx2 y1=y1+dy2

Volver

Rectaacutengulos Dibujar un rectaacutengulo es lo maacutes simple que hay simplemente se trazan dosliacuteneas horizontales y dos verticales Veamos entonces como nos quedariacutea elcoacutedigo

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 639

void Box(int x1 int y1 int x2 int y2 unsigned char color)

LineV(x2 y1 y2-y1 color)LineV(x1 y1 y2-y1 color) LineH(x1 y1 x2-x1 color)LineH(x1 y2 x2-x1 color)

Tambieacuten se pueden crear cuadros rellenos de alguacuten color esto tambieacuten essimple veamos como nos queda

void FillBox(int x int y int ancho int alto unsigned char color)

int px py for(px=x pxlt=x+ancho px++)

for(py=y pylt=y+alto py++) PutPixel(px py color)

Volver

Ejemplos A continuacioacuten encontraraacutes varios ejemplos usando las rutinas que vimos Libreriacutea graacutefica vgalibh

bull Dibujo de liacuteneas horizontales y verticales bull Dibujo de un circulo bull Liacuteneas que rotan bull Movimiento de un cuadrado bull Dibuja una figura geomeacutetrica denominada Toro mediante varios ciacuterculos bull Dibuja todas la primitivas vistas en forma aleatoria

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

PantallasVirtuales

Sprites

TablasPrefedifinidas

Efectos

Texto

Formatos graacuteficos

Ahora veremos como funciona la paleta de colores para poder cambiar nosotros mismos los colores y asiacute poder personalizarnosun programa o por ejemplo cuando cargamos una imagen quetambieacuten es necesario poner la paleta de esa imagen Vamos empezar viendo como funciona lo de la paleta de coloresque control un chip llamado DAC (Digital Analog Converter) paraasiacute conseguir hacer efectos de paleta pero estos lo encontrarasen la seccioacuten de efectos (hacer link)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 739

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Como ya sabemos en el modo 13h disponemos de una paleta de8 bits o sea 256 colores Cada color se consigue a basa demezclar tres componentes para ir consiguiendo asiacute diferentestonalidades Asiacute tenemos que un color estaacute formado por tres

colores baacutesicos el rojo verde y azul Estos tres colores puedentener un maacuteximo de 64 tonalidades desde el 0 (maacutes oscuro)hasta el 63 (maacutes claro) Esto es asiacute porque el sistema que seutiliza es el denominado RGB (Red Green Blue) que es el queel monitor utiliza para representar el color de un pixel ya que esteposee tres haces de luz una haz rojo otro verde y uno azul loscuales apuntan a una sola posicioacuten que es lo que conocemoscomo el haz de electrones y mezclaacutendose se consigue crear elcolor deseado Si queremos conseguir un color gris bastaraacute conponer los valores RGB a la misma intensidad cada uno Veamosun ejemplo si queremos que el color 0 sea negro entonces

utilizamos los valores (0 0 0) o si queremos que sea blancocolocamos los valores (63 63 63) Y si lo que queremos es quesea de color rojo intenso ponemos (63 0 0) y asiacute se puede jugar con los valores A continuacioacuten les muestro los valores de algunos colorescomunes

Con unos caacutelculos podemos ver que el numero total detonalidades disponibles es de 264 144 (64^3) diferentes perosolo podremos representar simultaacuteneamente 256 ya que la

profundidad es de 8 bits y lo maacuteximo que podemos representar enun byte es el valor 255 (0-255) Pero como podemos cambiar loscolores bueno como dije antes el chip encargado de esta tarea esel DAC o Digital Analog Converter cuya misioacuten es la detransformas las sentildeales digitales del computador a sentildealesanaloacutegicas que utiliza el monitor Para acceder a este chip yolvidarnos de la BIOS la cual dispone de funciones para trabajar con la paleta nosotros usaremos tres puertos a traveacutes de loscuales podremos leer y escribir las diferentes componentes de loscolores Estos registros son el 03C7h el 03C8h y el 03C9h En elsiguiente cuadro podraacutes encontrar la descripcioacuten detallada decada uno

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 839

Como vemos para leer el valor actual de un color lo quetendriacuteamos que hacer es primero enviar al puerto 3C7h elnuacutemero de color del que queremos obtener los 3 valores y luegoobtener y leer tres valores del puerto 3C9h que corresponderaacuten a

los valores RGB del color nuacutemero x que indicamos en el puerto3C7h Y si lo que queremos es cambiar los valores RGB de undeterminado color lo que haremos seraacute primero enviar al puerto3C8h el nuacutemero del color a cambiar y despueacutes enviar los valoresRGB al puerto 3C9h A continuacioacuten veremos las rutinascorrespondientes en C para cambiar y leer los valores RGB de uncolor determinado Cambiar los valores RGB de un color

void SetColor(unsigned char color char r char g char b)

outportb(0x3C8 color) outportb(0x3C9 r)outportb(0x3C9 g)outportb(0x3C9 b)

Y para leer los valores RGB de un color se hariacutea asiacute

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 939

void GetColor(unsigned char color char r char g char b)

outportb(0x3C7 color) r=inportb(0x3C9)g=inportb(0x3C9)b=inportb(0x3C9)

Ya sabemos cambiar los colores ahora veremos como seriacutean lasrutinas para cambiar o obtener una paleta Antes de estodebemos crear una estructura que nos permita guardar las paletaesto simplemente se puede hacer utilizando un arreglo de tamantildeo

768 (2563) y se podriacutea declarar de la siguiente manera char paleta[768] o incluso se podriacutea crear un tipo de dato llamado t_paleta paraasiacute hacer mas faacutecil las declaraciones de paletas en los programasque realicemos esto seriacutea asiacute typedef char t_paleta[768] de esta forma cuando queramos crear una variable que guarde lapaleta en este caso llamada pal simplemente la declarariacuteamosasiacute t_paleta pal La rutina modificar la paleta seriacutea asiacute

void SetPal(t_paleta pal) int i for(i=0 ilt256 i++)

SetColor(i pal[i3] pal[(i3)+1] pal[(i3)+2])

Lo que se hace aquiacute es recorrer los 256 colores y por cada uno ir cambiando las intensidades RGB correspondientes Y por uacuteltimo la rutina para obtener una paleta

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1039

void GetPal(t_paleta pal)

int i for(i=0 ilt256 i++) GetColor(i amppal[i3] amppal[(i3)+1] amppal[(i3)+2])

En esta rutina se hace simplemente lo contrario a la rutina SetPalNuevamente recorremos los 256 colores y por cada uno vamosobteniendo las intensidades RGB de cada color Cuandollamamos a la rutina GetColor debemos pasarle los valores RGBpor referencia es decir la direccioacuten para que de esta formasalgan modificados Lo que hariacutea en realidad la rutina GetPalseriacutea obtener la paleta activa que se encuentra en el sistema Ejemplos Libreriacutea graacutefica vgalibh

bull

Creacioacuten de distntos colores modificando las intensidadesRGB bull Cambio de los colores de la paleta

PantallasVirtuales

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirvenbull iquestCoacutemo se hace una pantalla virtualbull iquestCoacutemo dibujar en la pantalla virtualbull iquestCoacutemo copiamos una pantalla virtual a la VGAbull Ejemplo

iquestQueacute son y para queacute sirven Alguna vez habraacuten visto alguna demo o por lo menos un juegocomercial y se habraacuten dado cuenta que se hacen muchasanimaciones y efectos y no se ve ni el maacutes miacutenimo parpadeoen la pantalla Si por ejemplo nosotros realizamos una animacioacuten simple como

puede ser el movimiento de un cuadrado por la pantallanotaremos que el movimiento no es suave sino que la figuraparpadea constantemente y a veces puede pasar que no se vea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 339

Si queremos dibujar un ciacuterculo perfecto en el modo 320x200 tendriacuteamos quedividir el radio de la coordenada Y por un factor de 12 ya que

Podemos modificar nuestra funcioacuten para colocar un ciacuterculo ara que dibujeciacuterculos bien proporcionados solo hay que cambiar la liacutenea que dice y = cy + radio sin(angulo) por una que diga

y = cy + radio sin(angulo) 12 De esta forma podemos dibujar ciacuterculos maacutes ldquoperfectosrdquo aunque sea un pocomaacutes lento ya que se hace una divisioacuten extra por cada punto

Volver

Liacuteneas Muchos pensaran que dibujar liacuteneas es mucho maacutes faacutecil que hacer un ciacuterculopero estaacuten muy equivocados Las liacuteneas son maacutes difiacuteciles de dibujar que losciacuterculos y aun mas difiacutecil es dibujarlas raacutepido La razoacuten principal es que para los ciacuterculos ya teniacuteamos las funciones de seno ycoseno precalculadas y el resto es simplemente un ciclo Para las liacuteneas es diferente Primero tenemos que calcular la pendiente de larecta ver si es positiva o negativa ver si es mayor o menor que 1 y hasta quetengamos toda esa informacioacuten podremos dibujar una liacutenea Si las liacuteneas son horizontales o verticales no hay ninguacuten problema Para dibujar una liacutenea horizontal la funcioacuten seriacutea asiacute

void LineH(int x int y int ancho unsigned char color)

int i for(i=x ilt=x+ancho i++)

PutPixel(i y color)

Y para hacer la liacutenea vertical

void LineV(int x int y int alto unsigned char color)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 439

int i for(i=y ilt=y+alto i++)

PutPixel(x i color)

Ahora veremos como dibujar un liacutenea si esta tiene cualquier pendiente es decir esta inclinada hacia alguacuten lado Para solucionar esto podemos utilizar laecuacioacuten de la recta que es y = pendiente x pero nosotros veremos un algoritmo que es muchiacutesimo maacutes eficaz y se conocecon el nombre de ALGORITMO DE BRESENHAM Este algoritmo se basa enque cuando vamos a colocar un punto solo hay tres posibles soluciones (x+1y) o (x+1 y-1) o (x+1 y+1) El objetivo es trazar una liacutenea entre los puntos (xy) e (x1 y1) Veamos un ejemplo si x2 e y2 sin mayores que x1 e y1 entonces

calculamos longitud_x = abs(x2 - x1) longitud_y = abs(y2 ndash y1) (Nota la funcioacuten abs() se refiere al valor absoluto de un nuacutemero) entonces tenemos que longitud_x es mayor o igual a longitud_y Asiacute medianteotras dos variables que representen el punto actual a poner inicializaremos losvalores x1 para x e y1 para y Como hemos dicho este algoritmo se basa en ir tomando decisiones por eso tambieacuten tendremos que tener otra variable quenos indique la decisioacuten tomada para saber hacia que posicion nos correspondeir asiacute sabremos cuando tendremos que sumas uno a la variablePunto_actual_y Decision = (longitud_y + longitud_x) ndash longitud_x Punto_actual_x = x1 Punto_actual_y = y1 Y lo que tendremos que hacer ahora es tan solo ir repitiendo desde x1 a x2 elciclo Deberemos poder adaptar el algoritmo a todos los casos ya que sepuede dar que x1 e y1 sean mayores que x2 e y2 de manera que restaremosen uno en cada paso en vez de sumar Como esta es muy poro enredadoveremos como nos quedariacutea la funcion realizada en lenguaje C Pero antesharemos una funcioacuten que nos seraacute muy util en la rutina para colocar una liacuteneay es la siguiente

int sgn(int x)

if(xgt0) return(1) if(xlt0) return(-1) return (0)

la cual nos devuelve simplemente el signo de un nuacutemero o bien cero

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 539

void Line(int x1 int y1 int x2 int y2 unsigned char color)

int i s u v dx1 dx2 dy1 dy2 m n u=x2-x1 v=y2-y1 dx1=sgn(u) dy1=sgn(v) dx2=sgn(u) dy2=0 m=abs(u) n=abs(v) if((mgtn))

dx2=0 dy2=sgn(v) m=abs(v) n=abs(u)

s=mgtgt2 s=m2 for(i=0 ilt=m i++)

PutPixel(x1 y1 color) s=s+n if ((sltm)) s=s-m x1=x1+dx1 y1=y1+dy1

else

x1=x1+dx2 y1=y1+dy2

Volver

Rectaacutengulos Dibujar un rectaacutengulo es lo maacutes simple que hay simplemente se trazan dosliacuteneas horizontales y dos verticales Veamos entonces como nos quedariacutea elcoacutedigo

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 639

void Box(int x1 int y1 int x2 int y2 unsigned char color)

LineV(x2 y1 y2-y1 color)LineV(x1 y1 y2-y1 color) LineH(x1 y1 x2-x1 color)LineH(x1 y2 x2-x1 color)

Tambieacuten se pueden crear cuadros rellenos de alguacuten color esto tambieacuten essimple veamos como nos queda

void FillBox(int x int y int ancho int alto unsigned char color)

int px py for(px=x pxlt=x+ancho px++)

for(py=y pylt=y+alto py++) PutPixel(px py color)

Volver

Ejemplos A continuacioacuten encontraraacutes varios ejemplos usando las rutinas que vimos Libreriacutea graacutefica vgalibh

bull Dibujo de liacuteneas horizontales y verticales bull Dibujo de un circulo bull Liacuteneas que rotan bull Movimiento de un cuadrado bull Dibuja una figura geomeacutetrica denominada Toro mediante varios ciacuterculos bull Dibuja todas la primitivas vistas en forma aleatoria

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

PantallasVirtuales

Sprites

TablasPrefedifinidas

Efectos

Texto

Formatos graacuteficos

Ahora veremos como funciona la paleta de colores para poder cambiar nosotros mismos los colores y asiacute poder personalizarnosun programa o por ejemplo cuando cargamos una imagen quetambieacuten es necesario poner la paleta de esa imagen Vamos empezar viendo como funciona lo de la paleta de coloresque control un chip llamado DAC (Digital Analog Converter) paraasiacute conseguir hacer efectos de paleta pero estos lo encontrarasen la seccioacuten de efectos (hacer link)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 739

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Como ya sabemos en el modo 13h disponemos de una paleta de8 bits o sea 256 colores Cada color se consigue a basa demezclar tres componentes para ir consiguiendo asiacute diferentestonalidades Asiacute tenemos que un color estaacute formado por tres

colores baacutesicos el rojo verde y azul Estos tres colores puedentener un maacuteximo de 64 tonalidades desde el 0 (maacutes oscuro)hasta el 63 (maacutes claro) Esto es asiacute porque el sistema que seutiliza es el denominado RGB (Red Green Blue) que es el queel monitor utiliza para representar el color de un pixel ya que esteposee tres haces de luz una haz rojo otro verde y uno azul loscuales apuntan a una sola posicioacuten que es lo que conocemoscomo el haz de electrones y mezclaacutendose se consigue crear elcolor deseado Si queremos conseguir un color gris bastaraacute conponer los valores RGB a la misma intensidad cada uno Veamosun ejemplo si queremos que el color 0 sea negro entonces

utilizamos los valores (0 0 0) o si queremos que sea blancocolocamos los valores (63 63 63) Y si lo que queremos es quesea de color rojo intenso ponemos (63 0 0) y asiacute se puede jugar con los valores A continuacioacuten les muestro los valores de algunos colorescomunes

Con unos caacutelculos podemos ver que el numero total detonalidades disponibles es de 264 144 (64^3) diferentes perosolo podremos representar simultaacuteneamente 256 ya que la

profundidad es de 8 bits y lo maacuteximo que podemos representar enun byte es el valor 255 (0-255) Pero como podemos cambiar loscolores bueno como dije antes el chip encargado de esta tarea esel DAC o Digital Analog Converter cuya misioacuten es la detransformas las sentildeales digitales del computador a sentildealesanaloacutegicas que utiliza el monitor Para acceder a este chip yolvidarnos de la BIOS la cual dispone de funciones para trabajar con la paleta nosotros usaremos tres puertos a traveacutes de loscuales podremos leer y escribir las diferentes componentes de loscolores Estos registros son el 03C7h el 03C8h y el 03C9h En elsiguiente cuadro podraacutes encontrar la descripcioacuten detallada decada uno

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 839

Como vemos para leer el valor actual de un color lo quetendriacuteamos que hacer es primero enviar al puerto 3C7h elnuacutemero de color del que queremos obtener los 3 valores y luegoobtener y leer tres valores del puerto 3C9h que corresponderaacuten a

los valores RGB del color nuacutemero x que indicamos en el puerto3C7h Y si lo que queremos es cambiar los valores RGB de undeterminado color lo que haremos seraacute primero enviar al puerto3C8h el nuacutemero del color a cambiar y despueacutes enviar los valoresRGB al puerto 3C9h A continuacioacuten veremos las rutinascorrespondientes en C para cambiar y leer los valores RGB de uncolor determinado Cambiar los valores RGB de un color

void SetColor(unsigned char color char r char g char b)

outportb(0x3C8 color) outportb(0x3C9 r)outportb(0x3C9 g)outportb(0x3C9 b)

Y para leer los valores RGB de un color se hariacutea asiacute

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 939

void GetColor(unsigned char color char r char g char b)

outportb(0x3C7 color) r=inportb(0x3C9)g=inportb(0x3C9)b=inportb(0x3C9)

Ya sabemos cambiar los colores ahora veremos como seriacutean lasrutinas para cambiar o obtener una paleta Antes de estodebemos crear una estructura que nos permita guardar las paletaesto simplemente se puede hacer utilizando un arreglo de tamantildeo

768 (2563) y se podriacutea declarar de la siguiente manera char paleta[768] o incluso se podriacutea crear un tipo de dato llamado t_paleta paraasiacute hacer mas faacutecil las declaraciones de paletas en los programasque realicemos esto seriacutea asiacute typedef char t_paleta[768] de esta forma cuando queramos crear una variable que guarde lapaleta en este caso llamada pal simplemente la declarariacuteamosasiacute t_paleta pal La rutina modificar la paleta seriacutea asiacute

void SetPal(t_paleta pal) int i for(i=0 ilt256 i++)

SetColor(i pal[i3] pal[(i3)+1] pal[(i3)+2])

Lo que se hace aquiacute es recorrer los 256 colores y por cada uno ir cambiando las intensidades RGB correspondientes Y por uacuteltimo la rutina para obtener una paleta

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1039

void GetPal(t_paleta pal)

int i for(i=0 ilt256 i++) GetColor(i amppal[i3] amppal[(i3)+1] amppal[(i3)+2])

En esta rutina se hace simplemente lo contrario a la rutina SetPalNuevamente recorremos los 256 colores y por cada uno vamosobteniendo las intensidades RGB de cada color Cuandollamamos a la rutina GetColor debemos pasarle los valores RGBpor referencia es decir la direccioacuten para que de esta formasalgan modificados Lo que hariacutea en realidad la rutina GetPalseriacutea obtener la paleta activa que se encuentra en el sistema Ejemplos Libreriacutea graacutefica vgalibh

bull

Creacioacuten de distntos colores modificando las intensidadesRGB bull Cambio de los colores de la paleta

PantallasVirtuales

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirvenbull iquestCoacutemo se hace una pantalla virtualbull iquestCoacutemo dibujar en la pantalla virtualbull iquestCoacutemo copiamos una pantalla virtual a la VGAbull Ejemplo

iquestQueacute son y para queacute sirven Alguna vez habraacuten visto alguna demo o por lo menos un juegocomercial y se habraacuten dado cuenta que se hacen muchasanimaciones y efectos y no se ve ni el maacutes miacutenimo parpadeoen la pantalla Si por ejemplo nosotros realizamos una animacioacuten simple como

puede ser el movimiento de un cuadrado por la pantallanotaremos que el movimiento no es suave sino que la figuraparpadea constantemente y a veces puede pasar que no se vea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 439

int i for(i=y ilt=y+alto i++)

PutPixel(x i color)

Ahora veremos como dibujar un liacutenea si esta tiene cualquier pendiente es decir esta inclinada hacia alguacuten lado Para solucionar esto podemos utilizar laecuacioacuten de la recta que es y = pendiente x pero nosotros veremos un algoritmo que es muchiacutesimo maacutes eficaz y se conocecon el nombre de ALGORITMO DE BRESENHAM Este algoritmo se basa enque cuando vamos a colocar un punto solo hay tres posibles soluciones (x+1y) o (x+1 y-1) o (x+1 y+1) El objetivo es trazar una liacutenea entre los puntos (xy) e (x1 y1) Veamos un ejemplo si x2 e y2 sin mayores que x1 e y1 entonces

calculamos longitud_x = abs(x2 - x1) longitud_y = abs(y2 ndash y1) (Nota la funcioacuten abs() se refiere al valor absoluto de un nuacutemero) entonces tenemos que longitud_x es mayor o igual a longitud_y Asiacute medianteotras dos variables que representen el punto actual a poner inicializaremos losvalores x1 para x e y1 para y Como hemos dicho este algoritmo se basa en ir tomando decisiones por eso tambieacuten tendremos que tener otra variable quenos indique la decisioacuten tomada para saber hacia que posicion nos correspondeir asiacute sabremos cuando tendremos que sumas uno a la variablePunto_actual_y Decision = (longitud_y + longitud_x) ndash longitud_x Punto_actual_x = x1 Punto_actual_y = y1 Y lo que tendremos que hacer ahora es tan solo ir repitiendo desde x1 a x2 elciclo Deberemos poder adaptar el algoritmo a todos los casos ya que sepuede dar que x1 e y1 sean mayores que x2 e y2 de manera que restaremosen uno en cada paso en vez de sumar Como esta es muy poro enredadoveremos como nos quedariacutea la funcion realizada en lenguaje C Pero antesharemos una funcioacuten que nos seraacute muy util en la rutina para colocar una liacuteneay es la siguiente

int sgn(int x)

if(xgt0) return(1) if(xlt0) return(-1) return (0)

la cual nos devuelve simplemente el signo de un nuacutemero o bien cero

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 539

void Line(int x1 int y1 int x2 int y2 unsigned char color)

int i s u v dx1 dx2 dy1 dy2 m n u=x2-x1 v=y2-y1 dx1=sgn(u) dy1=sgn(v) dx2=sgn(u) dy2=0 m=abs(u) n=abs(v) if((mgtn))

dx2=0 dy2=sgn(v) m=abs(v) n=abs(u)

s=mgtgt2 s=m2 for(i=0 ilt=m i++)

PutPixel(x1 y1 color) s=s+n if ((sltm)) s=s-m x1=x1+dx1 y1=y1+dy1

else

x1=x1+dx2 y1=y1+dy2

Volver

Rectaacutengulos Dibujar un rectaacutengulo es lo maacutes simple que hay simplemente se trazan dosliacuteneas horizontales y dos verticales Veamos entonces como nos quedariacutea elcoacutedigo

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 639

void Box(int x1 int y1 int x2 int y2 unsigned char color)

LineV(x2 y1 y2-y1 color)LineV(x1 y1 y2-y1 color) LineH(x1 y1 x2-x1 color)LineH(x1 y2 x2-x1 color)

Tambieacuten se pueden crear cuadros rellenos de alguacuten color esto tambieacuten essimple veamos como nos queda

void FillBox(int x int y int ancho int alto unsigned char color)

int px py for(px=x pxlt=x+ancho px++)

for(py=y pylt=y+alto py++) PutPixel(px py color)

Volver

Ejemplos A continuacioacuten encontraraacutes varios ejemplos usando las rutinas que vimos Libreriacutea graacutefica vgalibh

bull Dibujo de liacuteneas horizontales y verticales bull Dibujo de un circulo bull Liacuteneas que rotan bull Movimiento de un cuadrado bull Dibuja una figura geomeacutetrica denominada Toro mediante varios ciacuterculos bull Dibuja todas la primitivas vistas en forma aleatoria

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

PantallasVirtuales

Sprites

TablasPrefedifinidas

Efectos

Texto

Formatos graacuteficos

Ahora veremos como funciona la paleta de colores para poder cambiar nosotros mismos los colores y asiacute poder personalizarnosun programa o por ejemplo cuando cargamos una imagen quetambieacuten es necesario poner la paleta de esa imagen Vamos empezar viendo como funciona lo de la paleta de coloresque control un chip llamado DAC (Digital Analog Converter) paraasiacute conseguir hacer efectos de paleta pero estos lo encontrarasen la seccioacuten de efectos (hacer link)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 739

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Como ya sabemos en el modo 13h disponemos de una paleta de8 bits o sea 256 colores Cada color se consigue a basa demezclar tres componentes para ir consiguiendo asiacute diferentestonalidades Asiacute tenemos que un color estaacute formado por tres

colores baacutesicos el rojo verde y azul Estos tres colores puedentener un maacuteximo de 64 tonalidades desde el 0 (maacutes oscuro)hasta el 63 (maacutes claro) Esto es asiacute porque el sistema que seutiliza es el denominado RGB (Red Green Blue) que es el queel monitor utiliza para representar el color de un pixel ya que esteposee tres haces de luz una haz rojo otro verde y uno azul loscuales apuntan a una sola posicioacuten que es lo que conocemoscomo el haz de electrones y mezclaacutendose se consigue crear elcolor deseado Si queremos conseguir un color gris bastaraacute conponer los valores RGB a la misma intensidad cada uno Veamosun ejemplo si queremos que el color 0 sea negro entonces

utilizamos los valores (0 0 0) o si queremos que sea blancocolocamos los valores (63 63 63) Y si lo que queremos es quesea de color rojo intenso ponemos (63 0 0) y asiacute se puede jugar con los valores A continuacioacuten les muestro los valores de algunos colorescomunes

Con unos caacutelculos podemos ver que el numero total detonalidades disponibles es de 264 144 (64^3) diferentes perosolo podremos representar simultaacuteneamente 256 ya que la

profundidad es de 8 bits y lo maacuteximo que podemos representar enun byte es el valor 255 (0-255) Pero como podemos cambiar loscolores bueno como dije antes el chip encargado de esta tarea esel DAC o Digital Analog Converter cuya misioacuten es la detransformas las sentildeales digitales del computador a sentildealesanaloacutegicas que utiliza el monitor Para acceder a este chip yolvidarnos de la BIOS la cual dispone de funciones para trabajar con la paleta nosotros usaremos tres puertos a traveacutes de loscuales podremos leer y escribir las diferentes componentes de loscolores Estos registros son el 03C7h el 03C8h y el 03C9h En elsiguiente cuadro podraacutes encontrar la descripcioacuten detallada decada uno

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 839

Como vemos para leer el valor actual de un color lo quetendriacuteamos que hacer es primero enviar al puerto 3C7h elnuacutemero de color del que queremos obtener los 3 valores y luegoobtener y leer tres valores del puerto 3C9h que corresponderaacuten a

los valores RGB del color nuacutemero x que indicamos en el puerto3C7h Y si lo que queremos es cambiar los valores RGB de undeterminado color lo que haremos seraacute primero enviar al puerto3C8h el nuacutemero del color a cambiar y despueacutes enviar los valoresRGB al puerto 3C9h A continuacioacuten veremos las rutinascorrespondientes en C para cambiar y leer los valores RGB de uncolor determinado Cambiar los valores RGB de un color

void SetColor(unsigned char color char r char g char b)

outportb(0x3C8 color) outportb(0x3C9 r)outportb(0x3C9 g)outportb(0x3C9 b)

Y para leer los valores RGB de un color se hariacutea asiacute

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 939

void GetColor(unsigned char color char r char g char b)

outportb(0x3C7 color) r=inportb(0x3C9)g=inportb(0x3C9)b=inportb(0x3C9)

Ya sabemos cambiar los colores ahora veremos como seriacutean lasrutinas para cambiar o obtener una paleta Antes de estodebemos crear una estructura que nos permita guardar las paletaesto simplemente se puede hacer utilizando un arreglo de tamantildeo

768 (2563) y se podriacutea declarar de la siguiente manera char paleta[768] o incluso se podriacutea crear un tipo de dato llamado t_paleta paraasiacute hacer mas faacutecil las declaraciones de paletas en los programasque realicemos esto seriacutea asiacute typedef char t_paleta[768] de esta forma cuando queramos crear una variable que guarde lapaleta en este caso llamada pal simplemente la declarariacuteamosasiacute t_paleta pal La rutina modificar la paleta seriacutea asiacute

void SetPal(t_paleta pal) int i for(i=0 ilt256 i++)

SetColor(i pal[i3] pal[(i3)+1] pal[(i3)+2])

Lo que se hace aquiacute es recorrer los 256 colores y por cada uno ir cambiando las intensidades RGB correspondientes Y por uacuteltimo la rutina para obtener una paleta

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1039

void GetPal(t_paleta pal)

int i for(i=0 ilt256 i++) GetColor(i amppal[i3] amppal[(i3)+1] amppal[(i3)+2])

En esta rutina se hace simplemente lo contrario a la rutina SetPalNuevamente recorremos los 256 colores y por cada uno vamosobteniendo las intensidades RGB de cada color Cuandollamamos a la rutina GetColor debemos pasarle los valores RGBpor referencia es decir la direccioacuten para que de esta formasalgan modificados Lo que hariacutea en realidad la rutina GetPalseriacutea obtener la paleta activa que se encuentra en el sistema Ejemplos Libreriacutea graacutefica vgalibh

bull

Creacioacuten de distntos colores modificando las intensidadesRGB bull Cambio de los colores de la paleta

PantallasVirtuales

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirvenbull iquestCoacutemo se hace una pantalla virtualbull iquestCoacutemo dibujar en la pantalla virtualbull iquestCoacutemo copiamos una pantalla virtual a la VGAbull Ejemplo

iquestQueacute son y para queacute sirven Alguna vez habraacuten visto alguna demo o por lo menos un juegocomercial y se habraacuten dado cuenta que se hacen muchasanimaciones y efectos y no se ve ni el maacutes miacutenimo parpadeoen la pantalla Si por ejemplo nosotros realizamos una animacioacuten simple como

puede ser el movimiento de un cuadrado por la pantallanotaremos que el movimiento no es suave sino que la figuraparpadea constantemente y a veces puede pasar que no se vea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 539

void Line(int x1 int y1 int x2 int y2 unsigned char color)

int i s u v dx1 dx2 dy1 dy2 m n u=x2-x1 v=y2-y1 dx1=sgn(u) dy1=sgn(v) dx2=sgn(u) dy2=0 m=abs(u) n=abs(v) if((mgtn))

dx2=0 dy2=sgn(v) m=abs(v) n=abs(u)

s=mgtgt2 s=m2 for(i=0 ilt=m i++)

PutPixel(x1 y1 color) s=s+n if ((sltm)) s=s-m x1=x1+dx1 y1=y1+dy1

else

x1=x1+dx2 y1=y1+dy2

Volver

Rectaacutengulos Dibujar un rectaacutengulo es lo maacutes simple que hay simplemente se trazan dosliacuteneas horizontales y dos verticales Veamos entonces como nos quedariacutea elcoacutedigo

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 639

void Box(int x1 int y1 int x2 int y2 unsigned char color)

LineV(x2 y1 y2-y1 color)LineV(x1 y1 y2-y1 color) LineH(x1 y1 x2-x1 color)LineH(x1 y2 x2-x1 color)

Tambieacuten se pueden crear cuadros rellenos de alguacuten color esto tambieacuten essimple veamos como nos queda

void FillBox(int x int y int ancho int alto unsigned char color)

int px py for(px=x pxlt=x+ancho px++)

for(py=y pylt=y+alto py++) PutPixel(px py color)

Volver

Ejemplos A continuacioacuten encontraraacutes varios ejemplos usando las rutinas que vimos Libreriacutea graacutefica vgalibh

bull Dibujo de liacuteneas horizontales y verticales bull Dibujo de un circulo bull Liacuteneas que rotan bull Movimiento de un cuadrado bull Dibuja una figura geomeacutetrica denominada Toro mediante varios ciacuterculos bull Dibuja todas la primitivas vistas en forma aleatoria

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

PantallasVirtuales

Sprites

TablasPrefedifinidas

Efectos

Texto

Formatos graacuteficos

Ahora veremos como funciona la paleta de colores para poder cambiar nosotros mismos los colores y asiacute poder personalizarnosun programa o por ejemplo cuando cargamos una imagen quetambieacuten es necesario poner la paleta de esa imagen Vamos empezar viendo como funciona lo de la paleta de coloresque control un chip llamado DAC (Digital Analog Converter) paraasiacute conseguir hacer efectos de paleta pero estos lo encontrarasen la seccioacuten de efectos (hacer link)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 739

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Como ya sabemos en el modo 13h disponemos de una paleta de8 bits o sea 256 colores Cada color se consigue a basa demezclar tres componentes para ir consiguiendo asiacute diferentestonalidades Asiacute tenemos que un color estaacute formado por tres

colores baacutesicos el rojo verde y azul Estos tres colores puedentener un maacuteximo de 64 tonalidades desde el 0 (maacutes oscuro)hasta el 63 (maacutes claro) Esto es asiacute porque el sistema que seutiliza es el denominado RGB (Red Green Blue) que es el queel monitor utiliza para representar el color de un pixel ya que esteposee tres haces de luz una haz rojo otro verde y uno azul loscuales apuntan a una sola posicioacuten que es lo que conocemoscomo el haz de electrones y mezclaacutendose se consigue crear elcolor deseado Si queremos conseguir un color gris bastaraacute conponer los valores RGB a la misma intensidad cada uno Veamosun ejemplo si queremos que el color 0 sea negro entonces

utilizamos los valores (0 0 0) o si queremos que sea blancocolocamos los valores (63 63 63) Y si lo que queremos es quesea de color rojo intenso ponemos (63 0 0) y asiacute se puede jugar con los valores A continuacioacuten les muestro los valores de algunos colorescomunes

Con unos caacutelculos podemos ver que el numero total detonalidades disponibles es de 264 144 (64^3) diferentes perosolo podremos representar simultaacuteneamente 256 ya que la

profundidad es de 8 bits y lo maacuteximo que podemos representar enun byte es el valor 255 (0-255) Pero como podemos cambiar loscolores bueno como dije antes el chip encargado de esta tarea esel DAC o Digital Analog Converter cuya misioacuten es la detransformas las sentildeales digitales del computador a sentildealesanaloacutegicas que utiliza el monitor Para acceder a este chip yolvidarnos de la BIOS la cual dispone de funciones para trabajar con la paleta nosotros usaremos tres puertos a traveacutes de loscuales podremos leer y escribir las diferentes componentes de loscolores Estos registros son el 03C7h el 03C8h y el 03C9h En elsiguiente cuadro podraacutes encontrar la descripcioacuten detallada decada uno

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 839

Como vemos para leer el valor actual de un color lo quetendriacuteamos que hacer es primero enviar al puerto 3C7h elnuacutemero de color del que queremos obtener los 3 valores y luegoobtener y leer tres valores del puerto 3C9h que corresponderaacuten a

los valores RGB del color nuacutemero x que indicamos en el puerto3C7h Y si lo que queremos es cambiar los valores RGB de undeterminado color lo que haremos seraacute primero enviar al puerto3C8h el nuacutemero del color a cambiar y despueacutes enviar los valoresRGB al puerto 3C9h A continuacioacuten veremos las rutinascorrespondientes en C para cambiar y leer los valores RGB de uncolor determinado Cambiar los valores RGB de un color

void SetColor(unsigned char color char r char g char b)

outportb(0x3C8 color) outportb(0x3C9 r)outportb(0x3C9 g)outportb(0x3C9 b)

Y para leer los valores RGB de un color se hariacutea asiacute

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 939

void GetColor(unsigned char color char r char g char b)

outportb(0x3C7 color) r=inportb(0x3C9)g=inportb(0x3C9)b=inportb(0x3C9)

Ya sabemos cambiar los colores ahora veremos como seriacutean lasrutinas para cambiar o obtener una paleta Antes de estodebemos crear una estructura que nos permita guardar las paletaesto simplemente se puede hacer utilizando un arreglo de tamantildeo

768 (2563) y se podriacutea declarar de la siguiente manera char paleta[768] o incluso se podriacutea crear un tipo de dato llamado t_paleta paraasiacute hacer mas faacutecil las declaraciones de paletas en los programasque realicemos esto seriacutea asiacute typedef char t_paleta[768] de esta forma cuando queramos crear una variable que guarde lapaleta en este caso llamada pal simplemente la declarariacuteamosasiacute t_paleta pal La rutina modificar la paleta seriacutea asiacute

void SetPal(t_paleta pal) int i for(i=0 ilt256 i++)

SetColor(i pal[i3] pal[(i3)+1] pal[(i3)+2])

Lo que se hace aquiacute es recorrer los 256 colores y por cada uno ir cambiando las intensidades RGB correspondientes Y por uacuteltimo la rutina para obtener una paleta

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1039

void GetPal(t_paleta pal)

int i for(i=0 ilt256 i++) GetColor(i amppal[i3] amppal[(i3)+1] amppal[(i3)+2])

En esta rutina se hace simplemente lo contrario a la rutina SetPalNuevamente recorremos los 256 colores y por cada uno vamosobteniendo las intensidades RGB de cada color Cuandollamamos a la rutina GetColor debemos pasarle los valores RGBpor referencia es decir la direccioacuten para que de esta formasalgan modificados Lo que hariacutea en realidad la rutina GetPalseriacutea obtener la paleta activa que se encuentra en el sistema Ejemplos Libreriacutea graacutefica vgalibh

bull

Creacioacuten de distntos colores modificando las intensidadesRGB bull Cambio de los colores de la paleta

PantallasVirtuales

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirvenbull iquestCoacutemo se hace una pantalla virtualbull iquestCoacutemo dibujar en la pantalla virtualbull iquestCoacutemo copiamos una pantalla virtual a la VGAbull Ejemplo

iquestQueacute son y para queacute sirven Alguna vez habraacuten visto alguna demo o por lo menos un juegocomercial y se habraacuten dado cuenta que se hacen muchasanimaciones y efectos y no se ve ni el maacutes miacutenimo parpadeoen la pantalla Si por ejemplo nosotros realizamos una animacioacuten simple como

puede ser el movimiento de un cuadrado por la pantallanotaremos que el movimiento no es suave sino que la figuraparpadea constantemente y a veces puede pasar que no se vea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 639

void Box(int x1 int y1 int x2 int y2 unsigned char color)

LineV(x2 y1 y2-y1 color)LineV(x1 y1 y2-y1 color) LineH(x1 y1 x2-x1 color)LineH(x1 y2 x2-x1 color)

Tambieacuten se pueden crear cuadros rellenos de alguacuten color esto tambieacuten essimple veamos como nos queda

void FillBox(int x int y int ancho int alto unsigned char color)

int px py for(px=x pxlt=x+ancho px++)

for(py=y pylt=y+alto py++) PutPixel(px py color)

Volver

Ejemplos A continuacioacuten encontraraacutes varios ejemplos usando las rutinas que vimos Libreriacutea graacutefica vgalibh

bull Dibujo de liacuteneas horizontales y verticales bull Dibujo de un circulo bull Liacuteneas que rotan bull Movimiento de un cuadrado bull Dibuja una figura geomeacutetrica denominada Toro mediante varios ciacuterculos bull Dibuja todas la primitivas vistas en forma aleatoria

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

PantallasVirtuales

Sprites

TablasPrefedifinidas

Efectos

Texto

Formatos graacuteficos

Ahora veremos como funciona la paleta de colores para poder cambiar nosotros mismos los colores y asiacute poder personalizarnosun programa o por ejemplo cuando cargamos una imagen quetambieacuten es necesario poner la paleta de esa imagen Vamos empezar viendo como funciona lo de la paleta de coloresque control un chip llamado DAC (Digital Analog Converter) paraasiacute conseguir hacer efectos de paleta pero estos lo encontrarasen la seccioacuten de efectos (hacer link)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 739

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Como ya sabemos en el modo 13h disponemos de una paleta de8 bits o sea 256 colores Cada color se consigue a basa demezclar tres componentes para ir consiguiendo asiacute diferentestonalidades Asiacute tenemos que un color estaacute formado por tres

colores baacutesicos el rojo verde y azul Estos tres colores puedentener un maacuteximo de 64 tonalidades desde el 0 (maacutes oscuro)hasta el 63 (maacutes claro) Esto es asiacute porque el sistema que seutiliza es el denominado RGB (Red Green Blue) que es el queel monitor utiliza para representar el color de un pixel ya que esteposee tres haces de luz una haz rojo otro verde y uno azul loscuales apuntan a una sola posicioacuten que es lo que conocemoscomo el haz de electrones y mezclaacutendose se consigue crear elcolor deseado Si queremos conseguir un color gris bastaraacute conponer los valores RGB a la misma intensidad cada uno Veamosun ejemplo si queremos que el color 0 sea negro entonces

utilizamos los valores (0 0 0) o si queremos que sea blancocolocamos los valores (63 63 63) Y si lo que queremos es quesea de color rojo intenso ponemos (63 0 0) y asiacute se puede jugar con los valores A continuacioacuten les muestro los valores de algunos colorescomunes

Con unos caacutelculos podemos ver que el numero total detonalidades disponibles es de 264 144 (64^3) diferentes perosolo podremos representar simultaacuteneamente 256 ya que la

profundidad es de 8 bits y lo maacuteximo que podemos representar enun byte es el valor 255 (0-255) Pero como podemos cambiar loscolores bueno como dije antes el chip encargado de esta tarea esel DAC o Digital Analog Converter cuya misioacuten es la detransformas las sentildeales digitales del computador a sentildealesanaloacutegicas que utiliza el monitor Para acceder a este chip yolvidarnos de la BIOS la cual dispone de funciones para trabajar con la paleta nosotros usaremos tres puertos a traveacutes de loscuales podremos leer y escribir las diferentes componentes de loscolores Estos registros son el 03C7h el 03C8h y el 03C9h En elsiguiente cuadro podraacutes encontrar la descripcioacuten detallada decada uno

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 839

Como vemos para leer el valor actual de un color lo quetendriacuteamos que hacer es primero enviar al puerto 3C7h elnuacutemero de color del que queremos obtener los 3 valores y luegoobtener y leer tres valores del puerto 3C9h que corresponderaacuten a

los valores RGB del color nuacutemero x que indicamos en el puerto3C7h Y si lo que queremos es cambiar los valores RGB de undeterminado color lo que haremos seraacute primero enviar al puerto3C8h el nuacutemero del color a cambiar y despueacutes enviar los valoresRGB al puerto 3C9h A continuacioacuten veremos las rutinascorrespondientes en C para cambiar y leer los valores RGB de uncolor determinado Cambiar los valores RGB de un color

void SetColor(unsigned char color char r char g char b)

outportb(0x3C8 color) outportb(0x3C9 r)outportb(0x3C9 g)outportb(0x3C9 b)

Y para leer los valores RGB de un color se hariacutea asiacute

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 939

void GetColor(unsigned char color char r char g char b)

outportb(0x3C7 color) r=inportb(0x3C9)g=inportb(0x3C9)b=inportb(0x3C9)

Ya sabemos cambiar los colores ahora veremos como seriacutean lasrutinas para cambiar o obtener una paleta Antes de estodebemos crear una estructura que nos permita guardar las paletaesto simplemente se puede hacer utilizando un arreglo de tamantildeo

768 (2563) y se podriacutea declarar de la siguiente manera char paleta[768] o incluso se podriacutea crear un tipo de dato llamado t_paleta paraasiacute hacer mas faacutecil las declaraciones de paletas en los programasque realicemos esto seriacutea asiacute typedef char t_paleta[768] de esta forma cuando queramos crear una variable que guarde lapaleta en este caso llamada pal simplemente la declarariacuteamosasiacute t_paleta pal La rutina modificar la paleta seriacutea asiacute

void SetPal(t_paleta pal) int i for(i=0 ilt256 i++)

SetColor(i pal[i3] pal[(i3)+1] pal[(i3)+2])

Lo que se hace aquiacute es recorrer los 256 colores y por cada uno ir cambiando las intensidades RGB correspondientes Y por uacuteltimo la rutina para obtener una paleta

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1039

void GetPal(t_paleta pal)

int i for(i=0 ilt256 i++) GetColor(i amppal[i3] amppal[(i3)+1] amppal[(i3)+2])

En esta rutina se hace simplemente lo contrario a la rutina SetPalNuevamente recorremos los 256 colores y por cada uno vamosobteniendo las intensidades RGB de cada color Cuandollamamos a la rutina GetColor debemos pasarle los valores RGBpor referencia es decir la direccioacuten para que de esta formasalgan modificados Lo que hariacutea en realidad la rutina GetPalseriacutea obtener la paleta activa que se encuentra en el sistema Ejemplos Libreriacutea graacutefica vgalibh

bull

Creacioacuten de distntos colores modificando las intensidadesRGB bull Cambio de los colores de la paleta

PantallasVirtuales

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirvenbull iquestCoacutemo se hace una pantalla virtualbull iquestCoacutemo dibujar en la pantalla virtualbull iquestCoacutemo copiamos una pantalla virtual a la VGAbull Ejemplo

iquestQueacute son y para queacute sirven Alguna vez habraacuten visto alguna demo o por lo menos un juegocomercial y se habraacuten dado cuenta que se hacen muchasanimaciones y efectos y no se ve ni el maacutes miacutenimo parpadeoen la pantalla Si por ejemplo nosotros realizamos una animacioacuten simple como

puede ser el movimiento de un cuadrado por la pantallanotaremos que el movimiento no es suave sino que la figuraparpadea constantemente y a veces puede pasar que no se vea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 739

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Como ya sabemos en el modo 13h disponemos de una paleta de8 bits o sea 256 colores Cada color se consigue a basa demezclar tres componentes para ir consiguiendo asiacute diferentestonalidades Asiacute tenemos que un color estaacute formado por tres

colores baacutesicos el rojo verde y azul Estos tres colores puedentener un maacuteximo de 64 tonalidades desde el 0 (maacutes oscuro)hasta el 63 (maacutes claro) Esto es asiacute porque el sistema que seutiliza es el denominado RGB (Red Green Blue) que es el queel monitor utiliza para representar el color de un pixel ya que esteposee tres haces de luz una haz rojo otro verde y uno azul loscuales apuntan a una sola posicioacuten que es lo que conocemoscomo el haz de electrones y mezclaacutendose se consigue crear elcolor deseado Si queremos conseguir un color gris bastaraacute conponer los valores RGB a la misma intensidad cada uno Veamosun ejemplo si queremos que el color 0 sea negro entonces

utilizamos los valores (0 0 0) o si queremos que sea blancocolocamos los valores (63 63 63) Y si lo que queremos es quesea de color rojo intenso ponemos (63 0 0) y asiacute se puede jugar con los valores A continuacioacuten les muestro los valores de algunos colorescomunes

Con unos caacutelculos podemos ver que el numero total detonalidades disponibles es de 264 144 (64^3) diferentes perosolo podremos representar simultaacuteneamente 256 ya que la

profundidad es de 8 bits y lo maacuteximo que podemos representar enun byte es el valor 255 (0-255) Pero como podemos cambiar loscolores bueno como dije antes el chip encargado de esta tarea esel DAC o Digital Analog Converter cuya misioacuten es la detransformas las sentildeales digitales del computador a sentildealesanaloacutegicas que utiliza el monitor Para acceder a este chip yolvidarnos de la BIOS la cual dispone de funciones para trabajar con la paleta nosotros usaremos tres puertos a traveacutes de loscuales podremos leer y escribir las diferentes componentes de loscolores Estos registros son el 03C7h el 03C8h y el 03C9h En elsiguiente cuadro podraacutes encontrar la descripcioacuten detallada decada uno

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 839

Como vemos para leer el valor actual de un color lo quetendriacuteamos que hacer es primero enviar al puerto 3C7h elnuacutemero de color del que queremos obtener los 3 valores y luegoobtener y leer tres valores del puerto 3C9h que corresponderaacuten a

los valores RGB del color nuacutemero x que indicamos en el puerto3C7h Y si lo que queremos es cambiar los valores RGB de undeterminado color lo que haremos seraacute primero enviar al puerto3C8h el nuacutemero del color a cambiar y despueacutes enviar los valoresRGB al puerto 3C9h A continuacioacuten veremos las rutinascorrespondientes en C para cambiar y leer los valores RGB de uncolor determinado Cambiar los valores RGB de un color

void SetColor(unsigned char color char r char g char b)

outportb(0x3C8 color) outportb(0x3C9 r)outportb(0x3C9 g)outportb(0x3C9 b)

Y para leer los valores RGB de un color se hariacutea asiacute

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 939

void GetColor(unsigned char color char r char g char b)

outportb(0x3C7 color) r=inportb(0x3C9)g=inportb(0x3C9)b=inportb(0x3C9)

Ya sabemos cambiar los colores ahora veremos como seriacutean lasrutinas para cambiar o obtener una paleta Antes de estodebemos crear una estructura que nos permita guardar las paletaesto simplemente se puede hacer utilizando un arreglo de tamantildeo

768 (2563) y se podriacutea declarar de la siguiente manera char paleta[768] o incluso se podriacutea crear un tipo de dato llamado t_paleta paraasiacute hacer mas faacutecil las declaraciones de paletas en los programasque realicemos esto seriacutea asiacute typedef char t_paleta[768] de esta forma cuando queramos crear una variable que guarde lapaleta en este caso llamada pal simplemente la declarariacuteamosasiacute t_paleta pal La rutina modificar la paleta seriacutea asiacute

void SetPal(t_paleta pal) int i for(i=0 ilt256 i++)

SetColor(i pal[i3] pal[(i3)+1] pal[(i3)+2])

Lo que se hace aquiacute es recorrer los 256 colores y por cada uno ir cambiando las intensidades RGB correspondientes Y por uacuteltimo la rutina para obtener una paleta

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1039

void GetPal(t_paleta pal)

int i for(i=0 ilt256 i++) GetColor(i amppal[i3] amppal[(i3)+1] amppal[(i3)+2])

En esta rutina se hace simplemente lo contrario a la rutina SetPalNuevamente recorremos los 256 colores y por cada uno vamosobteniendo las intensidades RGB de cada color Cuandollamamos a la rutina GetColor debemos pasarle los valores RGBpor referencia es decir la direccioacuten para que de esta formasalgan modificados Lo que hariacutea en realidad la rutina GetPalseriacutea obtener la paleta activa que se encuentra en el sistema Ejemplos Libreriacutea graacutefica vgalibh

bull

Creacioacuten de distntos colores modificando las intensidadesRGB bull Cambio de los colores de la paleta

PantallasVirtuales

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirvenbull iquestCoacutemo se hace una pantalla virtualbull iquestCoacutemo dibujar en la pantalla virtualbull iquestCoacutemo copiamos una pantalla virtual a la VGAbull Ejemplo

iquestQueacute son y para queacute sirven Alguna vez habraacuten visto alguna demo o por lo menos un juegocomercial y se habraacuten dado cuenta que se hacen muchasanimaciones y efectos y no se ve ni el maacutes miacutenimo parpadeoen la pantalla Si por ejemplo nosotros realizamos una animacioacuten simple como

puede ser el movimiento de un cuadrado por la pantallanotaremos que el movimiento no es suave sino que la figuraparpadea constantemente y a veces puede pasar que no se vea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 839

Como vemos para leer el valor actual de un color lo quetendriacuteamos que hacer es primero enviar al puerto 3C7h elnuacutemero de color del que queremos obtener los 3 valores y luegoobtener y leer tres valores del puerto 3C9h que corresponderaacuten a

los valores RGB del color nuacutemero x que indicamos en el puerto3C7h Y si lo que queremos es cambiar los valores RGB de undeterminado color lo que haremos seraacute primero enviar al puerto3C8h el nuacutemero del color a cambiar y despueacutes enviar los valoresRGB al puerto 3C9h A continuacioacuten veremos las rutinascorrespondientes en C para cambiar y leer los valores RGB de uncolor determinado Cambiar los valores RGB de un color

void SetColor(unsigned char color char r char g char b)

outportb(0x3C8 color) outportb(0x3C9 r)outportb(0x3C9 g)outportb(0x3C9 b)

Y para leer los valores RGB de un color se hariacutea asiacute

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 939

void GetColor(unsigned char color char r char g char b)

outportb(0x3C7 color) r=inportb(0x3C9)g=inportb(0x3C9)b=inportb(0x3C9)

Ya sabemos cambiar los colores ahora veremos como seriacutean lasrutinas para cambiar o obtener una paleta Antes de estodebemos crear una estructura que nos permita guardar las paletaesto simplemente se puede hacer utilizando un arreglo de tamantildeo

768 (2563) y se podriacutea declarar de la siguiente manera char paleta[768] o incluso se podriacutea crear un tipo de dato llamado t_paleta paraasiacute hacer mas faacutecil las declaraciones de paletas en los programasque realicemos esto seriacutea asiacute typedef char t_paleta[768] de esta forma cuando queramos crear una variable que guarde lapaleta en este caso llamada pal simplemente la declarariacuteamosasiacute t_paleta pal La rutina modificar la paleta seriacutea asiacute

void SetPal(t_paleta pal) int i for(i=0 ilt256 i++)

SetColor(i pal[i3] pal[(i3)+1] pal[(i3)+2])

Lo que se hace aquiacute es recorrer los 256 colores y por cada uno ir cambiando las intensidades RGB correspondientes Y por uacuteltimo la rutina para obtener una paleta

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1039

void GetPal(t_paleta pal)

int i for(i=0 ilt256 i++) GetColor(i amppal[i3] amppal[(i3)+1] amppal[(i3)+2])

En esta rutina se hace simplemente lo contrario a la rutina SetPalNuevamente recorremos los 256 colores y por cada uno vamosobteniendo las intensidades RGB de cada color Cuandollamamos a la rutina GetColor debemos pasarle los valores RGBpor referencia es decir la direccioacuten para que de esta formasalgan modificados Lo que hariacutea en realidad la rutina GetPalseriacutea obtener la paleta activa que se encuentra en el sistema Ejemplos Libreriacutea graacutefica vgalibh

bull

Creacioacuten de distntos colores modificando las intensidadesRGB bull Cambio de los colores de la paleta

PantallasVirtuales

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirvenbull iquestCoacutemo se hace una pantalla virtualbull iquestCoacutemo dibujar en la pantalla virtualbull iquestCoacutemo copiamos una pantalla virtual a la VGAbull Ejemplo

iquestQueacute son y para queacute sirven Alguna vez habraacuten visto alguna demo o por lo menos un juegocomercial y se habraacuten dado cuenta que se hacen muchasanimaciones y efectos y no se ve ni el maacutes miacutenimo parpadeoen la pantalla Si por ejemplo nosotros realizamos una animacioacuten simple como

puede ser el movimiento de un cuadrado por la pantallanotaremos que el movimiento no es suave sino que la figuraparpadea constantemente y a veces puede pasar que no se vea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 939

void GetColor(unsigned char color char r char g char b)

outportb(0x3C7 color) r=inportb(0x3C9)g=inportb(0x3C9)b=inportb(0x3C9)

Ya sabemos cambiar los colores ahora veremos como seriacutean lasrutinas para cambiar o obtener una paleta Antes de estodebemos crear una estructura que nos permita guardar las paletaesto simplemente se puede hacer utilizando un arreglo de tamantildeo

768 (2563) y se podriacutea declarar de la siguiente manera char paleta[768] o incluso se podriacutea crear un tipo de dato llamado t_paleta paraasiacute hacer mas faacutecil las declaraciones de paletas en los programasque realicemos esto seriacutea asiacute typedef char t_paleta[768] de esta forma cuando queramos crear una variable que guarde lapaleta en este caso llamada pal simplemente la declarariacuteamosasiacute t_paleta pal La rutina modificar la paleta seriacutea asiacute

void SetPal(t_paleta pal) int i for(i=0 ilt256 i++)

SetColor(i pal[i3] pal[(i3)+1] pal[(i3)+2])

Lo que se hace aquiacute es recorrer los 256 colores y por cada uno ir cambiando las intensidades RGB correspondientes Y por uacuteltimo la rutina para obtener una paleta

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1039

void GetPal(t_paleta pal)

int i for(i=0 ilt256 i++) GetColor(i amppal[i3] amppal[(i3)+1] amppal[(i3)+2])

En esta rutina se hace simplemente lo contrario a la rutina SetPalNuevamente recorremos los 256 colores y por cada uno vamosobteniendo las intensidades RGB de cada color Cuandollamamos a la rutina GetColor debemos pasarle los valores RGBpor referencia es decir la direccioacuten para que de esta formasalgan modificados Lo que hariacutea en realidad la rutina GetPalseriacutea obtener la paleta activa que se encuentra en el sistema Ejemplos Libreriacutea graacutefica vgalibh

bull

Creacioacuten de distntos colores modificando las intensidadesRGB bull Cambio de los colores de la paleta

PantallasVirtuales

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirvenbull iquestCoacutemo se hace una pantalla virtualbull iquestCoacutemo dibujar en la pantalla virtualbull iquestCoacutemo copiamos una pantalla virtual a la VGAbull Ejemplo

iquestQueacute son y para queacute sirven Alguna vez habraacuten visto alguna demo o por lo menos un juegocomercial y se habraacuten dado cuenta que se hacen muchasanimaciones y efectos y no se ve ni el maacutes miacutenimo parpadeoen la pantalla Si por ejemplo nosotros realizamos una animacioacuten simple como

puede ser el movimiento de un cuadrado por la pantallanotaremos que el movimiento no es suave sino que la figuraparpadea constantemente y a veces puede pasar que no se vea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1039

void GetPal(t_paleta pal)

int i for(i=0 ilt256 i++) GetColor(i amppal[i3] amppal[(i3)+1] amppal[(i3)+2])

En esta rutina se hace simplemente lo contrario a la rutina SetPalNuevamente recorremos los 256 colores y por cada uno vamosobteniendo las intensidades RGB de cada color Cuandollamamos a la rutina GetColor debemos pasarle los valores RGBpor referencia es decir la direccioacuten para que de esta formasalgan modificados Lo que hariacutea en realidad la rutina GetPalseriacutea obtener la paleta activa que se encuentra en el sistema Ejemplos Libreriacutea graacutefica vgalibh

bull

Creacioacuten de distntos colores modificando las intensidadesRGB bull Cambio de los colores de la paleta

PantallasVirtuales

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirvenbull iquestCoacutemo se hace una pantalla virtualbull iquestCoacutemo dibujar en la pantalla virtualbull iquestCoacutemo copiamos una pantalla virtual a la VGAbull Ejemplo

iquestQueacute son y para queacute sirven Alguna vez habraacuten visto alguna demo o por lo menos un juegocomercial y se habraacuten dado cuenta que se hacen muchasanimaciones y efectos y no se ve ni el maacutes miacutenimo parpadeoen la pantalla Si por ejemplo nosotros realizamos una animacioacuten simple como

puede ser el movimiento de un cuadrado por la pantallanotaremos que el movimiento no es suave sino que la figuraparpadea constantemente y a veces puede pasar que no se vea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1139

alguna parte de la figura En la seccioacuten ejemplos que seencuentra al final de esta pagina podraacuten darse cuenta de estosefectos que suceden y hacen que la realizacioacuten de unaanimacioacuten no sea profesional Todo este parpadeo es producido por los constantes cambios

que se hace en la pantalla en el momento en que se estaacutedibujando En la seccioacuten retrazado vertical vimos que el usar esta teacutecnicasincronizaba un poco nuestro programa con la pantalla perosupongamos que tenemos que dibujar un pantalla con un fondoun poco complejo y encima de este fondo tenemos que dibujar varias figuras que se moveraacuten en la pantalla El tiempo deretrazado vertical no seria suficiente para dibujar toda lapantalla asiacute que la teacutecnica de retrazado vertical en este caso nonos serviriacutea Piensen por ejemplo que no seriacutea nada excelente que el usuario

viera como dibujamos el fondo y luego las figuras una por una ydespueacutes borramos la pantalla para volver a dibujar el fondoEsto seriacutea horrible lo ideal seriacutea que todo se dibujara tanraacutepidamente que diera la impresioacuten que el fondo nunca se borray que las figuras realmente estaacuten en movimiento Pero la CPU y en especial la memoria de video no son tanraacutepidos como para lograr esto por lo que tenemos que hacer unpequentildeo truco Que pasariacutea si en lugar de dibujar el fondo y las figuras en lapantalla las dibujamos en otro lugar y luego simplementecopiamos todo a la pantalla real una vez que ha sido tododibujado Y mientras el usuario admira la escena nosotrosestamos dibujando el siguiente cuadro en nuestra ldquopantallavirtualrdquo pero el usuario no veraacute nada hasta que copiemos todalas escena a la pantalla real Copiar una pantalla de un lugar aotro en el modo13h significa mover 64000 bytes de una zonade la memoria a otraEntonces una pantalla virtual es simplemente una zona dememoria en el caso del modo 13h de 64000 bytes quefunciona como la memoria real de la VGA Nosotros podemosdibujar puntos liacuteneas ciacuterculos o lo que sea en nuestra pantalla

virtual la uacutenica diferencia es que nada de lo que dibujemos enla pantalla virtual es visible Nosotros podemos dibujar unaescena que tarde 1 segundo en dibujarse y luego simplementecopiamos los 64 Kb de la pantalla virtual a la memoria de laVGA lo cual tarda solo un instante Para el usuario que esta viendo el programa la pantalla sedibujoacute en ese instante aunque como ya sabemos esto no fueasiacute Ademaacutes mientras el usuario esta viendo la pantallanosotros podemos estar dibujando en otras pantalla virtuales sinmodificar lo que realmente se esta viendo

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1239

iquestCoacutemo se hace una pantalla virtual La pantalla virtual como ya sabemos debe contener 64000bytes Para necesitamos reservar una zona de memoria con 64Kb Alguien podriacutea pensar que para esto simplementepodriacuteamos usar un arreglo declarado de la siguiente forma unsigned char pvirtual[64000] Pero lamentablemente el lenguaje C y muchos otros lenguajesde alto nivel utilizan 64 Kb para las variables del programa por lo que si hacemos lo anterior nos quedariacuteamos sin memoriapara otras variables Asiacute que tenemos solo una posibilidad yesta es usar punteros para acceder al heap (montoacuten) Esto en Clo hariacuteamos asiacute primero definimos un puntero que apunte adatos de tipo byte unsigned char pvirtual Luego deberiacuteamos reservar la memoria necesaria utilizando lasfunciones que nos proporciona el lenguaje C podriacuteamos ocupar

la funcion malloc o la callos la diferencia de esta uacuteltima con lafuncioacuten malloc es que llena con ceros el bloque reservado locual es bueno en nuestro caso ya que nuestra pantalla virtualquedariacutea automaacuteticamente limpia es decir toda llena con elcolor 0 que por defecto es el negro Entonces podriacuteamosreservar memoria de dos formas pvirtual=(unsigned char )malloc(64000) o pvirtual=(unsigned char )calloc(64000 sizeof(unsignedchar)) De esta forma tendriacuteamos un puntero apuntando al primer elemento del bloque de 64 Kb Pero hay un problema debemosverificar si realmente se nos reservoacute la memoria requerida paraesto podemos ver si la variable pvirtual es igual a NULL si esasiacute significa que no hay memoria suficiente esta memoria serefiere a la memoria convencional que posee libre nuestro PCRecuerden que la memoria convencional es de 640 Kbsolamente Para verificar si se reservoacute o no memoria podemoshacer lo siguiente

if(pvirtual==NULL) printf(ldquoniexclNo hay memoria suficientenrdquo) exit(1)

Pero antes que termine nuestro programa debemos liberar lamemoria utilizada por la pantalla virtual y esto lo haremossimplemente utilizando la funcion free free(pvirtual) Ya sabemos crearnos una pantalla virtual pero seria

conveniente tener una funcion que nos hiciera todo este trabajoasiacute que crearemos un nuevo tipo de dato para la pantalla virtual

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1339

esto lo haremos asiacute typedef unsigned char t_pvirtual Asiacute si necesitamos una pantalla virtual simplemente ladeclararemos de esta forma t_pvirtual pv La funcion que nos cree la pantalla virtual es decir la que nosreserve la memoria y nos indique ademaacutes si pudo lograrlo sepodriacutea hacer asiacute

unsigned char SetPVirtual(unsigned char pv)

pv=(unsigned char )calloc(64000 sizeof(unsignedchar))

return (pv)

Ojo con esta funcion recibe como paraacutemetro un puntero a unpuntero esto es asiacute para poder ocupar el puntero fuera de lafuncion y modificarlo Despueacutes de reservar la memoria lafunciona devuelve el mismo puntero esto nos serviraacute paraverificar si se pudo reservar la memoria En caso que no selogra la reserva la funcion devolveraacute NULL ya que pv tendraacuteese valor Un ejemplo simple de la utilizacioacuten de esta funcioacutenpodriacutea ser el siguiente

Declaramos una variable de tipo pantalla virtual t_pvirtual pv Llamamos a la funcioacuten con el paraacutemetro requerido if(SetPVirtual(amppv))

printf(ldquonNo hay memoria suficientenrdquo) exit(1)

Ojo con el ejemplo le pasamos la direccioacuten del puntero amppv yaque la funcioacuten nos pide un puntero a un puntero Si la funciondevuelve NULL significaraacute que no se pudo reservar memoria ypor lo tanto ese NULL equivale a que la funcion devolvioacute uncero luego la negamos con y por lo tanto la condicioacuten del if tendraacute el valor 1 lo que significa que es verdadero (recuendenque en C 0=falso y 1=verdadero) y por lo tanto se ejecutaraacute elcoacutedigo correspondiente al if La funcion inversa es decir la que elimina el bloque de memoria

reservada es el siguiente

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1439

void FreePVirtual(unsigned char pv)

free(pv) pv=NULL

Esta funcioacuten es muy simple lo que se hace es liberar el bloquede memoria reservado anteriormente con malloc o calloc yluego se hace que el puntero no apunte a nada es decir se leasigna el valor NULL

Volver

iquestCoacutemo dibujar en la pantalla virtual Si ya tenemos reservada la memoria para un puntero llamadopor ejemplo pv dibujar en pv es anaacutelogo a como lo hicimos conel puntero DIR_VGA la uacutenica diferencia es que ahora lo quehagamos o mejor dicho dibujemos no se veraacute en la pantallaPor ejemplo podriacuteamos hacer lo siguiente con la variable pv

for(x=0 xlt320 x++) for(y=0 ylt200 y++)

pv[y320+x]=random(256)

En este caso lo que se hace es simplemente llenar los 64000bytes de nuestra pantalla virtual con pixeles al azar Ahora que ya sabemos trabajar muy bien con una pantallavirtual tendremos que modificar todas las rutinas que hemoshecho hasta el momento Para esto simplemente se le agregaraacuteun paraacutemetro a cada funcioacuten donde este paraacutemetro seraacute unpuntero que nos indicaraacute donde dibujar Voy hacer solo elejemplo para la funcion PutPixel las demaacutes modificaciones laspodraacutes ver al final de esta pagina en el archivo vgalibh

void PutPixel(int x int y unsigned char color unsignedchar where)

where[(yltlt8)+(yltlt6)+x]=color

Si se dan cuenta es super simple ahora cuando hagan unprograma solo deben especificar donde quieren dibujar Siquisieran dibujar en la pantalla real simplemente le pasan comoultimo paraacutemetro el puntero DIR_VGA

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1539

iquestCoacutemo copiamos una pantalla virtual a la VGA Esto tambieacuten es simple Para esto podemos usar una funcioacutenque se encuentra en memh y es la funcioacuten memmove Lo quehace esta funcion es mover un bloque de memoria de un lugar aotro Sus paraacutemetros son un puntero destino otro fuente y el

numero de bytes que se quieren mover El nuacutemero de bytesmaacuteximo que se pueden mover es de 64000 bytes lo que justamente corresponde a lo que nosotros necesitamosPodemos crear una funcion que reciba dos punteros uno destinoy otro fuente

void FlipTo(unsigned char source unsigned char where)

memmove(where source 64000)

Por ejemplo si quisieacuteramos mover el contenido de la pantallavirtual pv al memoria de la VGA hariacuteamos lo siguiente FlipTo(pv DIR_VGA) Como esta funcioacuten seraacute muy utilizada podemos crear otrassimilar pero solo con un paraacutemetro

void Flip(unsigned char source)

memmove(DIR_VGA source 64000)

Como ven ya sabemos todo lo necesario para trabajar conpantallas virtuales Pero las funciones Flip y FlipTo (queteacutecnicamente son iguales) pueden resultar un poco lentas Lasolucioacuten a esto es crear estas funciones en ensamblador perotodo lo que se refiere a optimizaciones lo encontraras en laseccioacuten correspondiente La funcioacuten de volcado es una de lasque deberiacutea estar mejor optimizada para lograr una velocidad

aceptable en nuestros programas Volver

Ejemplo Libreriacutea graacutefica vgalibh Muestra un cuadro en movimiento usando tres teacutecnicasdiferentes 1) Se borra y se vuelve a dibujar el cuadro 2) Se inserta el procedimiento WaitRetrace() antes de mover elcuadro 3) Se borra y se dibuja el bloque en una pantalla virtual luegollama al procedimiento WaitRetrace() y luego se copia la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1639

pantalla virtual a la VGA Cuando ejecuten el programa veraacuten la diferencia y ahiacute se daraacutencuenta de la gran utilidad de las pantallas virtuales De aquiacute enadelante las pantallas virtuales se usaraacuten mucho especialmenteen lo que se refiere a animaciones Ver ejemplo

Bajar todo (26 Kb)

Sprites

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute son y para queacute sirven los spritesbull Creando un spritebull Creando nuestro propio formato de sprite

bull Dibujando sprites en la pantallabull Sprites transparentesbull Animacionesbull Ejemplo

iquestQueacute son y para queacute sirven los spritesUn sprite es simplemente una figura o imagen de dimensionesno muy grandes que puede desplazarse por la pantalla esdecir que posee movimiento Hay que tener claro que tambienexisten los bitmaps que tambien son como los sprites pero noposeen movimiento es decir es una agrupacioacuten de pixeles queforma una figura y por lo tanto es estaacuteticaUn sprite estaacute formado por varios frames o cuadros lo cualesforman una animacioacuten por ejemplo nuestro protagonista de un juego de plataforma o un juego de naves etc Asiacute tenemos queun frame o cuadro es simplemente uno de los dibujos que semuestran en la pantalla Los sprites pueden tener cualquier tamantildeo y normalmentetendraacuten asociadas unas variables las cuales por ejemplopueden representar su posicioacuten en la pantalla el ancho y el alto

del sprite etc Algunas veces pueden tener factores como lavelocidad el estado del sprite Por ejemplo en un juego un spritetendraacute varias variables como por ejemplo una para saber sicolisionoacute o choco con otro sprite etc Los sprites siempre son rectangulares aunque al verlos en unprograma no lo parezcan esto se debe a teacutecnicas que seutilizan una de ellas es el uso de mascaras La principal funcioacuten de los sprites es la de las animaciones yasea en una presentacioacuten juego etc Los sprites son muy usados en los juegos 2-D ya sean deplataformas aventuras graacuteficas etc Aunque hay excepciones

donde los sprites pueden ser utilizados en juegos 3-D unejemplo de ello es el conocidisimo Wolfenstein 3D de la

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1739

empresa ID Software aunque no lo crean este juego utilizabasprites a diferencia de los ultimos juegos tridimensionales comoel Quake Duke Nukem etc Ejemplo de juegos que han utilizado sprites son el StreetFighter Mortal Kombat Killer Instinct y claacutesicos como The

Prince of Persia la saga Keen Commander etc Volver

Creando un sprite Antes de crear un sprite tendremos que crearnos una estructuraque almacene todas las variables necesarias y los frames queformaraacuten el sprite Esto en C se puede hacer asiacute

typedef struct

int x y Posicioacuten del sprite en lapantalla

unsigned char ancho alto Ancho y alto del spriteunsigned char num_frames Nuacutemero de frames que

tiene el sprite unsigned char frame[MAX_FRAMES] Cada uno de los

frames que forma el sprite t_sprite

Hemos creado un tipo de dato llamado t_sprite que contiene lasvariables baacutesicos para trabajar con un sprite Dentro de la estructura definimos a los frames de esta forma unsigned char frame[MAX_FRAMES] lo cual es un arreglo de punteros la gracia de hacer esto quepodemos crear un sprite de cualquier tamantildeo MAX_FRAMESes una constante que puede ser definida asiacute define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memorianecesaria Si de dan cuenta hay solo un inconveniente Imaginemos quetenemos un sprite de solo 3 frames y nosotros definimos esearreglo de tamantildeo 10 por lo que se desperdiciaran 7

posiciones Esto se puede solucionar usando listas enlazadaspero para no complicarnos lo haremos asiacute no mas Ya tenemos una estructura para guardar nuestros sprites peroahora iquestcoacutemo almaceno los sprites en el disco duro para poder cargarlos despueacutes desde mi programa Para esto hay variasposibilidades todas basadas en el uso de archivos una es tener archivos independientes es decir un archivo para cada framePero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames tendriacuteamos que tener 50 archivos Entodo caso nunca tendremos tantos Para tener archivosindependientes podriacuteamos usar los tiacutepicos archivos CEL del

Autodesk Animator o bien crearnos un tipo de archivo a nuestramedida y esto seraacute lo que haremos nosotros Otra forma seriacutea

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1839

guardar todos los frames en un mismo archivo de un formatopropio o en formatos tradicionales como el GIF PCX BMP Deestos tres el maacutes recomendable es el PCX ya que es mas faacutecilde trabajar y comprime las imaacutegenes

Volver

Creando nuestro propio formato de sprite Realizar esto no es complicado simplemente hay que conocer el manejo de archivos en C Lo que haremos seraacute crearnos unarchivo que tendraacute la extensioacuten SPR y tendraacute la siguientesestructura CABECERA 0 byte ancho del sprite 1 byte alto del sprite IMAGEN resto del archivo desde el byte 2 Los 2 primeros bytes contendraacuten el ancho y alto de nuestrosprites y el resto del archivo seraacute la informacioacuten de cada pixelque forma el frame Asiacute el tamantildeo de nuestro archivo se podraacute calcular de lasiguiente forma Tamantildeo = ancho alto + 2 La pregunta ahora es como creamos nuestro archivo esto sepuede hacer de varias formas las maacutes simple es tener nuestrosprite en un formato tradicional como el PCX entonces crearnosun ldquoprogramitardquo que transforme el archivo PCX en un archivocon nuestro formato En la seccioacuten herramientas podraacutesencontrar un programa muy simple que realice hace un tiempoy hace esto Su funcion es leer un archivo PCX luego lomuestra en pantalla luego guarda el ancho y el alto de laimagen y lee cada pixel y lo va guardando en un archivo Elprograma tambieacuten guarda la paleta Esta uacuteltima es muyimportante para conocer la informacioacuten de los colores que usanuestro sprite Veamos como nos quedariacutea la funcion que lee un simple framedesde un archivo

int LoadSpr(char filename unsigned char frame)

enumARCHIVO_NO_ENCONTRADO=0 NO_HAY_MEMORIA=-1MUY_GRANDE=-2 OK=1

int ancho alto FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO Leemos el ancho y alto del frame

ancho=fgetc(f)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 1939

alto=fgetc(f) if((anchogt255) || (altogt255))

fclose(f) return MUY_GRANDE

Reservamos memoria para la imagen el ancho y el alto if((frame=(unsigned char )malloc((anchoalto)+2))==NULL)

fclose(f) return NO_HAY_MEMORIA

Copiamos el ancho y el alto memcpy(frame ampancho 1) memcpy(frame+1 ampalto 1) Leemos la imagen fread(frame+2 sizeof(char) (anchoalto) f) fclose(f) return OK

Lo que hace esta funcion es recibir como paraacutemetro el nombredel archivo y un puntero a un puntero a un dato de tipo byte

Luego abrimos el archivo y vemos si existe o no Si no existedevolvemos un error En caso que exista leemos la cabecerapara conocer las dimensiones de nuestro frame si es masgrande que 55 devolvemos un error Si el tamantildeo del frame esmenor o igual a 255 reservamos la memoria necesaria asiacutenuestro puntero contendraacute en sus dos primeros bytes el ancho yel alto del byte 2 en adelante estaraacute la informacioacuten de laimagen Luego leemos los datos de la imagen del archivo y listoComo vemos ya podemos leer un archivo con nuestro formato yguardar los datos en memoria Al final de nuestro programa

deberemos liberar la memoria reservada para hacer estosimplemente llamamos a la funcion free con el puntero al framecomo paraacutemetro Ahora veremos como crearnos una funcioacuten que abra variosarchivos de tipo spr pero con la condicioacuten que todas tengan elmismo nombre y todos se encuentren enumeradosVeamos

int LoadSprite(char filename t_sprite sprite unsigned char num_frames)

unsigned char i num

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2039

int r char nombre numero Guardamos total de frames sprite-gtnum_frames=num_frames Inicializamos a cero las coordenadas del sprite sprite-gtx=sprite-gty=0 Cargaremos cada uno de los frames que forma el sprite for(i=0 num=1 iltnum_frames i++ num++)

Creamos el nombre del archivo strcpy(nombre filename) itoa(num numero 10) strcat(nombre numero) strcat(nombre spr) Lo cargamos r=LoadSpr(nombre amp(sprite-gtframe[i]))

Si hubo algun error salimos del for if(r=1) break

Si hubo algun error al cargar algun un frame liberamos la

memoria reservada hasta ese momento if(r=1)

if (i=0) Si se cargo en memoria al menos un frame

for(num=0 numlti num++) free(sprite-gtframe[num])

return r Retornamos el error producido Guardamos el ancho y el alto del sprite memcpy(amp(sprite-gtancho) amp(sprite-gtframe[0][0]) 1) memcpy(amp(sprite-gtalto) amp(sprite-gtframe[0][1]) 1) return 1 Todo OK

Espero que hayan entendido la funcioacuten aunque no es de lomejor lo ideal seriacutea usar listas enlazadas Tal vez maacutes adelanteen otra seccioacuten incluya como hacer esto uacuteltimo La secuencia de archivos para un sprite deberiacutea tener losnombres de esta forma por ejemplo si los archivos son de unauto y tenemos 3 los archivos deberiacutean llamarse auto1sprauto2spr y auto3spr Asiacute al llamar a la funcion LoadSprite lohariacuteamos de la siguiente forma r=LoadSpr(ldquoautordquo ampsprite 3) suponiendo que sprite se definioacute asiacute t_sprite sprite donde r seraacute una variable de tipo entero que guardaraacute el valor que regresa la funcion y 3 corresponde al numero de frames

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2139

que conforma el sprite Ojo que la funcion puede devolver los siguientes valores 0 Archivo no encontrado 1 OK -1 Memoria insuficiente -2 Tamantildeo de la imagen muy grande Pero esto no es todo debemos crearnos una funcion que eliminetodos los frames de la memoria

void FreeSprite(t_sprite sprite unsigned char num_frames)

unsigned char i sprite-gtx=sprite-gty=0 sprite-gtnum_frames=0 sprite-gtancho=sprite-gtalto=0 for(i=0 iltnum_frames i++)

free(sprite-gtframe[i])

De esta forma si por ejemplo queremos eliminar los frames delauto lo hariacuteamos asiacute FreeSprite(ampsprite 3)

Volver

Dibujando sprites en la pantalla

Ya sabemos como dejar un sprite en memoria pero ahoraiquestcoacutemo lo colocamos en la pantalla Para hacer esto podemostomar el sprite y leer fila a fila la imagen y visualizarlas Lo idealseriacutea que esta funcion que pone un sprite en la pantallaestuviera hecha en ensamblador Pero por ahora nosotrosveremos solo un funcion en C

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++) where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=frame[inc++]

Si se dan cuenta esta funcioacuten haraacute que nuestro sprite aparezcacomo un rectaacutengulo lo cual no resulta muy bonito acontinuacioacuten veremos como solucionar esto

Volver

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2239

Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color especiacutefico como fondo por ejemplo el color 0 (negro) Asiacutecuando queramos dibujar un sprite simplemente tendremos que

ldquopreguntarrdquo si el color que vamos a dibujar es el color de lamascara si es asiacute no lo dibujaremos y pasaremos al otroCuando encontremos un color distinto de 0 dibujaremos dichocolorCasi siempre se utiliza el color 0 como maacutescara ya que alrealizar la funcioacuten en ensamblador para colocar un sprite esmucho maacutes faacutecil verificar si una variable tiene el valor 0 Entonces nuestra rutina para colocar sprites transparentes sehariacutea asiacute

void PutSprite(int x int y unsigned char frame unsigned char where)

unsigned char ancho=frame[0] alto=frame[1] color int col fil inc=2 for(fil=0 filltalto fil++)

for(col=0 colltancho col++)

color=frame[inc++] if(color=0)

where[((fil+y)ltlt8)+ ((fil+y)ltlt6)+col+x]=color

De ahora en adelante nosotros utilizaremos esta funcioacuten ya queseriacutea muy ldquofeordquo que nuestro sprite se viera rectangular

Volver

Animaciones Realizar una animacioacuten de un sprite no es nada difiacutecilImaginemos que tenemos un ldquospriterdquo que comprende varios

frames y queremos animarla y desplazarla sobre un fondoestaacutetico Para hacer esto tenemos tres formas de hacerlo No son lasuacutenicas ni las mejores pero si son las maacutes comunas y sencillasveamos Meacutetodo 1ldquoUtiliza harta memoriardquo 1) Crear e inicializar dos pantallas virtuales (pv1 y pv2) 2) Dibujar el fondo en pv2 3) Copiar pv2 a pv1 4) Dibujar sprites en pv1 5) Esperar el retrazado vertical 6) Copiar pv1 a la VGA 7) Si es necesario modificar la posicioacuten de los sprites y de los

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2339

frames 8) Repetir desde el paso 3 VentajasEl mas faacutecil de implementar Es el mejor meacutetodo cuando se trata de muchos sprites Reduce al miacutenimo o a nada el parpadeo Desventajas - Necesita mucha memoria es decir dos pantallas virtuales maacuteslos datos de los sprites lo cual puede ser mas de 130 Kb

- No es el maacutes raacutepido cuando son pocos sprites Meacutetodo 2 ldquoNo necesita mucha memoriardquo 1) Dibujar el fondo en la VGA o copiarlo de alguna pantallavirtual 2) Almacenar la parte del fondo donde se va dibujar el sprite 3) Dibujar el sprite 4) Modificar posicion del sprite 5) Reponer la parte del fondo que se obtuvo en el paso 2 6) Repetir desde el paso 2 Ventajas - No necesita ninguna pantalla virtual - Funciona para pocos y pequentildeos sprites Desventajas - Dibujar en la VGA es maacutes lento que dibujar en una pantallavirtual - Puede causar mucho parpadeo con sprites grandes

Meacutetodo 3 ldquoUn poco de memoriardquo 1) Crear e inicializar una pantalla virtual (pv) 2) Dibujar el fondo en pv 3) Copiar pv a la VGA 4) Dibujar sprite en la VGA 5) Modificar posicion del sprite 6) Copiar la porcioacuten de fondo de pv a la VGA 7) Repetir desde el paso 4 Ventajas - No necesita tanta memoria solamente una pantalla virtual - Es maacutes raacutepido cuando se trata de pocos sprites - Hay menos parpadeo que en el meacutetodo 2 Desventajas - Es un poco maacutes complejo que lo otros meacutetodos - Con muchos sprites puede haber parpadeos Estos tres son los meacutetodos maacutes comunes pero pueden haber maacutes Lo que deben hacer ustedes es adaptar el meacutetodo quemaacutes se ajuste a su programa haciendo un balance entre lamemoria velocidad y calidad Incluso pueden combinar dos o

maacutes meacutetodos por ejemplo en el meacutetodo 3 en lugar de dibujar el fondo y los sprites en la VGA pueden dibujarlos en otra

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2439

pantalla virtual y copiar todo despueacutes a la VGA como en elmeacutetodo 1 Eso reduce mucho el parpadeo e incremente lavelocidad pero consume maacutes memoria Ya sabemos como crear una animacioacuten pero se nos queda algoimportante en el tintero que pasa si cargo un sprite iquestcoacutemo se

cuales son sus colores Bueno muy simple conociendo supaleta de colores para esto debemos tener en un archivo lapaleta de colores correspondiente al sprite que visualizaremosSi recuerdan una paleta tiene las valores RGB de los 256colores que pueden estar mostraacutendose en la pantallasimultaacuteneamente en la pantalla Entonces lo que haremos seraacuteleer desde un archivo la paleta de colores luego almacenarla enun arreglo t_paleta y colocarla en el sistema con SetPal() Paraesto crearemos una funcion que nos lea la informacioacuten de unapaleta desde un archivo es muy simple Veamos

int LoadPal(char filename t_paleta pal)

enumARCHIVO_NO_ENCONTRADO=0ARCHIVO_NO_VALIDO=-1 OK=1

FILE f if((f=fopen(filename rb))==NULL) return

ARCHIVO_NO_ENCONTRADO if(filesize(f)=768)

fclose(f) return ARCHIVO_NO_VALIDO fread(pal sizeof(char) 768 f) fclose(f) return OK

Esta funcioacuten recibe como paraacutemetros el nombre de la paletaque generalmente tiene la extensioacuten pal tambien recibe una

variable de tipo t_paleta para guardar los datos leiacutedos Se abreel archivo y se verifica que el archivo tenga el tamantildeo 768(recuerden 2563=768) y al final se lee la paleta La funcionfilesize la podraacutes encontrar en el archivo vgalibh Ahora veremos como hariacuteamos una animacioacuten utilizando elmeacutetodo 1 Lo primero que se haraacute seraacute cargar todos los spritesen memoria y cargar la paleta correspondiente Por ejemploimaginemos que tenemos la toda la secuencia de frames de unldquomonordquo caminando Supongamos que el sprite estaacute formado por 5 frames Entonces si queremos mostrar la animacioacuten ser hariacuteade esta forma

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2539

t_sprite mono Variable que guarda los datos del sprite t_pvirtual pv1 pv2 Pantallas virtuales t_paleta pal Para guardar la paleta del sprite int num=0 Nuacutemero del frame a mostrar SetPVirtual(amppv1) Reservamos memoria para las pantallasvirtuales SetPVirtual(amppv2) LoadSprite(ldquomonordquo ampmono 5) Cargamos el spriteLoadPal(ldquomonopalrdquo pal) Cargamos la paleta monox=0 Inicializamos variables de posicion del sprite monoy=100 SetMode(GRAFICO) Inicializamos el modo 13h (320x200) SetPal(pal) Colocamos nuestra paleta do

FlipTo(pv1 pv2) Copiamos pv2 a pv1 Dibujamos el spritePutSprite(monox monoy monoframe[num] DIR_VGA) Cambiamos el frame del sprite num++ if(numgt2) num=0 monox+=2 Modificamos posicion Verificamos si se sale de la pantallaif(monox+monoanchogt320) monox=0 WaitRetrace() Copiamos pv1 a la VGA Flip(pv1)

while(kbhit()) SetMode(TEXTO) Volvemos al modo texto FreePVirtual(amppv1) Liberamos memoria de las pantallasvirtuales FreePVirtual(amppv2) FreeSprite(ampmono 5) Liberamos la memoria del sprite

Como ven no es difiacutecil crear animaciones Tengan en cuentaque en el ejemplo no verificamos ninguacuten error como por ejemplo si no hay memoria o si no existe alguacuten archivo

Volver

Ejemplo Ahora podraacuten encontrar un ejemplo similar al anterior pero maacutescompleto y con los archivos de los sprites y paleta Ver Libreriacutea graacutefica vgalibh

TablasPrefefinidas

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2639

Hardware

Modo 13h

Retrazado Vertical

PrimitivasLa Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

bull iquestQueacute es un tabla predefinidabull Creando una tabla precalculadabull Ejemplo

iquestQueacute es un tabla predefinida Las tablas predefinidas o lookup table es algo muy simple deentender y que haraacute que en nuestros demos o juegos losdistintos caacutelculos y operaciones que tengamos que realizar nonos quiten tiempo y hagan maacutes raacutepidos nuestros programas Cuando en nuestras aplicaciones necesitamos realizar numerosos caacutelculos matemaacuteticos complejos de una formafrecuente esto puede hacer que el resultado de nuestro demo o juego se ponga muy lento debido al tiempo que se tardan enrealizar estos caacutelculos La idea para crear una tabla es sencilla iquestY si primerorealizamos las operaciones y los resultados los guardamos enuna tabla indexada Luego tendremos solo que tomar losvalores de la tabla cuando nos haga falta para algunaaplicacioacuten y extraer los resultados de esta previamentecalculados Esto de las tablas precalculadas es vital en la programacioacuten 3Do tambieacuten para hacer fractales etc

Volver

Creando una tabla precalculada Sabemos que el lenguaje C trae varias funcionestrigonomeacutetricas en las que se incluyen la del seno y cosenoLamentablemente estas funciones hacen muchascomprobaciones de rangos y algunos caacutelculos extra que hacenque su uso sea algo muy lento Ademaacutes de que el paraacutemetroque reciben debe ser un aacutengulo en radianes Por lo que siquisieacuteramos usar grados tendriacuteamos que hacer antes unaconversioacuten y lo que significa maacutes caacutelculos y maacutes tiempo que

esperar Lo que tenemos que hacer entonces es generar nuestra propiatabla de valores de las funciones almacenarla en un arreglo ysimplemente usar este arreglo en lugar de las funciones sin() ycos() Veamos un ejemplo de esto

define PI 3141516 typedef float t_tabla

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2739

t_tabla seno coseno void GeneraTablas(void)

int ang seno=(float )malloc(360sizeof(float)) coseno=(float )malloc(360sizeof(float)) for(ang=0 anglt360 ang++)

seno[ang]=sin(angPI180) coseno[ang]=cos(angPI180)

Primero definimos una constante para el valor de Pi Luego untipo de datos llamado t_tabla que es un puntero a datos de tipofloat para almacenar los nuacutemeros reales que corresponden alos senos yo cosenos de aacutengulos enteros de 0 a 360 gradosLuego creamos dos variable del tipo t_tabla una para los senosy otra para los cosenos Despueacutes en el procedimientoGeneraTablas() reservamos el espacio en memoria necesariopara nuestras tablas con la funcion malloc() Si intentamosacceder a las tablas antes de reservar el espacio en memoriapodriacuteamos hacer que se trabara la maacutequina

Luego calculamos los valores de las tablas En este caso noimporta usar las funciones sin y cos ya que solamentecalculamos las tablas una vez en el programa de preferencia alprincipio Las funciones sin y cos usan un argumento enradianes por lo tanto hay que convertir primero los grados aradianes Una vez que hemos calculado las tablas podemos usarlas encualquier parte del programa pero hay recordar que lasvariables seno y coseno son punteros Otra cosa a recordar esque las tablas son arreglos no funciones por lo tanto tenemosque especificar el paraacutemetro como si fuera un iacutendice es decir

entre [ ] Por ejemplo seno[45] devuelve el seno de 45 grados coseno[20] devuelve el coseno de 20 grados seno[305] devuelve un error de compilacioacuten Coseno[-20] devuelve un error de fuera de rango Antes de que termine un programa que usa tablas debemosliberar la memoria que hemos reservado para que el DOS lapueda utilizar en otros programas Esto la hacemos simplemente usando la funcioacuten free de lasiguientes forma free(seno) free(coseno)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2839

Obviamente despueacutes de liberar la memoria de una tabla ya nola podremos utilizar Al dibujar un ciacuterculo debemos hacer un ciclo de 0 a 360 gradospero no contando de uno en uno sino que hay que utilizar incrementos fraccionarios El problema es que nuestras tablas

de senos y cosenos son arreglos y C no permite que losarreglos tengan iacutendices fraccionarios por lo que tenemos quehacer un arreglo un poco maacutes grande Por ejemplo imaginemosque queremos dibujar un ciacuterculo con incrementos de 025 Para hacer esto en C podriacuteamos hacer lo siguiente float tabla tabla=(float )malloc(1440sizeof(float)) Notar que 1440 = 360 025 = 360 4 Esto significa que para calcular el seno o coseno de un aacutenguloespeciacutefico tendremos que usar seno[angulo4] coseno[angulo4]

Por ejemplo seno[80] = seno de 20 grados seno[720] = seno de 180 grados coseno[1] = coseno de 025 grados Pero lo que nosotros vamos hacer es un ciclo desde 0 hasta1440 por lo tanto no necesitamos hacer ninguacuten caacutelculo extra

Volver

Ejemplo Ahora podraacutes ver un ejemplo que hace uso de tablasprecalculadas para dibujar circunferencias en la pantallaPrimero se dibujan varias circunferencias conceacutentricas sinutilizar tablas predefinidas y luego utilizaacutendolas Libreriacutea graacutefica vgalibh Ver ejemplo

Texto enmodo graacutefico

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 2939

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

Hasta el momento para colocar texto en la pantalla soloutilizaacutebamos las funciones que nos proporcionaba nuestrocompilador Ahora veremos como colocar texto en modo graacutefico Podemos

colocar texto normal en negrita sombreado cursiva etc sin eluso de la BIOS ni funciones del compilador El meacutetodo que veremos se basa en la lectura de los caracteresque hay almacenados en la memoria ROM pero como veremosmaacutes adelante tambieacuten los podremos cargar de un archivoutilizando fuentes de 8x16 (los archivos fnt que ocupan 4096bytes=816256) Y como veremos y hemos dicho antes aestas les podremos aplicar diferentes efectos La tabla de caracteres se encuentra el la posicioacuten F000FA6A

aquiacute es donde comienza la descripcioacuten de los 256 caracteresCada uno esta representado mediante 8 bytes Cada byte es elpatroacuten o mascara de una fila Por ejemplo si tenemos la letraA sus 8 bytes seriacutean 56 108 198 198 254 198198 y 0como se muestra en la figura

Para descomponer los diferentes bits de un byte es decir parasaber si va un pixel o no lo que haremos seraacute utilizar laoperacioacuten loacutegica ldquogtgtrdquo Lo que hace esta operacioacuten es rotar un bitn posiciones a la derecha (lo cual corresponde a una divisioacuten)asiacute si queremos saber que valor hay en el bit nuacutemero 3 demenor peso del nuacutemero 53 (empezando por el de maacutes a laderecha) haremos la siguiente operacioacuten

53 AND (256 SHR 3)

Esto nos daraacute un 1 o por el contrario un cero depende de sidicho bit esta encendido o apagado Ahora crearemos nuestra primera rutina la cual colocaraacute soloun caraacutecter en la pantalla Pero para esto necesitamos unpuntero a la tabla de caracteres de la ROM unsigned char Font8x8=(unsigned char ) 0xF000FA6E

De esta forma utilizando el puntero Font8x8 podremos acceder

a cualquiera de los 256 caracteres disponibles

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3039

Para poder representar estos bytes adecuadamente en lapantalla tendremos que irnos a la posicioacuten correspondiente delas 256 e ir descomponiendo todos los bits de cada byte e ir dibujando soacutelo los que den 1 a medida que cambiemos de byte

aumentaremos la posicion Y en uno ya que es el quecorresponde a una liacutenea maacutes abajo en pantalla Veamos comoqueda

void WriteChar8x8(int x int y unsigned char car unsigned char color

unsigned char where)

register int linea pos for(linea=0 linealt8 linea++)

for(pos=0 poslt8 pos++) if(Font8x8[(carltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos]=color

Para dibujar una cadena entera lo que haremos seraacute antes deentrar en el bucle encargado de dibujarnos el caraacutecter obtener el tamantildeo de la cadena En C eso lo podemos hacer mediantela funcioacuten strlen() Como sabemos el tamantildeo de la cadena soacutelo tendremos que ir dibujando caraacutecter a caraacutecter teniendo en cuenta quetendremos que aumentar en 8 la X cada vez que dibujemos uncaraacutecter

void Write8x8(int x int y unsigned char cadena unsigned char color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Si queremos hacerlo con cursiva lo uacutenico que tendremos quehacer es ir desplazando X en n-1 posiciones cada vez de

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3139

manera que cuando Y sea igual 8 n sea igual 1 o sea a X lesumaremos 0 y asiacute quedaraacute como estaba vamos a ver estocon maacutes detalle la siguiente funcioacuten coloca texto en cursiva

void WriteCur8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

register int i linea pos int longitud=strlen(cadena) x+=6 for(i=0 iltlongitud i++)

for(linea=0 linealt8 linea++) for(pos=0 poslt8 pos++)

if(Font8x8[(cadena[i]ltlt3)+linea] amp (256gtgtpos))

where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+(iltlt3)-linea]=color

Si lo que queremos es dibujar con sombra la funcioacuten necesitaraacutedos valores el color del texto y el color de la sombra Ahora louacutenico que deberemos hacer es dibujar con la funcioacuten encargadade escribir un texto que vimos antes Write8x8() Primero colocaremos la sombra pero desplazando X e Y una

posicion y luego el texto con el color correspondiente

void WriteShadow8x8(int x int y unsigned char cadena unsignedchar color

unsigned char c_shadow unsigned char where)

Write8x8(x+1 y+1 cadena c_shadow where) Write8x8(x y cadena color where)

Tambieacuten podriacuteamos crear texto en negrita esto es muy simpleVeamos

void WriteNeg8x8(int x int y unsigned char cadena unsignedchar color

unsigned char where)

Write8x8(x y cadena color where) Write8x8(x+1 y cadena color where)

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3239

Normalmente el tamantildeo de 8x8 se nos hace demasiado

pequentildeo para los modos SVGA que se usan hoy en diacutea (comomiacutenimo 640x480) Existen otro tipo diferente de letras estasson el doble de altas que las anteriores Estos tipos de fuentespueden ser cargadas desde unos archivos de extensioacuten fntEstos archivos contienen varios tipos diferentes de fuentes quepodraacuten ser retocadas con alguno de los muchos diferentes tiposde programas que hay para esto asiacute que se hacen ideales parautilizar en juegos demos etc Estos archivos no son nada maacutesque caracteres de tamantildeo 8x16 almacenados de la mismaforma que los de 8x8 pero en vez de estar en memoria estosse encuentran en un archivo Los primeros 16 bytes de estos

archivos corresponderaacuten al caraacutecter 0 de la tabla ASCII y asiacuterecorriendo todas sus posiciones hasta llegar al byte nuacutemero4096 (25616) La forma de trabajar con estas no difiere ennada con las anteriores (8x8) pero ahora deberemos de tener en cuenta que son fuentes de 16 pixeles de alto en vez de 8 Para trabajar con estos archivos crearemos un nuevo tipo dedato typedef unsigned char t_font[4096] De esta forma cuando queramos cargar alguna fuente enespecial simplemente crearemos una variable del tipo t_font Una rutina que cargue estos archivos puede ser la siguiente

int LoadFont8x16(char filename t_font font)

enumARCHIVO_NO_ENCONTRADO=0 OK=1 FILE f if((f=fopen(filenamerb))==NULL) return

ARCHIVO_NO_ENCONTRADO fread(font sizeof(char) 4096 f) fclose(f) return OK

La funcioacuten para escribir cadenas de texto pero utilizando

caracteres de 8x16 es anaacuteloga a la que se hizo para las de 8x8Ojo que la funcioacuten tambien necesita como paraacutemetro una

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3339

variable de tipo t_font Veamos entonces como nos quedariacuteaesta funcioacuten

void Write8x16(int x int y unsigned char cadena unsigned char color t_font font

unsigned char where)

register int i linea pos int longitud=strlen(cadena) for(i=0 iltlongitud i++)

for(linea=0 linealt16 linea++) for(pos=0 poslt8 pos++)

if(font[(cadena[i]ltlt4)+linea] amp (256gtgtpos)) where[((y+linea)ltlt8)+((y+linea)ltlt6)+x+pos+

(iltlt3)]=color

Las demaacutes funciones para trabajar con fuentes de 8x16 al igualque todas las rutinas que ya vimos las podraacuten encontrar en unalibreriacutea llamada writeh

Ejemplos

Libreriacutea graacutefica vgalibh Libreriacutea texto writeh

bull Colocando texto en pantalla de tamantildeo 8x8 y 8x16 condiferentes estilos

bull Un scroll de texto

Formatos

Graacuteficos

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

Sprites

Tablas Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Muchas veces en lugar de dibujar en la pantalla utilizandoinstrucciones de liacuteneas ciacuterculos etc simplemente queremoscargar una imagen desde un archivo Existen muchosformatos de imaacutegenes entre los que destacan los siguientesBMP GIF PCX TIF TGA JPG y muchos otros Ahora veremos como cargar imaacutegenes en distintos formatosdesde un archivo De esta forma por ejemplo podremoscargar un fondo para una demo juego etc

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3439

Optimizaciones

Herramientas

Cursos

Links

Foro

bull Formato crudobull Formato PIC

bull Formato CEL

bull Formato PCX

Optimizaciones

Hardware

Modo 13h

Retrazado Vertical

Primitivas

La Paleta

Pantallas Virtuales

SpritesTablas

Prefedifinidas

Efectos

Texto

Formatos graacuteficos

Perifeacutericos

Optimizaciones

Herramientas

Cursos

Links

Foro

A continuacioacuten podraacutes encontrar algunas rutinas baacutesicas para laprogramacioacuten graacutefica en modo 13h optimizadas en ensamblador

Cambia a un nuevo modo de video

void SetMode(char mode)

asm xor ah ah asm mov al mode asm int 10h

Borra una pantalla virtual de un color determinado void Cls(BYTE color BYTE where)

asm les di [where] asm xor di di asm mov al [color] asm mov ah al asm mov dx ax asm db 0x66

asm shl ax 16 asm mov cx 16000 asm mov ax dx asm db 0xF3 0x66 0xAB

Coloca un pixel en una pantalla virtual void PutPixel(int x int y BYTE color BYTE where)

asm les di [where]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3539

asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al color asm mov es[di] al

Devuelve el color de un pixel de una posicioacuten determinada de lapantalla

BYTE GetPixel(int x int y BYTE where)

asm les di [where] asm mov ax y asm mov di ax asm shl ax 8 asm shl di 6 asm add di ax asm add di x asm mov al es[di] return _AL

Mueve el contenido de una pantalla virtual (64 Kb) a la VGA void Flip(BYTE source)

asm push ds asm mov ax 0xA000 asm mov es ax asm lds si [source] asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Mueve el contenido de una pantalla virtual a otra void FlipTo(BYTE source BYTE where)

asm push ds asm les di [where] asm lds si [source]

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3639

asm xor di di asm mov cx 16000 asm db 0xF3 0x66 0xA5 rep movsd asm pop ds

Cambia las intensidades RGB de un color determinado void SetColor(BYTE color char red char green char blue)

asm mov dx 3C8h asm mov al color asm out dx al asm inc dx dx=3C9h asm mov al red asm out dx al asm mov al green asm out dx al asm mov al blue asm out dx al

Obtiene las intensidades RGB de un color determinado

void GetColor(BYTE color char red char green char blue)

char r g b asm mov dx 3C7h asm mov al color asm out dx al asm inc dx asm inc dx dx=3C9h asm in al dx asm mov r al asm in al dx asm mov g al asm in al dx asm mov b al red=r green=g blue=b

Cambia la paleta actual por una pasada por paraacutemetro

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3739

void SetPal(t_paleta paleta)

asm push ds asm lds si paleta asm mov dx 3C8h asm xor al al asm out dx al asm inc dx asm mov cx 768 asm rep outsb asm pop ds

Obtiene la paleta actual void GetPal(t_paleta paleta)

asm les di paleta asm mov dx 3C7h asm xor al al asm out dx al asm add dx 2 asm mov cx 768 asm rep insb

Coloca un sprite en una pantalla virtual El tamantildeo maacuteximo es de255x255 En las dos primeras posiciones debe estar el ancho y alto delsprite respectivamente

void PutSprite(int x int y BYTE sprite BYTE where)

asm push ds Salva los registros de segmento asm push es asm les di [where] esdi direccioacuten de pantalla virtual asm lds si [sprite] dssi direccioacuten del sprite asm mov di y Calcula el offset lo cual corresponde asm mov ax di al numero de bytes para llegar al sprite asm shl di 8 desde el comienzo de la pantalla asm shl ax 6 asm add di ax asm add di x asm xor dx dx dx = 0

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3839

asm xor bx bx bx = 0 asm cld Incrementa los desplazamientos asm lodsw Recupera el primer word de DSSI y lo

guarda en AX asm mov dl al dl = ancho asm mov bl ah bl = alto asm mov cx bx Al registro de cuenta la altura

bucle1 asm mov bx cx Guardamos en bx el registro de cuenta asm mov cx dx Al registro de cuenta la anchura

bucle2 asm lodsb Recupera un byte del sprite asm or al al Para ver si es cero asm jz incdi si cero = parte transparente del sprite asm stosb Si no es cero lo visualizamos asm jmp seguir y volver a empezar

incdi

asm inc di Nos saltamos este byte seguir

asm dec cx asm jnz bucle2 Bucle de la anchura asm sub di dx Nos situamos en la liacutenea siguiente asm add di 320 asm mov cx bx Recuperamos contador de altura asm dec cx asm jnz bucle1 Bucle de altura asm pop es Recuperamos registros de segmento asm pop ds

Espera a que termine el retrazado vertical de la pantalla void WaitRetrace(void)

asm mov dx 03DAh espera1

asm in al dx asm test al 08h asm jnz espera1

espera2 asm in al dx asm test al 08h asm jz espera2

Ahora continuacioacuten podraacutes encontrar la libreriacutea graacutefica VGALIBHactualizada con las rutinas que vimos optimizadas enensamblador

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet

592018 Las primitivas son dibujos baacutesicos - slidepdfcom

httpslidepdfcomreaderfulllas-primitivas-son-dibujos-basicos 3939

Antes de compilar la libreriacutea es posible que tengan que activar elcoacutedigo para 80286 esto lo encuentran en los compiladoresBorland en

Options | Compiler | Advanced Code Generation | InstructionSet