bool C4FoWRegion::Render(const C4TargetFacet *pOnScreen) { #ifndef USE_CONSOLE // Update FoW at interesting location pFoW->Update(Region, pPlayer); // On screen? No need to set up frame buffer - simply shortcut if (pOnScreen) { pFoW->Render(this, pOnScreen, pPlayer, pGL->GetProjectionMatrix()); return true; } // Set up shader. If this one doesn't work, we're really in trouble. C4Shader *pShader = pFoW->GetFramebufShader(); assert(pShader); if (!pShader) return false; // Create & bind the frame buffer pDraw->StorePrimaryClipper(); if(!BindFramebuf()) { pDraw->RestorePrimaryClipper(); return false; } assert(pSurface && hFrameBufDraw); if (!pSurface || !hFrameBufDraw) return false; // Set up a clean context glViewport(0, 0, pSurface->Wdt, pSurface->Hgt); const StdProjectionMatrix projectionMatrix = StdProjectionMatrix::Orthographic(0.0f, pSurface->Wdt, pSurface->Hgt, 0.0f); // Clear texture contents assert(pSurface->Hgt % 2 == 0); glScissor(0, pSurface->Hgt / 2, pSurface->Wdt, pSurface->Hgt / 2); glClearColor(0.0f, 0.5f / 1.5f, 0.5f / 1.5f, 0.0f); glEnable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT); // clear lower half of texture glScissor(0, 0, pSurface->Wdt, pSurface->Hgt / 2); glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); // Render FoW to frame buffer object glBlendFunc(GL_ONE, GL_ONE); pFoW->Render(this, NULL, pPlayer, projectionMatrix); // Copy over the old state if (OldRegion.Wdt > 0) { // How much the borders have moved int dx0 = Region.x - OldRegion.x, dy0 = Region.y - OldRegion.y, dx1 = Region.x + Region.Wdt - OldRegion.x - OldRegion.Wdt, dy1 = Region.y + Region.Hgt - OldRegion.y - OldRegion.Hgt; // Source and target rect coordinates (landscape coordinate system) int sx0 = std::max(0, dx0), sy0 = std::max(0, dy0), sx1 = OldRegion.Wdt - std::max(0, -dx1), sy1 = OldRegion.Hgt - std::max(0, -dy1), tx0 = std::max(0, -dx0), ty0 = std::max(0, -dy0), tx1 = Region.Wdt - std::max(0, dx1), ty1 = Region.Hgt - std::max(0, dy1); // Quad coordinates float vtxData[16]; float* squad = &vtxData[0]; float* tquad = &vtxData[8]; squad[0] = float(sx0); squad[1] = float(sy0); squad[2] = float(sx0); squad[3] = float(sy1); squad[4] = float(sx1); squad[5] = float(sy0); squad[6] = float(sx1); squad[7] = float(sy1); tquad[0] = float(tx0); tquad[1] = float(ty0); tquad[2] = float(tx0); tquad[3] = float(ty1); tquad[4] = float(tx1); tquad[5] = float(ty0); tquad[6] = float(tx1); tquad[7] = float(ty1); // Transform into texture coordinates for (int i = 0; i < 4; i++) { squad[i*2] = squad[i*2] / pBackSurface->Wdt; squad[i*2+1] = 1.0 - squad[i*2+1] / pBackSurface->Hgt; } // Load coordinates into vertex buffer if (hVBO == 0) { glGenBuffers(1, &hVBO); glBindBuffer(GL_ARRAY_BUFFER, hVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vtxData), vtxData, GL_STREAM_DRAW); assert(vaoid == 0); vaoid = pGL->GenVAOID(); } else { glBindBuffer(GL_ARRAY_BUFFER, hVBO); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vtxData), vtxData); } // Copy using shader C4ShaderCall Call(pShader); Call.Start(); if (Call.AllocTexUnit(C4FoWFSU_Texture)) glBindTexture(GL_TEXTURE_2D, pBackSurface->texture->texName); Call.SetUniformMatrix4x4(C4FoWFSU_ProjectionMatrix, projectionMatrix); glBlendFunc(GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_COLOR); float normalBlend = 1.0f / 4.0f, // Normals change quickly brightBlend = 1.0f / 16.0f; // Intensity more slowly glBlendColor(0.0f,normalBlend,normalBlend,brightBlend); GLuint vao; const bool has_vao = pGL->GetVAO(vaoid, vao); glBindVertexArray(vao); if (!has_vao) { glEnableVertexAttribArray(pShader->GetAttribute(C4FoWFSA_Position)); glEnableVertexAttribArray(pShader->GetAttribute(C4FoWFSA_TexCoord)); glVertexAttribPointer(pShader->GetAttribute(C4FoWFSA_Position), 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const uint8_t*>(8 * sizeof(float))); glVertexAttribPointer(pShader->GetAttribute(C4FoWFSA_TexCoord), 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const uint8_t*>(0)); } glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); Call.Finish(); } // Done! glBindFramebuffer(GL_FRAMEBUFFER, 0); pDraw->RestorePrimaryClipper(); OldRegion = Region; #endif return true; }