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 "GLSpriteRenderer.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 
29 namespace spades {
30 	namespace draw {
31 
GLSpriteRenderer(GLRenderer * renderer)32 		GLSpriteRenderer::GLSpriteRenderer(GLRenderer *renderer)
33 		    : renderer(renderer),
34 		      device(renderer->GetGLDevice()),
35 		      settings(renderer->GetSettings()),
36 		      projectionViewMatrix("projectionViewMatrix"),
37 		      rightVector("rightVector"),
38 		      upVector("upVector"),
39 		      texture("mainTexture"),
40 		      viewMatrix("viewMatrix"),
41 		      fogDistance("fogDistance"),
42 		      fogColor("fogColor"),
43 		      viewOriginVector("viewOriginVector"),
44 		      positionAttribute("positionAttribute"),
45 		      spritePosAttribute("spritePosAttribute"),
46 		      colorAttribute("colorAttribute") {
47 			SPADES_MARK_FUNCTION();
48 
49 			program = renderer->RegisterProgram("Shaders/Sprite.program");
50 		}
51 
~GLSpriteRenderer()52 		GLSpriteRenderer::~GLSpriteRenderer() { SPADES_MARK_FUNCTION(); }
53 
Add(spades::draw::GLImage * img,spades::Vector3 center,float rad,float ang,Vector4 color)54 		void GLSpriteRenderer::Add(spades::draw::GLImage *img, spades::Vector3 center, float rad,
55 		                           float ang, Vector4 color) {
56 			SPADES_MARK_FUNCTION_DEBUG();
57 			Sprite spr;
58 			spr.image = img;
59 			spr.center = center;
60 			spr.radius = rad;
61 			spr.angle = ang;
62 			if (settings.r_hdr) {
63 				// linearize color
64 				if (color.x > color.w || color.y > color.w || color.z > color.w) {
65 					// emissive material
66 					color.x *= color.x;
67 					color.y *= color.y;
68 					color.z *= color.z;
69 				} else {
70 					// scattering/absorptive material
71 					float rcp = fastRcp(color.w + .01);
72 					color.x *= color.x * rcp;
73 					color.y *= color.y * rcp;
74 					color.z *= color.z * rcp;
75 				}
76 			}
77 			spr.color = color;
78 			sprites.push_back(spr);
79 		}
80 
Clear()81 		void GLSpriteRenderer::Clear() {
82 			SPADES_MARK_FUNCTION();
83 			sprites.clear();
84 		}
85 
Render()86 		void GLSpriteRenderer::Render() {
87 			SPADES_MARK_FUNCTION();
88 			lastImage = NULL;
89 			program->Use();
90 
91 			projectionViewMatrix(program);
92 			rightVector(program);
93 			upVector(program);
94 			texture(program);
95 			viewMatrix(program);
96 			fogDistance(program);
97 			fogColor(program);
98 			viewOriginVector(program);
99 
100 			positionAttribute(program);
101 			spritePosAttribute(program);
102 			colorAttribute(program);
103 
104 			projectionViewMatrix.SetValue(renderer->GetProjectionViewMatrix());
105 			viewMatrix.SetValue(renderer->GetViewMatrix());
106 
107 			fogDistance.SetValue(renderer->GetFogDistance());
108 
109 			const auto &viewOrigin = renderer->GetSceneDef().viewOrigin;
110 			viewOriginVector.SetValue(viewOrigin.x, viewOrigin.y, viewOrigin.z);
111 
112 			Vector3 fogCol = renderer->GetFogColor();
113 			fogCol *= fogCol;
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(spritePosAttribute(), 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.x = spr.center.x;
137 				v.y = spr.center.y;
138 				v.z = spr.center.z;
139 				v.radius = spr.radius;
140 				v.angle = spr.angle;
141 				v.r = spr.color.x;
142 				v.g = spr.color.y;
143 				v.b = spr.color.z;
144 				v.a = spr.color.w;
145 
146 				uint32_t idx = (uint32_t)vertices.size();
147 				v.sx = -1;
148 				v.sy = -1;
149 				vertices.push_back(v);
150 				v.sx = 1;
151 				v.sy = -1;
152 				vertices.push_back(v);
153 				v.sx = -1;
154 				v.sy = 1;
155 				vertices.push_back(v);
156 				v.sx = 1;
157 				v.sy = 1;
158 				vertices.push_back(v);
159 
160 				indices.push_back(idx);
161 				indices.push_back(idx + 1);
162 				indices.push_back(idx + 2);
163 				indices.push_back(idx + 1);
164 				indices.push_back(idx + 3);
165 				indices.push_back(idx + 2);
166 			}
167 
168 			Flush();
169 
170 			device->EnableVertexAttribArray(positionAttribute(), false);
171 			device->EnableVertexAttribArray(spritePosAttribute(), false);
172 			device->EnableVertexAttribArray(colorAttribute(), false);
173 		}
174 
Flush()175 		void GLSpriteRenderer::Flush() {
176 			SPADES_MARK_FUNCTION_DEBUG();
177 
178 			if (vertices.empty())
179 				return;
180 
181 			device->VertexAttribPointer(positionAttribute(), 4, IGLDevice::FloatType, false,
182 			                            sizeof(Vertex), &(vertices[0].x));
183 			device->VertexAttribPointer(spritePosAttribute(), 4, IGLDevice::FloatType, false,
184 			                            sizeof(Vertex), &(vertices[0].sx));
185 			device->VertexAttribPointer(colorAttribute(), 4, IGLDevice::FloatType, false,
186 			                            sizeof(Vertex), &(vertices[0].r));
187 
188 			SPAssert(lastImage);
189 			lastImage->Bind(IGLDevice::Texture2D);
190 
191 			device->DrawElements(IGLDevice::Triangles,
192 			                     static_cast<IGLDevice::Sizei>(indices.size()),
193 			                     IGLDevice::UnsignedInt, indices.data());
194 
195 			vertices.clear();
196 			indices.clear();
197 		}
198 	}
199 }
200