1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: Gas.cpp
4
5 Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Rev: 46365 $
14 *---------------------------------------------------------------------------*/
15
16 /*
17 *------------------------------------------------------------
18 * Copyright(c) 2009-2010 by Digital Media Professionals Inc.
19 * All rights reserved.
20 *------------------------------------------------------------
21 * This source code is the confidential and proprietary
22 * of Digital Media Professionals Inc.
23 *------------------------------------------------------------
24 */
25
26 #include <math.h>
27 #include "Gas.h"
28 #include "Util.h"
29
30 #include <assert.h>
31
32 extern GLuint pAccId;
33 extern GLuint pPostId;
34 extern struct gas_data gas;
35
36 /*
37 * Local definition
38 */
39 #define SHADING_WIDTH nn::gx::DISPLAY0_WIDTH
40 #define SHADING_HEIGHT nn::gx::DISPLAY0_HEIGHT
41 // SHADING_BUFFER uses the display buffer created by demo::RenderSystem.
42 // #define SHADING_BUFFER DISPLAY_BUFFER
43
44 /* buffer id */
45 static struct tagBufID
46 {
47 GLuint acc; /* frame buffer for accumulation */
48 GLuint shading; /* frame buffer for shading */
49 GLuint accColor; /* Color buffer for accumulation */
50 } gasbuf;
51
52 /* texture id */
53 GLuint gastex;
54
55 /* particle pattern file names */
56 static char* particle_files[PARTICLE_PATTERNS] = {PARTICLE_FILES};
57
58 /* vertex buffer id */
59 GLuint element_array_buffer_id;
60
61 /*=======================================================*/
62 /* buffer initialization */
63 /*=======================================================*/
GasInitialize(void)64 void GasInitialize(void)
65 {
66 /*
67 * Generate framebuffers and texture for gas rendering
68 */
69
70 /* generation */
71 glGenFramebuffers(1, (GLuint*)&gasbuf.acc);
72 glGenTextures(1, (GLuint*)&gastex);
73 glGenRenderbuffers(1, (GLuint*)&gasbuf.accColor);
74
75 /* set shading buffer
76 * shading buffer is DISPLAY_BUFFER */
77 // gasbuf.shading = SHADING_BUFFER;
78
79 /* initialize renderbuffer for color */
80 glBindRenderbuffer(GL_RENDERBUFFER, gasbuf.accColor);
81 glRenderbufferStorage(GL_RENDERBUFFER, GL_GAS_DMP, GAS_ACC_WIDTH, GAS_ACC_HEIGHT);
82
83 /* Attach renderbuffer to framebuffer */
84 glBindFramebuffer(GL_FRAMEBUFFER, gasbuf.acc);
85 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, gasbuf.accColor);
86
87 /*
88 * Initialize accumulation pow2 texture area (copy destination of accumulation result or shading result)
89 */
90 glBindTexture(GL_TEXTURE_2D, gastex);
91 glTexImage2D(GL_TEXTURE_2D, 0, GL_GAS_DMP, GAS_TEX_WIDTH, GAS_TEX_HEIGHT, 0, GL_GAS_DMP, GL_UNSIGNED_SHORT, 0);
92 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
93 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
94
95 /* element array buffer initialize */
96 GLushort index[4] = {0, 1, 2, 3};
97 glGenBuffers(1, &element_array_buffer_id);
98 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_array_buffer_id);
99 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLushort), &index[0], GL_STATIC_DRAW);
100 }
101 /*=======================================================*/
102 /* Setup of default gasesous object data structure */
103 /*=======================================================*/
DefaultGasObject(struct gas_data * gas,float * gasColorTable)104 void DefaultGasObject(struct gas_data *gas, float *gasColorTable)
105 {
106 gas->_dela_z = 5000.f;
107 gas->_autoAcc = GL_TRUE;
108 gas->_densMax = 1.0f;
109 gas->_lightDirX = 0.0f;
110 gas->_lightDirY = 0.0f;
111
112 gas->_LightXY[0] = 0.0f;
113 gas->_LightXY[1] = 0.0f;
114 gas->_LightXY[2] = 0.0f;
115 gas->_LightXY[3] = 0.0f; /* unsused */
116
117 gas->_LightZ[0] = 1.0f;
118 gas->_LightZ[1] = 0.0f;
119 gas->_LightZ[2] = 1.0f;
120 gas->_LightZ[3] = 1.0f;
121
122 gas->shadingDensitySrc = GL_GAS_DEPTH_DENSITY_DMP; /* GL_GAS_PLAIN_DENSITY_DMP/GL_GAS_DEPTH_DENSITY_DMP */
123 gas->colorLutInput = GL_GAS_DENSITY_DMP;
124
125 float dxt = 1.0f / 127.0f;
126 float xt = 0;
127 for (int i = 0; i < 128; i++)
128 {
129 gas->fogTable[i]= 1.0f - exp(-4.0f * xt);
130 xt += dxt;
131 }
132
133 for (int i = 0; i < 128; i++)
134 {
135 gas->fogTable[128 + i] = gas->fogTable[i + 1] - gas->fogTable[i];
136 }
137
138 gas->fogTable[255] = 0;
139 glGenTextures(1, &gas->CollectionLUT_ID);
140 glGenTextures(1, &gas->FogLut_ID);
141
142 glBindTexture(GL_TEXTURE_COLLECTION_DMP, gas->CollectionLUT_ID);
143 glBindTexture(GL_LUT_TEXTURE0_DMP, gas->FogLut_ID);
144 glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 256, 0, GL_LUMINANCEF_DMP, GL_FLOAT, gas->fogTable);
145
146 glGenTextures(3,&gas->gasTransfert_ID[0]);
147
148 SetGasColorTable(gas,gasColorTable);
149
150 float u0 = 0.0f;
151 float v0 = 0.0f;
152
153 float u1 = (GAS_ACC_WIDTH * 1.0f) / (GAS_TEX_WIDTH * 1.0f);
154 float v1 = (GAS_ACC_HEIGHT * 1.0f) / (GAS_TEX_HEIGHT * 1.0f);
155
156 GLfloat tex_unit[8]= {u0, v0, u0, v1, u1, v1, u1, v0};
157
158 GLfloat LX0, LY0, LX1, LY1;
159 LX0 = 0.0f;
160 LY0 = 0.0f;
161 LX1 = gas->_lightDirX;
162 LY1 = gas->_lightDirY;
163 GLfloat vertex_color[16] =
164 {
165 LX0, 0.0f, 0.0f, LY0,
166 LX0, 0.0f, 0.0f, LY1,
167 LX1, 0.0f, 0.0f, LY1,
168 LX1, 0.0f, 0.0f, LY0
169 };
170
171 GLushort _quadIndex[6] = {0, 1, 2, 0, 2, 3};
172 GLfloat vertex_unit[16] =
173 {
174 -1.0f, -1.0f, 0.0f, 1.0f,
175 -1.0f, 1.0f, 0.0f, 1.0f,
176 1.0f, 1.0f, 0.0f, 1.0f,
177 1.0f, -1.0f, 0.0f, 1.0f
178 };
179
180 glGenBuffers(1, &gas->quad_index_ID);
181 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gas->quad_index_ID);
182 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*sizeof(GLushort), &_quadIndex, GL_STATIC_DRAW);
183
184 glGenBuffers(1, &gas->quad_vertBuf_ID);
185 glBindBuffer(GL_ARRAY_BUFFER,gas->quad_vertBuf_ID);
186 glBufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), &vertex_unit, GL_STATIC_DRAW);
187
188 glGenBuffers(1, &gas->quad_texBuf_ID);
189 glBindBuffer(GL_ARRAY_BUFFER,gas->quad_texBuf_ID);
190 glBufferData(GL_ARRAY_BUFFER, 8*sizeof(GLfloat), &tex_unit, GL_STATIC_DRAW);
191
192 glGenBuffers(1, &gas->quad_colBuf_ID);
193 glBindBuffer(GL_ARRAY_BUFFER,gas->quad_colBuf_ID);
194 glBufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), &vertex_color, GL_STATIC_DRAW);
195
196 /*
197 * Load particle patterns
198 */
199 glGenTextures(PARTICLE_PATTERNS, &gas->pattern[0]);
200 for (int i = 0; i < PARTICLE_PATTERNS; i++)
201 {
202 bool alpha;
203 glBindTexture(GL_TEXTURE_2D, gas->pattern[i]);
204 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
205 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
206 loadTexture(particle_files[i], GL_TEXTURE_2D, 0, alpha);
207 }
208 }
209 /*=======================================================*/
210 /* Load Gas color lookup table */
211 /*=======================================================*/
SetGasColorTable(struct gas_data * gas,float * gasColorTable)212 void SetGasColorTable(struct gas_data *gas, float *gasColorTable)
213 {
214 glBindTexture(GL_TEXTURE_COLLECTION_DMP, gas->CollectionLUT_ID);
215 for(int i = 0; i < 8; i++)
216 {
217 gas->RR[i] = gasColorTable[3 * i + 0];
218 gas->GG[i] = gasColorTable[3 * i + 1];
219 gas->BB[i] = gasColorTable[3 * i + 2];
220
221 gas->RR[8 + i] = gasColorTable[3 * (i + 1) + 0] - gasColorTable[3 * i + 0];
222 gas->GG[8 + i] = gasColorTable[3 * (i + 1) + 1] - gasColorTable[3 * i + 1];
223 gas->BB[8 + i] = gasColorTable[3 * (i + 1) + 2] - gasColorTable[3 * i + 2];
224 }
225 gas->RR[15] = 0.0f;
226 gas->GG[15] = 0.0f;
227 gas->BB[15] = 0.0f;
228
229 glBindTexture(GL_LUT_TEXTURE1_DMP, gas->gasTransfert_ID[0]);
230 glTexImage1D(GL_LUT_TEXTURE1_DMP, 0, GL_LUMINANCEF_DMP, 16, 0, GL_LUMINANCEF_DMP, GL_FLOAT, gas->RR);
231
232 glBindTexture(GL_LUT_TEXTURE2_DMP, gas->gasTransfert_ID[1]);
233 glTexImage1D(GL_LUT_TEXTURE2_DMP, 0, GL_LUMINANCEF_DMP, 16, 0, GL_LUMINANCEF_DMP, GL_FLOAT, gas->GG);
234
235 glBindTexture(GL_LUT_TEXTURE3_DMP, gas->gasTransfert_ID[2]);
236 glTexImage1D(GL_LUT_TEXTURE3_DMP, 0, GL_LUMINANCEF_DMP, 16, 0, GL_LUMINANCEF_DMP, GL_FLOAT, gas->BB);
237 }
238
239 /*=======================================================*/
240 /* accumulation pass */
241 /*=======================================================*/
GasAccumulation()242 void GasAccumulation()
243 {
244 /*
245 * In accumulation pass, particles are accumulated into gas accumulation buffer as
246 * density information. This buffer is 'gasbuf.acc' in this sample.
247 * this buffer is exactly same size as DISPLAY_BUFFER (possible not to be
248 * pow2 size). So, for next pass, the accumulation result should be copy to pow2 size texture.
249 */
250
251 /* Bind accumulation buffer as a rendering target */
252 glBindFramebuffer(GL_FRAMEBUFFER, gasbuf.acc);
253 /* Set viewport */
254 glViewport(0, 0, GAS_ACC_WIDTH, GAS_ACC_HEIGHT);
255 /* Clear the buffer content (only color!) */
256 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
257 glClear(GL_COLOR_BUFFER_BIT);
258 /* use gas accumulation related program */
259 glUseProgram(pAccId);
260
261 /* misc state */
262 glDisable(GL_DEPTH_TEST);
263
264 glDisable(GL_CULL_FACE);
265
266 /* texture pattern binding */
267 /* assuming only 1 pattern */
268 glActiveTexture(GL_TEXTURE0);
269 glBindTexture(GL_TEXTURE_2D, gas.pattern[0]);
270
271 /* setup uniforms */
272 /* note that the program is shared with standard geometry to uniforms need to be reapply for each drawing call */
273 glUniform1i(glGetUniformLocation(pAccId, "dmp_Texture[0].samplerType"), GL_TEXTURE_2D);
274 glUniform1i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].combineRgb"), GL_MODULATE);
275 glUniform1i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].combineAlpha"), GL_MODULATE);
276 glUniform3i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_COLOR);
277 glUniform3i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
278 glUniform3i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].srcRgb"), GL_TEXTURE0, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR);
279 glUniform3i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].srcAlpha"), GL_TEXTURE0, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR);
280
281 /* Set the mode for the per fragment operation (gas accumulation mode) */
282 glUniform1i(glGetUniformLocation(pAccId, "dmp_FragOperation.mode"), GL_FRAGOP_MODE_GAS_ACC_DMP);
283
284 /* Set this value to control the accuracy of z intersection of surface and gaseous objects */
285 glUniform1f(glGetUniformLocation(pAccId, "dmp_Gas.deltaZ"), gas._dela_z);
286
287 glUniform1i(glGetUniformLocation(pAccId, "dmp_Fog.mode"), GL_FALSE);
288
289 nn::math::Matrix44 m;
290 nn::math::MTX44Transpose(&m, &gas.pSys.m_partsys_center);
291 glUniformMatrix4fv(glGetUniformLocation(pAccId, "uCenter"), 1, GL_FALSE, static_cast<f32*>(m));
292
293 nn::math::MTX44Transpose(&m, &gas.pSys.m_partsys_radius);
294 glUniformMatrix4fv(glGetUniformLocation(pAccId, "uRadii"), 1, GL_FALSE, static_cast<f32*>(m));
295
296 nn::math::MTX44Transpose(&m, &gas.pSys.m_partsys_color);
297 glUniformMatrix4fv(glGetUniformLocation(pAccId, "dmp_PartSys.color"), 1, GL_FALSE, static_cast<f32*>(m));
298
299 nn::math::MTX44Transpose(&m, &gas.pSys.m_partsys_aspect);
300 glUniformMatrix4fv(glGetUniformLocation(pAccId, "dmp_PartSys.aspect"), 1, GL_FALSE, static_cast<f32*>(m));
301
302 GLfloat viewport_size[2] = {0.0f, 0.0f};
303 viewport_size[0] = 1.f / (GLfloat)GAS_ACC_WIDTH;
304 viewport_size[1] = 1.f / (GLfloat)GAS_ACC_HEIGHT;
305 glUniform2fv(glGetUniformLocation(pAccId, "dmp_PartSys.viewport"), 1, &viewport_size[0]);
306
307 GLfloat distance_attenuation[3] = {0.0f, 0.0f, 0.0f};
308 distance_attenuation[0] = 0.0f;
309 distance_attenuation[1] = 0.0f;
310 distance_attenuation[2] = 1.0f / (float)(GAS_ACC_WIDTH * GAS_ACC_HEIGHT);
311
312 glUniform3fv(glGetUniformLocation(pAccId, "dmp_PartSys.distanceAttenuation"), 1, &distance_attenuation[0]);
313
314 glUniform1fv(glGetUniformLocation(pAccId, "dmp_PartSys.countMax"), 1, &gas.pSys.m_particleCountMax);
315 glUniform2fv(glGetUniformLocation(pAccId, "dmp_PartSys.pointSize"), 1, &gas.pSys.m_size_min_max[0]);
316 glUniform1fv(glGetUniformLocation(pAccId, "dmp_PartSys.speed"), 1, &gas.pSys.m_speed);
317
318 glUniform4fv(glGetUniformLocation(pAccId, "dmp_PartSys.randomCore"), 1, &gas.pSys.m_prng[0]);
319 glUniform4fv(glGetUniformLocation(pAccId, "dmp_PartSys.randSeed"), 1, &gas.pSys.m_random_seed[0]);
320
321 glUniform1fv(glGetUniformLocation(pAccId, "dmp_PartSys.time"), 1, &gas.pSys.simulationTime);
322
323 glEnableVertexAttribArray(0);
324 glBindBuffer(GL_ARRAY_BUFFER, gas.pSys.m_pSysPositionID);
325 glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, 0);
326 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_array_buffer_id);
327 glDrawElements(GL_GEOMETRY_PRIMITIVE_DMP, 4, GL_UNSIGNED_SHORT, 0);
328 glDisableVertexAttribArray(0);
329
330 glFinish();
331
332 /*
333 * Copy accumulation result to the texture buffer
334 */
335 glUniform1i(glGetUniformLocation(pAccId, "dmp_Texture[0].samplerType"), GL_TEXTURE_2D);
336 glBindTexture(GL_TEXTURE_2D, gastex);
337 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GAS_ACC_WIDTH, GAS_ACC_HEIGHT);
338 glFinish();
339
340 glBindTexture(GL_TEXTURE_2D, 0);
341 }
342
343 /*=======================================================*/
344 /* shading pass */
345 /*=======================================================*/
GasShading(void)346 void GasShading(void)
347 {
348 /*
349 * In shading pass, shaded gaseous image is blended to DISPLAY_BUFFER.
350 * Accumulated density information is used as a gas texture.
351 */
352
353 /* Bind shading buffer and set viewport
354 * shading buffer is DISPLAY_BUFFER */
355 // glBindFramebuffer(GL_FRAMEBUFFER, gasbuf.shading);
356 // glViewport(0, 0, SHADING_WIDTH, SHADING_HEIGHT);
357
358 /* use gas accumulation related program */
359 glUseProgram(pPostId);
360
361 /* Bind gas texture (accumulation result) */
362 glActiveTexture(GL_TEXTURE0);
363 glBindTexture(GL_TEXTURE_2D, gastex);
364
365 /* Setup blending unit #0
366 * r component of primary color has the influence of LIGHT_X and LIGHT_Y
367 * this output is transfered to FOG unit when FOG_MODE is set to GAS_DMP */
368 glUniform1i(glGetUniformLocation(pPostId, "dmp_Texture[0].samplerType"), GL_TEXTURE_2D);
369 glUniform1i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].combineRgb"), GL_ADD);
370 glUniform1i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].combineAlpha"), GL_ADD);
371 glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_COLOR);
372 glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
373 glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].srcRgb"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR);
374 glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].srcAlpha"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR);
375
376 /* Setup blending unit #5
377 * This is HW requirement. See specification document for more details
378 */
379 glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[5].srcRgb"), GL_PREVIOUS, GL_PREVIOUS, GL_TEXTURE0);
380 glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[5].srcAlpha"), GL_PREVIOUS, GL_PREVIOUS, GL_TEXTURE0);
381
382 /* setup of gas shading */
383 glUniform1i(glGetUniformLocation(pPostId, "dmp_Fog.sampler"), 0);
384 glUniform1i(glGetUniformLocation(pPostId, "dmp_Fog.mode"), GL_GAS_DMP);
385 glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.autoAcc"), 0);
386 glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.samplerTR"), 1);
387 glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.samplerTG"), 2);
388 glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.samplerTB"), 3);
389 glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.shadingDensitySrc"), gas.shadingDensitySrc);
390 glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.colorLutInput"), gas.colorLutInput);
391 glUniform1f(glGetUniformLocation(pPostId, "dmp_Gas.accMax"), gas._densMax);
392 glUniform4fv(glGetUniformLocation(pPostId, "dmp_Gas.lightZ"), 1, gas._LightZ);
393 glUniform3fv(glGetUniformLocation(pPostId, "dmp_Gas.lightXY"), 1, gas._LightXY);
394
395 glUniform1i(glGetUniformLocation(pPostId, "dmp_FragOperation.mode"), GL_FRAGOP_MODE_GL_DMP);
396
397 /*
398 * misc settings
399 */
400 glEnable(GL_BLEND);
401 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
402 glDisable(GL_DEPTH_TEST);
403 glDepthMask(0);
404
405 glBindTexture(GL_TEXTURE_COLLECTION_DMP, gas.CollectionLUT_ID);
406 glBindTexture(GL_TEXTURE_2D, gastex);
407
408 glEnableVertexAttribArray(0);
409 glEnableVertexAttribArray(1);
410 glEnableVertexAttribArray(2);
411
412 glBindBuffer(GL_ARRAY_BUFFER, gas.quad_vertBuf_ID);
413 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
414
415 glBindBuffer(GL_ARRAY_BUFFER, gas.quad_texBuf_ID);
416 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
417
418 glBindBuffer(GL_ARRAY_BUFFER, gas.quad_colBuf_ID);
419 glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, 0);
420
421 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gas.quad_index_ID);
422 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
423
424 glDisableVertexAttribArray(0);
425 glDisableVertexAttribArray(1);
426 glDisableVertexAttribArray(2);
427
428 glDisable(GL_BLEND);
429 glEnable(GL_DEPTH_TEST);
430 glDepthFunc(GL_LESS);
431
432 glDisable(GL_CULL_FACE);
433 glFrontFace(GL_CCW);
434 glCullFace(GL_BACK);
435 }
436
437