08.08.2013 Visualizaciones

tesis_uam/Graficacion en 3D_UAM1969.pdf - cedip

tesis_uam/Graficacion en 3D_UAM1969.pdf - cedip

tesis_uam/Graficacion en 3D_UAM1969.pdf - cedip

SHOW MORE
SHOW LESS

¡Convierta sus PDFs en revista en línea y aumente sus ingresos!

Optimice sus revistas en línea para SEO, use backlinks potentes y contenido multimedia para aumentar su visibilidad y ventas.

~ ~ I ~ E R AUTONOMA $ ~ 5 ~ 5 METROPOLI<br />

LICE CIATURA EN<br />

Arias M<strong>en</strong>doza Carlos<br />

Cuevas Bonilla Raúl<br />

Vilchis Orozco Roberto<br />

Trimestres 9 6-1 y 9 6-P


a<br />

Proyecto <strong>en</strong> la Ing<strong>en</strong>iería I y II<br />

"Graficación tridim<strong>en</strong>siional"<br />

Cont<strong>en</strong>ido<br />

Objetivos y plan de trabajo<br />

Espacios Vectoriales<br />

Repres<strong>en</strong>tación paramétrica de superficies<br />

Rotaciones<br />

Rotaciones <strong>en</strong> el espacio<br />

Metodos de ord<strong>en</strong>ación <strong>en</strong> profundidad<br />

Repres<strong>en</strong>tación <strong>en</strong> memoria de objetos<br />

tridim<strong>en</strong>sionales<br />

Reconocedor y g<strong>en</strong>erador de objetos<br />

tridim<strong>en</strong>sionales<br />

Metodo de "Z-Buffer"<br />

Administración de la memoria<br />

La programación XMS<br />

Utilización de la rutinas XMM1.H<br />

Bibliografía


Objetivo G<strong>en</strong>eral:<br />

Proyecto de investigación<br />

Titulo: "Graficación <strong>3D</strong>"<br />

Crear una biblioteca de funciones de graficación <strong>3D</strong> para PC, sujeta al estandard VESA (<br />

SVGA) a 256 colores.<br />

Marco Teórico:<br />

Es bi<strong>en</strong> sabido que la graficación por computadora y <strong>en</strong> particular la graficación<br />

tridim<strong>en</strong>sional reqltiere de algoritmos complejos y gran cantidad de recursos del sistema<br />

(memoria y velocidad de cómputo): Es por ello que converg<strong>en</strong> <strong>en</strong> ésta disciplina técnica de<br />

programación de sistemas, estructuras de datos, compiladores8, optimización, análisis y diseño de<br />

algoritmos, algebra lineal y geometría proyectiva.<br />

Uno de los objetivos principales de este proyecto e:; ( a parte del producto <strong>en</strong> si )<br />

complem<strong>en</strong>tar la formación de los educandos,por medio de la1 integración de sus conocimi<strong>en</strong>tos<br />

previam<strong>en</strong>te adquiridos con un propósito comun.<br />

Plan de Trabajo<br />

Primer trimestre:<br />

Estudiar diversas estructuras de datos para repres<strong>en</strong>tar objetos tridim<strong>en</strong>sionales y <strong>en</strong><br />

función de ello escoger la(s) que más conv<strong>en</strong>ga(n) a nuestros propósitos.<br />

Analizar y compr<strong>en</strong>der diversos algoritmos como por ejemplo: "ord<strong>en</strong>ación <strong>en</strong><br />

profundidad" y "z-buffer". Llevar a cabo s'u implem<strong>en</strong>tación.<br />

La programación se realizará <strong>en</strong> l<strong>en</strong>guaje C<br />

Segundo Trimestre:<br />

Estudiar técnrcas de manejo de memoria ext<strong>en</strong>dida, para satisfacer las necesidades de<br />

memoria de los algoritmos m<strong>en</strong>cionados.<br />

lmplem<strong>en</strong>tar una función que g<strong>en</strong>ere objetos tridim<strong>en</strong>sionales a partir de ecuaciones de<br />

superficies. (Se usarán tecnicas de Comptladares)


Transformaciones lineales:<br />

Espacios Vectoriales<br />

Dados U E R3 3 V E R3 una transformación lineal cumple las sigui<strong>en</strong>tes propiedades:<br />

L(U+V)=L(U)+L(V)<br />

L(cU) = cL(U)<br />

por ejemplo L:R3 -+ R<br />

(a,b,c) -+ a<br />

(a,b,c) -+a +b+c<br />

( a, b, c ) -+ 3a - 4b + 2c<br />

( a, b, c ) -+ 4a, 3b<br />

(a,b,c) -+ 5a,2c<br />

Las sigui<strong>en</strong>tes tramfomaciones R3 4 R2 recib<strong>en</strong> un punto <strong>en</strong> el espacio ( x,y,z ) y lo<br />

mandan (transforman) a un punto <strong>en</strong> el plano X'.Y'.<br />

ii,<br />

(1,0,0)+ al, bl<br />

(O,l,O)-+ a2,b2<br />

( O, O, 1 ) -+ a3, b3<br />

2 + x<br />

(O,O,l] (l.O,O]<br />

IR3<br />

y'l<br />

(aZb2)<br />

/"'<br />

(a3.b3)<br />

IR2


Las transformaciones lineales pued<strong>en</strong> repres<strong>en</strong>tarse como matrices, por lo que es posible<br />

repres<strong>en</strong>tar las transformaciones anteriores<br />

de la sigui<strong>en</strong>te manera:<br />

Aplicando las propiedades de las transformaciones lineales se ti<strong>en</strong>e:<br />

La matriz de transformación resulta:<br />

vectores - { }<br />

base<br />

O 0 1


Coord<strong>en</strong>adas Esféricas<br />

Repres<strong>en</strong>tación Paramétrica cle Superficies<br />

Una superficie tridim<strong>en</strong>sional puede repres<strong>en</strong>tarse <strong>en</strong> coord<strong>en</strong>adas rectangulares,<br />

cilíndricas y esfericas, <strong>en</strong> particular nos interesan las ecuacion'es pararnétricas <strong>en</strong> coord<strong>en</strong>adas<br />

esfericas, la repres<strong>en</strong>tación espacial de un punto es como sigue:<br />

/<br />

z = tcos 8<br />

t = r s<strong>en</strong> Q<br />

x = r s<strong>en</strong> Q s<strong>en</strong> 8<br />

y= rcos Q<br />

z= r s<strong>en</strong> cos8<br />

Del esquema anterior se observa que un punto con coord<strong>en</strong>adas (x,y,z) puede describirse<br />

<strong>en</strong> función de dos ángulos ( 6 y 9) los cuales son los parárnetos, y la distancia de dicho punto al<br />

orig<strong>en</strong> de coord<strong>en</strong>adas. En el caso de las coord<strong>en</strong>adas esféricas, los ángulos 0 y cp toman valores<br />

de O - 2Il y de O - Il radianes respectivam<strong>en</strong>te, con Io cual se cubre todo el espacio<br />

tridim<strong>en</strong>sional.


Rotaciones<br />

Una rotación es una transformación lineal, un caso particular es la rotación de un sistema<br />

de coord<strong>en</strong>adas. Considere un punto <strong>en</strong> el plano X-Y de coord<strong>en</strong>adas (x,y), expresado <strong>en</strong><br />

coord<strong>en</strong>adas polares se ti<strong>en</strong>e:<br />

1<br />

Q = arc: tan -<br />

X<br />

Y<br />

Si rotamos los ejes coord<strong>en</strong>ados q grados <strong>en</strong> el s<strong>en</strong>tido contrario a las manesillas del reloj,<br />

obt<strong>en</strong><strong>en</strong>mos un nuevo sistema de refer<strong>en</strong>cia X-Y'. Las nuevas coord<strong>en</strong>adas para el punto <strong>en</strong><br />

cuestion resultan:<br />

X<br />

YV = arc tan [-I - 8<br />

Y<br />

Observando los puntos (X,,Y,) = (1,O) y (X,,Y,) = ( C),1) del sistema de coord<strong>en</strong>adas<br />

original, podemos obt<strong>en</strong>er las nuevas coord<strong>en</strong>adas para este punto, resultando:<br />

( X,',Y,' ) = ( cos 0, s<strong>en</strong> 0 )<br />

( X,',Y,' ) = ( -s<strong>en</strong> 0, cos 8 )<br />

Ahora obt<strong>en</strong>emos que una rotación del plano X-Y 0 grados positivos se puede expresar<br />

como el producto de dos matrices:<br />

x' = x cos 8 - y s<strong>en</strong>0<br />

y' = x s<strong>en</strong>e +' y cos O<br />

Es decir para obt<strong>en</strong>er las nuevas coord<strong>en</strong>adas de un purlto que ha sido rotado 8 grados, se<br />

requier<strong>en</strong> las coord<strong>en</strong>adas del punto sin rotar y el ángulo de rotación.


Rotaciones <strong>en</strong> el espiacio<br />

Si rotamos los ejes X-Y y dejamos fijo el eje Z, t<strong>en</strong>emos:<br />

Y<br />

Z /<br />

Las nuevas coord<strong>en</strong>adas resultan:<br />

X<br />

(l,O,O) -+ ( cos 8, s<strong>en</strong>e, O )<br />

(0,1,0) -+ ( -s<strong>en</strong>e, cos 8, O )<br />

(0,0,1) -+ ( o, o, 1 1<br />

y '\<br />

Por lo.tanto la matriz de rotación con el eje Z fijo, es la si'gui<strong>en</strong>te:<br />

Dejando fijo el eje X<br />

(1 O O Y x 1 f x' \<br />

Io cos -s<strong>en</strong>e /I y I = I y' I<br />

\O s<strong>en</strong>e cos e I\ z I \ 2' I<br />

Dejando fijo el eje Y :<br />

(COS e o -s<strong>en</strong>e x ) f x' 1<br />

Io 1 O IIy I = I y' I<br />

\s<strong>en</strong>e O COS e i\ z I 2' I


Métodos de detección de suplerficie visible<br />

Una consideración importante <strong>en</strong> la g<strong>en</strong>eración de despliegues de gráficas realistas es la<br />

id<strong>en</strong>tificación de aquellas partes de una esc<strong>en</strong>a que son visibles desde una posición de vista<br />

seleccionada<br />

Los algoritmos de detección de superficie visible se clasifican <strong>en</strong> forma g<strong>en</strong>eral<br />

dzp<strong>en</strong>di<strong>en</strong>do de si manejan definiciones de objetos de ma,nera directa o con sus imág<strong>en</strong>es<br />

proyectadas. Estos dos planteami<strong>en</strong>tos se d<strong>en</strong>ominan métodios de objeto-espacio y métodos de<br />

imag<strong>en</strong>-espacio, de modo respectivo. Un método de objeto-espacio compara objetos y partes de<br />

objetos con cada tino de los mismos <strong>en</strong> la definición de la esc<strong>en</strong>a a fin de determinar qué<br />

superficies, como un todo, debemos designar como visibles. Ein un algoritmo de imag<strong>en</strong>-espacio,<br />

la visibilidad se decide punto por punto <strong>en</strong> cada posición de pixel <strong>en</strong> el plano de proyección.<br />

Método de clasificación de profundidad<br />

AI utilizar tanto operaciones de imag<strong>en</strong>-espacio coma1 de objeto espacio, el método de<br />

clasificación de profundidad realiza las funciones básicas sigui<strong>en</strong>tes:<br />

1) Se clasifican las superficies <strong>en</strong> ord<strong>en</strong> de profundidad decreci<strong>en</strong>te.<br />

2) Se conviert<strong>en</strong> por rastreo las superficies <strong>en</strong> ord<strong>en</strong>, al iniciar con la superficie de la mayor<br />

