GLColorBuffer GLLensFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute lensPosition("positionAttribute"); static GLProgramUniform lensTexture("mainTexture"); static GLProgramUniform lensFov("fov"); dev->Enable(IGLDevice::Blend, false); lensPosition(lens); lensTexture(lens); lensFov(lens); lens->Use(); client::SceneDefinition def = renderer->GetSceneDef(); lensFov.SetValue(tanf(def.fovX * .5f), tanf(def.fovY * .5f)); lensTexture.SetValue(0); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); qr.SetCoordAttributeIndex(lensPosition()); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); return output; }
GLColorBuffer GLLensDustFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); UpdateNoise(); std::vector<Level> levels; IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute thruPosition("positionAttribute"); static GLProgramUniform thruColor("colorUniform"); static GLProgramUniform thruTexture("mainTexture"); static GLProgramUniform thruTexCoordRange("texCoordRange"); thruPosition(thru); thruColor(thru); thruTexture(thru); thruTexCoordRange(thru); GLColorBuffer downSampled = DownSample(input, r_hdr ? false : true); downSampled = GaussianBlur(downSampled, false); downSampled = GaussianBlur(downSampled, true); thru->Use(); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexture.SetValue(0); dev->Enable(IGLDevice::Blend, false); levels.reserve(10); // create downsample levels for(int i = 0; i < 10; i++){ GLColorBuffer prevLevel; if(i == 0){ prevLevel = downSampled; }else{ prevLevel = levels.back().buffer; } int prevW = prevLevel.GetWidth(); int prevH = prevLevel.GetHeight(); int newW = (prevW + 1) / 2; int newH = (prevH + 1) / 2; if(newW <= 1 || newH <= 1) break; GLColorBuffer newLevel = DownSample(prevLevel); newLevel = GaussianBlur(newLevel, false); newLevel = GaussianBlur(newLevel, true); Level lv; lv.w = newW; lv.h = newH; lv.buffer = newLevel; levels.push_back(lv); } dev->Enable(IGLDevice::Blend, true); dev->BlendFunc(IGLDevice::SrcAlpha, IGLDevice::OneMinusSrcAlpha); // composite levels in the opposite direction thru->Use(); qr.SetCoordAttributeIndex(thruPosition()); for(int i = (int)levels.size() - 1; i >= 1; i--){ int cnt = (int)levels.size() - i; float alpha = (float)cnt / (float)(cnt + 1); alpha = alpha; GLColorBuffer curLevel = levels[i].buffer; float sx = .25f / curLevel.GetWidth(); float sy = .25f / curLevel.GetHeight(); for(int j = 0; j < 4; j++) { if(i < (int)levels.size() - 1) { curLevel = levels[i].retBuf[j]; } GLColorBuffer targLevel = levels[i - 1].buffer; GLColorBuffer targRet = input.GetManager()->CreateBufferHandle(targLevel.GetWidth(), targLevel.GetHeight(), false); levels[i - 1].retBuf[j] = targRet; dev->BindFramebuffer(IGLDevice::Framebuffer, targRet.GetFramebuffer()); dev->Viewport(0, 0, targRet.GetWidth(), targRet.GetHeight()); dev->BindTexture(IGLDevice::Texture2D, targLevel.GetTexture()); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexCoordRange.SetValue(0.f, 0.f, 1.f, 1.f); dev->Enable(IGLDevice::Blend, false); qr.Draw(); float cx = 0.f, cy = 0.f; switch(j){ case 0: cx = sx; break; case 1: cx = -sx; break; case 2: cy = sy; break; case 3: cy = -sy; break; } dev->BindTexture(IGLDevice::Texture2D, curLevel.GetTexture()); thruColor.SetValue(1.f, 1.f, 1.f, alpha); thruTexCoordRange.SetValue(cx, cy, 1.f, 1.f); dev->Enable(IGLDevice::Blend, true); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); } } static GLProgramAttribute dustPosition("positionAttribute"); static GLProgramUniform dustDustTexture("dustTexture"); static GLProgramUniform dustBlurTexture1("blurTexture1"); static GLProgramUniform dustBlurTexture2("blurTexture2"); static GLProgramUniform dustBlurTexture3("blurTexture3"); static GLProgramUniform dustBlurTexture4("blurTexture4"); static GLProgramUniform dustInputTexture("inputTexture"); static GLProgramUniform dustNoiseTexture("noiseTexture"); static GLProgramUniform dustNoiseTexCoordFactor("noiseTexCoordFactor"); dustPosition(dust); dustDustTexture(dust); dustBlurTexture1(dust); dustBlurTexture2(dust); dustBlurTexture3(dust); dustBlurTexture4(dust); dustInputTexture(dust); dustNoiseTexture(dust); dustNoiseTexCoordFactor(dust); dust->Use(); float facX = renderer->ScreenWidth() / 128.f; float facY = renderer->ScreenHeight() / 128.f; dustNoiseTexCoordFactor.SetValue(facX, facY, facX / 128.f, facY / 128.f); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); GLColorBuffer topLevel1 = levels[0].retBuf[0]; GLColorBuffer topLevel2 = levels[0].retBuf[1]; GLColorBuffer topLevel3 = levels[0].retBuf[2]; GLColorBuffer topLevel4 = levels[0].retBuf[3]; qr.SetCoordAttributeIndex(dustPosition()); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, topLevel1.GetTexture()); dev->ActiveTexture(2); dev->BindTexture(IGLDevice::Texture2D, topLevel2.GetTexture()); dev->ActiveTexture(3); dev->BindTexture(IGLDevice::Texture2D, topLevel3.GetTexture()); dev->ActiveTexture(4); dev->BindTexture(IGLDevice::Texture2D, topLevel4.GetTexture()); dev->ActiveTexture(5); dustImg->Bind(IGLDevice::Texture2D); dev->ActiveTexture(6); dev->BindTexture(IGLDevice::Texture2D, noiseTex); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); dustBlurTexture1.SetValue(2); dustBlurTexture2.SetValue(1); dustBlurTexture3.SetValue(3); dustBlurTexture4.SetValue(4); dustDustTexture.SetValue(5); dustNoiseTexture.SetValue(6); dustInputTexture.SetValue(0); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); dev->ActiveTexture(0); return output; }
GLColorBuffer GLBloomFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); std::vector<Level> levels; IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute thruPosition("positionAttribute"); static GLProgramUniform thruColor("colorUniform"); static GLProgramUniform thruTexture("texture"); static GLProgramUniform thruTexCoordRange("texCoordRange"); thruPosition(thru); thruColor(thru); thruTexture(thru); thruTexCoordRange(thru); GLProgram *gammaMix = renderer->RegisterProgram("Shaders/PostFilters/GammaMix.program"); static GLProgramAttribute gammaMixPosition("positionAttribute"); static GLProgramUniform gammaMixTexture1("texture1"); static GLProgramUniform gammaMixTexture2("texture2"); static GLProgramUniform gammaMixMix1("mix1"); static GLProgramUniform gammaMixMix2("mix2"); gammaMixPosition(gammaMix); gammaMixTexture1(gammaMix); gammaMixTexture2(gammaMix); gammaMixMix1(gammaMix); gammaMixMix2(gammaMix); thru->Use(); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexture.SetValue(0); dev->Enable(IGLDevice::Blend, false); // create downsample levels for(int i = 0; i < 6; i++){ GLColorBuffer prevLevel; if(i == 0){ prevLevel = input; }else{ prevLevel = levels.back().buffer; } int prevW = prevLevel.GetWidth(); int prevH = prevLevel.GetHeight(); int newW = (prevW + 1) / 2; int newH = (prevH + 1) / 2; GLColorBuffer newLevel = input.GetManager()->CreateBufferHandle(newW, newH); thru->Use(); qr.SetCoordAttributeIndex(thruPosition()); dev->BindTexture(IGLDevice::Texture2D, prevLevel.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, newLevel.GetFramebuffer()); dev->Viewport(0, 0, newLevel.GetWidth(), newLevel.GetHeight()); thruTexCoordRange.SetValue(0.f, 0.f, (float)newLevel.GetWidth() * 2.f / (float)prevW, (float)newLevel.GetHeight() * 2.f / (float)prevH); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); Level lv; lv.w = newW; lv.h = newH; lv.buffer = newLevel; levels.push_back(lv); } dev->Enable(IGLDevice::Blend, true); dev->BlendFunc(IGLDevice::SrcAlpha, IGLDevice::OneMinusSrcAlpha); // composite levels in the opposite direction thruTexCoordRange.SetValue(0.f, 0.f, 1.f, 1.f); for(int i = (int)levels.size() - 1; i >= 1; i--){ int cnt = (int)levels.size() - i; float alpha = (float)cnt / (float)(cnt + 1); alpha = sqrtf(alpha); GLColorBuffer curLevel = levels[i].buffer; GLColorBuffer targLevel = levels[i - 1].buffer; thru->Use(); qr.SetCoordAttributeIndex(thruPosition()); dev->BindTexture(IGLDevice::Texture2D, curLevel.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, targLevel.GetFramebuffer()); dev->Viewport(0, 0, targLevel.GetWidth(), targLevel.GetHeight()); thruColor.SetValue(1.f, 1.f, 1.f, alpha); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); } // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); GLColorBuffer topLevel = levels[0].buffer; gammaMix->Use(); qr.SetCoordAttributeIndex(gammaMixPosition()); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, topLevel.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); gammaMixTexture1.SetValue(0); gammaMixTexture2.SetValue(1); gammaMixMix1.SetValue(.8f, .8f, .8f); gammaMixMix2.SetValue(.2f, .2f, .2f); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); dev->ActiveTexture(0); return output; }
GLColorBuffer GLColorCorrectionFilter::Filter(GLColorBuffer input, Vector3 tintVal) { SPADES_MARK_FUNCTION(); IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute lensPosition("positionAttribute"); static GLProgramUniform lensTexture("mainTexture"); static GLProgramUniform saturation("saturation"); static GLProgramUniform enhancement("enhancement"); static GLProgramUniform tint("tint"); saturation(lens); enhancement(lens); tint(lens); dev->Enable(IGLDevice::Blend, false); lensPosition(lens); lensTexture(lens); lens->Use(); tint.SetValue(tintVal.x, tintVal.y, tintVal.z); const client::SceneDefinition &def = renderer->GetSceneDef(); if (settings.r_hdr) { // when HDR is enabled ACES tone mapping is applied first, so // lower enhancement value is required if (settings.r_bloom) { saturation.SetValue(0.8f * def.saturation * settings.r_saturation); enhancement.SetValue(0.1f); } else { saturation.SetValue(0.9f * def.saturation * settings.r_saturation); enhancement.SetValue(0.0f); } } else { if (settings.r_bloom) { // make image sharper saturation.SetValue(.85f * def.saturation * settings.r_saturation); enhancement.SetValue(0.7f); } else { saturation.SetValue(1.f * def.saturation * settings.r_saturation); enhancement.SetValue(0.3f); } } lensTexture.SetValue(0); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); qr.SetCoordAttributeIndex(lensPosition()); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); return output; }
GLColorBuffer GLFogFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); GLProgram *lens = renderer->RegisterProgram("Shaders/PostFilters/Fog.program"); static GLProgramAttribute lensPosition("positionAttribute"); static GLProgramUniform lensShadowMapTexture("shadowMapTexture"); static GLProgramUniform lensCoarseShadowMapTexture("coarseShadowMapTexture"); static GLProgramUniform lensColorTexture("colorTexture"); static GLProgramUniform lensDepthTexture("depthTexture"); static GLProgramUniform lensFov("fov"); static GLProgramUniform lensViewOrigin("viewOrigin"); static GLProgramUniform lensViewAxisUp("viewAxisUp"); static GLProgramUniform lensViewAxisSide("viewAxisSide"); static GLProgramUniform lensViewAxisFront("viewAxisFront"); static GLProgramUniform zNearFar("zNearFar");; static GLProgramUniform fogColor("fogColor"); static GLProgramUniform fogDistance("fogDistance"); dev->Enable(IGLDevice::Blend, false); lensPosition(lens); lensShadowMapTexture(lens); lensCoarseShadowMapTexture(lens); lensColorTexture(lens); lensDepthTexture(lens); lensFov(lens); lensViewOrigin(lens); lensViewAxisUp(lens); lensViewAxisSide(lens); lensViewAxisFront(lens); zNearFar(lens); fogColor(lens); fogDistance(lens); lens->Use(); client::SceneDefinition def = renderer->GetSceneDef(); lensFov.SetValue(tanf(def.fovX * .5f), tanf(def.fovY * .5f)); lensViewOrigin.SetValue(def.viewOrigin.x, def.viewOrigin.y, def.viewOrigin.z); lensViewAxisUp.SetValue(def.viewAxis[1].x, def.viewAxis[1].y, def.viewAxis[1].z); lensViewAxisSide.SetValue(def.viewAxis[0].x, def.viewAxis[0].y, def.viewAxis[0].z); lensViewAxisFront.SetValue(def.viewAxis[2].x, def.viewAxis[2].y, def.viewAxis[2].z); zNearFar.SetValue(def.zNear, def.zFar); Vector3 fogCol = renderer->GetFogColor(); fogCol *= fogCol; // linearize fogColor.SetValue(fogCol.x, fogCol.y, fogCol.z); fogDistance.SetValue(128.f); lensColorTexture.SetValue(0); lensDepthTexture.SetValue(1); lensShadowMapTexture.SetValue(2); lensCoarseShadowMapTexture.SetValue(3); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); dev->Enable(IGLDevice::Blend, false); qr.SetCoordAttributeIndex(lensPosition()); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, input.GetManager()->GetDepthTexture()); dev->ActiveTexture(2); dev->BindTexture(IGLDevice::Texture2D, renderer->GetMapShadowRenderer()->GetTexture()); dev->ActiveTexture(3); dev->BindTexture(IGLDevice::Texture2D, renderer->GetMapShadowRenderer()->GetCoarseTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); qr.Draw(); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, 0); return output; }
GLColorBuffer GLCameraBlurFilter::Filter(GLColorBuffer input, float radialBlur) { SPADES_MARK_FUNCTION(); if(radialBlur > 0.f) radialBlur = 1.f - radialBlur; else radialBlur = 1.f; bool hasRadialBlur = radialBlur < .9999f; IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); dev->Enable(IGLDevice::Blend, false); static GLProgramAttribute programPosition("positionAttribute"); static GLProgramUniform programTexture("texture"); static GLProgramUniform programDepthTexture("depthTexture"); static GLProgramUniform programReverseMatrix("reverseMatrix"); static GLProgramUniform programShutterTimeScale("shutterTimeScale"); programPosition(program); programTexture(program); programDepthTexture(program); programReverseMatrix(program); programShutterTimeScale(program); const client::SceneDefinition& def = renderer->GetSceneDef(); Matrix4 newMatrix = Matrix4::Identity(); newMatrix.m[0] = def.viewAxis[0].x; newMatrix.m[1] = def.viewAxis[1].x; newMatrix.m[2] = def.viewAxis[2].x; newMatrix.m[4] = def.viewAxis[0].y; newMatrix.m[5] = def.viewAxis[1].y; newMatrix.m[6] = def.viewAxis[2].y; newMatrix.m[8] = def.viewAxis[0].z; newMatrix.m[9] = def.viewAxis[1].z; newMatrix.m[10] = def.viewAxis[2].z; // othrogonal matrix can be reversed fast Matrix4 inverseNewMatrix = newMatrix.Transposed(); Matrix4 diffMatrix = prevMatrix * inverseNewMatrix; prevMatrix = newMatrix; Matrix4 reverseMatrix = ReverseMatrix(diffMatrix); if(diffMatrix.m[0] < .3f || diffMatrix.m[5] < .3f || diffMatrix.m[10] < .3f){ // too much change if(hasRadialBlur) { diffMatrix = Matrix4::Identity(); }else{ // skip blur return input; } } float movePixels = MyACos(diffMatrix.m[0]); float shutterTimeScale = .3f; movePixels = std::max(movePixels, MyACos(diffMatrix.m[5])); movePixels = std::max(movePixels, MyACos(diffMatrix.m[10])); movePixels = tanf(movePixels) / tanf(def.fovX * .5f); movePixels *= (float)dev->ScreenWidth() * .5f; movePixels *= shutterTimeScale; movePixels = std::max(movePixels, (1.f - radialBlur) * dev->ScreenWidth() * 0.5f); if(movePixels < 1.f){ // too less change, skip camera blur return input; } int levels = (int)ceilf(logf(movePixels) / logf(5.f)); if(levels <= 0) levels = 1; if(hasRadialBlur) radialBlur *= radialBlur; reverseMatrix = Matrix4::Scale(radialBlur, radialBlur, 1.f) * reverseMatrix; program->Use(); programTexture.SetValue(0); programDepthTexture.SetValue(1); programReverseMatrix.SetValue(reverseMatrix); // composite to the final image GLColorBuffer buf = input; qr.SetCoordAttributeIndex(programPosition()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, renderer->GetFramebufferManager()->GetDepthTexture()); dev->ActiveTexture(0); for(int i = 0; i < levels; i++){ GLProfiler measure(dev, "Apply [%d / %d]", i+1,levels); GLColorBuffer output = input.GetManager()->CreateBufferHandle(); programShutterTimeScale.SetValue(shutterTimeScale); dev->BindTexture(IGLDevice::Texture2D, buf.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); shutterTimeScale /= 5.f; buf = output; } dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, 0); dev->ActiveTexture(0); return buf; }
void GLSoftSpriteRenderer::Render() { SPADES_MARK_FUNCTION(); lastImage = NULL; program->Use(); device->Enable(IGLDevice::Blend, true); device->BlendFunc(IGLDevice::One, IGLDevice::OneMinusSrcAlpha); projectionViewMatrix(program); rightVector(program); frontVector(program); viewOriginVector(program); upVector(program); texture(program); depthTexture(program); viewMatrix(program); fogDistance(program); fogColor(program); zNearFar(program); positionAttribute(program); spritePosAttribute(program); colorAttribute(program); projectionViewMatrix.SetValue(renderer->GetProjectionViewMatrix()); viewMatrix.SetValue(renderer->GetViewMatrix()); fogDistance.SetValue(renderer->GetFogDistance()); Vector3 fogCol = renderer->GetFogColor(); fogCol *= fogCol; // linearize fogColor.SetValue(fogCol.x, fogCol.y, fogCol.z); const client::SceneDefinition &def = renderer->GetSceneDef(); rightVector.SetValue(def.viewAxis[0].x, def.viewAxis[0].y, def.viewAxis[0].z); upVector.SetValue(def.viewAxis[1].x, def.viewAxis[1].y, def.viewAxis[1].z); frontVector.SetValue(def.viewAxis[2].x, def.viewAxis[2].y, def.viewAxis[2].z); viewOriginVector.SetValue(def.viewOrigin.x, def.viewOrigin.y, def.viewOrigin.z); texture.SetValue(0); depthTexture.SetValue(1); zNearFar.SetValue(def.zNear, def.zFar); device->ActiveTexture(1); device->BindTexture(IGLDevice::Texture2D, renderer->GetFramebufferManager()->GetDepthTexture()); device->ActiveTexture(0); device->EnableVertexAttribArray(positionAttribute(), true); device->EnableVertexAttribArray(spritePosAttribute(), true); device->EnableVertexAttribArray(colorAttribute(), true); thresLow = tanf(def.fovX * .5f) * tanf(def.fovY * .5f) * 1.8f; thresRange = thresLow * .5f; // full-resolution sprites { GLProfiler::Context measure(renderer->GetGLProfiler(), "Full Resolution"); for (size_t i = 0; i < sprites.size(); i++) { Sprite &spr = sprites[i]; float layer = LayerForSprite(spr); if (layer == 1.f) continue; if (spr.image != lastImage) { Flush(); lastImage = spr.image; SPAssert(vertices.empty()); } Vertex v; v.x = spr.center.x; v.y = spr.center.y; v.z = spr.center.z; v.radius = spr.radius; v.angle = spr.angle; v.r = spr.color.x; v.g = spr.color.y; v.b = spr.color.z; v.a = spr.color.w; float fade = 1.f - layer; v.r *= fade; v.g *= fade; v.b *= fade; v.a *= fade; uint32_t idx = (uint32_t)vertices.size(); v.sx = -1; v.sy = -1; vertices.push_back(v); v.sx = 1; v.sy = -1; vertices.push_back(v); v.sx = -1; v.sy = 1; vertices.push_back(v); v.sx = 1; v.sy = 1; vertices.push_back(v); indices.push_back(idx); indices.push_back(idx + 1); indices.push_back(idx + 2); indices.push_back(idx + 1); indices.push_back(idx + 3); indices.push_back(idx + 2); } Flush(); } // low-res sprites IGLDevice::UInteger lastFb = device->GetInteger(IGLDevice::FramebufferBinding); int sW = device->ScreenWidth(), sH = device->ScreenHeight(); int lW = (sW + 3) / 4, lH = (sH + 3) / 4; int numLowResSprites = 0; GLColorBuffer buf = renderer->GetFramebufferManager()->CreateBufferHandle(lW, lH, true); device->BindFramebuffer(IGLDevice::Framebuffer, buf.GetFramebuffer()); device->ClearColor(0.f, 0.f, 0.f, 0.f); device->Clear(IGLDevice::ColorBufferBit); device->BlendFunc(IGLDevice::One, IGLDevice::OneMinusSrcAlpha); device->Viewport(0, 0, lW, lH); { GLProfiler::Context measure(renderer->GetGLProfiler(), "Low Resolution"); for (size_t i = 0; i < sprites.size(); i++) { Sprite &spr = sprites[i]; float layer = LayerForSprite(spr); if (layer == 0.f) continue; if (spr.image != lastImage) { Flush(); lastImage = spr.image; SPAssert(vertices.empty()); } numLowResSprites++; Vertex v; v.x = spr.center.x; v.y = spr.center.y; v.z = spr.center.z; v.radius = spr.radius; v.angle = spr.angle; v.r = spr.color.x; v.g = spr.color.y; v.b = spr.color.z; v.a = spr.color.w; float fade = layer; v.r *= fade; v.g *= fade; v.b *= fade; v.a *= fade; uint32_t idx = (uint32_t)vertices.size(); v.sx = -1; v.sy = -1; vertices.push_back(v); v.sx = 1; v.sy = -1; vertices.push_back(v); v.sx = -1; v.sy = 1; vertices.push_back(v); v.sx = 1; v.sy = 1; vertices.push_back(v); indices.push_back(idx); indices.push_back(idx + 1); indices.push_back(idx + 2); indices.push_back(idx + 1); indices.push_back(idx + 3); indices.push_back(idx + 2); } Flush(); } // finalize device->ActiveTexture(1); device->BindTexture(IGLDevice::Texture2D, 0); device->ActiveTexture(0); device->BindTexture(IGLDevice::Texture2D, 0); device->EnableVertexAttribArray(positionAttribute(), false); device->EnableVertexAttribArray(spritePosAttribute(), false); device->EnableVertexAttribArray(colorAttribute(), false); // composite downsampled sprite device->BlendFunc(IGLDevice::One, IGLDevice::OneMinusSrcAlpha); if (numLowResSprites > 0) { GLProfiler::Context measure(renderer->GetGLProfiler(), "Finalize"); GLQuadRenderer qr(device); // do gaussian blur GLProgram *program = renderer->RegisterProgram("Shaders/PostFilters/Gauss1D.program"); static GLProgramAttribute blur_positionAttribute("positionAttribute"); static GLProgramUniform blur_textureUniform("mainTexture"); static GLProgramUniform blur_unitShift("unitShift"); program->Use(); blur_positionAttribute(program); blur_textureUniform(program); blur_unitShift(program); blur_textureUniform.SetValue(0); device->ActiveTexture(0); qr.SetCoordAttributeIndex(blur_positionAttribute()); device->Enable(IGLDevice::Blend, false); // x-direction GLColorBuffer buf2 = renderer->GetFramebufferManager()->CreateBufferHandle(lW, lH, true); device->BindTexture(IGLDevice::Texture2D, buf.GetTexture()); device->BindFramebuffer(IGLDevice::Framebuffer, buf2.GetFramebuffer()); blur_unitShift.SetValue(1.f / lW, 0.f); qr.Draw(); buf.Release(); // x-direction GLColorBuffer buf3 = renderer->GetFramebufferManager()->CreateBufferHandle(lW, lH, true); device->BindTexture(IGLDevice::Texture2D, buf2.GetTexture()); device->BindFramebuffer(IGLDevice::Framebuffer, buf3.GetFramebuffer()); blur_unitShift.SetValue(0.f, 1.f / lH); qr.Draw(); buf2.Release(); buf = buf3; device->Enable(IGLDevice::Blend, true); // composite program = renderer->RegisterProgram("Shaders/PostFilters/PassThrough.program"); static GLProgramAttribute positionAttribute("positionAttribute"); static GLProgramUniform colorUniform("colorUniform"); static GLProgramUniform textureUniform("mainTexture"); static GLProgramUniform texCoordRange("texCoordRange"); positionAttribute(program); textureUniform(program); texCoordRange(program); colorUniform(program); program->Use(); textureUniform.SetValue(0); texCoordRange.SetValue(0.f, 0.f, 1.f, 1.f); colorUniform.SetValue(1.f, 1.f, 1.f, 1.f); qr.SetCoordAttributeIndex(positionAttribute()); device->BindFramebuffer(IGLDevice::Framebuffer, lastFb); device->BindTexture(IGLDevice::Texture2D, buf.GetTexture()); device->Viewport(0, 0, sW, sH); qr.Draw(); device->BindTexture(IGLDevice::Texture2D, 0); } else { device->Viewport(0, 0, sW, sH); device->BindFramebuffer(IGLDevice::Framebuffer, lastFb); } buf.Release(); }