1 /* 2 Copyright (c) 2013 yvt 3 4 This file is part of OpenSpades. 5 6 OpenSpades is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 OpenSpades is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with OpenSpades. If not, see <http://www.gnu.org/licenses/>. 18 19 */ 20 21 #include "GLSoftSpriteRenderer.h" 22 #include <Core/Debug.h> 23 #include "GLFramebufferManager.h" 24 #include "GLImage.h" 25 #include "GLProfiler.h" 26 #include "GLProgram.h" 27 #include "GLQuadRenderer.h" 28 #include "GLRenderer.h" 29 #include "IGLDevice.h" 30 #include "SWFeatureLevel.h" // for fastRcp 31 32 namespace spades { 33 namespace draw { 34 GLSoftSpriteRenderer(GLRenderer * renderer)35 GLSoftSpriteRenderer::GLSoftSpriteRenderer(GLRenderer *renderer) 36 : renderer(renderer), 37 device(renderer->GetGLDevice()), 38 settings(renderer->GetSettings()), 39 projectionViewMatrix("projectionViewMatrix"), 40 rightVector("rightVector"), 41 upVector("upVector"), 42 frontVector("frontVector"), 43 viewOriginVector("viewOriginVector"), 44 texture("mainTexture"), 45 depthTexture("depthTexture"), 46 viewMatrix("viewMatrix"), 47 fogDistance("fogDistance"), 48 fogColor("fogColor"), 49 zNearFar("zNearFar"), 50 positionAttribute("positionAttribute"), 51 spritePosAttribute("spritePosAttribute"), 52 colorAttribute("colorAttribute") { 53 SPADES_MARK_FUNCTION(); 54 55 program = renderer->RegisterProgram("Shaders/SoftSprite.program"); 56 } 57 ~GLSoftSpriteRenderer()58 GLSoftSpriteRenderer::~GLSoftSpriteRenderer() { SPADES_MARK_FUNCTION(); } 59 Add(spades::draw::GLImage * img,spades::Vector3 center,float rad,float ang,Vector4 color)60 void GLSoftSpriteRenderer::Add(spades::draw::GLImage *img, spades::Vector3 center, 61 float rad, float ang, Vector4 color) { 62 SPADES_MARK_FUNCTION_DEBUG(); 63 const client::SceneDefinition &def = renderer->GetSceneDef(); 64 Sprite spr; 65 spr.image = img; 66 spr.center = center; 67 spr.radius = rad; 68 spr.angle = ang; 69 if (settings.r_hdr) { 70 // linearize color 71 if (color.x > color.w || color.y > color.w || color.z > color.w) { 72 // emissive material 73 color.x *= color.x; 74 color.y *= color.y; 75 color.z *= color.z; 76 } else { 77 // scattering/absorptive material 78 float rcp = fastRcp(color.w + .01); 79 color.x *= color.x * rcp; 80 color.y *= color.y * rcp; 81 color.z *= color.z * rcp; 82 } 83 } 84 spr.color = color; 85 spr.area = rad * rad * 4.f / 86 std::max(Vector3::Dot(center - def.viewOrigin, def.viewAxis[2]), 0.01f); 87 sprites.push_back(spr); 88 } 89 Clear()90 void GLSoftSpriteRenderer::Clear() { 91 SPADES_MARK_FUNCTION(); 92 sprites.clear(); 93 } 94 LayerForSprite(const Sprite & spr)95 float GLSoftSpriteRenderer::LayerForSprite(const Sprite &spr) { 96 float v = (spr.area - thresLow) / thresRange; 97 if (v < 0.f) 98 v = 0.f; 99 if (v > 1.f) 100 v = 1.f; 101 return v; 102 } 103 Render()104 void GLSoftSpriteRenderer::Render() { 105 SPADES_MARK_FUNCTION(); 106 lastImage = NULL; 107 program->Use(); 108 109 device->Enable(IGLDevice::Blend, true); 110 device->BlendFunc(IGLDevice::One, IGLDevice::OneMinusSrcAlpha); 111 112 projectionViewMatrix(program); 113 rightVector(program); 114 frontVector(program); 115 viewOriginVector(program); 116 upVector(program); 117 texture(program); 118 depthTexture(program); 119 viewMatrix(program); 120 fogDistance(program); 121 fogColor(program); 122 zNearFar(program); 123 124 positionAttribute(program); 125 spritePosAttribute(program); 126 colorAttribute(program); 127 128 projectionViewMatrix.SetValue(renderer->GetProjectionViewMatrix()); 129 viewMatrix.SetValue(renderer->GetViewMatrix()); 130 131 fogDistance.SetValue(renderer->GetFogDistance()); 132 133 Vector3 fogCol = renderer->GetFogColor(); 134 fogCol *= fogCol; // linearize 135 fogColor.SetValue(fogCol.x, fogCol.y, fogCol.z); 136 137 const client::SceneDefinition &def = renderer->GetSceneDef(); 138 rightVector.SetValue(def.viewAxis[0].x, def.viewAxis[0].y, def.viewAxis[0].z); 139 upVector.SetValue(def.viewAxis[1].x, def.viewAxis[1].y, def.viewAxis[1].z); 140 frontVector.SetValue(def.viewAxis[2].x, def.viewAxis[2].y, def.viewAxis[2].z); 141 142 viewOriginVector.SetValue(def.viewOrigin.x, def.viewOrigin.y, def.viewOrigin.z); 143 texture.SetValue(0); 144 depthTexture.SetValue(1); 145 zNearFar.SetValue(def.zNear, def.zFar); 146 147 device->ActiveTexture(1); 148 device->BindTexture(IGLDevice::Texture2D, 149 renderer->GetFramebufferManager()->GetDepthTexture()); 150 device->ActiveTexture(0); 151 152 device->EnableVertexAttribArray(positionAttribute(), true); 153 device->EnableVertexAttribArray(spritePosAttribute(), true); 154 device->EnableVertexAttribArray(colorAttribute(), true); 155 156 thresLow = tanf(def.fovX * .5f) * tanf(def.fovY * .5f) * 1.8f; 157 thresRange = thresLow * .5f; 158 159 // full-resolution sprites 160 { 161 GLProfiler::Context measure(renderer->GetGLProfiler(), "Full Resolution"); 162 for (size_t i = 0; i < sprites.size(); i++) { 163 Sprite &spr = sprites[i]; 164 float layer = LayerForSprite(spr); 165 if (layer == 1.f) 166 continue; 167 if (spr.image != lastImage) { 168 Flush(); 169 lastImage = spr.image; 170 SPAssert(vertices.empty()); 171 } 172 173 Vertex v; 174 v.x = spr.center.x; 175 v.y = spr.center.y; 176 v.z = spr.center.z; 177 v.radius = spr.radius; 178 v.angle = spr.angle; 179 v.r = spr.color.x; 180 v.g = spr.color.y; 181 v.b = spr.color.z; 182 v.a = spr.color.w; 183 184 float fade = 1.f - layer; 185 v.r *= fade; 186 v.g *= fade; 187 v.b *= fade; 188 v.a *= fade; 189 190 uint32_t idx = (uint32_t)vertices.size(); 191 v.sx = -1; 192 v.sy = -1; 193 vertices.push_back(v); 194 v.sx = 1; 195 v.sy = -1; 196 vertices.push_back(v); 197 v.sx = -1; 198 v.sy = 1; 199 vertices.push_back(v); 200 v.sx = 1; 201 v.sy = 1; 202 vertices.push_back(v); 203 204 indices.push_back(idx); 205 indices.push_back(idx + 1); 206 indices.push_back(idx + 2); 207 indices.push_back(idx + 1); 208 indices.push_back(idx + 3); 209 indices.push_back(idx + 2); 210 } 211 212 Flush(); 213 } 214 215 // low-res sprites 216 IGLDevice::UInteger lastFb = device->GetInteger(IGLDevice::FramebufferBinding); 217 int sW = device->ScreenWidth(), sH = device->ScreenHeight(); 218 int lW = (sW + 3) / 4, lH = (sH + 3) / 4; 219 int numLowResSprites = 0; 220 GLColorBuffer buf = renderer->GetFramebufferManager()->CreateBufferHandle(lW, lH, true); 221 device->BindFramebuffer(IGLDevice::Framebuffer, buf.GetFramebuffer()); 222 device->ClearColor(0.f, 0.f, 0.f, 0.f); 223 device->Clear(IGLDevice::ColorBufferBit); 224 device->BlendFunc(IGLDevice::One, IGLDevice::OneMinusSrcAlpha); 225 device->Viewport(0, 0, lW, lH); 226 { 227 GLProfiler::Context measure(renderer->GetGLProfiler(), "Low Resolution"); 228 for (size_t i = 0; i < sprites.size(); i++) { 229 Sprite &spr = sprites[i]; 230 float layer = LayerForSprite(spr); 231 if (layer == 0.f) 232 continue; 233 if (spr.image != lastImage) { 234 Flush(); 235 lastImage = spr.image; 236 SPAssert(vertices.empty()); 237 } 238 239 numLowResSprites++; 240 241 Vertex v; 242 v.x = spr.center.x; 243 v.y = spr.center.y; 244 v.z = spr.center.z; 245 v.radius = spr.radius; 246 v.angle = spr.angle; 247 v.r = spr.color.x; 248 v.g = spr.color.y; 249 v.b = spr.color.z; 250 v.a = spr.color.w; 251 252 float fade = layer; 253 v.r *= fade; 254 v.g *= fade; 255 v.b *= fade; 256 v.a *= fade; 257 258 uint32_t idx = (uint32_t)vertices.size(); 259 v.sx = -1; 260 v.sy = -1; 261 vertices.push_back(v); 262 v.sx = 1; 263 v.sy = -1; 264 vertices.push_back(v); 265 v.sx = -1; 266 v.sy = 1; 267 vertices.push_back(v); 268 v.sx = 1; 269 v.sy = 1; 270 vertices.push_back(v); 271 272 indices.push_back(idx); 273 indices.push_back(idx + 1); 274 indices.push_back(idx + 2); 275 indices.push_back(idx + 1); 276 indices.push_back(idx + 3); 277 indices.push_back(idx + 2); 278 } 279 Flush(); 280 } 281 282 // finalize 283 284 device->ActiveTexture(1); 285 device->BindTexture(IGLDevice::Texture2D, 0); 286 device->ActiveTexture(0); 287 device->BindTexture(IGLDevice::Texture2D, 0); 288 device->EnableVertexAttribArray(positionAttribute(), false); 289 device->EnableVertexAttribArray(spritePosAttribute(), false); 290 device->EnableVertexAttribArray(colorAttribute(), false); 291 292 // composite downsampled sprite 293 device->BlendFunc(IGLDevice::One, IGLDevice::OneMinusSrcAlpha); 294 if (numLowResSprites > 0) { 295 GLProfiler::Context measure(renderer->GetGLProfiler(), "Finalize"); 296 GLQuadRenderer qr(device); 297 298 // do gaussian blur 299 GLProgram *program = 300 renderer->RegisterProgram("Shaders/PostFilters/Gauss1D.program"); 301 static GLProgramAttribute blur_positionAttribute("positionAttribute"); 302 static GLProgramUniform blur_textureUniform("mainTexture"); 303 static GLProgramUniform blur_unitShift("unitShift"); 304 program->Use(); 305 blur_positionAttribute(program); 306 blur_textureUniform(program); 307 blur_unitShift(program); 308 blur_textureUniform.SetValue(0); 309 device->ActiveTexture(0); 310 qr.SetCoordAttributeIndex(blur_positionAttribute()); 311 device->Enable(IGLDevice::Blend, false); 312 313 // x-direction 314 GLColorBuffer buf2 = 315 renderer->GetFramebufferManager()->CreateBufferHandle(lW, lH, true); 316 device->BindTexture(IGLDevice::Texture2D, buf.GetTexture()); 317 device->BindFramebuffer(IGLDevice::Framebuffer, buf2.GetFramebuffer()); 318 blur_unitShift.SetValue(1.f / lW, 0.f); 319 qr.Draw(); 320 buf.Release(); 321 322 // x-direction 323 GLColorBuffer buf3 = 324 renderer->GetFramebufferManager()->CreateBufferHandle(lW, lH, true); 325 device->BindTexture(IGLDevice::Texture2D, buf2.GetTexture()); 326 device->BindFramebuffer(IGLDevice::Framebuffer, buf3.GetFramebuffer()); 327 blur_unitShift.SetValue(0.f, 1.f / lH); 328 qr.Draw(); 329 buf2.Release(); 330 331 buf = buf3; 332 333 device->Enable(IGLDevice::Blend, true); 334 335 // composite 336 program = renderer->RegisterProgram("Shaders/PostFilters/PassThrough.program"); 337 static GLProgramAttribute positionAttribute("positionAttribute"); 338 static GLProgramUniform colorUniform("colorUniform"); 339 static GLProgramUniform textureUniform("mainTexture"); 340 static GLProgramUniform texCoordRange("texCoordRange"); 341 342 positionAttribute(program); 343 textureUniform(program); 344 texCoordRange(program); 345 colorUniform(program); 346 347 program->Use(); 348 349 textureUniform.SetValue(0); 350 texCoordRange.SetValue(0.f, 0.f, 1.f, 1.f); 351 colorUniform.SetValue(1.f, 1.f, 1.f, 1.f); 352 353 qr.SetCoordAttributeIndex(positionAttribute()); 354 device->BindFramebuffer(IGLDevice::Framebuffer, lastFb); 355 device->BindTexture(IGLDevice::Texture2D, buf.GetTexture()); 356 device->Viewport(0, 0, sW, sH); 357 qr.Draw(); 358 device->BindTexture(IGLDevice::Texture2D, 0); 359 360 } else { 361 device->Viewport(0, 0, sW, sH); 362 363 device->BindFramebuffer(IGLDevice::Framebuffer, lastFb); 364 } 365 366 buf.Release(); 367 } 368 Flush()369 void GLSoftSpriteRenderer::Flush() { 370 SPADES_MARK_FUNCTION_DEBUG(); 371 372 if (vertices.empty()) 373 return; 374 375 device->VertexAttribPointer(positionAttribute(), 4, IGLDevice::FloatType, false, 376 sizeof(Vertex), &(vertices[0].x)); 377 device->VertexAttribPointer(spritePosAttribute(), 4, IGLDevice::FloatType, false, 378 sizeof(Vertex), &(vertices[0].sx)); 379 device->VertexAttribPointer(colorAttribute(), 4, IGLDevice::FloatType, false, 380 sizeof(Vertex), &(vertices[0].r)); 381 382 SPAssert(lastImage); 383 lastImage->Bind(IGLDevice::Texture2D); 384 385 device->DrawElements(IGLDevice::Triangles, 386 static_cast<IGLDevice::Sizei>(indices.size()), 387 IGLDevice::UnsignedInt, indices.data()); 388 389 vertices.clear(); 390 indices.clear(); 391 } 392 } 393 } 394