profundidad.<br />

Las operaciones de clasificación se efectúan tanto <strong>en</strong> irnag<strong>en</strong> como <strong>en</strong> objeto-espacio y la<br />

conversión de rastreo de las superficies de polígono se lleva a cabo <strong>en</strong> imag<strong>en</strong>-espacio.<br />

Este método para solucionar el problema de las superficies ocultas a m<strong>en</strong>udo se d<strong>en</strong>omina<br />

algoritmo del pintor. Primero clasificamos las superficies de acuerdo con su distancia desde el<br />

plano de visión, de esta manera se capturan <strong>en</strong> el búfer de <strong>en</strong>friami<strong>en</strong>to los valores para la<br />

'superficie más alejada. AI manejar cada superficie a la vez ( ein ord<strong>en</strong> decreci<strong>en</strong>te de profundidad<br />

), "pintamos" las int<strong>en</strong>sidades de superficie <strong>en</strong> el búfer de estructura sobre las int<strong>en</strong>sidades de las<br />

superficies que se procesaron antes.<br />

La pintura de superficies de polígono <strong>en</strong> el búfer !de estructura de acuerdo con la<br />

profundidad se realiza <strong>en</strong> varios pasos. Si suponemos que vernos a lo largo de la dirección de las<br />

z, las superficies se ord<strong>en</strong>an <strong>en</strong> la primera trayectoria de acuerdo con el valor más alto de z <strong>en</strong><br />

cada superficie. La superficie con la profundidad más alta se compara <strong>en</strong>tonces con las otras<br />

superficies <strong>en</strong> la lista para determinar si hay alguna superposición la profundidad. si no se da<br />

nlnguna superposición <strong>en</strong> la profundidad, la superficie S se convierte por rastreo. La figura 1<br />

iiustra dos superficies que se superpon<strong>en</strong> <strong>en</strong> el plano xy pero no ti<strong>en</strong><strong>en</strong> ningún traslape de<br />

profundidad.


zmaxb<br />

Zrnin<br />

Asi se repite este proceso para la sigui<strong>en</strong>te superficie <strong>en</strong> la lista. En tanto que no haya<br />

ninguna superposición, se procesa cada superficie <strong>en</strong> ord<strong>en</strong> cle profundidad hasta que se hayan<br />

convertido todas por rastreo. Si se detecta una superposicitjn <strong>en</strong> la profundidad <strong>en</strong> cualquier<br />

punto de la lista, es necesario realizar algunas comparaciones adicionales para determinar si se<br />

debe reorganizar cualquiera de las superficies.<br />

Practicamos las pruebas sigui<strong>en</strong>tes para cada superficile que se traslapa con S. si alguna<br />

de estas pruebas es verdadera, no es necesario llevar a cabo ninguna reorganización para esa<br />

superficie. Las pruebas se listan <strong>en</strong> ord<strong>en</strong> increm<strong>en</strong>tal de dificultad.<br />

1) Los rectángulos limítrofes <strong>en</strong> el plano de xy para las dos superficies no se sobrepon<strong>en</strong>.<br />

2) La superficie S está por completo detrás de la superficie que se sobrepone con respecto<br />

de la posición de vista.<br />

3) La superficie que se sobrepone está por completo <strong>en</strong>fr<strong>en</strong>te de S con respecto de la<br />

posición de vista.<br />

4) Las proyecciones de las dos superficies <strong>en</strong> el plano de visión no se traslapan.<br />

Realizamos estas pruebas <strong>en</strong> el ord<strong>en</strong> <strong>en</strong> que se listan y procedemos a la sigui<strong>en</strong>te<br />

superficie que se sobrepone <strong>en</strong> cuanto <strong>en</strong>contramos que una de las pruebas es verdadera. Si<br />

todas las superficies que se traslapan pasan por Io m<strong>en</strong>os una de estas pruebas, ninguna de<br />

éstas se halla detrás de S. Así, no es necesario efectuar ninguna reorganización y se convierte<br />

por rastreo S.<br />

La prueba 1 se lleva a cabo <strong>en</strong> dos partes. Primero verificamos la sobreposición <strong>en</strong> la<br />

dirección de x, luego verificamos la sobreposición <strong>en</strong> la dirección de y Si alguna de estas<br />

direcciones no pres<strong>en</strong>ta sobreposición, los dos planos no pued<strong>en</strong> oscurecerse <strong>en</strong>tre si. En la<br />

figura 2 se pres<strong>en</strong>ta un ejemplo de dos superficies que se sobrepon<strong>en</strong> <strong>en</strong> la dirección de z pero<br />

no <strong>en</strong> la dirección de x.


-7v<br />

Xrnin Xrnax X'rnin X'max<br />

figura 2<br />

Dos supeMaés<br />

con sobreposia5n<br />

<strong>en</strong> profunddad<br />

pero sin fraslape<br />

<strong>en</strong> /a dremzn<br />

de x<br />

Podemos practicar las pruebas 2 y 3 con una prueba de polígono "interna y externa". Es<br />

decir, sustituimos las coord<strong>en</strong>adas para todos los vértices de S <strong>en</strong> la ecuación del plano para la<br />

superficie que se traslapa y verificamos el signo del resultado,. Si se establec<strong>en</strong> las ecuaciones<br />

del plano de manera que el exterior de la superficie se dirija hacia la posición de vista, <strong>en</strong>tonces S<br />

está atrás de S's¡ todos los vertices de S están "ad<strong>en</strong>tro" de S'( Figura 3).<br />

I figura 3<br />

La supeMaé S<br />

se h311a por comp/eto<br />

atris de [ad<strong>en</strong>tro de 1<br />

/a supedaé<br />

sobrepuesta S<br />

De modo similar S' está por completo <strong>en</strong>fr<strong>en</strong>te de S si todos los vértices de S están por<br />

completo "afuera" de S. La figura 4 ilustra una superficie S' que se traslapa, la cual está por<br />

completo <strong>en</strong>fr<strong>en</strong>te de S, pero la superficie S no está por completo "ad<strong>en</strong>tro" de S'(la prueba 2 no<br />

es verdadera).<br />

+ xi<br />

zi<br />

figura 4<br />

L 3 supehaé<br />

sobrepuesta S' esta'<br />

por cumpleto <strong>en</strong> tr<strong>en</strong>te<br />

de f afuera de]/.<br />

supedaé S, pero Sno<br />

estgpor completo<br />

atkk de S!


t<br />

Si las pruebas 1 y 3 no ti<strong>en</strong>e éxlto, int<strong>en</strong>tamos con la prueba 4 al verificar las<br />

intersecciones <strong>en</strong>tre las aristas limítrofes de las dos superficies utilizando las ecuaciones de la<br />

linea <strong>en</strong> el plano xy. Como se demuestra <strong>en</strong> la figura 5. dos superficies pued<strong>en</strong> intersectarse o no<br />

incluso si sus ext<strong>en</strong>siones de coord<strong>en</strong>adas se traslapan <strong>en</strong> las direcciones de x,y y 2.<br />

figura 5<br />

Si las cuatro pruebas fracasan con una superficie de sobreposición particular S',<br />

intercambiamos S y S' <strong>en</strong> la lista calificada. En la figura 6 se pres<strong>en</strong>ta un ejemplo de dos<br />

superficies que se deb<strong>en</strong> reorganizar con este procedimi<strong>en</strong>to.<br />

I<br />

I. I<br />

En este punto aún no sabemos con certeza que hemos <strong>en</strong>contrado la superficie más<br />

alejada del punto de visión. La figura 7 ilustra una situación <strong>en</strong> que primero intercambiariamos S<br />

y S'.


Repres<strong>en</strong>tación <strong>en</strong> memoria de objetos tridim<strong>en</strong>sionales<br />

Estructura de datos para un objeto tridim<strong>en</strong>sional:<br />

