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