1 /*
2 * This file is part of the Colobot: Gold Edition source code
3 * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
4 * http://epsitec.ch; http://colobot.info; http://github.com/colobot
5 *
6 * This program 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 * This program 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.
14 * See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see http://gnu.org/licenses
18 */
19
20
21 #include "graphics/opengl/gl14device.h"
22
23 #include "common/config.h"
24
25 #include "common/image.h"
26 #include "common/logger.h"
27
28 #include "graphics/core/light.h"
29
30 #include "graphics/engine/engine.h"
31
32 #include "graphics/opengl/glframebuffer.h"
33
34 #include "math/geometry.h"
35
36
37 #include <SDL.h>
38
39 #include <cassert>
40
41
42 // Graphics module namespace
43 namespace Gfx
44 {
45
CGL14Device(const DeviceConfig & config)46 CGL14Device::CGL14Device(const DeviceConfig &config)
47 : m_config(config)
48 {}
49
~CGL14Device()50 CGL14Device::~CGL14Device()
51 {
52 }
53
DebugHook()54 void CGL14Device::DebugHook()
55 {
56 /* This function is only called here, so it can be used
57 * as a breakpoint when debugging using gDEBugger */
58 glColor3i(0, 0, 0);
59 }
60
DebugLights()61 void CGL14Device::DebugLights()
62 {
63 Gfx::ColorHSV color(0.0, 1.0, 1.0);
64
65 glLineWidth(3.0f);
66 glDisable(GL_LIGHTING);
67 glDepthMask(GL_FALSE);
68 glDisable(GL_BLEND);
69
70 Math::Matrix saveWorldMat = m_worldMat;
71 m_worldMat.LoadIdentity();
72 UpdateModelviewMatrix();
73
74 for (int i = 0; i < static_cast<int>( m_lights.size() ); ++i)
75 {
76 color.h = static_cast<float>(i) / static_cast<float>(m_lights.size());
77 if (m_lightsEnabled[i])
78 {
79 const Light& l = m_lights[i];
80 if (l.type == LIGHT_DIRECTIONAL)
81 {
82 Gfx::VertexCol v[2];
83 v[0].coord = -Math::Normalize(l.direction) * 100.0f + Math::Vector(0.0f, 0.0f, 1.0f) * i;
84 v[0].color = HSV2RGB(color);
85 v[1].coord = Math::Normalize(l.direction) * 100.0f + Math::Vector(0.0f, 0.0f, 1.0f) * i;
86 v[1].color = HSV2RGB(color);
87 while (v[0].coord.y < 60.0f && v[0].coord.y < 60.0f)
88 {
89 v[0].coord.y += 10.0f;
90 v[1].coord.y += 10.0f;
91 }
92 DrawPrimitive(PRIMITIVE_LINES, v, 2);
93
94 v[0].coord = v[1].coord + Math::Normalize(v[0].coord - v[1].coord) * 50.0f;
95
96 glLineWidth(10.0f);
97 DrawPrimitive(PRIMITIVE_LINES, v, 2);
98 glLineWidth(3.0f);
99 }
100 else if (l.type == LIGHT_POINT)
101 {
102 Gfx::VertexCol v[8];
103 for (int i = 0; i < 8; ++i)
104 v[i].color = HSV2RGB(color);
105
106 v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f;
107 v[1].coord = l.position + Math::Vector( 1.0f, -1.0f, -1.0f) * 4.0f;
108 v[2].coord = l.position + Math::Vector( 1.0f, 1.0f, -1.0f) * 4.0f;
109 v[3].coord = l.position + Math::Vector(-1.0f, 1.0f, -1.0f) * 4.0f;
110 v[4].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f;
111 DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5);
112
113 v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f;
114 v[1].coord = l.position + Math::Vector( 1.0f, -1.0f, 1.0f) * 4.0f;
115 v[2].coord = l.position + Math::Vector( 1.0f, 1.0f, 1.0f) * 4.0f;
116 v[3].coord = l.position + Math::Vector(-1.0f, 1.0f, 1.0f) * 4.0f;
117 v[4].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f;
118 DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5);
119
120 v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f;
121 v[1].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f;
122 v[2].coord = l.position + Math::Vector( 1.0f, -1.0f, -1.0f) * 4.0f;
123 v[3].coord = l.position + Math::Vector( 1.0f, -1.0f, 1.0f) * 4.0f;
124 v[4].coord = l.position + Math::Vector( 1.0f, 1.0f, -1.0f) * 4.0f;
125 v[5].coord = l.position + Math::Vector( 1.0f, 1.0f, 1.0f) * 4.0f;
126 v[6].coord = l.position + Math::Vector(-1.0f, 1.0f, -1.0f) * 4.0f;
127 v[7].coord = l.position + Math::Vector(-1.0f, 1.0f, 1.0f) * 4.0f;
128 DrawPrimitive(PRIMITIVE_LINES, v, 8);
129 }
130 else if (l.type == LIGHT_SPOT)
131 {
132 Gfx::VertexCol v[5];
133 for (int i = 0; i < 5; ++i)
134 v[i].color = HSV2RGB(color);
135
136 v[0].coord = l.position + Math::Vector(-1.0f, 0.0f, -1.0f) * 4.0f;
137 v[1].coord = l.position + Math::Vector( 1.0f, 0.0f, -1.0f) * 4.0f;
138 v[2].coord = l.position + Math::Vector( 1.0f, 0.0f, 1.0f) * 4.0f;
139 v[3].coord = l.position + Math::Vector(-1.0f, 0.0f, 1.0f) * 4.0f;
140 v[4].coord = l.position + Math::Vector(-1.0f, 0.0f, -1.0f) * 4.0f;
141 DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5);
142
143 v[0].coord = l.position;
144 v[1].coord = l.position + Math::Normalize(l.direction) * 100.0f;
145 glEnable(GL_LINE_STIPPLE);
146 glLineStipple(3.0, 0xFF);
147 DrawPrimitive(PRIMITIVE_LINES, v, 2);
148 glDisable(GL_LINE_STIPPLE);
149 }
150 }
151 }
152
153 glLineWidth(1.0f);
154 glEnable(GL_LIGHTING);
155 glDepthMask(GL_TRUE);
156 glEnable(GL_BLEND);
157 m_worldMat = saveWorldMat;
158 UpdateModelviewMatrix();
159 }
160
GetName()161 std::string CGL14Device::GetName()
162 {
163 return std::string("OpenGL 1.4");
164 }
165
Create()166 bool CGL14Device::Create()
167 {
168 GetLogger()->Info("Creating CDevice - OpenGL 1.4\n");
169
170 if (!InitializeGLEW())
171 {
172 m_errorMessage = "An error occurred while initializing GLEW.";
173 return false;
174 }
175
176 // Extract OpenGL version
177 int glMajor = 1, glMinor = 1;
178 int glVersion = GetOpenGLVersion(glMajor, glMinor);
179
180 if (glVersion < 13)
181 {
182 GetLogger()->Error("Unsupported OpenGL version: %d.%d\n", glMajor, glMinor);
183 GetLogger()->Error("OpenGL 1.3 or newer is required to use this engine.\n");
184 m_errorMessage = "It seems your graphics card does not support OpenGL 1.3.\n";
185 m_errorMessage += "Please make sure you have appropriate hardware and newest drivers installed.\n\n";
186 m_errorMessage += GetHardwareInfo();
187 return false;
188 }
189
190 const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
191 const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
192
193 GetLogger()->Info("OpenGL %s\n", version);
194 GetLogger()->Info("%s\n", renderer);
195
196 // Detect Shadow mapping support
197 if (glVersion >= 14) // Core depth texture+shadow, OpenGL 1.4+
198 {
199 m_shadowMappingSupport = SMS_CORE;
200 m_capabilities.shadowMappingSupported = true;
201 GetLogger()->Info("Shadow mapping available (core)\n");
202 }
203 else if (glewIsSupported("GL_ARB_depth_texture GL_ARB_shadow")) // ARB depth texture + shadow
204 {
205 m_shadowMappingSupport = SMS_ARB;
206 m_capabilities.shadowMappingSupported = true;
207 GetLogger()->Info("Shadow mapping available (ARB)\n");
208 }
209 else // No Shadow mapping
210 {
211 m_shadowMappingSupport = SMS_NONE;
212 m_capabilities.shadowMappingSupported = false;
213 GetLogger()->Info("Shadow mapping not available\n");
214 }
215
216 // Detect support of anisotropic filtering
217 m_capabilities.anisotropySupported = glewIsSupported("GL_EXT_texture_filter_anisotropic");
218 if (m_capabilities.anisotropySupported)
219 {
220 // Obtain maximum anisotropy level available
221 float level;
222 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &level);
223 m_capabilities.maxAnisotropy = static_cast<int>(level);
224
225 GetLogger()->Info("Anisotropic filtering available\n");
226 GetLogger()->Info("Maximum anisotropy: %d\n", m_capabilities.maxAnisotropy);
227 }
228 else
229 {
230 GetLogger()->Info("Anisotropic filtering not available\n");
231 }
232
233 // Read maximum sample count for MSAA
234 if(glewIsSupported("GL_EXT_framebuffer_multisample"))
235 {
236 m_capabilities.multisamplingSupported = true;
237 glGetIntegerv(GL_MAX_SAMPLES_EXT, &m_capabilities.maxSamples);
238 GetLogger()->Info("Multisampling supported, max samples: %d\n", m_capabilities.maxSamples);
239 }
240 else
241 {
242 m_capabilities.multisamplingSupported = false;
243 GetLogger()->Info("Multisampling not supported\n");
244 }
245
246 // check for glMultiDrawArrays()
247 if (glVersion >= 14)
248 m_multiDrawArrays = true;
249
250 GetLogger()->Info("Auto-detecting VBO support\n");
251
252 // detecting VBO ARB extension
253 bool vboARB = glewIsSupported("GL_ARB_vertex_buffer_object");
254
255 // VBO is core OpenGL feature since 1.5
256 // everything below 1.5 means no VBO support
257 if (glVersion >= 15)
258 {
259 GetLogger()->Info("Core VBO supported\n", glMajor, glMinor);
260
261 // Set function pointers
262 m_glGenBuffers = glGenBuffers;
263 m_glDeleteBuffers = glDeleteBuffers;
264 m_glBindBuffer = glBindBuffer;
265 m_glBufferData = glBufferData;
266 m_glBufferSubData = glBufferSubData;
267 }
268 else if (vboARB) // VBO ARB extension available
269 {
270 GetLogger()->Info("ARB VBO supported\n");
271
272 // Set function pointers
273 m_glGenBuffers = glGenBuffersARB;
274 m_glDeleteBuffers = glDeleteBuffersARB;
275 m_glBindBuffer = glBindBufferARB;
276 m_glBufferData = glBufferDataARB;
277 m_glBufferSubData = glBufferSubDataARB;
278 }
279 else // no VBO support
280 {
281 m_errorMessage = "Your graphics card or drivers don't support OpenGL 1.5 or vertex buffer objects.\n"
282 "Ensure you have the latest graphics drivers for your graphics card.\n\n";
283 GetLogger()->Error(m_errorMessage.c_str());
284 m_errorMessage += GetHardwareInfo();
285 return false;
286 }
287
288 // This is mostly done in all modern hardware by default
289 // DirectX doesn't even allow the option to turn off perspective correction anymore
290 // So turn it on permanently
291 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
292
293 // To avoid problems with scaling & lighting
294 glEnable(GL_RESCALE_NORMAL);
295 //glEnable(GL_NORMALIZE); // this needs some testing
296
297 // Minimal depth bias to avoid Z-fighting
298 //SetDepthBias(0.001f);
299 glAlphaFunc(GL_GREATER, 0.1f);
300
301 // Set just to be sure
302 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
303 glMatrixMode(GL_PROJECTION);
304 glLoadIdentity();
305 glMatrixMode(GL_MODELVIEW);
306 glLoadIdentity();
307
308 glViewport(0, 0, m_config.size.x, m_config.size.y);
309
310 int numLights = 0;
311 glGetIntegerv(GL_MAX_LIGHTS, &numLights);
312
313 m_capabilities.maxLights = numLights;
314
315 m_lights = std::vector<Light>(numLights, Light());
316 m_lightsEnabled = std::vector<bool> (numLights, false);
317
318 int maxTextures = 0;
319 glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextures);
320 GetLogger()->Info("Maximum texture units: %d\n", maxTextures);
321
322 m_capabilities.multitexturingSupported = true;
323 m_capabilities.maxTextures = maxTextures;
324
325 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_capabilities.maxTextureSize);
326 GetLogger()->Info("Maximum texture size: %d\n", m_capabilities.maxTextureSize);
327
328 m_currentTextures = std::vector<Texture> (maxTextures, Texture());
329 m_texturesEnabled = std::vector<bool> (maxTextures, false);
330 m_textureStageParams = std::vector<TextureStageParams>(maxTextures, TextureStageParams());
331 m_remap = std::vector<int> (maxTextures, 0);
332
333 // default mapping
334 for (int i = 0; i < maxTextures; i++)
335 m_remap[i] = i;
336
337 // special remapping for quality shadows
338 if (maxTextures >= 4)
339 {
340 m_remap[0] = 2;
341 m_remap[1] = 3;
342 m_remap[2] = 0;
343 m_remap[3] = 1;
344
345 m_shadowQuality = true;
346 GetLogger()->Debug("Using quality shadows\n");
347 }
348 else
349 {
350 m_shadowQuality = false;
351 GetLogger()->Debug("Using simple shadows\n");
352 }
353
354 // create white texture
355 glGenTextures(1, &m_whiteTexture);
356 glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
357 int color = 0xFFFFFFFF;
358 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &color);
359 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
360 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
361 glBindTexture(GL_TEXTURE_2D, 0);
362
363 // create default framebuffer object
364 FramebufferParams framebufferParams;
365
366 framebufferParams.width = m_config.size.x;
367 framebufferParams.height = m_config.size.y;
368 framebufferParams.depth = m_config.depthSize;
369
370 m_framebuffers["default"] = MakeUnique<CDefaultFramebuffer>(framebufferParams);
371
372 m_framebufferSupport = DetectFramebufferSupport();
373 if (m_framebufferSupport == FBS_ARB)
374 {
375 m_capabilities.framebufferSupported = true;
376 GetLogger()->Info("Framebuffer supported (ARB)\n");
377
378 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_capabilities.maxRenderbufferSize);
379 GetLogger()->Info("Maximum renderbuffer size: %d\n", m_capabilities.maxRenderbufferSize);
380 }
381 else if (m_framebufferSupport == FBS_EXT)
382 {
383 m_capabilities.framebufferSupported = true;
384 GetLogger()->Info("Framebuffer supported (EXT)\n");
385
386 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &m_capabilities.maxRenderbufferSize);
387 GetLogger()->Info("Maximum renderbuffer size: %d\n", m_capabilities.maxRenderbufferSize);
388 }
389 else
390 {
391 m_capabilities.framebufferSupported = false;
392 GetLogger()->Info("Framebuffer not supported\n");
393 }
394
395 GetLogger()->Info("CDevice created successfully\n");
396
397 return true;
398 }
399
Destroy()400 void CGL14Device::Destroy()
401 {
402 // delete framebuffers
403 for (auto& framebuffer : m_framebuffers)
404 framebuffer.second->Destroy();
405
406 m_framebuffers.clear();
407
408 // Delete the remaining textures
409 // Should not be strictly necessary, but just in case
410 DestroyAllTextures();
411 glDeleteTextures(1, &m_whiteTexture);
412 m_whiteTexture = 0;
413
414 m_lights.clear();
415 m_lightsEnabled.clear();
416
417 m_currentTextures.clear();
418 m_texturesEnabled.clear();
419 m_textureStageParams.clear();
420 }
421
ConfigChanged(const DeviceConfig & newConfig)422 void CGL14Device::ConfigChanged(const DeviceConfig& newConfig)
423 {
424 m_config = newConfig;
425
426 // Reset state
427 m_lighting = false;
428
429 glViewport(0, 0, m_config.size.x, m_config.size.y);
430
431 // create default framebuffer object
432 FramebufferParams framebufferParams;
433
434 framebufferParams.width = m_config.size.x;
435 framebufferParams.height = m_config.size.y;
436 framebufferParams.depth = m_config.depthSize;
437
438 m_framebuffers["default"] = MakeUnique<CDefaultFramebuffer>(framebufferParams);
439 }
440
BeginScene()441 void CGL14Device::BeginScene()
442 {
443 Clear();
444
445 glMatrixMode(GL_PROJECTION);
446 glLoadMatrixf(m_projectionMat.Array());
447
448 UpdateModelviewMatrix();
449 }
450
EndScene()451 void CGL14Device::EndScene()
452 {
453 #ifdef DEV_BUILD
454 int count = ClearGLErrors();
455
456 if (count > 0)
457 GetLogger()->Debug("OpenGL errors detected: %d\n", count);
458 #endif
459 }
460
Clear()461 void CGL14Device::Clear()
462 {
463 glDepthMask(GL_TRUE);
464 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
465 }
466
SetRenderMode(RenderMode mode)467 void CGL14Device::SetRenderMode(RenderMode mode)
468 {
469 // nothing is done
470 }
471
SetTransform(TransformType type,const Math::Matrix & matrix)472 void CGL14Device::SetTransform(TransformType type, const Math::Matrix &matrix)
473 {
474 if (type == TRANSFORM_WORLD)
475 {
476 m_worldMat = matrix;
477 UpdateModelviewMatrix();
478
479 m_combinedMatrixOutdated = true;
480 }
481 else if (type == TRANSFORM_VIEW)
482 {
483 m_viewMat = matrix;
484 UpdateModelviewMatrix();
485
486 m_combinedMatrixOutdated = true;
487 }
488 else if (type == TRANSFORM_PROJECTION)
489 {
490 m_projectionMat = matrix;
491 glMatrixMode(GL_PROJECTION);
492 glLoadMatrixf(m_projectionMat.Array());
493
494 m_combinedMatrixOutdated = true;
495 }
496 else if (type == TRANSFORM_SHADOW)
497 {
498 m_shadowMatrix = matrix;
499
500 glActiveTexture(GL_TEXTURE0 + m_remap[2]);
501 glMatrixMode(GL_TEXTURE);
502 glLoadMatrixf(m_shadowMatrix.Array());
503 }
504 else
505 {
506 assert(false);
507 }
508 }
509
UpdateModelviewMatrix()510 void CGL14Device::UpdateModelviewMatrix()
511 {
512 glMatrixMode(GL_MODELVIEW);
513 glLoadIdentity();
514 glScalef(1.0f, 1.0f, -1.0f);
515 glMultMatrixf(m_viewMat.Array());
516 glMultMatrixf(m_worldMat.Array());
517 glGetFloatv(GL_MODELVIEW_MATRIX, m_modelviewMat.Array());
518
519 if (m_lighting)
520 {
521 UpdateLightPositions();
522 }
523 }
524
SetMaterial(const Material & material)525 void CGL14Device::SetMaterial(const Material &material)
526 {
527 m_material = material;
528
529 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, m_material.ambient.Array());
530 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, m_material.diffuse.Array());
531 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m_material.specular.Array());
532 }
533
GetMaxLightCount()534 int CGL14Device::GetMaxLightCount()
535 {
536 return m_lights.size();
537 }
538
SetLight(int index,const Light & light)539 void CGL14Device::SetLight(int index, const Light &light)
540 {
541 assert(index >= 0);
542 assert(index < static_cast<int>( m_lights.size() ));
543
544 m_lights[index] = light;
545
546 // Indexing from GL_LIGHT0 should always work
547 glLightfv(GL_LIGHT0 + index, GL_AMBIENT, const_cast<GLfloat*>(light.ambient.Array()));
548 glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, const_cast<GLfloat*>(light.diffuse.Array()));
549 glLightfv(GL_LIGHT0 + index, GL_SPECULAR, const_cast<GLfloat*>(light.specular.Array()));
550
551 glLightf(GL_LIGHT0 + index, GL_CONSTANT_ATTENUATION, light.attenuation0);
552 glLightf(GL_LIGHT0 + index, GL_LINEAR_ATTENUATION, light.attenuation1);
553 glLightf(GL_LIGHT0 + index, GL_QUADRATIC_ATTENUATION, light.attenuation2);
554
555 if (light.type == LIGHT_SPOT)
556 {
557 glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, light.spotAngle * Math::RAD_TO_DEG);
558 glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, light.spotIntensity);
559 }
560 else
561 {
562 glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, 180.0f);
563 }
564
565 UpdateLightPosition(index);
566 }
567
UpdateLightPosition(int index)568 void CGL14Device::UpdateLightPosition(int index)
569 {
570 assert(index >= 0);
571 assert(index < static_cast<int>( m_lights.size() ));
572
573 glMatrixMode(GL_MODELVIEW);
574 glPushMatrix();
575
576 Light &light = m_lights[index];
577
578 if (light.type == LIGHT_POINT)
579 {
580 glLoadIdentity();
581 glScalef(1.0f, 1.0f, -1.0f);
582 glMultMatrixf(m_viewMat.Array());
583
584 GLfloat position[4] = { light.position.x, light.position.y, light.position.z, 1.0f };
585 glLightfv(GL_LIGHT0 + index, GL_POSITION, position);
586 }
587 else
588 {
589 glLoadIdentity();
590 glScalef(1.0f, 1.0f, -1.0f);
591 Math::Matrix mat = m_viewMat;
592 mat.Set(1, 4, 0.0f);
593 mat.Set(2, 4, 0.0f);
594 mat.Set(3, 4, 0.0f);
595 glMultMatrixf(mat.Array());
596
597 if (light.type == LIGHT_SPOT)
598 {
599 GLfloat direction[4] = { -light.direction.x, -light.direction.y, -light.direction.z, 1.0f };
600 glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction);
601 }
602 else if (light.type == LIGHT_DIRECTIONAL)
603 {
604 GLfloat position[4] = { -light.direction.x, -light.direction.y, -light.direction.z, 0.0f };
605 glLightfv(GL_LIGHT0 + index, GL_POSITION, position);
606 }
607 }
608
609 glPopMatrix();
610 }
611
UpdateLightPositions()612 void CGL14Device::UpdateLightPositions()
613 {
614 glMatrixMode(GL_MODELVIEW);
615 glPushMatrix();
616
617 // update spotlights and directional lights
618 glLoadIdentity();
619 glScalef(1.0f, 1.0f, -1.0f);
620 Math::Matrix mat = m_viewMat;
621 mat.Set(1, 4, 0.0f);
622 mat.Set(2, 4, 0.0f);
623 mat.Set(3, 4, 0.0f);
624 glMultMatrixf(mat.Array());
625
626 int lightIndex = 0;
627
628 for (const Light &light : m_lights)
629 {
630 if (m_lightsEnabled[lightIndex])
631 {
632 if (light.type == LIGHT_SPOT)
633 {
634 GLfloat direction[4] = { -light.direction.x, -light.direction.y, -light.direction.z, 1.0f };
635 glLightfv(GL_LIGHT0 + lightIndex, GL_SPOT_DIRECTION, direction);
636 }
637 else if (light.type == LIGHT_DIRECTIONAL)
638 {
639 GLfloat position[4] = { -light.direction.x, -light.direction.y, -light.direction.z, 0.0f };
640 glLightfv(GL_LIGHT0 + lightIndex, GL_POSITION, position);
641 }
642 }
643
644 lightIndex++;
645 }
646
647 // update point lights
648 glLoadIdentity();
649 glScalef(1.0f, 1.0f, -1.0f);
650 glMultMatrixf(m_viewMat.Array());
651
652 lightIndex = 0;
653
654 for (const Light &light : m_lights)
655 {
656 if (m_lightsEnabled[lightIndex])
657 {
658 if (light.type == LIGHT_POINT)
659 {
660 GLfloat position[4] = { light.position.x, light.position.y, light.position.z, 1.0f };
661 glLightfv(GL_LIGHT0 + lightIndex, GL_POSITION, position);
662 }
663 }
664
665 lightIndex++;
666 }
667
668 glPopMatrix();
669 }
670
SetLightEnabled(int index,bool enabled)671 void CGL14Device::SetLightEnabled(int index, bool enabled)
672 {
673 assert(index >= 0);
674 assert(index < static_cast<int>( m_lights.size() ));
675
676 m_lightsEnabled[index] = enabled;
677
678 if (enabled)
679 glEnable(GL_LIGHT0 + index);
680 else
681 glDisable(GL_LIGHT0 + index);
682 }
683
684 /** If image is invalid, returns invalid texture.
685 Otherwise, returns pointer to new Texture struct.
686 This struct must not be deleted in other way than through DeleteTexture() */
CreateTexture(CImage * image,const TextureCreateParams & params)687 Texture CGL14Device::CreateTexture(CImage *image, const TextureCreateParams ¶ms)
688 {
689 ImageData *data = image->GetData();
690 if (data == nullptr)
691 {
692 GetLogger()->Error("Invalid texture data\n");
693 return Texture(); // invalid texture
694 }
695
696 Math::IntPoint originalSize = image->GetSize();
697
698 if (params.padToNearestPowerOfTwo)
699 image->PadToNearestPowerOfTwo();
700
701 Texture tex = CreateTexture(data, params);
702 tex.originalSize = originalSize;
703
704 return tex;
705 }
706
CreateTexture(ImageData * data,const TextureCreateParams & params)707 Texture CGL14Device::CreateTexture(ImageData *data, const TextureCreateParams ¶ms)
708 {
709 Texture result;
710
711 result.size.x = data->surface->w;
712 result.size.y = data->surface->h;
713
714 if (!Math::IsPowerOfTwo(result.size.x) || !Math::IsPowerOfTwo(result.size.y))
715 GetLogger()->Warn("Creating non-power-of-2 texture (%dx%d)!\n", result.size.x, result.size.y);
716
717 result.originalSize = result.size;
718
719 // Use & enable 1st texture stage
720 glActiveTexture(GL_TEXTURE0 + m_remap[0]);
721
722 glEnable(GL_TEXTURE_2D);
723
724 glGenTextures(1, &result.id);
725 glBindTexture(GL_TEXTURE_2D, result.id);
726
727 // Set texture parameters
728 GLint minF = GL_NEAREST, magF = GL_NEAREST;
729 int mipmapLevel = 1;
730
731 switch (params.filter)
732 {
733 case TEX_FILTER_NEAREST:
734 minF = GL_NEAREST;
735 magF = GL_NEAREST;
736 break;
737 case TEX_FILTER_BILINEAR:
738 minF = GL_LINEAR;
739 magF = GL_LINEAR;
740 break;
741 case TEX_FILTER_TRILINEAR:
742 minF = GL_LINEAR_MIPMAP_LINEAR;
743 magF = GL_LINEAR;
744 mipmapLevel = CEngine::GetInstance().GetTextureMipmapLevel();
745 break;
746 }
747
748 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minF);
749 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magF);
750
751 // Set mipmap level and automatic mipmap generation if neccesary
752 if (params.mipmap)
753 {
754 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
755 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapLevel - 1);
756 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
757 }
758 else
759 {
760 // Has to be set to 0 because no mipmaps are generated
761 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
762 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
763 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
764 }
765
766 // Set anisotropy level if available
767 if (m_capabilities.anisotropySupported)
768 {
769 float level = Math::Min(m_capabilities.maxAnisotropy, CEngine::GetInstance().GetTextureAnisotropyLevel());
770
771 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, level);
772 }
773
774 PreparedTextureData texData = PrepareTextureData(data, params.format);
775 result.alpha = texData.alpha;
776
777 glPixelStorei(GL_UNPACK_ROW_LENGTH, texData.actualSurface->pitch / texData.actualSurface->format->BytesPerPixel);
778 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
779
780 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texData.actualSurface->w, texData.actualSurface->h,
781 0, texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels);
782
783 SDL_FreeSurface(texData.convertedSurface);
784
785 m_allTextures.insert(result);
786
787 // Restore the previous state of 1st stage
788 glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
789
790 if (! m_texturesEnabled[0])
791 glDisable(GL_TEXTURE_2D);
792
793 return result;
794 }
795
CreateDepthTexture(int width,int height,int depth)796 Texture CGL14Device::CreateDepthTexture(int width, int height, int depth)
797 {
798 Texture result;
799
800 if (m_shadowMappingSupport == SMS_NONE)
801 {
802 result.id = 0;
803 return result;
804 }
805
806 result.alpha = false;
807 result.size.x = width;
808 result.size.y = height;
809
810 // Use & enable 1st texture stage
811 glActiveTexture(GL_TEXTURE0 + m_remap[0]);
812
813 glGenTextures(1, &result.id);
814 glBindTexture(GL_TEXTURE_2D, result.id);
815
816 GLuint format = GL_DEPTH_COMPONENT;
817
818 switch (depth)
819 {
820 case 16:
821 format = GL_DEPTH_COMPONENT16;
822 break;
823 case 24:
824 format = GL_DEPTH_COMPONENT24;
825 break;
826 case 32:
827 format = GL_DEPTH_COMPONENT32;
828 break;
829 }
830
831 glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr);
832 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
833 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
834
835 float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
836
837 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
838 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
839 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
840 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
841 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
842
843 glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
844
845 return result;
846 }
847
UpdateTexture(const Texture & texture,Math::IntPoint offset,ImageData * data,TexImgFormat format)848 void CGL14Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format)
849 {
850 // Use & enable 1st texture stage
851 glActiveTexture(GL_TEXTURE0 + m_remap[0]);
852
853 glEnable(GL_TEXTURE_2D);
854
855 glBindTexture(GL_TEXTURE_2D, texture.id);
856
857 PreparedTextureData texData = PrepareTextureData(data, format);
858
859 glPixelStorei(GL_UNPACK_ROW_LENGTH, texData.actualSurface->pitch / texData.actualSurface->format->BytesPerPixel);
860 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
861
862 glTexSubImage2D(GL_TEXTURE_2D, 0, offset.x, offset.y, texData.actualSurface->w, texData.actualSurface->h,
863 texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels);
864
865 SDL_FreeSurface(texData.convertedSurface);
866 }
867
DestroyTexture(const Texture & texture)868 void CGL14Device::DestroyTexture(const Texture &texture)
869 {
870 // Unbind the texture if in use anywhere
871 for (int index = 0; index < static_cast<int>( m_currentTextures.size() ); ++index)
872 {
873 if (m_currentTextures[index] == texture)
874 SetTexture(index, Texture()); // set to invalid texture
875 }
876
877 auto it = m_allTextures.find(texture);
878 if (it != m_allTextures.end())
879 {
880 glDeleteTextures(1, &texture.id);
881 m_allTextures.erase(it);
882 }
883 }
884
DestroyAllTextures()885 void CGL14Device::DestroyAllTextures()
886 {
887 // Unbind all texture stages
888 for (int index = 0; index < static_cast<int>( m_currentTextures.size() ); ++index)
889 SetTexture(index, Texture());
890
891 for (auto it = m_allTextures.begin(); it != m_allTextures.end(); ++it)
892 glDeleteTextures(1, &(*it).id);
893
894 m_allTextures.clear();
895
896 // recreate white texture
897 glActiveTexture(GL_TEXTURE0 + m_remap[0]);
898
899 glDeleteTextures(1, &m_whiteTexture);
900 glGenTextures(1, &m_whiteTexture);
901 glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
902 int color = 0xFFFFFFFF;
903 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &color);
904 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
905 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
906
907 glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
908 }
909
GetMaxTextureStageCount()910 int CGL14Device::GetMaxTextureStageCount()
911 {
912 return m_currentTextures.size();
913 }
914
915 /**
916 If \a texture is invalid, unbinds the given texture.
917 If valid, binds the texture and enables the given texture stage.
918 The setting is remembered, even if texturing is disabled at the moment. */
SetTexture(int index,const Texture & texture)919 void CGL14Device::SetTexture(int index, const Texture &texture)
920 {
921 assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() ));
922
923 bool same = m_currentTextures[index].id == texture.id;
924
925 m_currentTextures[index] = texture; // remember the new value
926
927 if (same)
928 return; // nothing to do
929
930 glActiveTexture(GL_TEXTURE0 + m_remap[index]);
931
932 glBindTexture(GL_TEXTURE_2D, texture.id);
933
934 // Params need to be updated for the new bound texture
935 UpdateTextureParams(index);
936 }
937
SetTexture(int index,unsigned int textureId)938 void CGL14Device::SetTexture(int index, unsigned int textureId)
939 {
940 assert(index >= 0 && index < static_cast<int>(m_currentTextures.size()));
941
942 if (m_currentTextures[index].id == textureId)
943 return; // nothing to do
944
945 m_currentTextures[index].id = textureId;
946
947 glActiveTexture(GL_TEXTURE0 + m_remap[index]);
948
949 glBindTexture(GL_TEXTURE_2D, textureId);
950
951 // Params need to be updated for the new bound texture
952 UpdateTextureParams(index);
953 }
954
SetTextureEnabled(int index,bool enabled)955 void CGL14Device::SetTextureEnabled(int index, bool enabled)
956 {
957 assert(index >= 0 && index < static_cast<int>(m_currentTextures.size()));
958
959 bool same = m_texturesEnabled[index] == enabled;
960
961 m_texturesEnabled[index] = enabled;
962
963 if (same)
964 return; // nothing to do
965
966 glActiveTexture(GL_TEXTURE0 + m_remap[index]);
967
968 if (enabled)
969 glEnable(GL_TEXTURE_2D);
970 else
971 glDisable(GL_TEXTURE_2D);
972 }
973
974 /**
975 Sets the texture parameters for the given texture stage.
976 If the given texture was not set (bound) yet, nothing happens.
977 The settings are remembered, even if texturing is disabled at the moment. */
SetTextureStageParams(int index,const TextureStageParams & params)978 void CGL14Device::SetTextureStageParams(int index, const TextureStageParams ¶ms)
979 {
980 assert(index >= 0 && index < static_cast<int>(m_currentTextures.size()));
981
982 // Remember the settings
983 m_textureStageParams[index] = params;
984
985 UpdateTextureParams(index);
986 }
987
UpdateTextureParams(int index)988 void CGL14Device::UpdateTextureParams(int index)
989 {
990 assert(index >= 0 && index < static_cast<int>(m_currentTextures.size()));
991
992 // Don't actually do anything if texture not set
993 if (! m_currentTextures[index].Valid())
994 return;
995
996 const TextureStageParams ¶ms = m_textureStageParams[index];
997
998 glActiveTexture(GL_TEXTURE0 + m_remap[index]);
999
1000 if (params.wrapS == TEX_WRAP_CLAMP)
1001 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1002 else if (params.wrapS == TEX_WRAP_CLAMP_TO_BORDER)
1003 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1004 else if (params.wrapS == TEX_WRAP_REPEAT)
1005 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1006 else assert(false);
1007
1008 if (params.wrapT == TEX_WRAP_CLAMP)
1009 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1010 else if (params.wrapT == TEX_WRAP_CLAMP_TO_BORDER)
1011 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1012 else if (params.wrapT == TEX_WRAP_REPEAT)
1013 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1014 else assert(false);
1015
1016 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, params.factor.Array());
1017
1018 // To save some trouble
1019 if ( (params.colorOperation == TEX_MIX_OPER_DEFAULT) &&
1020 (params.alphaOperation == TEX_MIX_OPER_DEFAULT) )
1021 {
1022 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1023 goto after_tex_operations;
1024 }
1025
1026 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1027
1028 // Only these modes of getting color & alpha are used
1029 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1030 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
1031 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1032 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
1033
1034 // Color operation
1035
1036 if (params.colorOperation == TEX_MIX_OPER_DEFAULT)
1037 {
1038 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
1039 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
1040 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
1041 goto after_tex_color;
1042 }
1043 else if (params.colorOperation == TEX_MIX_OPER_REPLACE)
1044 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
1045 else if (params.colorOperation == TEX_MIX_OPER_MODULATE)
1046 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
1047 else if (params.colorOperation == TEX_MIX_OPER_ADD)
1048 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
1049 else if (params.colorOperation == TEX_MIX_OPER_SUBTRACT)
1050 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
1051 else assert(false);
1052
1053 // Color arg1
1054 if (params.colorArg1 == TEX_MIX_ARG_TEXTURE)
1055 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
1056 else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_0)
1057 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
1058 else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_1)
1059 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE1);
1060 else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_2)
1061 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE2);
1062 else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_3)
1063 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE3);
1064 else if (params.colorArg1 == TEX_MIX_ARG_COMPUTED_COLOR)
1065 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
1066 else if (params.colorArg1 == TEX_MIX_ARG_SRC_COLOR)
1067 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
1068 else if (params.colorArg1 == TEX_MIX_ARG_FACTOR)
1069 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT);
1070 else assert(false);
1071
1072 // Color arg2
1073 if (params.colorArg2 == TEX_MIX_ARG_TEXTURE)
1074 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
1075 else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_0)
1076 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE0);
1077 else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_1)
1078 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1);
1079 else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_2)
1080 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE2);
1081 else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_3)
1082 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE3);
1083 else if (params.colorArg2 == TEX_MIX_ARG_COMPUTED_COLOR)
1084 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
1085 else if (params.colorArg2 == TEX_MIX_ARG_SRC_COLOR)
1086 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
1087 else if (params.colorArg2 == TEX_MIX_ARG_FACTOR)
1088 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
1089 else assert(false);
1090
1091
1092 after_tex_color:
1093
1094 // Alpha operation
1095 if (params.alphaOperation == TEX_MIX_OPER_DEFAULT)
1096 {
1097 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
1098 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
1099 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
1100 goto after_tex_operations;
1101 }
1102 else if (params.alphaOperation == TEX_MIX_OPER_REPLACE)
1103 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
1104 else if (params.alphaOperation == TEX_MIX_OPER_MODULATE)
1105 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
1106 else if (params.alphaOperation == TEX_MIX_OPER_ADD)
1107 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
1108 else if (params.alphaOperation == TEX_MIX_OPER_SUBTRACT)
1109 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_SUBTRACT);
1110 else assert(false);
1111
1112 // Alpha arg1
1113 if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE)
1114 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
1115 else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_0)
1116 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
1117 else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_1)
1118 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE1);
1119 else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_2)
1120 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE2);
1121 else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_3)
1122 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE3);
1123 else if (params.alphaArg1 == TEX_MIX_ARG_COMPUTED_COLOR)
1124 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
1125 else if (params.alphaArg1 == TEX_MIX_ARG_SRC_COLOR)
1126 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
1127 else if (params.alphaArg1 == TEX_MIX_ARG_FACTOR)
1128 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);
1129 else assert(false);
1130
1131 // Alpha arg2
1132 if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE)
1133 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
1134 else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_0)
1135 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE0);
1136 else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_1)
1137 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE1);
1138 else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_2)
1139 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE2);
1140 else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_3)
1141 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE3);
1142 else if (params.alphaArg2 == TEX_MIX_ARG_COMPUTED_COLOR)
1143 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
1144 else if (params.alphaArg2 == TEX_MIX_ARG_SRC_COLOR)
1145 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
1146 else if (params.alphaArg2 == TEX_MIX_ARG_FACTOR)
1147 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
1148 else assert(false);
1149
1150 after_tex_operations: ;
1151 }
1152
EnableShadows()1153 void CGL14Device::EnableShadows()
1154 {
1155 // already enabled
1156 if (m_shadowMapping) return;
1157
1158 // shadow map unit
1159 glActiveTexture(GL_TEXTURE0 + m_remap[2]);
1160 glEnable(GL_TEXTURE_2D);
1161
1162 glMatrixMode(GL_TEXTURE);
1163 glLoadMatrixf(m_shadowMatrix.Array());
1164
1165 // enable texture coordinate generation
1166 glEnable(GL_TEXTURE_GEN_S);
1167 glEnable(GL_TEXTURE_GEN_T);
1168 glEnable(GL_TEXTURE_GEN_R);
1169 glEnable(GL_TEXTURE_GEN_Q);
1170
1171 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
1172 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
1173 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
1174 glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
1175
1176 float plane1[] = { 1.0f, 0.0f, 0.0f, 0.0f };
1177 float plane2[] = { 0.0f, 1.0f, 0.0f, 0.0f };
1178 float plane3[] = { 0.0f, 0.0f, 1.0f, 0.0f };
1179 float plane4[] = { 0.0f, 0.0f, 0.0f, 1.0f };
1180
1181 glTexGenfv(GL_S, GL_EYE_PLANE, plane1);
1182 glTexGenfv(GL_T, GL_EYE_PLANE, plane2);
1183 glTexGenfv(GL_R, GL_EYE_PLANE, plane3);
1184 glTexGenfv(GL_Q, GL_EYE_PLANE, plane4);
1185
1186 // simple shadows
1187 if (!m_shadowQuality)
1188 {
1189 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1190 }
1191 // quality shadows
1192 else
1193 {
1194 // texture environment settings
1195 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1196
1197 float half[] = { 0.5f, 0.5f, 0.5f, 1.0f };
1198 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, half);
1199
1200 // color = 0.5 * (1.0 - shadow)
1201 // = 0.5 for shadow = 0.0
1202 // = 0.0 for shadow = 1.0
1203 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
1204
1205 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
1206 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
1207
1208 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
1209 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
1210
1211 // alpha = previous
1212 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
1213
1214 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
1215 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1216
1217 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1218 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1219
1220
1221 // combine unit
1222 glActiveTexture(GL_TEXTURE0 + m_remap[3]);
1223 glEnable(GL_TEXTURE_2D);
1224 glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
1225
1226 // texture enviromnent settings
1227 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1228
1229 // color = (1.0 - previous) * primary color
1230 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
1231
1232 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
1233 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
1234
1235 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
1236 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
1237
1238 // alpha = primary color
1239 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
1240
1241 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
1242 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1243 }
1244
1245 m_shadowMapping = true;
1246 }
1247
DisableShadows()1248 void CGL14Device::DisableShadows()
1249 {
1250 // already disabled
1251 if (!m_shadowMapping) return;
1252
1253 glActiveTexture(GL_TEXTURE0 + m_remap[2]);
1254 glDisable(GL_TEXTURE_2D);
1255 glBindTexture(GL_TEXTURE_2D, 0);
1256
1257 glDisable(GL_TEXTURE_GEN_S);
1258 glDisable(GL_TEXTURE_GEN_T);
1259 glDisable(GL_TEXTURE_GEN_R);
1260 glDisable(GL_TEXTURE_GEN_Q);
1261
1262 // quality shadows
1263 if (m_shadowQuality)
1264 {
1265 glActiveTexture(GL_TEXTURE0 + m_remap[3]);
1266 glDisable(GL_TEXTURE_2D);
1267 }
1268
1269 m_shadowMapping = false;
1270 }
1271
SetTextureStageWrap(int index,TexWrapMode wrapS,TexWrapMode wrapT)1272 void CGL14Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT)
1273 {
1274 assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() ));
1275
1276 // Remember the settings
1277 m_textureStageParams[index].wrapS = wrapS;
1278 m_textureStageParams[index].wrapT = wrapT;
1279
1280 // Don't actually do anything if texture not set
1281 if (! m_currentTextures[index].Valid())
1282 return;
1283
1284 glActiveTexture(GL_TEXTURE0 + m_remap[index]);
1285
1286 if (wrapS == TEX_WRAP_CLAMP)
1287 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1288 else if (wrapS == TEX_WRAP_CLAMP_TO_BORDER)
1289 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1290 else if (wrapS == TEX_WRAP_REPEAT)
1291 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1292 else assert(false);
1293
1294 if (wrapT == TEX_WRAP_CLAMP)
1295 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1296 else if (wrapT == TEX_WRAP_CLAMP_TO_BORDER)
1297 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1298 else if (wrapT == TEX_WRAP_REPEAT)
1299 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1300 else assert(false);
1301 }
1302
1303 namespace
1304 {
SetVertexAttributes(const Vertex * bufferBase,const std::vector<int> & textureRemapping)1305 void SetVertexAttributes(const Vertex* bufferBase, const std::vector<int>& textureRemapping)
1306 {
1307 glEnableClientState(GL_VERTEX_ARRAY);
1308 glVertexPointer(3, GL_FLOAT, sizeof(Vertex), reinterpret_cast<const char*>(bufferBase) + offsetof(Vertex, coord));
1309
1310 glEnableClientState(GL_NORMAL_ARRAY);
1311 glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast<const char*>(bufferBase) + offsetof(Vertex, normal));
1312
1313 glClientActiveTexture(GL_TEXTURE0 + textureRemapping[1]);
1314 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1315 glClientActiveTexture(GL_TEXTURE0 + textureRemapping[0]);
1316 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1317 glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<const char*>(bufferBase) + offsetof(Vertex, texCoord));
1318
1319 glDisableClientState(GL_COLOR_ARRAY);
1320 }
1321
SetVertexAttributes(const VertexTex2 * bufferBase,const std::vector<int> & textureRemapping)1322 void SetVertexAttributes(const VertexTex2* bufferBase, const std::vector<int>& textureRemapping)
1323 {
1324 glEnableClientState(GL_VERTEX_ARRAY);
1325 glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<const char*>(bufferBase) + offsetof(VertexTex2, coord));
1326
1327 glEnableClientState(GL_NORMAL_ARRAY);
1328 glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<const char*>(bufferBase) + offsetof(VertexTex2, normal));
1329
1330 glClientActiveTexture(GL_TEXTURE0 + textureRemapping[1]);
1331 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1332 glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<const char*>(bufferBase) + offsetof(VertexTex2, texCoord2));
1333 glClientActiveTexture(GL_TEXTURE0 + textureRemapping[0]);
1334 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1335 glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<const char*>(bufferBase) + offsetof(VertexTex2, texCoord));
1336
1337 glDisableClientState(GL_COLOR_ARRAY);
1338 }
1339
SetVertexAttributes(const VertexCol * bufferBase,const std::vector<int> & textureRemapping)1340 void SetVertexAttributes(const VertexCol* bufferBase, const std::vector<int>& textureRemapping)
1341 {
1342 glEnableClientState(GL_VERTEX_ARRAY);
1343 glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), reinterpret_cast<const char*>(bufferBase) + offsetof(VertexCol, coord));
1344
1345 glDisableClientState(GL_NORMAL_ARRAY);
1346
1347 glClientActiveTexture(GL_TEXTURE0 + textureRemapping[1]);
1348 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1349 glClientActiveTexture(GL_TEXTURE0 + textureRemapping[0]);
1350 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1351
1352 glEnableClientState(GL_COLOR_ARRAY);
1353 glColorPointer(4, GL_FLOAT, sizeof(VertexCol), reinterpret_cast<const char*>(bufferBase) + offsetof(VertexCol, color));
1354 }
1355 } // namespace
1356
DrawPrimitive(PrimitiveType type,const Vertex * vertices,int vertexCount,Color color)1357 void CGL14Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount,
1358 Color color)
1359 {
1360 m_glBindBuffer(GL_ARRAY_BUFFER, 0);
1361 SetVertexAttributes(vertices, m_remap);
1362 glColor4fv(color.Array());
1363
1364 glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
1365 }
1366
DrawPrimitive(PrimitiveType type,const VertexTex2 * vertices,int vertexCount,Color color)1367 void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
1368 Color color)
1369 {
1370 m_glBindBuffer(GL_ARRAY_BUFFER, 0);
1371 SetVertexAttributes(vertices, m_remap);
1372 glColor4fv(color.Array());
1373
1374 glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
1375 }
1376
DrawPrimitive(PrimitiveType type,const VertexCol * vertices,int vertexCount)1377 void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount)
1378 {
1379 m_glBindBuffer(GL_ARRAY_BUFFER, 0);
1380 SetVertexAttributes(vertices, m_remap);
1381
1382 glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
1383 }
1384
DrawPrimitives(PrimitiveType type,const Vertex * vertices,int first[],int count[],int drawCount,Color color)1385 void CGL14Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
1386 int first[], int count[], int drawCount, Color color)
1387 {
1388 m_glBindBuffer(GL_ARRAY_BUFFER, 0);
1389 SetVertexAttributes(vertices, m_remap);
1390 glColor4fv(color.Array());
1391
1392 GLenum t = TranslateGfxPrimitive(type);
1393
1394 if (m_multiDrawArrays)
1395 {
1396 glMultiDrawArrays(t, first, count, drawCount);
1397 }
1398 else
1399 {
1400 for (int i = 0; i < drawCount; i++)
1401 glDrawArrays(t, first[i], count[i]);
1402 }
1403 }
1404
DrawPrimitives(PrimitiveType type,const VertexTex2 * vertices,int first[],int count[],int drawCount,Color color)1405 void CGL14Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
1406 int first[], int count[], int drawCount, Color color)
1407 {
1408 m_glBindBuffer(GL_ARRAY_BUFFER, 0);
1409 SetVertexAttributes(vertices, m_remap);
1410 glColor4fv(color.Array());
1411
1412 GLenum t = TranslateGfxPrimitive(type);
1413
1414 if (m_multiDrawArrays)
1415 {
1416 glMultiDrawArrays(t, first, count, drawCount);
1417 }
1418 else
1419 {
1420 for (int i = 0; i < drawCount; i++)
1421 glDrawArrays(t, first[i], count[i]);
1422 }
1423 }
1424
DrawPrimitives(PrimitiveType type,const VertexCol * vertices,int first[],int count[],int drawCount)1425 void CGL14Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
1426 int first[], int count[], int drawCount)
1427 {
1428 m_glBindBuffer(GL_ARRAY_BUFFER, 0);
1429 SetVertexAttributes(vertices, m_remap);
1430
1431 GLenum t = TranslateGfxPrimitive(type);
1432
1433 if (m_multiDrawArrays)
1434 {
1435 glMultiDrawArrays(t, first, count, drawCount);
1436 }
1437 else
1438 {
1439 for (int i = 0; i < drawCount; i++)
1440 glDrawArrays(t, first[i], count[i]);
1441 }
1442 }
1443
1444 template <typename Vertex>
CreateStaticBufferImpl(PrimitiveType primitiveType,const Vertex * vertices,int vertexCount)1445 unsigned int CGL14Device::CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount)
1446 {
1447 unsigned int id = ++m_lastVboId;
1448
1449 VboObjectInfo info;
1450 info.primitiveType = primitiveType;
1451 info.vertexType = Vertex::VERTEX_TYPE;
1452 info.vertexCount = vertexCount;
1453 info.bufferId = 0;
1454
1455 m_glGenBuffers(1, &info.bufferId);
1456 m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
1457 m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
1458 m_glBindBuffer(GL_ARRAY_BUFFER, 0);
1459
1460 m_vboObjects[id] = info;
1461
1462 return id;
1463 }
1464
1465 template <typename Vertex>
UpdateStaticBufferImpl(unsigned int bufferId,PrimitiveType primitiveType,const Vertex * vertices,int vertexCount)1466 void CGL14Device::UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount)
1467 {
1468 auto it = m_vboObjects.find(bufferId);
1469 if (it == m_vboObjects.end())
1470 return;
1471
1472 VboObjectInfo& info = (*it).second;
1473 info.primitiveType = primitiveType;
1474 info.vertexType = Vertex::VERTEX_TYPE;
1475 info.vertexCount = vertexCount;
1476
1477 m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
1478 m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
1479 m_glBindBuffer(GL_ARRAY_BUFFER, 0);
1480 }
1481
DrawStaticBuffer(unsigned int bufferId)1482 void CGL14Device::DrawStaticBuffer(unsigned int bufferId)
1483 {
1484 auto it = m_vboObjects.find(bufferId);
1485 if (it == m_vboObjects.end())
1486 return;
1487
1488 m_glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId);
1489
1490 if ((*it).second.vertexType == VERTEX_TYPE_NORMAL)
1491 {
1492 SetVertexAttributes(static_cast<Vertex*>(nullptr), m_remap);
1493 }
1494 else if ((*it).second.vertexType == VERTEX_TYPE_TEX2)
1495 {
1496 SetVertexAttributes(static_cast<VertexTex2*>(nullptr), m_remap);
1497 }
1498 else if ((*it).second.vertexType == VERTEX_TYPE_COL)
1499 {
1500 SetVertexAttributes(static_cast<VertexCol*>(nullptr), m_remap);
1501 }
1502
1503 GLenum mode = TranslateGfxPrimitive((*it).second.primitiveType);
1504
1505 glDrawArrays(mode, 0, (*it).second.vertexCount);
1506 }
1507
DestroyStaticBuffer(unsigned int bufferId)1508 void CGL14Device::DestroyStaticBuffer(unsigned int bufferId)
1509 {
1510 auto it = m_vboObjects.find(bufferId);
1511 if (it == m_vboObjects.end())
1512 return;
1513
1514 m_glDeleteBuffers(1, &(*it).second.bufferId);
1515
1516 m_vboObjects.erase(it);
1517 }
1518
1519 /* Based on libwine's implementation */
1520
ComputeSphereVisibility(const Math::Vector & center,float radius)1521 int CGL14Device::ComputeSphereVisibility(const Math::Vector ¢er, float radius)
1522 {
1523 if (m_combinedMatrixOutdated)
1524 {
1525 m_combinedMatrix = Math::MultiplyMatrices(m_projectionMat, m_modelviewMat);
1526 m_combinedMatrixOutdated = false;
1527 }
1528
1529 Math::Matrix &m = m_combinedMatrix;
1530
1531 Math::Vector vec[6];
1532 float originPlane[6];
1533
1534 // Left plane
1535 vec[0].x = m.Get(4, 1) + m.Get(1, 1);
1536 vec[0].y = m.Get(4, 2) + m.Get(1, 2);
1537 vec[0].z = m.Get(4, 3) + m.Get(1, 3);
1538 float l1 = vec[0].Length();
1539 vec[0].Normalize();
1540 originPlane[0] = (m.Get(4, 4) + m.Get(1, 4)) / l1;
1541
1542 // Right plane
1543 vec[1].x = m.Get(4, 1) - m.Get(1, 1);
1544 vec[1].y = m.Get(4, 2) - m.Get(1, 2);
1545 vec[1].z = m.Get(4, 3) - m.Get(1, 3);
1546 float l2 = vec[1].Length();
1547 vec[1].Normalize();
1548 originPlane[1] = (m.Get(4, 4) - m.Get(1, 4)) / l2;
1549
1550 // Bottom plane
1551 vec[2].x = m.Get(4, 1) + m.Get(2, 1);
1552 vec[2].y = m.Get(4, 2) + m.Get(2, 2);
1553 vec[2].z = m.Get(4, 3) + m.Get(2, 3);
1554 float l3 = vec[2].Length();
1555 vec[2].Normalize();
1556 originPlane[2] = (m.Get(4, 4) + m.Get(2, 4)) / l3;
1557
1558 // Top plane
1559 vec[3].x = m.Get(4, 1) - m.Get(2, 1);
1560 vec[3].y = m.Get(4, 2) - m.Get(2, 2);
1561 vec[3].z = m.Get(4, 3) - m.Get(2, 3);
1562 float l4 = vec[3].Length();
1563 vec[3].Normalize();
1564 originPlane[3] = (m.Get(4, 4) - m.Get(2, 4)) / l4;
1565
1566 // Front plane
1567 vec[4].x = m.Get(4, 1) + m.Get(3, 1);
1568 vec[4].y = m.Get(4, 2) + m.Get(3, 2);
1569 vec[4].z = m.Get(4, 3) + m.Get(3, 3);
1570 float l5 = vec[4].Length();
1571 vec[4].Normalize();
1572 originPlane[4] = (m.Get(4, 4) + m.Get(3, 4)) / l5;
1573
1574 // Back plane
1575 vec[5].x = m.Get(4, 1) - m.Get(3, 1);
1576 vec[5].y = m.Get(4, 2) - m.Get(3, 2);
1577 vec[5].z = m.Get(4, 3) - m.Get(3, 3);
1578 float l6 = vec[5].Length();
1579 vec[5].Normalize();
1580 originPlane[5] = (m.Get(4, 4) - m.Get(3, 4)) / l6;
1581
1582 int result = 0;
1583
1584 if (InPlane(vec[0], originPlane[0], center, radius))
1585 result |= FRUSTUM_PLANE_LEFT;
1586 if (InPlane(vec[1], originPlane[1], center, radius))
1587 result |= FRUSTUM_PLANE_RIGHT;
1588 if (InPlane(vec[2], originPlane[2], center, radius))
1589 result |= FRUSTUM_PLANE_BOTTOM;
1590 if (InPlane(vec[3], originPlane[3], center, radius))
1591 result |= FRUSTUM_PLANE_TOP;
1592 if (InPlane(vec[4], originPlane[4], center, radius))
1593 result |= FRUSTUM_PLANE_FRONT;
1594 if (InPlane(vec[5], originPlane[5], center, radius))
1595 result |= FRUSTUM_PLANE_BACK;
1596
1597 return result;
1598 }
1599
SetViewport(int x,int y,int width,int height)1600 void CGL14Device::SetViewport(int x, int y, int width, int height)
1601 {
1602 glViewport(x, y, width, height);
1603 }
1604
SetRenderState(RenderState state,bool enabled)1605 void CGL14Device::SetRenderState(RenderState state, bool enabled)
1606 {
1607 if (state == RENDER_STATE_DEPTH_WRITE)
1608 {
1609 glDepthMask(enabled ? GL_TRUE : GL_FALSE);
1610 return;
1611 }
1612 else if (state == RENDER_STATE_LIGHTING)
1613 {
1614 m_lighting = enabled;
1615
1616 if (enabled)
1617 glEnable(GL_LIGHTING);
1618 else
1619 glDisable(GL_LIGHTING);
1620
1621 if (enabled)
1622 {
1623 UpdateLightPositions();
1624 }
1625
1626 return;
1627 }
1628 else if (state == RENDER_STATE_SHADOW_MAPPING)
1629 {
1630 if (enabled)
1631 EnableShadows();
1632 else
1633 DisableShadows();
1634
1635 return;
1636 }
1637
1638 GLenum flag = 0;
1639
1640 switch (state)
1641 {
1642 case RENDER_STATE_BLENDING: flag = GL_BLEND; break;
1643 case RENDER_STATE_FOG: flag = GL_FOG; break;
1644 case RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break;
1645 case RENDER_STATE_ALPHA_TEST: flag = GL_ALPHA_TEST; break;
1646 case RENDER_STATE_CULLING: flag = GL_CULL_FACE; break;
1647 case RENDER_STATE_DEPTH_BIAS: flag = GL_POLYGON_OFFSET_FILL; break;
1648 default: assert(false); break;
1649 }
1650
1651 if (enabled)
1652 glEnable(flag);
1653 else
1654 glDisable(flag);
1655 }
1656
SetColorMask(bool red,bool green,bool blue,bool alpha)1657 void CGL14Device::SetColorMask(bool red, bool green, bool blue, bool alpha)
1658 {
1659 glColorMask(red, green, blue, alpha);
1660 }
1661
SetDepthTestFunc(CompFunc func)1662 void CGL14Device::SetDepthTestFunc(CompFunc func)
1663 {
1664 glDepthFunc(TranslateGfxCompFunc(func));
1665 }
1666
SetDepthBias(float factor,float units)1667 void CGL14Device::SetDepthBias(float factor, float units)
1668 {
1669 glPolygonOffset(factor, units);
1670 }
1671
SetAlphaTestFunc(CompFunc func,float refValue)1672 void CGL14Device::SetAlphaTestFunc(CompFunc func, float refValue)
1673 {
1674 glAlphaFunc(TranslateGfxCompFunc(func), refValue);
1675 }
1676
SetBlendFunc(BlendFunc srcBlend,BlendFunc dstBlend)1677 void CGL14Device::SetBlendFunc(BlendFunc srcBlend, BlendFunc dstBlend)
1678 {
1679 glBlendFunc(TranslateGfxBlendFunc(srcBlend), TranslateGfxBlendFunc(dstBlend));
1680 }
1681
SetClearColor(const Color & color)1682 void CGL14Device::SetClearColor(const Color &color)
1683 {
1684 glClearColor(color.r, color.g, color.b, color.a);
1685 }
1686
SetGlobalAmbient(const Color & color)1687 void CGL14Device::SetGlobalAmbient(const Color &color)
1688 {
1689 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.Array());
1690 }
1691
SetFogParams(FogMode mode,const Color & color,float start,float end,float density)1692 void CGL14Device::SetFogParams(FogMode mode, const Color &color, float start, float end, float density)
1693 {
1694 if (mode == FOG_LINEAR) glFogi(GL_FOG_MODE, GL_LINEAR);
1695 else if (mode == FOG_EXP) glFogi(GL_FOG_MODE, GL_EXP);
1696 else if (mode == FOG_EXP2) glFogi(GL_FOG_MODE, GL_EXP2);
1697 else assert(false);
1698
1699 glFogf(GL_FOG_START, start);
1700 glFogf(GL_FOG_END, end);
1701 glFogf(GL_FOG_DENSITY, density);
1702 glFogfv(GL_FOG_COLOR, color.Array());
1703 }
1704
SetCullMode(CullMode mode)1705 void CGL14Device::SetCullMode(CullMode mode)
1706 {
1707 // Cull clockwise back faces, so front face is the opposite
1708 // (assuming GL_CULL_FACE is GL_BACK)
1709 if (mode == CULL_CW ) glFrontFace(GL_CCW);
1710 else if (mode == CULL_CCW) glFrontFace(GL_CW);
1711 else assert(false);
1712 }
1713
SetShadeModel(ShadeModel model)1714 void CGL14Device::SetShadeModel(ShadeModel model)
1715 {
1716 if (model == SHADE_FLAT) glShadeModel(GL_FLAT);
1717 else if (model == SHADE_SMOOTH) glShadeModel(GL_SMOOTH);
1718 else assert(false);
1719 }
1720
SetShadowColor(float value)1721 void CGL14Device::SetShadowColor(float value)
1722 {
1723 // doesn't do anything because it can't
1724 }
1725
SetFillMode(FillMode mode)1726 void CGL14Device::SetFillMode(FillMode mode)
1727 {
1728 if (mode == FILL_POINT) glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
1729 else if (mode == FILL_LINES) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1730 else if (mode == FILL_POLY) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1731 else assert(false);
1732 }
1733
CopyFramebufferToTexture(Texture & texture,int xOffset,int yOffset,int x,int y,int width,int height)1734 void CGL14Device::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
1735 {
1736 if (texture.id == 0) return;
1737
1738 // Use & enable 1st texture stage
1739 glActiveTexture(GL_TEXTURE0 + m_remap[0]);
1740
1741 glBindTexture(GL_TEXTURE_2D, texture.id);
1742 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);
1743
1744 // Restore previous texture
1745 glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
1746 }
1747
GetFrameBufferPixels() const1748 std::unique_ptr<CFrameBufferPixels> CGL14Device::GetFrameBufferPixels() const
1749 {
1750 return GetGLFrameBufferPixels(m_config.size);
1751 }
1752
GetFramebuffer(std::string name)1753 CFramebuffer* CGL14Device::GetFramebuffer(std::string name)
1754 {
1755 auto it = m_framebuffers.find(name);
1756 if (it == m_framebuffers.end())
1757 return nullptr;
1758
1759 return it->second.get();
1760 }
1761
CreateFramebuffer(std::string name,const FramebufferParams & params)1762 CFramebuffer* CGL14Device::CreateFramebuffer(std::string name, const FramebufferParams& params)
1763 {
1764 // existing framebuffer was found
1765 if (m_framebuffers.find(name) != m_framebuffers.end())
1766 {
1767 return nullptr;
1768 }
1769
1770 std::unique_ptr<CFramebuffer> framebuffer;
1771
1772 if (m_framebufferSupport == FBS_ARB)
1773 framebuffer = MakeUnique<CGLFramebuffer>(params);
1774 else if (m_framebufferSupport == FBS_EXT)
1775 framebuffer = MakeUnique<CGLFramebufferEXT>(params);
1776 else
1777 return nullptr;
1778
1779 if (!framebuffer->Create()) return nullptr;
1780
1781 CFramebuffer* framebufferPtr = framebuffer.get();
1782 m_framebuffers[name] = std::move(framebuffer);
1783 return framebufferPtr;
1784 }
1785
DeleteFramebuffer(std::string name)1786 void CGL14Device::DeleteFramebuffer(std::string name)
1787 {
1788 // can't delete default framebuffer
1789 if (name == "default") return;
1790
1791 auto it = m_framebuffers.find(name);
1792 if (it != m_framebuffers.end())
1793 {
1794 it->second->Destroy();
1795 m_framebuffers.erase(it);
1796 }
1797 }
1798
IsAnisotropySupported()1799 bool CGL14Device::IsAnisotropySupported()
1800 {
1801 return m_capabilities.anisotropySupported;
1802 }
1803
GetMaxAnisotropyLevel()1804 int CGL14Device::GetMaxAnisotropyLevel()
1805 {
1806 return m_capabilities.maxAnisotropy;
1807 }
1808
GetMaxSamples()1809 int CGL14Device::GetMaxSamples()
1810 {
1811 return m_capabilities.maxSamples;
1812 }
1813
IsShadowMappingSupported()1814 bool CGL14Device::IsShadowMappingSupported()
1815 {
1816 return m_capabilities.shadowMappingSupported;
1817 }
1818
GetMaxTextureSize()1819 int CGL14Device::GetMaxTextureSize()
1820 {
1821 return m_capabilities.maxTextureSize;
1822 }
1823
IsFramebufferSupported()1824 bool CGL14Device::IsFramebufferSupported()
1825 {
1826 return m_capabilities.framebufferSupported;
1827 }
1828
1829 } // namespace Gfx
1830