tesis_uam/Graficacion en 3D_UAM1969.pdf - cedip
tesis_uam/Graficacion en 3D_UAM1969.pdf - cedip
tesis_uam/Graficacion en 3D_UAM1969.pdf - cedip
¡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