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