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