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 "GLLongSpriteRenderer.h" 22 #include <Core/Debug.h> 23 #include "GLImage.h" 24 #include "GLProgram.h" 25 #include "GLRenderer.h" 26 #include "IGLDevice.h" 27 #include "SWFeatureLevel.h" 28 #include <Core/Settings.h> 29 30 namespace spades { 31 namespace draw { 32 GLLongSpriteRenderer(GLRenderer * renderer)33 GLLongSpriteRenderer::GLLongSpriteRenderer(GLRenderer *renderer) 34 : renderer(renderer), 35 device(renderer->GetGLDevice()), 36 settings(renderer->GetSettings()), 37 projectionViewMatrix("projectionViewMatrix"), 38 rightVector("rightVector"), 39 upVector("upVector"), 40 texture("mainTexture"), 41 viewMatrix("viewMatrix"), 42 fogDistance("fogDistance"), 43 fogColor("fogColor"), 44 viewOriginVector("viewOriginVector"), 45 positionAttribute("positionAttribute"), 46 texCoordAttribute("texCoordAttribute"), 47 colorAttribute("colorAttribute") { 48 SPADES_MARK_FUNCTION(); 49 50 program = renderer->RegisterProgram("Shaders/LongSprite.program"); 51 } 52 ~GLLongSpriteRenderer()53 GLLongSpriteRenderer::~GLLongSpriteRenderer() { SPADES_MARK_FUNCTION(); } 54 Add(spades::draw::GLImage * img,spades::Vector3 p1,spades::Vector3 p2,float rad,Vector4 color)55 void GLLongSpriteRenderer::Add(spades::draw::GLImage *img, spades::Vector3 p1, 56 spades::Vector3 p2, float rad, Vector4 color) { 57 SPADES_MARK_FUNCTION_DEBUG(); 58 Sprite spr; 59 spr.image = img; 60 spr.start = p1; 61 spr.end = p2; 62 spr.radius = rad; 63 if (settings.r_hdr) { 64 // linearize color 65 if (color.x > color.w || color.y > color.w || color.z > color.w) { 66 // emissive material 67 color.x *= color.x; 68 color.y *= color.y; 69 color.z *= color.z; 70 } else { 71 // scattering/absorptive material 72 float rcp = fastRcp(color.w + .01); 73 color.x *= color.x * rcp; 74 color.y *= color.y * rcp; 75 color.z *= color.z * rcp; 76 } 77 } 78 spr.color = color; 79 sprites.push_back(spr); 80 } 81 Clear()82 void GLLongSpriteRenderer::Clear() { 83 SPADES_MARK_FUNCTION(); 84 sprites.clear(); 85 } 86 Render()87 void GLLongSpriteRenderer::Render() { 88 SPADES_MARK_FUNCTION(); 89 lastImage = NULL; 90 program->Use(); 91 92 projectionViewMatrix(program); 93 rightVector(program); 94 upVector(program); 95 texture(program); 96 viewMatrix(program); 97 fogDistance(program); 98 fogColor(program); 99 viewOriginVector(program); 100 101 positionAttribute(program); 102 texCoordAttribute(program); 103 colorAttribute(program); 104 105 projectionViewMatrix.SetValue(renderer->GetProjectionViewMatrix()); 106 viewMatrix.SetValue(renderer->GetViewMatrix()); 107 108 fogDistance.SetValue(renderer->GetFogDistance()); 109 110 const auto &viewOrigin = renderer->GetSceneDef().viewOrigin; 111 viewOriginVector.SetValue(viewOrigin.x, viewOrigin.y, viewOrigin.z); 112 113 Vector3 fogCol = renderer->GetFogColor(); 114 fogColor.SetValue(fogCol.x, fogCol.y, fogCol.z); 115 116 const client::SceneDefinition &def = renderer->GetSceneDef(); 117 rightVector.SetValue(def.viewAxis[0].x, def.viewAxis[0].y, def.viewAxis[0].z); 118 upVector.SetValue(def.viewAxis[1].x, def.viewAxis[1].y, def.viewAxis[1].z); 119 texture.SetValue(0); 120 121 device->ActiveTexture(0); 122 123 device->EnableVertexAttribArray(positionAttribute(), true); 124 device->EnableVertexAttribArray(texCoordAttribute(), true); 125 device->EnableVertexAttribArray(colorAttribute(), true); 126 127 for (size_t i = 0; i < sprites.size(); i++) { 128 Sprite &spr = sprites[i]; 129 if (spr.image != lastImage) { 130 Flush(); 131 lastImage = spr.image; 132 SPAssert(vertices.empty()); 133 } 134 135 Vertex v; 136 v.r = spr.color.x; 137 v.g = spr.color.y; 138 v.b = spr.color.z; 139 v.a = spr.color.w; 140 141 uint32_t idx = (uint32_t)vertices.size(); 142 143 // clip by view plane 144 { 145 float d1 = Vector3::Dot(spr.start - def.viewOrigin, def.viewAxis[2]); 146 float d2 = Vector3::Dot(spr.end - def.viewOrigin, def.viewAxis[2]); 147 const float clipPlane = .1f; 148 if (d1 < clipPlane && d2 < clipPlane) 149 continue; 150 if (d1 > clipPlane || d2 > clipPlane) { 151 if (d1 < clipPlane) { 152 float per = (clipPlane - d1) / (d2 - d1); 153 spr.start = Mix(spr.start, spr.end, per); 154 } else if (d2 < clipPlane) { 155 float per = (clipPlane - d1) / (d2 - d1); 156 spr.end = Mix(spr.start, spr.end, per); 157 } 158 } 159 } 160 161 // calculate view position 162 Vector3 view1 = spr.start - def.viewOrigin; 163 Vector3 view2 = spr.end - def.viewOrigin; 164 view1 = MakeVector3(Vector3::Dot(view1, def.viewAxis[0]), 165 Vector3::Dot(view1, def.viewAxis[1]), 166 Vector3::Dot(view1, def.viewAxis[2])); 167 view2 = MakeVector3(Vector3::Dot(view2, def.viewAxis[0]), 168 Vector3::Dot(view2, def.viewAxis[1]), 169 Vector3::Dot(view2, def.viewAxis[2])); 170 171 // transform to screen 172 Vector2 scr1 = MakeVector2(view1.x / view1.z, view1.y / view1.z); 173 Vector2 scr2 = MakeVector2(view2.x / view2.z, view2.y / view2.z); 174 175 Vector3 vecX = def.viewAxis[0] * spr.radius; 176 Vector3 vecY = def.viewAxis[1] * spr.radius; 177 float normalThreshold = spr.radius * 0.5f / ((view1.z + view2.z) * .5f); 178 if ((scr2 - scr1).GetPoweredLength() < normalThreshold * normalThreshold) { 179 // too short in screen; normal sprite 180 v = spr.start - vecX - vecY; 181 v.u = 0; 182 v.v = 0; 183 vertices.push_back(v); 184 185 v = spr.start + vecX - vecY; 186 v.u = 1; 187 v.v = 0; 188 vertices.push_back(v); 189 190 v = spr.start - vecX + vecY; 191 v.u = 0; 192 v.v = 1; 193 vertices.push_back(v); 194 195 v = spr.start + vecX + vecY; 196 v.u = 1; 197 v.v = 1; 198 vertices.push_back(v); 199 200 indices.push_back(idx); 201 indices.push_back(idx + 1); 202 indices.push_back(idx + 2); 203 indices.push_back(idx + 1); 204 indices.push_back(idx + 3); 205 indices.push_back(idx + 2); 206 } else { 207 Vector2 scrDir = (scr2 - scr1).Normalize(); 208 Vector2 normDir = {scrDir.y, -scrDir.x}; 209 Vector3 vecU = vecX * normDir.x + vecY * normDir.y; 210 Vector3 vecV = vecX * scrDir.x + vecY * scrDir.y; 211 212 v = spr.start - vecU - vecV; 213 v.u = 0; 214 v.v = 0; 215 vertices.push_back(v); 216 217 v = spr.start + vecU - vecV; 218 v.u = 1; 219 v.v = 0; 220 vertices.push_back(v); 221 222 v = spr.start - vecU; 223 v.u = 0; 224 v.v = 0.5f; 225 vertices.push_back(v); 226 227 v = spr.start + vecU; 228 v.u = 1; 229 v.v = 0.5f; 230 vertices.push_back(v); 231 232 v = spr.end - vecU; 233 v.u = 0; 234 v.v = 0.5f; 235 vertices.push_back(v); 236 237 v = spr.end + vecU; 238 v.u = 1; 239 v.v = 0.5f; 240 vertices.push_back(v); 241 242 v = spr.end - vecU + vecV; 243 v.u = 0; 244 v.v = 1; 245 vertices.push_back(v); 246 247 v = spr.end + vecU + vecV; 248 v.u = 1; 249 v.v = 1; 250 vertices.push_back(v); 251 252 indices.push_back(idx); 253 indices.push_back(idx + 1); 254 indices.push_back(idx + 2); 255 indices.push_back(idx + 1); 256 indices.push_back(idx + 3); 257 indices.push_back(idx + 2); 258 259 indices.push_back(idx + 2); 260 indices.push_back(idx + 2 + 1); 261 indices.push_back(idx + 2 + 2); 262 indices.push_back(idx + 2 + 1); 263 indices.push_back(idx + 2 + 3); 264 indices.push_back(idx + 2 + 2); 265 266 indices.push_back(idx + 4); 267 indices.push_back(idx + 4 + 1); 268 indices.push_back(idx + 4 + 2); 269 indices.push_back(idx + 4 + 1); 270 indices.push_back(idx + 4 + 3); 271 indices.push_back(idx + 4 + 2); 272 273 idx = (uint32_t)vertices.size(); 274 275 v = spr.start - vecU + vecV; 276 v.u = 0; 277 v.v = 0; 278 vertices.push_back(v); 279 280 v = spr.start + vecU + vecV; 281 v.u = 1; 282 v.v = 0; 283 vertices.push_back(v); 284 285 v = spr.end - vecU - vecV; 286 v.u = 0; 287 v.v = 1; 288 vertices.push_back(v); 289 290 v = spr.end + vecU - vecV; 291 v.u = 1; 292 v.v = 1; 293 vertices.push_back(v); 294 295 v.r = v.g = v.b = v.a = 0.f; 296 297 v = spr.start - vecU; 298 v.u = 0; 299 v.v = 0.5f; 300 vertices.push_back(v); 301 302 v = spr.start + vecU; 303 v.u = 1; 304 v.v = 0.5f; 305 vertices.push_back(v); 306 307 v = spr.end - vecU; 308 v.u = 0; 309 v.v = 0.5f; 310 vertices.push_back(v); 311 312 v = spr.end + vecU; 313 v.u = 1; 314 v.v = 0.5f; 315 vertices.push_back(v); 316 317 indices.push_back(idx); 318 indices.push_back(idx + 1); 319 indices.push_back(idx + 2 + 2); 320 indices.push_back(idx + 1); 321 indices.push_back(idx + 2 + 3); 322 indices.push_back(idx + 2 + 2); 323 324 indices.push_back(idx + 2); 325 indices.push_back(idx + 2 + 1); 326 indices.push_back(idx + 4 + 2); 327 indices.push_back(idx + 2 + 1); 328 indices.push_back(idx + 4 + 3); 329 indices.push_back(idx + 4 + 2); 330 } 331 } 332 333 Flush(); 334 335 device->EnableVertexAttribArray(positionAttribute(), false); 336 device->EnableVertexAttribArray(texCoordAttribute(), false); 337 device->EnableVertexAttribArray(colorAttribute(), false); 338 } 339 Flush()340 void GLLongSpriteRenderer::Flush() { 341 SPADES_MARK_FUNCTION_DEBUG(); 342 343 if (vertices.empty()) 344 return; 345 346 device->VertexAttribPointer(positionAttribute(), 3, IGLDevice::FloatType, false, 347 sizeof(Vertex), &(vertices[0].x)); 348 device->VertexAttribPointer(texCoordAttribute(), 2, IGLDevice::FloatType, false, 349 sizeof(Vertex), &(vertices[0].u)); 350 device->VertexAttribPointer(colorAttribute(), 4, IGLDevice::FloatType, false, 351 sizeof(Vertex), &(vertices[0].r)); 352 353 SPAssert(lastImage); 354 lastImage->Bind(IGLDevice::Texture2D); 355 356 device->DrawElements(IGLDevice::Triangles, 357 static_cast<IGLDevice::Sizei>(indices.size()), 358 IGLDevice::UnsignedInt, indices.data()); 359 360 vertices.clear(); 361 indices.clear(); 362 } 363 } 364 } 365