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