Sign in Join
Wiki copytemporary

OpenGL Tutorial/es: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11OpenGL es el principal entorno para el diseño de aplicaciones 2D y 3D portables. Desde su introducción en 1992, OpenGL ha llegado a ser la interfaz de programación de aplicaciones (API) gráficas 2D y 3D más ampliamente utilizadao en la industria, aportando miles de aplicaciones a una gran variedad de plataformas de computación. OpenGL promueve la innovación y acelera el diseño de aplicaciones mediante la incorporación de un amplio conjunto de acabados, aplicACIÓN de texturas, efectos especiales y otras potentes funciones de visualización. Los desarrolladores pueden llevar la potencia de OpenGL a través de todos los escritorios más extendidos y plataformas de estaciones de trabajo, asegurando un amplio desarrollo de aplicaciones.
22
33   Puedes encontrar más información acerca de OpenGL [aquí](http://www.opengl.org/about/overview/).
44
55# GLUT
66
77   GLUT es el conjunto de utilidades OpenGL, un conjunto de utilidades de ventana independiente para escribir programas OpenGL. Implementa una interfaz gráfica simple de programación de aplicaciones (API) para OpenGL. GLUT hace que sea considerablemente más fácil de aprender y explorar la programación con OpenGL aportando una API portable de forma que permite escribir un programa que funcionará en todos los PC y estaciones de trabajo en las diferentes plataformas existentes.
88
99   Se puede encontrar más información acerca de GLUT [aquí](http://www.opengl.org/resources/libraries/glut/).
1010
1111   Algunos Sistemas Operativos llevan preinstalado GLUT, pero en el caso de que no sea así se puede encontrar fácilmente utilizando [Google](http://www.google.com/).
1212
1313   Los binarios para Windows se pueden descargar desde [www.xmission.com](http://www.xmission.com/~nate/glut.html).
1414
1515   La información de las unidades de FPC para GLUT se encuentran aquí [[OpenGL]].
1616
1717# LCL
1818
1919   La librería de componente de Lazarus también se puede utilizar con OpenGL. Lazarus incluye un control "TOpenGLControl" - un control LCL con un contexto OpenGL. Se puede encontrar el paquete LazOpenGLContext en lazarus/components/opengl/lazopenglcontext.lpk. Además podemos encontrar un ejemplo en lazarus/examples/openglcontrol/openglcontrol_demo.lpi.
2020
2121# LCL / GLUT
2222
2323   ¿Cuando utilizar GLUT, y cuando LCL?
2424
2525- GLUT es mejor si deseas dibujar todo tu mismo.
2626- LCL es mejor para las aplicaciones habituales. Por ejemplo un editor 3D necesita una pocas ventanas OpenGL y el resto es una aplicación normal utilizando botones, cajas de edición, ventanas, ventanas modales, etc.
2727
2828   La parte OpenGL es otro tanto de lo mismo. GLUT necesita una dll en windows, mientras la LCL no requiere ninguna, pero el ejecutable LCL es bastante más grande.
2929
3030# Creando tu primer programa GLUT
3131
3232   Para utilizar GLUT, primero hay que iniciarlo. Esto se hace utilizando la función **glutInit**. Esta función analiza la línea de ordenes y pasa los parámetros a la ventana principal, pero espera la entrada en estilo C/C++. Tendrás que escribir tu propia función para realizar la conversión de *ParamCount* y *ParamStr* a parámetros al estilo C/C++ de línea de ordenes.
3333
3434``` pascal
3535 procedure glutInitPascal(ParseCmdLine: Boolean);
3636 var
3737 Cmd: array of PChar;
3838 CmdCount, I: Integer;
3939 begin
4040 if ParseCmdLine then
4141 CmdCount := ParamCount + 1
4242 else
4343 CmdCount := 1;
4444 SetLength(Cmd, CmdCount);
4545 for I := 0 to CmdCount - 1 do
4646 Cmd[I] := PChar(ParamStr(I));
4747 glutInit(@CmdCount, @Cmd);
4848 end;
4949```
5050
5151   En esencia lo que hace es crear una matriz y rellenarla con las cadenas (strings) de ParamStr. Este procedimiento recibe un parámetro que permite controlar lo que se pasa a glutInit, bien la línea de mandatos completa o bien sólo el nombre del fichero ejecutable.
5252
5353   ToDo: probablemente **glutInit(@argc, @argv);** sea suficiente.
5454
5555   Más acerca de glutInit: <http://www.opengl.org/resources/libraries/glut/spec3/node10.html>
5656
5757   Ahora, necesitas crear una ventana principal. Ajusta el modo de visualización de la ventana principal con **glutInitDisplayMode**. Únicamente recibe un parámetro, que es una combinación de indicadores. En general todo lo que se necesita es **GLUT_DOUBLE** o **GLUT_RGB o GLUT_DEPTH**.
5858
5959   Más acerca de glutInitDisplayMode: <http://www.opengl.org/resources/libraries/glut/spec3/node12.html>
6060
6161   La posición y el tamaño de la ventana se controla utilizando **glutInitWindowPosition** y **glutInitWindowSize**. Toman 2 parámetros. Las coordenada X e Y en el former, y width (ancho) y height (alto) en el latter. Se puede utilizar **glutGet** para obtener el tamaño de pantalla y centrar la ventana.
6262
6363   Más acerca de glutInitWindowPosition, glutInitWindowSize y glutGet: <http://www.opengl.org/resources/libraries/glut/spec3/node11.html> <http://www.opengl.org/documentation/specs/glut/spec3/node70.html>
6464
6565   Finalmente se debería crear la ventana utilizando la función **glutCreateWindow**. Esto generará la ventana y establecerá su caption a través de un parámetro. Como resultado se retornará el manejador (handler) de ventana. Esto se puede utilizar con otras funciones que lo requieran.
6666
6767   Más acerca de glutCreateWindow: <http://www.opengl.org/resources/libraries/glut/spec3/node16.html>
6868
6969   Antes de que el programa pueda entrar en el bucle principal, se deben establecer algunas callbacks. Se necesitarán las callback para dibujar la ventana, para su redimensionado y para obtener las entradas desde el teclado. Estas callbacks se establecen utilizando **glutDisplayFunc**, **glutReshapeFunc** y **glutKeyboardFunc**.
7070
7171   Más acerca de las callbacks: <http://www.opengl.org/resources/libraries/glut/spec3/node45.html#SECTION00080000000000000000>
7272
7373   Tu función de dibujo podría parecerse a lo siguiente:
7474
7575``` pascal
7676 procedure DrawGLScene; cdecl;
7777 begin
7878 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
7979 glutSwapBuffers;
8080 end;
8181```
8282
8383   Esto solamente borra la ventana con el color de fondo y realiza un reset del zbuffer (no te preocupes acerca de que puede ser el zbuffer...más acerca de esto más adelante).
8484
8585   La función de redimensionado podría parecerse a esto:
8686
8787``` pascal
8888 procedure ReSizeGLScene(Width, Height: Integer); cdecl;
8989 begin
9090 if Height = 0 then
9191 Height := 1;
9292
9393 glViewport(0, 0, Width, Height);
9494 glMatrixMode(GL_PROJECTION);
9595 glLoadIdentity;
9696 gluPerspective(45, Width / Height, 0.1, 1000);
9797
9898 glMatrixMode(GL_MODELVIEW);
9999 glLoadIdentity;
100100 end;
101101```
102102
103103   Con este código, se le indica a OpenGL donde debe dibujar en la ventana y establecer las matrices a los valores deseados (las funciones de matriz se explicarán más adelante).
104104
105105   La entrada de teclado (Keyboard) se evalúa con la siguiente callback:
106106
107107``` pascal
108108 procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl;
109109 begin
110110 if Key = 27 then
111111 Halt(0);
112112 end;
113113```
114114
115115   Esta función indica al programa que debe salir del mismo si se presiona la tecla ESC. GLUT está orientado a eventos y el único medio de salir del programa es llamar **Halt** desde dentro de una de las funciones callback. Si se cierra la ventana de algún otro modo, desaparecerá, pero el programa continuará en el bucle dentro de la rutina principal indefinidamente. Para comenzar el bucle principal hay que llamar a la función **glutMainLoop**. Esto iniciará un bucle que nunca finalizará y que realizará las llamadas a todas las funciones callback.
116116
117117   La porción principal del programa puede parecerse a lo siguiente:
118118
119119``` pascal
120120 const
121121 AppWidth = 640;
122122 AppHeight = 480;
123123
124124 procedure InitializeGL;
125125 begin
126126 glClearColor(0.18, 0.20, 0.66, 0);
127127 end;
128128
129129 var
130130 ScreenWidth, ScreenHeight: Integer;
131131 begin
132132 glutInitPascal(True);
133133 glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGB or GLUT_DEPTH);
134134 glutInitWindowSize(AppWidth, AppHeight);
135135 ScreenWidth := glutGet(GLUT_SCREEN_WIDTH);
136136 ScreenHeight := glutGet(GLUT_SCREEN_HEIGHT);
137137 glutInitWindowPosition((ScreenWidth - AppWidth) div 2,
138138 (ScreenHeight - AppHeight) div 2);
139139 glutCreateWindow('OpenGL Tutorial 1');
140140
141141 InitializeGL;
142142
143143 glutDisplayFunc(@DrawGLScene);
144144 glutReshapeFunc(@ReSizeGLScene);
145145 glutKeyboardFunc(@GLKeyboard);
146146
147147 glutMainLoop;
148148 end.
149149```
150150
151151   La siguiente tutoría añade un poco de código que dibuja una figura sencilla.
152152
153153   Descarga el código fuente o un ejecutable Linux / Windows desde [Lazarus CCR SourceForge](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=199145).
154154
155155# Dibujando una figura simple
156156
157157**Nota:** Las siguientes partes tratan principalmente sobre OpenGL, por lo que utilizan las librerías GLUT y LCL. Las funciones específicas de GLUT se reconocen porque llevan el prefijo 'glu'.
158158
159159   Esta vez solo añadiremos unas pocas líneas de código y nos centraremos en explicar algunas de las funciones de OpenGL.
160160
161161   Expliquemos el código que ya tenemos escrito.
162162
163163``` pascal
164164 .
165165 .
166166 .
167167 glMatrixMode(GL_PROJECTION);
168168 glLoadIdentity;
169169 gluPerspective(45, Width / Height, 0.1, 1000);
170170
171171 glMatrixMode(GL_MODELVIEW);
172172 glLoadIdentity;
173173 end;
174174```
175175
176176   Usando la función **glMatrixMode** elegimos que matriz queremos cambiar. OpenGL trabaja con 3 matrices: **GL_MODELVIEW**: Se usa para mover el vértice al espacio del modelo. **GL_PROJECTION**: Se usa para convertir las coordenadas 3d en coordenadas 2d para determinar la posición final del pixel. **GL_TEXTURE**: Se usa para alterar las coordenadas de la textura.
177177
178178   Una vez que elegimos la matriz que queremos cambiar, podemos llamar a las funciones que afectan a los valores de la matriz. **glLoadIdentity** reinicializa la matriz por lo que no afectará a la posición del vértice. Puesto que casi todas las funciones de matrices multiplican la matriz actual por una generada, a veces necesitaremos limpiar la matriz usando esta función.
179179
180180   Para establecer una matriz de perspectiva, podemos usar la función **gluPerspective**. Cuatro parámetros presentan el punto de vista, aspecto (aspect radio), distancia la plano. Es así de simple.
181181
182182   Ahora, vamos a cambiar la matriz modelo... esta vez la ajustamos a la identidad.
183183
184184   Bien... y ahora, el código para dibujar la primera figura:
185185
186186``` pascal
187187 procedure DrawGLScene; cdecl;
188188 begin
189189 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
190190
191191 glLoadIdentity;
192192 glTranslatef(0, 0, -5);
193193
194194 glBegin(GL_TRIANGLES);
195195 glColor3f(1, 0, 0);
196196 glVertex3f(-1, -1, 0);
197197
198198 glColor3f(0, 1, 0);
199199 glVertex3f(1, -1, 0);
200200
201201 glColor3f(0, 0, 1);
202202 glVertex3f(0, 1, 0);
203203 glEnd;
204204
205205 glutSwapBuffers;
206206 end;
207207```
208208
209209   Ya hemos usado la función glClear, que reseteará los buffers. Vamos a saltarnos las dos siguientes funciones, y vayamos directamente a las de dibujo.
210210
211211   **glBegin** marca el inicio de un bloque de dibujo. Después de esta función puedes empezar a introducir vértices. Los parámetros describen como van a ser usados los vértices cuando se dibujen.
212212
213213- GL_POINTS: Trata cada vértices como un único punto. Vertex n define el punto n. Pueden dibujarse n.
214214- GL_LINES: Trata cada par de vérices como un segmento independiente. Los vértices 2n-1 y 2n definen la línea n. Se dibujan n/2 lineas.
215215- GL_LINE_STRIP: Dibuja un grupo de segmentos de línea conectados entre sí. Se dibujan n-1 lineas.
216216- GL_LINE_LOOP: Dibuja un grupo de segmentos de lineas conectados entre sí. El primer vértice y el último también están conectados, formando un lazo. Los vertices n y n+1 definen la línea n. La última linea es definida por los vertices n y 1. Se dibujan n líneas.
217217- GL_TRIANGLES: Trata cada triplete de vértices como un triángulo independiente. Los vértices 3n-2, 3n-1 y 3n definen el triángulo. Se dibujan n/3 triángulos.
218218- GL_TRIANGLE_STRIP: Dibuja un grupo de triángulos conectados. Un triángulo es definido por cada vértice creado después de los dos primeros vértices. Para valores inpares de n, vertices n, n+1 and n+2 define triangle n. For even n, vertices n+1, n and n+2 define triangle n. Se dibujan n-2 triángulos.
219219- GL_TRIANGLE_FAN: Dibuja un grupo de triángulos conectados. Un triángulo se define con cada vértice creado después de los dos primeros vértices. Los vértices 1. n+1 y n+2 definen el triángulo n. Se dibujan n-2 triángulos.
220220- GL_QUADS: Trata cada grupo de 4 vértices como un cuadrilátero independiente. Los vértices 4n-3, 4n-2, 4n-1 y 4n definen el cuadrilátero n. Se dibujan n/4 cuadriláteros.
221221- GL_QUAD_STRIP: Dibuja un grupo de cuadriláteros conectados. Un cuadrilátero es definido por cada pa de vértices creados después del primer par. Los vértices 2n-1, 2n, 2n+2 y 2n+1 definen el cuadrilátero n. Se dibujan n/2-1 cuadriláteros. Tenga en cuenta que el orden en el que los vértices se usan para crear un cuadrilátero a partir de strip data es diferente from that used with independent data.
222222- GL_POLYGON: Dibuja un polígono convexo. Los vértices del 1 al n definen este polígono.
223223
224224![](/wiki-images/f/f3/SimpleShapePic1.jpg)    You'll draw single triangle and for that GL_TRIANGLES flag will do the trick. La función **glVertex3f** define la posición del vértice que queremos dibujar. Hay más funciones glVertex*. Solo se diferencian en el número y tipo de los parámetros que introducimos. For instance... glVertex2i toma dos parámetros (X e Y) de tipo integer. Casi siempre glVertex3f será la función que más se use.
225225
226226   Before glVertex you can set color, material, textura... Por simplicidad you'll just specify color para cada vértice en este tutorial. El color se establece usando la función **glColor3f**. glColor tambien puede tomar un conjunto de parámetros diferentes como glVertex.
227227
228228   As we look through code podemos ver que asignamos a Z el valor 0 en todos los vértices. Since you set near plane to 0.1, triangle will not be visible. That is where those two functions we skipped in the beginning jump in. ya sabemos que glLoadIdentity resetea la matriz. **glTranslatef** moves triangles by X, Y and Z values you provide. Since you set Z to -5 (negative Z is farther from camera) todos los vertices se dibujarán 5 unidades far from point of view and will be visible.
229229
230230   Al final llamamos a la función **glEnd** que termina el proceso de dibujado. Si queremos, podemos comenzar otro bloque de dibujado usando glBegin.
231231
232232   Descargue el código fuente, el ejecutable de linux o windows desde [Lazarus CCR SourceForge](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=199145).
233233
234234# Usando [Listas de despliegue](http://es.wikipedia.org/wiki/Lista_de_despliegue)
235235
236236   A veces necesitaras dibujar algunos objetos varias veces en la escena. OpenGL tiene la habiliad de construir **Listas de despliegue (*display lists*)** con las cuales dibujar se hace un poco más rápido. Crear una lista de despliegue es muy fácil... dibuja los vértices como hiciste en el tutorial anterior, y enciérralos con las llamadas **glNewList** y **glEndList**.
237237
238238``` pascal
239239 const
240240 LIST_OBJECT = 1;
241241
242242 procedure CreateList;
243243 begin
244244 glNewList(LIST_OBJECT, GL_COMPILE);
245245 glBegin(GL_TRIANGLE_FAN);
246246 glColor3f(1, 0, 0);
247247 glVertex3f(0, 0.5, 0);
248248
249249 glColor3f(1, 1, 0);
250250 glVertex3f(-0.5, -0.5, 0.5);
251251
252252 glColor3f(1, 1, 1);
253253 glVertex3f(0.5, -0.5, 0.5);
254254
255255 glColor3f(0, 1, 1);
256256 glVertex3f(0.5, -0.5, -0.5);
257257
258258 glColor3f(0, 0, 1);
259259 glVertex3f(-0.5, -0.5, -0.5);
260260
261261 glColor3f(0, 1, 0);
262262 glVertex3f(-0.5, -0.5, 0.5);
263263 glEnd;
264264
265265 glBegin(GL_QUADS);
266266 glColor3f(1, 1, 0);
267267 glVertex3f(-0.5, -0.5, 0.5);
268268
269269 glColor3f(1, 1, 1);
270270 glVertex3f(0.5, -0.5, 0.5);
271271
272272 glColor3f(0, 1, 1);
273273 glVertex3f(0.5, -0.5, -0.5);
274274
275275 glColor3f(0, 0, 1);
276276 glVertex3f(-0.5, -0.5, -0.5);
277277
278278 glColor3f(0, 1, 0);
279279 glVertex3f(-0.5, -0.5, 0.5);
280280 glEnd;
281281 glEndList;
282282 end;
283283```
284284
285285   **glNewList** crea una nueva lista de despliegue y todas las funciones de dibujo serán grabadas hasta que se llame a **glEndList**. El primer parámetro para la función glNewList es list ID. Toda lista es definida por su ID. Si una lista con un ID dado ya está creada, será borrada antes de grabar. Si el segundo parámetro es GL_COMPILE entonces todas las funciones solamente son grabadas, pero si es GL_COMPILE_AND_EXECUTE entonces son guardadas y ejecutadas automáticamente.
286286
287287   **glIsList** es una función que puede ayudar con tus listas de despliegue. Puede decirte si un ID de una lista ya contiene datos.
288288
289289   Otra función útil es *glGenLists*'. Creará múltiples listas. Puedes pasar el número de listas de despliegue que necesitas y obtendrás el ID del primero. Si necesitas n listas, y obtienes un ID, listas de despliegue son: r, r+1, r+2,..., r+n-1
290290
291291   Todas las listas deben ser borradas antes de que el programa acabe:
292292
293293``` pascal
294294 procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl;
295295 begin
296296 if Key = 27 then
297297 begin
298298 glDeleteLists(LIST_OBJECT, 1);
299299 Halt(0);
300300 end;
301301 end;
302302```
303303
304304   **glDeleteLists** tiene 2 parámetros, ID de lista de despliegue y un número de listas a borrar. Si el ID es r, y el número de listas a borrar es n, las litas borradas son: r, r+1, r+2,..., r+n-1
305305
306306   Ahora conoces como crear y borrar listas, vamos a ver como dibujarlas:
307307
308308``` pascal
309309 procedure DrawGLScene; cdecl;
310310 begin
311311 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
312312
313313 glLoadIdentity;
314314 glTranslatef(-2, 0, -5);
315315 glRotatef(40, 1, 0, 1);
316316 glCallList(LIST_OBJECT);
317317
318318 glLoadIdentity;
319319 glTranslatef(1, -2, -10);
320320 glRotatef(62, 0, 1, 0);
321321 glCallList(LIST_OBJECT);
322322
323323 glLoadIdentity;
324324 glTranslatef(-4, 0.5, -15);
325325 glRotatef(200, 1, 0, 0);
326326 glCallList(LIST_OBJECT);
327327
328328 glutSwapBuffers;
329329 end;
330330```
331331
332332![](/wiki-images/a/a5/DisplayListsPic1.jpg)   Usando **glCallList** puedes dibujar solo un display list. En este tutorial, antes de display list, puedes cambiar la matriz modelo, y dibujar en diferentes lugares.    A veces te gustaria dibujar multiples listas de una vez. Esto es posible usando la función **glCallLists**. Coge el número de listas que quieres dibujar, es un array que contiene los ID de display list. El tipo de lista puede ser una de los siguientes:
333333
334334- GL_BYTE: list is treated as an array of signed bytes, each in the range -128 through 127.
335335- GL_UNSIGNED_BYTE: list is treated as an array of unsigned bytes, each in the range 0 through 255.
336336- GL_SHORT: list is treated as an array of signed two-byte integers, each in the range -32768 through 32767.
337337- GL_UNSIGNED_SHORT: list is treated as an array of unsigned two-byte integers, each in the range 0 through 65535.
338338- GL_INT: lists is treated as an array of signed four-byte integers.
339339- GL_UNSIGNED_INT: list is treated as an array of unsigned four-byte integers.
340340- GL_FLOAT: list is treated as an array of four-byte floating-point values.
341341- GL_2_BYTES: list is treated as an array of unsigned bytes. Each pair of bytes specifies a single display list ID. The value of the pair is computed as 256 times the unsigned value of the first byte plus the unsigned value of the second byte.
342342- GL_3_BYTES: list is treated as an array of unsigned bytes. Each triplet of bytes specifies a single display list ID. The value of the triplet is computed as 65536 times the unsigned value of the first byte, plus 256 times the unsigned value of the second byte, plus the unsigned value of the third byte.
343343- GL_4_BYTES: list is treated as an array of unsigned bytes. Each quadruplet of bytes specifies a single display list ID. The value of the quadruplet is computed as 16777216 times the unsigned value of the first byte, plus 65536 times the unsigned value of the second byte, plus 256 times the unsigned value of the third byte, plus the unsigned value of the fourth byte.
344344
345345   Esto es todo por ahora. En el siguiente tutorial, mostraré como crear un pequeño sistema planetario. Hablaremos sobre las matrices y como hacer una escena animada que no dependa del número de cuadros por segundo.
346346
347347   Descarga el codido fuente, linux ejecutable o windows ejecutable de [Lazarus CCR SourceForge](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=199145).
348348
349349# Full screen animation
350350
351351   Entrar en modo pantalal completa es fácil con. Hagamos cambios en la parte "main del programa:the program:
352352
353353``` pascal
354354 const
355355 FSMode = '800x600:32@75';
356356
357357 begin
358358 glutInitPascal(False);
359359 glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGB or GLUT_DEPTH);
360360 glutGameModeString(FSMode);
361361 glutEnterGameMode;
362362 glutSetCursor(GLUT_CURSOR_NONE);
363363
364364 InitializeGL;
365365
366366 glutDisplayFunc(@DrawGLScene);
367367 glutReshapeFunc(@ReSizeGLScene);
368368 glutKeyboardFunc(@GLKeyboard);
369369 glutIdleFunc(@DrawGLScene);
370370
371371 glutMainLoop;
372372 end.
373373```
374374
375375   Since we don't want GLUT to parse command line this time we call glutInitPascal with False parameter. As you can see, there is no code for window creation. GLUT have **glutEnterGameMode** that create full screen window. To specify what kind of full screen mode you want, you call **glutGameModeString** function which takes string that defines mode you like.
376376
377377   Format of that string is:
378378
379-`[width "x" height][":" bpp]["@" hertz]`
379+```text
380+[width "x" height][":" bpp]["@" hertz]
381+```
380382
381383   In FSMode string we declared that full screen mode should be 800x600, with 32bit pallete and 75Hz refresh. It is possible to skip one of the group. If you omit size, GLUT will try to use current one or first smaller that can work. That policy is used and for other parameters.
382384
383385   Usually in full screen mode cursor is not visible. To hide cursor you use **glutSetCursor** function. It takes only one parameter which describes cursor you would like to see:
384386
385387``` pascal
386388 GLUT_CURSOR_RIGHT_ARROW
387389 GLUT_CURSOR_LEFT_ARROW
388390 GLUT_CURSOR_INFO
389391 GLUT_CURSOR_DESTROY
390392 GLUT_CURSOR_HELP
391393 GLUT_CURSOR_CYCLE
392394 GLUT_CURSOR_SPRAY
393395 GLUT_CURSOR_WAIT
394396 GLUT_CURSOR_TEXT
395397 GLUT_CURSOR_CROSSHAIR
396398 GLUT_CURSOR_UP_DOWN
397399 GLUT_CURSOR_LEFT_RIGHT
398400 GLUT_CURSOR_TOP_SIDE
399401 GLUT_CURSOR_BOTTOM_SIDE
400402 GLUT_CURSOR_LEFT_SIDE
401403 GLUT_CURSOR_RIGHT_SIDE
402404 GLUT_CURSOR_TOP_LEFT_CORNER
403405 GLUT_CURSOR_TOP_RIGHT_CORNER
404406 GLUT_CURSOR_BOTTOM_RIGHT_CORNER
405407 GLUT_CURSOR_BOTTOM_LEFT_CORNER
406408 GLUT_CURSOR_FULL_CROSSHAIR
407409 GLUT_CURSOR_NONE
408410 GLUT_CURSOR_INHERIT
409411```
410412
411413   **glutIdleFunc** defines callback function that you want to be called every time you program has no messages to process. Since we just want to render new frame if there is nothing to do, just set idle function to DrawGLScene. Some other tutorials show that idle function should send refresh message insted of drawing, but that way I have 50-100 frames less than using method I described.
412414
413415   Now, let's look at the program termination where you need to exit full screen mode:
414416
415417``` pascal
416418 procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl;
417419 begin
418420 if Key = 27 then
419421 begin
420422 glutLeaveGameMode;
421423 Halt(0);
422424 end;
423425 end;
424426```
425427
426428   As you can see, all you need to do is to call **glutLeaveGameMode**.
427429
428430   Now, we'll introduce some new matrix functions. First, let's change ReSizeGLScene function:
429431
430432``` pascal
431433 procedure ReSizeGLScene(Width, Height: Integer); cdecl;
432434 begin
433435 .
434436 .
435437 .
436438
437439 glMatrixMode(GL_MODELVIEW);
438440 glLoadIdentity;
439441 gluLookAt(0, 20, 25, 0, 0, 0, 0, 1, 0);
440442 end;
441443```
442444
443445   **gluLookAt** create matrix that will define from where are you look to objects. First 3 parameters are X, Y and Z coordinate of position of camera. Next 3 parameters are X, Y and Z coordinate of point where camera look at, and last 3 parameters defines "up" vector (where is "up" for the camera). Usually, up is positive y axis.
444446
445447   OK, let's draw now. Since you set matrix with gluLookAt that should be used with all objects, you can't just use glLoadIdentity to reset matrix for next object... you'll save previous matrix state and restore it after object is drawn:
446448
447449``` pascal
448450 procedure DrawGLScene; cdecl;
449451 var
450452 T: Single;
451453 begin
452454 T := glutGet(GLUT_ELAPSED_TIME) / 1000;
453455 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
454456
455457 glPushMatrix;
456458 glRotatef(5 * T, 0, 1, 0);
457459 glColor3f(1, 1, 0);
458460 glutWireSphere(2, 20, 20);
459461 glPopMatrix;
460462
461463 glPushMatrix;
462464 glRotatef(90 * T, 0, 1, 0);
463465 glTranslatef(5, 0, 0);
464466 glRotatef(40 * T, 0, 1, 0);
465467 glColor3f(1, 0, 0);
466468 glutWireSphere(0.6, 10, 10);
467469 glPopMatrix;
468470
469471 glPushMatrix;
470472 glRotatef(60 * T, 0, 1, 0);
471473 glTranslatef(-3, 0, 9);
472474 glRotatef(50 * T, 0, 1, 0);
473475 glColor3f(0, 1, 0);
474476 glutWireSphere(1, 16, 16);
475477
476478 glPushMatrix;
477479 glRotatef(360 * T, 0, 1, 0);
478480 glTranslatef(-1.7, 0, 0);
479481 glRotatef(50 * T, 0, 1, 0);
480482 glColor3f(0, 0, 1);
481483 glutWireSphere(0.4, 10, 10);
482484 glPopMatrix;
483485
484486 glPopMatrix;
485487
486488 glutSwapBuffers;
487489 end;
488490```
489491
490492![](/wiki-images/5/51/FullScreenAnimationPic1.jpg)   **glPushMatrix** i **glPopMatrix** are used to save and restore matrix state. As you can see, we save matrix state, then change matrix in order to draw object in right place, and then restore old matrix state.
491493
492494   You may wonder what is **T** variable for. Well, it is used to determen animation speed. Every change that depends on time is multiplied with T. That way animation speed is constant on every frame rate. **glutGet** function with **GLUT_ELAPSED_TIME** parameter returns time in milliseconds from glutInit is called. By dividing that value with 1000, we get time in seconds.
493495
494496   **glRotatef** function create rotation matrix. First parameter is angle in degrees, and last 3 parameters defines axis around which rotation will be done. Since you multiplied angle with T, object will be rotated by that angle in exactly 1 second.
495497
496498   Download source code, linux executable or windows executable from [Lazarus CCR SourceForge](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=199145).
497499
498500# Luz
499501
500502   Este tutorial introducirá algo de luz en la escena. You'll make rotating cube and one light which will add some realism to the scene, but first let's make some utility unit.
501503
502504   Por el momento tendremos sólamente funciones básicas para ayudarnos a obtener los tiempos current y delta (tiempo transcurrido desde la llamada de un render a otro) y para calcular los frames por segundo.
503505
504506``` pascal
505507 unit utils;
506508
507509 {$mode objfpc}{$H+}
508510
509511 interface
510512
511513 uses
512514 glut;
513515
514516 function GetTotalTime: Single;
515517 function GetDeltaTime: Single;
516518 procedure FrameRendered(Count: Integer = 1);
517519 function GetFPS: Single;
518520
519521 implementation
520522
521523 var
522524 OldTime: Integer = 0;
523525 FPSTime: Integer = 0;
524526 FPSCount: Integer = 0;
525527
526528 function GetTotalTime: Single;
527529 begin
528530 Result := glutGet(GLUT_ELAPSED_TIME) / 1000;
529531 end;
530532
531533 function GetDeltaTime: Single;
532534 var
533535 NewTime: Integer;
534536 begin
535537 NewTime := glutGet(GLUT_ELAPSED_TIME);
536538 Result := (NewTime - OldTime) / 1000;
537539 OldTime := NewTime;
538540 end;
539541
540542 procedure FrameRendered(Count: Integer);
541543 begin
542544 Inc(FPSCount, Count);
543545 end;
544546
545547 function GetFPS: Single;
546548 var
547549 NewTime: Integer;
548550 begin
549551 NewTime := glutGet(GLUT_ELAPSED_TIME);
550552
551553 Result := FPSCount / ((NewTime - FPSTime) / 1000);
552554
553555 FPSTime := NewTime;
554556 FPSCount := 0;
555557 end;
556558
557559 end.
558560```
559561
560562   Como puedes observar, no hay complejidades en esta unit. Se salva simplente el tiempo entre las llamadas y se retorna la diferencia. Se debe hacer una llamada a FrameRendered cada vez que se dibuja una escena de manera que la función pueda calcular los FPS (Frames por segundo:Frames Per Second).
561563
562564   Ahora, divirtámonos con las luces.
563565
564566   OpenGL tiene varios tipos de luz... ambiente, difusa, point, spot, especular y emissive.
565567
566568   La luz ambiente es algo así como la del Sol. Cuando los rayos solares pasan a través de la ventana de una habitación inciden sobre las paredes y tiene lugar su reflexión y su dispersión en todas las direcciones lo cual averagely brightens up la habitación completa. Todos los vertices son lit con luz ambiente.
567569
568570   La Luz Difusa puede representarse como rayos de luz paralelos llegando desde puntos lejanos. They will lit only vertices that are oriented towards the light source.
569571
570572   Point light lights all around it. Es como una bola de fuego, it send light rays all around it and lights vertices that are oriented towards light source and that are close enough.
571573
572574   Spot light es como la luz de una linterna. Es simplemente un punto de luz source con un cono de luz de radio pequeño. All vertices that falls inside of cone and are close enough are lit.
573575
574576   Just like Diffuse light, Specular light is a directional type of light. It comes from one particular direction. The difference between the two is that specular light reflects off the surface in a sharp and uniform way. The rendering of specular light relies on the angle between the viewer and the light source. From the viewer’s standpoint specular light creates a highlighted area on the surface of the viewed object known as specular highlight or specular reflection.
575577
576578   Emissive light is a little different than any other previously explained light components. This light comes out of object you draw but don't lit other objects in nearby.
577579
578580   Por simplicidad utilizaremos únicamente luz difusa en este tutorial. Con el tiempo puede que aparezcan otros tipos de luz pero por ahora nos centraremos en este. :)
579581
580582   Veamos como habilitar la luz en la escena:
581583
582584``` pascal
583585 const
584586 DiffuseLight: array[0..3] of GLfloat = (0.8, 0.8, 0.8, 1);
585587
586588 glEnable(GL_LIGHTING);
587589 glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseLight);
588590 glEnable(GL_LIGHT0);
589591```
590592
591593   As you see, we enable lighting in OpenGL so lights affect scene you are rendering. Light parameters are set with **glLightfv** function. It takes 3 parameters... one for light number you want to change (OpenGL suports up to 8 lights), next tells OpenGL que parámetro de la luz cambiar, y este último es el nuevo parámetro para la luz. You'll set just diffuse color for light en este tutorial. After that, you can enable light and there will be light en la escena... pero... eso no es todo.
592594
593595   Para saber más sobre glLightfv: <http://www.opengl.org//documentation/specs/man_pages/hardcopy/GL/html/gl/light.html>
594596
595597   Si necesitas utilizar luces no basta simplemente con establecer el color de los vértices... debes establecer el material de los vértices. Establezcamos el material para el dibujo:
596598
597-`glEnable(GL_COLOR_MATERIAL);`\
598-`glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);`
599+```text
600+glEnable(GL_COLOR_MATERIAL);
601+glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
602+```
599603
600604![](/wiki-images/e/ed/LightPic1.jpg)   ¿Esperabas hacer algo más complicado? :) Bien, este código nos permitirá utilizar la función glColor para configurar los materiales de los vértices. Utilizando la función glEnable y la bandera GL_COLOR_MATERIAL, puedes definir que propiedades de los materiales, cambiará glColor. **glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE)** le dice a OpenGL que glColor cambia las propiedades del material ambient y diffuse. Discutiremos los materiales más tarde en estos tutoriales.
601605
602606   Una cosa más que es importante cuando utilizamos luces... cada vértice debe tener asociada una "normal". La "Normal" se utiliza para encontrar la dirección del vértice de forma que la luz se puede calcular de la forma apropiada. Utilizarás la función GLUT para dibujar un cubo que nos aportará las "normales" de por sí, so this time we'll just walk by normals.
603607
604608   Después de establecer todo esto, la luz brillará en el cubo :)
605609
606610   Parte de lo que sigue está copiado de [The OpenGL Light Bible](http://www.falloutsoftware.com/tutorials/gl/gl8.htm)
607611
608612   Download source code, linux executable or windows executable from [Lazarus CCR SourceForge](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=199145).
609613
610614# Fuentes Bitmap
611615
612616   Games and programs usually need to write some text on screen. GLUT provides several functions for drawing chars that are platform independent.
613617
614618   First, we'll show how to use default bitmap fonts. Almost all code additions will be made to utils.pas unit.
615619
616620   Since text will be drawn in 2D, we'll need to know width and height of viewport... so, we'll write two functions for that:
617621
618622``` pascal
619623 function glGetViewportWidth: Integer;
620624 var
621625 Rect: array[0..3] of Integer;
622626 begin
623627 glGetIntegerv(GL_VIEWPORT, @Rect);
624628 Result := Rect[2] - Rect[0];
625629 end;
626630
627631 function glGetViewportHeight: Integer;
628632 var
629633 Rect: array[0..3] of Integer;
630634 begin
631635 glGetIntegerv(GL_VIEWPORT, @Rect);
632636 Result := Rect[3] - Rect[1];
633637 end;
634638```
635639
636640   We just get left/right, top/bottom and calculate width/height by subtracting them.
637641
638642   There must be functions for entering and leaving 2D mode:
639643
640644``` pascal
641645 procedure glEnter2D;
642646 begin
643647 glMatrixMode(GL_PROJECTION);
644648 glPushMatrix;
645649 glLoadIdentity;
646650 gluOrtho2D(0, glGetViewportWidth, 0, glGetViewportHeight);
647651
648652 glMatrixMode(GL_MODELVIEW);
649653 glPushMatrix;
650654 glLoadIdentity;
651655
652656 glDisable(GL_DEPTH_TEST);
653657 end;
654658
655659 procedure glLeave2D;
656660 begin
657661 glMatrixMode(GL_PROJECTION);
658662 glPopMatrix;
659663 glMatrixMode(GL_MODELVIEW);
660664 glPopMatrix;
661665
662666 glEnable(GL_DEPTH_TEST);
663667 end;
664668```
665669
666670   When entering 2D mode, we save current matrices and set 2D matrix using **gluOrtho2D** function. This way if we draw some thing on 100, 100 it will be drawn on exactly 100 pixels from left edge of window, and 100 pixels form bottom edge (positive Y is up). Also, we disable ZBuffer. This way text won't alter ZBuffer.
667671
668672   Leaving 2D mode just returns old matrices and enable ZBuffer.
669673
670674   Now, we can create function for text drawing:
671675
672676``` pascal
673677 procedure glWrite(X, Y: GLfloat; Font: Pointer; Text: String);
674678 var
675679 I: Integer;
676680 begin
677681 glRasterPos2f(X, Y);
678682 for I := 1 to Length(Text) do
679683 glutBitmapCharacter(Font, Integer(Text[I]));
680684 end;
681685```
682686
683687   **glutBitmapCharacter** can draw only one character of selected font. First parameter is desired font (GLUT_BITMAP_9_BY_15, GLUT_BITMAP_8_BY_13, GLUT_BITMAP_TIMES_ROMAN_10, GLUT_BITMAP_TIMES_ROMAN_24, GLUT_BITMAP_HELVETICA_10, GLUT_BITMAP_HELVETICA_12 or GLUT_BITMAP_HELVETICA_18) and other one is character.
684688
685689   Character will be drawn at current raster position. To set desired raster position we call **glRasterPos** function. glRasterPos can handle different number and types of parameters just like glVertex function. Coordinate specified is transformed by model and projection matrix to get 2D coordinate where new raster position will be. Since we entered 2D mode, X and Y coordinates are actual 2D coordinates where drawing will occur.
686690
687691   This new functions will make text drawing very easy:
688692
689693``` pascal
690694 procedure DrawGLScene; cdecl;
691695 begin
692696 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
693697
694698 glLoadIdentity;
695699 glTranslatef(0, 0, -5);
696700 glRotatef(GetTotalTime * 10, 0, 0.5, 0.5);
697701
698702 glColor3f(1, 0, 0);
699703 glutSolidCube(2);
700704
701705 glEnter2D;
702706
703707 glColor3f(0.2, 0.8 + 0.2 * Sin(GetTotalTime * 5), 0);
704708 glWrite(20, glGetViewportHeight - 20, GLUT_BITMAP_8_BY_13,
705709 Format('OpenGL Tutorial :: Bitmap Fonts :: FPS - %.2f FPS', [FPS]));
706710
707711 glColor3f(1, 1, 1);
708712 glWrite(50, glGetViewportHeight - 60, GLUT_BITMAP_9_BY_15, 'GLUT_BITMAP_9_BY_15');
709713 glWrite(50, glGetViewportHeight - 90, GLUT_BITMAP_8_BY_13, 'GLUT_BITMAP_8_BY_13');
710714 glWrite(50, glGetViewportHeight - 120, GLUT_BITMAP_TIMES_ROMAN_10, 'GLUT_BITMAP_TIMES_ROMAN_10');
711715 glWrite(50, glGetViewportHeight - 150, GLUT_BITMAP_TIMES_ROMAN_24, 'GLUT_BITMAP_TIMES_ROMAN_24');
712716 glWrite(50, glGetViewportHeight - 180, GLUT_BITMAP_HELVETICA_10, 'GLUT_BITMAP_HELVETICA_10');
713717 glWrite(50, glGetViewportHeight - 210, GLUT_BITMAP_HELVETICA_12, 'GLUT_BITMAP_HELVETICA_12');
714718 glWrite(50, glGetViewportHeight - 240, GLUT_BITMAP_HELVETICA_18, 'GLUT_BITMAP_HELVETICA_18');
715719
716720 glColor3f(0.5, 0.5, 1);
717721 glWrite(
718722 glGetViewportWidth - glutBitmapLength(GLUT_BITMAP_9_BY_15, LazText) - 5,
719723 10, GLUT_BITMAP_9_BY_15, LazText);
720724
721725 glLeave2D;
722726
723727 glutSwapBuffers;
724728
725729 FrameRendered;
726730 end;
727731```
728732
729733![](/wiki-images/b/ba/BitmapFontsPic1.jpg)   We draw red cube and rotate it, and some text to show how various bitmap fonts look like. **glutBitmapLength** function is used to find width of string so it could be aligned to right. Code can easily be altered to center text.
730734
731735   Note: See how cube looks without light.
732736
733737   Download source code, linux executable or windows executable from [Lazarus CCR SourceForge](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=199145).
734738
735739# Texturas
736740
737741   Es tiempo de usar texturas :)
738742
739743   Este tutorial mostrará como dibujar polígonos con textura y como to blend textures using multipass technic. Since OpenGL has no builtin mechanism for loading textures, we'll use external library: [Vampyre Imaging Library](http://imaginglib.sourceforge.net/). We'll use just OpenGL helper functions, but you may find this lib handy for some other things to.
740744
741745   Let's get started... we'll create display list for drawing textured rectangle:
742746
743747``` pascal
744748 procedure CreateList;
745749 begin
746750 glNewList(LIST_OBJECT, GL_COMPILE);
747751 glBegin(GL_QUADS);
748752 glTexCoord2f(1, 0);
749753 glVertex3f( 2, 2, 0);
750754 glTexCoord2f(0, 0);
751755 glVertex3f(-2, 2, 0);
752756 glTexCoord2f(0, 1);
753757 glVertex3f(-2,-2, 0);
754758 glTexCoord2f(1, 1);
755759 glVertex3f( 2,-2, 0);
756760 glEnd;
757761 glEndList;
758762 end;
759763```
760764
761765   Notice **glTexCoord** functions. They are used to specify which part of texture is assigned to vertex. Coordinates defined in this functions are from 0 to 1 (values greater than 1 are allowed but can generate different results). 0 is first pixel and 1 is last pixel. So, 0.5 will be right in the middle of texture.
762766
763767   Texture loading is extremely easy with Vampyre Imaging Library:
764768
765769``` pascal
766770 var
767771 Tex1, Tex2: GLuint;
768772
769773 procedure InitializeGL;
770774 begin
771775 glClearColor(0, 0, 0, 0);
772776 Tex1 := LoadGLTextureFromFile('ashwood.bmp');
773777 Tex2 := LoadGLTextureFromFile('Flare.bmp');
774778 glEnable(GL_TEXTURE_2D);
775779 end;
776780```
777781
778782   **LoadGLTextureFromFile** loads texture from file and returns it's ID. When texture is loaded it is allready setup for rendering.    Last line just enables 2D textures.
779783
780784   To draw textured polygon you have to bind texture and setup texture coordinations (texture coordinations are set in display list in this tutorial):
781785
782786``` pascal
783787 ...
784788 glLoadIdentity;
785789 glTranslatef(-5, 0, -15);
786790 glBindTexture(GL_TEXTURE_2D, Tex1);
787791 glCallList(LIST_OBJECT);
788792 ...
789793```
790794
791795   **glBindTexture** function is used to select texture. When you draw polygins they will have selected texture on them. It's that easy :)
792796
793797   So, using one texture is easy... but how to blend two textures. Basicly you draw polygon once with one texture, setup blending parameters, and draw polygon once more time with other texture. You can blend houndreds of textures this way. Let's see how code for this looks:
794798
795799``` pascal
796800 ...
797801 glLoadIdentity;
798802 glTranslatef(5, 0, -15);
799803 glBindTexture(GL_TEXTURE_2D, Tex1);
800804 glCallList(LIST_OBJECT);
801805
802806 glEnable(GL_BLEND);
803807 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
804808 glLoadIdentity;
805809 glTranslatef(5, 0, -15);
806810 glBindTexture(GL_TEXTURE_2D, Tex2);
807811 glCallList(LIST_OBJECT);
808812 glDisable(GL_BLEND);
809813 ...
810814```
811815
812816   As you can see, polygon is drawn first time like we allready know. Before second drawing we enable blending by calling **glEnable(GL_BLEND)**. Blending means that finall pixel color is calculated like this:
813817
814818- DrawingColor * SRCBLEND + BackgroundColor * DESTBLEND
815819
816820SRCBLEND and DESTBLEND are defined using **glBlendFunc** function. In this tutorial we set SRCBLEND to GL_ZERO (zero) and DESTBLENT to GL_SRC_COLOR (DrawingColor) and finall color is then:
817821
818822   DrawingColor * 0 + BackgroundColor * DrawingColor ![](/wiki-images/d/d4/TexturesPic1.jpg)
819823
820824   This means that background will get darker when you draw with dark colors... when you draw with white color, background color will not be changed. The result will look like this
821825
822826   Next time, we'll use extensions to show how to use singlepass multitexturing.
823827
824828   Download source code, linux executable or windows executable from [Lazarus CCR SourceForge](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=199145).
825829
826830# Multitexturing (extensions)
827831
828832   When youknow multipass multi texturing, singlepass is very easy. Texturing is separated in stages. First stage setup and draw first texture, second stage draws another one and so on. Todo lo que hay que hacer es configurar las etapas de textura y renderizar el objeto.
829833
830834   Veamos como queda el código:
831835
832836``` pascal
833837 procedure InitializeGL;
834838 begin
835839 Load_GL_ARB_multitexture;
836840 glClearColor(0, 0, 0, 0);
837841 Tex1 := LoadGLTextureFromFile('Lazarus.bmp');
838842 Tex2 := LoadGLTextureFromFile('Mask.bmp');
839843 glActiveTextureARB(GL_TEXTURE0_ARB);
840844 glEnable(GL_TEXTURE_2D);
841845 glBindTexture(GL_TEXTURE_2D, Tex1);
842846 glActiveTextureARB(GL_TEXTURE1_ARB);
843847 glEnable(GL_TEXTURE_2D);
844848 glBindTexture(GL_TEXTURE_2D, Tex2);
845849 end;
846850```
847851
848852   Primero necesitamos cargar la extensión de OpenGL que permitirá utilizar las funciones de multitextura. **Load_GL_ARB_multitexture** tratará de cargar estas extensiones retornando TRUE en caso de éxito.
849853
850854   Para seleccionar la etapa de textura que queremos establecer utilizamos la función **glActiveTextureARB**. Toma únicamente un parámetro para definir la etapa que se necesita. Después de esto todas las funciones de textura (enabling, disabling, binding, creating...) afectarán esta etapa.
851855
852856   Después de establecer todo en la función de inicialización, todo lo que resta por hacer es dibujar el objeto:
853857
854858``` pascal
855859 procedure DrawGLScene; cdecl;
856860 begin
857861 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
858862
859863 glLoadIdentity;
860864 glTranslatef(0, 0, -5);
861865
862866 glBegin(GL_QUADS);
863867 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1, 0);
864868 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1, 0);
865869 glVertex3f(2.516, 2, 0);
866870 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 0);
867871 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 0);
868872 glVertex3f(-2.516, 2, 0);
869873 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 1);
870874 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 1);
871875 glVertex3f(-2.516,-2, 0);
872876 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1, 1);
873877 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1, 1);
874878 glVertex3f(2.516,-2, 0);
875879 glEnd;
876880
877881 glutSwapBuffers;
878882 end;
879883```
880884
881885![](/wiki-images/5/52/MultitexturePic1.jpg)   Como puedes observar, la diferencia está únicamente en la definiciónde las coordenadas de la textura. We now use **glMultiTexCoord2fARB** function that takes texture stage and texture coordinations. Every thing else is unchanged.
882886
883887   Hoy días prácticamente todas las tarjetas gráficas soportan al menos 2 etapas de textura. Using singlepass multitexturing is faster than multipass version since you draw objects only once. If hardware supports singlepass multitexturing (Load_GL_ARB_multitexture returns TRUE) use it.
884888
885889   Download source code, linux executable or windows executable from [Lazarus CCR SourceForge](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=199145).
886890
887891# Render to texture
888892
889893   This one will be short. OpenGL can capture current scene to texture so you can use it for texturing other objects (TV screen, mirror or some thing else). Well just render scene to texture and apply it to rotating plane.
890894
891895   First, we must create empty texture which we'll use to capture scene:
892896
893897``` pascal
894898 procedure SetupRenderTexture;
895899 var
896900 Data: Pointer;
897901 begin
898902 GetMem(Data, 256*256*3);
899903 glGenTextures(1, @RenderTexture);
900904 glBindTexture(GL_TEXTURE_2D, RenderTexture);
901905 glTexImage2D(GL_TEXTURE_2D, 0, 3, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, Data);
902906 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
903907 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
904908 FreeMem(Data);
905909 end;
906910```
907911
908912   Buffer for 256*256 RGB image is created and it is used to setup 2D texture.
909913
910914   Main part is in drawing function:
911915
912916``` pascal
913917 procedure DrawGLScene; cdecl;
914918 var
915919 TotalTime: Single;
916920 begin
917921 glClearColor(0, 0, 0, 0);
918922 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
919923 glEnable(GL_LIGHTING);
920924 glDisable(GL_TEXTURE_2D);
921925 glViewport(0, 0, 256, 256);
922926
923927 TotalTime := GetTotalTime;
924928
925929 glLoadIdentity;
926930 glTranslatef(0, 0, -5);
927931 glRotatef(50 * TotalTime, 1, 0, 0);
928932 glRotatef(100 * TotalTime, 0, 1, 0);
929933 glRotatef(50 * TotalTime, 0, 0, 1);
930934
931935 glColor3f(1, 1, 1);
932936 glutSolidCube(2);
933937
934938 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 256, 256, 0);
935939
936940 glClearColor(0.18, 0.20, 0.66, 0);
937941 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
938942 glDisable(GL_LIGHTING);
939943 glEnable(GL_TEXTURE_2D);
940944 glViewport(0, 0, AppWidth, AppHeight);
941945
942946 glLoadIdentity;
943947 glTranslatef(0, 0, -7);
944948 glRotatef(20 * TotalTime, 1, 0, 0);
945949 glRotatef(50 * TotalTime, 0, 1, 0);
946950
947951 glBegin(GL_QUADS);
948952 glTexCoord2f(1, 0);
949953 glVertex3f(2, 2, 0);
950954 glTexCoord2f(0, 0);
951955 glVertex3f(-2, 2, 0);
952956 glTexCoord2f(0, 1);
953957 glVertex3f(-2,-2, 0);
954958 glTexCoord2f(1, 1);
955959 glVertex3f(2,-2, 0);
956960 glEnd;
957961
958962 glutSwapBuffers;
959963 end;
960964```
961965
962966![](/wiki-images/6/6e/RenderToTexturePic1.jpg)   First, everything is setup for scene that will be captured. Viewport is reduced to 256*256 so it will fit into texture and scene is drawn. **glCopyTexImage2D** is used to capture scene to currently selected texture.
963967
964968   When we have scene captured to texture, everything can be cleared again, viewport can be returned to original size and final scene is drawn using previous scene as texture.
965969
966970   P.S. Captured texture can be saved using **SaveGLTextureToFile** function from [Vampyre Imaging Library](http://imaginglib.sourceforge.net/).
967971
968972   Download source code, linux executable or windows executable from [Lazarus CCR SourceForge](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=199145).
969973
970974# Vertex array
971975
972976   OpenGL is capable of rendering primitives using data that is stored in buffers insted of calling glVertex. Buffers can be used to define vertex and texture coordinates, and colors (index and RGBA), normals and edge flags.
973977
974978   In this tutorial well use only vertex and color buffers, and we'll show non-indexed and indexed drawing. Non-indexed mode draws buffers as streams. Indexed mode will draw buffer elements in order that is defined in index buffer. But enough talking... let's start coding.
975979
976980   First, let's define some types and constants:
977981
978982``` pascal
979983 type
980984 TVertex3f = record
981985 X, Y, Z: Single;
982986 end;
983987
984988 TColor3f = record
985989 R, G, B: Single;
986990 end;
987991
988992 VertexBuffer: array [0..5] of TVertex3f = (
989993 (X : 1; Y : 1; Z : 0),
990994 (X : -1; Y : 1; Z : 0),
991995 (X : -1; Y : -1; Z : 0),
992996 (X : 1; Y : 1; Z : 0),
993997 (X : -1; Y : -1; Z : 0),
994998 (X : 1; Y : -1; Z : 0)
995999 );
9961000 ColorBuffer: array [0..5] of TColor3f = (
9971001 (R : 1; G : 0; B : 1),
9981002 (R : 0; G : 0; B : 1),
9991003 (R : 0; G : 1; B : 0),
10001004 (R : 1; G : 0; B : 1),
10011005 (R : 0; G : 1; B : 0),
10021006 (R : 1; G : 1; B : 0)
10031007 );
10041008```
10051009
10061010   We have two buffers. One for vertex coordinates and one for vertex colors. This 6 vertices defines 2 triangles that forms rectangle.
10071011
10081012   Drawing primitives using buffers is easy:
10091013
10101014``` pascal
10111015 glEnableClientState(GL_VERTEX_ARRAY);
10121016 glEnableClientState(GL_COLOR_ARRAY);
10131017 glVertexPointer(3, GL_FLOAT, 0, @VertexBuffer[0]);
10141018 glColorPointer(3, GL_FLOAT, 0, @ColorBuffer[0]);
10151019
10161020 glDrawArrays(GL_TRIANGLES, 0, Length(VertexBuffer));
10171021
10181022 glDisableClientState(GL_VERTEX_ARRAY);
10191023 glDisableClientState(GL_COLOR_ARRAY);
10201024```
10211025
10221026   First we enable buffers we want to use using **glEnableClientState** function. Than we can select buffers we want to use. Every buffer type has own function for selecting (**glColorPointer**, **glEdgeFlagPointer**, **glIndexPointer**, **glNormalPointer**, **glTexCoordPointer**, **glVertexPointer**).
10231027
10241028   First parameter in those functions defines how many numbers every element contains. For example, let's take vertex buffer. If this parameter is 2 than OpenGL expects that every element in buffer contains x and y coordinate. If this parameter is, for example, 4, than every element should contains x, y, z and w coordinate.
10251029
10261030   Next parameter defines what type of data element contains (GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT or GL_DOUBLE).
10271031
10281032   Next one defines how many bytes are between each element. This way you can have buffer that contains vertex coordinates and some custom data. For arbitrary data type, this parameter can be calculated like this:
10291033
10301034``` pascal
10311035 type
10321036 TBufferData = record
10331037 DataBefore: TDataBefore;
10341038 Vertex: TVertex;
10351039 DataAfter: TDataAfter;
10361040 end;
10371041```
10381042
1039-`Bytes between elements = SizeOf(TDataBefore) + SizeOf(TDataAfter)`
1043+```text
1044+Bytes between elements = SizeOf(TDataBefore) + SizeOf(TDataAfter)
1045+```
10401046
10411047   Last parameter if pointer to the begginig of buffer.
10421048
10431049   When buffers are selected we can draw them using **glDrawArrays** functions. All enabled buffers are used to draw primitives. What kind of polygons are being generated is defined in first parameter (same as in glBegin function). Next two defines subset of buffer which is used for drawing (start and count).
10441050
10451051   When buffers are not needed you can disable them.
10461052
10471053   To demonstrate indexed mode, I made some simple mesh class that can load vertex, color and index data from external files:
10481054
10491055``` pascal
10501056 type
10511057 TMesh = class
10521058 private
10531059 FVertices: array of TVertex3f;
10541060 FColors: array of TColor3f;
10551061 FIndices: array of Integer;
10561062 procedure FreeBuffers;
10571063 public
10581064 constructor Create;
10591065 destructor Destroy; override;
10601066 procedure LoadMesh(FileName: String);
10611067 procedure DrawMesh;
10621068 end;
10631069```
10641070
10651071   FVertices will contain data about vertices, FColors data about color and FIndices data about indices when external file is loaded.
10661072
10671073   First we'll write some code that deals with creation and destruction of class:
10681074
10691075``` pascal
10701076 procedure TMesh.FreeBuffers;
10711077 begin
10721078 FVertices := nil;
10731079 FColors := nil;
10741080 FIndices := nil;
10751081 end;
10761082
10771083 constructor TMesh.Create;
10781084 begin
10791085 FreeBuffers;
10801086 end;
10811087
10821088 destructor TMesh.Destroy;
10831089 begin
10841090 FreeBuffers;
10851091 inherited Destroy;
10861092 end;
10871093```
10881094
10891095   File that will contain mesh data is simple text file. First row will contain number of vertices and indices separated by space character. After that row will come rows for every vertex and color. X, Y, Z, R, G and B all separated by space character. In the end, there will be rows for indices... every index number is written in its own row... so, for one triangle, data file will look like this:
10901096
1091-`3 3`\
1092-`-1 -1 0 1 1 1`\
1093-`1 -1 0 1 1 1`\
1094-`0 1 0 1 1 1`\
1095-`0`\
1096-`1`\
1097-`2`
1097+```text
1098+3 3
1099+-1 -1 0 1 1 1
1100+1 -1 0 1 1 1
1101+0 1 0 1 1 1
1102+0
1103+1
1104+2
1105+```
10981106
10991107   This means that there is 3 vertices and 3 indices defined in file. First vrtex is at -1, -1, 0 and has color 1, 1, 1 and so on. Indices defines that order in which vertices are drawn (in this case vertices are drawn in the same order as they are defined).
11001108
11011109   Code for loading this data will loke like this:
11021110
11031111``` pascal
11041112 procedure TMesh.LoadMesh(FileName: String);
11051113 var
11061114 MeshFile: TextFile;
11071115 VertexCount, IndexCount: Integer;
11081116 iV, iI: Integer;
11091117 begin
11101118 FreeBuffers;
11111119
11121120 AssignFile(MeshFile, FileName);
11131121 Reset(MeshFile);
11141122
11151123 ReadLn(MeshFile, VertexCount, IndexCount);
11161124
11171125 SetLength(FVertices, VertexCount);
11181126 SetLength(FColors, VertexCount);
11191127 SetLength(FIndices, IndexCount);
11201128
11211129 for iV := 0 to VertexCount - 1 do
11221130 ReadLn(MeshFile,
11231131 FVertices[iV].X, FVertices[iV].Y, FVertices[iV].Z,
11241132 FColors[iV].R, FColors[iV].G, FColors[iV].B);
11251133
11261134 for iI := 0 to IndexCount - 1 do
11271135 ReadLn(MeshFile, FIndices[iI]);
11281136
11291137 CloseFile(MeshFile);
11301138 end;
11311139```
11321140
11331141   After loading data, we have everything for drawing:
11341142
11351143``` pascal
11361144 procedure TMesh.DrawMesh;
11371145 begin
11381146 glEnableClientState(GL_VERTEX_ARRAY);
11391147 glEnableClientState(GL_COLOR_ARRAY);
11401148 glVertexPointer(3, GL_FLOAT, 0, @FVertices[0]);
11411149 glColorPointer(3, GL_FLOAT, 0, @FColors[0]);
11421150
11431151 glDrawElements(GL_TRIANGLES, Length(FIndices), GL_UNSIGNED_INT, @FIndices[0]);
11441152
11451153 glDisableClientState(GL_VERTEX_ARRAY);
11461154 glDisableClientState(GL_COLOR_ARRAY);
11471155 end;
11481156```
11491157
11501158   As you can see, allmost everything is the same as for non-indexed drawing, except function that actually draw polygons. In this case we use **glDrawElements** function. For this one we specify what kind of polygons we want, how many indices are in index buffer, type of data in index buffer and pointer to the beginning of index buffer.
11511159
11521160   ![](/wiki-images/7/77/VertexArrayPic1.jpg)Full source code comes with mesh data file that this class can use to generates rectangle that is identical with one that is drawn using non-indexed mode. Mesh data file looks like this:
11531161
1154-`4 6`\
1155-`1 1 0 1 0 1`\
1156-`-1 1 0 0 0 1`\
1157-`-1 -1 0 0 1 0`\
1158-`1 -1 0 1 1 0`\
1159-`0`\
1160-`1`\
1161-`2`\
1162-`0`\
1163-`2`\
1164-`3`
1162+```text
1163+4 6
1164+1 1 0 1 0 1
1165+-1 1 0 0 0 1
1166+-1 -1 0 0 1 0
1167+1 -1 0 1 1 0
1168+0
1169+1
1170+2
1171+0
1172+2
1173+3
1174+```
11651175
11661176   As you can see, there is data for only 4 vertices and 6 indices. So, first triangle is defined by vertices 0, 1 and 2, and the seccond one by vertices 0, 2 and 3. By using indexed mode we don't have to duplicate vertices.
11671177
11681178   Download source code, linux executable or windows executable from [Lazarus CCR SourceForge](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=199145).
11691179
11701180------------------------------------------------------------------------
11711181
11721182[[Creating bindings for C libraries]]
11731183
11741184---
11751185*From the Free Pascal wiki, page "OpenGL Tutorial/es", as it stood on 2020-02-23 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
11761186Category: Castellano
11771187Category: Español
11781188Category: Example programs/es

Back to history