void ParticleRenderer::RenderParticles(bool solidColor) { CShaderTechniquePtr shader = solidColor ? m->shaderSolid : m->shader; shader->BeginPass(); shader->GetShader()->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); if (!solidColor) glEnable(GL_BLEND); glDepthMask(0); for (size_t i = 0; i < m->emitters.size(); ++i) { CParticleEmitter* emitter = m->emitters[i]; emitter->Bind(shader->GetShader()); emitter->RenderArray(shader->GetShader()); } CVertexBuffer::Unbind(); pglBlendEquationEXT(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glDepthMask(1); shader->EndPass(); }
// This sets up and draws the rectangle on the minimap // which represents the view of the camera in the world. void CMiniMap::DrawViewRect(CMatrix3D transform) { // Compute the camera frustum intersected with a fixed-height plane. // Use the water height as a fixed base height, which should be the lowest we can go float h = g_Renderer.GetWaterManager()->m_WaterHeight; const float width = m_CachedActualSize.GetWidth(); const float height = m_CachedActualSize.GetHeight(); const float invTileMapSize = 1.0f / float(TERRAIN_TILE_SIZE * m_MapSize); CVector3D hitPt[4]; hitPt[0] = m_Camera->GetWorldCoordinates(0, g_Renderer.GetHeight(), h); hitPt[1] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), g_Renderer.GetHeight(), h); hitPt[2] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), 0, h); hitPt[3] = m_Camera->GetWorldCoordinates(0, 0, h); float ViewRect[4][2]; for (int i = 0; i < 4; ++i) { // convert to minimap space ViewRect[i][0] = (width * hitPt[i].X * invTileMapSize); ViewRect[i][1] = (height * hitPt[i].Z * invTileMapSize); } float viewVerts[] = { ViewRect[0][0], -ViewRect[0][1], ViewRect[1][0], -ViewRect[1][1], ViewRect[2][0], -ViewRect[2][1], ViewRect[3][0], -ViewRect[3][1] }; // Enable Scissoring to restrict the rectangle to only the minimap. glScissor( m_CachedActualSize.left / g_GuiScale, g_Renderer.GetHeight() - m_CachedActualSize.bottom / g_GuiScale, width / g_GuiScale, height / g_GuiScale); glEnable(GL_SCISSOR_TEST); glLineWidth(2.0f); CShaderDefines lineDefines; lineDefines.Add(str_MINIMAP_LINE, str_1); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), lineDefines); tech->BeginPass(); CShaderProgramPtr shader = tech->GetShader(); shader->Uniform(str_transform, transform); shader->Uniform(str_color, 1.0f, 0.3f, 0.3f, 1.0f); shader->VertexPointer(2, GL_FLOAT, 0, viewVerts); shader->AssertPointersBound(); if (!g_Renderer.m_SkipSubmit) glDrawArrays(GL_LINE_LOOP, 0, 4); tech->EndPass(); glLineWidth(1.0f); glDisable(GL_SCISSOR_TEST); }
void CPostprocManager::ApplyBlurDownscale2x(GLuint inTex, GLuint outTex, int inWidth, int inHeight) { // Bind inTex to framebuffer for rendering. pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, outTex, 0); // Get bloom shader with instructions to simply copy texels. CShaderDefines defines; defines.Add(str_BLOOM_NOP, str_1); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); CShaderProgramPtr shader = tech->GetShader(); GLuint renderedTex = inTex; // Cheat by creating high quality mipmaps for inTex, so the copying operation actually // produces good scaling due to hardware filtering. glBindTexture(GL_TEXTURE_2D, renderedTex); pglGenerateMipmapEXT(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); shader->BindTexture(str_renderedTex, renderedTex); const SViewPort oldVp = g_Renderer.GetViewport(); const SViewPort vp = { 0, 0, inWidth / 2, inHeight / 2 }; g_Renderer.SetViewport(vp); float quadVerts[] = { 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f }; float quadTex[] = { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }; shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); shader->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, 0, 6); g_Renderer.SetViewport(oldVp); tech->EndPass(); }
void OverlayRenderer::RenderSphereOverlays() { PROFILE3_GPU("overlays (spheres)"); #if CONFIG2_GLES #warning TODO: implement OverlayRenderer::RenderSphereOverlays for GLES #else if (g_Renderer.GetRenderPath() != CRenderer::RP_SHADER) return; if (m->spheres.empty()) return; glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDepthMask(0); glEnableClientState(GL_VERTEX_ARRAY); CShaderProgramPtr shader; CShaderTechniquePtr tech; tech = g_Renderer.GetShaderManager().LoadEffect(str_overlay_solid); tech->BeginPass(); shader = tech->GetShader(); m->GenerateSphere(); shader->VertexPointer(3, GL_FLOAT, 0, &m->sphereVertexes[0]); for (size_t i = 0; i < m->spheres.size(); ++i) { SOverlaySphere* sphere = m->spheres[i]; CMatrix3D transform; transform.SetIdentity(); transform.Scale(sphere->m_Radius, sphere->m_Radius, sphere->m_Radius); transform.Translate(sphere->m_Center); shader->Uniform(str_transform, transform); shader->Uniform(str_color, sphere->m_Color); glDrawElements(GL_TRIANGLES, m->sphereIndexes.size(), GL_UNSIGNED_SHORT, &m->sphereIndexes[0]); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_OverlayTris = m->sphereIndexes.size()/3; } tech->EndPass(); glDisableClientState(GL_VERTEX_ARRAY); glDepthMask(1); glDisable(GL_BLEND); #endif }
void CPostprocManager::ApplyEffect(CShaderTechniquePtr &shaderTech1, int pass) { // select the other FBO for rendering if (!m_WhichBuffer) pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); else pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); shaderTech1->BeginPass(pass); CShaderProgramPtr shader = shaderTech1->GetShader(pass); shader->Bind(); // Use the textures from the current FBO as input to the shader. // We also bind a bunch of other textures and parameters, but since // this only happens once per frame the overhead is negligible. if (m_WhichBuffer) shader->BindTexture(str_renderedTex, m_ColourTex1); else shader->BindTexture(str_renderedTex, m_ColourTex2); shader->BindTexture(str_depthTex, m_DepthTex); shader->BindTexture(str_blurTex2, m_BlurTex2a); shader->BindTexture(str_blurTex4, m_BlurTex4a); shader->BindTexture(str_blurTex8, m_BlurTex8a); shader->Uniform(str_width, m_Width); shader->Uniform(str_height, m_Height); shader->Uniform(str_zNear, g_Game->GetView()->GetNear()); shader->Uniform(str_zFar, g_Game->GetView()->GetFar()); shader->Uniform(str_brightness, g_LightEnv.m_Brightness); shader->Uniform(str_hdr, g_LightEnv.m_Contrast); shader->Uniform(str_saturation, g_LightEnv.m_Saturation); shader->Uniform(str_bloom, g_LightEnv.m_Bloom); glBegin(GL_QUADS); glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(1.0, 1.0); glVertex2f(1,1); glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); glEnd(); shader->Unbind(); shaderTech1->EndPass(pass); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); m_WhichBuffer = !m_WhichBuffer; }
//Render Manager. void CConsole::Render() { if (! (m_bVisible || m_bToggle) ) return; PROFILE3_GPU("console"); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); CShaderTechniquePtr solidTech = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid); solidTech->BeginPass(); CShaderProgramPtr solidShader = solidTech->GetShader(); CMatrix3D transform = GetDefaultGuiMatrix(); // animation: slide in from top of screen const float DeltaY = (1.0f - m_fVisibleFrac) * m_fHeight; transform.PostTranslate(m_fX, m_fY - DeltaY, 0.0f); // move to window position solidShader->Uniform(str_transform, transform); DrawWindow(solidShader); solidTech->EndPass(); CShaderTechniquePtr textTech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text); textTech->BeginPass(); CTextRenderer textRenderer(textTech->GetShader()); textRenderer.Font(CStrIntern(CONSOLE_FONT)); textRenderer.SetTransform(transform); DrawHistory(textRenderer); DrawBuffer(textRenderer); textRenderer.Render(); textTech->EndPass(); glDisable(GL_BLEND); }
void TerrainRenderer::RenderTerrainShader(const CShaderDefines& context, ShadowMap* shadow, bool filtered) { ENSURE(m->phase == Phase_Render); std::vector<CPatchRData*>& visiblePatches = filtered ? m->filteredPatches : m->visiblePatches; std::vector<CDecalRData*>& visibleDecals = filtered ? m->filteredDecals : m->visibleDecals; if (visiblePatches.empty() && visibleDecals.empty()) return; // render the solid black sides of the map first CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid); techSolid->BeginPass(); CShaderProgramPtr shaderSolid = techSolid->GetShader(); shaderSolid->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); shaderSolid->Uniform(str_color, 0.0f, 0.0f, 0.0f, 1.0f); PROFILE_START("render terrain sides"); for (size_t i = 0; i < visiblePatches.size(); ++i) visiblePatches[i]->RenderSides(shaderSolid); PROFILE_END("render terrain sides"); techSolid->EndPass(); PROFILE_START("render terrain base"); CPatchRData::RenderBases(visiblePatches, context, shadow); PROFILE_END("render terrain base"); // no need to write to the depth buffer a second time glDepthMask(0); // render blend passes for each patch PROFILE_START("render terrain blends"); CPatchRData::RenderBlends(visiblePatches, context, shadow, false); PROFILE_END("render terrain blends"); PROFILE_START("render terrain decals"); CDecalRData::RenderDecals(visibleDecals, context, shadow, false); PROFILE_END("render terrain decals"); // restore OpenGL state g_Renderer.BindTexture(1, 0); g_Renderer.BindTexture(2, 0); g_Renderer.BindTexture(3, 0); glDepthMask(1); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); }
void CGUI::DrawText(SGUIText &Text, const CColor &DefaultColor, const CPos &pos, const float &z, const CRect &clipping) { CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text); tech->BeginPass(); bool isClipped = (clipping != CRect()); if (isClipped) { glEnable(GL_SCISSOR_TEST); glScissor(clipping.left, g_yres - clipping.bottom, clipping.GetWidth(), clipping.GetHeight()); } CTextRenderer textRenderer(tech->GetShader()); textRenderer.SetClippingRect(clipping); textRenderer.Translate(0.0f, 0.0f, z); for (std::vector<SGUIText::STextCall>::const_iterator it = Text.m_TextCalls.begin(); it != Text.m_TextCalls.end(); ++it) { // If this is just a placeholder for a sprite call, continue if (it->m_pSpriteCall) continue; CColor color = it->m_UseCustomColor ? it->m_Color : DefaultColor; textRenderer.Color(color); textRenderer.Font(it->m_Font); textRenderer.Put((float)(int)(pos.x+it->m_Pos.x), (float)(int)(pos.y+it->m_Pos.y), &it->m_String); } textRenderer.Render(); for (std::list<SGUIText::SSpriteCall>::iterator it=Text.m_SpriteCalls.begin(); it!=Text.m_SpriteCalls.end(); ++it) { DrawSprite(it->m_Sprite, it->m_CellID, z, it->m_Area + pos); } if (isClipped) glDisable(GL_SCISSOR_TEST); tech->EndPass(); }
void CGUI::DrawText(SGUIText& Text, const CColor& DefaultColor, const CPos& pos, const float& z, const CRect& clipping) { CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text); tech->BeginPass(); bool isClipped = (clipping != CRect()); if (isClipped) { glEnable(GL_SCISSOR_TEST); glScissor( clipping.left / g_GuiScale, g_yres - clipping.bottom / g_GuiScale, clipping.GetWidth() / g_GuiScale, clipping.GetHeight() / g_GuiScale); } CTextRenderer textRenderer(tech->GetShader()); textRenderer.SetClippingRect(clipping); textRenderer.Translate(0.0f, 0.0f, z); for (const SGUIText::STextCall& tc : Text.m_TextCalls) { // If this is just a placeholder for a sprite call, continue if (tc.m_pSpriteCall) continue; CColor color = tc.m_UseCustomColor ? tc.m_Color : DefaultColor; textRenderer.Color(color); textRenderer.Font(tc.m_Font); textRenderer.Put((float)(int)(pos.x + tc.m_Pos.x), (float)(int)(pos.y + tc.m_Pos.y), &tc.m_String); } textRenderer.Render(); for (const SGUIText::SSpriteCall& sc : Text.m_SpriteCalls) DrawSprite(sc.m_Sprite, sc.m_CellID, z, sc.m_Area + pos); if (isClipped) glDisable(GL_SCISSOR_TEST); tech->EndPass(); }
void TerrainRenderer::RenderPriorities() { PROFILE("priorities"); ENSURE(m->phase == Phase_Render); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect("gui_text"); tech->BeginPass(); CTextRenderer textRenderer(tech->GetShader()); textRenderer.Font(L"mono-stroke-10"); textRenderer.Color(1.0f, 1.0f, 0.0f); for (size_t i = 0; i < m->visiblePatches.size(); ++i) m->visiblePatches[i]->RenderPriorities(textRenderer); textRenderer.Render(); tech->EndPass(); }
void ShadowMap::RenderDebugTexture() { glDepthMask(0); glDisable(GL_DEPTH_TEST); #if !CONFIG2_GLES g_Renderer.BindTexture(0, m->Texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); #endif CShaderTechniquePtr texTech = g_Renderer.GetShaderManager().LoadEffect("gui_basic"); texTech->BeginPass(); CShaderProgramPtr texShader = texTech->GetShader(); texShader->Uniform("transform", GetDefaultGuiMatrix()); texShader->BindTexture("tex", m->Texture); float s = 256.f; float boxVerts[] = { 0,0, 0,s, s,0, s,0, 0,s, s,s }; float boxUV[] = { 0,0, 0,1, 1,0, 1,0, 0,1, 1,1 }; texShader->VertexPointer(2, GL_FLOAT, 0, boxVerts); texShader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, boxUV); texShader->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, 0, 6); texTech->EndPass(); #if !CONFIG2_GLES g_Renderer.BindTexture(0, m->Texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); #endif glEnable(GL_DEPTH_TEST); glDepthMask(1); }
void CPostprocManager::ApplyBlurDownscale2x(GLuint inTex, GLuint outTex, int inWidth, int inHeight) { // Bind inTex to framebuffer for rendering. pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, outTex, 0); // Get bloom shader with instructions to simply copy texels. CShaderDefines defines; defines.Add(str_BLOOM_NOP, str_1); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); CShaderProgramPtr shader = tech->GetShader(); GLuint renderedTex = inTex; // Cheat by creating high quality mipmaps for inTex, so the copying operation actually // produces good scaling due to hardware filtering. glBindTexture(GL_TEXTURE_2D, renderedTex); pglGenerateMipmapEXT(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); shader->BindTexture(str_renderedTex, renderedTex); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, inWidth / 2, inHeight / 2); glBegin(GL_QUADS); glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(1.0, 1.0); glVertex2f(1,1); glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); glEnd(); glPopAttrib(); tech->EndPass(); }
// TODO: render the minimap in a framebuffer and just draw the frambuffer texture // most of the time, updating the framebuffer twice a frame. // Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling // (those operations cause a gpu sync, which slows down the way gpu works) void CMiniMap::Draw() { PROFILE3("render minimap"); // The terrain isn't actually initialized until the map is loaded, which // happens when the game is started, so abort until then. if(!(GetGUI() && g_Game && g_Game->IsGameStarted())) return; CSimulation2* sim = g_Game->GetSimulation2(); CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY); ENSURE(cmpRangeManager); // Set our globals in case they hadn't been set before m_Camera = g_Game->GetView()->GetCamera(); m_Terrain = g_Game->GetWorld()->GetTerrain(); m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); m_MapSize = m_Terrain->GetVerticesPerSide(); m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); if(!m_TerrainTexture || g_GameRestarted) CreateTextures(); // only update 2x / second // (note: since units only move a few pixels per second on the minimap, // we can get away with infrequent updates; this is slow) // TODO: store frequency in a config file? static double last_time; const double cur_time = timer_Time(); const bool doUpdate = cur_time - last_time > 0.5; if(doUpdate) { last_time = cur_time; if(m_TerrainDirty) RebuildTerrainTexture(); } glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); CMatrix3D matrix = GetDefaultGuiMatrix(); glLoadMatrixf(&matrix._11); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture glDepthMask(0); CShaderProgramPtr shader; CShaderTechniquePtr tech; if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { CShaderDefines defines; defines.Add(str_MINIMAP_BASE, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; const float z = GetBufferedZ(); const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize; const float angle = GetAngle(); // Draw the main textured quad if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture(str_baseTex, m_TerrainTexture); else g_Renderer.BindTexture(0, m_TerrainTexture); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z); // Draw territory boundaries CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture(str_baseTex, territoryTexture.GetTexture()); else territoryTexture.BindTexture(0); glEnable(GL_BLEND); glMatrixMode(GL_TEXTURE); glLoadMatrixf(territoryTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); // Draw the LOS quad in black, using alpha values from the LOS texture CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add(str_MINIMAP_LOS, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); shader->BindTexture(str_baseTex, losTexture.GetTexture()); } else { losTexture.BindTexture(0); } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor3f(0.0f, 0.0f, 0.0f); glMatrixMode(GL_TEXTURE); glLoadMatrixf(losTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add(str_MINIMAP_POINT, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } // Set up the matrix for drawing points and lines glPushMatrix(); glTranslatef(x, y, z); // Rotate around the center of the map glTranslatef((x2-x)/2.f, (y2-y)/2.f, 0.f); // Scale square maps to fit in circular minimap area float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); glScalef(unitScale, unitScale, 1.f); glRotatef(angle * 180.f/M_PI, 0.f, 0.f, 1.f); glTranslatef(-(x2-x)/2.f, -(y2-y)/2.f, 0.f); PROFILE_START("minimap units"); const float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); const float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); if (doUpdate) { VertexArrayIterator<float[2]> attrPos = m_AttributePos.GetIterator<float[2]>(); VertexArrayIterator<u8[4]> attrColor = m_AttributeColor.GetIterator<u8[4]>(); m_EntitiesDrawn = 0; MinimapUnitVertex v; std::vector<MinimapUnitVertex> pingingVertices; pingingVertices.reserve(MAX_ENTITIES_DRAWN/2); const double time = timer_Time(); if (time > m_NextBlinkTime) { m_BlinkState = !m_BlinkState; m_NextBlinkTime = time + m_HalfBlinkDuration; } entity_pos_t posX, posZ; for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) { ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second); if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) { ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID()); if (vis != ICmpRangeManager::VIS_HIDDEN) { v.a = 255; v.x = posX.ToFloat()*sx; v.y = -posZ.ToFloat()*sy; // Check minimap pinging to indicate something if (m_BlinkState && cmpMinimap->CheckPing(time, m_PingDuration)) { v.r = 255; // ping color is white v.g = 255; v.b = 255; pingingVertices.push_back(v); } else { addVertex(v, attrColor, attrPos); ++m_EntitiesDrawn; } } } } // Add the pinged vertices at the end, so they are drawn on top for (size_t v = 0; v < pingingVertices.size(); ++v) { addVertex(pingingVertices[v], attrColor, attrPos); ++m_EntitiesDrawn; } ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN); m_VertexArray.Upload(); } if (m_EntitiesDrawn > 0) { // Don't enable GL_POINT_SMOOTH because it's far too slow // (~70msec/frame on a GF4 rendering a thousand points) glPointSize(3.f); u8* indexBase = m_IndexArray.Bind(); u8* base = m_VertexArray.Bind(); const GLsizei stride = (GLsizei)m_VertexArray.GetStride(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); shader->AssertPointersBound(); } else { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glDisable(GL_TEXTURE_2D); glVertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); glColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); } if (!g_Renderer.m_SkipSubmit) { glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase); } g_Renderer.GetStats().m_DrawCalls++; CVertexBuffer::Unbind(); } PROFILE_END("minimap units"); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add(str_MINIMAP_LINE, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } else { glEnable(GL_TEXTURE_2D); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } DrawViewRect(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); } // Reset everything back to normal glPointSize(1.0f); glEnable(GL_TEXTURE_2D); glDepthMask(1); }
void ShadowMap::RenderDebugBounds() { CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect("gui_solid"); shaderTech->BeginPass(); CShaderProgramPtr shader = shaderTech->GetShader(); glDepthMask(0); glDisable(GL_CULL_FACE); // Render shadow bound shader->Uniform("transform", g_Renderer.GetViewCamera().GetViewProjection() * m->InvLightTransform); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); shader->Uniform("color", 0.0f, 0.0f, 1.0f, 0.25f); m->ShadowBound.Render(shader); glDisable(GL_BLEND); shader->Uniform("color", 0.0f, 0.0f, 1.0f, 1.0f); m->ShadowBound.RenderOutline(shader); // Draw a funny line/triangle direction indicator thing for unknown reasons float shadowLineVerts[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 50.0, 0.0, 0.0, 50.0, 50.0, 0.0, 50.0, 50.0, 0.0, 50.0, 0.0, 50.0, 50.0, 0.0, 50.0, 50.0, 0.0, 0.0, 50.0 }; shader->VertexPointer(3, GL_FLOAT, 0, shadowLineVerts); shader->AssertPointersBound(); glDrawArrays(GL_LINES, 0, 8); shaderTech->EndPass(); #if 0 CMatrix3D InvTexTransform; m->TextureMatrix.GetInverse(InvTexTransform); // Render representative texture rectangle glPushMatrix(); glMultMatrixf(&InvTexTransform._11); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4ub(255,0,0,64); glBegin(GL_QUADS); glVertex3f(0.0, 0.0, 0.0); glVertex3f(1.0, 0.0, 0.0); glVertex3f(1.0, 1.0, 0.0); glVertex3f(0.0, 1.0, 0.0); glEnd(); glDisable(GL_BLEND); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3ub(255,0,0); glBegin(GL_QUADS); glVertex3f(0.0, 0.0, 0.0); glVertex3f(1.0, 0.0, 0.0); glVertex3f(1.0, 1.0, 0.0); glVertex3f(0.0, 1.0, 0.0); glEnd(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPopMatrix(); #endif glEnable(GL_CULL_FACE); glDepthMask(1); }
void CDecalRData::RenderDecals(std::vector<CDecalRData*>& decals, const CShaderDefines& context, ShadowMap* shadow, bool isDummyShader, const CShaderProgramPtr& dummy) { CShaderDefines contextDecal = context; contextDecal.Add("DECAL", "1"); for (size_t i = 0; i < decals.size(); ++i) { CDecalRData *decal = decals[i]; CMaterial &material = decal->m_Decal->m_Decal.m_Material; if (material.GetShaderEffect().length() == 0) { LOGERROR(L"Terrain renderer failed to load shader effect.\n"); continue; } int numPasses = 1; CShaderTechniquePtr techBase; if (!isDummyShader) { techBase = g_Renderer.GetShaderManager().LoadEffect( material.GetShaderEffect(), contextDecal, material.GetShaderDefines()); if (!techBase) { LOGERROR(L"Terrain renderer failed to load shader effect (%hs)\n", material.GetShaderEffect().string().c_str()); continue; } numPasses = techBase->GetNumPasses(); } for (int pass = 0; pass < numPasses; ++pass) { if (!isDummyShader) { techBase->BeginPass(pass); TerrainRenderer::PrepareShader(techBase->GetShader(), shadow); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } const CShaderProgramPtr& shader = isDummyShader ? dummy : techBase->GetShader(pass); if (material.GetSamplers().size() != 0) { CMaterial::SamplersVector samplers = material.GetSamplers(); size_t samplersNum = samplers.size(); for (size_t s = 0; s < samplersNum; ++s) { CMaterial::TextureSampler &samp = samplers[s]; shader->BindTexture(samp.Name.c_str(), samp.Sampler); } material.GetStaticUniforms().BindUniforms(shader); // TODO: Need to handle floating decals correctly. In particular, we need // to render non-floating before water and floating after water (to get // the blending right), and we also need to apply the correct lighting in // each case, which doesn't really seem possible with the current // TerrainRenderer. // Also, need to mark the decals as dirty when water height changes. // glDisable(GL_TEXTURE_2D); // m_Decal->GetBounds().Render(); // glEnable(GL_TEXTURE_2D); u8* base = decal->m_Array.Bind(); GLsizei stride = (GLsizei)decal->m_Array.GetStride(); u8* indexBase = decal->m_IndexArray.Bind(); #if !CONFIG2_GLES if (isDummyShader) { glColor3fv(decal->m_Decal->GetShadingColor().FloatArray()); } else #endif { shader->Uniform("shadingColor", decal->m_Decal->GetShadingColor()); } shader->VertexPointer(3, GL_FLOAT, stride, base + decal->m_Position.offset); shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + decal->m_DiffuseColor.offset); shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, base + decal->m_UV.offset); shader->AssertPointersBound(); if (!g_Renderer.m_SkipSubmit) { glDrawElements(GL_TRIANGLES, (GLsizei)decal->m_IndexArray.GetNumVertices(), GL_UNSIGNED_SHORT, indexBase); } // bump stats g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_TerrainTris += decal->m_IndexArray.GetNumVertices() / 3; CVertexBuffer::Unbind(); } if (!isDummyShader) { glDisable(GL_BLEND); techBase->EndPass(); } } } }
void CPatchRData::RenderBases(const std::vector<CPatchRData*>& patches, const CShaderDefines& context, ShadowMap* shadow, bool isDummyShader, const CShaderProgramPtr& dummy) { Allocators::Arena<> arena(ARENA_SIZE); TextureBatches batches (TextureBatches::key_compare(), (TextureBatches::allocator_type(arena))); PROFILE_START("compute batches"); // Collect all the patches' base splats into their appropriate batches for (size_t i = 0; i < patches.size(); ++i) { CPatchRData* patch = patches[i]; for (size_t j = 0; j < patch->m_Splats.size(); ++j) { SSplat& splat = patch->m_Splats[j]; BatchElements& batch = PooledPairGet( PooledMapGet( PooledMapGet(batches, splat.m_Texture, arena), patch->m_VBBase->m_Owner, arena ), patch->m_VBBaseIndices->m_Owner, arena ); batch.first.push_back(splat.m_IndexCount); u8* indexBase = patch->m_VBBaseIndices->m_Owner->GetBindAddress(); batch.second.push_back(indexBase + sizeof(u16)*(patch->m_VBBaseIndices->m_Index + splat.m_IndexStart)); } } PROFILE_END("compute batches"); // Render each batch for (TextureBatches::iterator itt = batches.begin(); itt != batches.end(); ++itt) { int numPasses = 1; CShaderTechniquePtr techBase; if (!isDummyShader) { if (itt->first->GetMaterial().GetShaderEffect().length() == 0) { LOGERROR(L"Terrain renderer failed to load shader effect.\n"); continue; } techBase = g_Renderer.GetShaderManager().LoadEffect(itt->first->GetMaterial().GetShaderEffect(), context, itt->first->GetMaterial().GetShaderDefines()); numPasses = techBase->GetNumPasses(); } for (int pass = 0; pass < numPasses; ++pass) { if (!isDummyShader) { techBase->BeginPass(pass); TerrainRenderer::PrepareShader(techBase->GetShader(), shadow); } const CShaderProgramPtr& shader = isDummyShader ? dummy : techBase->GetShader(pass); if (itt->first->GetMaterial().GetSamplers().size() != 0) { CMaterial::SamplersVector samplers = itt->first->GetMaterial().GetSamplers(); size_t samplersNum = samplers.size(); for (size_t s = 0; s < samplersNum; ++s) { CMaterial::TextureSampler &samp = samplers[s]; shader->BindTexture(samp.Name.c_str(), samp.Sampler); } itt->first->GetMaterial().GetStaticUniforms().BindUniforms(shader); #if !CONFIG2_GLES if (isDummyShader) { glMatrixMode(GL_TEXTURE); glLoadMatrixf(itt->first->GetTextureMatrix()); glMatrixMode(GL_MODELVIEW); } else #endif { float c = itt->first->GetTextureMatrix()[0]; float ms = itt->first->GetTextureMatrix()[8]; shader->Uniform("textureTransform", c, ms, -ms, 0.f); } } else { shader->BindTexture("baseTex", g_Renderer.GetTextureManager().GetErrorTexture()); } for (VertexBufferBatches::iterator itv = itt->second.begin(); itv != itt->second.end(); ++itv) { GLsizei stride = sizeof(SBaseVertex); SBaseVertex *base = (SBaseVertex *)itv->first->Bind(); shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor); shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); shader->AssertPointersBound(); for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) { it->first->Bind(); BatchElements& batch = it->second; if (!g_Renderer.m_SkipSubmit) { // Don't use glMultiDrawElements here since it doesn't have a significant // performance impact and it suffers from various driver bugs (e.g. it breaks // in Mesa 7.10 swrast with index VBOs) for (size_t i = 0; i < batch.first.size(); ++i) glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); } g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_TerrainTris += std::accumulate(batch.first.begin(), batch.first.end(), 0) / 3; } } if (!isDummyShader) techBase->EndPass(); } } #if !CONFIG2_GLES if (isDummyShader) { glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); } #endif CVertexBuffer::Unbind(); }
/////////////////////////////////////////////////////////////////// // Render sky void SkyManager::RenderSky() { #if CONFIG2_GLES #warning TODO: implement SkyManager::RenderSky for GLES #else // Draw the sky as a small box around the camera position, with depth write enabled. // This will be done before anything else is drawn so we'll be overlapped by everything else. // Note: The coordinates for this were set up through a rather cumbersome trial-and-error // process - there might be a smarter way to do it, but this seems to work. // Do nothing unless SetSkySet was called if (m_SkySet.empty()) return; glDepthMask( GL_FALSE ); pglActiveTextureARB(GL_TEXTURE0_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glMatrixMode(GL_MODELVIEW); glPushMatrix(); // Translate so we are at the camera in the X and Z directions, but // put the horizon at a fixed height regardless of camera Y const CCamera& camera = g_Renderer.GetViewCamera(); CVector3D pos = camera.m_Orientation.GetTranslation(); glTranslatef( pos.X, m_HorizonHeight, pos.Z ); // Rotate so that the "left" face, which contains the brightest part of each // skymap, is in the direction of the sun from our light environment glRotatef( 90.0f + RADTODEG(g_Renderer.GetLightEnv().GetRotation()), 0.0f, 1.0f, 0.0f ); // Distance to draw the faces at const float D = 2000.0; CShaderProgramPtr shader; CShaderTechniquePtr skytech; if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { skytech = g_Renderer.GetShaderManager().LoadEffect("sky_simple"); skytech->BeginPass(); shader = skytech->GetShader(); } // Front face (positive Z) if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture("baseTex", m_SkyTexture[FRONT]); else m_SkyTexture[FRONT]->Bind(); glBegin( GL_QUADS ); glTexCoord2f( 0, 1 ); glVertex3f( -D, -D, +D ); glTexCoord2f( 1, 1 ); glVertex3f( +D, -D, +D ); glTexCoord2f( 1, 0 ); glVertex3f( +D, +D, +D ); glTexCoord2f( 0, 0 ); glVertex3f( -D, +D, +D ); glEnd(); // Back face (negative Z) if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture("baseTex", m_SkyTexture[BACK]); else m_SkyTexture[BACK]->Bind(); glBegin( GL_QUADS ); glTexCoord2f( 1, 1 ); glVertex3f( -D, -D, -D ); glTexCoord2f( 1, 0 ); glVertex3f( -D, +D, -D ); glTexCoord2f( 0, 0 ); glVertex3f( +D, +D, -D ); glTexCoord2f( 0, 1 ); glVertex3f( +D, -D, -D ); glEnd(); // Right face (negative X) if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture("baseTex", m_SkyTexture[RIGHT]); else m_SkyTexture[RIGHT]->Bind(); glBegin( GL_QUADS ); glTexCoord2f( 0, 1 ); glVertex3f( -D, -D, -D ); glTexCoord2f( 1, 1 ); glVertex3f( -D, -D, +D ); glTexCoord2f( 1, 0 ); glVertex3f( -D, +D, +D ); glTexCoord2f( 0, 0 ); glVertex3f( -D, +D, -D ); glEnd(); // Left face (positive X) if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture("baseTex", m_SkyTexture[LEFT]); else m_SkyTexture[LEFT]->Bind(); glBegin( GL_QUADS ); glTexCoord2f( 1, 1 ); glVertex3f( +D, -D, -D ); glTexCoord2f( 1, 0 ); glVertex3f( +D, +D, -D ); glTexCoord2f( 0, 0 ); glVertex3f( +D, +D, +D ); glTexCoord2f( 0, 1 ); glVertex3f( +D, -D, +D ); glEnd(); // Top face (positive Y) if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture("baseTex", m_SkyTexture[TOP]); else m_SkyTexture[TOP]->Bind(); glBegin( GL_QUADS ); glTexCoord2f( 1, 0 ); glVertex3f( +D, +D, -D ); glTexCoord2f( 0, 0 ); glVertex3f( -D, +D, -D ); glTexCoord2f( 0, 1 ); glVertex3f( -D, +D, +D ); glTexCoord2f( 1, 1 ); glVertex3f( +D, +D, +D ); glEnd(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) skytech->EndPass(); glPopMatrix(); glDepthMask( GL_TRUE ); #endif }
// TODO: render the minimap in a framebuffer and just draw the frambuffer texture // most of the time, updating the framebuffer twice a frame. // Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling // (those operations cause a gpu sync, which slows down the way gpu works) void CMiniMap::Draw() { PROFILE3("render minimap"); // The terrain isn't actually initialized until the map is loaded, which // happens when the game is started, so abort until then. if (!(GetGUI() && g_Game && g_Game->IsGameStarted())) return; CSimulation2* sim = g_Game->GetSimulation2(); CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY); ENSURE(cmpRangeManager); // Set our globals in case they hadn't been set before m_Camera = g_Game->GetView()->GetCamera(); m_Terrain = g_Game->GetWorld()->GetTerrain(); m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); m_MapSize = m_Terrain->GetVerticesPerSide(); m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); if (!m_TerrainTexture || g_GameRestarted) CreateTextures(); // only update 2x / second // (note: since units only move a few pixels per second on the minimap, // we can get away with infrequent updates; this is slow) // TODO: Update all but camera at same speed as simulation static double last_time; const double cur_time = timer_Time(); const bool doUpdate = cur_time - last_time > 0.5; if (doUpdate) { last_time = cur_time; if (m_TerrainDirty) RebuildTerrainTexture(); } const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; const float z = GetBufferedZ(); const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize; const float angle = GetAngle(); const float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture. glDepthMask(0); CShaderProgramPtr shader; CShaderTechniquePtr tech; CShaderDefines baseDefines; baseDefines.Add(str_MINIMAP_BASE, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), baseDefines); tech->BeginPass(); shader = tech->GetShader(); // Draw the main textured quad shader->BindTexture(str_baseTex, m_TerrainTexture); const CMatrix3D baseTransform = GetDefaultGuiMatrix(); CMatrix3D baseTextureTransform; baseTextureTransform.SetIdentity(); shader->Uniform(str_transform, baseTransform); shader->Uniform(str_textureTransform, baseTextureTransform); DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z); // Draw territory boundaries glEnable(GL_BLEND); CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); shader->BindTexture(str_baseTex, territoryTexture.GetTexture()); const CMatrix3D* territoryTransform = territoryTexture.GetMinimapTextureMatrix(); shader->Uniform(str_transform, baseTransform); shader->Uniform(str_textureTransform, *territoryTransform); DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); tech->EndPass(); // Draw the LOS quad in black, using alpha values from the LOS texture CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); CShaderDefines losDefines; losDefines.Add(str_MINIMAP_LOS, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), losDefines); tech->BeginPass(); shader = tech->GetShader(); shader->BindTexture(str_baseTex, losTexture.GetTexture()); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const CMatrix3D* losTransform = losTexture.GetMinimapTextureMatrix(); shader->Uniform(str_transform, baseTransform); shader->Uniform(str_textureTransform, *losTransform); DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); tech->EndPass(); glDisable(GL_BLEND); PROFILE_START("minimap units"); CShaderDefines pointDefines; pointDefines.Add(str_MINIMAP_POINT, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), pointDefines); tech->BeginPass(); shader = tech->GetShader(); shader->Uniform(str_transform, baseTransform); shader->Uniform(str_pointSize, 3.f); CMatrix3D unitMatrix; unitMatrix.SetIdentity(); // Center the minimap on the origin of the axis of rotation. unitMatrix.Translate(-(x2 - x) / 2.f, -(y2 - y) / 2.f, 0.f); // Rotate the map. unitMatrix.RotateZ(angle); // Scale square maps to fit. unitMatrix.Scale(unitScale, unitScale, 1.f); // Move the minimap back to it's starting position. unitMatrix.Translate((x2 - x) / 2.f, (y2 - y) / 2.f, 0.f); // Move the minimap to it's final location. unitMatrix.Translate(x, y, z); // Apply the gui matrix. unitMatrix *= GetDefaultGuiMatrix(); // Load the transform into the shader. shader->Uniform(str_transform, unitMatrix); const float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); const float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); if (doUpdate) { VertexArrayIterator<float[2]> attrPos = m_AttributePos.GetIterator<float[2]>(); VertexArrayIterator<u8[4]> attrColor = m_AttributeColor.GetIterator<u8[4]>(); m_EntitiesDrawn = 0; MinimapUnitVertex v; std::vector<MinimapUnitVertex> pingingVertices; pingingVertices.reserve(MAX_ENTITIES_DRAWN / 2); if (cur_time > m_NextBlinkTime) { m_BlinkState = !m_BlinkState; m_NextBlinkTime = cur_time + m_HalfBlinkDuration; } entity_pos_t posX, posZ; for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) { ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second); if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) { ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID()); if (vis != ICmpRangeManager::VIS_HIDDEN) { v.a = 255; v.x = posX.ToFloat() * sx; v.y = -posZ.ToFloat() * sy; // Check minimap pinging to indicate something if (m_BlinkState && cmpMinimap->CheckPing(cur_time, m_PingDuration)) { v.r = 255; // ping color is white v.g = 255; v.b = 255; pingingVertices.push_back(v); } else { addVertex(v, attrColor, attrPos); ++m_EntitiesDrawn; } } } } // Add the pinged vertices at the end, so they are drawn on top for (size_t v = 0; v < pingingVertices.size(); ++v) { addVertex(pingingVertices[v], attrColor, attrPos); ++m_EntitiesDrawn; } ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN); m_VertexArray.Upload(); } m_VertexArray.PrepareForRendering(); if (m_EntitiesDrawn > 0) { #if !CONFIG2_GLES if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif u8* indexBase = m_IndexArray.Bind(); u8* base = m_VertexArray.Bind(); const GLsizei stride = (GLsizei)m_VertexArray.GetStride(); shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); shader->AssertPointersBound(); if (!g_Renderer.m_SkipSubmit) glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase); g_Renderer.GetStats().m_DrawCalls++; CVertexBuffer::Unbind(); #if !CONFIG2_GLES if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif } tech->EndPass(); DrawViewRect(unitMatrix); PROFILE_END("minimap units"); // Reset depth mask glDepthMask(1); }
void CMiniMap::Draw() { PROFILE3("render minimap"); // The terrain isn't actually initialized until the map is loaded, which // happens when the game is started, so abort until then. if(!(GetGUI() && g_Game && g_Game->IsGameStarted())) return; CSimulation2* sim = g_Game->GetSimulation2(); CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY); ENSURE(cmpRangeManager); // Set our globals in case they hadn't been set before m_Camera = g_Game->GetView()->GetCamera(); m_Terrain = g_Game->GetWorld()->GetTerrain(); m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); m_MapSize = m_Terrain->GetVerticesPerSide(); m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); if(!m_TerrainTexture || g_GameRestarted) CreateTextures(); // only update 2x / second // (note: since units only move a few pixels per second on the minimap, // we can get away with infrequent updates; this is slow) static double last_time; const double cur_time = timer_Time(); if(cur_time - last_time > 0.5) { last_time = cur_time; if(m_TerrainDirty) RebuildTerrainTexture(); } glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); CMatrix3D matrix = GetDefaultGuiMatrix(); glLoadMatrixf(&matrix._11); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture glDepthMask(0); CShaderProgramPtr shader; CShaderTechniquePtr tech; if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { CShaderDefines defines; defines.Add("MINIMAP_BASE", "1"); tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("minimap"), g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } else { shader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines()); shader->Bind(); } const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; const float z = GetBufferedZ(); const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize; const float angle = GetAngle(); // Draw the main textured quad //g_Renderer.BindTexture(0, m_TerrainTexture); shader->BindTexture("baseTex", m_TerrainTexture); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); DrawTexture(texCoordMax, angle, x, y, x2, y2, z); // Draw territory boundaries CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); shader->BindTexture("baseTex", territoryTexture.GetTexture()); //territoryTexture.BindTexture(0); glEnable(GL_BLEND); glMatrixMode(GL_TEXTURE); glLoadMatrixf(territoryTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); // Draw the LOS quad in black, using alpha values from the LOS texture CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add("MINIMAP_LOS", "1"); tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("minimap"), g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } shader->BindTexture("baseTex", losTexture.GetTexture()); //losTexture.BindTexture(0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor3f(0.0f, 0.0f, 0.0f); glMatrixMode(GL_TEXTURE); glLoadMatrixf(losTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add("MINIMAP_POINT", "1"); tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("minimap"), g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } // Set up the matrix for drawing points and lines glPushMatrix(); glTranslatef(x, y, z); // Rotate around the center of the map glTranslatef((x2-x)/2.f, (y2-y)/2.f, 0.f); // Scale square maps to fit in circular minimap area float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); glScalef(unitScale, unitScale, 1.f); glRotatef(angle * 180.f/M_PI, 0.f, 0.f, 1.f); glTranslatef(-(x2-x)/2.f, -(y2-y)/2.f, 0.f); PROFILE_START("minimap units"); // Don't enable GL_POINT_SMOOTH because it's far too slow // (~70msec/frame on a GF4 rendering a thousand points) glPointSize(3.f); float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); std::vector<MinimapUnitVertex> vertexArray; vertexArray.reserve(ents.size()); for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) { MinimapUnitVertex v; ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second); entity_pos_t posX, posZ; if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) { ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID()); if (vis != ICmpRangeManager::VIS_HIDDEN) { v.a = 255; v.x = posX.ToFloat()*sx; v.y = -posZ.ToFloat()*sy; vertexArray.push_back(v); } } } if (!vertexArray.empty()) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); shader->VertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x); shader->ColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r); glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size()); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); } PROFILE_END("minimap units"); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add("MINIMAP_LINE", "1"); tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("minimap"), g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } DrawViewRect(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); } else { shader->Unbind(); } // Reset everything back to normal glPointSize(1.0f); glEnable(GL_TEXTURE_2D); glDepthMask(1); }
void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches, const CShaderDefines& context, ShadowMap* shadow, bool isDummyShader, const CShaderProgramPtr& dummy) { Allocators::Arena<> arena(ARENA_SIZE); typedef std::vector<SBlendBatch, ProxyAllocator<SBlendBatch, Allocators::Arena<> > > BatchesStack; BatchesStack batches((BatchesStack::allocator_type(arena))); CShaderDefines contextBlend = context; contextBlend.Add("BLEND", "1"); PROFILE_START("compute batches"); // Reserve an arbitrary size that's probably big enough in most cases, // to avoid heavy reallocations batches.reserve(256); typedef std::vector<SBlendStackItem, ProxyAllocator<SBlendStackItem, Allocators::Arena<> > > BlendStacks; BlendStacks blendStacks((BlendStacks::allocator_type(arena))); blendStacks.reserve(patches.size()); // Extract all the blend splats from each patch for (size_t i = 0; i < patches.size(); ++i) { CPatchRData* patch = patches[i]; if (!patch->m_BlendSplats.empty()) { blendStacks.push_back(SBlendStackItem(patch->m_VBBlends, patch->m_VBBlendIndices, patch->m_BlendSplats, arena)); // Reverse the splats so the first to be rendered is at the back of the list std::reverse(blendStacks.back().splats.begin(), blendStacks.back().splats.end()); } } // Rearrange the collection of splats to be grouped by texture, preserving // order of splats within each patch: // (This is exactly the same algorithm used in CPatchRData::BuildBlends, // but applied to patch-sized splats rather than to tile-sized splats; // see that function for comments on the algorithm.) while (true) { if (!batches.empty()) { CTerrainTextureEntry* tex = batches.back().m_Texture; for (size_t k = 0; k < blendStacks.size(); ++k) { SBlendStackItem::SplatStack& splats = blendStacks[k].splats; if (!splats.empty() && splats.back().m_Texture == tex) { CVertexBuffer::VBChunk* vertices = blendStacks[k].vertices; CVertexBuffer::VBChunk* indices = blendStacks[k].indices; BatchElements& batch = PooledPairGet(PooledMapGet(batches.back().m_Batches, vertices->m_Owner, arena), indices->m_Owner, arena); batch.first.push_back(splats.back().m_IndexCount); u8* indexBase = indices->m_Owner->GetBindAddress(); batch.second.push_back(indexBase + sizeof(u16)*(indices->m_Index + splats.back().m_IndexStart)); splats.pop_back(); } } } CTerrainTextureEntry* bestTex = NULL; size_t bestStackSize = 0; for (size_t k = 0; k < blendStacks.size(); ++k) { SBlendStackItem::SplatStack& splats = blendStacks[k].splats; if (splats.size() > bestStackSize) { bestStackSize = splats.size(); bestTex = splats.back().m_Texture; } } if (bestStackSize == 0) break; SBlendBatch layer(arena); layer.m_Texture = bestTex; batches.push_back(layer); } PROFILE_END("compute batches"); CVertexBuffer* lastVB = NULL; for (BatchesStack::iterator itt = batches.begin(); itt != batches.end(); ++itt) { if (itt->m_Texture->GetMaterial().GetSamplers().size() == 0) continue; int numPasses = 1; CShaderTechniquePtr techBase; if (!isDummyShader) { techBase = g_Renderer.GetShaderManager().LoadEffect(itt->m_Texture->GetMaterial().GetShaderEffect(), contextBlend, itt->m_Texture->GetMaterial().GetShaderDefines()); numPasses = techBase->GetNumPasses(); } CShaderProgramPtr previousShader; for (int pass = 0; pass < numPasses; ++pass) { if (!isDummyShader) { techBase->BeginPass(pass); TerrainRenderer::PrepareShader(techBase->GetShader(), shadow); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } const CShaderProgramPtr& shader = isDummyShader ? dummy : techBase->GetShader(pass); if (itt->m_Texture) { CMaterial::SamplersVector samplers = itt->m_Texture->GetMaterial().GetSamplers(); size_t samplersNum = samplers.size(); for (size_t s = 0; s < samplersNum; ++s) { CMaterial::TextureSampler &samp = samplers[s]; shader->BindTexture(samp.Name.c_str(), samp.Sampler); } shader->BindTexture("blendTex", itt->m_Texture->m_TerrainAlpha->second.m_hCompositeAlphaMap); itt->m_Texture->GetMaterial().GetStaticUniforms().BindUniforms(shader); #if !CONFIG2_GLES if (isDummyShader) { pglClientActiveTextureARB(GL_TEXTURE0); glMatrixMode(GL_TEXTURE); glLoadMatrixf(itt->m_Texture->GetTextureMatrix()); glMatrixMode(GL_MODELVIEW); } else #endif { float c = itt->m_Texture->GetTextureMatrix()[0]; float ms = itt->m_Texture->GetTextureMatrix()[8]; shader->Uniform("textureTransform", c, ms, -ms, 0.f); } } else { shader->BindTexture("baseTex", g_Renderer.GetTextureManager().GetErrorTexture()); } for (VertexBufferBatches::iterator itv = itt->m_Batches.begin(); itv != itt->m_Batches.end(); ++itv) { // Rebind the VB only if it changed since the last batch if (itv->first != lastVB || shader != previousShader) { lastVB = itv->first; previousShader = shader; GLsizei stride = sizeof(SBlendVertex); SBlendVertex *base = (SBlendVertex *)itv->first->Bind(); shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor); shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, &base->m_AlphaUVs[0]); } shader->AssertPointersBound(); for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) { it->first->Bind(); BatchElements& batch = it->second; if (!g_Renderer.m_SkipSubmit) { for (size_t i = 0; i < batch.first.size(); ++i) glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); } g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_BlendSplats++; g_Renderer.m_Stats.m_TerrainTris += std::accumulate(batch.first.begin(), batch.first.end(), 0) / 3; } } if (!isDummyShader) { glDisable(GL_BLEND); techBase->EndPass(); } } } #if !CONFIG2_GLES if (isDummyShader) { pglClientActiveTextureARB(GL_TEXTURE0); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); } #endif CVertexBuffer::Unbind(); }
void CChart::Draw() { PROFILE3("render chart"); if (!GetGUI()) return; if (m_Series.empty()) return; const float bz = GetBufferedZ(); CRect rect = GetChartRect(); const float width = rect.GetWidth(); const float height = rect.GetHeight(); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture. glDepthMask(0); // Setup the render state CMatrix3D transform = GetDefaultGuiMatrix(); CShaderDefines lineDefines; CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid, g_Renderer.GetSystemShaderDefines(), lineDefines); tech->BeginPass(); CShaderProgramPtr shader = tech->GetShader(); shader->Uniform(str_transform, transform); CVector2D leftBottom, rightTop; leftBottom = rightTop = m_Series[0].m_Points[0]; for (const CChartData& data : m_Series) for (const CVector2D& point : data.m_Points) { if (point.X < leftBottom.X) leftBottom.X = point.X; if (point.Y < leftBottom.Y) leftBottom.Y = point.Y; if (point.X > rightTop.X) rightTop.X = point.X; if (point.Y > rightTop.Y) rightTop.Y = point.Y; } CVector2D scale(width / (rightTop.X - leftBottom.X), height / (rightTop.Y - leftBottom.Y)); for (const CChartData& data : m_Series) { if (data.m_Points.empty()) continue; std::vector<float> vertices; vertices.reserve(data.m_Points.size() * 3); for (const CVector2D& point : data.m_Points) { vertices.push_back(rect.left + (point.X - leftBottom.X) * scale.X); vertices.push_back(rect.bottom - (point.Y - leftBottom.Y) * scale.Y); vertices.push_back(bz + 0.5f); } shader->Uniform(str_color, data.m_Color); shader->VertexPointer(3, GL_FLOAT, 0, &vertices[0]); shader->AssertPointersBound(); glEnable(GL_LINE_SMOOTH); glLineWidth(1.1f); if (!g_Renderer.m_SkipSubmit) glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 3); glLineWidth(1.0f); glDisable(GL_LINE_SMOOTH); } tech->EndPass(); // Reset depth mask glDepthMask(1); }
void CPostprocManager::ApplyBlurGauss(GLuint inOutTex, GLuint tempTex, int inWidth, int inHeight) { // Set tempTex as our rendering target. pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tempTex, 0); // Get bloom shader, for a horizontal Gaussian blur pass. CShaderDefines defines2; defines2.Add(str_BLOOM_PASS_H, str_1); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, g_Renderer.GetSystemShaderDefines(), defines2); tech->BeginPass(); CShaderProgramPtr shader = tech->GetShader(); shader->BindTexture(str_renderedTex, inOutTex); shader->Uniform(str_texSize, inWidth, inHeight, 0.0f, 0.0f); const SViewPort oldVp = g_Renderer.GetViewport(); const SViewPort vp = { 0, 0, inWidth, inHeight }; g_Renderer.SetViewport(vp); float quadVerts[] = { 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f }; float quadTex[] = { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }; shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); shader->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, 0, 6); g_Renderer.SetViewport(oldVp); tech->EndPass(); // Set result texture as our render target. pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, inOutTex, 0); // Get bloom shader, for a vertical Gaussian blur pass. CShaderDefines defines3; defines3.Add(str_BLOOM_PASS_V, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, g_Renderer.GetSystemShaderDefines(), defines3); tech->BeginPass(); shader = tech->GetShader(); // Our input texture to the shader is the output of the horizontal pass. shader->BindTexture(str_renderedTex, tempTex); shader->Uniform(str_texSize, inWidth, inHeight, 0.0f, 0.0f); g_Renderer.SetViewport(vp); shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); shader->VertexPointer(2, GL_FLOAT, 0, quadVerts); shader->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, 0, 6); g_Renderer.SetViewport(oldVp); tech->EndPass(); }
// Render void CProfileViewer::RenderProfile() { if (!m->profileVisible) return; if (!m->path.size()) { m->profileVisible = false; return; } PROFILE3_GPU("profile viewer"); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); AbstractProfileTable* table = m->path[m->path.size() - 1]; const std::vector<ProfileColumn>& columns = table->GetColumns(); size_t numrows = table->GetNumberRows(); CStrIntern font_name("mono-stroke-10"); CFontMetrics font(font_name); int lineSpacing = font.GetLineSpacing(); // Render background GLint estimate_height; GLint estimate_width; estimate_width = 50; for(size_t i = 0; i < columns.size(); ++i) estimate_width += (GLint)columns[i].width; estimate_height = 3 + (GLint)numrows; if (m->path.size() > 1) estimate_height += 2; estimate_height = lineSpacing*estimate_height; CShaderTechniquePtr solidTech = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid); solidTech->BeginPass(); CShaderProgramPtr solidShader = solidTech->GetShader(); solidShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.5f); CMatrix3D transform = GetDefaultGuiMatrix(); solidShader->Uniform(str_transform, transform); float backgroundVerts[] = { (float)estimate_width, 0.0f, 0.0f, 0.0f, 0.0f, (float)estimate_height, 0.0f, (float)estimate_height, (float)estimate_width, (float)estimate_height, (float)estimate_width, 0.0f }; solidShader->VertexPointer(2, GL_FLOAT, 0, backgroundVerts); solidShader->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, 0, 6); transform.PostTranslate(22.0f, lineSpacing*3.0f, 0.0f); solidShader->Uniform(str_transform, transform); // Draw row backgrounds for (size_t row = 0; row < numrows; ++row) { if (row % 2) solidShader->Uniform(str_color, 1.0f, 1.0f, 1.0f, 0.1f); else solidShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.1f); float rowVerts[] = { -22.f, 2.f, estimate_width-22.f, 2.f, estimate_width-22.f, 2.f-lineSpacing, estimate_width-22.f, 2.f-lineSpacing, -22.f, 2.f-lineSpacing, -22.f, 2.f }; solidShader->VertexPointer(2, GL_FLOAT, 0, rowVerts); solidShader->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, 0, 6); transform.PostTranslate(0.0f, lineSpacing, 0.0f); solidShader->Uniform(str_transform, transform); } solidTech->EndPass(); // Print table and column titles CShaderTechniquePtr textTech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text); textTech->BeginPass(); CTextRenderer textRenderer(textTech->GetShader()); textRenderer.Font(font_name); textRenderer.Color(1.0f, 1.0f, 1.0f); textRenderer.PrintfAt(2.0f, lineSpacing, L"%hs", table->GetTitle().c_str()); textRenderer.Translate(22.0f, lineSpacing*2.0f, 0.0f); float colX = 0.0f; for (size_t col = 0; col < columns.size(); ++col) { CStrW text = columns[col].title.FromUTF8(); int w, h; font.CalculateStringSize(text.c_str(), w, h); float x = colX; if (col > 0) // right-align all but the first column x += columns[col].width - w; textRenderer.Put(x, 0.0f, text.c_str()); colX += columns[col].width; } textRenderer.Translate(0.0f, lineSpacing, 0.0f); // Print rows int currentExpandId = 1; for (size_t row = 0; row < numrows; ++row) { if (table->IsHighlightRow(row)) textRenderer.Color(1.0f, 0.5f, 0.5f); else textRenderer.Color(1.0f, 1.0f, 1.0f); if (table->GetChild(row)) { textRenderer.PrintfAt(-15.0f, 0.0f, L"%d", currentExpandId); currentExpandId++; } float colX = 0.0f; for (size_t col = 0; col < columns.size(); ++col) { CStrW text = table->GetCellText(row, col).FromUTF8(); int w, h; font.CalculateStringSize(text.c_str(), w, h); float x = colX; if (col > 0) // right-align all but the first column x += columns[col].width - w; textRenderer.Put(x, 0.0f, text.c_str()); colX += columns[col].width; } textRenderer.Translate(0.0f, lineSpacing, 0.0f); } textRenderer.Color(1.0f, 1.0f, 1.0f); if (m->path.size() > 1) { textRenderer.Translate(0.0f, lineSpacing, 0.0f); textRenderer.Put(-15.0f, 0.0f, L"0"); textRenderer.Put(0.0f, 0.0f, L"back to parent"); } textRenderer.Render(); textTech->EndPass(); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); }
void OverlayRenderer::RenderForegroundOverlays(const CCamera& viewCamera) { PROFILE3_GPU("overlays (fg)"); #if CONFIG2_GLES #warning TODO: implement OverlayRenderer::RenderForegroundOverlays for GLES #else glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST); CVector3D right = -viewCamera.m_Orientation.GetLeft(); CVector3D up = viewCamera.m_Orientation.GetUp(); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); CShaderProgramPtr shader; CShaderTechniquePtr tech; if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech = g_Renderer.GetShaderManager().LoadEffect("foreground_overlay"); tech->BeginPass(); shader = tech->GetShader(); } else { shader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines()); shader->Bind(); } float uvs[8] = { 0,0, 1,0, 1,1, 0,1 }; shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, sizeof(float)*2, &uvs[0]); for (size_t i = 0; i < m->sprites.size(); ++i) { SOverlaySprite* sprite = m->sprites[i]; shader->BindTexture("baseTex", sprite->m_Texture); CVector3D pos[4] = { sprite->m_Position + right*sprite->m_X0 + up*sprite->m_Y0, sprite->m_Position + right*sprite->m_X1 + up*sprite->m_Y0, sprite->m_Position + right*sprite->m_X1 + up*sprite->m_Y1, sprite->m_Position + right*sprite->m_X0 + up*sprite->m_Y1 }; shader->VertexPointer(3, GL_FLOAT, sizeof(float)*3, &pos[0].X); glDrawArrays(GL_QUADS, 0, (GLsizei)4); g_Renderer.GetStats().m_DrawCalls++; g_Renderer.GetStats().m_OverlayTris += 2; } if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); } else { shader->Unbind(); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); #endif }
void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow, bool filtered) { ENSURE(m->phase == Phase_Render); std::vector<CPatchRData*>& visiblePatches = filtered ? m->filteredPatches : m->visiblePatches; std::vector<CDecalRData*>& visibleDecals = filtered ? m->filteredDecals : m->visibleDecals; if (visiblePatches.empty() && visibleDecals.empty()) return; CShaderManager& shaderManager = g_Renderer.GetShaderManager(); typedef std::map<CStr, CStr> Defines; Defines defBasic; if (shadow) { defBasic["USE_SHADOW"] = "1"; if (g_Renderer.m_Caps.m_ARBProgramShadow && g_Renderer.m_Options.m_ARBProgramShadow) defBasic["USE_FP_SHADOW"] = "1"; if (g_Renderer.m_Options.m_ShadowPCF) defBasic["USE_SHADOW_PCF"] = "1"; #if !CONFIG2_GLES defBasic["USE_SHADOW_SAMPLER"] = "1"; #endif } defBasic["LIGHTING_MODEL_" + g_Renderer.GetLightEnv().GetLightingModel()] = "1"; CShaderTechniquePtr techBase(shaderManager.LoadEffect("terrain_base", defBasic)); CShaderTechniquePtr techBlend(shaderManager.LoadEffect("terrain_blend", defBasic)); CShaderTechniquePtr techDecal(shaderManager.LoadEffect("terrain_decal", defBasic)); // render the solid black sides of the map first CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect("gui_solid"); techSolid->BeginPass(); CShaderProgramPtr shaderSolid = techSolid->GetShader(); shaderSolid->Uniform("transform", g_Renderer.GetViewCamera().GetViewProjection()); shaderSolid->Uniform("color", 0.0f, 0.0f, 0.0f, 1.0f); PROFILE_START("render terrain sides"); for (size_t i = 0; i < visiblePatches.size(); ++i) visiblePatches[i]->RenderSides(shaderSolid); PROFILE_END("render terrain sides"); techSolid->EndPass(); techBase->BeginPass(); PrepareShader(techBase->GetShader(), shadow); PROFILE_START("render terrain base"); CPatchRData::RenderBases(visiblePatches, techBase->GetShader(), false); PROFILE_END("render terrain base"); techBase->EndPass(); // render blends techBlend->BeginPass(); PrepareShader(techBlend->GetShader(), shadow); // switch on blending glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // no need to write to the depth buffer a second time glDepthMask(0); // render blend passes for each patch PROFILE_START("render terrain blends"); CPatchRData::RenderBlends(visiblePatches, techBlend->GetShader(), false); PROFILE_END("render terrain blends"); techBlend->EndPass(); // Render terrain decals techDecal->BeginPass(); PrepareShader(techDecal->GetShader(), shadow); PROFILE_START("render terrain decals"); for (size_t i = 0; i < visibleDecals.size(); ++i) visibleDecals[i]->Render(techDecal->GetShader(), false); PROFILE_END("render terrain decals"); techDecal->EndPass(); // restore OpenGL state g_Renderer.BindTexture(1, 0); g_Renderer.BindTexture(2, 0); g_Renderer.BindTexture(3, 0); glDepthMask(1); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); }
void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags) { if (m->submissions[cullGroup].empty()) return; CMatrix3D worldToCam; g_Renderer.GetViewCamera().m_Orientation.GetInverse(worldToCam); /* * Rendering approach: * * m->submissions contains the list of CModels to render. * * The data we need to render a model is: * - CShaderTechnique * - CTexture * - CShaderUniforms * - CModelDef (mesh data) * - CModel (model instance data) * * For efficient rendering, we need to batch the draw calls to minimise state changes. * (Uniform and texture changes are assumed to be cheaper than binding new mesh data, * and shader changes are assumed to be most expensive.) * First, group all models that share a technique to render them together. * Within those groups, sub-group by CModelDef. * Within those sub-groups, sub-sub-group by CTexture. * Within those sub-sub-groups, sub-sub-sub-group by CShaderUniforms. * * Alpha-blended models have to be sorted by distance from camera, * then we can batch as long as the order is preserved. * Non-alpha-blended models can be arbitrarily reordered to maximise batching. * * For each model, the CShaderTechnique is derived from: * - The current global 'context' defines * - The CModel's material's defines * - The CModel's material's shader effect name * * There are a smallish number of materials, and a smaller number of techniques. * * To minimise technique lookups, we first group models by material, * in 'materialBuckets' (a hash table). * * For each material bucket we then look up the appropriate shader technique. * If the technique requires sort-by-distance, the model is added to the * 'sortByDistItems' list with its computed distance. * Otherwise, the bucket's list of models is sorted by modeldef+texture+uniforms, * then the technique and model list is added to 'techBuckets'. * * 'techBuckets' is then sorted by technique, to improve batching when multiple * materials map onto the same technique. * * (Note that this isn't perfect batching: we don't sort across models in * multiple buckets that share a technique. In practice that shouldn't reduce * batching much (we rarely have one mesh used with multiple materials), * and it saves on copying and lets us sort smaller lists.) * * Extra tech buckets are added for the sorted-by-distance models without reordering. * Finally we render by looping over each tech bucket, then looping over the model * list in each, rebinding the GL state whenever it changes. */ Allocators::DynamicArena arena(256 * KiB); typedef ProxyAllocator<CModel*, Allocators::DynamicArena> ModelListAllocator; typedef std::vector<CModel*, ModelListAllocator> ModelList_t; typedef boost::unordered_map<SMRMaterialBucketKey, ModelList_t, SMRMaterialBucketKeyHash, std::equal_to<SMRMaterialBucketKey>, ProxyAllocator<std::pair<const SMRMaterialBucketKey, ModelList_t>, Allocators::DynamicArena> > MaterialBuckets_t; MaterialBuckets_t materialBuckets((MaterialBuckets_t::allocator_type(arena))); { PROFILE3("bucketing by material"); for (size_t i = 0; i < m->submissions[cullGroup].size(); ++i) { CModel* model = m->submissions[cullGroup][i]; uint32_t condFlags = 0; const CShaderConditionalDefines& condefs = model->GetMaterial().GetConditionalDefines(); for (size_t j = 0; j < condefs.GetSize(); ++j) { const CShaderConditionalDefines::CondDefine& item = condefs.GetItem(j); int type = item.m_CondType; switch (type) { case DCOND_DISTANCE: { CVector3D modelpos = model->GetTransform().GetTranslation(); float dist = worldToCam.Transform(modelpos).Z; float dmin = item.m_CondArgs[0]; float dmax = item.m_CondArgs[1]; if ((dmin < 0 || dist >= dmin) && (dmax < 0 || dist < dmax)) condFlags |= (1 << j); break; } } } CShaderDefines defs = model->GetMaterial().GetShaderDefines(condFlags); SMRMaterialBucketKey key(model->GetMaterial().GetShaderEffect(), defs); MaterialBuckets_t::iterator it = materialBuckets.find(key); if (it == materialBuckets.end()) { std::pair<MaterialBuckets_t::iterator, bool> inserted = materialBuckets.insert( std::make_pair(key, ModelList_t(ModelList_t::allocator_type(arena)))); inserted.first->second.reserve(32); inserted.first->second.push_back(model); } else { it->second.push_back(model); } } } typedef ProxyAllocator<SMRSortByDistItem, Allocators::DynamicArena> SortByDistItemsAllocator; std::vector<SMRSortByDistItem, SortByDistItemsAllocator> sortByDistItems((SortByDistItemsAllocator(arena))); typedef ProxyAllocator<CShaderTechniquePtr, Allocators::DynamicArena> SortByTechItemsAllocator; std::vector<CShaderTechniquePtr, SortByTechItemsAllocator> sortByDistTechs((SortByTechItemsAllocator(arena))); // indexed by sortByDistItems[i].techIdx // (which stores indexes instead of CShaderTechniquePtr directly // to avoid the shared_ptr copy cost when sorting; maybe it'd be better // if we just stored raw CShaderTechnique* and assumed the shader manager // will keep it alive long enough) typedef ProxyAllocator<SMRTechBucket, Allocators::DynamicArena> TechBucketsAllocator; std::vector<SMRTechBucket, TechBucketsAllocator> techBuckets((TechBucketsAllocator(arena))); { PROFILE3("processing material buckets"); for (MaterialBuckets_t::iterator it = materialBuckets.begin(); it != materialBuckets.end(); ++it) { CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(it->first.effect, context, it->first.defines); // Skip invalid techniques (e.g. from data file errors) if (!tech) continue; if (tech->GetSortByDistance()) { // Add the tech into a vector so we can index it // (There might be duplicates in this list, but that doesn't really matter) if (sortByDistTechs.empty() || sortByDistTechs.back() != tech) sortByDistTechs.push_back(tech); size_t techIdx = sortByDistTechs.size()-1; // Add each model into sortByDistItems for (size_t i = 0; i < it->second.size(); ++i) { SMRSortByDistItem itemWithDist; itemWithDist.techIdx = techIdx; CModel* model = it->second[i]; itemWithDist.model = model; CVector3D modelpos = model->GetTransform().GetTranslation(); itemWithDist.dist = worldToCam.Transform(modelpos).Z; sortByDistItems.push_back(itemWithDist); } } else { // Sort model list by modeldef+texture, for batching // TODO: This only sorts by base texture. While this is an OK approximation // for most cases (as related samplers are usually used together), it would be better // to take all the samplers into account when sorting here. std::sort(it->second.begin(), it->second.end(), SMRBatchModel()); // Add a tech bucket pointing at this model list SMRTechBucket techBucket = { tech, &it->second[0], it->second.size() }; techBuckets.push_back(techBucket); } } } { PROFILE3("sorting tech buckets"); // Sort by technique, for better batching std::sort(techBuckets.begin(), techBuckets.end(), SMRCompareTechBucket()); } // List of models corresponding to sortByDistItems[i].model // (This exists primarily because techBuckets wants a CModel**; // we could avoid the cost of copying into this list by adding // a stride length into techBuckets and not requiring contiguous CModel*s) std::vector<CModel*, ModelListAllocator> sortByDistModels((ModelListAllocator(arena))); if (!sortByDistItems.empty()) { { PROFILE3("sorting items by dist"); std::sort(sortByDistItems.begin(), sortByDistItems.end(), SMRCompareSortByDistItem()); } { PROFILE3("batching dist-sorted items"); sortByDistModels.reserve(sortByDistItems.size()); // Find runs of distance-sorted models that share a technique, // and create a new tech bucket for each run size_t start = 0; // start of current run size_t currentTechIdx = sortByDistItems[start].techIdx; for (size_t end = 0; end < sortByDistItems.size(); ++end) { sortByDistModels.push_back(sortByDistItems[end].model); size_t techIdx = sortByDistItems[end].techIdx; if (techIdx != currentTechIdx) { // Start of a new run - push the old run into a new tech bucket SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], end-start }; techBuckets.push_back(techBucket); start = end; currentTechIdx = techIdx; } } // Add the tech bucket for the final run SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], sortByDistItems.size()-start }; techBuckets.push_back(techBucket); } } { PROFILE3("rendering bucketed submissions"); size_t idxTechStart = 0; // This vector keeps track of texture changes during rendering. It is kept outside the // loops to avoid excessive reallocations. The token allocation of 64 elements // should be plenty, though it is reallocated below (at a cost) if necessary. typedef ProxyAllocator<CTexture*, Allocators::DynamicArena> TextureListAllocator; std::vector<CTexture*, TextureListAllocator> currentTexs((TextureListAllocator(arena))); currentTexs.reserve(64); // texBindings holds the identifier bindings in the shader, which can no longer be defined // statically in the ShaderRenderModifier class. texBindingNames uses interned strings to // keep track of when bindings need to be reevaluated. typedef ProxyAllocator<CShaderProgram::Binding, Allocators::DynamicArena> BindingListAllocator; std::vector<CShaderProgram::Binding, BindingListAllocator> texBindings((BindingListAllocator(arena))); texBindings.reserve(64); typedef ProxyAllocator<CStrIntern, Allocators::DynamicArena> BindingNamesListAllocator; std::vector<CStrIntern, BindingNamesListAllocator> texBindingNames((BindingNamesListAllocator(arena))); texBindingNames.reserve(64); while (idxTechStart < techBuckets.size()) { CShaderTechniquePtr currentTech = techBuckets[idxTechStart].tech; // Find runs [idxTechStart, idxTechEnd) in techBuckets of the same technique size_t idxTechEnd; for (idxTechEnd = idxTechStart + 1; idxTechEnd < techBuckets.size(); ++idxTechEnd) { if (techBuckets[idxTechEnd].tech != currentTech) break; } // For each of the technique's passes, render all the models in this run for (int pass = 0; pass < currentTech->GetNumPasses(); ++pass) { currentTech->BeginPass(pass); const CShaderProgramPtr& shader = currentTech->GetShader(pass); int streamflags = shader->GetStreamFlags(); modifier->BeginPass(shader); m->vertexRenderer->BeginPass(streamflags); // When the shader technique changes, textures need to be // rebound, so ensure there are no remnants from the last pass. // (the vector size is set to 0, but memory is not freed) currentTexs.clear(); texBindings.clear(); texBindingNames.clear(); CModelDef* currentModeldef = NULL; CShaderUniforms currentStaticUniforms; for (size_t idx = idxTechStart; idx < idxTechEnd; ++idx) { CModel** models = techBuckets[idx].models; size_t numModels = techBuckets[idx].numModels; for (size_t i = 0; i < numModels; ++i) { CModel* model = models[i]; if (flags && !(model->GetFlags() & flags)) continue; const CMaterial::SamplersVector& samplers = model->GetMaterial().GetSamplers(); size_t samplersNum = samplers.size(); // make sure the vectors are the right virtual sizes, and also // reallocate if there are more samplers than expected. if (currentTexs.size() != samplersNum) { currentTexs.resize(samplersNum, NULL); texBindings.resize(samplersNum, CShaderProgram::Binding()); texBindingNames.resize(samplersNum, CStrIntern()); // ensure they are definitely empty std::fill(texBindings.begin(), texBindings.end(), CShaderProgram::Binding()); std::fill(currentTexs.begin(), currentTexs.end(), (CTexture*)NULL); std::fill(texBindingNames.begin(), texBindingNames.end(), CStrIntern()); } // bind the samplers to the shader for (size_t s = 0; s < samplersNum; ++s) { const CMaterial::TextureSampler& samp = samplers[s]; CShaderProgram::Binding bind = texBindings[s]; // check that the handles are current // and reevaluate them if necessary if (texBindingNames[s] == samp.Name && bind.Active()) { bind = texBindings[s]; } else { bind = shader->GetTextureBinding(samp.Name); texBindings[s] = bind; texBindingNames[s] = samp.Name; } // same with the actual sampler bindings CTexture* newTex = samp.Sampler.get(); if (bind.Active() && newTex != currentTexs[s]) { shader->BindTexture(bind, samp.Sampler->GetHandle()); currentTexs[s] = newTex; } } // Bind modeldef when it changes CModelDef* newModeldef = model->GetModelDef().get(); if (newModeldef != currentModeldef) { currentModeldef = newModeldef; m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef); } // Bind all uniforms when any change CShaderUniforms newStaticUniforms = model->GetMaterial().GetStaticUniforms(); if (newStaticUniforms != currentStaticUniforms) { currentStaticUniforms = newStaticUniforms; currentStaticUniforms.BindUniforms(shader); } const CShaderRenderQueries& renderQueries = model->GetMaterial().GetRenderQueries(); for (size_t q = 0; q < renderQueries.GetSize(); q++) { CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q); if (rq.first == RQUERY_TIME) { CShaderProgram::Binding binding = shader->GetUniformBinding(rq.second); if (binding.Active()) { double time = g_Renderer.GetTimeManager().GetGlobalTime(); shader->Uniform(binding, time, 0,0,0); } } else if (rq.first == RQUERY_WATER_TEX) { WaterManager* WaterMgr = g_Renderer.GetWaterManager(); double time = WaterMgr->m_WaterTexTimer; double period = 1.6; int curTex = (int)(time*60/period) % 60; if (WaterMgr->m_RenderWater && WaterMgr->WillRenderFancyWater()) shader->BindTexture(str_waterTex, WaterMgr->m_NormalMap[curTex]); else shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture()); } else if (rq.first == RQUERY_SKY_CUBE) { shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube()); } } modifier->PrepareModel(shader, model); CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData()); ENSURE(rdata->GetKey() == m->vertexRenderer.get()); m->vertexRenderer->RenderModel(shader, streamflags, model, rdata); } } m->vertexRenderer->EndPass(streamflags); currentTech->EndPass(pass); } idxTechStart = idxTechEnd; } } }
void CPostprocManager::ApplyBlurGauss(GLuint inOutTex, GLuint tempTex, int inWidth, int inHeight) { // Set tempTex as our rendering target. pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tempTex, 0); // Get bloom shader, for a horizontal Gaussian blur pass. CShaderDefines defines2; defines2.Add(str_BLOOM_PASS_H, str_1); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, g_Renderer.GetSystemShaderDefines(), defines2); tech->BeginPass(); CShaderProgramPtr shader = tech->GetShader(); shader->BindTexture(str_renderedTex, inOutTex); shader->Uniform(str_texSize, inWidth, inHeight, 0.0f, 0.0f); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, inWidth, inHeight); glBegin(GL_QUADS); glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(1.0, 1.0); glVertex2f(1,1); glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); glEnd(); glPopAttrib(); tech->EndPass(); // Set result texture as our render target. pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, inOutTex, 0); // Get bloom shader, for a vertical Gaussian blur pass. CShaderDefines defines3; defines3.Add(str_BLOOM_PASS_V, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, g_Renderer.GetSystemShaderDefines(), defines3); tech->BeginPass(); shader = tech->GetShader(); // Our input texture to the shader is the output of the horizontal pass. shader->BindTexture(str_renderedTex, tempTex); shader->Uniform(str_texSize, inWidth, inHeight, 0.0f, 0.0f); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, inWidth, inHeight); glBegin(GL_QUADS); glColor4f(1.f, 1.f, 1.f, 1.f); glTexCoord2f(1.0, 1.0); glVertex2f(1,1); glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); glEnd(); glPopAttrib(); tech->EndPass(); }