/* renders subset of billboards array */ void render_billboards(unsigned int i) { if (i >= g_context.iterationCount) return; Vertex* vbuffer = g_context.vbuffer[i%NUM_VERTEX_BUFFERS]; int sliceCount = NUM_SLICES / g_context.iterationCount; // fill current vertex buffer if we just started if (i == 0) { create_modified_torus_billboards(vbuffer,(float*)&g_context.world, g_context.sint, sliceCount*i, sliceCount); } // render previously generated vertex buffer sceGumMatrixMode(GU_MODEL); sceGumLoadMatrix(&g_context.world); sceGumDrawArray(GU_SPRITES,GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D,sliceCount*NUM_ROWS*2,0,vbuffer); g_context.vertsRendered += sliceCount*NUM_ROWS*2; // fill next vertex buffer for future rendering int nextI = i + 1; if (nextI < g_context.iterationCount ) { Vertex* vbufferNext; vbufferNext = g_context.vbuffer[nextI%NUM_VERTEX_BUFFERS]; create_modified_torus_billboards(vbufferNext,(float*)&g_context.world, g_context.sint, sliceCount*nextI, sliceCount); } #ifdef USING_SIGNALS // send a signal when rendering was completed // signals 0x01..0x03 - seems to be available for custom usage sceGuSignal( 1, nextI ); // HACK: keeps CPU waiting until all jobs were submitted for GPU if (nextI == g_context.iterationCount) sceGuFinish(); #endif }
void VertexBufferRenderer::setup(Mesh &obj, bool init_texcoord) { // special lights which have been bound that contribute to texturing // unsigned int tex_offset = Texture::tex_use+1; #if !defined(OPENGL_ES) && !defined(ARCH_DC) if (obj.buffer_state && lockObj != &obj) { // Bind the vertex buffers from the cache data glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, obj.cache_data.elementBufferNum); glBindBuffer(GL_ARRAY_BUFFER_ARB, obj.cache_data.dataBufferNum); // set the vertex pointer glVertexPointer(3,GL_FLOAT,0,BUFFER_OFFSET(0)); glEnableClientState(GL_VERTEX_ARRAY); // set the normal pointer glNormalPointer(GL_FLOAT,0,BUFFER_OFFSET(obj.normalCacheOffset)); glEnableClientState(GL_NORMAL_ARRAY); // activate uv map pointers for multitexture layers if (init_texcoord) { for (unsigned int m = 0; m < obj.cache_data.max_uvs; m++) { Texture::setTexture(m); glTexCoordPointer(2, GL_FLOAT, 0, BUFFER_OFFSET(obj.uvCacheOffset+(sizeof(va_uv)*obj.cache_data.vertex_count*m))); } glEnableClientState(GL_TEXTURE_COORD_ARRAY); } } else #endif if (lockObj != &obj) { #if !defined(OPENGL_ES) && !defined(ARCH_DC) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB); glUnmapBuffer(GL_ARRAY_BUFFER_ARB); #endif if (obj.hasColorMap) { glColorPointer(3, GL_FLOAT, 0, (const GLvoid *)(obj.cache_data.data+(obj.colorMapOffset))); } glVertexPointer(3, GL_FLOAT, 0, (const GLvoid *)obj.cache_data.data); glEnableClientState(GL_VERTEX_ARRAY); #ifndef ARCH_DC // DC doesn't process normals glNormalPointer(GL_FLOAT, 0, (const GLvoid *)(obj.cache_data.data+(obj.normalCacheOffset))); glEnableClientState(GL_NORMAL_ARRAY); #endif if (init_texcoord) { for (unsigned int m = 0; m < obj.cache_data.max_uvs; m++) { Texture::setTexture(m); glTexCoordPointer(2, GL_FLOAT, 0, (const GLvoid *)(obj.cache_data.data+obj.uvCacheOffset+(sizeof(va_uv)*obj.cache_data.vertex_count*m))); } glEnableClientState(GL_TEXTURE_COORD_ARRAY); } } if (obj.dynamic_colors) // Mostly just for Dreamcast lighting at the moment { glColorPointer(3, GL_FLOAT, 0, (const GLvoid *)obj.dynamic_colors); glEnableClientState(GL_COLOR_ARRAY); } #ifdef ARCH_PSP sceGuSignal(GU_BEHAVIOR_SUSPEND, 2); #endif lockObj = &obj; }
void VertexBufferRenderer::render(Mesh &obj, int stage) { #define BUFFER_OFFSET(i) ((char *)NULL + (i)) // mat_reflist_i -- used to iterate through the material mat_reflist of the object std::map<Material *, map< unsigned int, std::map<cvrIndex, va_ref, ltindex>, ltuint > >::iterator obj_matref_i; // segment iterator map< unsigned int, std::map<cvrIndex, va_ref, ltindex>, ltuint >::iterator mat_segment_type_i; // mat_facetypelist_i -- used to iterate through the set of face types which belong to the mat_reflist_i map std::map<cvrIndex, va_ref, ltindex>::iterator matref_type_i; // mat_facetypelist_i -- used to iterate through the set of face types which belong to the mat_reflist_i map std::map<cvrIndex, va_ref, ltindex>::reverse_iterator matref_last_i; bool has_trans = false; unsigned int element_index = 0; unsigned int shadow_count = 0; Material *mat; set<Light *>::iterator light_i; if (!obj.buffer_state) element_index = (unsigned long)obj.cache_data.cache_element; // Reset mutitexture state Texture::clearAllTextures(); // special lights which have been bound that contribute to texturing unsigned int tex_offset = Texture::tex_use+1; //#if !defined(OPENGL_ES) && !defined(ARCH_DC) // store attribs // glPushAttrib(GL_ENABLE_BIT); //#endif #ifndef ARCH_PSP VertexBufferRenderer::setup(obj,stage != SHADER_STAGE_NOMATERIAL && stage != SHADER_STAGE_NOTEXTURE); #else sceGuSignal(GU_BEHAVIOR_SUSPEND, 1); #endif // iterate through the list of materials with face reference sets for (obj_matref_i = obj.mat_cache_data.begin(); obj_matref_i != obj.mat_cache_data.end(); obj_matref_i++) { // (*obj_matref_i).first // material reference bool mat_use = false; mat = (*obj_matref_i).first; // store material transparency state bool has_mask = mat->hasMask(); unsigned int segLimit = (*obj_matref_i).second.size(); unsigned int segIndex = 0; unsigned int segRun = 0; unsigned int segRangeIndex = 0; unsigned int segRangeType = 0; unsigned int segElementIndex = 0; bool fault = false; bool usefault = (obj.numSegments != 1); // assume objects with one segment don't need segment fault tests //true; //((*mat_segment_type_i).second.size()==1 && (*obj_matref_i).second.size()!=1); va_ref segRange; segRange.range_min = obj.cache_data.vertex_count; segRange.range_max = 0; segRange.element_count = 0; segRangeIndex = element_index; for (mat_segment_type_i = (*obj_matref_i).second.begin(); mat_segment_type_i != (*obj_matref_i).second.end(); mat_segment_type_i++) { segIndex++; if (stage == SHADER_STAGE_TRANSPARENT) // we're in the transparency stage and opaque isn't needed, we have to increase the element count though { if (!has_mask) { element_index += (*(*mat_segment_type_i).second.begin()).second.group_size*sizeof(cvrElement); segIndex++; continue; } } else if (stage == SHADER_STAGE_NULL || stage == SHADER_STAGE_OPAQUE || stage == SHADER_STAGE_NOTEXTURE) { if (has_mask) // vice-versa { element_index += (*(*mat_segment_type_i).second.begin()).second.group_size*sizeof(cvrElement); has_trans = true; segIndex++; continue; } } if (obj.numSegments >= 1 && obj.segmentMask) { if (obj.segmentMask->isSet((*mat_segment_type_i).first) == false) { fault = true; } } segRangeType = (*(*mat_segment_type_i).second.begin()).first; if (fault) { element_index += (*(*mat_segment_type_i).second.begin()).second.group_size*sizeof(cvrElement); if (!usefault) { fault=false; continue; } } else { segRun++; segRange.element_count += (*(*mat_segment_type_i).second.begin()).second.group_size; if ((*(*mat_segment_type_i).second.begin()).second.range_min < segRange.range_min) { segRange.range_min = (*(*mat_segment_type_i).second.begin()).second.range_min; } if ((*(*mat_segment_type_i).second.begin()).second.range_max > segRange.range_max) { segRange.range_max = (*(*mat_segment_type_i).second.begin()).second.range_max; } if (usefault) if (segIndex < segLimit) { element_index += (*(*mat_segment_type_i).second.begin()).second.group_size*sizeof(cvrElement); continue; } } //**** Material Initialization *****/ if (!mat_use) { mat_use = true; // if we're in the opaque shader stage then we need to discard the transparent materials and vice versa // transparent shader stage if (stage == SHADER_STAGE_TRANSPARENT) { // alpha mask if (has_mask) { if (stage == SHADER_STAGE_NOTEXTURE) // no texture { mat->surfaceSetup(); } else // full material { mat->use(); } } } else if (stage == SHADER_STAGE_NULL || stage == SHADER_STAGE_OPAQUE || stage == SHADER_STAGE_NOTEXTURE) { if (!has_mask) // we're in the transparency stage and opaque isn't needed, we have to increase the element count though { // no texturing, just use the surface setup for colors and transparencies if (stage == SHADER_STAGE_NOTEXTURE) { mat->surfaceSetup(); } else // else full material { mat->use(); } } } #ifndef ARCH_PSP // the active texcoord states change on a per material basis if (stage != SHADER_STAGE_NOMATERIAL && stage != SHADER_STAGE_NOTEXTURE) for (unsigned int m = 0; m < obj.cache_data.max_uvs; m++) { Texture::setTexture(tex_offset+m); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } #endif #ifndef ARCH_PSP if (obj.cache_data.max_uvs == 0) { Texture::setTexture(tex_offset); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } #endif if (stage == SHADER_STAGE_TRANSPARENT) { mat->setupAlpha(); } else if (mat->alpha_mask) { mat->setupAlpha(); } } shadow_count = 0; int numLights = 0; #ifdef ARCH_PSP // sceGuDepthFunc( GU_GEQUAL ); #else glDepthFunc(GL_LEQUAL); #endif numLights = lights?(*lights).size():0; if (numLights) { light_i = lights->begin(); } // if (obj.tangent_binormal_state) // { // GLShader::defaultShader.setShaderAttrib("binormal",(unsigned int)BUFFER_OFFSET(obj.binormalCacheOffset)); // GLShader::defaultShader.setShaderAttrib("tangent",(unsigned int)BUFFER_OFFSET(obj.binormalCacheOffset)); // } // printf("vb numLights %d\n",(*lights).size()); #if !defined(OPENGL_ES) && !defined(ARCH_DC) && !defined(ARCH_PSP)// shader light loop header RGB global_amb_temp = Light::global_ambient; for (int shaderCount = 0; shaderCount <= numLights; shaderCount++) { unsigned long shadowMask = 0; if (shaderCount < numLights) { if ((mat->shader_mask & SHADER_VARIANT_LIGHTMAP) && shaderCount > 0) mat->shader_mask -= SHADER_VARIANT_LIGHTMAP; if (shaderCount > 0) { glEnable(GL_BLEND); glDepthMask(false); Light::setGlobalAmbient(RGB(0,0,0)); if (stage == SHADER_STAGE_TRANSPARENT) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); } else { glBlendFunc(GL_ONE, GL_ONE); } } else { glDepthMask(true); if (stage == SHADER_STAGE_TRANSPARENT) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(false); } else { glDisable(GL_BLEND); } } if ((*light_i)->has_shadow) { switch ((*light_i)->type) { case LIGHT_SPOT: glActiveTexture(GL_TEXTURE0+(*light_i)->shadow_mtex); glClientActiveTexture(GL_TEXTURE0+(*light_i)->shadow_mtex); GLShader::defaultShader.setShaderValue("shadowMap0", (*light_i)->shadow_mtex); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, (*light_i)->shadowmapTex); switch (shadow_count) { case 0: shadowMask |= SHADER_VARIANT_SHADOW0; break; case 1: shadowMask |= SHADER_VARIANT_SHADOW1; break; case 2: shadowMask |= SHADER_VARIANT_SHADOW2; break; case 3: shadowMask |= SHADER_VARIANT_SHADOW3; break; case 4: shadowMask |= SHADER_VARIANT_SHADOW4; break; case 5: shadowMask |= SHADER_VARIANT_SHADOW5; break; case 6: shadowMask |= SHADER_VARIANT_SHADOW6; break; case 7: shadowMask |= SHADER_VARIANT_SHADOW7; break; } shadow_count++; break; case LIGHT_AREA: AreaLight *aLight = (AreaLight*)(*light_i); glActiveTexture(GL_TEXTURE0+aLight->oLight[0].shadow_mtex); glClientActiveTexture(GL_TEXTURE0+aLight->oLight[0].shadow_mtex); GLShader::defaultShader.setShaderValue("shadowMap0", aLight->oLight[0].shadow_mtex); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, aLight->oLight[0].shadowmapTex); glActiveTexture(GL_TEXTURE0+aLight->oLight[1].shadow_mtex); glClientActiveTexture(GL_TEXTURE0+aLight->oLight[1].shadow_mtex); GLShader::defaultShader.setShaderValue("shadowMap1", aLight->oLight[1].shadow_mtex); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, aLight->oLight[1].shadowmapTex); glActiveTexture(GL_TEXTURE0+aLight->oLight[2].shadow_mtex); glClientActiveTexture(GL_TEXTURE0+aLight->oLight[2].shadow_mtex); GLShader::defaultShader.setShaderValue("shadowMap2", aLight->oLight[2].shadow_mtex); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, aLight->oLight[2].shadowmapTex); for (int n = 0; n < 3; n++) { switch (shadow_count) { case 0: shadowMask |= SHADER_VARIANT_SHADOW0; break; case 1: shadowMask |= SHADER_VARIANT_SHADOW1; break; case 2: shadowMask |= SHADER_VARIANT_SHADOW2; break; case 3: shadowMask |= SHADER_VARIANT_SHADOW3; break; case 4: shadowMask |= SHADER_VARIANT_SHADOW4; break; case 5: shadowMask |= SHADER_VARIANT_SHADOW5; break; case 6: shadowMask |= SHADER_VARIANT_SHADOW6; break; case 7: shadowMask |= SHADER_VARIANT_SHADOW7; break; } shadow_count++; } break; } } if (!GLShader::defaultShader.activateLight((*light_i)->type,shaderCount,(*light_i)->hasShadow()?(mat->shader_mask|shadowMask):mat->shader_mask,false)) { light_i++; continue; } light_i++; } else if (!numLights) { if (shaderCount == 0) { glDisable(GL_BLEND); } else { glEnable(GL_BLEND); glBlendFunc(GL_ZERO, GL_SRC_COLOR); } glDepthMask(true); if (!GLShader::defaultShader.activateLight(LIGHT_NULL,0,mat->shader_mask,false)) continue; } else { glEnable(GL_BLEND); if (mat->shader_mask & SHADER_VARIANT_LIGHTMAP) { glBlendFunc(GL_ONE, GL_ONE); if (!GLShader::defaultShader.activateLight(LIGHT_NULL,0,mat->shader_mask,false)) break; } else { Light::setGlobalAmbient(global_amb_temp); break; } } #endif // end shader light loop header if (!usefault) // no fault segments needed, just render all primitives { segElementIndex = element_index; for (matref_type_i = (*mat_segment_type_i).second.begin(); matref_type_i != (*mat_segment_type_i).second.end(); matref_type_i++) { if (!(*matref_type_i).second.element_count) continue; #ifndef ARCH_PSP switch((*matref_type_i).first) { case 1: glDrawRangeElements(GL_POINTS,(*matref_type_i).second.range_min,(*matref_type_i).second.range_max,(*matref_type_i).second.element_count,GL_UNSIGNED_INT,BUFFER_OFFSET(segElementIndex)); break; case 2: glDrawRangeElements(GL_LINES,(*matref_type_i).second.range_min,(*matref_type_i).second.range_max,(*matref_type_i).second.element_count,GL_UNSIGNED_INT,BUFFER_OFFSET(segElementIndex)); break; case 3: glDrawRangeElements(GL_TRIANGLES,(*matref_type_i).second.range_min,(*matref_type_i).second.range_max,(*matref_type_i).second.element_count,GL_UNSIGNED_INT,BUFFER_OFFSET(segElementIndex)); break; #if !defined(OPENGL_ES) case 4: glDrawRangeElements(GL_QUADS,(*matref_type_i).second.range_min,(*matref_type_i).second.range_max,(*matref_type_i).second.element_count,GL_UNSIGNED_INT,BUFFER_OFFSET(segElementIndex)); break; #endif } #else // sceGuDisable(GU_TEXTURE_2D); // sceGuDisable(GU_LIGHTING); // sceGuColor(0xff66ccff); unsigned int vtype = GU_INDEX_16BIT|GU_NORMAL_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_3D; if (obj.cache_data.max_uvs) vtype |= GU_TEXTURE_32BITF; if (obj.hasColorMap) vtype |= GU_COLOR_8888; unsigned int ptype = 0; switch ((*matref_type_i).first) { case 1: ptype = GU_POINTS; break; case 2: ptype = GU_LINES; break; case 3: ptype = GU_TRIANGLES; break; } sceGumDrawArray( ptype, vtype, (*matref_type_i).second.element_count, BUFFER_OFFSET(segElementIndex), obj.cache_data.data); int matLayerCount = mat->getLayerSize(); for (unsigned int matLayer = 1; matLayer < matLayerCount; matLayer++) { mat->texSetup(matLayer); sceGumDrawArray( ptype, vtype, (*matref_type_i).second.element_count, BUFFER_OFFSET(segElementIndex), obj.cache_data.data); } #endif segElementIndex += (*matref_type_i).second.element_count*sizeof(cvrElement); } } else // use accumulated cache fault runs { #ifndef ARCH_PSP switch (segRangeType) { case 1: glDrawRangeElements(GL_POINTS,segRange.range_min,segRange.range_max,segRange.element_count,GL_UNSIGNED_INT,BUFFER_OFFSET(segRangeIndex)); break; case 2: glDrawRangeElements(GL_LINES,segRange.range_min,segRange.range_max,segRange.element_count,GL_UNSIGNED_INT,BUFFER_OFFSET(segRangeIndex)); break; case 3: glDrawRangeElements(GL_TRIANGLES,segRange.range_min,segRange.range_max,segRange.element_count,GL_UNSIGNED_INT,BUFFER_OFFSET(segRangeIndex)); break; #if !defined(OPENGL_ES) case 4: glDrawRangeElements(GL_QUADS,segRange.range_min,segRange.range_max,segRange.element_count,GL_UNSIGNED_INT,BUFFER_OFFSET(segRangeIndex)); break; #endif } #else unsigned int vtype = GU_INDEX_16BIT|GU_NORMAL_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_3D; if (obj.cache_data.max_uvs) vtype |= GU_TEXTURE_32BITF; if (obj.hasColorMap) vtype |= GU_COLOR_8888; unsigned int ptype = 0; switch (segRangeType) { case 1: ptype = GU_POINTS; break; case 2: ptype = GU_LINES; break; case 3: ptype = GU_TRIANGLES; break; } if (ptype) sceGumDrawArray( ptype, vtype, segRange.element_count, BUFFER_OFFSET(segRangeIndex), obj.cache_data.data); #endif } #if !defined(OPENGL_ES) && !defined(ARCH_DC) && !defined(ARCH_PSP) // end shader light loop } #endif if (!usefault) element_index += (*(*mat_segment_type_i).second.begin()).second.group_size*sizeof(cvrElement); if (usefault) // reset fault line { segRange.range_min = obj.cache_data.vertex_count; segRange.range_max = 0; segRange.element_count = 0; segRun = 0; if (!fault) element_index += (*(*mat_segment_type_i).second.begin()).second.group_size*sizeof(cvrElement); fault = false; segRangeIndex = element_index; } } } // clear the textures used in this material if (stage != SHADER_STAGE_NOMATERIAL && stage != SHADER_STAGE_NOTEXTURE) { Texture::clearAllTextures(); } // call the transparency stage if necessary if (stage == SHADER_STAGE_NULL && has_trans) render(obj,SHADER_STAGE_TRANSPARENT); };