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 &params)
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 &params)
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 &params)
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 &params = 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 &center, 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