struct punto {<br />

float x,y,z;<br />

1;<br />

struct plano {<br />

int numero-de-vertices;<br />

float z-min,z-max;<br />

float N-X,N-Y,N-Z;<br />

struct punto ** ptr-lista-puntos;<br />

struct plano *sigui<strong>en</strong>te;<br />

1;<br />

struct objeto {<br />

struct punto *ptr-puntos;<br />

struct plano *ptr-planos;<br />

1;<br />

El usuario declara d<strong>en</strong>tro de main() o bi<strong>en</strong> como variable global un puntero a una estructura<br />

de tipo objeto o bi<strong>en</strong> una estructura de tipo objeto :<br />

Caso (1) struct objeto *ptr-objeto;<br />

Caso (2) struct objeto mi-objeto;<br />

Si el usuario opta pcr el caso (1) deberá solicitar memorla para la estructura, como se<br />

muestra a continuación:<br />

ptr-objeto = farrcalloc(1, sizeof ( struct objeto ) );<br />

o bi<strong>en</strong>:<br />

ptr-objeto = malloc( sizeof ( struct objeto ) );<br />

Calculo para los puntos tridim<strong>en</strong>sionales de un bojeto<br />

Dada la ecuación paramétrica de un ob,._:o tridim<strong>en</strong>sional, se plantea al número de puntos a<br />

graficar tomando <strong>en</strong> cu<strong>en</strong>ta el número de intervalos de división para cada uno de los parámetros<br />

del objeto, por ejemplo, si U y V son los parámetros de cierto objeto, el usuario determina el<br />

número de puntos <strong>en</strong> los que se divide cada uno, con IC) que obt<strong>en</strong>emos dos variables :<br />

parametro-U y parametro-\/, la cantidad de puntos a gráficar se obti<strong>en</strong>e de:<br />

numguntos-a graficar = (( parametro-U +I) * (parametro-V +I));<br />

El sigui<strong>en</strong>te paso es resevar la memoria necesaria para almac<strong>en</strong>ar este número de puntos,<br />

el campo puntos de la estructura objeto almac<strong>en</strong>a la dirección de esta lista dinámica de puntos,<br />

esto lo hacemos con la sigui<strong>en</strong>te instrucción:<br />

ptr-objeto->puntos = farcalloc(numguntos-a_grafic~tr, sizeof(struct punto) );


En este punto se ti<strong>en</strong>e lo slgui<strong>en</strong>te <strong>en</strong> memoria:<br />

De acuerdo a la ecuación paramétrica de cada objeto. se calculan los valor tridim<strong>en</strong>sionales<br />

(x,y,z) de cada punto de la superficie del objeto, y se almac<strong>en</strong>an <strong>en</strong> la lista de puntos.<br />

Calculo de los planos que forman la superficie del objeto<br />

Con los valores de los puntos (x,y,z) <strong>en</strong> memoria ahora es posible formar una lista para los<br />

planos que formarán el objeto. La estructura de datos declarada como struct plano conti<strong>en</strong>e un<br />

campo llamado sigui<strong>en</strong>te con el que se crea la lista de manera dinámica, el otro campo llamado<br />

*ptr-/ista_puntos es un puntero que apunta a una lista dinámica de punteros a estructuras de tipo<br />

punto, tal y como se muestra <strong>en</strong> el sigui<strong>en</strong>te esquema:<br />

struct plano wr'<br />

I<br />

1 t I____) .<br />

struct punto<br />

Para crear un plano se solicita memoria dinámica para una estructura de tipo plano, y se<br />

comi<strong>en</strong>za a crear la lista de planos, esta lista es apuntada por ptr-objeto->p/anos.<br />

En el mom<strong>en</strong>to de crear un primer nodo de la lista, se debe solicitar también memoria para la<br />

lista de punteros a estructuras de tipo punto, este nuevo arreglo dinámico de punteros solicitara el<br />

número de localidades necesarias según los planos se form<strong>en</strong> con tres o cuatro puntos, como se<br />

observa <strong>en</strong> la sigui<strong>en</strong>te instrucción:<br />

struct punto *puntos;<br />

puntos = malloc ( (nurn-de-vertices) * (sizeof (* struct punto) ) );<br />

donde nurn-de-vertices es uno de los campos de la estructura 'struct plano'. El campo<br />

*ptr-lista-puntos apunta a esta lista dinámica de punteros a puntos.


AI mom<strong>en</strong>to de formar un plano de 3 o 4 puntos, se calculan los valores de profundidad<br />

minima y profundidad máxima los cuales se guardan <strong>en</strong> los campos z-min y z-rnax<br />

respectivam<strong>en</strong>te. Recordando que cada vertice del plano ti<strong>en</strong>e compon<strong>en</strong>tes x,y,z, es posible<br />

comparar cada uno de los valores para z y obt<strong>en</strong>r el máximo y el minimo.<br />

Obt<strong>en</strong>ción de las<br />

coord<strong>en</strong>adas<br />

z-min y z-max<br />

para un plano<br />

partucular.<br />

z-min<br />

z-m ax<br />

z-<br />

Tambi<strong>en</strong> es posible calcular <strong>en</strong> este mom<strong>en</strong>to las compon<strong>en</strong>tes del vector normal a dicho<br />

plano , que ocupan los campos N-X, N-Y y N-2, estos valores se obti<strong>en</strong><strong>en</strong> de calcular el “produto<br />

cruz” <strong>en</strong>tre dos vectores que pert<strong>en</strong>ec<strong>en</strong> al plano. A su vez un vector que pert<strong>en</strong>ece al plano se<br />

obti<strong>en</strong><strong>en</strong> de restar dos puntos que pasan por el plano, estos puntos ya fueron calculados <strong>en</strong> la<br />

etapa previa a la formación de este plano.<br />

z<br />

I<br />

En el caso <strong>en</strong> que un plano este formado por cuatro puntos, se ti<strong>en</strong>e que cada punto ti<strong>en</strong>e<br />

corrd<strong>en</strong>adas x,y,z de tal forma que pi = (x,y,z), obt<strong>en</strong>emos un vector sobre el plano mediante la<br />

resta de dos puntos del plano, por ejemplo:<br />

El producto punto <strong>en</strong>tre dos vectores a y b se obti<strong>en</strong>e mediante:<br />

a = (al ,a2,a3) y b = (bl,b2,b3)<br />

El producto anterior nos da el vector normal al plano


"Reconocedor y G<strong>en</strong>eradoir<br />

Uno de los objetivos de nuestro proyecto era el de realizar un "Reconocedor y G<strong>en</strong>erador" el cual se <strong>en</strong>cargara<br />

de aceptar expresiones de la forma:<br />

donde:<br />

"varl[ini,fin,inter],var2[ini,fin,inter],x,y,z"<br />

varl .va2:Son los dos parametros de los que dep<strong>en</strong>deran las ecuaciones parametricas.<br />

ini,fin :Es donde comi<strong>en</strong>za y donde termina el intervalo de cada parametro.<br />

inter :Es el No. de divisiones del intervalo.<br />

x,y,z :Son las ecuaciones parametricas del Objeto a graficar.<br />

Una vez reconocida y aceptada la expresión se procede a g<strong>en</strong>erar la Lista de Puntos del Objeto.<br />

RECONOCEDOR DE EXPRESIONES<br />

Para reconocer las expresiones se utilizan 3 archivos que el usuario debera utilizar con '%include" y son :<br />

g<strong>en</strong>3d.h<br />

lex3d.h<br />

parse3d. h<br />

GEN<strong>3D</strong>.H<br />

El archivo "g<strong>en</strong>3d.h" incluye (por medio de 'Winclude" ) a "parse3d,h".Prirneram<strong>en</strong>te la función principal es<br />

"g<strong>en</strong>era" y es mandada llamar por el usuario de la sigui<strong>en</strong>te forma:<br />

mi-objeto=g<strong>en</strong>era("expresión");<br />

La variable "mi-objeto" será un apuntador a una estructura tipo objeto, por Io tanto regresara el apuntador a el<br />

objeto ya g<strong>en</strong>erado.<br />

Esta función "g<strong>en</strong>era" realizá propiam<strong>en</strong>te el reconocimi<strong>en</strong>to de toda la expresión y como se observa recibe una<br />

cad<strong>en</strong>a que guarda <strong>en</strong> una variable llamada "exp" la cual a su vez es igualada a la variable "yyin", que es la que<br />

utiliza nuestro analizador lexico.<br />

A la expresión , para nuestro análisis la dividimos <strong>en</strong> dos partes, la primera es la que conti<strong>en</strong>e a cada una de los<br />

parametros con su respectiva información sobre sus intervalos y la segunda es la que conti<strong>en</strong>e las ecuaciones<br />

parametricas.<br />

La información de la primera parte es guardada <strong>en</strong> un arreglo de dos llarnado "U" del tipo:<br />

struct GEN-VAR{<br />

float in¡;<br />

float fin;<br />

int n; /*No. de intervalos*/<br />

float val; /*Valor que irá tomado el parametro*/<br />

char nomb[lO]; /*Nombre del parametro*/<br />

1; struct GEN-VAR U[2];<br />

Para el análisis de esta primera parte de la expresión se va recorri<strong>en</strong>do cada uno de los caracteres de la cad<strong>en</strong>a<br />

y pasandose cada uno a la vez al analizador lexico.<br />

El análisis de la segunda parte se hace d<strong>en</strong>tro de dos ciclos (que van desde "ini" hasta "fin" con un salto de<br />

"inter") que van recorri<strong>en</strong>do los intervalos de los 2 parametros y dandole valor a cada uno.Obt<strong>en</strong>i<strong>en</strong>do el valor de<br />

cada uno de los parametros de esta forma , se manda llamar al analizador sernántico para cada una de las<br />

ecuaciones parametricas y por supuesto regresara el valor para "x"',"y" o ' Y que son guardados <strong>en</strong> una<br />

estructura de tipo "punto".Así al recorrer los 2 ciclos habremos obt<strong>en</strong>ido la lista de puntos del objeto.


En seguida se mandan a llamar las funciones que ya se han com<strong>en</strong>tado anteriorm<strong>en</strong>te:<br />

translada(OBJET0) /*Translada la lista de puntos al nuevo sistema de<br />

Coord<strong>en</strong>adas segun el punto de vision.<br />

Planos(OBJET0) /*G<strong>en</strong>era los planos del objeto a graf'icar.<br />

Pre-Ord<strong>en</strong>acion(OBJET0) /*Ord<strong>en</strong>a los planos según la 'Z' mas negativa.<br />

Ord<strong>en</strong>acion-<strong>en</strong>-Profundidad(OBJET0) /*Ord<strong>en</strong>a ahora los planos segun el Algoritmo<br />

de Ord<strong>en</strong>aciopn por Profundidad.<br />

LEX<strong>3D</strong>.H<br />

Este archivo conti<strong>en</strong>e el Analizador Lexico.Este analizador es llamaclo tanto por la función "g<strong>en</strong>era" como por el<br />

Analizador Semántico, y regresa cada uno de los tok<strong>en</strong>s respectivos:<br />

1) Caractares alfanumericos.<br />

Para este caso t<strong>en</strong>emos cuatro cad<strong>en</strong>as <strong>en</strong> particular que regresan tok<strong>en</strong>s especiales:<br />

"sin" regresa el tok<strong>en</strong> SIN.<br />

"cos" regresa el tok<strong>en</strong> COS.<br />

"tan" regresa el tok<strong>en</strong> TAN.<br />

"Pi" regresa el tok<strong>en</strong> PI.<br />

De otro forma solo se regresa el tok<strong>en</strong> ID.<br />

2) Digitos (Reconoce de Tipo 'float') y regresa el tok<strong>en</strong> NUM.<br />

3) Cualquier otro difer<strong>en</strong>te a los anteriores regresa propiam<strong>en</strong>te el caracter leido.<br />

PARSE<strong>3D</strong>.H<br />

Este archivo ti<strong>en</strong>e un ''#include" para "lex3d.h".Fue g<strong>en</strong>erado por medio de la herrami<strong>en</strong>ta BISON para obt<strong>en</strong>er<br />

Analizadores Semánticos :<br />

YO{<br />

"0)<br />

#define alloca malloc<br />

#define WSTYPE double<br />

%tok<strong>en</strong> WNUM YYlD SEN COS TAN PI<br />

%left '+,' I-'<br />

Ohleft '*I '1<br />

%right um<strong>en</strong>os<br />

Ohright 'N<br />

L3 : L2 I,' E {return($3);}<br />

L2 : L1 ',I E {return($3);}<br />

L1 :E {return($l);}<br />

E : E '+' E {$$=S1 +$3;}<br />

I E "' E {$$=$1-$3;}<br />

I E '*I E {$$=$1'$3;}<br />

1 E 'r E {$$=$1/$3;}<br />

I I-' E %prec um<strong>en</strong>os {$$ = -$2;}<br />

I '(I E I)' {$$=$2;}<br />

I E I*' E {$$=pow($l,$3);}<br />

I YYNUM {$$=yylval;}<br />

I YYlD {$$=yylval;}<br />

I SEN '(I E I)' {$$=sin($3);}


Oh Oh<br />

1 COS '(I E 'j' {$$=COS($~);}<br />

I TAN '(I E I)' {$$=tan($3);}<br />

I PI {$$=Pi;}<br />

I error (return(0);)<br />

#include "lex3d.h"<br />

yyerror(){printf("ERROR!!!!!! ...'I);}<br />

GRAFICACION DEL OBJETO<br />

Para la graficación del Objeto se debe incluir al archivo "graf3d.h" , que ti<strong>en</strong>e las sigui<strong>en</strong>tes funciones<br />

com<strong>en</strong>tadas ya anteriorm<strong>en</strong>te:<br />

Inicializa-Graficos().Pide el tipo de modo grafico a inicializar<br />

Libera-Objeto(struct objeto *objeto).Recibe un apuntador a la estructura del objeto.<br />

Dibuja(struct objeto *objeto).También recibe ese apuntador al Objeto y va graficando<br />

cada plano ya ord<strong>en</strong>ados propiam<strong>en</strong>te.<br />

INTERFASE CON EL USUARIO<br />

El usuario creará su archivo <strong>en</strong> C el cual deberá cont<strong>en</strong>er primeram<strong>en</strong>te dos '%include" que son "g<strong>en</strong>3d.h" y<br />

"graf3d.h".Despues .debera inicializar un apuntador a una estructura tipo objeto.Enseguida debera inicializar el<br />

modo grafico mediante la llamada a la funcion Inicializa-Graficos".El apuntador al objeto declarado previam<strong>en</strong>te<br />

será regresado por la llamada a la función "g<strong>en</strong>era",ya t<strong>en</strong>i<strong>en</strong>do este ;apuntador se pasa éste para ser graficado<br />

mediante la funcion "Dibuja".Cuando el usuario decida debera liberar la memoria requerida por toda la estructura<br />

del Objebmediante la llamada a "Libera-Objeto".<br />

Un ejemplo para graficar un cilindro sería:<br />

#include "g<strong>en</strong>3d.h"<br />

#include "graf3d.h"<br />

struct objeto *mi-objeto;<br />

man(){<br />

clrscr();<br />

Inicializa-Graficos();<br />

mi objeto=g<strong>en</strong>era("u[0,2*Pi,2O~,v[0,2*Pi,20],50*~~~'~~),20*u,50*sin(v)");<br />

Dibuja(mi-objeto);<br />

getch0;<br />

Libera-Objeto(mi-objeto);<br />

closegraph();<br />

1


Introducci5n:<br />

BUFFER 2<br />

Todas los monitores pres<strong>en</strong>tan las imág<strong>en</strong>es mediante la composición de pequeños<br />

puntas de color que se <strong>en</strong>ci<strong>en</strong>d<strong>en</strong> y apagan <strong>en</strong> la pantalla; a estos puntos se !es conoc<strong>en</strong><br />

como pixeles y varían <strong>en</strong> numero dep<strong>en</strong>di<strong>en</strong>do de la resol.ución del monitor, a mayor<br />

numero de pixeles <strong>en</strong> la pantalla de un monitor, mayor será 1.a resolución de imág<strong>en</strong>es de<br />

este. Como ejemplo de resolución <strong>en</strong> monitores se ti<strong>en</strong><strong>en</strong>:<br />

320x 200<br />

640x 200<br />

@Ox 480<br />

8OOx 600<br />

1024x 764<br />

1024x1024<br />

Estas resoluciones indican e! numero de pixeles <strong>en</strong> línea horizontal contra el<br />

numero de pixeles <strong>en</strong> Xnea vertical con lo cual se puede definir un sistema de coord<strong>en</strong>adas<br />

{X,Y}. Suponi<strong>en</strong>do que el espacio tridim<strong>en</strong>sional esta formado por el sistema de<br />

coord<strong>en</strong>adas (X,Y,Z}, defini<strong>en</strong>do la profundidad como 2 :y haci<strong>en</strong>do coincidir X & Y del<br />

espacio tridim<strong>en</strong>sional con el X & Y de las coord<strong>en</strong>adas de la pantalla, <strong>en</strong>tonces, la<br />

visualización de objetos tridim<strong>en</strong>sionales <strong>en</strong> una pantalla de video será por ia proyección de<br />

los mismos <strong>en</strong> el plano (X,Y) al cual d<strong>en</strong>ominaremos como "Plano de Visión".<br />

El método del Buffer Z es un planteami<strong>en</strong>to de grafkación de imag<strong>en</strong> <strong>en</strong> espacio<br />

que utiliza un método común para detectar superficies visibles comparando las<br />

profundidades de cada superficie <strong>en</strong> cada una de las posiciones de pixel <strong>en</strong> la pantalla o<br />

plano de visión. La profundidad mínima o mas próxima de todos los planos que se<br />

proyectan sobre el la posición de pixel analizado es almac<strong>en</strong>ado <strong>en</strong> un arreglo rectangular<br />

de! igual numero de pixeles de la superficie de visión; es este arreglo !!amado el buffer de<br />

' profundidad o buffer z del cual deriva el nombre de! mt5todo. Es necesario <strong>en</strong>tonces<br />

procesar cada una de las superficies que forman los objetos <strong>en</strong> una esc<strong>en</strong>a.<br />

Procedimi<strong>en</strong>to:<br />

Las esc<strong>en</strong>as <strong>en</strong> la pantalla están formadas por los objetos que se grafican, los<br />

objetos están compuestos por superficies planas acotadas por los bordes del objeto. El<br />

procedimi<strong>en</strong>to apllcado <strong>en</strong> la graficación por Buffer Z consiste <strong>en</strong> reallzar un barrido sobre<br />

todos los puntos de pixel <strong>en</strong> !a pantaila realizando las operaciones necesarias para<br />

determinar si el pixel barrido esta cont<strong>en</strong>ido d<strong>en</strong>tro de l a proyección ortogonal de la<br />

superficie <strong>en</strong> !e plano de visión y <strong>en</strong> caso de estarlo determinar la profundidad de la<br />

superficie <strong>en</strong> ese punto de pixel y compararla con valores almac<strong>en</strong>ados de antemano <strong>en</strong> el<br />

buffer (es necesario <strong>en</strong>tonces que el buffer sea inicializado a. e! valor mas profundo de la<br />

esc<strong>en</strong>a) y reemplazar el valor del buffer con el valor determinado de la profundidad del<br />

plano si este equivale a un punto mas prcximo al plano de visión. Es requerido para este<br />

proceso contar tambiCn con un buffer de color de igual tamaño al buffer de profundidad<br />

para almac<strong>en</strong>ar el valor del color de cada punto de pixel de la pantalla (este buffer también<br />

deberá ser inicializado con e! color del fondo de la pantalla). .Al finalizar el proceso, el buffer<br />

Z cont<strong>en</strong>drá los puntos de profundidad visible para cada punto de pixel <strong>en</strong> el plano de<br />

visión mi<strong>en</strong>tras que el buffer de color cont<strong>en</strong>drá el valor del color de cada punto <strong>en</strong> el plano<br />

de visión.


El proceso de irnplem<strong>en</strong>tación de método Buffer Z es el sigui<strong>en</strong>te:<br />

a) G<strong>en</strong>erar los objetos mediante superficies (planos) con vértices coord<strong>en</strong>ados <strong>en</strong> el<br />

espacio tridim<strong>en</strong>sional {X,Y,Z). Cada objeto deberá cont<strong>en</strong>er la información de numero de<br />

vértices que compon<strong>en</strong> cada una de sus superficies, las coord<strong>en</strong>adas de cada vértice, las<br />

coord<strong>en</strong>adas del vector normal de la superficie, color primario del plano y color de la<br />

frontera de la superficie.<br />

b) Inicializar el buffer de profundidad al máximo valor de profundidad posible e inicializar el<br />

buffer de color al color del fondo.<br />

c) Suponi<strong>en</strong>do que la línea de rastreo barre los pixeles del plano de visión de izquierda a<br />

derecha y de arriba hacia abajo. Se puede ver esta línea de rasrreo como una recta<br />

horizontal sobre el plano {X,Y), es necesario para determinar (si exist<strong>en</strong>) los puntos de<br />

intersección de la línea de barrido con las líneas de los bordes de las proyecciones de l a s<br />

superficies para comprobar si cierto punto de pixel sobre la línea de rastreo esta cont<strong>en</strong>ida<br />

<strong>en</strong> la proyección de la superficie. Una manera s<strong>en</strong>cilla de determinar los puntos de<br />

interseccibn de la línea de rastreo con los bordes de las proyecciones de las superficies es<br />

mediante el uso de triángulos equival<strong>en</strong>tes; Si cada borde de la proyección es una recta<br />

que m es horizontal ni vertical y que se intersecta con la recta de la línea de rastreQ. es<br />

posible formar dos triingulos rectángulos equival<strong>en</strong>tes tomando como base de un triángulo<br />

la recta de la difer<strong>en</strong>cia <strong>en</strong> X de los extremos del borde y la recta del la línea de rastreo.<br />

dl En caso de que un punto de pixel sobre la línea de rasxeo se <strong>en</strong>cu<strong>en</strong>tre d<strong>en</strong>tro de !a<br />

proyección de una superficie se procede a calcular el ,valor de la profundidad de la<br />

superficie <strong>en</strong> ese punto utilizando para ello la ecuación del plano:<br />

Ax+By+Cz+D=O


9 cont<strong>en</strong>drá<br />

Supóngase que las coord<strong>en</strong>adas del vector normal de la superficie tratada son<br />

(nx,ny,nz) y que un punto de la superficie <strong>en</strong> el espació tridim<strong>en</strong>sional es (xl,yl,zl) se<br />

ti<strong>en</strong>e que:<br />

nx(x - XI) + ny(y - yl) + nz(z -. zl) = O<br />

m(x) + ny(y) + nz(z) + (-nx(xl)-ny(yl)-nz(zl)) = O<br />

A=M B = ny c=nz<br />

D = (-m(x1)-ny(yl)-nz(zl))<br />

Donde x & y serán las coord<strong>en</strong>adas del punto de pixel <strong>en</strong> la proyección de la superficie.<br />

e) Del valor de la profundidad del plano obt<strong>en</strong>ido <strong>en</strong> el punto (de pixel tratado se compara<br />

con el valor guardado de antemano <strong>en</strong> el buffer z. Si el nuevo valor es mas próximo al plano<br />

de visión, el valor almac<strong>en</strong>ado <strong>en</strong> el buffer z será reemplazado por este nuevo valor y <strong>en</strong> el<br />

buffer de color será almac<strong>en</strong>ado el color del punto de pixel que deberá t<strong>en</strong>er para ese punto<br />

de profundidad.<br />

f) repetir el procedimi<strong>en</strong>to desde el inciso (c) para cada una de las superficies que<br />

compon<strong>en</strong> la esc<strong>en</strong>a a graficar. AI finalizar el proceso con todas las superficies se ti<strong>en</strong>e<br />

almac<strong>en</strong>ado <strong>en</strong> el buffer z todos los puntos de visión de una esc<strong>en</strong>a y el buffer de color<br />

los colores de cada uno de los puntos de pixel de la esc<strong>en</strong>a.<br />

g) Buffer z requiere ser del mismo tamaño rectangular que el numero de puntos de pixel <strong>en</strong><br />

la pantalla !o que significa t<strong>en</strong>er la capacidad de memoria para. las operaciones, cantidad<br />

que aum<strong>en</strong>tara al aum<strong>en</strong>tar la resolución de las esc<strong>en</strong>as que se grafiqu<strong>en</strong>, por ejemplo:<br />

Para una resolución de 640x200 pixeles y suponi<strong>en</strong>do que se utilic<strong>en</strong> valores <strong>en</strong>teros de<br />

profundidad <strong>en</strong> el buffer z se requier<strong>en</strong> 640x200~2 =256 kbytes de memoria para realizar las<br />

operaciones mas 128 kbytes para el buffer de color suponi<strong>en</strong>do que tan solo se manej<strong>en</strong><br />

256 colores lo que suma un total de 384 kbytes de memoria necesaria para graficar la<br />

esc<strong>en</strong>a. Esto conlleva a limitaciones de memoria base disponible por lo que se requiere<br />

hacer uso de memoria ext<strong>en</strong>dida (si se dispone de ella) o bi<strong>en</strong> dividir la esc<strong>en</strong>a <strong>en</strong> v<strong>en</strong>tanas<br />

de m<strong>en</strong>or tamaño de<br />

v<strong>en</strong>tana por v<strong>en</strong>tana.<br />

tal manera que se pueda ajustar los buffers y realizar !a graficación


Librería Gráfica Buffer Z:<br />

Como parte del proyecto, se g<strong>en</strong>ero un archivo de librería para graficación por<br />

Buffer z d<strong>en</strong>ominado "GRAF-<strong>3D</strong>.H" el cual conti<strong>en</strong>e las funciones para la graficación de<br />

objetos tridim<strong>en</strong>sionales g<strong>en</strong>erados de antemano por otras librerías.<br />

Funciones para Usuario:<br />

void Graf<strong>3D</strong> (Objeto<strong>3D</strong> *ob) < graf-3d. > h<br />

Objetivo: Gráfica un objeto <strong>3D</strong> con el método de Buffer 2:. debido a los requerimi<strong>en</strong>tos de<br />

memoria del buffer z esta funcicin divide la esc<strong>en</strong>a <strong>en</strong> v<strong>en</strong>tanas de 160x120 puntos de pixel<br />

para 256 colores.<br />

Parámetros: (Objeto<strong>3D</strong> *ob) apuntador a la estructura de objetos que conti<strong>en</strong>e el apuntador<br />

a la lista de planos del objeto, el apuntador a la tabla de puntos del objeto y el numero de<br />

puntos <strong>en</strong> la tabla.<br />

retorna: ningún valor.<br />

Funciones Internas de la Libreria:<br />

void Algoritmo buffer z (Plano<strong>3D</strong> *ob,Punto2D r)<br />

void :Rango xy TPuntoTD *mn,PuntoZD *mx,Punto2D *ax,PuntoZD r.Plano<strong>3D</strong> *pg)<br />

void Inicializa-buffers (void)<br />

void -1nterseccion jint t,Plano<strong>3D</strong> *pg,Pint **pin,Punto2D r)<br />

int &ntosInt (int t,Punto2D p1,PuntoZD p2,char *bn)<br />

Punto<strong>3D</strong> Punto min (Plano<strong>3D</strong> *g)<br />

Punto<strong>3D</strong> IPuntoImax (Plano<strong>3D</strong> *g)


Codino Principal del archivo GRAF-<strong>3D</strong>.H:<br />

.............................................................. I<br />

/********** UNIVERSIDAD AUTONOMA METROPOLITANA ************* I<br />

/********** Unidad - lztapalapa ************* I<br />

.............................................................. I<br />

/'Proyecto terminal "GRAFICACION <strong>3D</strong>" (Trim: 96-1 & 96-P)*/<br />

/*Turbo C*/<br />

/*LIBRERIA GRAF-<strong>3D</strong>.H'/<br />

#include <br />

#ir,clude <br />

#include <br />

#define pi 3.141592<br />

#define K (1 7324.5)<br />

#define XP ((r.x)*160)<br />

#define YP ((r.y)*120)<br />

typedef struct { /'Estructura de dos dim<strong>en</strong>cione:j*/<br />

int x,y;<br />

} Punto2D;<br />

typedef ?unto2D Delta;<br />

struct intr {<br />

int p;<br />

char sec;<br />

struct, intr *sig;<br />

1;<br />

typedef intr Pint;<br />

void Graf<strong>3D</strong> (Objeto<strong>3D</strong> *ob);<br />

void -Algoritmo-buffer-z (Plano<strong>3D</strong> *ob,Punto2D r);<br />

float L;<br />

int BUFFER-Z[160][120];<br />

char BUFFER~COLOR[160][120];<br />

void Graf<strong>3D</strong> (Objeto<strong>3D</strong> *ob)<br />

{<br />

int tl ,t2,xx.yy;<br />

Punto2D tr;<br />

xx=getmaxx ()+I ;yy=getmaxy ()+l;<br />

L=xx/yy;<br />

xx=xx/160;yy=yyI120;<br />

for (t2=0;t2


*PROCEDIMIENTO BUFFER Z*/<br />

void -Algoritmo-buffer-z (Plano<strong>3D</strong> *ob,Punto2D<br />

{<br />

Plano<strong>3D</strong> *pg;<br />

Punto<strong>3D</strong> ptl;<br />

Punto2D mn,mx,cb;<br />

Pint *Inter,*d<strong>en</strong>;<br />

Delta ax;<br />

float A,B,C,D,sx,sy;<br />

int Z,tl ,tZ,xx,yy;<br />

char bnl ,bn2,cl;<br />

xx=getmaxx ();yy=getrnaxy ();<br />

r)<br />

setviewport (XP,YP,XP+159,YP+I 19,l); /*v<strong>en</strong>mtana de buffer*/<br />

- Inicializa-buffers ();<br />

pg =o b;<br />

if (ob==NULL) return:<br />

/*inicializa buffers*/<br />

for (;pg!=NULL;) { /*planos del objeto*/<br />

- Rango-xy (&mn,&mx,&ax,r,pg);<br />

if ((mn.xsec;<br />

if (tl ==d<strong>en</strong>->p) {<br />

bn2=1;<br />

Cl=pg->Cb;<br />

I<br />

if ((t2==ax.x)ll(t2==ax.y)) cl=pg->cb;<br />

d<strong>en</strong>=d<strong>en</strong>->sig;<br />

1<br />

if (bn2!=0) {<br />

if (pg->Normal.z!=O) {<br />

Sx=(tl-320+XP)/(K*L);<br />

sy=240-t2-YP;<br />

if (bnl ==O) { /*determina ecuacion del plano*/<br />

A=pg->Normal.x;<br />

B=pg->Normal.y;<br />

C=pg->Normal.z;<br />

D=(-A*(pg->pt[O]->~))+(-B*(pg->pt[O]->y))<br />

+(-C*(pg->pt[Dp"));<br />

bnl =I;<br />

1<br />

Z=(int)((-(A*sx)-(B*sy)-D)/C); /*determina punto <strong>en</strong> el plano*/<br />

/*else Z=Z-(A/C);*/<br />

if (BUFFER_Z[tl][t2]


d<strong>en</strong>=lnter;<br />

for (;d<strong>en</strong>!=NULL;) {<br />

Inter=d<strong>en</strong>->sig;<br />

free(d<strong>en</strong>);<br />

d<strong>en</strong>=lnter;<br />

/*libera puntos de interseccion*i<br />

I<br />

1 I<br />

pg=pg->liga;<br />

1<br />

/*sigui<strong>en</strong>te plano*/<br />

for (t2=0;t2x=(int)((K*L*rmin.x+318)-XP);<br />

mx->x=(int)((K*L*rmax.x+322)-XP);<br />

mn->y=(int)((240-rmax.y)-YP);<br />

mx->y=(int)((240-rmin.y)-YP);<br />

ax->x=mn->y;ax->y=mx->y;<br />

if ((mn->x)x=O;<br />

if ((mx->x)>l59) mx->x=l59;<br />

if ((mn->y)y=O;<br />

if ((mx->y)>ll9) mx->y=l19;<br />

' 1<br />

/*PROCEDIMIENTO PARA INICIALIZAR LOS BUFFERS*/<br />

void -Inicializa-buffers (void)<br />

{<br />

int i,j,k;<br />

for (i=O;ix;<br />

m.y=g->pt[Opy;<br />

m.z=g->pt[O]->z;<br />

for (i=l;iNum);i++) {


if (m.x>(g->pt[i]->x)) m.x=g->pt[i]->x;<br />

if (m.y>(g->pt[i]->y)) m.y=g->pt[i]->y;<br />

if (m.z>(g->pt[i]->z)) m.z=g->pt[i]->z;<br />

1<br />

return (m);<br />

1<br />

/*PROCEDIMIENTO PARA DETERMINAR COORDENADAS MAXIMAS DE UN PLANO*/<br />

Punto<strong>3D</strong> -Punto-max (Plano<strong>3D</strong> *g)<br />

{ int i;<br />

Punto<strong>3D</strong> m;<br />

if (g==NULL) return (m);<br />

m.x=g->pt[O]->x;<br />

m.y=g->pt[O]->y;<br />

m.z=g->pt[O]->z;<br />

for (i=l;iNun);¡++) {<br />

if (m.xpt[i]->x)) m.x=g->pt[i]->x;<br />

if (m.ypt[i]->y)) m.y=g->pt[i]->y;<br />

if (m.zpt[i]->z)) m.z=g->pt[i]->z;<br />

1<br />

return (m);<br />

1<br />

/*PROCEDIMIENTO PARA DEREMINAR PUNTOS DE INTERSECCION PLAN-SCANLINE*/<br />

void -1nterseccion (int t,Plano<strong>3D</strong> *pg,Pint **pin,Punto2D r)<br />

{<br />

Pint *ipl ,*ip2;<br />

Punto2D ptl ,pt2;<br />

char bn;<br />

int i,j,lnter;<br />

for (i=O;iNum;i++) {<br />

ptl .x=(int)((K*L*(pg->pt[i]->x)+320)-XP);<br />

ptl .y=(int)((240-(pg->pt[i]->y))-YP);<br />

pt2.~=(int)((K*L*(pg->pt[(i+l)%(pg->Num)]->x)+320)-XP);<br />

pt2.y=(int)((240-(pg->pt[(i+l)%(pg->Num)]->y))-YP);<br />

Inter=-Puntoslnt (t,ptl ,pt2,&bn);<br />

if (bn==O) {<br />

ipl =(Pint*)malloc(sizeof(Pint));<br />

if (ipl ==NULL) exit (O);<br />

ipl->p=lnter;<br />

ipl->sig=*pin;<br />

*pin=ipl;<br />

}<br />

1<br />

ipl =*pin;<br />

¡=I;<br />

for (;ipl!=NULL;) {<br />

ip2=ipl;<br />

for (;ip2!=NULL;) {<br />

if ((ipl->p)>(ip2->p)) {<br />

Inter=ipl ->p;<br />

ipl ->p=ip2->p;<br />

ip2->p=lnter;<br />

1<br />

ip2=ip2->sig;<br />

I


if (ipl ==*pin) j=ipl ->p:<br />

if (j==ipl->p) ¡=I;<br />

ipl->sec=i;<br />

i=(++i)%2:<br />

if (ipl->sig==NULL) ipl->sec=O;<br />

ipl =ipl->sig;<br />

I<br />

1<br />

/*PROCEDIMIENTO PARA CALCULO DE INTERSECCION DE RECTAS*/<br />

int -Puntoslnt (int t,Punto2D pl ,Punto2D p2,char *bn)<br />

{<br />

float Deter,A,B,a,b;<br />

int In;<br />

if (((t=p2.y))ll((t=pl .y))) {<br />

A=(float)((p2.~)-(pl .x));<br />

B=(float)((pl .y)-(p2.y));<br />

b=(float)(t-(p2.y));<br />

if @!=O) {<br />

a=(b*NB);<br />

In=(int)((p2.x)-a);<br />

*bn=O;<br />

I<br />

else {<br />

*bn=l :<br />

In=O;<br />

else {<br />

*bn=l ;<br />

In=O;<br />

}<br />

return (In);<br />

' 1


Administración de la memoria<br />

En la actualidad una computadora PC moderna esta equipada con al m<strong>en</strong>os 4 MBytes de memoria<br />

principal, habitualm<strong>en</strong>te con un tiempo de acceso de 70 ns o mejor. IBajo DOS sólo se pued<strong>en</strong> emplear 640<br />

KBytes de esta memoria <strong>en</strong> forma directa. Estos 640 KB pued<strong>en</strong> no ser sufici<strong>en</strong>tes para algún programa <strong>en</strong><br />

particular. por Io que resulta de especial interés el poder emplear el resto de la memoria.<br />

Memoria Ext<strong>en</strong>dida ( XMS )<br />

El estándar XMS fue desarrollado por las compañías Microsoft Lotus e Intel. En su creación también<br />

participo la empresa AST Research. Las funciones del XMS se poner! a disposición por un controlador XMS,<br />

que se coloca <strong>en</strong> el vector de interrupcrón 2Fh.<br />

Las funciones del controlador no se direcclonan mediante una interrupción, sino como Far Call. Para<br />

obt<strong>en</strong>er la dirección del controlador ha de comprobar primero si hay instalado un controlador XMS. Esto Io puede<br />

hacer llamando a la interrupción 2Fh con el valor 4300h <strong>en</strong> el registro AX. Si se devuelve el valor 80h <strong>en</strong> el<br />

registro AL, el controlador está instalado. En este caso la interrupción se ha de llamar de nuevo, con el valor<br />

4310h <strong>en</strong> el regrstro A X. Se obti<strong>en</strong>e la dirección del segm<strong>en</strong>to del controlador <strong>en</strong> el registro ES y la dirección del<br />

offset del XMM ( ext<strong>en</strong>ded Memory Manager ) <strong>en</strong> el registro BX.<br />

Cuando haya obt<strong>en</strong>ido la dirección del XMM, puede llamar a sus funciones mediante un Far Call. Si la<br />

función se pudo procesar con éxito, habitualm<strong>en</strong>te devuelve el código de estado O001 h <strong>en</strong> AX. En caso contrario<br />

el registro BL cont<strong>en</strong>drá un código de error. Los códigos de error ti<strong>en</strong>e el sigui<strong>en</strong>te significado:<br />

80<br />

81<br />

82<br />

8E<br />

8F<br />

90<br />

91<br />

92<br />

93<br />

94<br />

A0<br />

AI<br />

A2<br />

A3<br />

A4<br />

A5<br />

A6<br />

A7<br />

A8<br />

A9<br />

AA<br />

AB<br />

AC<br />

AD<br />

BO<br />

B1<br />

B2<br />

Función Desconocida<br />

VDISK-Ramdisk <strong>en</strong>contrado<br />

Error <strong>en</strong> la linea de direcciones A20<br />

Error g<strong>en</strong>eral de controlador<br />

Error irrecuperable<br />

HMA no pres<strong>en</strong>te<br />

HMA ya asignado<br />

Tamaño especificado de DX demasiado pequeño<br />

HMA no alojada<br />

Linea de direcciones A20 aún activa<br />

No queda XMS disponible<br />

Todos los handles XMS ocupados<br />

Handle no válido<br />

Handle fu<strong>en</strong>te no válido<br />

Offset fu<strong>en</strong>te no válido<br />

Handle destino no válido<br />

Offset destino no válido<br />

Longitud incorrecta para función MO\. *.<br />

Solapado incorrecto <strong>en</strong> función MOVE<br />

Parity-Error<br />

UMB no bloqueado<br />

UMB aún bloqueado<br />

Rebase del controlador de bloqueo UMB<br />

UMB no se puede bloquear<br />

UMB disponible es más pequeño<br />

No hay UMB disponible<br />

Dirección del segm<strong>en</strong>to UMB incorrecta


La programación XMS<br />

El número de función de la funciones del XMM se pasa siempre <strong>en</strong> el registro AH. A continuación se listan<br />

algunas de las funciones básicas que ofrece el XMM.<br />

FunciónOOh Obt<strong>en</strong>er número de versión<br />

Entrada AH = OOh<br />

Salida AX = numero de versión XMS<br />

BX = numero de revisión interno<br />

DX = Estado de la HMA<br />

Con esta función puede averiguar el número de versión del controlador. si <strong>en</strong> el estado HMA se <strong>en</strong>cu<strong>en</strong>tra<br />

el valor 1, la HMA está disponible, de lo contrario no se permite el acceso a la misma.<br />

Función03h Activar A20 globalm<strong>en</strong>te<br />

Entrada AH = 03h<br />

Salida BL = código de error<br />

Si quiere emplear la HMA <strong>en</strong> el modo real de forma fiable, ha de llamar esta función antes o después de<br />

la petición de la HMA. Recuerde cerrar la linea de direcciones antles de finalizar su programa, para evitar<br />

rebases de segm<strong>en</strong>to <strong>en</strong> los programas subsigui<strong>en</strong>tes.<br />

Función04h Cerrar A20 globalm<strong>en</strong>te<br />

Entrada AH = 04h<br />

Salida BL = código de error<br />

FunciÓnOSh Activar A20 localm<strong>en</strong>te<br />

Entrada AH = 05h<br />

Salida BL = código de error<br />

Mkdiante esta función de activa la línea de direcciones A20. Es' decir que sólo se activa si la función no<br />

habia sido llamada con anterioridad. Esta comprobación se realiza mlediante un contador de llamadas, que es<br />

increm<strong>en</strong>tado por la función 05h y decrem<strong>en</strong>tado por la función 06h.<br />

FunciÓnOGh Desactivar A20 localm<strong>en</strong>te<br />

Entrada AH = 06h<br />

Salida BL = código de error<br />

Función07h Obt<strong>en</strong>er estado de A20<br />

Entrada AH = 07h<br />

Salida AX = estado de la linea de direcciones<br />

BL = código de error<br />

Si A20 está libre, obti<strong>en</strong>e el valor O001 h <strong>en</strong> A X , de 10 contrario será 0000h.<br />

Función08h Obt<strong>en</strong>er XMS libre<br />

Entrada AH = 08h<br />

Salida AX = longitud del mayor bloque libre<br />

DX = tamaño total del XMS <strong>en</strong> KBytes<br />

BL = código de error<br />

Con esta función puede averiguar la memoria XMS libre. Pero at<strong>en</strong>ción, los valores devueltos siempre<br />

mld<strong>en</strong> 64 KBytes de más, ya que tamblén se cu<strong>en</strong>ta la HMA, que tambi<strong>en</strong> mide 64 KBytes.


FunciÓnOSh Alojar bloque <strong>en</strong> la memoria ext<strong>en</strong>dida<br />

Entrada AH = 09h<br />

DX = Tamaño del bloque <strong>en</strong> KBytes<br />

Salida DX = Handle para el acceso al bloque<br />

BL = código de error<br />

Esta función reserva un bloque de memoria ext<strong>en</strong>dida ( EMB ). El alojami<strong>en</strong>to sólo funciona si aún queda<br />

libre un bloque del tamaño sufici<strong>en</strong>te <strong>en</strong> la XMS. El bloque ocupado se puede direccionar a través del Handle<br />

devueito.<br />

FunciónOAh Liberar bloque de memoria ext<strong>en</strong>dida<br />

Entrada AH = OAh DX = Handle para el acceso al bloque<br />

Salida BL = código de error<br />

Mediante esta función vuelve a liberar un EMB alojado. Después de la llamada el Handle queda como no<br />

válido, y los datos están perman<strong>en</strong>tem<strong>en</strong>te borrados.<br />

FunciónOBh Copiar memoria<br />

Entrada AH = OBh<br />

DS = Segm<strong>en</strong>to de la estructura de copia<br />

SI = Offset de la estructura de copia<br />

Salida BL = código de error<br />

Con esta función puede copiar memoria a/de la XMS. Ya que los registros no son sufici<strong>en</strong>tes para guardar<br />

todos los datos, la func 5n emplea una estructura de copia. La estructura ti<strong>en</strong>e la sigui<strong>en</strong>te forma:<br />

Offset Función Tipo de datos<br />

OOh Longitud del bloque a copiar 1 Dword<br />

04h Handle bloque del fu<strong>en</strong>te 1 Word<br />

36h Offset el <strong>en</strong> bloque fu<strong>en</strong>te 1 Dword<br />

OAh Handle del bloque destino 1 Word<br />

OCh Offset <strong>en</strong> el bloque destino 1 Dword<br />

Cuando se pres<strong>en</strong>ta el solapado de las zonas, la zona fu<strong>en</strong>te ha de estar antes de la zona destino, sino no<br />

se garantiza un funcionami<strong>en</strong>to perfecto. Para permitir una copia rápida, debería com<strong>en</strong>zar sus zonas de<br />

memoria <strong>en</strong> una dirección divisible <strong>en</strong>tre cuatro.<br />

FunciónOCh Bloquear EMB contra desplazami<strong>en</strong>to<br />

Entrada AH = OCh<br />

DX = Handle<br />

Salida DX:BX = Dirección lineal de 32 bits<br />

BL = código de error<br />

Para que no se cre<strong>en</strong> agujeros <strong>en</strong> la XMS, el XMM, si es necesario, desplaza algunos bloques de<br />

memoria. Para asegurar un bloque contra el desplazami<strong>en</strong>to, Io que puede ser interesante SI se quiere acceder<br />

directam<strong>en</strong>te a la memoria, se emplea esta función. Como resultado st?. obti<strong>en</strong>e <strong>en</strong> DX:BX la dirección lineal bajo<br />

la cual puede direccionar la memoria.<br />

FunciónODh Desbloquear EMB asegurado<br />

Entrada AH = ODh<br />

DX = Handle<br />

Salida BL = código de error


FunciónOEh Obt<strong>en</strong>er información sobre el EMB<br />

Entrada AH = OEh<br />

DX = Handle<br />

Salida DX = Longitud del bloque<br />

Mediante estas funciones se pued<strong>en</strong> obt<strong>en</strong>er tanto informaciones sobre el bloque de memoria, como<br />

determinar el número de handles XMS libres. Si la función ha trabajada sin errores, <strong>en</strong> AX se puede <strong>en</strong>contrar el<br />

valor 0001h. En este caso se <strong>en</strong>cu<strong>en</strong>tra <strong>en</strong> BH el contador de bloqueo del EMB. El contador se increm<strong>en</strong>ta con<br />

cada llamada a la función OCh y se decrem<strong>en</strong>ta con cada llamada a la función ODh. Si el valor de BH es mayor<br />

de O, ha de llamar a la función ODh BH veces, para liberar el bloque. En BL se <strong>en</strong>cu<strong>en</strong>tra la cantidad de handles<br />

XMS libres. T<strong>en</strong>ga <strong>en</strong> cu<strong>en</strong>ta que es mejor ocupar bloques de memoria lo más grande posibles, ya que el<br />

número de handles es limitado.<br />

FunciónOFh Modificar tamaño del EMB<br />

Entrada AH = OFh<br />

BX = Nuevo tamaño del EMB<br />

DX = Handle<br />

Salida BL = código de error


Utilización de las rutinas XMM.H<br />

El archivo XMM.H conti<strong>en</strong>e la declaración de una clase llamada vfp (very far pointer) por medio del cual se<br />

t<strong>en</strong>drá acceso a la memoria ext<strong>en</strong>dida, esta clase repres<strong>en</strong>ta un tipo de dato puntero a memoria ext<strong>en</strong>dida.<br />

Declarando objetos de esta clase el usuario puede almac<strong>en</strong>ar sus datos <strong>en</strong> la XMS. Las funciones miembro de<br />

esta clase son algunas de las m<strong>en</strong>cionadas anteriorm<strong>en</strong>te, como por ejemplo, verificar la exist<strong>en</strong>cia de un<br />

controlador XMM, reservar memoria ext<strong>en</strong>dida, liberar memoria ext<strong>en</strong>dida, copiar de memoria conv<strong>en</strong>cional a<br />

ext<strong>en</strong>dida, de XMS a memoria conv<strong>en</strong>cional, etc.<br />

Estas rutinas se podrán compilar y g<strong>en</strong>erar código ejecutable utilizando un compilador C++ que cont<strong>en</strong>ga<br />

el uso de 'templates', por ejemplo "Borland C++ 3.0" o superior. A continuación se muestra la manera de<br />

declarar un objeto vfp, asignar valores, leer valores, etc.<br />

Declaración de objetos vfp<br />

#include "XMM.H"<br />

Declaración de un solo elem<strong>en</strong>to<br />

Declarar un solo elem<strong>en</strong>to vfp se logra con la sigui<strong>en</strong>te sintaxis:<br />

vfp nombre-del-puntero;<br />

donde Tipo-de-dato se refiere a un tipo de dato predefinido $ 0 bi<strong>en</strong> a un tipo de dato definido por el<br />

usuario, y nombre-del-puntero es la variable con la cual se puede hacer refer<strong>en</strong>cia al dato que se guarda <strong>en</strong><br />

memoria ext<strong>en</strong>dida.<br />

Por ejemplo el segm<strong>en</strong>to de programa sigui<strong>en</strong>te declara un <strong>en</strong>tero apuntado por puntero-a-<strong>en</strong>tero, y una<br />

estructura de tipo punto apuntada por puntero-a-mi-estructura, ambos datos el <strong>en</strong>tero y la estructura se<br />

guardaran <strong>en</strong> memoria ext<strong>en</strong>dida:<br />

#include "XMh1.H"<br />

typedef struct {<br />

int x;<br />

int y;<br />

int z;<br />

} punto;<br />

void main()<br />

{<br />

vfp puntero-a-<strong>en</strong>tero;<br />

vfp puntero-a-mi-estructura;<br />

...<br />

1<br />

La manera de referirnos a este elem<strong>en</strong>to es por medio del nombre del puntero vfp, por ejemplo:<br />

puntero-a-<strong>en</strong>tero = 10;


Asigna el número 10 al elem<strong>en</strong>to de tipo <strong>en</strong>tero apuntado por puntero-a-<strong>en</strong>tero. Otra manera de guardar<br />

este dato es con la sigui<strong>en</strong>te Instrucclón:<br />

puntero-a-<strong>en</strong>tero[O] = 1 O;<br />

Dado que puntero-a-<strong>en</strong>tero apunta a un solo elem<strong>en</strong>to de tipo int, es como si se tratara de un arreglo<br />

lineal de una casilla, por lo cual sus indices permitidos van de [O - (numero-de-casillas - I)], <strong>en</strong> este caso el<br />

indice [O] es válido ya que es el indice inicial y también final del arreglo de 1 casilla. Si se hiciera refer<strong>en</strong>cia al<br />

indice [I], esto provocaría un error.<br />

Declaración de arreglo lineales<br />

Para indicar al compilador que deseamos un arreglo lineal de elem<strong>en</strong>to de tipo Tipo-de-dato, utilizamos<br />

parén<strong>tesis</strong> seguido del nombre-del-puntero con la sigui<strong>en</strong>te sintaxis:<br />

vfp nombre-del-puntero(cuantos)<br />

En este caso cuantos indica al compilador la cantidad de elem<strong>en</strong>tos de tipo Tipo-de-dato que se<br />

guardarán <strong>en</strong> XMS y serán refer<strong>en</strong>ciados por nombre-de-puntero. Por ejemplo<br />

#include "XMM.H"<br />

typedef struct {<br />

char nombre[30];<br />

char dirección[50];<br />

} registro;<br />

void main()<br />

{<br />

vfp arreglo( 1000); // Arreglo de 1 O00 float's<br />

vfp datos(300); //Arreglo de 300 registros<br />

Hacemos una refer<strong>en</strong>cia a un elem<strong>en</strong>to <strong>en</strong> particular del arreglo por medio de los indices <strong>en</strong>cerrados <strong>en</strong>tre<br />

corchetes [I, por ejemplo:<br />

arreglo[ 1001 = 12345.6789;<br />

Guarda <strong>en</strong> la localidad 100 el número 12345 6789. Recordemos que <strong>en</strong> este caso los indices válidos van<br />

de [O-9991, por Io que la sigui<strong>en</strong>te instrucción causaria un error:<br />

arreglo[1000] = 12345.6789; /I Error no hay casilla 1000


Declaración de arreqlos bidim<strong>en</strong>sionales ( matrices)<br />

vfp nombre_de_puntero(num-de-columnas,num_de-r<strong>en</strong>glones)~<br />

donde num-de-columnas es <strong>en</strong> numero de columnas de la matriz, y num-de-r<strong>en</strong>glones es el numero de<br />

r<strong>en</strong>glones.<br />

Por ejemplo:<br />

#include "XMM.H"<br />

void main()<br />

{ vfp VIDEO_VGA(640,480); // Matriz de <strong>en</strong>teros de 640 x 480<br />

vfp b( 1000,2000); // Matriz de float's de 1 O00 x 2000<br />

...<br />

1<br />

Para accesar alguna de las casillas de la matriz debemos especificar la columna y el r<strong>en</strong>glón <strong>en</strong>tre<br />

parén<strong>tesis</strong>, esto seguido del nombre-del-puntero, por ejemplo:<br />

a(10,15) = 33;<br />

guarda el número 33 <strong>en</strong> la casilla ubicada <strong>en</strong> la columna 10 y <strong>en</strong> el r<strong>en</strong>glón 15. Para el caso de la matriz<br />

'VIDEO-VGA los indices permitidos son [O-6391 y de [O4791 para las columnas y los r<strong>en</strong>glones<br />

respectivam<strong>en</strong>te.<br />

Operaciones permitidas sobre punteros vfp<br />

Dadas las sigui<strong>en</strong>tes declaraciones de punteros vfp:<br />

(a) vfp mi-char;<br />

(b) vfp mi-arreglo-de-chars(4);<br />

(c) vfp mi-matriz-de-chars(3,3)<br />

En el caso de un solo elem<strong>en</strong>to no ti<strong>en</strong>e s<strong>en</strong>tido increm<strong>en</strong>tar o decrem<strong>en</strong>tar el puntero. pero <strong>en</strong> los otros<br />

dos casos es posible no solo increm<strong>en</strong>tar o decrem<strong>en</strong>tar al puntero vfp sino que también es posible sumar y<br />

restar cierto desplazami<strong>en</strong>to al puntero a la colección de datos. Las sigui<strong>en</strong>tes instrucciones son válidas:<br />

mi-arreglo-de-chars++;<br />

++mi-arreglo-de-chars;<br />

mi-arreglo-de-chars + 1 O;<br />

mi-matriz-de-chars--;<br />

--mi-matriz-de-chars;<br />

mi-matriz-de-chars - 2;<br />

Fixordemos que los indices para un arreglo lineal de 10 elem<strong>en</strong>to por ejemplo, van de O - 9, por lo que<br />

una refer<strong>en</strong>cia al 10 elem<strong>en</strong>to causará un error que det<strong>en</strong>drá el programa y <strong>en</strong>viara un m<strong>en</strong>saje indicando el tipo<br />

de error.


La función miembro actual() de la clase vfp<br />

En la declaración de la clase vfp se ha incluido una función miembro llamada actual(), esta función se<br />

emplea especialm<strong>en</strong>te <strong>en</strong> la lectura de elem<strong>en</strong>tos apuntados por objetos vfp. Esta función es útil cuando<br />

desconocemos el índice del arreglo <strong>en</strong> memoria o de la matriz utilizada, esto pudiera ocurrir después de emplear<br />

las operadores ++ o -- por Io que el programador pudiera perder el índilce 'actual'. A continuación se muestra el<br />

uso de esta función:<br />

#include "XMM.H"<br />

typedef struct {<br />

int Re;<br />

int Im;<br />

} complejo;<br />

void main()<br />

c<br />

int real, imaginaria;<br />

vfp a( 100); /I Arreglo de 100 números complejos<br />

a.malloc-vfp();<br />

a++;<br />

a + 33;<br />

++a;<br />

a - 12;<br />

I/ Reservamos memoria<br />

real = a.actual().Re; I/ Parte real del incide actual<br />

Imaginaria = a.actual().lm; // Pzrte imaginaria del índice actual<br />

a.free-vfp();<br />

...<br />

}<br />

I/ Liberamos memoria<br />

Observe como al punteo 'a' ha sido afectado por operaciones de increm<strong>en</strong>to y adición, por lo que resulta<br />

ittil tomar el cont<strong>en</strong>ido del índice actual sin importar cual sea éste.


A continuación se pres<strong>en</strong>ta el listado completo del archivo XMM.H:<br />

Proyecto <strong>en</strong> la ing<strong>en</strong>ieria Electronica II<br />

Asesor: M. <strong>en</strong> C. Miguel Angel Pizaña Lopez<br />

Alumno: Carlos Arias M<strong>en</strong>doza<br />

* ******* Librerias para el uso de memoria ext<strong>en</strong>dida **"****<br />

I**********U**************~~****H***** I<br />

#include <br />

#include <br />

#include


static struct copia {<br />

unsigned long size;<br />

unsigned int Handle-Fu<strong>en</strong>te:<br />

unsigned long Offset-Fu<strong>en</strong>te;<br />

unsigned int Handle-Destino;<br />

unsigned long Offset-Destino;<br />

} x;<br />

/**************t*************************************************************<br />

.............................................................................<br />

template <br />

class vfp<br />

{<br />

public:<br />

VfPO;<br />

vfp(unsigned int valor);<br />

vfp(unsigned int r<strong>en</strong>glon,unsigned int columna);<br />

vfpcT> operator=(T info);<br />

T& operator=(vfp);<br />

vfp operator++(int);<br />

vfp operator++();<br />

vfp operator--(kt);<br />

vfpcT> operator--();<br />

vfpcT> operator+(unsigned int increm<strong>en</strong>to);<br />

vfp operator-(unsigned int decrem<strong>en</strong>to);<br />

T& operator[](unsigned int finger):<br />

T& operator()(unsigned int r<strong>en</strong>glon,unsigned int columna);<br />

T& actual();<br />

unsigned int XPAS-Libre();<br />

unsigned int malloc-vfp();<br />

void free-vfpo;<br />

void Error(unsigned char code):<br />

private:<br />

unsigned int Check-for-XMS();<br />

void (far *X")();<br />

T *buffer;<br />

unsigned int Pres<strong>en</strong>te-XMM;<br />

unsigned int XMS-handle;<br />

unsigned int indice;<br />

unsigned int buffer-size;<br />

unsigned int size-of-type;<br />

unsigned int indice-izq;<br />

unsigned int indice-der;<br />

unsigned int num-r<strong>en</strong>glones;<br />

unsigned int num-columnas;<br />

unsigned int ext<strong>en</strong>d-izq;<br />

unsigned int ext<strong>en</strong>d-der;<br />

unsigned long limite;<br />

unsigned long size-of-block;<br />

1; .............................................................................<br />

I<br />

/<br />

I


..............................................................................<br />

I<br />

template vfp.:vfp()<br />

{<br />

if ( Check-for-XMS() )<br />

Pres<strong>en</strong>te-XMM = 1;<br />

size-of-type = sizeof(T);<br />

size-of-block = 1:<br />

buffer-size = buffer-tamkize-of-type;<br />

indice = O;<br />

indice-izq = O;<br />

indice-der = buffer-size - 1;<br />

ext<strong>en</strong>d-izq = 1:<br />

ext<strong>en</strong>d-der = buffer-tam;<br />

limite = O;<br />

buffer = (T *)calloc(buffer-size,size-of-type);<br />

I<br />

..............................................................................<br />

I<br />

..............................................................................<br />

I<br />

template vfp::vfp(unsigned int valor)<br />

{<br />

if ( Check-for-XMS() )<br />

Pres<strong>en</strong>te-XMM = 1;<br />

size-of-type = sizeof(T);<br />

size-of-block = valor;<br />

buffer-size = buffer-tamlsize-of-type;<br />

indice = O:<br />

indice-izq = O;<br />

indice-der = buffer-size - 1;<br />

ext<strong>en</strong>d-izq = 1;<br />

ext<strong>en</strong>d-der = buffer-tam;<br />

limite = valor - 1;<br />

buffer = (T *)calloc(buffer-size,size-of-type);<br />

Y<br />

................................................................................. I<br />

..............................................................................<br />

I<br />

template vfp::vfp(unsigned int r<strong>en</strong>glon,unsigned int columna)<br />

{<br />

if ( Check-for-XMS() )<br />

Pres<strong>en</strong>te-XMM = 1;<br />

size-of-type = sizeof(T);<br />

size-of-block = r<strong>en</strong>glon*columna;<br />

buffer-size = buffer-tam/size-of-type;<br />

indice = O;<br />

indice-izq = O;<br />

indice-der = buffer-size - 1;<br />

num-r<strong>en</strong>glones = r<strong>en</strong>glon;<br />

num-columnas = columna;<br />

ext<strong>en</strong>d-izq = 1;<br />

ext<strong>en</strong>d-der = buffer-tam;<br />

limite = (r<strong>en</strong>glon * columna) - 1;<br />

buffer = (T *)calloc(buffer-size,size-of-type);<br />

1<br />

.............................................................................<br />

I


template vfp vfp::operator=(T info)<br />

{<br />

buffer[indice] = info;<br />

return(*this);<br />

I<br />

.............................................................................<br />

.............................................................................<br />

template T& vfp::actual()<br />

{<br />

return(buffer[indice]);<br />

I<br />

.............................................................................<br />

template vfp vfp::operator++(int)<br />

{<br />

int new-index;<br />

new-index = indice;<br />

new-index++;<br />

if ( new-index = O )<br />

indice--;<br />

else<br />

Error(Ox71);<br />

return(*this);<br />

.............................................................................<br />

I<br />

I<br />

I<br />

I


eturn(*this);<br />

template vfp vfp::operator+(unslgned int increm<strong>en</strong>to)<br />

{<br />

int new-index;<br />

new-index = indice + increm<strong>en</strong>to;<br />

if ( new-index = O )<br />

indice = new-index;<br />

else<br />

Error(Ox71);<br />

return(*this);<br />

}<br />

.............................................................................<br />

I<br />

.............................................................................<br />

I<br />

template T& vfp::operator[](unsigned int finger)<br />

{<br />

unsigned int indice-temporal;<br />

indice-temporal = finger:<br />

indice-temporal %= buffer-size ;<br />

if ( finger > limite )<br />

Error(Ox71);<br />

if ( finger >= Indice-izq && finger


indice-temporal *= buffer-size;<br />

indice-izq = indice-temporal;<br />

indice-der = indice-izq + buffer-size - 1 ;<br />

copy-XMS-to-RAM(XMM, 1024.buffer,XMS-handle,ext<strong>en</strong>d-1zc~);<br />

1<br />

return(buffer[indice-temporal]);<br />

I<br />

.............................................................................<br />

I<br />

.............................................................................<br />

I<br />

template = num-r<strong>en</strong>glones )<br />

Error(Ox72);<br />

if ( columna >= num-columnas )<br />

Error(Ox73);<br />

finger = indice-temporal = r<strong>en</strong>g1on*num~co1umnas + columna;<br />

if ( finger > limite )<br />

Error(Ox71);<br />

indice-temporal %= buffer-size ;<br />

if ( finger >= indice-izq && finger


mascara = reg.r-es;<br />

mascara = mascara


if ( Pres<strong>en</strong>te-XMM )<br />

{<br />

tipo = size-of-type:<br />

bloque = size-of-block;<br />

bytes = tipo * bloque;<br />

if ( bytes ::free-vfp()<br />

I ’<br />

unsigned char code;<br />

unsigned int code-error;<br />

unsigned int result;<br />

- AX = OxOA00;<br />

- DX = XMS-handle;<br />

(*XMM)O;<br />

result = - A X ;<br />

code-error = -BX;<br />

if ( result == 1 )<br />

return:<br />

else<br />

{ code = (unsigned char)code-error;<br />

Error(code);<br />

I<br />

1<br />

............................................................................. I<br />

I


.............................................................................<br />

I<br />

template void vfp.:Error(unsigned char code)<br />

{<br />

switch(code)<br />

{<br />

case 0x70 : printf(error-70h);break;<br />

case 0x71 : printf(error-71 h);break;<br />

case 0x72 : printf(error-72h);break;<br />

case 0x73 : printf(error-73h);break;<br />

case 0x80 : printf(error-80h);break;<br />

case 0x81 : printf(error-81 h);break;<br />

case 0x82 : printf(error-82h);break;<br />

case Ox8E : printf(error-8Eh);break;<br />

case Ox8F : printf(error-8Fh);break;<br />

case Ox90 : printf(error-90h);break;<br />

case Ox91 : printf(error-91 h);break;<br />

case 0x92 : printf(error_92h),break;<br />

case 0x93 : prmtf(error-93h);break;<br />

case 0x94 : printf(error-94h);break;<br />

case OxAO : printf(error-A0h);break;<br />

case OxAl : printf(error-Al h);break;<br />

case OxA2 : printf(error-A2h);break;<br />

case OxA3 : printf(error-A3h);break;<br />

case OxA4 : printf(error-A4h);break;<br />

case OxA5 : printf(error-A5h);break;<br />

case OxA6 : printf(error-A6h);break;<br />

case OxA7.: ~rintf(error~A7h);break;<br />

case OxA8 : printf(error-A8h);break;<br />

case OxA9 : printf(error-Agh);break;<br />

case OxAA : printf(error-AAh);break;<br />

case OxAB : printf(error-ABh);break;<br />

case OxAC : printf(error-ACh);break;<br />

case OxAD : printf(error-ADh);break;<br />

case OxBO : printf(error-B0h);break;<br />

case OxBl : printfferror-B1 h);break;<br />

case OxB2 1 printf(error-B2h):break;<br />

I<br />

exit(0);<br />

1<br />

.............................................................................<br />

I<br />

...............................................................................<br />

I<br />

unsigned int copy-RAM-to-XMS(void (far *ptr)(),unsigned long bytes,void far<br />

*fu<strong>en</strong>te - offset,unsigned int handle,unsigned long desplazami<strong>en</strong>to)<br />

{<br />

unsigned char code;<br />

unsigned int code-error;<br />

unsigned int result;<br />

void (far *manejador-X")();<br />

manejador-XMM = ptr;<br />

X.size = bytes;<br />

X.Handle-Fu<strong>en</strong>te = O; I* O = RAM *I<br />

X.Offset-Fu<strong>en</strong>te = (unsigned 1ong)fu<strong>en</strong>te-offset;<br />

X.Handle-Destino = handle;<br />

X.Offset-Destino = desplazami<strong>en</strong>to;


- SI = FP-OFF(&X);<br />

- DS = FP-SEG(&X);<br />

- AX = OxOBOO;<br />

(*rnanejador"XMM)();<br />

result = - A X ;<br />

code-error = -BX;<br />

if ( result == 1 )<br />

return( 1);<br />

else<br />

{<br />

code = (unsigned char)code-error;<br />

cprintf('lr\n\a Error! (%X) No se pudo realizar la copia de RAM a XMS ...", code);<br />

1<br />

return(0);<br />

1 ............................................................................. I<br />

............................................................................. I<br />

unsigned int copy-XMS-to-RAM(void (far *ptr)(),unsigned long bytes,void far<br />

*fu<strong>en</strong>te-offset,unsigned int handle,unsigned long desplazami<strong>en</strong>to)<br />

{<br />

unsigned char code;<br />

unsigned int code-error;<br />

unsigned int result;<br />

void (far *manejador-X")();<br />

qanejador-XMM = ptr;<br />

X.size = bytes;<br />

X.Handle-Fu<strong>en</strong>te = handle;<br />

X.Offset-Fu<strong>en</strong>te = desplazami<strong>en</strong>to;<br />

X.Handlz-Destino = O; I* O RAM *I<br />

X.Offset-Destino = (unsigned 1ong)fu<strong>en</strong>te-offset;<br />

- SI = FP-OFF(&X);<br />

- DS = FP-SEG(&X);<br />

- AX = OxOB00;<br />

(*manejador-X")();<br />

result = - A X ;<br />

code-error = -BX;<br />

if ( result == 1 )<br />

{<br />

return(1);<br />

I<br />

else<br />

{<br />

code = (unsigned char)code-error;<br />

cprintf("\r\n\a Error! (%X) No se pudo realizar la copia de XMS a RAM...",code);<br />

1<br />

return(0);<br />

I


Bibliografia<br />

Borland C++ Handbook<br />

Chris H. Pappas &William H. Murray Ill<br />

Editorial McGraw Hill<br />

Graficas por Computadora<br />

Segunda Edición<br />

Donald Hearn & M. Pauline Baker<br />

Editorial Pr<strong>en</strong>tice Hall<br />

Gráficos Animados por Computadora<br />

David Fox & Mitchell Waite<br />

Editorial McGraw Hill

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!