aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp
diff options
context:
space:
mode:
authorDavid Walter Seikel2013-01-13 17:24:39 +1000
committerDavid Walter Seikel2013-01-13 17:24:39 +1000
commit393b5cd1dc438872af89d334ef6e5fcc59f27d47 (patch)
tree6a14521219942a08a1b95cb2f5a923a9edd60f63 /libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp
parentAdd a note about rasters suggested start up code. (diff)
downloadSledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.zip
SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.gz
SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.bz2
SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.xz
Added Irrlicht 1.8, but without all the Windows binaries.
Diffstat (limited to '')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp4826
1 files changed, 4826 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp b/libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp
new file mode 100644
index 0000000..1caa9c6
--- /dev/null
+++ b/libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp
@@ -0,0 +1,4826 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "COpenGLDriver.h"
6// needed here also because of the create methods' parameters
7#include "CNullDriver.h"
8
9#ifdef _IRR_COMPILE_WITH_OPENGL_
10
11#include "COpenGLTexture.h"
12#include "COpenGLMaterialRenderer.h"
13#include "COpenGLShaderMaterialRenderer.h"
14#include "COpenGLSLMaterialRenderer.h"
15#include "COpenGLCgMaterialRenderer.h"
16#include "COpenGLNormalMapRenderer.h"
17#include "COpenGLParallaxMapRenderer.h"
18#include "os.h"
19
20#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
21#include <SDL/SDL.h>
22#endif
23
24namespace irr
25{
26namespace video
27{
28
29// -----------------------------------------------------------------------
30// WINDOWS CONSTRUCTOR
31// -----------------------------------------------------------------------
32#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
33//! Windows constructor and init code
34COpenGLDriver::COpenGLDriver(const irr::SIrrlichtCreationParameters& params,
35 io::IFileSystem* io, CIrrDeviceWin32* device)
36: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(),
37 CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true),
38 AntiAlias(params.AntiAlias), RenderTargetTexture(0),
39 CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8),
40 CurrentTarget(ERT_FRAME_BUFFER), Params(params),
41 HDc(0), Window(static_cast<HWND>(params.WindowId)), Win32Device(device),
42 DeviceType(EIDT_WIN32)
43{
44 #ifdef _DEBUG
45 setDebugName("COpenGLDriver");
46 #endif
47
48 #ifdef _IRR_COMPILE_WITH_CG_
49 CgContext = 0;
50 #endif
51}
52
53
54bool COpenGLDriver::changeRenderContext(const SExposedVideoData& videoData, CIrrDeviceWin32* device)
55{
56 if (videoData.OpenGLWin32.HWnd && videoData.OpenGLWin32.HDc && videoData.OpenGLWin32.HRc)
57 {
58 if (!wglMakeCurrent((HDC)videoData.OpenGLWin32.HDc, (HGLRC)videoData.OpenGLWin32.HRc))
59 {
60 os::Printer::log("Render Context switch failed.");
61 return false;
62 }
63 else
64 {
65 HDc = (HDC)videoData.OpenGLWin32.HDc;
66 }
67 }
68 // set back to main context
69 else if (HDc != ExposedData.OpenGLWin32.HDc)
70 {
71 if (!wglMakeCurrent((HDC)ExposedData.OpenGLWin32.HDc, (HGLRC)ExposedData.OpenGLWin32.HRc))
72 {
73 os::Printer::log("Render Context switch failed.");
74 return false;
75 }
76 else
77 {
78 HDc = (HDC)ExposedData.OpenGLWin32.HDc;
79 }
80 }
81 return true;
82}
83
84//! inits the open gl driver
85bool COpenGLDriver::initDriver(CIrrDeviceWin32* device)
86{
87 // Create a window to test antialiasing support
88 const fschar_t* ClassName = __TEXT("GLCIrrDeviceWin32");
89 HINSTANCE lhInstance = GetModuleHandle(0);
90
91 // Register Class
92 WNDCLASSEX wcex;
93 wcex.cbSize = sizeof(WNDCLASSEX);
94 wcex.style = CS_HREDRAW | CS_VREDRAW;
95 wcex.lpfnWndProc = (WNDPROC)DefWindowProc;
96 wcex.cbClsExtra = 0;
97 wcex.cbWndExtra = 0;
98 wcex.hInstance = lhInstance;
99 wcex.hIcon = NULL;
100 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
101 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
102 wcex.lpszMenuName = 0;
103 wcex.lpszClassName = ClassName;
104 wcex.hIconSm = 0;
105 wcex.hIcon = 0;
106 RegisterClassEx(&wcex);
107
108 RECT clientSize;
109 clientSize.top = 0;
110 clientSize.left = 0;
111 clientSize.right = Params.WindowSize.Width;
112 clientSize.bottom = Params.WindowSize.Height;
113
114 DWORD style = WS_POPUP;
115 if (!Params.Fullscreen)
116 style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
117
118 AdjustWindowRect(&clientSize, style, FALSE);
119
120 const s32 realWidth = clientSize.right - clientSize.left;
121 const s32 realHeight = clientSize.bottom - clientSize.top;
122
123 const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;
124 const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;
125
126 HWND temporary_wnd=CreateWindow(ClassName, __TEXT(""), style, windowLeft,
127 windowTop, realWidth, realHeight, NULL, NULL, lhInstance, NULL);
128
129 if (!temporary_wnd)
130 {
131 os::Printer::log("Cannot create a temporary window.", ELL_ERROR);
132 UnregisterClass(ClassName, lhInstance);
133 return false;
134 }
135
136 HDc = GetDC(temporary_wnd);
137
138 // Set up pixel format descriptor with desired parameters
139 PIXELFORMATDESCRIPTOR pfd = {
140 sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
141 1, // Version Number
142 PFD_DRAW_TO_WINDOW | // Format Must Support Window
143 PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
144 (Params.Doublebuffer?PFD_DOUBLEBUFFER:0) | // Must Support Double Buffering
145 (Params.Stereobuffer?PFD_STEREO:0), // Must Support Stereo Buffer
146 PFD_TYPE_RGBA, // Request An RGBA Format
147 Params.Bits, // Select Our Color Depth
148 0, 0, 0, 0, 0, 0, // Color Bits Ignored
149 0, // No Alpha Buffer
150 0, // Shift Bit Ignored
151 0, // No Accumulation Buffer
152 0, 0, 0, 0, // Accumulation Bits Ignored
153 Params.ZBufferBits, // Z-Buffer (Depth Buffer)
154 BYTE(Params.Stencilbuffer ? 1 : 0), // Stencil Buffer Depth
155 0, // No Auxiliary Buffer
156 PFD_MAIN_PLANE, // Main Drawing Layer
157 0, // Reserved
158 0, 0, 0 // Layer Masks Ignored
159 };
160
161 GLuint PixelFormat;
162
163 for (u32 i=0; i<6; ++i)
164 {
165 if (i == 1)
166 {
167 if (Params.Stencilbuffer)
168 {
169 os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING);
170 Params.Stencilbuffer = false;
171 pfd.cStencilBits = 0;
172 }
173 else
174 continue;
175 }
176 else
177 if (i == 2)
178 {
179 pfd.cDepthBits = 24;
180 }
181 else
182 if (i == 3)
183 {
184 if (Params.Bits!=16)
185 pfd.cDepthBits = 16;
186 else
187 continue;
188 }
189 else
190 if (i == 4)
191 {
192 // try single buffer
193 if (Params.Doublebuffer)
194 pfd.dwFlags &= ~PFD_DOUBLEBUFFER;
195 else
196 continue;
197 }
198 else
199 if (i == 5)
200 {
201 os::Printer::log("Cannot create a GL device context", "No suitable format for temporary window.", ELL_ERROR);
202 ReleaseDC(temporary_wnd, HDc);
203 DestroyWindow(temporary_wnd);
204 UnregisterClass(ClassName, lhInstance);
205 return false;
206 }
207
208 // choose pixelformat
209 PixelFormat = ChoosePixelFormat(HDc, &pfd);
210 if (PixelFormat)
211 break;
212 }
213
214 SetPixelFormat(HDc, PixelFormat, &pfd);
215 HGLRC hrc=wglCreateContext(HDc);
216 if (!hrc)
217 {
218 os::Printer::log("Cannot create a temporary GL rendering context.", ELL_ERROR);
219 ReleaseDC(temporary_wnd, HDc);
220 DestroyWindow(temporary_wnd);
221 UnregisterClass(ClassName, lhInstance);
222 return false;
223 }
224
225 SExposedVideoData data;
226 data.OpenGLWin32.HDc = HDc;
227 data.OpenGLWin32.HRc = hrc;
228 data.OpenGLWin32.HWnd = temporary_wnd;
229
230
231 if (!changeRenderContext(data, device))
232 {
233 os::Printer::log("Cannot activate a temporary GL rendering context.", ELL_ERROR);
234 wglDeleteContext(hrc);
235 ReleaseDC(temporary_wnd, HDc);
236 DestroyWindow(temporary_wnd);
237 UnregisterClass(ClassName, lhInstance);
238 return false;
239 }
240
241 core::stringc wglExtensions;
242#ifdef WGL_ARB_extensions_string
243 PFNWGLGETEXTENSIONSSTRINGARBPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
244 if (irrGetExtensionsString)
245 wglExtensions = irrGetExtensionsString(HDc);
246#elif defined(WGL_EXT_extensions_string)
247 PFNWGLGETEXTENSIONSSTRINGEXTPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");
248 if (irrGetExtensionsString)
249 wglExtensions = irrGetExtensionsString(HDc);
250#endif
251 const bool pixel_format_supported = (wglExtensions.find("WGL_ARB_pixel_format") != -1);
252 const bool multi_sample_supported = ((wglExtensions.find("WGL_ARB_multisample") != -1) ||
253 (wglExtensions.find("WGL_EXT_multisample") != -1) || (wglExtensions.find("WGL_3DFX_multisample") != -1) );
254#ifdef _DEBUG
255 os::Printer::log("WGL_extensions", wglExtensions);
256#endif
257
258#ifdef WGL_ARB_pixel_format
259 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat_ARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
260 if (pixel_format_supported && wglChoosePixelFormat_ARB)
261 {
262 // This value determines the number of samples used for antialiasing
263 // My experience is that 8 does not show a big
264 // improvement over 4, but 4 shows a big improvement
265 // over 2.
266
267 if(AntiAlias > 32)
268 AntiAlias = 32;
269
270 f32 fAttributes[] = {0.0, 0.0};
271 s32 iAttributes[] =
272 {
273 WGL_DRAW_TO_WINDOW_ARB,1,
274 WGL_SUPPORT_OPENGL_ARB,1,
275 WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
276 WGL_COLOR_BITS_ARB,(Params.Bits==32) ? 24 : 15,
277 WGL_ALPHA_BITS_ARB,(Params.Bits==32) ? 8 : 1,
278 WGL_DEPTH_BITS_ARB,Params.ZBufferBits, // 10,11
279 WGL_STENCIL_BITS_ARB,Params.Stencilbuffer ? 1 : 0,
280 WGL_DOUBLE_BUFFER_ARB,Params.Doublebuffer ? 1 : 0,
281 WGL_STEREO_ARB,Params.Stereobuffer ? 1 : 0,
282 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
283#ifdef WGL_ARB_multisample
284 WGL_SAMPLES_ARB,AntiAlias, // 20,21
285 WGL_SAMPLE_BUFFERS_ARB, 1,
286#elif defined(WGL_EXT_multisample)
287 WGL_SAMPLES_EXT,AntiAlias, // 20,21
288 WGL_SAMPLE_BUFFERS_EXT, 1,
289#elif defined(WGL_3DFX_multisample)
290 WGL_SAMPLES_3DFX,AntiAlias, // 20,21
291 WGL_SAMPLE_BUFFERS_3DFX, 1,
292#endif
293#ifdef WGL_ARB_framebuffer_sRGB
294 WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, Params.HandleSRGB ? 1:0,
295#elif defined(WGL_EXT_framebuffer_sRGB)
296 WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT, Params.HandleSRGB ? 1:0,
297#endif
298// WGL_DEPTH_FLOAT_EXT, 1,
299 0,0,0,0
300 };
301 int iAttrSize = sizeof(iAttributes)/sizeof(int);
302 const bool framebuffer_srgb_supported = ((wglExtensions.find("WGL_ARB_framebuffer_sRGB") != -1) ||
303 (wglExtensions.find("WGL_EXT_framebuffer_sRGB") != -1));
304 if (!framebuffer_srgb_supported)
305 {
306 memmove(&iAttributes[24],&iAttributes[26],sizeof(int)*(iAttrSize-26));
307 iAttrSize -= 2;
308 }
309 if (!multi_sample_supported)
310 {
311 memmove(&iAttributes[20],&iAttributes[24],sizeof(int)*(iAttrSize-24));
312 iAttrSize -= 4;
313 }
314
315 s32 rv=0;
316 // Try to get an acceptable pixel format
317 do
318 {
319 int pixelFormat=0;
320 UINT numFormats=0;
321 const BOOL valid = wglChoosePixelFormat_ARB(HDc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
322
323 if (valid && numFormats)
324 rv = pixelFormat;
325 else
326 iAttributes[21] -= 1;
327 }
328 while(rv==0 && iAttributes[21]>1);
329 if (rv)
330 {
331 PixelFormat=rv;
332 AntiAlias=iAttributes[21];
333 }
334 }
335 else
336#endif
337 AntiAlias=0;
338
339 wglMakeCurrent(HDc, NULL);
340 wglDeleteContext(hrc);
341 ReleaseDC(temporary_wnd, HDc);
342 DestroyWindow(temporary_wnd);
343 UnregisterClass(ClassName, lhInstance);
344
345 // get hdc
346 HDc=GetDC(Window);
347 if (!HDc)
348 {
349 os::Printer::log("Cannot create a GL device context.", ELL_ERROR);
350 return false;
351 }
352
353 // search for pixel format the simple way
354 if (PixelFormat==0 || (!SetPixelFormat(HDc, PixelFormat, &pfd)))
355 {
356 for (u32 i=0; i<5; ++i)
357 {
358 if (i == 1)
359 {
360 if (Params.Stencilbuffer)
361 {
362 os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING);
363 Params.Stencilbuffer = false;
364 pfd.cStencilBits = 0;
365 }
366 else
367 continue;
368 }
369 else
370 if (i == 2)
371 {
372 pfd.cDepthBits = 24;
373 }
374 if (i == 3)
375 {
376 if (Params.Bits!=16)
377 pfd.cDepthBits = 16;
378 else
379 continue;
380 }
381 else
382 if (i == 4)
383 {
384 os::Printer::log("Cannot create a GL device context", "No suitable format.", ELL_ERROR);
385 return false;
386 }
387
388 // choose pixelformat
389 PixelFormat = ChoosePixelFormat(HDc, &pfd);
390 if (PixelFormat)
391 break;
392 }
393 }
394
395 // set pixel format
396 if (!SetPixelFormat(HDc, PixelFormat, &pfd))
397 {
398 os::Printer::log("Cannot set the pixel format.", ELL_ERROR);
399 return false;
400 }
401 os::Printer::log("Pixel Format", core::stringc(PixelFormat).c_str(), ELL_DEBUG);
402
403 // create rendering context
404#ifdef WGL_ARB_create_context
405 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs_ARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
406 if (wglCreateContextAttribs_ARB)
407 {
408 int iAttribs[] =
409 {
410 WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
411 WGL_CONTEXT_MINOR_VERSION_ARB, 1,
412 0
413 };
414 hrc=wglCreateContextAttribs_ARB(HDc, 0, iAttribs);
415 }
416 else
417#endif
418 hrc=wglCreateContext(HDc);
419
420 if (!hrc)
421 {
422 os::Printer::log("Cannot create a GL rendering context.", ELL_ERROR);
423 return false;
424 }
425
426 // set exposed data
427 ExposedData.OpenGLWin32.HDc = HDc;
428 ExposedData.OpenGLWin32.HRc = hrc;
429 ExposedData.OpenGLWin32.HWnd = Window;
430
431 // activate rendering context
432
433 if (!changeRenderContext(ExposedData, device))
434 {
435 os::Printer::log("Cannot activate GL rendering context", ELL_ERROR);
436 wglDeleteContext(hrc);
437 return false;
438 }
439
440 int pf = GetPixelFormat(HDc);
441 DescribePixelFormat(HDc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
442 if (pfd.cAlphaBits != 0)
443 {
444 if (pfd.cRedBits == 8)
445 ColorFormat = ECF_A8R8G8B8;
446 else
447 ColorFormat = ECF_A1R5G5B5;
448 }
449 else
450 {
451 if (pfd.cRedBits == 8)
452 ColorFormat = ECF_R8G8B8;
453 else
454 ColorFormat = ECF_R5G6B5;
455 }
456
457 genericDriverInit();
458
459 extGlSwapInterval(Params.Vsync ? 1 : 0);
460 return true;
461}
462
463#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_
464
465// -----------------------------------------------------------------------
466// MacOSX CONSTRUCTOR
467// -----------------------------------------------------------------------
468#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_
469//! Windows constructor and init code
470COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params,
471 io::IFileSystem* io, CIrrDeviceMacOSX *device)
472: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(),
473 CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true),
474 AntiAlias(params.AntiAlias), RenderTargetTexture(0),
475 CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8),
476 CurrentTarget(ERT_FRAME_BUFFER), Params(params),
477 OSXDevice(device), DeviceType(EIDT_OSX)
478{
479 #ifdef _DEBUG
480 setDebugName("COpenGLDriver");
481 #endif
482
483 #ifdef _IRR_COMPILE_WITH_CG_
484 CgContext = 0;
485 #endif
486
487 genericDriverInit();
488}
489
490#endif
491
492// -----------------------------------------------------------------------
493// LINUX CONSTRUCTOR
494// -----------------------------------------------------------------------
495#ifdef _IRR_COMPILE_WITH_X11_DEVICE_
496//! Linux constructor and init code
497COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params,
498 io::IFileSystem* io, CIrrDeviceLinux* device)
499: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(),
500 CurrentRenderMode(ERM_NONE), ResetRenderStates(true),
501 Transformation3DChanged(true), AntiAlias(params.AntiAlias),
502 RenderTargetTexture(0), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8),
503 CurrentTarget(ERT_FRAME_BUFFER), Params(params),
504 X11Device(device), DeviceType(EIDT_X11)
505{
506 #ifdef _DEBUG
507 setDebugName("COpenGLDriver");
508 #endif
509
510 #ifdef _IRR_COMPILE_WITH_CG_
511 CgContext = 0;
512 #endif
513}
514
515
516bool COpenGLDriver::changeRenderContext(const SExposedVideoData& videoData, CIrrDeviceLinux* device)
517{
518 if (videoData.OpenGLLinux.X11Window)
519 {
520 if (videoData.OpenGLLinux.X11Display && videoData.OpenGLLinux.X11Context)
521 {
522 if (!glXMakeCurrent((Display*)videoData.OpenGLLinux.X11Display, videoData.OpenGLLinux.X11Window, (GLXContext)videoData.OpenGLLinux.X11Context))
523 {
524 os::Printer::log("Render Context switch failed.");
525 return false;
526 }
527 else
528 {
529 Drawable = videoData.OpenGLLinux.X11Window;
530 X11Display = (Display*)videoData.OpenGLLinux.X11Display;
531 }
532 }
533 else
534 {
535 // in case we only got a window ID, try with the existing values for display and context
536 if (!glXMakeCurrent((Display*)ExposedData.OpenGLLinux.X11Display, videoData.OpenGLLinux.X11Window, (GLXContext)ExposedData.OpenGLLinux.X11Context))
537 {
538 os::Printer::log("Render Context switch failed.");
539 return false;
540 }
541 else
542 {
543 Drawable = videoData.OpenGLLinux.X11Window;
544 X11Display = (Display*)ExposedData.OpenGLLinux.X11Display;
545 }
546 }
547 }
548 // set back to main context
549 else if (X11Display != ExposedData.OpenGLLinux.X11Display)
550 {
551 if (!glXMakeCurrent((Display*)ExposedData.OpenGLLinux.X11Display, ExposedData.OpenGLLinux.X11Window, (GLXContext)ExposedData.OpenGLLinux.X11Context))
552 {
553 os::Printer::log("Render Context switch failed.");
554 return false;
555 }
556 else
557 {
558 Drawable = ExposedData.OpenGLLinux.X11Window;
559 X11Display = (Display*)ExposedData.OpenGLLinux.X11Display;
560 }
561 }
562 return true;
563}
564
565
566//! inits the open gl driver
567bool COpenGLDriver::initDriver(CIrrDeviceLinux* device)
568{
569 ExposedData.OpenGLLinux.X11Context = glXGetCurrentContext();
570 ExposedData.OpenGLLinux.X11Display = glXGetCurrentDisplay();
571 ExposedData.OpenGLLinux.X11Window = (unsigned long)Params.WindowId;
572 Drawable = glXGetCurrentDrawable();
573 X11Display = (Display*)ExposedData.OpenGLLinux.X11Display;
574
575 genericDriverInit();
576
577 // set vsync
578 extGlSwapInterval(Params.Vsync ? 1 : 0);
579 return true;
580}
581
582#endif // _IRR_COMPILE_WITH_X11_DEVICE_
583
584
585// -----------------------------------------------------------------------
586// SDL CONSTRUCTOR
587// -----------------------------------------------------------------------
588#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
589//! SDL constructor and init code
590COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params,
591 io::IFileSystem* io, CIrrDeviceSDL* device)
592: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(),
593 CurrentRenderMode(ERM_NONE), ResetRenderStates(true),
594 Transformation3DChanged(true), AntiAlias(params.AntiAlias),
595 RenderTargetTexture(0), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8),
596 CurrentTarget(ERT_FRAME_BUFFER), Params(params),
597 SDLDevice(device), DeviceType(EIDT_SDL)
598{
599 #ifdef _DEBUG
600 setDebugName("COpenGLDriver");
601 #endif
602
603 #ifdef _IRR_COMPILE_WITH_CG_
604 CgContext = 0;
605 #endif
606
607 genericDriverInit();
608}
609
610#endif // _IRR_COMPILE_WITH_SDL_DEVICE_
611
612
613//! destructor
614COpenGLDriver::~COpenGLDriver()
615{
616 #ifdef _IRR_COMPILE_WITH_CG_
617 if (CgContext)
618 cgDestroyContext(CgContext);
619 #endif
620
621 RequestedLights.clear();
622
623 deleteMaterialRenders();
624
625 CurrentTexture.clear();
626 // I get a blue screen on my laptop, when I do not delete the
627 // textures manually before releasing the dc. Oh how I love this.
628 deleteAllTextures();
629 removeAllOcclusionQueries();
630 removeAllHardwareBuffers();
631
632#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
633 if (DeviceType == EIDT_WIN32)
634 {
635
636 if (ExposedData.OpenGLWin32.HRc)
637 {
638 if (!wglMakeCurrent(HDc, 0))
639 os::Printer::log("Release of dc and rc failed.", ELL_WARNING);
640
641 if (!wglDeleteContext((HGLRC)ExposedData.OpenGLWin32.HRc))
642 os::Printer::log("Release of rendering context failed.", ELL_WARNING);
643 }
644
645 if (HDc)
646 ReleaseDC(Window, HDc);
647 }
648#endif
649}
650
651// -----------------------------------------------------------------------
652// METHODS
653// -----------------------------------------------------------------------
654
655bool COpenGLDriver::genericDriverInit()
656{
657 Name=L"OpenGL ";
658 Name.append(glGetString(GL_VERSION));
659 s32 pos=Name.findNext(L' ', 7);
660 if (pos != -1)
661 Name=Name.subString(0, pos);
662 printVersion();
663
664 // print renderer information
665 const GLubyte* renderer = glGetString(GL_RENDERER);
666 const GLubyte* vendor = glGetString(GL_VENDOR);
667 if (renderer && vendor)
668 {
669 os::Printer::log(reinterpret_cast<const c8*>(renderer), reinterpret_cast<const c8*>(vendor), ELL_INFORMATION);
670 VendorName = reinterpret_cast<const c8*>(vendor);
671 }
672
673 u32 i;
674 CurrentTexture.clear();
675 // load extensions
676 initExtensions(Params.Stencilbuffer);
677 if (queryFeature(EVDF_ARB_GLSL))
678 {
679 char buf[32];
680 const u32 maj = ShaderLanguageVersion/100;
681 snprintf(buf, 32, "%u.%u", maj, ShaderLanguageVersion-maj*100);
682 os::Printer::log("GLSL version", buf, ELL_INFORMATION);
683 }
684 else
685 os::Printer::log("GLSL not available.", ELL_INFORMATION);
686 DriverAttributes->setAttribute("MaxTextures", MaxTextureUnits);
687 DriverAttributes->setAttribute("MaxSupportedTextures", MaxSupportedTextures);
688 DriverAttributes->setAttribute("MaxLights", MaxLights);
689 DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy);
690 DriverAttributes->setAttribute("MaxUserClipPlanes", MaxUserClipPlanes);
691 DriverAttributes->setAttribute("MaxAuxBuffers", MaxAuxBuffers);
692 DriverAttributes->setAttribute("MaxMultipleRenderTargets", MaxMultipleRenderTargets);
693 DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices);
694 DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize);
695 DriverAttributes->setAttribute("MaxGeometryVerticesOut", (s32)MaxGeometryVerticesOut);
696 DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias);
697 DriverAttributes->setAttribute("Version", Version);
698 DriverAttributes->setAttribute("ShaderLanguageVersion", ShaderLanguageVersion);
699 DriverAttributes->setAttribute("AntiAlias", AntiAlias);
700
701 glPixelStorei(GL_PACK_ALIGNMENT, 1);
702
703 // Reset The Current Viewport
704 glViewport(0, 0, Params.WindowSize.Width, Params.WindowSize.Height);
705
706 UserClipPlanes.reallocate(MaxUserClipPlanes);
707 for (i=0; i<MaxUserClipPlanes; ++i)
708 UserClipPlanes.push_back(SUserClipPlane());
709
710 for (i=0; i<ETS_COUNT; ++i)
711 setTransform(static_cast<E_TRANSFORMATION_STATE>(i), core::IdentityMatrix);
712
713 setAmbientLight(SColorf(0.0f,0.0f,0.0f,0.0f));
714#ifdef GL_EXT_separate_specular_color
715 if (FeatureAvailable[IRR_EXT_separate_specular_color])
716 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
717#endif
718 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
719
720 Params.HandleSRGB &= ((FeatureAvailable[IRR_ARB_framebuffer_sRGB] || FeatureAvailable[IRR_EXT_framebuffer_sRGB]) &&
721 FeatureAvailable[IRR_EXT_texture_sRGB]);
722#if defined(GL_ARB_framebuffer_sRGB)
723 if (Params.HandleSRGB)
724 glEnable(GL_FRAMEBUFFER_SRGB);
725#elif defined(GL_EXT_framebuffer_sRGB)
726 if (Params.HandleSRGB)
727 glEnable(GL_FRAMEBUFFER_SRGB_EXT);
728#endif
729
730// This is a fast replacement for NORMALIZE_NORMALS
731// if ((Version>101) || FeatureAvailable[IRR_EXT_rescale_normal])
732// glEnable(GL_RESCALE_NORMAL_EXT);
733
734 glClearDepth(1.0);
735 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
736 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
737 glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
738 glDepthFunc(GL_LEQUAL);
739 glFrontFace(GL_CW);
740 // adjust flat coloring scheme to DirectX version
741#if defined(GL_ARB_provoking_vertex) || defined(GL_EXT_provoking_vertex)
742 extGlProvokingVertex(GL_FIRST_VERTEX_CONVENTION_EXT);
743#endif
744
745 // create material renderers
746 createMaterialRenderers();
747
748 // set the renderstates
749 setRenderStates3DMode();
750
751 glAlphaFunc(GL_GREATER, 0.f);
752
753 // set fog mode
754 setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog);
755
756 // create matrix for flipping textures
757 TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0,0), core::vector2df(0,1.0f), core::vector2df(1.0f,-1.0f));
758
759 // We need to reset once more at the beginning of the first rendering.
760 // This fixes problems with intermediate changes to the material during texture load.
761 ResetRenderStates = true;
762
763 #ifdef _IRR_COMPILE_WITH_CG_
764 CgContext = cgCreateContext();
765 #endif
766
767 return true;
768}
769
770
771void COpenGLDriver::createMaterialRenderers()
772{
773 // create OpenGL material renderers
774
775 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID(this));
776 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID_2_LAYER(this));
777
778 // add the same renderer for all lightmap types
779 COpenGLMaterialRenderer_LIGHTMAP* lmr = new COpenGLMaterialRenderer_LIGHTMAP(this);
780 addMaterialRenderer(lmr); // for EMT_LIGHTMAP:
781 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD:
782 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2:
783 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4:
784 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING:
785 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2:
786 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4:
787 lmr->drop();
788
789 // add remaining material renderer
790 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_DETAIL_MAP(this));
791 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SPHERE_MAP(this));
792 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_REFLECTION_2_LAYER(this));
793 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR(this));
794 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(this));
795 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(this));
796 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA(this));
797 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(this));
798
799 // add normal map renderers
800 s32 tmp = 0;
801 video::IMaterialRenderer* renderer = 0;
802 renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_SOLID].Renderer);
803 renderer->drop();
804 renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer);
805 renderer->drop();
806 renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer);
807 renderer->drop();
808
809 // add parallax map renderers
810 renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_SOLID].Renderer);
811 renderer->drop();
812 renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer);
813 renderer->drop();
814 renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer);
815 renderer->drop();
816
817 // add basic 1 texture blending
818 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_ONETEXTURE_BLEND(this));
819}
820
821
822//! presents the rendered scene on the screen, returns false if failed
823bool COpenGLDriver::endScene()
824{
825 CNullDriver::endScene();
826
827 glFlush();
828
829#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
830 if (DeviceType == EIDT_WIN32)
831 return SwapBuffers(HDc) == TRUE;
832#endif
833
834#ifdef _IRR_COMPILE_WITH_X11_DEVICE_
835 if (DeviceType == EIDT_X11)
836 {
837 glXSwapBuffers(X11Display, Drawable);
838 return true;
839 }
840#endif
841
842#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_
843 if (DeviceType == EIDT_OSX)
844 {
845 OSXDevice->flush();
846 return true;
847 }
848#endif
849
850#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
851 if (DeviceType == EIDT_SDL)
852 {
853 SDL_GL_SwapBuffers();
854 return true;
855 }
856#endif
857
858 // todo: console device present
859
860 return false;
861}
862
863
864//! clears the zbuffer and color buffer
865void COpenGLDriver::clearBuffers(bool backBuffer, bool zBuffer, bool stencilBuffer, SColor color)
866{
867 GLbitfield mask = 0;
868 if (backBuffer)
869 {
870 const f32 inv = 1.0f / 255.0f;
871 glClearColor(color.getRed() * inv, color.getGreen() * inv,
872 color.getBlue() * inv, color.getAlpha() * inv);
873
874 mask |= GL_COLOR_BUFFER_BIT;
875 }
876
877 if (zBuffer)
878 {
879 glDepthMask(GL_TRUE);
880 LastMaterial.ZWriteEnable=true;
881 mask |= GL_DEPTH_BUFFER_BIT;
882 }
883
884 if (stencilBuffer)
885 mask |= GL_STENCIL_BUFFER_BIT;
886
887 if (mask)
888 glClear(mask);
889}
890
891
892//! init call for rendering start
893bool COpenGLDriver::beginScene(bool backBuffer, bool zBuffer, SColor color,
894 const SExposedVideoData& videoData, core::rect<s32>* sourceRect)
895{
896 CNullDriver::beginScene(backBuffer, zBuffer, color, videoData, sourceRect);
897
898 switch (DeviceType)
899 {
900#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
901 case EIDT_WIN32:
902 changeRenderContext(videoData, Win32Device);
903 break;
904#endif
905#ifdef _IRR_COMPILE_WITH_X11_DEVICE_
906 case EIDT_X11:
907 changeRenderContext(videoData, X11Device);
908 break;
909#endif
910 default:
911 changeRenderContext(videoData, (void*)0);
912 break;
913 }
914
915#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
916 if (DeviceType == EIDT_SDL)
917 {
918 // todo: SDL sets glFrontFace(GL_CCW) after driver creation,
919 // it would be better if this was fixed elsewhere.
920 glFrontFace(GL_CW);
921 }
922#endif
923
924 clearBuffers(backBuffer, zBuffer, false, color);
925 return true;
926}
927
928
929//! Returns the transformation set by setTransform
930const core::matrix4& COpenGLDriver::getTransform(E_TRANSFORMATION_STATE state) const
931{
932 return Matrices[state];
933}
934
935
936//! sets transformation
937void COpenGLDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)
938{
939 Matrices[state] = mat;
940 Transformation3DChanged = true;
941
942 switch (state)
943 {
944 case ETS_VIEW:
945 case ETS_WORLD:
946 {
947 // OpenGL only has a model matrix, view and world is not existent. so lets fake these two.
948 glMatrixMode(GL_MODELVIEW);
949
950 // first load the viewing transformation for user clip planes
951 glLoadMatrixf((Matrices[ETS_VIEW]).pointer());
952
953 // we have to update the clip planes to the latest view matrix
954 for (u32 i=0; i<MaxUserClipPlanes; ++i)
955 if (UserClipPlanes[i].Enabled)
956 uploadClipPlane(i);
957
958 // now the real model-view matrix
959 glMultMatrixf(Matrices[ETS_WORLD].pointer());
960 }
961 break;
962 case ETS_PROJECTION:
963 {
964 glMatrixMode(GL_PROJECTION);
965 glLoadMatrixf(mat.pointer());
966 }
967 break;
968 case ETS_COUNT:
969 return;
970 default:
971 {
972 const u32 i = state - ETS_TEXTURE_0;
973 if (i >= MATERIAL_MAX_TEXTURES)
974 break;
975
976 const bool isRTT = Material.getTexture(i) && Material.getTexture(i)->isRenderTarget();
977
978 if (MultiTextureExtension)
979 extGlActiveTexture(GL_TEXTURE0_ARB + i);
980
981 glMatrixMode(GL_TEXTURE);
982 if (!isRTT && mat.isIdentity() )
983 glLoadIdentity();
984 else
985 {
986 GLfloat glmat[16];
987 if (isRTT)
988 getGLTextureMatrix(glmat, mat * TextureFlipMatrix);
989 else
990 getGLTextureMatrix(glmat, mat);
991 glLoadMatrixf(glmat);
992 }
993 break;
994 }
995 }
996}
997
998
999bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
1000{
1001 if (!HWBuffer)
1002 return false;
1003
1004 if (!FeatureAvailable[IRR_ARB_vertex_buffer_object])
1005 return false;
1006
1007#if defined(GL_ARB_vertex_buffer_object)
1008 const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
1009 const void* vertices=mb->getVertices();
1010 const u32 vertexCount=mb->getVertexCount();
1011 const E_VERTEX_TYPE vType=mb->getVertexType();
1012 const u32 vertexSize = getVertexPitchFromType(vType);
1013
1014 const c8* vbuf = static_cast<const c8*>(vertices);
1015 core::array<c8> buffer;
1016 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
1017 {
1018 //buffer vertex data, and convert colors...
1019 buffer.set_used(vertexSize * vertexCount);
1020 memcpy(buffer.pointer(), vertices, vertexSize * vertexCount);
1021 vbuf = buffer.const_pointer();
1022
1023 // in order to convert the colors into opengl format (RGBA)
1024 switch (vType)
1025 {
1026 case EVT_STANDARD:
1027 {
1028 S3DVertex* pb = reinterpret_cast<S3DVertex*>(buffer.pointer());
1029 const S3DVertex* po = static_cast<const S3DVertex*>(vertices);
1030 for (u32 i=0; i<vertexCount; i++)
1031 {
1032 po[i].Color.toOpenGLColor((u8*)&(pb[i].Color));
1033 }
1034 }
1035 break;
1036 case EVT_2TCOORDS:
1037 {
1038 S3DVertex2TCoords* pb = reinterpret_cast<S3DVertex2TCoords*>(buffer.pointer());
1039 const S3DVertex2TCoords* po = static_cast<const S3DVertex2TCoords*>(vertices);
1040 for (u32 i=0; i<vertexCount; i++)
1041 {
1042 po[i].Color.toOpenGLColor((u8*)&(pb[i].Color));
1043 }
1044 }
1045 break;
1046 case EVT_TANGENTS:
1047 {
1048 S3DVertexTangents* pb = reinterpret_cast<S3DVertexTangents*>(buffer.pointer());
1049 const S3DVertexTangents* po = static_cast<const S3DVertexTangents*>(vertices);
1050 for (u32 i=0; i<vertexCount; i++)
1051 {
1052 po[i].Color.toOpenGLColor((u8*)&(pb[i].Color));
1053 }
1054 }
1055 break;
1056 default:
1057 {
1058 return false;
1059 }
1060 }
1061 }
1062
1063 //get or create buffer
1064 bool newBuffer=false;
1065 if (!HWBuffer->vbo_verticesID)
1066 {
1067 extGlGenBuffers(1, &HWBuffer->vbo_verticesID);
1068 if (!HWBuffer->vbo_verticesID)
1069 return false;
1070 newBuffer=true;
1071 }
1072 else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize)
1073 {
1074 newBuffer=true;
1075 }
1076
1077 extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID);
1078
1079 //copy data to graphics card
1080 glGetError(); // clear error storage
1081 if (!newBuffer)
1082 extGlBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, vbuf);
1083 else
1084 {
1085 HWBuffer->vbo_verticesSize = vertexCount*vertexSize;
1086
1087 if (HWBuffer->Mapped_Vertex==scene::EHM_STATIC)
1088 extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STATIC_DRAW);
1089 else if (HWBuffer->Mapped_Vertex==scene::EHM_DYNAMIC)
1090 extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_DYNAMIC_DRAW);
1091 else //scene::EHM_STREAM
1092 extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STREAM_DRAW);
1093 }
1094
1095 extGlBindBuffer(GL_ARRAY_BUFFER, 0);
1096
1097 return (glGetError() == GL_NO_ERROR);
1098#else
1099 return false;
1100#endif
1101}
1102
1103
1104bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
1105{
1106 if (!HWBuffer)
1107 return false;
1108
1109 if (!FeatureAvailable[IRR_ARB_vertex_buffer_object])
1110 return false;
1111
1112#if defined(GL_ARB_vertex_buffer_object)
1113 const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
1114
1115 const void* indices=mb->getIndices();
1116 u32 indexCount= mb->getIndexCount();
1117
1118 GLenum indexSize;
1119 switch (mb->getIndexType())
1120 {
1121 case EIT_16BIT:
1122 {
1123 indexSize=sizeof(u16);
1124 break;
1125 }
1126 case EIT_32BIT:
1127 {
1128 indexSize=sizeof(u32);
1129 break;
1130 }
1131 default:
1132 {
1133 return false;
1134 }
1135 }
1136
1137
1138 //get or create buffer
1139 bool newBuffer=false;
1140 if (!HWBuffer->vbo_indicesID)
1141 {
1142 extGlGenBuffers(1, &HWBuffer->vbo_indicesID);
1143 if (!HWBuffer->vbo_indicesID)
1144 return false;
1145 newBuffer=true;
1146 }
1147 else if (HWBuffer->vbo_indicesSize < indexCount*indexSize)
1148 {
1149 newBuffer=true;
1150 }
1151
1152 extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);
1153
1154 //copy data to graphics card
1155 glGetError(); // clear error storage
1156 if (!newBuffer)
1157 extGlBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices);
1158 else
1159 {
1160 HWBuffer->vbo_indicesSize = indexCount*indexSize;
1161
1162 if (HWBuffer->Mapped_Index==scene::EHM_STATIC)
1163 extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW);
1164 else if (HWBuffer->Mapped_Index==scene::EHM_DYNAMIC)
1165 extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW);
1166 else //scene::EHM_STREAM
1167 extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STREAM_DRAW);
1168 }
1169
1170 extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1171
1172 return (glGetError() == GL_NO_ERROR);
1173#else
1174 return false;
1175#endif
1176}
1177
1178
1179//! updates hardware buffer if needed
1180bool COpenGLDriver::updateHardwareBuffer(SHWBufferLink *HWBuffer)
1181{
1182 if (!HWBuffer)
1183 return false;
1184
1185 if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)
1186 {
1187 if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex()
1188 || !((SHWBufferLink_opengl*)HWBuffer)->vbo_verticesID)
1189 {
1190
1191 HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex();
1192
1193 if (!updateVertexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer))
1194 return false;
1195 }
1196 }
1197
1198 if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)
1199 {
1200 if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index()
1201 || !((SHWBufferLink_opengl*)HWBuffer)->vbo_indicesID)
1202 {
1203
1204 HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index();
1205
1206 if (!updateIndexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer))
1207 return false;
1208 }
1209 }
1210
1211 return true;
1212}
1213
1214
1215//! Create hardware buffer from meshbuffer
1216COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::IMeshBuffer* mb)
1217{
1218#if defined(GL_ARB_vertex_buffer_object)
1219 if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))
1220 return 0;
1221
1222 SHWBufferLink_opengl *HWBuffer=new SHWBufferLink_opengl(mb);
1223
1224 //add to map
1225 HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer);
1226
1227 HWBuffer->ChangedID_Vertex=HWBuffer->MeshBuffer->getChangedID_Vertex();
1228 HWBuffer->ChangedID_Index=HWBuffer->MeshBuffer->getChangedID_Index();
1229 HWBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex();
1230 HWBuffer->Mapped_Index=mb->getHardwareMappingHint_Index();
1231 HWBuffer->LastUsed=0;
1232 HWBuffer->vbo_verticesID=0;
1233 HWBuffer->vbo_indicesID=0;
1234 HWBuffer->vbo_verticesSize=0;
1235 HWBuffer->vbo_indicesSize=0;
1236
1237 if (!updateHardwareBuffer(HWBuffer))
1238 {
1239 deleteHardwareBuffer(HWBuffer);
1240 return 0;
1241 }
1242
1243 return HWBuffer;
1244#else
1245 return 0;
1246#endif
1247}
1248
1249
1250void COpenGLDriver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer)
1251{
1252 if (!_HWBuffer)
1253 return;
1254
1255#if defined(GL_ARB_vertex_buffer_object)
1256 SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer;
1257 if (HWBuffer->vbo_verticesID)
1258 {
1259 extGlDeleteBuffers(1, &HWBuffer->vbo_verticesID);
1260 HWBuffer->vbo_verticesID=0;
1261 }
1262 if (HWBuffer->vbo_indicesID)
1263 {
1264 extGlDeleteBuffers(1, &HWBuffer->vbo_indicesID);
1265 HWBuffer->vbo_indicesID=0;
1266 }
1267#endif
1268
1269 CNullDriver::deleteHardwareBuffer(_HWBuffer);
1270}
1271
1272
1273//! Draw hardware buffer
1274void COpenGLDriver::drawHardwareBuffer(SHWBufferLink *_HWBuffer)
1275{
1276 if (!_HWBuffer)
1277 return;
1278
1279 updateHardwareBuffer(_HWBuffer); //check if update is needed
1280 _HWBuffer->LastUsed=0; //reset count
1281
1282#if defined(GL_ARB_vertex_buffer_object)
1283 SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer;
1284
1285 const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
1286 const void *vertices=mb->getVertices();
1287 const void *indexList=mb->getIndices();
1288
1289 if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)
1290 {
1291 extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID);
1292 vertices=0;
1293 }
1294
1295 if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)
1296 {
1297 extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);
1298 indexList=0;
1299 }
1300
1301 drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList, mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType());
1302
1303 if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)
1304 extGlBindBuffer(GL_ARRAY_BUFFER, 0);
1305 if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)
1306 extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1307#endif
1308}
1309
1310
1311//! Create occlusion query.
1312/** Use node for identification and mesh for occlusion test. */
1313void COpenGLDriver::addOcclusionQuery(scene::ISceneNode* node,
1314 const scene::IMesh* mesh)
1315{
1316 if (!queryFeature(EVDF_OCCLUSION_QUERY))
1317 return;
1318
1319 CNullDriver::addOcclusionQuery(node, mesh);
1320 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1321 if ((index != -1) && (OcclusionQueries[index].UID == 0))
1322 extGlGenQueries(1, reinterpret_cast<GLuint*>(&OcclusionQueries[index].UID));
1323}
1324
1325
1326//! Remove occlusion query.
1327void COpenGLDriver::removeOcclusionQuery(scene::ISceneNode* node)
1328{
1329 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1330 if (index != -1)
1331 {
1332 if (OcclusionQueries[index].UID != 0)
1333 extGlDeleteQueries(1, reinterpret_cast<GLuint*>(&OcclusionQueries[index].UID));
1334 CNullDriver::removeOcclusionQuery(node);
1335 }
1336}
1337
1338
1339//! Run occlusion query. Draws mesh stored in query.
1340/** If the mesh shall not be rendered visible, use
1341overrideMaterial to disable the color and depth buffer. */
1342void COpenGLDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)
1343{
1344 if (!node)
1345 return;
1346
1347 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1348 if (index != -1)
1349 {
1350 if (OcclusionQueries[index].UID)
1351 extGlBeginQuery(
1352#ifdef GL_ARB_occlusion_query
1353 GL_SAMPLES_PASSED_ARB,
1354#else
1355 0,
1356#endif
1357 OcclusionQueries[index].UID);
1358 CNullDriver::runOcclusionQuery(node,visible);
1359 if (OcclusionQueries[index].UID)
1360 extGlEndQuery(
1361#ifdef GL_ARB_occlusion_query
1362 GL_SAMPLES_PASSED_ARB);
1363#else
1364 0);
1365#endif
1366 testGLError();
1367 }
1368}
1369
1370
1371//! Update occlusion query. Retrieves results from GPU.
1372/** If the query shall not block, set the flag to false.
1373Update might not occur in this case, though */
1374void COpenGLDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)
1375{
1376 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1377 if (index != -1)
1378 {
1379 // not yet started
1380 if (OcclusionQueries[index].Run==u32(~0))
1381 return;
1382 GLint available = block?GL_TRUE:GL_FALSE;
1383 if (!block)
1384 extGlGetQueryObjectiv(OcclusionQueries[index].UID,
1385#ifdef GL_ARB_occlusion_query
1386 GL_QUERY_RESULT_AVAILABLE_ARB,
1387#elif defined(GL_NV_occlusion_query)
1388 GL_PIXEL_COUNT_AVAILABLE_NV,
1389#else
1390 0,
1391#endif
1392 &available);
1393 testGLError();
1394 if (available==GL_TRUE)
1395 {
1396 extGlGetQueryObjectiv(OcclusionQueries[index].UID,
1397#ifdef GL_ARB_occlusion_query
1398 GL_QUERY_RESULT_ARB,
1399#elif defined(GL_NV_occlusion_query)
1400 GL_PIXEL_COUNT_NV,
1401#else
1402 0,
1403#endif
1404 &available);
1405 if (queryFeature(EVDF_OCCLUSION_QUERY))
1406 OcclusionQueries[index].Result = available;
1407 }
1408 testGLError();
1409 }
1410}
1411
1412
1413//! Return query result.
1414/** Return value is the number of visible pixels/fragments.
1415The value is a safe approximation, i.e. can be larger than the
1416actual value of pixels. */
1417u32 COpenGLDriver::getOcclusionQueryResult(scene::ISceneNode* node) const
1418{
1419 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1420 if (index != -1)
1421 return OcclusionQueries[index].Result;
1422 else
1423 return ~0;
1424}
1425
1426
1427// small helper function to create vertex buffer object adress offsets
1428static inline u8* buffer_offset(const long offset)
1429{
1430 return ((u8*)0 + offset);
1431}
1432
1433
1434//! draws a vertex primitive list
1435void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount,
1436 const void* indexList, u32 primitiveCount,
1437 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
1438{
1439 if (!primitiveCount || !vertexCount)
1440 return;
1441
1442 if (!checkPrimitiveCount(primitiveCount))
1443 return;
1444
1445 CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);
1446
1447 if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
1448 getColorBuffer(vertices, vertexCount, vType);
1449
1450 // draw everything
1451 setRenderStates3DMode();
1452
1453 if (MultiTextureExtension)
1454 extGlClientActiveTexture(GL_TEXTURE0_ARB);
1455
1456 glEnableClientState(GL_COLOR_ARRAY);
1457 glEnableClientState(GL_VERTEX_ARRAY);
1458 if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES))
1459 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1460 if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES))
1461 glEnableClientState(GL_NORMAL_ARRAY);
1462
1463//due to missing defines in OSX headers, we have to be more specific with this check
1464//#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra)
1465#ifdef GL_BGRA
1466 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
1467#else
1468 const GLint colorSize=4;
1469#endif
1470 if (vertices)
1471 {
1472 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
1473 {
1474 switch (vType)
1475 {
1476 case EVT_STANDARD:
1477 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);
1478 break;
1479 case EVT_2TCOORDS:
1480 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Color);
1481 break;
1482 case EVT_TANGENTS:
1483 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Color);
1484 break;
1485 }
1486 }
1487 else
1488 {
1489 // avoid passing broken pointer to OpenGL
1490 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
1491 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
1492 }
1493 }
1494
1495 switch (vType)
1496 {
1497 case EVT_STANDARD:
1498 if (vertices)
1499 {
1500 glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Normal);
1501 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);
1502 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);
1503 }
1504 else
1505 {
1506 glNormalPointer(GL_FLOAT, sizeof(S3DVertex), buffer_offset(12));
1507 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24));
1508 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));
1509 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), 0);
1510 }
1511
1512 if (MultiTextureExtension && CurrentTexture[1])
1513 {
1514 extGlClientActiveTexture(GL_TEXTURE1_ARB);
1515 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1516 if (vertices)
1517 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);
1518 else
1519 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));
1520 }
1521 break;
1522 case EVT_2TCOORDS:
1523 if (vertices)
1524 {
1525 glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Normal);
1526 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords);
1527 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Pos);
1528 }
1529 else
1530 {
1531 glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(12));
1532 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24));
1533 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28));
1534 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0));
1535 }
1536
1537
1538 if (MultiTextureExtension)
1539 {
1540 extGlClientActiveTexture(GL_TEXTURE1_ARB);
1541 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1542 if (vertices)
1543 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords2);
1544 else
1545 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36));
1546 }
1547 break;
1548 case EVT_TANGENTS:
1549 if (vertices)
1550 {
1551 glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Normal);
1552 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].TCoords);
1553 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Pos);
1554 }
1555 else
1556 {
1557 glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12));
1558 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24));
1559 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28));
1560 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0));
1561 }
1562
1563 if (MultiTextureExtension)
1564 {
1565 extGlClientActiveTexture(GL_TEXTURE1_ARB);
1566 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1567 if (vertices)
1568 glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Tangent);
1569 else
1570 glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36));
1571
1572 extGlClientActiveTexture(GL_TEXTURE2_ARB);
1573 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1574 if (vertices)
1575 glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Binormal);
1576 else
1577 glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48));
1578 }
1579 break;
1580 }
1581
1582 renderArray(indexList, primitiveCount, pType, iType);
1583
1584 if (MultiTextureExtension)
1585 {
1586 if (vType==EVT_TANGENTS)
1587 {
1588 extGlClientActiveTexture(GL_TEXTURE2_ARB);
1589 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1590 }
1591 if ((vType!=EVT_STANDARD) || CurrentTexture[1])
1592 {
1593 extGlClientActiveTexture(GL_TEXTURE1_ARB);
1594 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1595 }
1596 extGlClientActiveTexture(GL_TEXTURE0_ARB);
1597 }
1598 glDisableClientState(GL_COLOR_ARRAY);
1599 glDisableClientState(GL_VERTEX_ARRAY);
1600 glDisableClientState(GL_NORMAL_ARRAY);
1601 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1602}
1603
1604
1605void COpenGLDriver::getColorBuffer(const void* vertices, u32 vertexCount, E_VERTEX_TYPE vType)
1606{
1607 // convert colors to gl color format.
1608 vertexCount *= 4; //reused as color component count
1609 ColorBuffer.set_used(vertexCount);
1610 u32 i;
1611
1612 switch (vType)
1613 {
1614 case EVT_STANDARD:
1615 {
1616 const S3DVertex* p = static_cast<const S3DVertex*>(vertices);
1617 for (i=0; i<vertexCount; i+=4)
1618 {
1619 p->Color.toOpenGLColor(&ColorBuffer[i]);
1620 ++p;
1621 }
1622 }
1623 break;
1624 case EVT_2TCOORDS:
1625 {
1626 const S3DVertex2TCoords* p = static_cast<const S3DVertex2TCoords*>(vertices);
1627 for (i=0; i<vertexCount; i+=4)
1628 {
1629 p->Color.toOpenGLColor(&ColorBuffer[i]);
1630 ++p;
1631 }
1632 }
1633 break;
1634 case EVT_TANGENTS:
1635 {
1636 const S3DVertexTangents* p = static_cast<const S3DVertexTangents*>(vertices);
1637 for (i=0; i<vertexCount; i+=4)
1638 {
1639 p->Color.toOpenGLColor(&ColorBuffer[i]);
1640 ++p;
1641 }
1642 }
1643 break;
1644 }
1645}
1646
1647
1648void COpenGLDriver::renderArray(const void* indexList, u32 primitiveCount,
1649 scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
1650{
1651 GLenum indexSize=0;
1652
1653 switch (iType)
1654 {
1655 case EIT_16BIT:
1656 {
1657 indexSize=GL_UNSIGNED_SHORT;
1658 break;
1659 }
1660 case EIT_32BIT:
1661 {
1662 indexSize=GL_UNSIGNED_INT;
1663 break;
1664 }
1665 }
1666
1667 switch (pType)
1668 {
1669 case scene::EPT_POINTS:
1670 case scene::EPT_POINT_SPRITES:
1671 {
1672#ifdef GL_ARB_point_sprite
1673 if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite])
1674 glEnable(GL_POINT_SPRITE_ARB);
1675#endif
1676
1677 // prepare size and attenuation (where supported)
1678 GLfloat particleSize=Material.Thickness;
1679// if (AntiAlias)
1680// particleSize=core::clamp(particleSize, DimSmoothedPoint[0], DimSmoothedPoint[1]);
1681// else
1682 particleSize=core::clamp(particleSize, DimAliasedPoint[0], DimAliasedPoint[1]);
1683#if defined(GL_VERSION_1_4) || defined(GL_ARB_point_parameters) || defined(GL_EXT_point_parameters) || defined(GL_SGIS_point_parameters)
1684 const float att[] = {1.0f, 1.0f, 0.0f};
1685#if defined(GL_VERSION_1_4)
1686 extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, att);
1687// extGlPointParameterf(GL_POINT_SIZE_MIN,1.f);
1688 extGlPointParameterf(GL_POINT_SIZE_MAX, particleSize);
1689 extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE, 1.0f);
1690#elif defined(GL_ARB_point_parameters)
1691 extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
1692// extGlPointParameterf(GL_POINT_SIZE_MIN_ARB,1.f);
1693 extGlPointParameterf(GL_POINT_SIZE_MAX_ARB, particleSize);
1694 extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0f);
1695#elif defined(GL_EXT_point_parameters)
1696 extGlPointParameterfv(GL_DISTANCE_ATTENUATION_EXT, att);
1697// extGlPointParameterf(GL_POINT_SIZE_MIN_EXT,1.f);
1698 extGlPointParameterf(GL_POINT_SIZE_MAX_EXT, particleSize);
1699 extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0f);
1700#elif defined(GL_SGIS_point_parameters)
1701 extGlPointParameterfv(GL_DISTANCE_ATTENUATION_SGIS, att);
1702// extGlPointParameterf(GL_POINT_SIZE_MIN_SGIS,1.f);
1703 extGlPointParameterf(GL_POINT_SIZE_MAX_SGIS, particleSize);
1704 extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_SGIS, 1.0f);
1705#endif
1706#endif
1707 glPointSize(particleSize);
1708
1709#ifdef GL_ARB_point_sprite
1710 if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite])
1711 glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_TRUE);
1712#endif
1713 glDrawArrays(GL_POINTS, 0, primitiveCount);
1714#ifdef GL_ARB_point_sprite
1715 if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite])
1716 {
1717 glDisable(GL_POINT_SPRITE_ARB);
1718 glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_FALSE);
1719 }
1720#endif
1721 }
1722 break;
1723 case scene::EPT_LINE_STRIP:
1724 glDrawElements(GL_LINE_STRIP, primitiveCount+1, indexSize, indexList);
1725 break;
1726 case scene::EPT_LINE_LOOP:
1727 glDrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList);
1728 break;
1729 case scene::EPT_LINES:
1730 glDrawElements(GL_LINES, primitiveCount*2, indexSize, indexList);
1731 break;
1732 case scene::EPT_TRIANGLE_STRIP:
1733 glDrawElements(GL_TRIANGLE_STRIP, primitiveCount+2, indexSize, indexList);
1734 break;
1735 case scene::EPT_TRIANGLE_FAN:
1736 glDrawElements(GL_TRIANGLE_FAN, primitiveCount+2, indexSize, indexList);
1737 break;
1738 case scene::EPT_TRIANGLES:
1739 glDrawElements(GL_TRIANGLES, primitiveCount*3, indexSize, indexList);
1740 break;
1741 case scene::EPT_QUAD_STRIP:
1742 glDrawElements(GL_QUAD_STRIP, primitiveCount*2+2, indexSize, indexList);
1743 break;
1744 case scene::EPT_QUADS:
1745 glDrawElements(GL_QUADS, primitiveCount*4, indexSize, indexList);
1746 break;
1747 case scene::EPT_POLYGON:
1748 glDrawElements(GL_POLYGON, primitiveCount, indexSize, indexList);
1749 break;
1750 }
1751}
1752
1753
1754//! draws a vertex primitive list in 2d
1755void COpenGLDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount,
1756 const void* indexList, u32 primitiveCount,
1757 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
1758{
1759 if (!primitiveCount || !vertexCount)
1760 return;
1761
1762 if (!checkPrimitiveCount(primitiveCount))
1763 return;
1764
1765 CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);
1766
1767 if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
1768 getColorBuffer(vertices, vertexCount, vType);
1769
1770 // draw everything
1771 this->setActiveTexture(0, Material.getTexture(0));
1772 if (Material.MaterialType==EMT_ONETEXTURE_BLEND)
1773 {
1774 E_BLEND_FACTOR srcFact;
1775 E_BLEND_FACTOR dstFact;
1776 E_MODULATE_FUNC modulo;
1777 u32 alphaSource;
1778 unpack_textureBlendFunc ( srcFact, dstFact, modulo, alphaSource, Material.MaterialTypeParam);
1779 setRenderStates2DMode(alphaSource&video::EAS_VERTEX_COLOR, (Material.getTexture(0) != 0), (alphaSource&video::EAS_TEXTURE) != 0);
1780 }
1781 else
1782 setRenderStates2DMode(Material.MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA, (Material.getTexture(0) != 0), Material.MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL);
1783
1784 if (MultiTextureExtension)
1785 extGlClientActiveTexture(GL_TEXTURE0_ARB);
1786
1787 glEnableClientState(GL_COLOR_ARRAY);
1788 glEnableClientState(GL_VERTEX_ARRAY);
1789 if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES))
1790 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1791
1792//due to missing defines in OSX headers, we have to be more specific with this check
1793//#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra)
1794#ifdef GL_BGRA
1795 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
1796#else
1797 const GLint colorSize=4;
1798#endif
1799 if (vertices)
1800 {
1801 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
1802 {
1803 switch (vType)
1804 {
1805 case EVT_STANDARD:
1806 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);
1807 break;
1808 case EVT_2TCOORDS:
1809 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Color);
1810 break;
1811 case EVT_TANGENTS:
1812 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Color);
1813 break;
1814 }
1815 }
1816 else
1817 {
1818 // avoid passing broken pointer to OpenGL
1819 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
1820 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
1821 }
1822 }
1823
1824 switch (vType)
1825 {
1826 case EVT_STANDARD:
1827 if (vertices)
1828 {
1829 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);
1830 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);
1831 }
1832 else
1833 {
1834 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24));
1835 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));
1836 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), 0);
1837 }
1838
1839 if (MultiTextureExtension && CurrentTexture[1])
1840 {
1841 extGlClientActiveTexture(GL_TEXTURE1_ARB);
1842 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1843 if (vertices)
1844 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);
1845 else
1846 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));
1847 }
1848 break;
1849 case EVT_2TCOORDS:
1850 if (vertices)
1851 {
1852 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords);
1853 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Pos);
1854 }
1855 else
1856 {
1857 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24));
1858 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28));
1859 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0));
1860 }
1861
1862 if (MultiTextureExtension)
1863 {
1864 extGlClientActiveTexture(GL_TEXTURE1_ARB);
1865 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1866 if (vertices)
1867 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords2);
1868 else
1869 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36));
1870 }
1871 break;
1872 case EVT_TANGENTS:
1873 if (vertices)
1874 {
1875 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].TCoords);
1876 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Pos);
1877 }
1878 else
1879 {
1880 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24));
1881 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28));
1882 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0));
1883 }
1884
1885 break;
1886 }
1887
1888 renderArray(indexList, primitiveCount, pType, iType);
1889
1890 if (MultiTextureExtension)
1891 {
1892 if ((vType!=EVT_STANDARD) || CurrentTexture[1])
1893 {
1894 extGlClientActiveTexture(GL_TEXTURE1_ARB);
1895 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1896 }
1897 extGlClientActiveTexture(GL_TEXTURE0_ARB);
1898 }
1899 glDisableClientState(GL_COLOR_ARRAY);
1900 glDisableClientState(GL_VERTEX_ARRAY);
1901 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1902}
1903
1904
1905//! draws a set of 2d images, using a color and the alpha channel of the
1906//! texture if desired.
1907void COpenGLDriver::draw2DImageBatch(const video::ITexture* texture,
1908 const core::array<core::position2d<s32> >& positions,
1909 const core::array<core::rect<s32> >& sourceRects,
1910 const core::rect<s32>* clipRect,
1911 SColor color,
1912 bool useAlphaChannelOfTexture)
1913{
1914 if (!texture)
1915 return;
1916
1917 const u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
1918
1919 const core::dimension2d<u32>& ss = texture->getOriginalSize();
1920 const f32 invW = 1.f / static_cast<f32>(ss.Width);
1921 const f32 invH = 1.f / static_cast<f32>(ss.Height);
1922 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
1923
1924 disableTextures(1);
1925 if (!setActiveTexture(0, texture))
1926 return;
1927 setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);
1928
1929 glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
1930 glBegin(GL_QUADS);
1931
1932 for (u32 i=0; i<drawCount; ++i)
1933 {
1934 if (!sourceRects[i].isValid())
1935 continue;
1936
1937 core::position2d<s32> targetPos(positions[i]);
1938 core::position2d<s32> sourcePos(sourceRects[i].UpperLeftCorner);
1939 // This needs to be signed as it may go negative.
1940 core::dimension2d<s32> sourceSize(sourceRects[i].getSize());
1941 if (clipRect)
1942 {
1943 if (targetPos.X < clipRect->UpperLeftCorner.X)
1944 {
1945 sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;
1946 if (sourceSize.Width <= 0)
1947 continue;
1948
1949 sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;
1950 targetPos.X = clipRect->UpperLeftCorner.X;
1951 }
1952
1953 if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X)
1954 {
1955 sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;
1956 if (sourceSize.Width <= 0)
1957 continue;
1958 }
1959
1960 if (targetPos.Y < clipRect->UpperLeftCorner.Y)
1961 {
1962 sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;
1963 if (sourceSize.Height <= 0)
1964 continue;
1965
1966 sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;
1967 targetPos.Y = clipRect->UpperLeftCorner.Y;
1968 }
1969
1970 if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y)
1971 {
1972 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;
1973 if (sourceSize.Height <= 0)
1974 continue;
1975 }
1976 }
1977
1978 // clip these coordinates
1979
1980 if (targetPos.X<0)
1981 {
1982 sourceSize.Width += targetPos.X;
1983 if (sourceSize.Width <= 0)
1984 continue;
1985
1986 sourcePos.X -= targetPos.X;
1987 targetPos.X = 0;
1988 }
1989
1990 if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)
1991 {
1992 sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;
1993 if (sourceSize.Width <= 0)
1994 continue;
1995 }
1996
1997 if (targetPos.Y<0)
1998 {
1999 sourceSize.Height += targetPos.Y;
2000 if (sourceSize.Height <= 0)
2001 continue;
2002
2003 sourcePos.Y -= targetPos.Y;
2004 targetPos.Y = 0;
2005 }
2006
2007 if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)
2008 {
2009 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;
2010 if (sourceSize.Height <= 0)
2011 continue;
2012 }
2013
2014 // ok, we've clipped everything.
2015 // now draw it.
2016
2017 const core::rect<f32> tcoords(
2018 sourcePos.X * invW,
2019 sourcePos.Y * invH,
2020 (sourcePos.X + sourceSize.Width) * invW,
2021 (sourcePos.Y + sourceSize.Height) * invH);
2022
2023 const core::rect<s32> poss(targetPos, sourceSize);
2024
2025 glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
2026 glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y));
2027
2028 glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
2029 glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y));
2030
2031 glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
2032 glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y));
2033
2034 glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
2035 glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y));
2036 }
2037 glEnd();
2038}
2039
2040
2041//! draws a 2d image, using a color and the alpha channel of the texture if
2042//! desired. The image is drawn at pos, clipped against clipRect (if != 0).
2043//! Only the subtexture defined by sourceRect is used.
2044void COpenGLDriver::draw2DImage(const video::ITexture* texture,
2045 const core::position2d<s32>& pos,
2046 const core::rect<s32>& sourceRect,
2047 const core::rect<s32>* clipRect, SColor color,
2048 bool useAlphaChannelOfTexture)
2049{
2050 if (!texture)
2051 return;
2052
2053 if (!sourceRect.isValid())
2054 return;
2055
2056 core::position2d<s32> targetPos(pos);
2057 core::position2d<s32> sourcePos(sourceRect.UpperLeftCorner);
2058 // This needs to be signed as it may go negative.
2059 core::dimension2d<s32> sourceSize(sourceRect.getSize());
2060 if (clipRect)
2061 {
2062 if (targetPos.X < clipRect->UpperLeftCorner.X)
2063 {
2064 sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;
2065 if (sourceSize.Width <= 0)
2066 return;
2067
2068 sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;
2069 targetPos.X = clipRect->UpperLeftCorner.X;
2070 }
2071
2072 if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X)
2073 {
2074 sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;
2075 if (sourceSize.Width <= 0)
2076 return;
2077 }
2078
2079 if (targetPos.Y < clipRect->UpperLeftCorner.Y)
2080 {
2081 sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;
2082 if (sourceSize.Height <= 0)
2083 return;
2084
2085 sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;
2086 targetPos.Y = clipRect->UpperLeftCorner.Y;
2087 }
2088
2089 if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y)
2090 {
2091 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;
2092 if (sourceSize.Height <= 0)
2093 return;
2094 }
2095 }
2096
2097 // clip these coordinates
2098
2099 if (targetPos.X<0)
2100 {
2101 sourceSize.Width += targetPos.X;
2102 if (sourceSize.Width <= 0)
2103 return;
2104
2105 sourcePos.X -= targetPos.X;
2106 targetPos.X = 0;
2107 }
2108
2109 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
2110
2111 if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)
2112 {
2113 sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;
2114 if (sourceSize.Width <= 0)
2115 return;
2116 }
2117
2118 if (targetPos.Y<0)
2119 {
2120 sourceSize.Height += targetPos.Y;
2121 if (sourceSize.Height <= 0)
2122 return;
2123
2124 sourcePos.Y -= targetPos.Y;
2125 targetPos.Y = 0;
2126 }
2127
2128 if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)
2129 {
2130 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;
2131 if (sourceSize.Height <= 0)
2132 return;
2133 }
2134
2135 // ok, we've clipped everything.
2136 // now draw it.
2137
2138 const core::dimension2d<u32>& ss = texture->getOriginalSize();
2139 const f32 invW = 1.f / static_cast<f32>(ss.Width);
2140 const f32 invH = 1.f / static_cast<f32>(ss.Height);
2141 const core::rect<f32> tcoords(
2142 sourcePos.X * invW,
2143 sourcePos.Y * invH,
2144 (sourcePos.X + sourceSize.Width) * invW,
2145 (sourcePos.Y + sourceSize.Height) * invH);
2146
2147 const core::rect<s32> poss(targetPos, sourceSize);
2148
2149 disableTextures(1);
2150 if (!setActiveTexture(0, texture))
2151 return;
2152 setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);
2153
2154 glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
2155 glBegin(GL_QUADS);
2156
2157 glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
2158 glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y));
2159
2160 glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
2161 glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y));
2162
2163 glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
2164 glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y));
2165
2166 glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
2167 glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y));
2168
2169 glEnd();
2170}
2171
2172
2173//! The same, but with a four element array of colors, one for each vertex
2174void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
2175 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
2176 const video::SColor* const colors, bool useAlphaChannelOfTexture)
2177{
2178 if (!texture)
2179 return;
2180
2181 const core::dimension2d<u32>& ss = texture->getOriginalSize();
2182 const f32 invW = 1.f / static_cast<f32>(ss.Width);
2183 const f32 invH = 1.f / static_cast<f32>(ss.Height);
2184 const core::rect<f32> tcoords(
2185 sourceRect.UpperLeftCorner.X * invW,
2186 sourceRect.UpperLeftCorner.Y * invH,
2187 sourceRect.LowerRightCorner.X * invW,
2188 sourceRect.LowerRightCorner.Y *invH);
2189
2190 const video::SColor temp[4] =
2191 {
2192 0xFFFFFFFF,
2193 0xFFFFFFFF,
2194 0xFFFFFFFF,
2195 0xFFFFFFFF
2196 };
2197
2198 const video::SColor* const useColor = colors ? colors : temp;
2199
2200 disableTextures(1);
2201 setActiveTexture(0, texture);
2202 setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 ||
2203 useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255,
2204 true, useAlphaChannelOfTexture);
2205
2206 if (clipRect)
2207 {
2208 if (!clipRect->isValid())
2209 return;
2210
2211 glEnable(GL_SCISSOR_TEST);
2212 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
2213 glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y,
2214 clipRect->getWidth(), clipRect->getHeight());
2215 }
2216
2217 glBegin(GL_QUADS);
2218
2219 glColor4ub(useColor[0].getRed(), useColor[0].getGreen(), useColor[0].getBlue(), useColor[0].getAlpha());
2220 glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
2221 glVertex2f(GLfloat(destRect.UpperLeftCorner.X), GLfloat(destRect.UpperLeftCorner.Y));
2222
2223 glColor4ub(useColor[3].getRed(), useColor[3].getGreen(), useColor[3].getBlue(), useColor[3].getAlpha());
2224 glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
2225 glVertex2f(GLfloat(destRect.LowerRightCorner.X), GLfloat(destRect.UpperLeftCorner.Y));
2226
2227 glColor4ub(useColor[2].getRed(), useColor[2].getGreen(), useColor[2].getBlue(), useColor[2].getAlpha());
2228 glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
2229 glVertex2f(GLfloat(destRect.LowerRightCorner.X), GLfloat(destRect.LowerRightCorner.Y));
2230
2231 glColor4ub(useColor[1].getRed(), useColor[1].getGreen(), useColor[1].getBlue(), useColor[1].getAlpha());
2232 glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
2233 glVertex2f(GLfloat(destRect.UpperLeftCorner.X), GLfloat(destRect.LowerRightCorner.Y));
2234
2235 glEnd();
2236
2237 if (clipRect)
2238 glDisable(GL_SCISSOR_TEST);
2239}
2240
2241
2242//! draws a set of 2d images, using a color and the alpha channel of the
2243//! texture if desired. The images are drawn beginning at pos and concatenated
2244//! in one line. All drawings are clipped against clipRect (if != 0).
2245//! The subtextures are defined by the array of sourceRects and are chosen
2246//! by the indices given.
2247void COpenGLDriver::draw2DImage(const video::ITexture* texture,
2248 const core::position2d<s32>& pos,
2249 const core::array<core::rect<s32> >& sourceRects,
2250 const core::array<s32>& indices,
2251 const core::rect<s32>* clipRect, SColor color,
2252 bool useAlphaChannelOfTexture)
2253{
2254 if (!texture)
2255 return;
2256
2257 disableTextures(1);
2258 if (!setActiveTexture(0, texture))
2259 return;
2260 setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);
2261
2262 glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
2263 if (clipRect)
2264 {
2265 if (!clipRect->isValid())
2266 return;
2267
2268 glEnable(GL_SCISSOR_TEST);
2269 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
2270 glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y,
2271 clipRect->getWidth(),clipRect->getHeight());
2272 }
2273
2274 const core::dimension2d<u32>& ss = texture->getOriginalSize();
2275 core::position2d<s32> targetPos(pos);
2276 const f32 invW = 1.f / static_cast<f32>(ss.Width);
2277 const f32 invH = 1.f / static_cast<f32>(ss.Height);
2278
2279 for (u32 i=0; i<indices.size(); ++i)
2280 {
2281 const s32 currentIndex = indices[i];
2282 if (!sourceRects[currentIndex].isValid())
2283 break;
2284
2285 const core::rect<f32> tcoords(
2286 sourceRects[currentIndex].UpperLeftCorner.X * invW,
2287 sourceRects[currentIndex].UpperLeftCorner.Y * invH,
2288 sourceRects[currentIndex].LowerRightCorner.X * invW,
2289 sourceRects[currentIndex].LowerRightCorner.Y * invH);
2290
2291 const core::rect<s32> poss(targetPos, sourceRects[currentIndex].getSize());
2292
2293 glBegin(GL_QUADS);
2294
2295 glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
2296 glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y));
2297
2298 glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
2299 glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y));
2300
2301 glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
2302 glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y));
2303
2304 glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
2305 glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y));
2306
2307 glEnd();
2308 targetPos.X += sourceRects[currentIndex].getWidth();
2309 }
2310 if (clipRect)
2311 glDisable(GL_SCISSOR_TEST);
2312}
2313
2314
2315//! draw a 2d rectangle
2316void COpenGLDriver::draw2DRectangle(SColor color, const core::rect<s32>& position,
2317 const core::rect<s32>* clip)
2318{
2319 disableTextures();
2320 setRenderStates2DMode(color.getAlpha() < 255, false, false);
2321
2322 core::rect<s32> pos = position;
2323
2324 if (clip)
2325 pos.clipAgainst(*clip);
2326
2327 if (!pos.isValid())
2328 return;
2329
2330 glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
2331 glRectf(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y),
2332 GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y));
2333}
2334
2335
2336//! draw an 2d rectangle
2337void COpenGLDriver::draw2DRectangle(const core::rect<s32>& position,
2338 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
2339 const core::rect<s32>* clip)
2340{
2341 core::rect<s32> pos = position;
2342
2343 if (clip)
2344 pos.clipAgainst(*clip);
2345
2346 if (!pos.isValid())
2347 return;
2348
2349 disableTextures();
2350
2351 setRenderStates2DMode(colorLeftUp.getAlpha() < 255 ||
2352 colorRightUp.getAlpha() < 255 ||
2353 colorLeftDown.getAlpha() < 255 ||
2354 colorRightDown.getAlpha() < 255, false, false);
2355
2356 glBegin(GL_QUADS);
2357 glColor4ub(colorLeftUp.getRed(), colorLeftUp.getGreen(),
2358 colorLeftUp.getBlue(), colorLeftUp.getAlpha());
2359 glVertex2f(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y));
2360
2361 glColor4ub(colorRightUp.getRed(), colorRightUp.getGreen(),
2362 colorRightUp.getBlue(), colorRightUp.getAlpha());
2363 glVertex2f(GLfloat(pos.LowerRightCorner.X), GLfloat(pos.UpperLeftCorner.Y));
2364
2365 glColor4ub(colorRightDown.getRed(), colorRightDown.getGreen(),
2366 colorRightDown.getBlue(), colorRightDown.getAlpha());
2367 glVertex2f(GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y));
2368
2369 glColor4ub(colorLeftDown.getRed(), colorLeftDown.getGreen(),
2370 colorLeftDown.getBlue(), colorLeftDown.getAlpha());
2371 glVertex2f(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.LowerRightCorner.Y));
2372
2373 glEnd();
2374}
2375
2376
2377//! Draws a 2d line.
2378void COpenGLDriver::draw2DLine(const core::position2d<s32>& start,
2379 const core::position2d<s32>& end, SColor color)
2380{
2381 if (start==end)
2382 drawPixel(start.X, start.Y, color);
2383 else
2384 {
2385 disableTextures();
2386 setRenderStates2DMode(color.getAlpha() < 255, false, false);
2387
2388 glBegin(GL_LINES);
2389 glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
2390 GLfloat x=(GLfloat)start.X;
2391 GLfloat y=(GLfloat)start.Y;
2392 if (x>end.X)
2393 x += 0.5f;
2394 if (y>end.Y)
2395 y += 0.5f;
2396 glVertex2f(GLfloat(x), GLfloat(y));
2397 x=(GLfloat)end.X;
2398 y=(GLfloat)end.Y;
2399 if (x>start.X)
2400 x += 0.5f;
2401 if (y>start.Y)
2402 y += 0.5f;
2403 glVertex2f(GLfloat(x), GLfloat(y));
2404 glEnd();
2405 }
2406}
2407
2408//! Draws a pixel
2409void COpenGLDriver::drawPixel(u32 x, u32 y, const SColor &color)
2410{
2411 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
2412 if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height)
2413 return;
2414
2415 disableTextures();
2416 setRenderStates2DMode(color.getAlpha() < 255, false, false);
2417
2418 glBegin(GL_POINTS);
2419 glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
2420 glVertex2i(x, y);
2421 glEnd();
2422}
2423
2424bool COpenGLDriver::setActiveTexture(u32 stage, const video::ITexture* texture)
2425{
2426 if (stage >= MaxSupportedTextures)
2427 return false;
2428
2429 if (CurrentTexture[stage]==texture)
2430 return true;
2431
2432 if (MultiTextureExtension)
2433 extGlActiveTexture(GL_TEXTURE0_ARB + stage);
2434
2435 CurrentTexture.set(stage,texture);
2436
2437 if (!texture)
2438 {
2439 glDisable(GL_TEXTURE_2D);
2440 return true;
2441 }
2442 else
2443 {
2444 if (texture->getDriverType() != EDT_OPENGL)
2445 {
2446 glDisable(GL_TEXTURE_2D);
2447 CurrentTexture.set(stage, 0);
2448 os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
2449 return false;
2450 }
2451
2452 glEnable(GL_TEXTURE_2D);
2453 glBindTexture(GL_TEXTURE_2D,
2454 static_cast<const COpenGLTexture*>(texture)->getOpenGLTextureName());
2455 }
2456 return true;
2457}
2458
2459
2460//! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled.
2461//! Returns whether disabling was successful or not.
2462bool COpenGLDriver::disableTextures(u32 fromStage)
2463{
2464 bool result=true;
2465 for (u32 i=fromStage; i<MaxSupportedTextures; ++i)
2466 result &= setActiveTexture(i, 0);
2467 return result;
2468}
2469
2470
2471//! creates a matrix in supplied GLfloat array to pass to OpenGL
2472inline void COpenGLDriver::getGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m)
2473{
2474 memcpy(gl_matrix, m.pointer(), 16 * sizeof(f32));
2475}
2476
2477
2478//! creates a opengltexturematrix from a D3D style texture matrix
2479inline void COpenGLDriver::getGLTextureMatrix(GLfloat *o, const core::matrix4& m)
2480{
2481 o[0] = m[0];
2482 o[1] = m[1];
2483 o[2] = 0.f;
2484 o[3] = 0.f;
2485
2486 o[4] = m[4];
2487 o[5] = m[5];
2488 o[6] = 0.f;
2489 o[7] = 0.f;
2490
2491 o[8] = 0.f;
2492 o[9] = 0.f;
2493 o[10] = 1.f;
2494 o[11] = 0.f;
2495
2496 o[12] = m[8];
2497 o[13] = m[9];
2498 o[14] = 0.f;
2499 o[15] = 1.f;
2500}
2501
2502
2503//! returns a device dependent texture from a software surface (IImage)
2504video::ITexture* COpenGLDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData)
2505{
2506 return new COpenGLTexture(surface, name, mipmapData, this);
2507}
2508
2509
2510//! Sets a material. All 3d drawing functions draw geometry now using this material.
2511void COpenGLDriver::setMaterial(const SMaterial& material)
2512{
2513 Material = material;
2514 OverrideMaterial.apply(Material);
2515
2516 for (s32 i = MaxTextureUnits-1; i>= 0; --i)
2517 {
2518 setActiveTexture(i, material.getTexture(i));
2519 setTransform ((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i),
2520 Material.getTextureMatrix(i));
2521 }
2522}
2523
2524
2525//! prints error if an error happened.
2526bool COpenGLDriver::testGLError()
2527{
2528#ifdef _DEBUG
2529 GLenum g = glGetError();
2530 switch (g)
2531 {
2532 case GL_NO_ERROR:
2533 return false;
2534 case GL_INVALID_ENUM:
2535 os::Printer::log("GL_INVALID_ENUM", ELL_ERROR); break;
2536 case GL_INVALID_VALUE:
2537 os::Printer::log("GL_INVALID_VALUE", ELL_ERROR); break;
2538 case GL_INVALID_OPERATION:
2539 os::Printer::log("GL_INVALID_OPERATION", ELL_ERROR); break;
2540 case GL_STACK_OVERFLOW:
2541 os::Printer::log("GL_STACK_OVERFLOW", ELL_ERROR); break;
2542 case GL_STACK_UNDERFLOW:
2543 os::Printer::log("GL_STACK_UNDERFLOW", ELL_ERROR); break;
2544 case GL_OUT_OF_MEMORY:
2545 os::Printer::log("GL_OUT_OF_MEMORY", ELL_ERROR); break;
2546 case GL_TABLE_TOO_LARGE:
2547 os::Printer::log("GL_TABLE_TOO_LARGE", ELL_ERROR); break;
2548#if defined(GL_EXT_framebuffer_object)
2549 case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
2550 os::Printer::log("GL_INVALID_FRAMEBUFFER_OPERATION", ELL_ERROR); break;
2551#endif
2552 };
2553// _IRR_DEBUG_BREAK_IF(true);
2554 return true;
2555#else
2556 return false;
2557#endif
2558}
2559
2560
2561//! sets the needed renderstates
2562void COpenGLDriver::setRenderStates3DMode()
2563{
2564 if (CurrentRenderMode != ERM_3D)
2565 {
2566 // Reset Texture Stages
2567 glDisable(GL_BLEND);
2568 glDisable(GL_ALPHA_TEST);
2569 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2570
2571 // switch back the matrices
2572 glMatrixMode(GL_MODELVIEW);
2573 glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer());
2574
2575 glMatrixMode(GL_PROJECTION);
2576 glLoadMatrixf(Matrices[ETS_PROJECTION].pointer());
2577
2578 ResetRenderStates = true;
2579#ifdef GL_EXT_clip_volume_hint
2580 if (FeatureAvailable[IRR_EXT_clip_volume_hint])
2581 glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_NICEST);
2582#endif
2583 }
2584
2585 if (ResetRenderStates || LastMaterial != Material)
2586 {
2587 // unset old material
2588
2589 if (LastMaterial.MaterialType != Material.MaterialType &&
2590 static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
2591 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
2592
2593 // set new material.
2594 if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
2595 MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial(
2596 Material, LastMaterial, ResetRenderStates, this);
2597
2598 LastMaterial = Material;
2599 ResetRenderStates = false;
2600 }
2601
2602 if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
2603 MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD);
2604
2605 CurrentRenderMode = ERM_3D;
2606}
2607
2608
2609//! Get native wrap mode value
2610GLint COpenGLDriver::getTextureWrapMode(const u8 clamp)
2611{
2612 GLint mode=GL_REPEAT;
2613 switch (clamp)
2614 {
2615 case ETC_REPEAT:
2616 mode=GL_REPEAT;
2617 break;
2618 case ETC_CLAMP:
2619 mode=GL_CLAMP;
2620 break;
2621 case ETC_CLAMP_TO_EDGE:
2622#ifdef GL_VERSION_1_2
2623 if (Version>101)
2624 mode=GL_CLAMP_TO_EDGE;
2625 else
2626#endif
2627#ifdef GL_SGIS_texture_edge_clamp
2628 if (FeatureAvailable[IRR_SGIS_texture_edge_clamp])
2629 mode=GL_CLAMP_TO_EDGE_SGIS;
2630 else
2631#endif
2632 // fallback
2633 mode=GL_CLAMP;
2634 break;
2635 case ETC_CLAMP_TO_BORDER:
2636#ifdef GL_VERSION_1_3
2637 if (Version>102)
2638 mode=GL_CLAMP_TO_BORDER;
2639 else
2640#endif
2641#ifdef GL_ARB_texture_border_clamp
2642 if (FeatureAvailable[IRR_ARB_texture_border_clamp])
2643 mode=GL_CLAMP_TO_BORDER_ARB;
2644 else
2645#endif
2646#ifdef GL_SGIS_texture_border_clamp
2647 if (FeatureAvailable[IRR_SGIS_texture_border_clamp])
2648 mode=GL_CLAMP_TO_BORDER_SGIS;
2649 else
2650#endif
2651 // fallback
2652 mode=GL_CLAMP;
2653 break;
2654 case ETC_MIRROR:
2655#ifdef GL_VERSION_1_4
2656 if (Version>103)
2657 mode=GL_MIRRORED_REPEAT;
2658 else
2659#endif
2660#ifdef GL_ARB_texture_border_clamp
2661 if (FeatureAvailable[IRR_ARB_texture_mirrored_repeat])
2662 mode=GL_MIRRORED_REPEAT_ARB;
2663 else
2664#endif
2665#ifdef GL_IBM_texture_mirrored_repeat
2666 if (FeatureAvailable[IRR_IBM_texture_mirrored_repeat])
2667 mode=GL_MIRRORED_REPEAT_IBM;
2668 else
2669#endif
2670 mode=GL_REPEAT;
2671 break;
2672 case ETC_MIRROR_CLAMP:
2673#ifdef GL_EXT_texture_mirror_clamp
2674 if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])
2675 mode=GL_MIRROR_CLAMP_EXT;
2676 else
2677#endif
2678#if defined(GL_ATI_texture_mirror_once)
2679 if (FeatureAvailable[IRR_ATI_texture_mirror_once])
2680 mode=GL_MIRROR_CLAMP_ATI;
2681 else
2682#endif
2683 mode=GL_CLAMP;
2684 break;
2685 case ETC_MIRROR_CLAMP_TO_EDGE:
2686#ifdef GL_EXT_texture_mirror_clamp
2687 if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])
2688 mode=GL_MIRROR_CLAMP_TO_EDGE_EXT;
2689 else
2690#endif
2691#if defined(GL_ATI_texture_mirror_once)
2692 if (FeatureAvailable[IRR_ATI_texture_mirror_once])
2693 mode=GL_MIRROR_CLAMP_TO_EDGE_ATI;
2694 else
2695#endif
2696 mode=GL_CLAMP;
2697 break;
2698 case ETC_MIRROR_CLAMP_TO_BORDER:
2699#ifdef GL_EXT_texture_mirror_clamp
2700 if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])
2701 mode=GL_MIRROR_CLAMP_TO_BORDER_EXT;
2702 else
2703#endif
2704 mode=GL_CLAMP;
2705 break;
2706 }
2707 return mode;
2708}
2709
2710
2711void COpenGLDriver::setWrapMode(const SMaterial& material)
2712{
2713 // texture address mode
2714 // Has to be checked always because it depends on the textures
2715 for (u32 u=0; u<MaxTextureUnits; ++u)
2716 {
2717 if (!CurrentTexture[u])
2718 continue;
2719 if (MultiTextureExtension)
2720 extGlActiveTexture(GL_TEXTURE0_ARB + u);
2721 else if (u>0)
2722 break; // stop loop
2723
2724 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[u].TextureWrapU));
2725 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[u].TextureWrapV));
2726 }
2727}
2728
2729
2730//! Can be called by an IMaterialRenderer to make its work easier.
2731void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial,
2732 bool resetAllRenderStates)
2733{
2734 if (resetAllRenderStates ||
2735 lastmaterial.ColorMaterial != material.ColorMaterial)
2736 {
2737 switch (material.ColorMaterial)
2738 {
2739 case ECM_NONE:
2740 glDisable(GL_COLOR_MATERIAL);
2741 break;
2742 case ECM_DIFFUSE:
2743 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
2744 break;
2745 case ECM_AMBIENT:
2746 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
2747 break;
2748 case ECM_EMISSIVE:
2749 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
2750 break;
2751 case ECM_SPECULAR:
2752 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
2753 break;
2754 case ECM_DIFFUSE_AND_AMBIENT:
2755 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
2756 break;
2757 }
2758 if (material.ColorMaterial != ECM_NONE)
2759 glEnable(GL_COLOR_MATERIAL);
2760 }
2761
2762 if (resetAllRenderStates ||
2763 lastmaterial.AmbientColor != material.AmbientColor ||
2764 lastmaterial.DiffuseColor != material.DiffuseColor ||
2765 lastmaterial.EmissiveColor != material.EmissiveColor ||
2766 lastmaterial.ColorMaterial != material.ColorMaterial)
2767 {
2768 GLfloat color[4];
2769
2770 const f32 inv = 1.0f / 255.0f;
2771
2772 if ((material.ColorMaterial != video::ECM_AMBIENT) &&
2773 (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT))
2774 {
2775 color[0] = material.AmbientColor.getRed() * inv;
2776 color[1] = material.AmbientColor.getGreen() * inv;
2777 color[2] = material.AmbientColor.getBlue() * inv;
2778 color[3] = material.AmbientColor.getAlpha() * inv;
2779 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);
2780 }
2781
2782 if ((material.ColorMaterial != video::ECM_DIFFUSE) &&
2783 (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT))
2784 {
2785 color[0] = material.DiffuseColor.getRed() * inv;
2786 color[1] = material.DiffuseColor.getGreen() * inv;
2787 color[2] = material.DiffuseColor.getBlue() * inv;
2788 color[3] = material.DiffuseColor.getAlpha() * inv;
2789 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
2790 }
2791
2792 if (material.ColorMaterial != video::ECM_EMISSIVE)
2793 {
2794 color[0] = material.EmissiveColor.getRed() * inv;
2795 color[1] = material.EmissiveColor.getGreen() * inv;
2796 color[2] = material.EmissiveColor.getBlue() * inv;
2797 color[3] = material.EmissiveColor.getAlpha() * inv;
2798 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color);
2799 }
2800 }
2801
2802 if (resetAllRenderStates ||
2803 lastmaterial.SpecularColor != material.SpecularColor ||
2804 lastmaterial.Shininess != material.Shininess ||
2805 lastmaterial.ColorMaterial != material.ColorMaterial)
2806 {
2807 GLfloat color[4]={0.f,0.f,0.f,1.f};
2808 const f32 inv = 1.0f / 255.0f;
2809
2810 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess);
2811 // disable Specular colors if no shininess is set
2812 if ((material.Shininess != 0.0f) &&
2813 (material.ColorMaterial != video::ECM_SPECULAR))
2814 {
2815#ifdef GL_EXT_separate_specular_color
2816 if (FeatureAvailable[IRR_EXT_separate_specular_color])
2817 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
2818#endif
2819 color[0] = material.SpecularColor.getRed() * inv;
2820 color[1] = material.SpecularColor.getGreen() * inv;
2821 color[2] = material.SpecularColor.getBlue() * inv;
2822 color[3] = material.SpecularColor.getAlpha() * inv;
2823 }
2824#ifdef GL_EXT_separate_specular_color
2825 else if (FeatureAvailable[IRR_EXT_separate_specular_color])
2826 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
2827#endif
2828 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);
2829 }
2830
2831 // Texture filter
2832 // Has to be checked always because it depends on the textures
2833 // Filtering has to be set for each texture layer
2834 for (u32 i=0; i<MaxTextureUnits; ++i)
2835 {
2836 if (!CurrentTexture[i])
2837 continue;
2838 if (MultiTextureExtension)
2839 extGlActiveTexture(GL_TEXTURE0_ARB + i);
2840 else if (i>0)
2841 break;
2842
2843#ifdef GL_EXT_texture_lod_bias
2844 if (FeatureAvailable[IRR_EXT_texture_lod_bias])
2845 {
2846 if (material.TextureLayer[i].LODBias)
2847 {
2848 const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);
2849 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp);
2850 }
2851 else
2852 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f);
2853 }
2854#endif
2855
2856 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2857 (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);
2858
2859 if (material.UseMipMaps && CurrentTexture[i]->hasMipMaps())
2860 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2861 material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR :
2862 material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST :
2863 GL_NEAREST_MIPMAP_NEAREST);
2864 else
2865 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2866 (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);
2867
2868#ifdef GL_EXT_texture_filter_anisotropic
2869 if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic])
2870 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
2871 material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1);
2872#endif
2873 }
2874
2875 // fillmode
2876 if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud))
2877 glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL);
2878
2879 // shademode
2880 if (resetAllRenderStates || (lastmaterial.GouraudShading != material.GouraudShading))
2881 {
2882 if (material.GouraudShading)
2883 glShadeModel(GL_SMOOTH);
2884 else
2885 glShadeModel(GL_FLAT);
2886 }
2887
2888 // lighting
2889 if (resetAllRenderStates || (lastmaterial.Lighting != material.Lighting))
2890 {
2891 if (material.Lighting)
2892 glEnable(GL_LIGHTING);
2893 else
2894 glDisable(GL_LIGHTING);
2895 }
2896
2897 // zbuffer
2898 if (resetAllRenderStates || lastmaterial.ZBuffer != material.ZBuffer)
2899 {
2900 switch (material.ZBuffer)
2901 {
2902 case ECFN_NEVER:
2903 glDisable(GL_DEPTH_TEST);
2904 break;
2905 case ECFN_LESSEQUAL:
2906 glEnable(GL_DEPTH_TEST);
2907 glDepthFunc(GL_LEQUAL);
2908 break;
2909 case ECFN_EQUAL:
2910 glEnable(GL_DEPTH_TEST);
2911 glDepthFunc(GL_EQUAL);
2912 break;
2913 case ECFN_LESS:
2914 glEnable(GL_DEPTH_TEST);
2915 glDepthFunc(GL_LESS);
2916 break;
2917 case ECFN_NOTEQUAL:
2918 glEnable(GL_DEPTH_TEST);
2919 glDepthFunc(GL_NOTEQUAL);
2920 break;
2921 case ECFN_GREATEREQUAL:
2922 glEnable(GL_DEPTH_TEST);
2923 glDepthFunc(GL_GEQUAL);
2924 break;
2925 case ECFN_GREATER:
2926 glEnable(GL_DEPTH_TEST);
2927 glDepthFunc(GL_GREATER);
2928 break;
2929 case ECFN_ALWAYS:
2930 glEnable(GL_DEPTH_TEST);
2931 glDepthFunc(GL_ALWAYS);
2932 break;
2933 }
2934 }
2935
2936 // zwrite
2937// if (resetAllRenderStates || lastmaterial.ZWriteEnable != material.ZWriteEnable)
2938 {
2939 if (material.ZWriteEnable && (AllowZWriteOnTransparent || !material.isTransparent()))
2940 {
2941 glDepthMask(GL_TRUE);
2942 }
2943 else
2944 glDepthMask(GL_FALSE);
2945 }
2946
2947 // back face culling
2948 if (resetAllRenderStates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling))
2949 {
2950 if ((material.FrontfaceCulling) && (material.BackfaceCulling))
2951 {
2952 glCullFace(GL_FRONT_AND_BACK);
2953 glEnable(GL_CULL_FACE);
2954 }
2955 else
2956 if (material.BackfaceCulling)
2957 {
2958 glCullFace(GL_BACK);
2959 glEnable(GL_CULL_FACE);
2960 }
2961 else
2962 if (material.FrontfaceCulling)
2963 {
2964 glCullFace(GL_FRONT);
2965 glEnable(GL_CULL_FACE);
2966 }
2967 else
2968 glDisable(GL_CULL_FACE);
2969 }
2970
2971 // fog
2972 if (resetAllRenderStates || lastmaterial.FogEnable != material.FogEnable)
2973 {
2974 if (material.FogEnable)
2975 glEnable(GL_FOG);
2976 else
2977 glDisable(GL_FOG);
2978 }
2979
2980 // normalization
2981 if (resetAllRenderStates || lastmaterial.NormalizeNormals != material.NormalizeNormals)
2982 {
2983 if (material.NormalizeNormals)
2984 glEnable(GL_NORMALIZE);
2985 else
2986 glDisable(GL_NORMALIZE);
2987 }
2988
2989 // Color Mask
2990 if (resetAllRenderStates || lastmaterial.ColorMask != material.ColorMask)
2991 {
2992 glColorMask(
2993 (material.ColorMask & ECP_RED)?GL_TRUE:GL_FALSE,
2994 (material.ColorMask & ECP_GREEN)?GL_TRUE:GL_FALSE,
2995 (material.ColorMask & ECP_BLUE)?GL_TRUE:GL_FALSE,
2996 (material.ColorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE);
2997 }
2998
2999 if (queryFeature(EVDF_BLEND_OPERATIONS) &&
3000 (resetAllRenderStates|| lastmaterial.BlendOperation != material.BlendOperation))
3001 {
3002 if (material.BlendOperation==EBO_NONE)
3003 glDisable(GL_BLEND);
3004 else
3005 {
3006 glEnable(GL_BLEND);
3007#if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) || defined(GL_VERSION_1_2)
3008 switch (material.BlendOperation)
3009 {
3010 case EBO_SUBTRACT:
3011#if defined(GL_EXT_blend_subtract)
3012 if (FeatureAvailable[IRR_EXT_blend_subtract] || (Version>=120))
3013 extGlBlendEquation(GL_FUNC_SUBTRACT_EXT);
3014#elif defined(GL_VERSION_1_2)
3015 if (Version>=120)
3016 extGlBlendEquation(GL_FUNC_SUBTRACT);
3017#endif
3018 break;
3019 case EBO_REVSUBTRACT:
3020#if defined(GL_EXT_blend_subtract)
3021 if (FeatureAvailable[IRR_EXT_blend_subtract] || (Version>=120))
3022 extGlBlendEquation(GL_FUNC_REVERSE_SUBTRACT_EXT);
3023#elif defined(GL_VERSION_1_2)
3024 if (Version>=120)
3025 extGlBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
3026#endif
3027 break;
3028 case EBO_MIN:
3029#if defined(GL_EXT_blend_minmax)
3030 if (FeatureAvailable[IRR_EXT_blend_minmax] || (Version>=120))
3031 extGlBlendEquation(GL_MIN_EXT);
3032#elif defined(GL_VERSION_1_2)
3033 if (Version>=120)
3034 extGlBlendEquation(GL_MIN);
3035#endif
3036 break;
3037 case EBO_MAX:
3038#if defined(GL_EXT_blend_minmax)
3039 if (FeatureAvailable[IRR_EXT_blend_minmax] || (Version>=120))
3040 extGlBlendEquation(GL_MAX_EXT);
3041#elif defined(GL_VERSION_1_2)
3042 if (Version>=120)
3043 extGlBlendEquation(GL_MAX);
3044#endif
3045 break;
3046 case EBO_MIN_FACTOR:
3047#if defined(GL_AMD_blend_minmax_factor)
3048 if (FeatureAvailable[IRR_AMD_blend_minmax_factor])
3049 extGlBlendEquation(GL_FACTOR_MIN_AMD);
3050#endif
3051 // fallback in case of missing extension
3052#if defined(GL_VERSION_1_2)
3053#if defined(GL_AMD_blend_minmax_factor)
3054 else
3055#endif
3056 if (Version>=120)
3057 extGlBlendEquation(GL_MIN);
3058#endif
3059 break;
3060 case EBO_MAX_FACTOR:
3061#if defined(GL_AMD_blend_minmax_factor)
3062 if (FeatureAvailable[IRR_AMD_blend_minmax_factor])
3063 extGlBlendEquation(GL_FACTOR_MAX_AMD);
3064#endif
3065 // fallback in case of missing extension
3066#if defined(GL_VERSION_1_2)
3067#if defined(GL_AMD_blend_minmax_factor)
3068 else
3069#endif
3070 if (Version>=120)
3071 extGlBlendEquation(GL_MAX);
3072#endif
3073 break;
3074 case EBO_MIN_ALPHA:
3075#if defined(GL_SGIX_blend_alpha_minmax)
3076 if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax])
3077 extGlBlendEquation(GL_ALPHA_MIN_SGIX);
3078 // fallback in case of missing extension
3079 else
3080 if (FeatureAvailable[IRR_EXT_blend_minmax])
3081 extGlBlendEquation(GL_MIN_EXT);
3082#endif
3083 break;
3084 case EBO_MAX_ALPHA:
3085#if defined(GL_SGIX_blend_alpha_minmax)
3086 if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax])
3087 extGlBlendEquation(GL_ALPHA_MAX_SGIX);
3088 // fallback in case of missing extension
3089 else
3090 if (FeatureAvailable[IRR_EXT_blend_minmax])
3091 extGlBlendEquation(GL_MAX_EXT);
3092#endif
3093 break;
3094 default:
3095#if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op)
3096 extGlBlendEquation(GL_FUNC_ADD_EXT);
3097#elif defined(GL_VERSION_1_2)
3098 extGlBlendEquation(GL_FUNC_ADD);
3099#endif
3100 break;
3101 }
3102#endif
3103 }
3104 }
3105
3106 // Polygon Offset
3107 if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderStates ||
3108 lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection ||
3109 lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor))
3110 {
3111 glDisable(lastmaterial.Wireframe?GL_POLYGON_OFFSET_LINE:lastmaterial.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);
3112 if (material.PolygonOffsetFactor)
3113 {
3114 glDisable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);
3115 glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);
3116 }
3117 if (material.PolygonOffsetDirection==EPO_BACK)
3118 glPolygonOffset(1.0f, (GLfloat)material.PolygonOffsetFactor);
3119 else
3120 glPolygonOffset(-1.0f, (GLfloat)-material.PolygonOffsetFactor);
3121 }
3122
3123 // thickness
3124 if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness)
3125 {
3126 if (AntiAlias)
3127 {
3128// glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimSmoothedPoint[0], DimSmoothedPoint[1]));
3129 // we don't use point smoothing
3130 glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1]));
3131 glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimSmoothedLine[0], DimSmoothedLine[1]));
3132 }
3133 else
3134 {
3135 glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1]));
3136 glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedLine[0], DimAliasedLine[1]));
3137 }
3138 }
3139
3140 // Anti aliasing
3141 if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing)
3142 {
3143 if (FeatureAvailable[IRR_ARB_multisample])
3144 {
3145 if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)
3146 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
3147 else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)
3148 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
3149
3150 if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY)))
3151 {
3152 glEnable(GL_MULTISAMPLE_ARB);
3153#ifdef GL_NV_multisample_filter_hint
3154 if (FeatureAvailable[IRR_NV_multisample_filter_hint])
3155 {
3156 if ((material.AntiAliasing & EAAM_QUALITY) == EAAM_QUALITY)
3157 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
3158 else
3159 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
3160 }
3161#endif
3162 }
3163 else
3164 glDisable(GL_MULTISAMPLE_ARB);
3165 }
3166 if ((material.AntiAliasing & EAAM_LINE_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH))
3167 {
3168 if (material.AntiAliasing & EAAM_LINE_SMOOTH)
3169 glEnable(GL_LINE_SMOOTH);
3170 else if (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH)
3171 glDisable(GL_LINE_SMOOTH);
3172 }
3173 if ((material.AntiAliasing & EAAM_POINT_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH))
3174 {
3175 if (material.AntiAliasing & EAAM_POINT_SMOOTH)
3176 // often in software, and thus very slow
3177 glEnable(GL_POINT_SMOOTH);
3178 else if (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH)
3179 glDisable(GL_POINT_SMOOTH);
3180 }
3181 }
3182
3183 setWrapMode(material);
3184
3185 // be sure to leave in texture stage 0
3186 if (MultiTextureExtension)
3187 extGlActiveTexture(GL_TEXTURE0_ARB);
3188}
3189
3190
3191//! Enable the 2d override material
3192void COpenGLDriver::enableMaterial2D(bool enable)
3193{
3194 if (!enable)
3195 CurrentRenderMode = ERM_NONE;
3196 CNullDriver::enableMaterial2D(enable);
3197}
3198
3199
3200//! sets the needed renderstates
3201void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel)
3202{
3203 if (CurrentRenderMode != ERM_2D || Transformation3DChanged)
3204 {
3205 // unset last 3d material
3206 if (CurrentRenderMode == ERM_3D)
3207 {
3208 if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
3209 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
3210 }
3211 if (Transformation3DChanged)
3212 {
3213 glMatrixMode(GL_PROJECTION);
3214
3215 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
3216 core::matrix4 m(core::matrix4::EM4CONST_NOTHING);
3217 m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f);
3218 m.setTranslation(core::vector3df(-1,1,0));
3219 glLoadMatrixf(m.pointer());
3220
3221 glMatrixMode(GL_MODELVIEW);
3222 glLoadIdentity();
3223 glTranslatef(0.375f, 0.375f, 0.0f);
3224
3225 // Make sure we set first texture matrix
3226 if (MultiTextureExtension)
3227 extGlActiveTexture(GL_TEXTURE0_ARB);
3228
3229 Transformation3DChanged = false;
3230 }
3231 if (!OverrideMaterial2DEnabled)
3232 {
3233 setBasicRenderStates(InitMaterial2D, LastMaterial, true);
3234 LastMaterial = InitMaterial2D;
3235 }
3236 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3237#ifdef GL_EXT_clip_volume_hint
3238 if (FeatureAvailable[IRR_EXT_clip_volume_hint])
3239 glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST);
3240#endif
3241
3242 }
3243 if (OverrideMaterial2DEnabled)
3244 {
3245 OverrideMaterial2D.Lighting=false;
3246 setBasicRenderStates(OverrideMaterial2D, LastMaterial, false);
3247 LastMaterial = OverrideMaterial2D;
3248 }
3249
3250 // no alphaChannel without texture
3251 alphaChannel &= texture;
3252
3253 if (alphaChannel || alpha)
3254 {
3255 glEnable(GL_BLEND);
3256 glEnable(GL_ALPHA_TEST);
3257 glAlphaFunc(GL_GREATER, 0.f);
3258 }
3259 else
3260 {
3261 glDisable(GL_BLEND);
3262 glDisable(GL_ALPHA_TEST);
3263 }
3264
3265 if (texture)
3266 {
3267 if (!OverrideMaterial2DEnabled)
3268 {
3269 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3270 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3271 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
3272 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
3273 }
3274 Material.setTexture(0, const_cast<video::ITexture*>(CurrentTexture[0]));
3275 setTransform(ETS_TEXTURE_0, core::IdentityMatrix);
3276 // Due to the transformation change, the previous line would call a reset each frame
3277 // but we can safely reset the variable as it was false before
3278 Transformation3DChanged=false;
3279
3280 if (alphaChannel)
3281 {
3282 // if alpha and alpha texture just modulate, otherwise use only the alpha channel
3283 if (alpha)
3284 {
3285 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
3286 }
3287 else
3288 {
3289#if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine)
3290 if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine])
3291 {
3292#ifdef GL_ARB_texture_env_combine
3293 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
3294 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
3295 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
3296 // rgb always modulates
3297 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
3298 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
3299 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
3300#else
3301 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
3302 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);
3303 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE);
3304 // rgb always modulates
3305 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
3306 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
3307 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
3308#endif
3309 }
3310 else
3311#endif
3312 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
3313 }
3314 }
3315 else
3316 {
3317 if (alpha)
3318 {
3319#if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine)
3320 if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine])
3321 {
3322#ifdef GL_ARB_texture_env_combine
3323 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
3324 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
3325 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
3326 // rgb always modulates
3327 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
3328 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
3329 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
3330#else
3331 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
3332 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);
3333 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT);
3334 // rgb always modulates
3335 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
3336 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
3337 glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
3338#endif
3339 }
3340 else
3341#endif
3342 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
3343 }
3344 else
3345 {
3346 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
3347 }
3348 }
3349 }
3350
3351 CurrentRenderMode = ERM_2D;
3352}
3353
3354
3355//! \return Returns the name of the video driver.
3356const wchar_t* COpenGLDriver::getName() const
3357{
3358 return Name.c_str();
3359}
3360
3361
3362//! deletes all dynamic lights there are
3363void COpenGLDriver::deleteAllDynamicLights()
3364{
3365 for (s32 i=0; i<MaxLights; ++i)
3366 glDisable(GL_LIGHT0 + i);
3367
3368 RequestedLights.clear();
3369
3370 CNullDriver::deleteAllDynamicLights();
3371}
3372
3373
3374//! adds a dynamic light
3375s32 COpenGLDriver::addDynamicLight(const SLight& light)
3376{
3377 CNullDriver::addDynamicLight(light);
3378
3379 RequestedLights.push_back(RequestedLight(light));
3380
3381 u32 newLightIndex = RequestedLights.size() - 1;
3382
3383 // Try and assign a hardware light just now, but don't worry if I can't
3384 assignHardwareLight(newLightIndex);
3385
3386 return (s32)newLightIndex;
3387}
3388
3389
3390void COpenGLDriver::assignHardwareLight(u32 lightIndex)
3391{
3392 setTransform(ETS_WORLD, core::matrix4());
3393
3394 s32 lidx;
3395 for (lidx=GL_LIGHT0; lidx < GL_LIGHT0 + MaxLights; ++lidx)
3396 {
3397 if(!glIsEnabled(lidx))
3398 {
3399 RequestedLights[lightIndex].HardwareLightIndex = lidx;
3400 break;
3401 }
3402 }
3403
3404 if(lidx == GL_LIGHT0 + MaxLights) // There's no room for it just now
3405 return;
3406
3407 GLfloat data[4];
3408 const SLight & light = RequestedLights[lightIndex].LightData;
3409
3410 switch (light.Type)
3411 {
3412 case video::ELT_SPOT:
3413 data[0] = light.Direction.X;
3414 data[1] = light.Direction.Y;
3415 data[2] = light.Direction.Z;
3416 data[3] = 0.0f;
3417 glLightfv(lidx, GL_SPOT_DIRECTION, data);
3418
3419 // set position
3420 data[0] = light.Position.X;
3421 data[1] = light.Position.Y;
3422 data[2] = light.Position.Z;
3423 data[3] = 1.0f; // 1.0f for positional light
3424 glLightfv(lidx, GL_POSITION, data);
3425
3426 glLightf(lidx, GL_SPOT_EXPONENT, light.Falloff);
3427 glLightf(lidx, GL_SPOT_CUTOFF, light.OuterCone);
3428 break;
3429 case video::ELT_POINT:
3430 // set position
3431 data[0] = light.Position.X;
3432 data[1] = light.Position.Y;
3433 data[2] = light.Position.Z;
3434 data[3] = 1.0f; // 1.0f for positional light
3435 glLightfv(lidx, GL_POSITION, data);
3436
3437 glLightf(lidx, GL_SPOT_EXPONENT, 0.0f);
3438 glLightf(lidx, GL_SPOT_CUTOFF, 180.0f);
3439 break;
3440 case video::ELT_DIRECTIONAL:
3441 // set direction
3442 data[0] = -light.Direction.X;
3443 data[1] = -light.Direction.Y;
3444 data[2] = -light.Direction.Z;
3445 data[3] = 0.0f; // 0.0f for directional light
3446 glLightfv(lidx, GL_POSITION, data);
3447
3448 glLightf(lidx, GL_SPOT_EXPONENT, 0.0f);
3449 glLightf(lidx, GL_SPOT_CUTOFF, 180.0f);
3450 break;
3451 default:
3452 break;
3453 }
3454
3455 // set diffuse color
3456 data[0] = light.DiffuseColor.r;
3457 data[1] = light.DiffuseColor.g;
3458 data[2] = light.DiffuseColor.b;
3459 data[3] = light.DiffuseColor.a;
3460 glLightfv(lidx, GL_DIFFUSE, data);
3461
3462 // set specular color
3463 data[0] = light.SpecularColor.r;
3464 data[1] = light.SpecularColor.g;
3465 data[2] = light.SpecularColor.b;
3466 data[3] = light.SpecularColor.a;
3467 glLightfv(lidx, GL_SPECULAR, data);
3468
3469 // set ambient color
3470 data[0] = light.AmbientColor.r;
3471 data[1] = light.AmbientColor.g;
3472 data[2] = light.AmbientColor.b;
3473 data[3] = light.AmbientColor.a;
3474 glLightfv(lidx, GL_AMBIENT, data);
3475
3476 // 1.0f / (constant + linear * d + quadratic*(d*d);
3477
3478 // set attenuation
3479 glLightf(lidx, GL_CONSTANT_ATTENUATION, light.Attenuation.X);
3480 glLightf(lidx, GL_LINEAR_ATTENUATION, light.Attenuation.Y);
3481 glLightf(lidx, GL_QUADRATIC_ATTENUATION, light.Attenuation.Z);
3482
3483 glEnable(lidx);
3484}
3485
3486
3487//! Turns a dynamic light on or off
3488//! \param lightIndex: the index returned by addDynamicLight
3489//! \param turnOn: true to turn the light on, false to turn it off
3490void COpenGLDriver::turnLightOn(s32 lightIndex, bool turnOn)
3491{
3492 if(lightIndex < 0 || lightIndex >= (s32)RequestedLights.size())
3493 return;
3494
3495 RequestedLight & requestedLight = RequestedLights[lightIndex];
3496
3497 requestedLight.DesireToBeOn = turnOn;
3498
3499 if(turnOn)
3500 {
3501 if(-1 == requestedLight.HardwareLightIndex)
3502 assignHardwareLight(lightIndex);
3503 }
3504 else
3505 {
3506 if(-1 != requestedLight.HardwareLightIndex)
3507 {
3508 // It's currently assigned, so free up the hardware light
3509 glDisable(requestedLight.HardwareLightIndex);
3510 requestedLight.HardwareLightIndex = -1;
3511
3512 // Now let the first light that's waiting on a free hardware light grab it
3513 for(u32 requested = 0; requested < RequestedLights.size(); ++requested)
3514 if(RequestedLights[requested].DesireToBeOn
3515 &&
3516 -1 == RequestedLights[requested].HardwareLightIndex)
3517 {
3518 assignHardwareLight(requested);
3519 break;
3520 }
3521 }
3522 }
3523}
3524
3525
3526//! returns the maximal amount of dynamic lights the device can handle
3527u32 COpenGLDriver::getMaximalDynamicLightAmount() const
3528{
3529 return MaxLights;
3530}
3531
3532
3533//! Sets the dynamic ambient light color. The default color is
3534//! (0,0,0,0) which means it is dark.
3535//! \param color: New color of the ambient light.
3536void COpenGLDriver::setAmbientLight(const SColorf& color)
3537{
3538 GLfloat data[4] = {color.r, color.g, color.b, color.a};
3539 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data);
3540}
3541
3542
3543// this code was sent in by Oliver Klems, thank you! (I modified the glViewport
3544// method just a bit.
3545void COpenGLDriver::setViewPort(const core::rect<s32>& area)
3546{
3547 if (area == ViewPort)
3548 return;
3549 core::rect<s32> vp = area;
3550 core::rect<s32> rendert(0,0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height);
3551 vp.clipAgainst(rendert);
3552
3553 if (vp.getHeight()>0 && vp.getWidth()>0)
3554 {
3555 glViewport(vp.UpperLeftCorner.X,
3556 getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(),
3557 vp.getWidth(), vp.getHeight());
3558
3559 ViewPort = vp;
3560 }
3561}
3562
3563
3564//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do
3565//! this: First, draw all geometry. Then use this method, to draw the shadow
3566//! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow.
3567void COpenGLDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)
3568{
3569 const u32 count=triangles.size();
3570 if (!StencilBuffer || !count)
3571 return;
3572
3573 // unset last 3d material
3574 if (CurrentRenderMode == ERM_3D &&
3575 static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
3576 {
3577 MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial();
3578 ResetRenderStates = true;
3579 }
3580
3581 // store current OpenGL state
3582 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT |
3583 GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT);
3584
3585 glDisable(GL_LIGHTING);
3586 glDisable(GL_FOG);
3587 glDepthFunc(GL_LESS);
3588 glDepthMask(GL_FALSE); // no depth buffer writing
3589 if (debugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)
3590 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
3591 if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY)))
3592 {
3593 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color buffer drawing
3594 glEnable(GL_STENCIL_TEST);
3595 }
3596
3597 glEnableClientState(GL_VERTEX_ARRAY);
3598 glVertexPointer(3,GL_FLOAT,sizeof(core::vector3df),triangles.const_pointer());
3599 glStencilMask(~0);
3600 glStencilFunc(GL_ALWAYS, 0, ~0);
3601
3602 GLenum incr = GL_INCR;
3603 GLenum decr = GL_DECR;
3604#ifdef GL_EXT_stencil_wrap
3605 if (FeatureAvailable[IRR_EXT_stencil_wrap])
3606 {
3607 incr = GL_INCR_WRAP_EXT;
3608 decr = GL_DECR_WRAP_EXT;
3609 }
3610#endif
3611#ifdef GL_NV_depth_clamp
3612 if (FeatureAvailable[IRR_NV_depth_clamp])
3613 glEnable(GL_DEPTH_CLAMP_NV);
3614#endif
3615
3616 // The first parts are not correctly working, yet.
3617#if 0
3618#ifdef GL_EXT_stencil_two_side
3619 if (FeatureAvailable[IRR_EXT_stencil_two_side])
3620 {
3621 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3622 glDisable(GL_CULL_FACE);
3623 if (zfail)
3624 {
3625 extGlActiveStencilFace(GL_BACK);
3626 glStencilOp(GL_KEEP, incr, GL_KEEP);
3627 glStencilMask(~0);
3628 glStencilFunc(GL_ALWAYS, 0, ~0);
3629
3630 extGlActiveStencilFace(GL_FRONT);
3631 glStencilOp(GL_KEEP, decr, GL_KEEP);
3632 }
3633 else // zpass
3634 {
3635 extGlActiveStencilFace(GL_BACK);
3636 glStencilOp(GL_KEEP, GL_KEEP, decr);
3637 glStencilMask(~0);
3638 glStencilFunc(GL_ALWAYS, 0, ~0);
3639
3640 extGlActiveStencilFace(GL_FRONT);
3641 glStencilOp(GL_KEEP, GL_KEEP, incr);
3642 }
3643 glStencilMask(~0);
3644 glStencilFunc(GL_ALWAYS, 0, ~0);
3645 glDrawArrays(GL_TRIANGLES,0,count);
3646 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3647 }
3648 else
3649#endif
3650 if (FeatureAvailable[IRR_ATI_separate_stencil])
3651 {
3652 glDisable(GL_CULL_FACE);
3653 if (zfail)
3654 {
3655 extGlStencilOpSeparate(GL_BACK, GL_KEEP, incr, GL_KEEP);
3656 extGlStencilOpSeparate(GL_FRONT, GL_KEEP, decr, GL_KEEP);
3657 }
3658 else // zpass
3659 {
3660 extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, decr);
3661 extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, incr);
3662 }
3663 extGlStencilFuncSeparate(GL_ALWAYS, GL_ALWAYS, 0, ~0);
3664 glStencilMask(~0);
3665 glDrawArrays(GL_TRIANGLES,0,count);
3666 }
3667 else
3668#endif
3669 {
3670 glEnable(GL_CULL_FACE);
3671 if (zfail)
3672 {
3673 glCullFace(GL_FRONT);
3674 glStencilOp(GL_KEEP, incr, GL_KEEP);
3675 glDrawArrays(GL_TRIANGLES,0,count);
3676
3677 glCullFace(GL_BACK);
3678 glStencilOp(GL_KEEP, decr, GL_KEEP);
3679 glDrawArrays(GL_TRIANGLES,0,count);
3680 }
3681 else // zpass
3682 {
3683 glCullFace(GL_BACK);
3684 glStencilOp(GL_KEEP, GL_KEEP, incr);
3685 glDrawArrays(GL_TRIANGLES,0,count);
3686
3687 glCullFace(GL_FRONT);
3688 glStencilOp(GL_KEEP, GL_KEEP, decr);
3689 glDrawArrays(GL_TRIANGLES,0,count);
3690 }
3691 }
3692#ifdef GL_NV_depth_clamp
3693 if (FeatureAvailable[IRR_NV_depth_clamp])
3694 glDisable(GL_DEPTH_CLAMP_NV);
3695#endif
3696
3697 glDisable(GL_POLYGON_OFFSET_FILL);
3698 glDisableClientState(GL_VERTEX_ARRAY); //not stored on stack
3699 glPopAttrib();
3700}
3701
3702//! Fills the stencil shadow with color. After the shadow volume has been drawn
3703//! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this
3704//! to draw the color of the shadow.
3705void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge,
3706 video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge)
3707{
3708 if (!StencilBuffer)
3709 return;
3710
3711 disableTextures();
3712
3713 // store attributes
3714 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT | GL_LIGHTING_BIT);
3715
3716 glDisable(GL_LIGHTING);
3717 glDisable(GL_FOG);
3718 glDepthMask(GL_FALSE);
3719
3720 glShadeModel(GL_FLAT);
3721 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3722
3723 glEnable(GL_BLEND);
3724 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3725
3726 glEnable(GL_STENCIL_TEST);
3727 glStencilFunc(GL_NOTEQUAL, 0, ~0);
3728 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
3729
3730 // draw a shadow rectangle covering the entire screen using stencil buffer
3731 glMatrixMode(GL_MODELVIEW);
3732 glPushMatrix();
3733 glLoadIdentity();
3734 glMatrixMode(GL_PROJECTION);
3735 glPushMatrix();
3736 glLoadIdentity();
3737
3738 glBegin(GL_QUADS);
3739
3740 glColor4ub(leftDownEdge.getRed(), leftDownEdge.getGreen(), leftDownEdge.getBlue(), leftDownEdge.getAlpha());
3741 glVertex3f(-1.f,-1.f,-0.9f);
3742
3743 glColor4ub(leftUpEdge.getRed(), leftUpEdge.getGreen(), leftUpEdge.getBlue(), leftUpEdge.getAlpha());
3744 glVertex3f(-1.f, 1.f,-0.9f);
3745
3746 glColor4ub(rightUpEdge.getRed(), rightUpEdge.getGreen(), rightUpEdge.getBlue(), rightUpEdge.getAlpha());
3747 glVertex3f(1.f, 1.f,-0.9f);
3748
3749 glColor4ub(rightDownEdge.getRed(), rightDownEdge.getGreen(), rightDownEdge.getBlue(), rightDownEdge.getAlpha());
3750 glVertex3f(1.f,-1.f,-0.9f);
3751
3752 glEnd();
3753
3754 clearBuffers(false, false, clearStencilBuffer, 0x0);
3755
3756 // restore settings
3757 glPopMatrix();
3758 glMatrixMode(GL_MODELVIEW);
3759 glPopMatrix();
3760 glPopAttrib();
3761}
3762
3763
3764//! Sets the fog mode.
3765void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start,
3766 f32 end, f32 density, bool pixelFog, bool rangeFog)
3767{
3768 CNullDriver::setFog(c, fogType, start, end, density, pixelFog, rangeFog);
3769
3770 glFogf(GL_FOG_MODE, GLfloat((fogType==EFT_FOG_LINEAR)? GL_LINEAR : (fogType==EFT_FOG_EXP)?GL_EXP:GL_EXP2));
3771
3772#ifdef GL_EXT_fog_coord
3773 if (FeatureAvailable[IRR_EXT_fog_coord])
3774 glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH);
3775#endif
3776#ifdef GL_NV_fog_distance
3777 if (FeatureAvailable[IRR_NV_fog_distance])
3778 {
3779 if (rangeFog)
3780 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV);
3781 else
3782 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
3783 }
3784#endif
3785
3786 if (fogType==EFT_FOG_LINEAR)
3787 {
3788 glFogf(GL_FOG_START, start);
3789 glFogf(GL_FOG_END, end);
3790 }
3791 else
3792 glFogf(GL_FOG_DENSITY, density);
3793
3794 if (pixelFog)
3795 glHint(GL_FOG_HINT, GL_NICEST);
3796 else
3797 glHint(GL_FOG_HINT, GL_FASTEST);
3798
3799 SColorf color(c);
3800 GLfloat data[4] = {color.r, color.g, color.b, color.a};
3801 glFogfv(GL_FOG_COLOR, data);
3802}
3803
3804
3805//! Draws a 3d line.
3806void COpenGLDriver::draw3DLine(const core::vector3df& start,
3807 const core::vector3df& end, SColor color)
3808{
3809 setRenderStates3DMode();
3810
3811 glBegin(GL_LINES);
3812 glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
3813 glVertex3f(start.X, start.Y, start.Z);
3814
3815 glVertex3f(end.X, end.Y, end.Z);
3816 glEnd();
3817}
3818
3819
3820//! Removes a texture from the texture cache and deletes it, freeing lot of memory.
3821void COpenGLDriver::removeTexture(ITexture* texture)
3822{
3823 if (!texture)
3824 return;
3825
3826 CNullDriver::removeTexture(texture);
3827 // Remove this texture from CurrentTexture as well
3828 CurrentTexture.remove(texture);
3829}
3830
3831
3832//! Only used by the internal engine. Used to notify the driver that
3833//! the window was resized.
3834void COpenGLDriver::OnResize(const core::dimension2d<u32>& size)
3835{
3836 CNullDriver::OnResize(size);
3837 glViewport(0, 0, size.Width, size.Height);
3838 Transformation3DChanged = true;
3839}
3840
3841
3842//! Returns type of video driver
3843E_DRIVER_TYPE COpenGLDriver::getDriverType() const
3844{
3845 return EDT_OPENGL;
3846}
3847
3848
3849//! returns color format
3850ECOLOR_FORMAT COpenGLDriver::getColorFormat() const
3851{
3852 return ColorFormat;
3853}
3854
3855
3856//! Sets a vertex shader constant.
3857void COpenGLDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
3858{
3859#ifdef GL_ARB_vertex_program
3860 for (s32 i=0; i<constantAmount; ++i)
3861 extGlProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, startRegister+i, &data[i*4]);
3862#endif
3863}
3864
3865//! Sets a pixel shader constant.
3866void COpenGLDriver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
3867{
3868#ifdef GL_ARB_fragment_program
3869 for (s32 i=0; i<constantAmount; ++i)
3870 extGlProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, startRegister+i, &data[i*4]);
3871#endif
3872}
3873
3874//! Sets a constant for the vertex shader based on a name.
3875bool COpenGLDriver::setVertexShaderConstant(const c8* name, const f32* floats, int count)
3876{
3877 //pass this along, as in GLSL the same routine is used for both vertex and fragment shaders
3878 return setPixelShaderConstant(name, floats, count);
3879}
3880
3881//! Bool interface for the above.
3882bool COpenGLDriver::setVertexShaderConstant(const c8* name, const bool* bools, int count)
3883{
3884 return setPixelShaderConstant(name, bools, count);
3885}
3886
3887//! Int interface for the above.
3888bool COpenGLDriver::setVertexShaderConstant(const c8* name, const s32* ints, int count)
3889{
3890 return setPixelShaderConstant(name, ints, count);
3891}
3892
3893//! Sets a constant for the pixel shader based on a name.
3894bool COpenGLDriver::setPixelShaderConstant(const c8* name, const f32* floats, int count)
3895{
3896 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");
3897 return false;
3898}
3899
3900//! Bool interface for the above.
3901bool COpenGLDriver::setPixelShaderConstant(const c8* name, const bool* bools, int count)
3902{
3903 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");
3904 return false;
3905}
3906
3907//! Int interface for the above.
3908bool COpenGLDriver::setPixelShaderConstant(const c8* name, const s32* ints, int count)
3909{
3910 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");
3911 return false;
3912}
3913
3914
3915//! Adds a new material renderer to the VideoDriver, using pixel and/or
3916//! vertex shaders to render geometry.
3917s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram,
3918 const c8* pixelShaderProgram,
3919 IShaderConstantSetCallBack* callback,
3920 E_MATERIAL_TYPE baseMaterial, s32 userData)
3921{
3922 s32 nr = -1;
3923 COpenGLShaderMaterialRenderer* r = new COpenGLShaderMaterialRenderer(
3924 this, nr, vertexShaderProgram, pixelShaderProgram,
3925 callback, getMaterialRenderer(baseMaterial), userData);
3926
3927 r->drop();
3928 return nr;
3929}
3930
3931
3932//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.
3933s32 COpenGLDriver::addHighLevelShaderMaterial(
3934 const c8* vertexShaderProgram,
3935 const c8* vertexShaderEntryPointName,
3936 E_VERTEX_SHADER_TYPE vsCompileTarget,
3937 const c8* pixelShaderProgram,
3938 const c8* pixelShaderEntryPointName,
3939 E_PIXEL_SHADER_TYPE psCompileTarget,
3940 const c8* geometryShaderProgram,
3941 const c8* geometryShaderEntryPointName,
3942 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
3943 scene::E_PRIMITIVE_TYPE inType,
3944 scene::E_PRIMITIVE_TYPE outType,
3945 u32 verticesOut,
3946 IShaderConstantSetCallBack* callback,
3947 E_MATERIAL_TYPE baseMaterial,
3948 s32 userData, E_GPU_SHADING_LANGUAGE shadingLang)
3949{
3950 s32 nr = -1;
3951
3952 #ifdef _IRR_COMPILE_WITH_CG_
3953 if (shadingLang == EGSL_CG)
3954 {
3955 COpenGLCgMaterialRenderer* r = new COpenGLCgMaterialRenderer(
3956 this, nr,
3957 vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget,
3958 pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget,
3959 geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget,
3960 inType, outType, verticesOut,
3961 callback,getMaterialRenderer(baseMaterial), userData);
3962
3963 r->drop();
3964 }
3965 else
3966 #endif
3967 {
3968 COpenGLSLMaterialRenderer* r = new COpenGLSLMaterialRenderer(
3969 this, nr,
3970 vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget,
3971 pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget,
3972 geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget,
3973 inType, outType, verticesOut,
3974 callback,getMaterialRenderer(baseMaterial), userData);
3975
3976 r->drop();
3977 }
3978
3979 return nr;
3980}
3981
3982
3983//! Returns a pointer to the IVideoDriver interface. (Implementation for
3984//! IMaterialRendererServices)
3985IVideoDriver* COpenGLDriver::getVideoDriver()
3986{
3987 return this;
3988}
3989
3990
3991ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
3992 const io::path& name,
3993 const ECOLOR_FORMAT format)
3994{
3995 //disable mip-mapping
3996 bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
3997 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);
3998
3999 video::ITexture* rtt = 0;
4000#if defined(GL_EXT_framebuffer_object)
4001 // if driver supports FrameBufferObjects, use them
4002 if (queryFeature(EVDF_FRAMEBUFFER_OBJECT))
4003 {
4004 rtt = new COpenGLFBOTexture(size, name, this, format);
4005 if (rtt)
4006 {
4007 bool success = false;
4008 addTexture(rtt);
4009 ITexture* tex = createDepthTexture(rtt);
4010 if (tex)
4011 {
4012 success = static_cast<video::COpenGLFBODepthTexture*>(tex)->attach(rtt);
4013 if ( !success )
4014 {
4015 removeDepthTexture(tex);
4016 }
4017 tex->drop();
4018 }
4019 rtt->drop();
4020 if (!success)
4021 {
4022 removeTexture(rtt);
4023 rtt=0;
4024 }
4025 }
4026 }
4027 else
4028#endif
4029 {
4030 // the simple texture is only possible for size <= screensize
4031 // we try to find an optimal size with the original constraints
4032 core::dimension2du destSize(core::min_(size.Width,ScreenSize.Width), core::min_(size.Height,ScreenSize.Height));
4033 destSize = destSize.getOptimalSize((size==size.getOptimalSize()), false, false);
4034 rtt = addTexture(destSize, name, ECF_A8R8G8B8);
4035 if (rtt)
4036 {
4037 static_cast<video::COpenGLTexture*>(rtt)->setIsRenderTarget(true);
4038 }
4039 }
4040
4041 //restore mip-mapping
4042 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);
4043
4044 return rtt;
4045}
4046
4047
4048//! Returns the maximum amount of primitives (mostly vertices) which
4049//! the device is able to render with one drawIndexedTriangleList
4050//! call.
4051u32 COpenGLDriver::getMaximalPrimitiveCount() const
4052{
4053 return 0x7fffffff;
4054}
4055
4056
4057//! set or reset render target
4058bool COpenGLDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
4059 bool clearZBuffer, SColor color)
4060{
4061 if (target != CurrentTarget)
4062 setRenderTarget(0, false, false, 0x0);
4063
4064 if (ERT_RENDER_TEXTURE == target)
4065 {
4066 os::Printer::log("For render textures call setRenderTarget with the actual texture as first parameter.", ELL_ERROR);
4067 return false;
4068 }
4069 if (ERT_MULTI_RENDER_TEXTURES == target)
4070 {
4071 os::Printer::log("For multiple render textures call setRenderTarget with the texture array as first parameter.", ELL_ERROR);
4072 return false;
4073 }
4074
4075 if (Params.Stereobuffer && (ERT_STEREO_RIGHT_BUFFER == target))
4076 {
4077 if (Params.Doublebuffer)
4078 glDrawBuffer(GL_BACK_RIGHT);
4079 else
4080 glDrawBuffer(GL_FRONT_RIGHT);
4081 }
4082 else if (Params.Stereobuffer && ERT_STEREO_BOTH_BUFFERS == target)
4083 {
4084 if (Params.Doublebuffer)
4085 glDrawBuffer(GL_BACK);
4086 else
4087 glDrawBuffer(GL_FRONT);
4088 }
4089 else if ((target >= ERT_AUX_BUFFER0) && (target-ERT_AUX_BUFFER0 < MaxAuxBuffers))
4090 {
4091 glDrawBuffer(GL_AUX0+target-ERT_AUX_BUFFER0);
4092 }
4093 else
4094 {
4095 if (Params.Doublebuffer)
4096 glDrawBuffer(GL_BACK_LEFT);
4097 else
4098 glDrawBuffer(GL_FRONT_LEFT);
4099 // exit with false, but also with working color buffer
4100 if (target != ERT_FRAME_BUFFER)
4101 return false;
4102 }
4103 CurrentTarget=target;
4104 clearBuffers(clearTarget, clearZBuffer, false, color);
4105 return true;
4106}
4107
4108
4109//! set or reset render target
4110bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer,
4111 bool clearZBuffer, SColor color)
4112{
4113 // check for right driver type
4114
4115 if (texture && texture->getDriverType() != EDT_OPENGL)
4116 {
4117 os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
4118 return false;
4119 }
4120
4121#if defined(GL_EXT_framebuffer_object)
4122 if (CurrentTarget==ERT_MULTI_RENDER_TEXTURES)
4123 {
4124 for (u32 i=0; i<MRTargets.size(); ++i)
4125 {
4126 if (MRTargets[i].TargetType==ERT_RENDER_TEXTURE)
4127 {
4128 for (++i; i<MRTargets.size(); ++i)
4129 if (MRTargets[i].TargetType==ERT_RENDER_TEXTURE)
4130 extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i, GL_TEXTURE_2D, 0, 0);
4131 }
4132 }
4133 MRTargets.clear();
4134 }
4135#endif
4136
4137 // check if we should set the previous RT back
4138 if ((RenderTargetTexture != texture) ||
4139 (CurrentTarget==ERT_MULTI_RENDER_TEXTURES))
4140 {
4141 setActiveTexture(0, 0);
4142 ResetRenderStates=true;
4143 if (RenderTargetTexture!=0)
4144 {
4145 RenderTargetTexture->unbindRTT();
4146 }
4147
4148 if (texture)
4149 {
4150 // we want to set a new target. so do this.
4151 glViewport(0, 0, texture->getSize().Width, texture->getSize().Height);
4152 RenderTargetTexture = static_cast<COpenGLTexture*>(texture);
4153 // calls glDrawBuffer as well
4154 RenderTargetTexture->bindRTT();
4155 CurrentRendertargetSize = texture->getSize();
4156 CurrentTarget=ERT_RENDER_TEXTURE;
4157 }
4158 else
4159 {
4160 glViewport(0,0,ScreenSize.Width,ScreenSize.Height);
4161 RenderTargetTexture = 0;
4162 CurrentRendertargetSize = core::dimension2d<u32>(0,0);
4163 CurrentTarget=ERT_FRAME_BUFFER;
4164 glDrawBuffer(Params.Doublebuffer?GL_BACK_LEFT:GL_FRONT_LEFT);
4165 }
4166 // we need to update the matrices due to the rendersize change.
4167 Transformation3DChanged=true;
4168 }
4169
4170 clearBuffers(clearBackBuffer, clearZBuffer, false, color);
4171
4172 return true;
4173}
4174
4175
4176//! Sets multiple render targets
4177bool COpenGLDriver::setRenderTarget(const core::array<video::IRenderTarget>& targets,
4178 bool clearBackBuffer, bool clearZBuffer, SColor color)
4179{
4180 // if simply disabling the MRT via array call
4181 if (targets.size()==0)
4182 return setRenderTarget(0, clearBackBuffer, clearZBuffer, color);
4183 // if disabling old MRT, but enabling new one as well
4184 if ((MRTargets.size()!=0) && (targets != MRTargets))
4185 setRenderTarget(0, clearBackBuffer, clearZBuffer, color);
4186 // if no change, simply clear buffers
4187 else if (targets == MRTargets)
4188 {
4189 clearBuffers(clearBackBuffer, clearZBuffer, false, color);
4190 return true;
4191 }
4192
4193 // copy to storage for correct disabling
4194 MRTargets=targets;
4195
4196 u32 maxMultipleRTTs = core::min_(static_cast<u32>(MaxMultipleRenderTargets), targets.size());
4197
4198 // determine common size
4199 core::dimension2du rttSize = CurrentRendertargetSize;
4200 if (targets[0].TargetType==ERT_RENDER_TEXTURE)
4201 {
4202 if (!targets[0].RenderTexture)
4203 {
4204 os::Printer::log("Missing render texture for MRT.", ELL_ERROR);
4205 return false;
4206 }
4207 rttSize=targets[0].RenderTexture->getSize();
4208 }
4209
4210 for (u32 i = 0; i < maxMultipleRTTs; ++i)
4211 {
4212 // check for right driver type
4213 if (targets[i].TargetType==ERT_RENDER_TEXTURE)
4214 {
4215 if (!targets[i].RenderTexture)
4216 {
4217 maxMultipleRTTs=i;
4218 os::Printer::log("Missing render texture for MRT.", ELL_WARNING);
4219 break;
4220 }
4221 if (targets[i].RenderTexture->getDriverType() != EDT_OPENGL)
4222 {
4223 maxMultipleRTTs=i;
4224 os::Printer::log("Tried to set a texture not owned by this driver.", ELL_WARNING);
4225 break;
4226 }
4227
4228 // check for valid render target
4229 if (!targets[i].RenderTexture->isRenderTarget() || !static_cast<COpenGLTexture*>(targets[i].RenderTexture)->isFrameBufferObject())
4230 {
4231 maxMultipleRTTs=i;
4232 os::Printer::log("Tried to set a non FBO-RTT as render target.", ELL_WARNING);
4233 break;
4234 }
4235
4236 // check for valid size
4237 if (rttSize != targets[i].RenderTexture->getSize())
4238 {
4239 maxMultipleRTTs=i;
4240 os::Printer::log("Render target texture has wrong size.", ELL_WARNING);
4241 break;
4242 }
4243 }
4244 }
4245 if (maxMultipleRTTs==0)
4246 {
4247 os::Printer::log("No valid MRTs.", ELL_ERROR);
4248 return false;
4249 }
4250
4251 // init FBO, if any
4252 for (u32 i=0; i<maxMultipleRTTs; ++i)
4253 {
4254 if (targets[i].TargetType==ERT_RENDER_TEXTURE)
4255 {
4256 setRenderTarget(targets[i].RenderTexture, false, false, 0x0);
4257 break; // bind only first RTT
4258 }
4259 }
4260 // init other main buffer, if necessary
4261 if (targets[0].TargetType!=ERT_RENDER_TEXTURE)
4262 setRenderTarget(targets[0].TargetType, false, false, 0x0);
4263
4264 // attach other textures and store buffers into array
4265 if (maxMultipleRTTs > 1)
4266 {
4267 CurrentTarget=ERT_MULTI_RENDER_TEXTURES;
4268 core::array<GLenum> MRTs;
4269 MRTs.set_used(maxMultipleRTTs);
4270 for(u32 i = 0; i < maxMultipleRTTs; i++)
4271 {
4272 if (FeatureAvailable[IRR_EXT_draw_buffers2])
4273 {
4274 extGlColorMaskIndexed(i,
4275 (targets[i].ColorMask & ECP_RED)?GL_TRUE:GL_FALSE,
4276 (targets[i].ColorMask & ECP_GREEN)?GL_TRUE:GL_FALSE,
4277 (targets[i].ColorMask & ECP_BLUE)?GL_TRUE:GL_FALSE,
4278 (targets[i].ColorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE);
4279 if (targets[i].BlendOp==EBO_NONE)
4280 extGlDisableIndexed(GL_BLEND, i);
4281 else
4282 extGlEnableIndexed(GL_BLEND, i);
4283 }
4284#if defined(GL_AMD_draw_buffers_blend) || defined(GL_ARB_draw_buffers_blend)
4285 if (FeatureAvailable[IRR_AMD_draw_buffers_blend] || FeatureAvailable[IRR_ARB_draw_buffers_blend])
4286 {
4287 extGlBlendFuncIndexed(i, getGLBlend(targets[i].BlendFuncSrc), getGLBlend(targets[i].BlendFuncDst));
4288 switch(targets[i].BlendOp)
4289 {
4290 case EBO_SUBTRACT:
4291 extGlBlendEquationIndexed(i, GL_FUNC_SUBTRACT);
4292 break;
4293 case EBO_REVSUBTRACT:
4294 extGlBlendEquationIndexed(i, GL_FUNC_REVERSE_SUBTRACT);
4295 break;
4296 case EBO_MIN:
4297 extGlBlendEquationIndexed(i, GL_MIN);
4298 break;
4299 case EBO_MAX:
4300 extGlBlendEquationIndexed(i, GL_MAX);
4301 break;
4302 case EBO_MIN_FACTOR:
4303 case EBO_MIN_ALPHA:
4304#if defined(GL_AMD_blend_minmax_factor)
4305 if (FeatureAvailable[IRR_AMD_blend_minmax_factor])
4306 extGlBlendEquationIndexed(i, GL_FACTOR_MIN_AMD);
4307 // fallback in case of missing extension
4308 else
4309#endif
4310 extGlBlendEquation(GL_MIN);
4311 break;
4312 case EBO_MAX_FACTOR:
4313 case EBO_MAX_ALPHA:
4314#if defined(GL_AMD_blend_minmax_factor)
4315 if (FeatureAvailable[IRR_AMD_blend_minmax_factor])
4316 extGlBlendEquationIndexed(i, GL_FACTOR_MAX_AMD);
4317 // fallback in case of missing extension
4318 else
4319#endif
4320 extGlBlendEquation(GL_MAX);
4321 break;
4322 default:
4323 extGlBlendEquationIndexed(i, GL_FUNC_ADD);
4324 break;
4325 }
4326 }
4327#endif
4328 if (targets[i].TargetType==ERT_RENDER_TEXTURE)
4329 {
4330 GLenum attachment = GL_NONE;
4331#ifdef GL_EXT_framebuffer_object
4332 // attach texture to FrameBuffer Object on Color [i]
4333 attachment = GL_COLOR_ATTACHMENT0_EXT+i;
4334 if ((i != 0) && (targets[i].RenderTexture != RenderTargetTexture))
4335 extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_2D, static_cast<COpenGLTexture*>(targets[i].RenderTexture)->getOpenGLTextureName(), 0);
4336#endif
4337 MRTs[i]=attachment;
4338 }
4339 else
4340 {
4341 switch(targets[i].TargetType)
4342 {
4343 case ERT_FRAME_BUFFER:
4344 MRTs[i]=GL_BACK_LEFT;
4345 break;
4346 case ERT_STEREO_BOTH_BUFFERS:
4347 MRTs[i]=GL_BACK;
4348 break;
4349 case ERT_STEREO_RIGHT_BUFFER:
4350 MRTs[i]=GL_BACK_RIGHT;
4351 break;
4352 case ERT_STEREO_LEFT_BUFFER:
4353 MRTs[i]=GL_BACK_LEFT;
4354 break;
4355 default:
4356 MRTs[i]=GL_AUX0+(targets[i].TargetType-ERT_AUX_BUFFER0);
4357 break;
4358 }
4359 }
4360 }
4361
4362 extGlDrawBuffers(maxMultipleRTTs, MRTs.const_pointer());
4363 }
4364
4365 clearBuffers(clearBackBuffer, clearZBuffer, false, color);
4366 return true;
4367}
4368
4369
4370// returns the current size of the screen or rendertarget
4371const core::dimension2d<u32>& COpenGLDriver::getCurrentRenderTargetSize() const
4372{
4373 if (CurrentRendertargetSize.Width == 0)
4374 return ScreenSize;
4375 else
4376 return CurrentRendertargetSize;
4377}
4378
4379
4380//! Clears the ZBuffer.
4381void COpenGLDriver::clearZBuffer()
4382{
4383 clearBuffers(false, true, false, 0x0);
4384}
4385
4386
4387//! Returns an image created from the last rendered frame.
4388IImage* COpenGLDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
4389{
4390 if (target==video::ERT_MULTI_RENDER_TEXTURES || target==video::ERT_RENDER_TEXTURE || target==video::ERT_STEREO_BOTH_BUFFERS)
4391 return 0;
4392
4393 // allows to read pixels in top-to-bottom order
4394#ifdef GL_MESA_pack_invert
4395 if (FeatureAvailable[IRR_MESA_pack_invert])
4396 glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
4397#endif
4398
4399 if (format==video::ECF_UNKNOWN)
4400 format=getColorFormat();
4401 GLenum fmt;
4402 GLenum type;
4403 switch (format)
4404 {
4405 case ECF_A1R5G5B5:
4406 fmt = GL_BGRA;
4407 type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
4408 break;
4409 case ECF_R5G6B5:
4410 fmt = GL_RGB;
4411 type = GL_UNSIGNED_SHORT_5_6_5;
4412 break;
4413 case ECF_R8G8B8:
4414 fmt = GL_RGB;
4415 type = GL_UNSIGNED_BYTE;
4416 break;
4417 case ECF_A8R8G8B8:
4418 fmt = GL_BGRA;
4419 if (Version > 101)
4420 type = GL_UNSIGNED_INT_8_8_8_8_REV;
4421 else
4422 type = GL_UNSIGNED_BYTE;
4423 break;
4424 case ECF_R16F:
4425 if (FeatureAvailable[IRR_ARB_texture_rg])
4426 fmt = GL_RED;
4427 else
4428 fmt = GL_LUMINANCE;
4429#ifdef GL_ARB_half_float_pixel
4430 if (FeatureAvailable[IRR_ARB_half_float_pixel])
4431 type = GL_HALF_FLOAT_ARB;
4432 else
4433#endif
4434 {
4435 type = GL_FLOAT;
4436 format = ECF_R32F;
4437 }
4438 break;
4439 case ECF_G16R16F:
4440#ifdef GL_ARB_texture_rg
4441 if (FeatureAvailable[IRR_ARB_texture_rg])
4442 fmt = GL_RG;
4443 else
4444#endif
4445 fmt = GL_LUMINANCE_ALPHA;
4446#ifdef GL_ARB_half_float_pixel
4447 if (FeatureAvailable[IRR_ARB_half_float_pixel])
4448 type = GL_HALF_FLOAT_ARB;
4449 else
4450#endif
4451 {
4452 type = GL_FLOAT;
4453 format = ECF_G32R32F;
4454 }
4455 break;
4456 case ECF_A16B16G16R16F:
4457 fmt = GL_BGRA;
4458#ifdef GL_ARB_half_float_pixel
4459 if (FeatureAvailable[IRR_ARB_half_float_pixel])
4460 type = GL_HALF_FLOAT_ARB;
4461 else
4462#endif
4463 {
4464 type = GL_FLOAT;
4465 format = ECF_A32B32G32R32F;
4466 }
4467 break;
4468 case ECF_R32F:
4469 if (FeatureAvailable[IRR_ARB_texture_rg])
4470 fmt = GL_RED;
4471 else
4472 fmt = GL_LUMINANCE;
4473 type = GL_FLOAT;
4474 break;
4475 case ECF_G32R32F:
4476#ifdef GL_ARB_texture_rg
4477 if (FeatureAvailable[IRR_ARB_texture_rg])
4478 fmt = GL_RG;
4479 else
4480#endif
4481 fmt = GL_LUMINANCE_ALPHA;
4482 type = GL_FLOAT;
4483 break;
4484 case ECF_A32B32G32R32F:
4485 fmt = GL_BGRA;
4486 type = GL_FLOAT;
4487 break;
4488 default:
4489 fmt = GL_BGRA;
4490 type = GL_UNSIGNED_BYTE;
4491 break;
4492 }
4493 IImage* newImage = createImage(format, ScreenSize);
4494
4495 u8* pixels = 0;
4496 if (newImage)
4497 pixels = static_cast<u8*>(newImage->lock());
4498 if (pixels)
4499 {
4500 GLenum tgt=GL_FRONT;
4501 switch (target)
4502 {
4503 case video::ERT_FRAME_BUFFER:
4504 break;
4505 case video::ERT_STEREO_LEFT_BUFFER:
4506 tgt=GL_FRONT_LEFT;
4507 break;
4508 case video::ERT_STEREO_RIGHT_BUFFER:
4509 tgt=GL_FRONT_RIGHT;
4510 break;
4511 default:
4512 tgt=GL_AUX0+(target-video::ERT_AUX_BUFFER0);
4513 break;
4514 }
4515 glReadBuffer(tgt);
4516 glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, fmt, type, pixels);
4517 testGLError();
4518 glReadBuffer(GL_BACK);
4519 }
4520
4521#ifdef GL_MESA_pack_invert
4522 if (FeatureAvailable[IRR_MESA_pack_invert])
4523 glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE);
4524 else
4525#endif
4526 if (pixels)
4527 {
4528 // opengl images are horizontally flipped, so we have to fix that here.
4529 const s32 pitch=newImage->getPitch();
4530 u8* p2 = pixels + (ScreenSize.Height - 1) * pitch;
4531 u8* tmpBuffer = new u8[pitch];
4532 for (u32 i=0; i < ScreenSize.Height; i += 2)
4533 {
4534 memcpy(tmpBuffer, pixels, pitch);
4535// for (u32 j=0; j<pitch; ++j)
4536// {
4537// pixels[j]=(u8)(p2[j]*255.f);
4538// }
4539 memcpy(pixels, p2, pitch);
4540// for (u32 j=0; j<pitch; ++j)
4541// {
4542// p2[j]=(u8)(tmpBuffer[j]*255.f);
4543// }
4544 memcpy(p2, tmpBuffer, pitch);
4545 pixels += pitch;
4546 p2 -= pitch;
4547 }
4548 delete [] tmpBuffer;
4549 }
4550
4551 if (newImage)
4552 {
4553 newImage->unlock();
4554 if (testGLError() || !pixels)
4555 {
4556 newImage->drop();
4557 return 0;
4558 }
4559 }
4560 return newImage;
4561}
4562
4563
4564//! get depth texture for the given render target texture
4565ITexture* COpenGLDriver::createDepthTexture(ITexture* texture, bool shared)
4566{
4567 if ((texture->getDriverType() != EDT_OPENGL) || (!texture->isRenderTarget()))
4568 return 0;
4569 COpenGLTexture* tex = static_cast<COpenGLTexture*>(texture);
4570
4571 if (!tex->isFrameBufferObject())
4572 return 0;
4573
4574 if (shared)
4575 {
4576 for (u32 i=0; i<DepthTextures.size(); ++i)
4577 {
4578 if (DepthTextures[i]->getSize()==texture->getSize())
4579 {
4580 DepthTextures[i]->grab();
4581 return DepthTextures[i];
4582 }
4583 }
4584 DepthTextures.push_back(new COpenGLFBODepthTexture(texture->getSize(), "depth1", this));
4585 return DepthTextures.getLast();
4586 }
4587 return (new COpenGLFBODepthTexture(texture->getSize(), "depth1", this));
4588}
4589
4590
4591void COpenGLDriver::removeDepthTexture(ITexture* texture)
4592{
4593 for (u32 i=0; i<DepthTextures.size(); ++i)
4594 {
4595 if (texture==DepthTextures[i])
4596 {
4597 DepthTextures.erase(i);
4598 return;
4599 }
4600 }
4601}
4602
4603
4604//! Set/unset a clipping plane.
4605bool COpenGLDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)
4606{
4607 if (index >= MaxUserClipPlanes)
4608 return false;
4609
4610 UserClipPlanes[index].Plane=plane;
4611 enableClipPlane(index, enable);
4612 return true;
4613}
4614
4615
4616void COpenGLDriver::uploadClipPlane(u32 index)
4617{
4618 // opengl needs an array of doubles for the plane equation
4619 GLdouble clip_plane[4];
4620 clip_plane[0] = UserClipPlanes[index].Plane.Normal.X;
4621 clip_plane[1] = UserClipPlanes[index].Plane.Normal.Y;
4622 clip_plane[2] = UserClipPlanes[index].Plane.Normal.Z;
4623 clip_plane[3] = UserClipPlanes[index].Plane.D;
4624 glClipPlane(GL_CLIP_PLANE0 + index, clip_plane);
4625}
4626
4627
4628//! Enable/disable a clipping plane.
4629void COpenGLDriver::enableClipPlane(u32 index, bool enable)
4630{
4631 if (index >= MaxUserClipPlanes)
4632 return;
4633 if (enable)
4634 {
4635 if (!UserClipPlanes[index].Enabled)
4636 {
4637 uploadClipPlane(index);
4638 glEnable(GL_CLIP_PLANE0 + index);
4639 }
4640 }
4641 else
4642 glDisable(GL_CLIP_PLANE0 + index);
4643
4644 UserClipPlanes[index].Enabled=enable;
4645}
4646
4647
4648core::dimension2du COpenGLDriver::getMaxTextureSize() const
4649{
4650 return core::dimension2du(MaxTextureSize, MaxTextureSize);
4651}
4652
4653
4654//! Convert E_PRIMITIVE_TYPE to OpenGL equivalent
4655GLenum COpenGLDriver::primitiveTypeToGL(scene::E_PRIMITIVE_TYPE type) const
4656{
4657 switch (type)
4658 {
4659 case scene::EPT_POINTS:
4660 return GL_POINTS;
4661 case scene::EPT_LINE_STRIP:
4662 return GL_LINE_STRIP;
4663 case scene::EPT_LINE_LOOP:
4664 return GL_LINE_LOOP;
4665 case scene::EPT_LINES:
4666 return GL_LINES;
4667 case scene::EPT_TRIANGLE_STRIP:
4668 return GL_TRIANGLE_STRIP;
4669 case scene::EPT_TRIANGLE_FAN:
4670 return GL_TRIANGLE_FAN;
4671 case scene::EPT_TRIANGLES:
4672 return GL_TRIANGLES;
4673 case scene::EPT_QUAD_STRIP:
4674 return GL_QUAD_STRIP;
4675 case scene::EPT_QUADS:
4676 return GL_QUADS;
4677 case scene::EPT_POLYGON:
4678 return GL_POLYGON;
4679 case scene::EPT_POINT_SPRITES:
4680#ifdef GL_ARB_point_sprite
4681 return GL_POINT_SPRITE_ARB;
4682#else
4683 return GL_POINTS;
4684#endif
4685 }
4686 return GL_TRIANGLES;
4687}
4688
4689
4690GLenum COpenGLDriver::getGLBlend(E_BLEND_FACTOR factor) const
4691{
4692 GLenum r = 0;
4693 switch (factor)
4694 {
4695 case EBF_ZERO: r = GL_ZERO; break;
4696 case EBF_ONE: r = GL_ONE; break;
4697 case EBF_DST_COLOR: r = GL_DST_COLOR; break;
4698 case EBF_ONE_MINUS_DST_COLOR: r = GL_ONE_MINUS_DST_COLOR; break;
4699 case EBF_SRC_COLOR: r = GL_SRC_COLOR; break;
4700 case EBF_ONE_MINUS_SRC_COLOR: r = GL_ONE_MINUS_SRC_COLOR; break;
4701 case EBF_SRC_ALPHA: r = GL_SRC_ALPHA; break;
4702 case EBF_ONE_MINUS_SRC_ALPHA: r = GL_ONE_MINUS_SRC_ALPHA; break;
4703 case EBF_DST_ALPHA: r = GL_DST_ALPHA; break;
4704 case EBF_ONE_MINUS_DST_ALPHA: r = GL_ONE_MINUS_DST_ALPHA; break;
4705 case EBF_SRC_ALPHA_SATURATE: r = GL_SRC_ALPHA_SATURATE; break;
4706 }
4707 return r;
4708}
4709
4710GLenum COpenGLDriver::getZBufferBits() const
4711{
4712 GLenum bits = 0;
4713 switch (Params.ZBufferBits)
4714 {
4715 case 16:
4716 bits = GL_DEPTH_COMPONENT16;
4717 break;
4718 case 24:
4719 bits = GL_DEPTH_COMPONENT24;
4720 break;
4721 case 32:
4722 bits = GL_DEPTH_COMPONENT32;
4723 break;
4724 default:
4725 bits = GL_DEPTH_COMPONENT;
4726 break;
4727 }
4728 return bits;
4729}
4730
4731#ifdef _IRR_COMPILE_WITH_CG_
4732const CGcontext& COpenGLDriver::getCgContext()
4733{
4734 return CgContext;
4735}
4736#endif
4737
4738
4739} // end namespace
4740} // end namespace
4741
4742#endif // _IRR_COMPILE_WITH_OPENGL_
4743
4744namespace irr
4745{
4746namespace video
4747{
4748
4749
4750// -----------------------------------
4751// WINDOWS VERSION
4752// -----------------------------------
4753#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
4754IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params,
4755 io::IFileSystem* io, CIrrDeviceWin32* device)
4756{
4757#ifdef _IRR_COMPILE_WITH_OPENGL_
4758 COpenGLDriver* ogl = new COpenGLDriver(params, io, device);
4759 if (!ogl->initDriver(device))
4760 {
4761 ogl->drop();
4762 ogl = 0;
4763 }
4764 return ogl;
4765#else
4766 return 0;
4767#endif // _IRR_COMPILE_WITH_OPENGL_
4768}
4769#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_
4770
4771// -----------------------------------
4772// MACOSX VERSION
4773// -----------------------------------
4774#if defined(_IRR_COMPILE_WITH_OSX_DEVICE_)
4775IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params,
4776 io::IFileSystem* io, CIrrDeviceMacOSX *device)
4777{
4778#ifdef _IRR_COMPILE_WITH_OPENGL_
4779 return new COpenGLDriver(params, io, device);
4780#else
4781 return 0;
4782#endif // _IRR_COMPILE_WITH_OPENGL_
4783}
4784#endif // _IRR_COMPILE_WITH_OSX_DEVICE_
4785
4786// -----------------------------------
4787// X11 VERSION
4788// -----------------------------------
4789#ifdef _IRR_COMPILE_WITH_X11_DEVICE_
4790IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params,
4791 io::IFileSystem* io, CIrrDeviceLinux* device)
4792{
4793#ifdef _IRR_COMPILE_WITH_OPENGL_
4794 COpenGLDriver* ogl = new COpenGLDriver(params, io, device);
4795 if (!ogl->initDriver(device))
4796 {
4797 ogl->drop();
4798 ogl = 0;
4799 }
4800 return ogl;
4801#else
4802 return 0;
4803#endif // _IRR_COMPILE_WITH_OPENGL_
4804}
4805#endif // _IRR_COMPILE_WITH_X11_DEVICE_
4806
4807
4808// -----------------------------------
4809// SDL VERSION
4810// -----------------------------------
4811#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
4812IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params,
4813 io::IFileSystem* io, CIrrDeviceSDL* device)
4814{
4815#ifdef _IRR_COMPILE_WITH_OPENGL_
4816 return new COpenGLDriver(params, io, device);
4817#else
4818 return 0;
4819#endif // _IRR_COMPILE_WITH_OPENGL_
4820}
4821#endif // _IRR_COMPILE_WITH_SDL_DEVICE_
4822
4823} // end namespace
4824} // end namespace
4825
4826