/* *------------------------------------------------------------ * Copyright(c) 2009-2010 by Digital Media Professionals Inc. * All rights reserved. *------------------------------------------------------------ * This source code is the confidential and proprietary * of Digital Media Professionals Inc. *------------------------------------------------------------ */ #include #include "Gas.h" #include "Util.h" #include extern GLuint pAccId; extern GLuint pPostId; extern struct gas_data gas; /* * Local definition */ #define SHADING_WIDTH nn::gx::DISPLAY0_WIDTH #define SHADING_HEIGHT nn::gx::DISPLAY0_HEIGHT // SHADING_BUFFER uses the display buffer created by demo::RenderSystem. // #define SHADING_BUFFER DISPLAY_BUFFER /* buffer id */ static struct tagBufID { GLuint acc; /* frame buffer for accumulation */ GLuint shading; /* frame buffer for shading */ GLuint accColor; /* Color buffer for accumulation */ } gasbuf; /* texture id */ GLuint gastex; /* particle pattern file names */ static char* particle_files[PARTICLE_PATTERNS] = {PARTICLE_FILES}; /*=======================================================*/ /* buffer initialization */ /*=======================================================*/ void GasInitialize(GLuint depthBuf) { /* * Generate framebuffers and texture for gas rendering */ /* generation */ glGenFramebuffers(1, (GLuint*)&gasbuf.acc); glGenTextures(1, (GLuint*)&gastex); glGenRenderbuffers(1, (GLuint*)&gasbuf.accColor); /* set shading buffer * In GAS_CONFIG_SIMPLE case, shading buffer is DISPLAY_BUFFER * and in GAS_CONFIG_OPTIMAL case, shading buffer is accumulation buffer(reused) */ // gasbuf.shading = SHADING_BUFFER; /* * Initialize accumulation buffer (destination of gas accumulation rendering) * (in GAS_CONFIG_OPTIMAL case, this buffer is reused as a destination of shading) */ /* initialize renderbuffer for color */ glBindRenderbuffer(GL_RENDERBUFFER, gasbuf.accColor); glRenderbufferStorage(GL_RENDERBUFFER, GL_GAS_DMP, GAS_ACC_WIDTH, GAS_ACC_HEIGHT); /* Attach renderbuffer to framebuffer */ glBindFramebuffer(GL_FRAMEBUFFER, gasbuf.acc); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, gasbuf.accColor); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthBuf); /* * Initialize accumulation pow2 texture area (copy destination of accumulation result or shading result) */ glBindTexture(GL_TEXTURE_2D, gastex); glTexImage2D(GL_TEXTURE_2D, 0, GL_GAS_DMP, GAS_TEX_WIDTH, GAS_TEX_HEIGHT, 0, GL_GAS_DMP, GL_UNSIGNED_SHORT, 0); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); } /*=======================================================*/ /* Setup of default gasesous object data structure */ /*=======================================================*/ void DefaultGasObject(struct gas_data *gas, float *gasColorTable) { gas->_dela_z = 100.0f; gas->_autoAcc = GL_TRUE; gas->_densMax = 1.0f/6.0f; gas->_lightDirX = 0.5f; gas->_lightDirY = 0.5f; gas->_LightXY[0] = 0.0f; gas->_LightXY[1] = 0.3f; gas->_LightXY[2] = 1.0f; gas->_LightXY[3] = 0.0f; /* unsused */ gas->_LightZ[0] = 0.0f; gas->_LightZ[1] = 1.0f; gas->_LightZ[2] = 0.5f; gas->_LightZ[3] = 1.0f; gas->shadingDensitySrc = GL_GAS_DEPTH_DENSITY_DMP; /* GL_GAS_DEPTH_DENSITY_DMP/GL_GAS_PLAIN_DENSITY_DMP */ gas->colorLutInput = GL_GAS_DENSITY_DMP; /* GL_GAS_DENSITY_DMP/GL_GAS_LIGHT_FACTOR_DMP */ float dxt = 1.0f / 127.0f; float xt = 0; for (int i = 0; i < 128; i++) { gas->fogTable[i]= 1.0f - exp(-8.0f * xt); xt += dxt; } for (int i = 0; i < 128; i++) { gas->fogTable[128 + i] = gas->fogTable[i + 1] - gas->fogTable[i]; } gas->fogTable[255] = 0; glGenTextures(1, &gas->CollectionLUT_ID); glGenTextures(1, &gas->FogLut_ID); glBindTexture(GL_TEXTURE_COLLECTION_DMP, gas->CollectionLUT_ID); glBindTexture(GL_LUT_TEXTURE0_DMP, gas->FogLut_ID); glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 256, 0, GL_LUMINANCEF_DMP, GL_FLOAT, gas->fogTable); glGenTextures(3,&gas->gasTransfert_ID[0]); SetGasColorTable(gas,gasColorTable); float u0 = 0.0f; float v0 = 0.0f; float u1 = (GAS_ACC_WIDTH * 1.0f) / (GAS_TEX_WIDTH * 1.0f); float v1 = (GAS_ACC_HEIGHT * 1.0f) / (GAS_TEX_HEIGHT * 1.0f); GLfloat tex_unit[8]= {u0, v0, u0, v1, u1, v1, u1, v0}; GLfloat LX0, LY0, LX1, LY1; LX0 = 0.0f; LY0 = 0.0f; LX1 = gas->_lightDirX; LY1 = gas->_lightDirY; GLfloat vertex_color[16] = { LX0, 0.0f, 0.0f, LY0, LX0, 0.0f, 0.0f, LY1, LX1, 0.0f, 0.0f, LY1, LX1, 0.0f, 0.0f, LY0 }; GLushort _quadIndex[6] = {0, 1, 2, 0, 2, 3}; GLfloat vertex_unit[16] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f }; glGenBuffers(1, &gas->quad_index_ID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gas->quad_index_ID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*sizeof(GLushort), &_quadIndex, GL_STATIC_DRAW); glGenBuffers(1, &gas->quad_vertBuf_ID); glBindBuffer(GL_ARRAY_BUFFER,gas->quad_vertBuf_ID); glBufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), &vertex_unit, GL_STATIC_DRAW); glGenBuffers(1, &gas->quad_texBuf_ID); glBindBuffer(GL_ARRAY_BUFFER,gas->quad_texBuf_ID); glBufferData(GL_ARRAY_BUFFER, 8*sizeof(GLfloat), &tex_unit, GL_STATIC_DRAW); glGenBuffers(1, &gas->quad_colBuf_ID); glBindBuffer(GL_ARRAY_BUFFER,gas->quad_colBuf_ID); glBufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), &vertex_color, GL_STATIC_DRAW); /* * Load particle patterns */ glGenTextures(PARTICLE_PATTERNS, &gas->pattern[0]); for (int i = 0; i < PARTICLE_PATTERNS; i++) { bool alpha; glBindTexture(GL_TEXTURE_2D, gas->pattern[i]); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); loadTexture(particle_files[i], GL_TEXTURE_2D, 0, alpha); } } /*=======================================================*/ /* Load Gas color lookup table */ /*=======================================================*/ void SetGasColorTable(struct gas_data *gas, float *gasColorTable) { glBindTexture(GL_TEXTURE_COLLECTION_DMP, gas->CollectionLUT_ID); for(int i = 0; i < 8; i++) { gas->RR[i] = gasColorTable[3 * i + 0]; gas->GG[i] = gasColorTable[3 * i + 1]; gas->BB[i] = gasColorTable[3 * i + 2]; gas->RR[8 + i] = gasColorTable[3 * (i + 1) + 0] - gasColorTable[3 * i + 0]; gas->GG[8 + i] = gasColorTable[3 * (i + 1) + 1] - gasColorTable[3 * i + 1]; gas->BB[8 + i] = gasColorTable[3 * (i + 1) + 2] - gasColorTable[3 * i + 2]; } gas->RR[15] = 0.0f; gas->GG[15] = 0.0f; gas->BB[15] = 0.0f; glBindTexture(GL_LUT_TEXTURE1_DMP, gas->gasTransfert_ID[0]); glTexImage1D(GL_LUT_TEXTURE1_DMP, 0, GL_LUMINANCEF_DMP, 16, 0, GL_LUMINANCEF_DMP, GL_FLOAT, gas->RR); glBindTexture(GL_LUT_TEXTURE2_DMP, gas->gasTransfert_ID[1]); glTexImage1D(GL_LUT_TEXTURE2_DMP, 0, GL_LUMINANCEF_DMP, 16, 0, GL_LUMINANCEF_DMP, GL_FLOAT, gas->GG); glBindTexture(GL_LUT_TEXTURE3_DMP, gas->gasTransfert_ID[2]); glTexImage1D(GL_LUT_TEXTURE3_DMP, 0, GL_LUMINANCEF_DMP, 16, 0, GL_LUMINANCEF_DMP, GL_FLOAT, gas->BB); } void SetGasAccumulationUniform(void) { glUseProgram(pAccId); glUniform1i(glGetUniformLocation(pAccId, "dmp_Texture[0].samplerType"), GL_TEXTURE_2D); glUniform1i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].combineRgb"), GL_MODULATE); glUniform1i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].combineAlpha"), GL_REPLACE); glUniform3i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR); glUniform3i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA); glUniform3i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].srcRgb"), GL_TEXTURE0, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR); glUniform3i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].srcAlpha"), GL_TEXTURE0, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR); /* Set the mode for the per fragment operation (gas accumulation mode) */ glUniform1i(glGetUniformLocation(pAccId, "dmp_FragOperation.mode"), GL_FRAGOP_MODE_GAS_ACC_DMP); /* Set this value to control the accuracy of z intersection of surface and gaseous objects */ glUniform1f(glGetUniformLocation(pAccId, "dmp_Gas.deltaZ"),gas._dela_z); glUniform1i(glGetUniformLocation(pAccId, "dmp_Fog.mode"), GL_FALSE); float wh[2] = {0}; wh[0] = 1.f / (float)GAS_ACC_WIDTH; wh[1] = 1.f / (float)GAS_ACC_HEIGHT; glUniform2fv ( glGetUniformLocation ( pAccId, "dmp_Point.viewport" ), 1, wh ) ; glUniform1i(glGetUniformLocation(pAccId, "dmp_Point.distanceAttenuation"), GL_TRUE); } void SetGasShadingUniform(void) { glUseProgram(pPostId); /* Setup blending unit #0 * r component of primary color has the influence of LIGHT_X and LIGHT_Y * this output is transfered to FOG unit when FOG_MODE is set to GAS_DMP */ glUniform1i(glGetUniformLocation(pPostId, "dmp_Texture[0].samplerType"), GL_TEXTURE_2D); glUniform1i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].combineRgb"), GL_REPLACE); glUniform1i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].combineAlpha"), GL_ADD); glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_COLOR); glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA); glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].srcRgb"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR); glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[0].srcAlpha"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR); /* Setup blending unit #5 * This is HW requirement. See specification document for more details */ glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[5].srcRgb"), GL_PREVIOUS, GL_PREVIOUS, GL_TEXTURE0); glUniform3i(glGetUniformLocation(pPostId, "dmp_TexEnv[5].srcAlpha"), GL_PREVIOUS, GL_PREVIOUS, GL_TEXTURE0); /* setup of gas shading */ glUniform1i(glGetUniformLocation(pPostId, "dmp_Fog.sampler"), 0); glUniform1i(glGetUniformLocation(pPostId, "dmp_Fog.mode"), GL_GAS_DMP); glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.autoAcc"), gas._autoAcc); glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.samplerTR"), 1); glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.samplerTG"), 2); glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.samplerTB"), 3); glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.shadingDensitySrc"), gas.shadingDensitySrc); glUniform1i(glGetUniformLocation(pPostId, "dmp_Gas.colorLutInput"), gas.colorLutInput); glUniform1f(glGetUniformLocation(pPostId, "dmp_Gas.accMax"), gas._densMax); glUniform4fv(glGetUniformLocation(pPostId, "dmp_Gas.lightZ"), 1, gas._LightZ); glUniform3fv(glGetUniformLocation(pPostId, "dmp_Gas.lightXY"), 1, gas._LightXY); glUniform1i(glGetUniformLocation(pPostId, "dmp_FragOperation.mode"), GL_FRAGOP_MODE_GL_DMP); } /*=======================================================*/ /* accumulation pass */ /*=======================================================*/ void GasAccumulation() { /* * In accumulation pass, particles are accumulated into gas accumulation buffer as * density information. This buffer is 'gasbuf.acc' in this sample. In GAS_CONFIG_SIMPLE * configuration, this buffer is exactly same size as DISPLAY_BUFFER (possible not to be * pow2 size). So, for next pass, the accumulation result should be copy to pow2 size texture. */ /* Bind accumulation buffer as a rendering target */ glBindFramebuffer(GL_FRAMEBUFFER, gasbuf.acc); /* use gas accumulation related program */ glUseProgram(pAccId); /* Set viewport */ glViewport(0, 0, GAS_ACC_WIDTH, GAS_ACC_HEIGHT); /* Clear the buffer content (only color!) */ glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); /* misc state */ glDisable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glDisable(GL_CULL_FACE); glFrontFace(GL_CCW); glCullFace(GL_BACK); /* texture pattern binding */ /* assuming only 1 pattern */ glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, gas.pattern[0]); /* * Setup buffer */ glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, gas.gasgeo_center_ID); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, gas.gasgeo_density_ID); glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, gas.gasgeo_size_ID); glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_GEOMETRY_PRIMITIVE_DMP, 0,gas.gasgeo_size); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); glFinish(); /* * Copy accumulation result to the texture buffer */ glBindTexture(GL_TEXTURE_2D, gastex); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GAS_ACC_WIDTH, GAS_ACC_HEIGHT); glFinish(); glBindTexture(GL_TEXTURE_2D, 0); } /*=======================================================*/ /* shading pass */ /*=======================================================*/ void GasShading(void) { /* * In shading pass, shaded gaseous image is blended to DISPLAY_BUFFER. * Accumulated density information is used as a gas texture. * Note that in GAS_CONFIG_OPTIMAL case, DISPLAY_BUFFER is defferent size * from gas texture and PICA does not support filter for gas format texture. * So gaseous shaded image is rendered to another buffer and then blend to * DIPLAY_BUFFER. */ /* Bind shading buffer and set viewport * In GAS_CONFIG_SIMPLE case, shading buffer is DISPLAY_BUFFER * and in GAS_CONFIG_OPTIMAL case, shading buffer is accumulation buffer(reused) */ // glBindFramebuffer(GL_FRAMEBUFFER, gasbuf.shading); // glViewport(0, 0, SHADING_WIDTH, SHADING_HEIGHT); /* use gas accumulation related program */ glUseProgram(pPostId); /* Bind gas texture (accumulation result) */ glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, gastex); /* * misc settings */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DEPTH_TEST); glDepthMask(0); glBindTexture(GL_TEXTURE_COLLECTION_DMP, gas.CollectionLUT_ID); glBindTexture(GL_TEXTURE_2D, gastex); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, gas.quad_vertBuf_ID); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, gas.quad_texBuf_ID); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, gas.quad_colBuf_ID); glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gas.quad_index_ID); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glDisable(GL_CULL_FACE); glFrontFace(GL_CCW); glCullFace(GL_BACK); }