/*---------------------------------------------------------------------------* Project: Horizon File: Gas.cpp Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 46365 $ *---------------------------------------------------------------------------*/ /* *------------------------------------------------------------ * 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}; /* vertex buffer id */ GLuint element_array_buffer_id; /*=======================================================*/ /* buffer initialization */ /*=======================================================*/ void GasInitialize(void) { /* * 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 * shading buffer is DISPLAY_BUFFER */ // gasbuf.shading = SHADING_BUFFER; /* 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); /* * 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); /* element array buffer initialize */ GLushort index[4] = {0, 1, 2, 3}; glGenBuffers(1, &element_array_buffer_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_array_buffer_id); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLushort), &index[0], GL_STATIC_DRAW); } /*=======================================================*/ /* Setup of default gasesous object data structure */ /*=======================================================*/ void DefaultGasObject(struct gas_data *gas, float *gasColorTable) { gas->_dela_z = 5000.f; gas->_autoAcc = GL_TRUE; gas->_densMax = 1.0f; gas->_lightDirX = 0.0f; gas->_lightDirY = 0.0f; gas->_LightXY[0] = 0.0f; gas->_LightXY[1] = 0.0f; gas->_LightXY[2] = 0.0f; gas->_LightXY[3] = 0.0f; /* unsused */ gas->_LightZ[0] = 1.0f; gas->_LightZ[1] = 0.0f; gas->_LightZ[2] = 1.0f; gas->_LightZ[3] = 1.0f; gas->shadingDensitySrc = GL_GAS_DEPTH_DENSITY_DMP; /* GL_GAS_PLAIN_DENSITY_DMP/GL_GAS_DEPTH_DENSITY_DMP */ gas->colorLutInput = GL_GAS_DENSITY_DMP; float dxt = 1.0f / 127.0f; float xt = 0; for (int i = 0; i < 128; i++) { gas->fogTable[i]= 1.0f - exp(-4.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); } /*=======================================================*/ /* 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. * 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); /* 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); /* use gas accumulation related program */ glUseProgram(pAccId); /* misc state */ glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); /* texture pattern binding */ /* assuming only 1 pattern */ glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, gas.pattern[0]); /* setup uniforms */ /* note that the program is shared with standard geometry to uniforms need to be reapply for each drawing call */ 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_MODULATE); glUniform3i(glGetUniformLocation(pAccId, "dmp_TexEnv[0].operandRgb"), GL_SRC_COLOR, GL_SRC_ALPHA, 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); nn::math::Matrix44 m; nn::math::MTX44Transpose(&m, &gas.pSys.m_partsys_center); glUniformMatrix4fv(glGetUniformLocation(pAccId, "uCenter"), 1, GL_FALSE, static_cast(m)); nn::math::MTX44Transpose(&m, &gas.pSys.m_partsys_radius); glUniformMatrix4fv(glGetUniformLocation(pAccId, "uRadii"), 1, GL_FALSE, static_cast(m)); nn::math::MTX44Transpose(&m, &gas.pSys.m_partsys_color); glUniformMatrix4fv(glGetUniformLocation(pAccId, "dmp_PartSys.color"), 1, GL_FALSE, static_cast(m)); nn::math::MTX44Transpose(&m, &gas.pSys.m_partsys_aspect); glUniformMatrix4fv(glGetUniformLocation(pAccId, "dmp_PartSys.aspect"), 1, GL_FALSE, static_cast(m)); GLfloat viewport_size[2] = {0.0f, 0.0f}; viewport_size[0] = 1.f / (GLfloat)GAS_ACC_WIDTH; viewport_size[1] = 1.f / (GLfloat)GAS_ACC_HEIGHT; glUniform2fv(glGetUniformLocation(pAccId, "dmp_PartSys.viewport"), 1, &viewport_size[0]); GLfloat distance_attenuation[3] = {0.0f, 0.0f, 0.0f}; distance_attenuation[0] = 0.0f; distance_attenuation[1] = 0.0f; distance_attenuation[2] = 1.0f / (float)(GAS_ACC_WIDTH * GAS_ACC_HEIGHT); glUniform3fv(glGetUniformLocation(pAccId, "dmp_PartSys.distanceAttenuation"), 1, &distance_attenuation[0]); glUniform1fv(glGetUniformLocation(pAccId, "dmp_PartSys.countMax"), 1, &gas.pSys.m_particleCountMax); glUniform2fv(glGetUniformLocation(pAccId, "dmp_PartSys.pointSize"), 1, &gas.pSys.m_size_min_max[0]); glUniform1fv(glGetUniformLocation(pAccId, "dmp_PartSys.speed"), 1, &gas.pSys.m_speed); glUniform4fv(glGetUniformLocation(pAccId, "dmp_PartSys.randomCore"), 1, &gas.pSys.m_prng[0]); glUniform4fv(glGetUniformLocation(pAccId, "dmp_PartSys.randSeed"), 1, &gas.pSys.m_random_seed[0]); glUniform1fv(glGetUniformLocation(pAccId, "dmp_PartSys.time"), 1, &gas.pSys.simulationTime); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, gas.pSys.m_pSysPositionID); glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_array_buffer_id); glDrawElements(GL_GEOMETRY_PRIMITIVE_DMP, 4, GL_UNSIGNED_SHORT, 0); glDisableVertexAttribArray(0); glFinish(); /* * Copy accumulation result to the texture buffer */ glUniform1i(glGetUniformLocation(pAccId, "dmp_Texture[0].samplerType"), GL_TEXTURE_2D); 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. */ /* Bind shading buffer and set viewport * shading buffer is DISPLAY_BUFFER */ // 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); /* 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_ADD); 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"), 0); 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); /* * 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); }