// gets called every frame to draw the scene void CRenderer::Update(const float dt, const uint32_t ticks) { CObj* obj, *localctrl; int localctrlid; OBJITER iter; matrix_t m; vec3_t dir, up, side; CFrustum frustum; CWorld* world; localctrl = m_world->GetLocalController(); localctrlid = m_world->GetLocalObj()->GetID(); world = m_world->GetInterpWorld(); const vec3_t campos = localctrl->GetOrigin(); const quaternion_t camrot = localctrl->GetRot(); m.SetCamTransform(campos, camrot); m.GetVec3Cam(&dir, &up, &side); dir = -dir; frustum.Setup(campos, dir, up, side, RENDERER_FOV, (float)m_width/(float)m_height, PLANE_NEAR, PLANE_FAR); // light floating above the players head const vec3_t lightpos0(campos + vec3_t(0,25.0f,0)); const quaternion_t lightrot0(quaternion_t(vec3_t::xAxis, -90.0f*lynxmath::DEGTORAD)); const float lightpos0_4f[4] = {lightpos0.x, lightpos0.y, lightpos0.z, 1}; glLightfv(GL_LIGHT0, GL_POSITION, lightpos0_4f); if(m_shaderactive) { if(m_useShadows) { glUseProgram(0); // draw shadowmap with fixed function pipeline PrepareShadowMap(lightpos0, lightrot0, world, localctrlid); // the player is the light } glUseProgram(m_program); // activate shader } glMatrixMode(GL_MODELVIEW); glLoadMatrixf(m.pm); glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT); glActiveTexture(GL_TEXTURE0); // normal texture channel if(m_shaderactive) { glUniform1i(m_tex, 0); // good old textures: GL_TEXTURE0 glUniform1i(m_normalMap, 1); // normal maps are GL_TEXTURE1 glUniform1i(m_lightmap, 2); // lightmap if(m_useShadows) { glUniform1i(m_shadowMapUniform, 7); glActiveTexture(GL_TEXTURE7); // shadow mapping texture GL_TEXTURE7 glBindTexture(GL_TEXTURE_2D, m_depthTextureId); glActiveTexture(GL_TEXTURE0); } #ifdef DRAW_NORMALS glUseProgram(0); // use fixed pipeline for this debug mode #endif } // Main drawing DrawScene(frustum, world, localctrlid, false); if(m_shaderactive) glUseProgram(0); // don't use shader for particles // Particle Draw glDisable(GL_LIGHTING); glDepthMask(false); for(iter=world->ObjBegin();iter!=world->ObjEnd();++iter) { obj = (*iter).second; if(obj->GetMesh()) { // Animate mesh is done in the particle loop // and not in DrawScene, because DrawScene // can be called multiple times per frame obj->GetMesh()->Animate(obj->GetMeshState(), dt); } if(obj->GetID() == localctrlid || !obj->GetParticleSystem()) continue; // Update/animate the particles, depending on dt and the current position. obj->GetParticleSystem()->Update(dt, ticks, obj->GetOrigin()); // Draw the particles. FIXME: this should use a frustum test obj->GetParticleSystem()->Render(side, up, dir); } glDepthMask(true); glColor4f(1,1,1,1); glEnable(GL_LIGHTING); #ifdef DRAW_NORMALS // Draw vertex normals of level geometry (not face normals) if(world && world->GetBSP()) { glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); world->GetBSP()->RenderNormals(); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); } #endif // Draw weapon if(m_shaderactive) // use shader for weapon glUseProgram(m_program); CModelMD5* viewmodel; md5_state_t* viewmodelstate; m_world->m_hud.GetModel(&viewmodel, &viewmodelstate); glDisable(GL_LIGHTING); if(viewmodel) { glClear(GL_DEPTH_BUFFER_BIT); glPushMatrix(); glLoadIdentity(); viewmodel->Render(viewmodelstate); viewmodel->Animate(viewmodelstate, dt); glPopMatrix(); } glEnable(GL_LIGHTING); // Draw HUD if(m_shaderactive) glUseProgram(0); // no shader for HUD glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, m_width, m_height, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glColor4f(1,1,1,1); glBindTexture(GL_TEXTURE_2D, m_crosshair); // Draw center crosshair glBegin(GL_QUADS); glTexCoord2d(0,1); glVertex3f((m_width-m_crosshair_width)*0.5f, (m_height-m_crosshair_height)*0.5f,0.0f); glTexCoord2d(0,0); glVertex3f((m_width-m_crosshair_width)*0.5f, (m_height+m_crosshair_height)*0.5f,0.0f); glTexCoord2d(1,0); glVertex3f((m_width+m_crosshair_width)*0.5f, (m_height+m_crosshair_height)*0.5f,0.0f); glTexCoord2d(1,1); glVertex3f((m_width+m_crosshair_width)*0.5f, (m_height-m_crosshair_height)*0.5f,0.0f); glEnd(); // draw HUD text: score, health... char hudtextbuf[64]; sprintf(hudtextbuf, "Frags: %i", m_world->m_hud.score); m_font.DrawGL(10.0f, m_height - 30.0f, 0.0f, hudtextbuf); sprintf(hudtextbuf, "%i", m_world->m_hud.health); m_font.DrawGL(10.0f, m_height - 35.0f - (float)m_font.GetHeight(), 0.0f, hudtextbuf); #ifdef DRAW_SHADOWMAP // draw a small window with the scene from the light POV if(m_shaderactive) { //glBindTexture(GL_TEXTURE_2D, m_depthTextureId); glBindTexture(GL_TEXTURE_2D, g_fboShadowCamColor); const float shadowmap_debug_width = 200.0f; const float shadowmap_debug_height = shadowmap_debug_width*(float)m_height/(float)m_width; glBegin(GL_QUADS); glTexCoord2d(0,1); // upper left glVertex3f(0.0f, 0.0f, 0.0f); glTexCoord2d(0,0); //lower left glVertex3f(0.0f, shadowmap_debug_height, 0.0f); glTexCoord2d(1,0); //lower right glVertex3f(shadowmap_debug_width, shadowmap_debug_height, 0.0f); glTexCoord2d(1,1); // upper right glVertex3f(shadowmap_debug_width, 0.0f, 0.0f); glEnd(); } #endif glBindTexture(GL_TEXTURE_2D, 0); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); }
void CRenderer::PrepareShadowMap(const vec3_t& lightpos, const quaternion_t& lightrot, CWorld* world, int localctrlid) { CFrustum frustum; vec3_t dir, up, side; matrix_t mviewlight; mviewlight.SetCamTransform(lightpos, lightrot); mviewlight.GetVec3Cam(&dir, &up, &side); dir = -dir; frustum.Setup(lightpos, dir, up, side, RENDERER_FOV, (float)m_width/(float)m_height, PLANE_NEAR, PLANE_FAR); glViewport(0, 0, (int)(m_width * SHADOW_MAP_RATIO), (int)(m_height * SHADOW_MAP_RATIO)); float projection[16]; glMatrixMode(GL_PROJECTION); // Shadow mapping with ortho projection can be useful //const float lightDistance = PLANE_FAR*0.1f; //glLoadIdentity(); //glOrtho(-35.0f, 35.0f, -35.0f, 35.0f, 0.0f, PLANE_FAR*0.1f); // dimension: light area in m glGetFloatv(GL_PROJECTION_MATRIX, projection); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(mviewlight.pm); // set camera to light pos glMatrixMode(GL_TEXTURE); glActiveTexture(GL_TEXTURE7); glLoadMatrixf(g_shadowBias); // to map from -1..1 to 0..1 glMultMatrixf(projection); glMultMatrixf(mviewlight.pm); glMatrixMode(GL_MODELVIEW); // Render to FBO glBindFramebuffer(GL_FRAMEBUFFER, m_fboId); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glDisable(GL_LIGHTING); glDisable(GL_BLEND); #ifndef DRAW_SHADOWMAP glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); #endif //glCullFace(GL_FRONT); glPolygonOffset( 1.1f, 4.0f ); glEnable(GL_POLYGON_OFFSET_FILL); DrawScene(frustum, world, localctrlid, true); glDisable(GL_POLYGON_OFFSET_FILL); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, m_width, m_height); #ifndef DRAW_SHADOWMAP glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); #endif //glCullFace(GL_BACK); glEnable(GL_LIGHTING); glEnable(GL_BLEND); UpdatePerspective(); // restore standard projection }