From 959831f4ef5a3e797f576c3de08cd65032c997ad Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 13 Jan 2013 18:54:10 +1000 Subject: Remove damned ancient DOS line endings from Irrlicht. Hopefully I did not go overboard. --- .../irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp | 9652 ++++++++++---------- 1 file changed, 4826 insertions(+), 4826 deletions(-) (limited to 'libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp') diff --git a/libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp b/libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp index 1caa9c6..67c6b72 100644 --- a/libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp +++ b/libraries/irrlicht-1.8/source/Irrlicht/COpenGLDriver.cpp @@ -1,4826 +1,4826 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "COpenGLDriver.h" -// needed here also because of the create methods' parameters -#include "CNullDriver.h" - -#ifdef _IRR_COMPILE_WITH_OPENGL_ - -#include "COpenGLTexture.h" -#include "COpenGLMaterialRenderer.h" -#include "COpenGLShaderMaterialRenderer.h" -#include "COpenGLSLMaterialRenderer.h" -#include "COpenGLCgMaterialRenderer.h" -#include "COpenGLNormalMapRenderer.h" -#include "COpenGLParallaxMapRenderer.h" -#include "os.h" - -#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ -#include -#endif - -namespace irr -{ -namespace video -{ - -// ----------------------------------------------------------------------- -// WINDOWS CONSTRUCTOR -// ----------------------------------------------------------------------- -#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ -//! Windows constructor and init code -COpenGLDriver::COpenGLDriver(const irr::SIrrlichtCreationParameters& params, - io::IFileSystem* io, CIrrDeviceWin32* device) -: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), - CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), - AntiAlias(params.AntiAlias), RenderTargetTexture(0), - CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), - CurrentTarget(ERT_FRAME_BUFFER), Params(params), - HDc(0), Window(static_cast(params.WindowId)), Win32Device(device), - DeviceType(EIDT_WIN32) -{ - #ifdef _DEBUG - setDebugName("COpenGLDriver"); - #endif - - #ifdef _IRR_COMPILE_WITH_CG_ - CgContext = 0; - #endif -} - - -bool COpenGLDriver::changeRenderContext(const SExposedVideoData& videoData, CIrrDeviceWin32* device) -{ - if (videoData.OpenGLWin32.HWnd && videoData.OpenGLWin32.HDc && videoData.OpenGLWin32.HRc) - { - if (!wglMakeCurrent((HDC)videoData.OpenGLWin32.HDc, (HGLRC)videoData.OpenGLWin32.HRc)) - { - os::Printer::log("Render Context switch failed."); - return false; - } - else - { - HDc = (HDC)videoData.OpenGLWin32.HDc; - } - } - // set back to main context - else if (HDc != ExposedData.OpenGLWin32.HDc) - { - if (!wglMakeCurrent((HDC)ExposedData.OpenGLWin32.HDc, (HGLRC)ExposedData.OpenGLWin32.HRc)) - { - os::Printer::log("Render Context switch failed."); - return false; - } - else - { - HDc = (HDC)ExposedData.OpenGLWin32.HDc; - } - } - return true; -} - -//! inits the open gl driver -bool COpenGLDriver::initDriver(CIrrDeviceWin32* device) -{ - // Create a window to test antialiasing support - const fschar_t* ClassName = __TEXT("GLCIrrDeviceWin32"); - HINSTANCE lhInstance = GetModuleHandle(0); - - // Register Class - WNDCLASSEX wcex; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = (WNDPROC)DefWindowProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = lhInstance; - wcex.hIcon = NULL; - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); - wcex.lpszMenuName = 0; - wcex.lpszClassName = ClassName; - wcex.hIconSm = 0; - wcex.hIcon = 0; - RegisterClassEx(&wcex); - - RECT clientSize; - clientSize.top = 0; - clientSize.left = 0; - clientSize.right = Params.WindowSize.Width; - clientSize.bottom = Params.WindowSize.Height; - - DWORD style = WS_POPUP; - if (!Params.Fullscreen) - style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - - AdjustWindowRect(&clientSize, style, FALSE); - - const s32 realWidth = clientSize.right - clientSize.left; - const s32 realHeight = clientSize.bottom - clientSize.top; - - const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2; - const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; - - HWND temporary_wnd=CreateWindow(ClassName, __TEXT(""), style, windowLeft, - windowTop, realWidth, realHeight, NULL, NULL, lhInstance, NULL); - - if (!temporary_wnd) - { - os::Printer::log("Cannot create a temporary window.", ELL_ERROR); - UnregisterClass(ClassName, lhInstance); - return false; - } - - HDc = GetDC(temporary_wnd); - - // Set up pixel format descriptor with desired parameters - PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor - 1, // Version Number - PFD_DRAW_TO_WINDOW | // Format Must Support Window - PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - (Params.Doublebuffer?PFD_DOUBLEBUFFER:0) | // Must Support Double Buffering - (Params.Stereobuffer?PFD_STEREO:0), // Must Support Stereo Buffer - PFD_TYPE_RGBA, // Request An RGBA Format - Params.Bits, // Select Our Color Depth - 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // No Alpha Buffer - 0, // Shift Bit Ignored - 0, // No Accumulation Buffer - 0, 0, 0, 0, // Accumulation Bits Ignored - Params.ZBufferBits, // Z-Buffer (Depth Buffer) - BYTE(Params.Stencilbuffer ? 1 : 0), // Stencil Buffer Depth - 0, // No Auxiliary Buffer - PFD_MAIN_PLANE, // Main Drawing Layer - 0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; - - GLuint PixelFormat; - - for (u32 i=0; i<6; ++i) - { - if (i == 1) - { - if (Params.Stencilbuffer) - { - os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING); - Params.Stencilbuffer = false; - pfd.cStencilBits = 0; - } - else - continue; - } - else - if (i == 2) - { - pfd.cDepthBits = 24; - } - else - if (i == 3) - { - if (Params.Bits!=16) - pfd.cDepthBits = 16; - else - continue; - } - else - if (i == 4) - { - // try single buffer - if (Params.Doublebuffer) - pfd.dwFlags &= ~PFD_DOUBLEBUFFER; - else - continue; - } - else - if (i == 5) - { - os::Printer::log("Cannot create a GL device context", "No suitable format for temporary window.", ELL_ERROR); - ReleaseDC(temporary_wnd, HDc); - DestroyWindow(temporary_wnd); - UnregisterClass(ClassName, lhInstance); - return false; - } - - // choose pixelformat - PixelFormat = ChoosePixelFormat(HDc, &pfd); - if (PixelFormat) - break; - } - - SetPixelFormat(HDc, PixelFormat, &pfd); - HGLRC hrc=wglCreateContext(HDc); - if (!hrc) - { - os::Printer::log("Cannot create a temporary GL rendering context.", ELL_ERROR); - ReleaseDC(temporary_wnd, HDc); - DestroyWindow(temporary_wnd); - UnregisterClass(ClassName, lhInstance); - return false; - } - - SExposedVideoData data; - data.OpenGLWin32.HDc = HDc; - data.OpenGLWin32.HRc = hrc; - data.OpenGLWin32.HWnd = temporary_wnd; - - - if (!changeRenderContext(data, device)) - { - os::Printer::log("Cannot activate a temporary GL rendering context.", ELL_ERROR); - wglDeleteContext(hrc); - ReleaseDC(temporary_wnd, HDc); - DestroyWindow(temporary_wnd); - UnregisterClass(ClassName, lhInstance); - return false; - } - - core::stringc wglExtensions; -#ifdef WGL_ARB_extensions_string - PFNWGLGETEXTENSIONSSTRINGARBPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); - if (irrGetExtensionsString) - wglExtensions = irrGetExtensionsString(HDc); -#elif defined(WGL_EXT_extensions_string) - PFNWGLGETEXTENSIONSSTRINGEXTPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"); - if (irrGetExtensionsString) - wglExtensions = irrGetExtensionsString(HDc); -#endif - const bool pixel_format_supported = (wglExtensions.find("WGL_ARB_pixel_format") != -1); - const bool multi_sample_supported = ((wglExtensions.find("WGL_ARB_multisample") != -1) || - (wglExtensions.find("WGL_EXT_multisample") != -1) || (wglExtensions.find("WGL_3DFX_multisample") != -1) ); -#ifdef _DEBUG - os::Printer::log("WGL_extensions", wglExtensions); -#endif - -#ifdef WGL_ARB_pixel_format - PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat_ARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); - if (pixel_format_supported && wglChoosePixelFormat_ARB) - { - // This value determines the number of samples used for antialiasing - // My experience is that 8 does not show a big - // improvement over 4, but 4 shows a big improvement - // over 2. - - if(AntiAlias > 32) - AntiAlias = 32; - - f32 fAttributes[] = {0.0, 0.0}; - s32 iAttributes[] = - { - WGL_DRAW_TO_WINDOW_ARB,1, - WGL_SUPPORT_OPENGL_ARB,1, - WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB, - WGL_COLOR_BITS_ARB,(Params.Bits==32) ? 24 : 15, - WGL_ALPHA_BITS_ARB,(Params.Bits==32) ? 8 : 1, - WGL_DEPTH_BITS_ARB,Params.ZBufferBits, // 10,11 - WGL_STENCIL_BITS_ARB,Params.Stencilbuffer ? 1 : 0, - WGL_DOUBLE_BUFFER_ARB,Params.Doublebuffer ? 1 : 0, - WGL_STEREO_ARB,Params.Stereobuffer ? 1 : 0, - WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, -#ifdef WGL_ARB_multisample - WGL_SAMPLES_ARB,AntiAlias, // 20,21 - WGL_SAMPLE_BUFFERS_ARB, 1, -#elif defined(WGL_EXT_multisample) - WGL_SAMPLES_EXT,AntiAlias, // 20,21 - WGL_SAMPLE_BUFFERS_EXT, 1, -#elif defined(WGL_3DFX_multisample) - WGL_SAMPLES_3DFX,AntiAlias, // 20,21 - WGL_SAMPLE_BUFFERS_3DFX, 1, -#endif -#ifdef WGL_ARB_framebuffer_sRGB - WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, Params.HandleSRGB ? 1:0, -#elif defined(WGL_EXT_framebuffer_sRGB) - WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT, Params.HandleSRGB ? 1:0, -#endif -// WGL_DEPTH_FLOAT_EXT, 1, - 0,0,0,0 - }; - int iAttrSize = sizeof(iAttributes)/sizeof(int); - const bool framebuffer_srgb_supported = ((wglExtensions.find("WGL_ARB_framebuffer_sRGB") != -1) || - (wglExtensions.find("WGL_EXT_framebuffer_sRGB") != -1)); - if (!framebuffer_srgb_supported) - { - memmove(&iAttributes[24],&iAttributes[26],sizeof(int)*(iAttrSize-26)); - iAttrSize -= 2; - } - if (!multi_sample_supported) - { - memmove(&iAttributes[20],&iAttributes[24],sizeof(int)*(iAttrSize-24)); - iAttrSize -= 4; - } - - s32 rv=0; - // Try to get an acceptable pixel format - do - { - int pixelFormat=0; - UINT numFormats=0; - const BOOL valid = wglChoosePixelFormat_ARB(HDc,iAttributes,fAttributes,1,&pixelFormat,&numFormats); - - if (valid && numFormats) - rv = pixelFormat; - else - iAttributes[21] -= 1; - } - while(rv==0 && iAttributes[21]>1); - if (rv) - { - PixelFormat=rv; - AntiAlias=iAttributes[21]; - } - } - else -#endif - AntiAlias=0; - - wglMakeCurrent(HDc, NULL); - wglDeleteContext(hrc); - ReleaseDC(temporary_wnd, HDc); - DestroyWindow(temporary_wnd); - UnregisterClass(ClassName, lhInstance); - - // get hdc - HDc=GetDC(Window); - if (!HDc) - { - os::Printer::log("Cannot create a GL device context.", ELL_ERROR); - return false; - } - - // search for pixel format the simple way - if (PixelFormat==0 || (!SetPixelFormat(HDc, PixelFormat, &pfd))) - { - for (u32 i=0; i<5; ++i) - { - if (i == 1) - { - if (Params.Stencilbuffer) - { - os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING); - Params.Stencilbuffer = false; - pfd.cStencilBits = 0; - } - else - continue; - } - else - if (i == 2) - { - pfd.cDepthBits = 24; - } - if (i == 3) - { - if (Params.Bits!=16) - pfd.cDepthBits = 16; - else - continue; - } - else - if (i == 4) - { - os::Printer::log("Cannot create a GL device context", "No suitable format.", ELL_ERROR); - return false; - } - - // choose pixelformat - PixelFormat = ChoosePixelFormat(HDc, &pfd); - if (PixelFormat) - break; - } - } - - // set pixel format - if (!SetPixelFormat(HDc, PixelFormat, &pfd)) - { - os::Printer::log("Cannot set the pixel format.", ELL_ERROR); - return false; - } - os::Printer::log("Pixel Format", core::stringc(PixelFormat).c_str(), ELL_DEBUG); - - // create rendering context -#ifdef WGL_ARB_create_context - PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs_ARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); - if (wglCreateContextAttribs_ARB) - { - int iAttribs[] = - { - WGL_CONTEXT_MAJOR_VERSION_ARB, 3, - WGL_CONTEXT_MINOR_VERSION_ARB, 1, - 0 - }; - hrc=wglCreateContextAttribs_ARB(HDc, 0, iAttribs); - } - else -#endif - hrc=wglCreateContext(HDc); - - if (!hrc) - { - os::Printer::log("Cannot create a GL rendering context.", ELL_ERROR); - return false; - } - - // set exposed data - ExposedData.OpenGLWin32.HDc = HDc; - ExposedData.OpenGLWin32.HRc = hrc; - ExposedData.OpenGLWin32.HWnd = Window; - - // activate rendering context - - if (!changeRenderContext(ExposedData, device)) - { - os::Printer::log("Cannot activate GL rendering context", ELL_ERROR); - wglDeleteContext(hrc); - return false; - } - - int pf = GetPixelFormat(HDc); - DescribePixelFormat(HDc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); - if (pfd.cAlphaBits != 0) - { - if (pfd.cRedBits == 8) - ColorFormat = ECF_A8R8G8B8; - else - ColorFormat = ECF_A1R5G5B5; - } - else - { - if (pfd.cRedBits == 8) - ColorFormat = ECF_R8G8B8; - else - ColorFormat = ECF_R5G6B5; - } - - genericDriverInit(); - - extGlSwapInterval(Params.Vsync ? 1 : 0); - return true; -} - -#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_ - -// ----------------------------------------------------------------------- -// MacOSX CONSTRUCTOR -// ----------------------------------------------------------------------- -#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ -//! Windows constructor and init code -COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, - io::IFileSystem* io, CIrrDeviceMacOSX *device) -: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), - CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), - AntiAlias(params.AntiAlias), RenderTargetTexture(0), - CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), - CurrentTarget(ERT_FRAME_BUFFER), Params(params), - OSXDevice(device), DeviceType(EIDT_OSX) -{ - #ifdef _DEBUG - setDebugName("COpenGLDriver"); - #endif - - #ifdef _IRR_COMPILE_WITH_CG_ - CgContext = 0; - #endif - - genericDriverInit(); -} - -#endif - -// ----------------------------------------------------------------------- -// LINUX CONSTRUCTOR -// ----------------------------------------------------------------------- -#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ -//! Linux constructor and init code -COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, - io::IFileSystem* io, CIrrDeviceLinux* device) -: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), - CurrentRenderMode(ERM_NONE), ResetRenderStates(true), - Transformation3DChanged(true), AntiAlias(params.AntiAlias), - RenderTargetTexture(0), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), - CurrentTarget(ERT_FRAME_BUFFER), Params(params), - X11Device(device), DeviceType(EIDT_X11) -{ - #ifdef _DEBUG - setDebugName("COpenGLDriver"); - #endif - - #ifdef _IRR_COMPILE_WITH_CG_ - CgContext = 0; - #endif -} - - -bool COpenGLDriver::changeRenderContext(const SExposedVideoData& videoData, CIrrDeviceLinux* device) -{ - if (videoData.OpenGLLinux.X11Window) - { - if (videoData.OpenGLLinux.X11Display && videoData.OpenGLLinux.X11Context) - { - if (!glXMakeCurrent((Display*)videoData.OpenGLLinux.X11Display, videoData.OpenGLLinux.X11Window, (GLXContext)videoData.OpenGLLinux.X11Context)) - { - os::Printer::log("Render Context switch failed."); - return false; - } - else - { - Drawable = videoData.OpenGLLinux.X11Window; - X11Display = (Display*)videoData.OpenGLLinux.X11Display; - } - } - else - { - // in case we only got a window ID, try with the existing values for display and context - if (!glXMakeCurrent((Display*)ExposedData.OpenGLLinux.X11Display, videoData.OpenGLLinux.X11Window, (GLXContext)ExposedData.OpenGLLinux.X11Context)) - { - os::Printer::log("Render Context switch failed."); - return false; - } - else - { - Drawable = videoData.OpenGLLinux.X11Window; - X11Display = (Display*)ExposedData.OpenGLLinux.X11Display; - } - } - } - // set back to main context - else if (X11Display != ExposedData.OpenGLLinux.X11Display) - { - if (!glXMakeCurrent((Display*)ExposedData.OpenGLLinux.X11Display, ExposedData.OpenGLLinux.X11Window, (GLXContext)ExposedData.OpenGLLinux.X11Context)) - { - os::Printer::log("Render Context switch failed."); - return false; - } - else - { - Drawable = ExposedData.OpenGLLinux.X11Window; - X11Display = (Display*)ExposedData.OpenGLLinux.X11Display; - } - } - return true; -} - - -//! inits the open gl driver -bool COpenGLDriver::initDriver(CIrrDeviceLinux* device) -{ - ExposedData.OpenGLLinux.X11Context = glXGetCurrentContext(); - ExposedData.OpenGLLinux.X11Display = glXGetCurrentDisplay(); - ExposedData.OpenGLLinux.X11Window = (unsigned long)Params.WindowId; - Drawable = glXGetCurrentDrawable(); - X11Display = (Display*)ExposedData.OpenGLLinux.X11Display; - - genericDriverInit(); - - // set vsync - extGlSwapInterval(Params.Vsync ? 1 : 0); - return true; -} - -#endif // _IRR_COMPILE_WITH_X11_DEVICE_ - - -// ----------------------------------------------------------------------- -// SDL CONSTRUCTOR -// ----------------------------------------------------------------------- -#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ -//! SDL constructor and init code -COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, - io::IFileSystem* io, CIrrDeviceSDL* device) -: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), - CurrentRenderMode(ERM_NONE), ResetRenderStates(true), - Transformation3DChanged(true), AntiAlias(params.AntiAlias), - RenderTargetTexture(0), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), - CurrentTarget(ERT_FRAME_BUFFER), Params(params), - SDLDevice(device), DeviceType(EIDT_SDL) -{ - #ifdef _DEBUG - setDebugName("COpenGLDriver"); - #endif - - #ifdef _IRR_COMPILE_WITH_CG_ - CgContext = 0; - #endif - - genericDriverInit(); -} - -#endif // _IRR_COMPILE_WITH_SDL_DEVICE_ - - -//! destructor -COpenGLDriver::~COpenGLDriver() -{ - #ifdef _IRR_COMPILE_WITH_CG_ - if (CgContext) - cgDestroyContext(CgContext); - #endif - - RequestedLights.clear(); - - deleteMaterialRenders(); - - CurrentTexture.clear(); - // I get a blue screen on my laptop, when I do not delete the - // textures manually before releasing the dc. Oh how I love this. - deleteAllTextures(); - removeAllOcclusionQueries(); - removeAllHardwareBuffers(); - -#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ - if (DeviceType == EIDT_WIN32) - { - - if (ExposedData.OpenGLWin32.HRc) - { - if (!wglMakeCurrent(HDc, 0)) - os::Printer::log("Release of dc and rc failed.", ELL_WARNING); - - if (!wglDeleteContext((HGLRC)ExposedData.OpenGLWin32.HRc)) - os::Printer::log("Release of rendering context failed.", ELL_WARNING); - } - - if (HDc) - ReleaseDC(Window, HDc); - } -#endif -} - -// ----------------------------------------------------------------------- -// METHODS -// ----------------------------------------------------------------------- - -bool COpenGLDriver::genericDriverInit() -{ - Name=L"OpenGL "; - Name.append(glGetString(GL_VERSION)); - s32 pos=Name.findNext(L' ', 7); - if (pos != -1) - Name=Name.subString(0, pos); - printVersion(); - - // print renderer information - const GLubyte* renderer = glGetString(GL_RENDERER); - const GLubyte* vendor = glGetString(GL_VENDOR); - if (renderer && vendor) - { - os::Printer::log(reinterpret_cast(renderer), reinterpret_cast(vendor), ELL_INFORMATION); - VendorName = reinterpret_cast(vendor); - } - - u32 i; - CurrentTexture.clear(); - // load extensions - initExtensions(Params.Stencilbuffer); - if (queryFeature(EVDF_ARB_GLSL)) - { - char buf[32]; - const u32 maj = ShaderLanguageVersion/100; - snprintf(buf, 32, "%u.%u", maj, ShaderLanguageVersion-maj*100); - os::Printer::log("GLSL version", buf, ELL_INFORMATION); - } - else - os::Printer::log("GLSL not available.", ELL_INFORMATION); - DriverAttributes->setAttribute("MaxTextures", MaxTextureUnits); - DriverAttributes->setAttribute("MaxSupportedTextures", MaxSupportedTextures); - DriverAttributes->setAttribute("MaxLights", MaxLights); - DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy); - DriverAttributes->setAttribute("MaxUserClipPlanes", MaxUserClipPlanes); - DriverAttributes->setAttribute("MaxAuxBuffers", MaxAuxBuffers); - DriverAttributes->setAttribute("MaxMultipleRenderTargets", MaxMultipleRenderTargets); - DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices); - DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize); - DriverAttributes->setAttribute("MaxGeometryVerticesOut", (s32)MaxGeometryVerticesOut); - DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias); - DriverAttributes->setAttribute("Version", Version); - DriverAttributes->setAttribute("ShaderLanguageVersion", ShaderLanguageVersion); - DriverAttributes->setAttribute("AntiAlias", AntiAlias); - - glPixelStorei(GL_PACK_ALIGNMENT, 1); - - // Reset The Current Viewport - glViewport(0, 0, Params.WindowSize.Width, Params.WindowSize.Height); - - UserClipPlanes.reallocate(MaxUserClipPlanes); - for (i=0; i(i), core::IdentityMatrix); - - setAmbientLight(SColorf(0.0f,0.0f,0.0f,0.0f)); -#ifdef GL_EXT_separate_specular_color - if (FeatureAvailable[IRR_EXT_separate_specular_color]) - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); -#endif - glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); - - Params.HandleSRGB &= ((FeatureAvailable[IRR_ARB_framebuffer_sRGB] || FeatureAvailable[IRR_EXT_framebuffer_sRGB]) && - FeatureAvailable[IRR_EXT_texture_sRGB]); -#if defined(GL_ARB_framebuffer_sRGB) - if (Params.HandleSRGB) - glEnable(GL_FRAMEBUFFER_SRGB); -#elif defined(GL_EXT_framebuffer_sRGB) - if (Params.HandleSRGB) - glEnable(GL_FRAMEBUFFER_SRGB_EXT); -#endif - -// This is a fast replacement for NORMALIZE_NORMALS -// if ((Version>101) || FeatureAvailable[IRR_EXT_rescale_normal]) -// glEnable(GL_RESCALE_NORMAL_EXT); - - glClearDepth(1.0); - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST); - glDepthFunc(GL_LEQUAL); - glFrontFace(GL_CW); - // adjust flat coloring scheme to DirectX version -#if defined(GL_ARB_provoking_vertex) || defined(GL_EXT_provoking_vertex) - extGlProvokingVertex(GL_FIRST_VERTEX_CONVENTION_EXT); -#endif - - // create material renderers - createMaterialRenderers(); - - // set the renderstates - setRenderStates3DMode(); - - glAlphaFunc(GL_GREATER, 0.f); - - // set fog mode - setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); - - // create matrix for flipping textures - TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0,0), core::vector2df(0,1.0f), core::vector2df(1.0f,-1.0f)); - - // We need to reset once more at the beginning of the first rendering. - // This fixes problems with intermediate changes to the material during texture load. - ResetRenderStates = true; - - #ifdef _IRR_COMPILE_WITH_CG_ - CgContext = cgCreateContext(); - #endif - - return true; -} - - -void COpenGLDriver::createMaterialRenderers() -{ - // create OpenGL material renderers - - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID(this)); - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID_2_LAYER(this)); - - // add the same renderer for all lightmap types - COpenGLMaterialRenderer_LIGHTMAP* lmr = new COpenGLMaterialRenderer_LIGHTMAP(this); - addMaterialRenderer(lmr); // for EMT_LIGHTMAP: - addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD: - addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2: - addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4: - addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING: - addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2: - addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4: - lmr->drop(); - - // add remaining material renderer - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_DETAIL_MAP(this)); - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SPHERE_MAP(this)); - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_REFLECTION_2_LAYER(this)); - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR(this)); - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(this)); - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(this)); - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA(this)); - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(this)); - - // add normal map renderers - s32 tmp = 0; - video::IMaterialRenderer* renderer = 0; - renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_SOLID].Renderer); - renderer->drop(); - renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); - renderer->drop(); - renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); - renderer->drop(); - - // add parallax map renderers - renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_SOLID].Renderer); - renderer->drop(); - renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); - renderer->drop(); - renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); - renderer->drop(); - - // add basic 1 texture blending - addAndDropMaterialRenderer(new COpenGLMaterialRenderer_ONETEXTURE_BLEND(this)); -} - - -//! presents the rendered scene on the screen, returns false if failed -bool COpenGLDriver::endScene() -{ - CNullDriver::endScene(); - - glFlush(); - -#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ - if (DeviceType == EIDT_WIN32) - return SwapBuffers(HDc) == TRUE; -#endif - -#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ - if (DeviceType == EIDT_X11) - { - glXSwapBuffers(X11Display, Drawable); - return true; - } -#endif - -#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ - if (DeviceType == EIDT_OSX) - { - OSXDevice->flush(); - return true; - } -#endif - -#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ - if (DeviceType == EIDT_SDL) - { - SDL_GL_SwapBuffers(); - return true; - } -#endif - - // todo: console device present - - return false; -} - - -//! clears the zbuffer and color buffer -void COpenGLDriver::clearBuffers(bool backBuffer, bool zBuffer, bool stencilBuffer, SColor color) -{ - GLbitfield mask = 0; - if (backBuffer) - { - const f32 inv = 1.0f / 255.0f; - glClearColor(color.getRed() * inv, color.getGreen() * inv, - color.getBlue() * inv, color.getAlpha() * inv); - - mask |= GL_COLOR_BUFFER_BIT; - } - - if (zBuffer) - { - glDepthMask(GL_TRUE); - LastMaterial.ZWriteEnable=true; - mask |= GL_DEPTH_BUFFER_BIT; - } - - if (stencilBuffer) - mask |= GL_STENCIL_BUFFER_BIT; - - if (mask) - glClear(mask); -} - - -//! init call for rendering start -bool COpenGLDriver::beginScene(bool backBuffer, bool zBuffer, SColor color, - const SExposedVideoData& videoData, core::rect* sourceRect) -{ - CNullDriver::beginScene(backBuffer, zBuffer, color, videoData, sourceRect); - - switch (DeviceType) - { -#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ - case EIDT_WIN32: - changeRenderContext(videoData, Win32Device); - break; -#endif -#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ - case EIDT_X11: - changeRenderContext(videoData, X11Device); - break; -#endif - default: - changeRenderContext(videoData, (void*)0); - break; - } - -#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) - if (DeviceType == EIDT_SDL) - { - // todo: SDL sets glFrontFace(GL_CCW) after driver creation, - // it would be better if this was fixed elsewhere. - glFrontFace(GL_CW); - } -#endif - - clearBuffers(backBuffer, zBuffer, false, color); - return true; -} - - -//! Returns the transformation set by setTransform -const core::matrix4& COpenGLDriver::getTransform(E_TRANSFORMATION_STATE state) const -{ - return Matrices[state]; -} - - -//! sets transformation -void COpenGLDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) -{ - Matrices[state] = mat; - Transformation3DChanged = true; - - switch (state) - { - case ETS_VIEW: - case ETS_WORLD: - { - // OpenGL only has a model matrix, view and world is not existent. so lets fake these two. - glMatrixMode(GL_MODELVIEW); - - // first load the viewing transformation for user clip planes - glLoadMatrixf((Matrices[ETS_VIEW]).pointer()); - - // we have to update the clip planes to the latest view matrix - for (u32 i=0; i= MATERIAL_MAX_TEXTURES) - break; - - const bool isRTT = Material.getTexture(i) && Material.getTexture(i)->isRenderTarget(); - - if (MultiTextureExtension) - extGlActiveTexture(GL_TEXTURE0_ARB + i); - - glMatrixMode(GL_TEXTURE); - if (!isRTT && mat.isIdentity() ) - glLoadIdentity(); - else - { - GLfloat glmat[16]; - if (isRTT) - getGLTextureMatrix(glmat, mat * TextureFlipMatrix); - else - getGLTextureMatrix(glmat, mat); - glLoadMatrixf(glmat); - } - break; - } - } -} - - -bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) -{ - if (!HWBuffer) - return false; - - if (!FeatureAvailable[IRR_ARB_vertex_buffer_object]) - return false; - -#if defined(GL_ARB_vertex_buffer_object) - const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; - const void* vertices=mb->getVertices(); - const u32 vertexCount=mb->getVertexCount(); - const E_VERTEX_TYPE vType=mb->getVertexType(); - const u32 vertexSize = getVertexPitchFromType(vType); - - const c8* vbuf = static_cast(vertices); - core::array buffer; - if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) - { - //buffer vertex data, and convert colors... - buffer.set_used(vertexSize * vertexCount); - memcpy(buffer.pointer(), vertices, vertexSize * vertexCount); - vbuf = buffer.const_pointer(); - - // in order to convert the colors into opengl format (RGBA) - switch (vType) - { - case EVT_STANDARD: - { - S3DVertex* pb = reinterpret_cast(buffer.pointer()); - const S3DVertex* po = static_cast(vertices); - for (u32 i=0; i(buffer.pointer()); - const S3DVertex2TCoords* po = static_cast(vertices); - for (u32 i=0; i(buffer.pointer()); - const S3DVertexTangents* po = static_cast(vertices); - for (u32 i=0; ivbo_verticesID) - { - extGlGenBuffers(1, &HWBuffer->vbo_verticesID); - if (!HWBuffer->vbo_verticesID) - return false; - newBuffer=true; - } - else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize) - { - newBuffer=true; - } - - extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); - - //copy data to graphics card - glGetError(); // clear error storage - if (!newBuffer) - extGlBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, vbuf); - else - { - HWBuffer->vbo_verticesSize = vertexCount*vertexSize; - - if (HWBuffer->Mapped_Vertex==scene::EHM_STATIC) - extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STATIC_DRAW); - else if (HWBuffer->Mapped_Vertex==scene::EHM_DYNAMIC) - extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_DYNAMIC_DRAW); - else //scene::EHM_STREAM - extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STREAM_DRAW); - } - - extGlBindBuffer(GL_ARRAY_BUFFER, 0); - - return (glGetError() == GL_NO_ERROR); -#else - return false; -#endif -} - - -bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) -{ - if (!HWBuffer) - return false; - - if (!FeatureAvailable[IRR_ARB_vertex_buffer_object]) - return false; - -#if defined(GL_ARB_vertex_buffer_object) - const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; - - const void* indices=mb->getIndices(); - u32 indexCount= mb->getIndexCount(); - - GLenum indexSize; - switch (mb->getIndexType()) - { - case EIT_16BIT: - { - indexSize=sizeof(u16); - break; - } - case EIT_32BIT: - { - indexSize=sizeof(u32); - break; - } - default: - { - return false; - } - } - - - //get or create buffer - bool newBuffer=false; - if (!HWBuffer->vbo_indicesID) - { - extGlGenBuffers(1, &HWBuffer->vbo_indicesID); - if (!HWBuffer->vbo_indicesID) - return false; - newBuffer=true; - } - else if (HWBuffer->vbo_indicesSize < indexCount*indexSize) - { - newBuffer=true; - } - - extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); - - //copy data to graphics card - glGetError(); // clear error storage - if (!newBuffer) - extGlBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices); - else - { - HWBuffer->vbo_indicesSize = indexCount*indexSize; - - if (HWBuffer->Mapped_Index==scene::EHM_STATIC) - extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW); - else if (HWBuffer->Mapped_Index==scene::EHM_DYNAMIC) - extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW); - else //scene::EHM_STREAM - extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STREAM_DRAW); - } - - extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - return (glGetError() == GL_NO_ERROR); -#else - return false; -#endif -} - - -//! updates hardware buffer if needed -bool COpenGLDriver::updateHardwareBuffer(SHWBufferLink *HWBuffer) -{ - if (!HWBuffer) - return false; - - if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) - { - if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex() - || !((SHWBufferLink_opengl*)HWBuffer)->vbo_verticesID) - { - - HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); - - if (!updateVertexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) - return false; - } - } - - if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) - { - if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index() - || !((SHWBufferLink_opengl*)HWBuffer)->vbo_indicesID) - { - - HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); - - if (!updateIndexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) - return false; - } - } - - return true; -} - - -//! Create hardware buffer from meshbuffer -COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::IMeshBuffer* mb) -{ -#if defined(GL_ARB_vertex_buffer_object) - if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER)) - return 0; - - SHWBufferLink_opengl *HWBuffer=new SHWBufferLink_opengl(mb); - - //add to map - HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer); - - HWBuffer->ChangedID_Vertex=HWBuffer->MeshBuffer->getChangedID_Vertex(); - HWBuffer->ChangedID_Index=HWBuffer->MeshBuffer->getChangedID_Index(); - HWBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex(); - HWBuffer->Mapped_Index=mb->getHardwareMappingHint_Index(); - HWBuffer->LastUsed=0; - HWBuffer->vbo_verticesID=0; - HWBuffer->vbo_indicesID=0; - HWBuffer->vbo_verticesSize=0; - HWBuffer->vbo_indicesSize=0; - - if (!updateHardwareBuffer(HWBuffer)) - { - deleteHardwareBuffer(HWBuffer); - return 0; - } - - return HWBuffer; -#else - return 0; -#endif -} - - -void COpenGLDriver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer) -{ - if (!_HWBuffer) - return; - -#if defined(GL_ARB_vertex_buffer_object) - SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; - if (HWBuffer->vbo_verticesID) - { - extGlDeleteBuffers(1, &HWBuffer->vbo_verticesID); - HWBuffer->vbo_verticesID=0; - } - if (HWBuffer->vbo_indicesID) - { - extGlDeleteBuffers(1, &HWBuffer->vbo_indicesID); - HWBuffer->vbo_indicesID=0; - } -#endif - - CNullDriver::deleteHardwareBuffer(_HWBuffer); -} - - -//! Draw hardware buffer -void COpenGLDriver::drawHardwareBuffer(SHWBufferLink *_HWBuffer) -{ - if (!_HWBuffer) - return; - - updateHardwareBuffer(_HWBuffer); //check if update is needed - _HWBuffer->LastUsed=0; //reset count - -#if defined(GL_ARB_vertex_buffer_object) - SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; - - const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; - const void *vertices=mb->getVertices(); - const void *indexList=mb->getIndices(); - - if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) - { - extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); - vertices=0; - } - - if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) - { - extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); - indexList=0; - } - - drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList, mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType()); - - if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) - extGlBindBuffer(GL_ARRAY_BUFFER, 0); - if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) - extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -#endif -} - - -//! Create occlusion query. -/** Use node for identification and mesh for occlusion test. */ -void COpenGLDriver::addOcclusionQuery(scene::ISceneNode* node, - const scene::IMesh* mesh) -{ - if (!queryFeature(EVDF_OCCLUSION_QUERY)) - return; - - CNullDriver::addOcclusionQuery(node, mesh); - const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); - if ((index != -1) && (OcclusionQueries[index].UID == 0)) - extGlGenQueries(1, reinterpret_cast(&OcclusionQueries[index].UID)); -} - - -//! Remove occlusion query. -void COpenGLDriver::removeOcclusionQuery(scene::ISceneNode* node) -{ - const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); - if (index != -1) - { - if (OcclusionQueries[index].UID != 0) - extGlDeleteQueries(1, reinterpret_cast(&OcclusionQueries[index].UID)); - CNullDriver::removeOcclusionQuery(node); - } -} - - -//! Run occlusion query. Draws mesh stored in query. -/** If the mesh shall not be rendered visible, use -overrideMaterial to disable the color and depth buffer. */ -void COpenGLDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible) -{ - if (!node) - return; - - const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); - if (index != -1) - { - if (OcclusionQueries[index].UID) - extGlBeginQuery( -#ifdef GL_ARB_occlusion_query - GL_SAMPLES_PASSED_ARB, -#else - 0, -#endif - OcclusionQueries[index].UID); - CNullDriver::runOcclusionQuery(node,visible); - if (OcclusionQueries[index].UID) - extGlEndQuery( -#ifdef GL_ARB_occlusion_query - GL_SAMPLES_PASSED_ARB); -#else - 0); -#endif - testGLError(); - } -} - - -//! Update occlusion query. Retrieves results from GPU. -/** If the query shall not block, set the flag to false. -Update might not occur in this case, though */ -void COpenGLDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block) -{ - const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); - if (index != -1) - { - // not yet started - if (OcclusionQueries[index].Run==u32(~0)) - return; - GLint available = block?GL_TRUE:GL_FALSE; - if (!block) - extGlGetQueryObjectiv(OcclusionQueries[index].UID, -#ifdef GL_ARB_occlusion_query - GL_QUERY_RESULT_AVAILABLE_ARB, -#elif defined(GL_NV_occlusion_query) - GL_PIXEL_COUNT_AVAILABLE_NV, -#else - 0, -#endif - &available); - testGLError(); - if (available==GL_TRUE) - { - extGlGetQueryObjectiv(OcclusionQueries[index].UID, -#ifdef GL_ARB_occlusion_query - GL_QUERY_RESULT_ARB, -#elif defined(GL_NV_occlusion_query) - GL_PIXEL_COUNT_NV, -#else - 0, -#endif - &available); - if (queryFeature(EVDF_OCCLUSION_QUERY)) - OcclusionQueries[index].Result = available; - } - testGLError(); - } -} - - -//! Return query result. -/** Return value is the number of visible pixels/fragments. -The value is a safe approximation, i.e. can be larger than the -actual value of pixels. */ -u32 COpenGLDriver::getOcclusionQueryResult(scene::ISceneNode* node) const -{ - const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); - if (index != -1) - return OcclusionQueries[index].Result; - else - return ~0; -} - - -// small helper function to create vertex buffer object adress offsets -static inline u8* buffer_offset(const long offset) -{ - return ((u8*)0 + offset); -} - - -//! draws a vertex primitive list -void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, - const void* indexList, u32 primitiveCount, - E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) -{ - if (!primitiveCount || !vertexCount) - return; - - if (!checkPrimitiveCount(primitiveCount)) - return; - - CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); - - if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) - getColorBuffer(vertices, vertexCount, vType); - - // draw everything - setRenderStates3DMode(); - - if (MultiTextureExtension) - extGlClientActiveTexture(GL_TEXTURE0_ARB); - - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) - glEnableClientState(GL_NORMAL_ARRAY); - -//due to missing defines in OSX headers, we have to be more specific with this check -//#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra) -#ifdef GL_BGRA - const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; -#else - const GLint colorSize=4; -#endif - if (vertices) - { - if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) - { - switch (vType) - { - case EVT_STANDARD: - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); - break; - case EVT_2TCOORDS: - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Color); - break; - case EVT_TANGENTS: - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Color); - break; - } - } - else - { - // avoid passing broken pointer to OpenGL - _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); - glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); - } - } - - switch (vType) - { - case EVT_STANDARD: - if (vertices) - { - glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Normal); - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); - glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); - } - else - { - glNormalPointer(GL_FLOAT, sizeof(S3DVertex), buffer_offset(12)); - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24)); - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); - glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), 0); - } - - if (MultiTextureExtension && CurrentTexture[1]) - { - extGlClientActiveTexture(GL_TEXTURE1_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (vertices) - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); - else - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); - } - break; - case EVT_2TCOORDS: - if (vertices) - { - glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Normal); - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords); - glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Pos); - } - else - { - glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(12)); - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24)); - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28)); - glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0)); - } - - - if (MultiTextureExtension) - { - extGlClientActiveTexture(GL_TEXTURE1_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (vertices) - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords2); - else - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36)); - } - break; - case EVT_TANGENTS: - if (vertices) - { - glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Normal); - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].TCoords); - glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Pos); - } - else - { - glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12)); - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24)); - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28)); - glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0)); - } - - if (MultiTextureExtension) - { - extGlClientActiveTexture(GL_TEXTURE1_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (vertices) - glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Tangent); - else - glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36)); - - extGlClientActiveTexture(GL_TEXTURE2_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (vertices) - glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Binormal); - else - glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48)); - } - break; - } - - renderArray(indexList, primitiveCount, pType, iType); - - if (MultiTextureExtension) - { - if (vType==EVT_TANGENTS) - { - extGlClientActiveTexture(GL_TEXTURE2_ARB); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - if ((vType!=EVT_STANDARD) || CurrentTexture[1]) - { - extGlClientActiveTexture(GL_TEXTURE1_ARB); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - extGlClientActiveTexture(GL_TEXTURE0_ARB); - } - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); -} - - -void COpenGLDriver::getColorBuffer(const void* vertices, u32 vertexCount, E_VERTEX_TYPE vType) -{ - // convert colors to gl color format. - vertexCount *= 4; //reused as color component count - ColorBuffer.set_used(vertexCount); - u32 i; - - switch (vType) - { - case EVT_STANDARD: - { - const S3DVertex* p = static_cast(vertices); - for (i=0; iColor.toOpenGLColor(&ColorBuffer[i]); - ++p; - } - } - break; - case EVT_2TCOORDS: - { - const S3DVertex2TCoords* p = static_cast(vertices); - for (i=0; iColor.toOpenGLColor(&ColorBuffer[i]); - ++p; - } - } - break; - case EVT_TANGENTS: - { - const S3DVertexTangents* p = static_cast(vertices); - for (i=0; iColor.toOpenGLColor(&ColorBuffer[i]); - ++p; - } - } - break; - } -} - - -void COpenGLDriver::renderArray(const void* indexList, u32 primitiveCount, - scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) -{ - GLenum indexSize=0; - - switch (iType) - { - case EIT_16BIT: - { - indexSize=GL_UNSIGNED_SHORT; - break; - } - case EIT_32BIT: - { - indexSize=GL_UNSIGNED_INT; - break; - } - } - - switch (pType) - { - case scene::EPT_POINTS: - case scene::EPT_POINT_SPRITES: - { -#ifdef GL_ARB_point_sprite - if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) - glEnable(GL_POINT_SPRITE_ARB); -#endif - - // prepare size and attenuation (where supported) - GLfloat particleSize=Material.Thickness; -// if (AntiAlias) -// particleSize=core::clamp(particleSize, DimSmoothedPoint[0], DimSmoothedPoint[1]); -// else - particleSize=core::clamp(particleSize, DimAliasedPoint[0], DimAliasedPoint[1]); -#if defined(GL_VERSION_1_4) || defined(GL_ARB_point_parameters) || defined(GL_EXT_point_parameters) || defined(GL_SGIS_point_parameters) - const float att[] = {1.0f, 1.0f, 0.0f}; -#if defined(GL_VERSION_1_4) - extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, att); -// extGlPointParameterf(GL_POINT_SIZE_MIN,1.f); - extGlPointParameterf(GL_POINT_SIZE_MAX, particleSize); - extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE, 1.0f); -#elif defined(GL_ARB_point_parameters) - extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION_ARB, att); -// extGlPointParameterf(GL_POINT_SIZE_MIN_ARB,1.f); - extGlPointParameterf(GL_POINT_SIZE_MAX_ARB, particleSize); - extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0f); -#elif defined(GL_EXT_point_parameters) - extGlPointParameterfv(GL_DISTANCE_ATTENUATION_EXT, att); -// extGlPointParameterf(GL_POINT_SIZE_MIN_EXT,1.f); - extGlPointParameterf(GL_POINT_SIZE_MAX_EXT, particleSize); - extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0f); -#elif defined(GL_SGIS_point_parameters) - extGlPointParameterfv(GL_DISTANCE_ATTENUATION_SGIS, att); -// extGlPointParameterf(GL_POINT_SIZE_MIN_SGIS,1.f); - extGlPointParameterf(GL_POINT_SIZE_MAX_SGIS, particleSize); - extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_SGIS, 1.0f); -#endif -#endif - glPointSize(particleSize); - -#ifdef GL_ARB_point_sprite - if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) - glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_TRUE); -#endif - glDrawArrays(GL_POINTS, 0, primitiveCount); -#ifdef GL_ARB_point_sprite - if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) - { - glDisable(GL_POINT_SPRITE_ARB); - glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_FALSE); - } -#endif - } - break; - case scene::EPT_LINE_STRIP: - glDrawElements(GL_LINE_STRIP, primitiveCount+1, indexSize, indexList); - break; - case scene::EPT_LINE_LOOP: - glDrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList); - break; - case scene::EPT_LINES: - glDrawElements(GL_LINES, primitiveCount*2, indexSize, indexList); - break; - case scene::EPT_TRIANGLE_STRIP: - glDrawElements(GL_TRIANGLE_STRIP, primitiveCount+2, indexSize, indexList); - break; - case scene::EPT_TRIANGLE_FAN: - glDrawElements(GL_TRIANGLE_FAN, primitiveCount+2, indexSize, indexList); - break; - case scene::EPT_TRIANGLES: - glDrawElements(GL_TRIANGLES, primitiveCount*3, indexSize, indexList); - break; - case scene::EPT_QUAD_STRIP: - glDrawElements(GL_QUAD_STRIP, primitiveCount*2+2, indexSize, indexList); - break; - case scene::EPT_QUADS: - glDrawElements(GL_QUADS, primitiveCount*4, indexSize, indexList); - break; - case scene::EPT_POLYGON: - glDrawElements(GL_POLYGON, primitiveCount, indexSize, indexList); - break; - } -} - - -//! draws a vertex primitive list in 2d -void COpenGLDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, - const void* indexList, u32 primitiveCount, - E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) -{ - if (!primitiveCount || !vertexCount) - return; - - if (!checkPrimitiveCount(primitiveCount)) - return; - - CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); - - if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) - getColorBuffer(vertices, vertexCount, vType); - - // draw everything - this->setActiveTexture(0, Material.getTexture(0)); - if (Material.MaterialType==EMT_ONETEXTURE_BLEND) - { - E_BLEND_FACTOR srcFact; - E_BLEND_FACTOR dstFact; - E_MODULATE_FUNC modulo; - u32 alphaSource; - unpack_textureBlendFunc ( srcFact, dstFact, modulo, alphaSource, Material.MaterialTypeParam); - setRenderStates2DMode(alphaSource&video::EAS_VERTEX_COLOR, (Material.getTexture(0) != 0), (alphaSource&video::EAS_TEXTURE) != 0); - } - else - setRenderStates2DMode(Material.MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA, (Material.getTexture(0) != 0), Material.MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL); - - if (MultiTextureExtension) - extGlClientActiveTexture(GL_TEXTURE0_ARB); - - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - -//due to missing defines in OSX headers, we have to be more specific with this check -//#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra) -#ifdef GL_BGRA - const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; -#else - const GLint colorSize=4; -#endif - if (vertices) - { - if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) - { - switch (vType) - { - case EVT_STANDARD: - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); - break; - case EVT_2TCOORDS: - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Color); - break; - case EVT_TANGENTS: - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Color); - break; - } - } - else - { - // avoid passing broken pointer to OpenGL - _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); - glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); - } - } - - switch (vType) - { - case EVT_STANDARD: - if (vertices) - { - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); - glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); - } - else - { - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24)); - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); - glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), 0); - } - - if (MultiTextureExtension && CurrentTexture[1]) - { - extGlClientActiveTexture(GL_TEXTURE1_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (vertices) - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); - else - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); - } - break; - case EVT_2TCOORDS: - if (vertices) - { - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords); - glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Pos); - } - else - { - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24)); - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28)); - glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0)); - } - - if (MultiTextureExtension) - { - extGlClientActiveTexture(GL_TEXTURE1_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (vertices) - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords2); - else - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36)); - } - break; - case EVT_TANGENTS: - if (vertices) - { - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].TCoords); - glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Pos); - } - else - { - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24)); - glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28)); - glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0)); - } - - break; - } - - renderArray(indexList, primitiveCount, pType, iType); - - if (MultiTextureExtension) - { - if ((vType!=EVT_STANDARD) || CurrentTexture[1]) - { - extGlClientActiveTexture(GL_TEXTURE1_ARB); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - extGlClientActiveTexture(GL_TEXTURE0_ARB); - } - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); -} - - -//! draws a set of 2d images, using a color and the alpha channel of the -//! texture if desired. -void COpenGLDriver::draw2DImageBatch(const video::ITexture* texture, - const core::array >& positions, - const core::array >& sourceRects, - const core::rect* clipRect, - SColor color, - bool useAlphaChannelOfTexture) -{ - if (!texture) - return; - - const u32 drawCount = core::min_(positions.size(), sourceRects.size()); - - const core::dimension2d& ss = texture->getOriginalSize(); - const f32 invW = 1.f / static_cast(ss.Width); - const f32 invH = 1.f / static_cast(ss.Height); - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - - disableTextures(1); - if (!setActiveTexture(0, texture)) - return; - setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); - - glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); - glBegin(GL_QUADS); - - for (u32 i=0; i targetPos(positions[i]); - core::position2d sourcePos(sourceRects[i].UpperLeftCorner); - // This needs to be signed as it may go negative. - core::dimension2d sourceSize(sourceRects[i].getSize()); - if (clipRect) - { - if (targetPos.X < clipRect->UpperLeftCorner.X) - { - sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; - if (sourceSize.Width <= 0) - continue; - - sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; - targetPos.X = clipRect->UpperLeftCorner.X; - } - - if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) - { - sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; - if (sourceSize.Width <= 0) - continue; - } - - if (targetPos.Y < clipRect->UpperLeftCorner.Y) - { - sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; - if (sourceSize.Height <= 0) - continue; - - sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; - targetPos.Y = clipRect->UpperLeftCorner.Y; - } - - if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) - { - sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; - if (sourceSize.Height <= 0) - continue; - } - } - - // clip these coordinates - - if (targetPos.X<0) - { - sourceSize.Width += targetPos.X; - if (sourceSize.Width <= 0) - continue; - - sourcePos.X -= targetPos.X; - targetPos.X = 0; - } - - if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) - { - sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; - if (sourceSize.Width <= 0) - continue; - } - - if (targetPos.Y<0) - { - sourceSize.Height += targetPos.Y; - if (sourceSize.Height <= 0) - continue; - - sourcePos.Y -= targetPos.Y; - targetPos.Y = 0; - } - - if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) - { - sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; - if (sourceSize.Height <= 0) - continue; - } - - // ok, we've clipped everything. - // now draw it. - - const core::rect tcoords( - sourcePos.X * invW, - sourcePos.Y * invH, - (sourcePos.X + sourceSize.Width) * invW, - (sourcePos.Y + sourceSize.Height) * invH); - - const core::rect poss(targetPos, sourceSize); - - glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); - glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y)); - - glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); - glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y)); - - glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); - glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y)); - - glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); - glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y)); - } - glEnd(); -} - - -//! draws a 2d image, using a color and the alpha channel of the texture if -//! desired. The image is drawn at pos, clipped against clipRect (if != 0). -//! Only the subtexture defined by sourceRect is used. -void COpenGLDriver::draw2DImage(const video::ITexture* texture, - const core::position2d& pos, - const core::rect& sourceRect, - const core::rect* clipRect, SColor color, - bool useAlphaChannelOfTexture) -{ - if (!texture) - return; - - if (!sourceRect.isValid()) - return; - - core::position2d targetPos(pos); - core::position2d sourcePos(sourceRect.UpperLeftCorner); - // This needs to be signed as it may go negative. - core::dimension2d sourceSize(sourceRect.getSize()); - if (clipRect) - { - if (targetPos.X < clipRect->UpperLeftCorner.X) - { - sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; - if (sourceSize.Width <= 0) - return; - - sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; - targetPos.X = clipRect->UpperLeftCorner.X; - } - - if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) - { - sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; - if (sourceSize.Width <= 0) - return; - } - - if (targetPos.Y < clipRect->UpperLeftCorner.Y) - { - sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; - if (sourceSize.Height <= 0) - return; - - sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; - targetPos.Y = clipRect->UpperLeftCorner.Y; - } - - if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) - { - sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; - if (sourceSize.Height <= 0) - return; - } - } - - // clip these coordinates - - if (targetPos.X<0) - { - sourceSize.Width += targetPos.X; - if (sourceSize.Width <= 0) - return; - - sourcePos.X -= targetPos.X; - targetPos.X = 0; - } - - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - - if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) - { - sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; - if (sourceSize.Width <= 0) - return; - } - - if (targetPos.Y<0) - { - sourceSize.Height += targetPos.Y; - if (sourceSize.Height <= 0) - return; - - sourcePos.Y -= targetPos.Y; - targetPos.Y = 0; - } - - if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) - { - sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; - if (sourceSize.Height <= 0) - return; - } - - // ok, we've clipped everything. - // now draw it. - - const core::dimension2d& ss = texture->getOriginalSize(); - const f32 invW = 1.f / static_cast(ss.Width); - const f32 invH = 1.f / static_cast(ss.Height); - const core::rect tcoords( - sourcePos.X * invW, - sourcePos.Y * invH, - (sourcePos.X + sourceSize.Width) * invW, - (sourcePos.Y + sourceSize.Height) * invH); - - const core::rect poss(targetPos, sourceSize); - - disableTextures(1); - if (!setActiveTexture(0, texture)) - return; - setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); - - glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); - glBegin(GL_QUADS); - - glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); - glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y)); - - glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); - glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y)); - - glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); - glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y)); - - glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); - glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y)); - - glEnd(); -} - - -//! The same, but with a four element array of colors, one for each vertex -void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, - const core::rect& sourceRect, const core::rect* clipRect, - const video::SColor* const colors, bool useAlphaChannelOfTexture) -{ - if (!texture) - return; - - const core::dimension2d& ss = texture->getOriginalSize(); - const f32 invW = 1.f / static_cast(ss.Width); - const f32 invH = 1.f / static_cast(ss.Height); - const core::rect tcoords( - sourceRect.UpperLeftCorner.X * invW, - sourceRect.UpperLeftCorner.Y * invH, - sourceRect.LowerRightCorner.X * invW, - sourceRect.LowerRightCorner.Y *invH); - - const video::SColor temp[4] = - { - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF - }; - - const video::SColor* const useColor = colors ? colors : temp; - - disableTextures(1); - setActiveTexture(0, texture); - setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 || - useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255, - true, useAlphaChannelOfTexture); - - if (clipRect) - { - if (!clipRect->isValid()) - return; - - glEnable(GL_SCISSOR_TEST); - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, - clipRect->getWidth(), clipRect->getHeight()); - } - - glBegin(GL_QUADS); - - glColor4ub(useColor[0].getRed(), useColor[0].getGreen(), useColor[0].getBlue(), useColor[0].getAlpha()); - glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); - glVertex2f(GLfloat(destRect.UpperLeftCorner.X), GLfloat(destRect.UpperLeftCorner.Y)); - - glColor4ub(useColor[3].getRed(), useColor[3].getGreen(), useColor[3].getBlue(), useColor[3].getAlpha()); - glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); - glVertex2f(GLfloat(destRect.LowerRightCorner.X), GLfloat(destRect.UpperLeftCorner.Y)); - - glColor4ub(useColor[2].getRed(), useColor[2].getGreen(), useColor[2].getBlue(), useColor[2].getAlpha()); - glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); - glVertex2f(GLfloat(destRect.LowerRightCorner.X), GLfloat(destRect.LowerRightCorner.Y)); - - glColor4ub(useColor[1].getRed(), useColor[1].getGreen(), useColor[1].getBlue(), useColor[1].getAlpha()); - glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); - glVertex2f(GLfloat(destRect.UpperLeftCorner.X), GLfloat(destRect.LowerRightCorner.Y)); - - glEnd(); - - if (clipRect) - glDisable(GL_SCISSOR_TEST); -} - - -//! draws a set of 2d images, using a color and the alpha channel of the -//! texture if desired. The images are drawn beginning at pos and concatenated -//! in one line. All drawings are clipped against clipRect (if != 0). -//! The subtextures are defined by the array of sourceRects and are chosen -//! by the indices given. -void COpenGLDriver::draw2DImage(const video::ITexture* texture, - const core::position2d& pos, - const core::array >& sourceRects, - const core::array& indices, - const core::rect* clipRect, SColor color, - bool useAlphaChannelOfTexture) -{ - if (!texture) - return; - - disableTextures(1); - if (!setActiveTexture(0, texture)) - return; - setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); - - glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); - if (clipRect) - { - if (!clipRect->isValid()) - return; - - glEnable(GL_SCISSOR_TEST); - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, - clipRect->getWidth(),clipRect->getHeight()); - } - - const core::dimension2d& ss = texture->getOriginalSize(); - core::position2d targetPos(pos); - const f32 invW = 1.f / static_cast(ss.Width); - const f32 invH = 1.f / static_cast(ss.Height); - - for (u32 i=0; i tcoords( - sourceRects[currentIndex].UpperLeftCorner.X * invW, - sourceRects[currentIndex].UpperLeftCorner.Y * invH, - sourceRects[currentIndex].LowerRightCorner.X * invW, - sourceRects[currentIndex].LowerRightCorner.Y * invH); - - const core::rect poss(targetPos, sourceRects[currentIndex].getSize()); - - glBegin(GL_QUADS); - - glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); - glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y)); - - glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); - glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y)); - - glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); - glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y)); - - glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); - glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y)); - - glEnd(); - targetPos.X += sourceRects[currentIndex].getWidth(); - } - if (clipRect) - glDisable(GL_SCISSOR_TEST); -} - - -//! draw a 2d rectangle -void COpenGLDriver::draw2DRectangle(SColor color, const core::rect& position, - const core::rect* clip) -{ - disableTextures(); - setRenderStates2DMode(color.getAlpha() < 255, false, false); - - core::rect pos = position; - - if (clip) - pos.clipAgainst(*clip); - - if (!pos.isValid()) - return; - - glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); - glRectf(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y), - GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y)); -} - - -//! draw an 2d rectangle -void COpenGLDriver::draw2DRectangle(const core::rect& position, - SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, - const core::rect* clip) -{ - core::rect pos = position; - - if (clip) - pos.clipAgainst(*clip); - - if (!pos.isValid()) - return; - - disableTextures(); - - setRenderStates2DMode(colorLeftUp.getAlpha() < 255 || - colorRightUp.getAlpha() < 255 || - colorLeftDown.getAlpha() < 255 || - colorRightDown.getAlpha() < 255, false, false); - - glBegin(GL_QUADS); - glColor4ub(colorLeftUp.getRed(), colorLeftUp.getGreen(), - colorLeftUp.getBlue(), colorLeftUp.getAlpha()); - glVertex2f(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y)); - - glColor4ub(colorRightUp.getRed(), colorRightUp.getGreen(), - colorRightUp.getBlue(), colorRightUp.getAlpha()); - glVertex2f(GLfloat(pos.LowerRightCorner.X), GLfloat(pos.UpperLeftCorner.Y)); - - glColor4ub(colorRightDown.getRed(), colorRightDown.getGreen(), - colorRightDown.getBlue(), colorRightDown.getAlpha()); - glVertex2f(GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y)); - - glColor4ub(colorLeftDown.getRed(), colorLeftDown.getGreen(), - colorLeftDown.getBlue(), colorLeftDown.getAlpha()); - glVertex2f(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.LowerRightCorner.Y)); - - glEnd(); -} - - -//! Draws a 2d line. -void COpenGLDriver::draw2DLine(const core::position2d& start, - const core::position2d& end, SColor color) -{ - if (start==end) - drawPixel(start.X, start.Y, color); - else - { - disableTextures(); - setRenderStates2DMode(color.getAlpha() < 255, false, false); - - glBegin(GL_LINES); - glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); - GLfloat x=(GLfloat)start.X; - GLfloat y=(GLfloat)start.Y; - if (x>end.X) - x += 0.5f; - if (y>end.Y) - y += 0.5f; - glVertex2f(GLfloat(x), GLfloat(y)); - x=(GLfloat)end.X; - y=(GLfloat)end.Y; - if (x>start.X) - x += 0.5f; - if (y>start.Y) - y += 0.5f; - glVertex2f(GLfloat(x), GLfloat(y)); - glEnd(); - } -} - -//! Draws a pixel -void COpenGLDriver::drawPixel(u32 x, u32 y, const SColor &color) -{ - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) - return; - - disableTextures(); - setRenderStates2DMode(color.getAlpha() < 255, false, false); - - glBegin(GL_POINTS); - glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); - glVertex2i(x, y); - glEnd(); -} - -bool COpenGLDriver::setActiveTexture(u32 stage, const video::ITexture* texture) -{ - if (stage >= MaxSupportedTextures) - return false; - - if (CurrentTexture[stage]==texture) - return true; - - if (MultiTextureExtension) - extGlActiveTexture(GL_TEXTURE0_ARB + stage); - - CurrentTexture.set(stage,texture); - - if (!texture) - { - glDisable(GL_TEXTURE_2D); - return true; - } - else - { - if (texture->getDriverType() != EDT_OPENGL) - { - glDisable(GL_TEXTURE_2D); - CurrentTexture.set(stage, 0); - os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); - return false; - } - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, - static_cast(texture)->getOpenGLTextureName()); - } - return true; -} - - -//! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled. -//! Returns whether disabling was successful or not. -bool COpenGLDriver::disableTextures(u32 fromStage) -{ - bool result=true; - for (u32 i=fromStage; i= 0; --i) - { - setActiveTexture(i, material.getTexture(i)); - setTransform ((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i), - Material.getTextureMatrix(i)); - } -} - - -//! prints error if an error happened. -bool COpenGLDriver::testGLError() -{ -#ifdef _DEBUG - GLenum g = glGetError(); - switch (g) - { - case GL_NO_ERROR: - return false; - case GL_INVALID_ENUM: - os::Printer::log("GL_INVALID_ENUM", ELL_ERROR); break; - case GL_INVALID_VALUE: - os::Printer::log("GL_INVALID_VALUE", ELL_ERROR); break; - case GL_INVALID_OPERATION: - os::Printer::log("GL_INVALID_OPERATION", ELL_ERROR); break; - case GL_STACK_OVERFLOW: - os::Printer::log("GL_STACK_OVERFLOW", ELL_ERROR); break; - case GL_STACK_UNDERFLOW: - os::Printer::log("GL_STACK_UNDERFLOW", ELL_ERROR); break; - case GL_OUT_OF_MEMORY: - os::Printer::log("GL_OUT_OF_MEMORY", ELL_ERROR); break; - case GL_TABLE_TOO_LARGE: - os::Printer::log("GL_TABLE_TOO_LARGE", ELL_ERROR); break; -#if defined(GL_EXT_framebuffer_object) - case GL_INVALID_FRAMEBUFFER_OPERATION_EXT: - os::Printer::log("GL_INVALID_FRAMEBUFFER_OPERATION", ELL_ERROR); break; -#endif - }; -// _IRR_DEBUG_BREAK_IF(true); - return true; -#else - return false; -#endif -} - - -//! sets the needed renderstates -void COpenGLDriver::setRenderStates3DMode() -{ - if (CurrentRenderMode != ERM_3D) - { - // Reset Texture Stages - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // switch back the matrices - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer()); - - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(Matrices[ETS_PROJECTION].pointer()); - - ResetRenderStates = true; -#ifdef GL_EXT_clip_volume_hint - if (FeatureAvailable[IRR_EXT_clip_volume_hint]) - glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_NICEST); -#endif - } - - if (ResetRenderStates || LastMaterial != Material) - { - // unset old material - - if (LastMaterial.MaterialType != Material.MaterialType && - static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) - MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); - - // set new material. - if (static_cast(Material.MaterialType) < MaterialRenderers.size()) - MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial( - Material, LastMaterial, ResetRenderStates, this); - - LastMaterial = Material; - ResetRenderStates = false; - } - - if (static_cast(Material.MaterialType) < MaterialRenderers.size()) - MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD); - - CurrentRenderMode = ERM_3D; -} - - -//! Get native wrap mode value -GLint COpenGLDriver::getTextureWrapMode(const u8 clamp) -{ - GLint mode=GL_REPEAT; - switch (clamp) - { - case ETC_REPEAT: - mode=GL_REPEAT; - break; - case ETC_CLAMP: - mode=GL_CLAMP; - break; - case ETC_CLAMP_TO_EDGE: -#ifdef GL_VERSION_1_2 - if (Version>101) - mode=GL_CLAMP_TO_EDGE; - else -#endif -#ifdef GL_SGIS_texture_edge_clamp - if (FeatureAvailable[IRR_SGIS_texture_edge_clamp]) - mode=GL_CLAMP_TO_EDGE_SGIS; - else -#endif - // fallback - mode=GL_CLAMP; - break; - case ETC_CLAMP_TO_BORDER: -#ifdef GL_VERSION_1_3 - if (Version>102) - mode=GL_CLAMP_TO_BORDER; - else -#endif -#ifdef GL_ARB_texture_border_clamp - if (FeatureAvailable[IRR_ARB_texture_border_clamp]) - mode=GL_CLAMP_TO_BORDER_ARB; - else -#endif -#ifdef GL_SGIS_texture_border_clamp - if (FeatureAvailable[IRR_SGIS_texture_border_clamp]) - mode=GL_CLAMP_TO_BORDER_SGIS; - else -#endif - // fallback - mode=GL_CLAMP; - break; - case ETC_MIRROR: -#ifdef GL_VERSION_1_4 - if (Version>103) - mode=GL_MIRRORED_REPEAT; - else -#endif -#ifdef GL_ARB_texture_border_clamp - if (FeatureAvailable[IRR_ARB_texture_mirrored_repeat]) - mode=GL_MIRRORED_REPEAT_ARB; - else -#endif -#ifdef GL_IBM_texture_mirrored_repeat - if (FeatureAvailable[IRR_IBM_texture_mirrored_repeat]) - mode=GL_MIRRORED_REPEAT_IBM; - else -#endif - mode=GL_REPEAT; - break; - case ETC_MIRROR_CLAMP: -#ifdef GL_EXT_texture_mirror_clamp - if (FeatureAvailable[IRR_EXT_texture_mirror_clamp]) - mode=GL_MIRROR_CLAMP_EXT; - else -#endif -#if defined(GL_ATI_texture_mirror_once) - if (FeatureAvailable[IRR_ATI_texture_mirror_once]) - mode=GL_MIRROR_CLAMP_ATI; - else -#endif - mode=GL_CLAMP; - break; - case ETC_MIRROR_CLAMP_TO_EDGE: -#ifdef GL_EXT_texture_mirror_clamp - if (FeatureAvailable[IRR_EXT_texture_mirror_clamp]) - mode=GL_MIRROR_CLAMP_TO_EDGE_EXT; - else -#endif -#if defined(GL_ATI_texture_mirror_once) - if (FeatureAvailable[IRR_ATI_texture_mirror_once]) - mode=GL_MIRROR_CLAMP_TO_EDGE_ATI; - else -#endif - mode=GL_CLAMP; - break; - case ETC_MIRROR_CLAMP_TO_BORDER: -#ifdef GL_EXT_texture_mirror_clamp - if (FeatureAvailable[IRR_EXT_texture_mirror_clamp]) - mode=GL_MIRROR_CLAMP_TO_BORDER_EXT; - else -#endif - mode=GL_CLAMP; - break; - } - return mode; -} - - -void COpenGLDriver::setWrapMode(const SMaterial& material) -{ - // texture address mode - // Has to be checked always because it depends on the textures - for (u32 u=0; u0) - break; // stop loop - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[u].TextureWrapU)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[u].TextureWrapV)); - } -} - - -//! Can be called by an IMaterialRenderer to make its work easier. -void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, - bool resetAllRenderStates) -{ - if (resetAllRenderStates || - lastmaterial.ColorMaterial != material.ColorMaterial) - { - switch (material.ColorMaterial) - { - case ECM_NONE: - glDisable(GL_COLOR_MATERIAL); - break; - case ECM_DIFFUSE: - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - break; - case ECM_AMBIENT: - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT); - break; - case ECM_EMISSIVE: - glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION); - break; - case ECM_SPECULAR: - glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR); - break; - case ECM_DIFFUSE_AND_AMBIENT: - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - break; - } - if (material.ColorMaterial != ECM_NONE) - glEnable(GL_COLOR_MATERIAL); - } - - if (resetAllRenderStates || - lastmaterial.AmbientColor != material.AmbientColor || - lastmaterial.DiffuseColor != material.DiffuseColor || - lastmaterial.EmissiveColor != material.EmissiveColor || - lastmaterial.ColorMaterial != material.ColorMaterial) - { - GLfloat color[4]; - - const f32 inv = 1.0f / 255.0f; - - if ((material.ColorMaterial != video::ECM_AMBIENT) && - (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT)) - { - color[0] = material.AmbientColor.getRed() * inv; - color[1] = material.AmbientColor.getGreen() * inv; - color[2] = material.AmbientColor.getBlue() * inv; - color[3] = material.AmbientColor.getAlpha() * inv; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); - } - - if ((material.ColorMaterial != video::ECM_DIFFUSE) && - (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT)) - { - color[0] = material.DiffuseColor.getRed() * inv; - color[1] = material.DiffuseColor.getGreen() * inv; - color[2] = material.DiffuseColor.getBlue() * inv; - color[3] = material.DiffuseColor.getAlpha() * inv; - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color); - } - - if (material.ColorMaterial != video::ECM_EMISSIVE) - { - color[0] = material.EmissiveColor.getRed() * inv; - color[1] = material.EmissiveColor.getGreen() * inv; - color[2] = material.EmissiveColor.getBlue() * inv; - color[3] = material.EmissiveColor.getAlpha() * inv; - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color); - } - } - - if (resetAllRenderStates || - lastmaterial.SpecularColor != material.SpecularColor || - lastmaterial.Shininess != material.Shininess || - lastmaterial.ColorMaterial != material.ColorMaterial) - { - GLfloat color[4]={0.f,0.f,0.f,1.f}; - const f32 inv = 1.0f / 255.0f; - - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess); - // disable Specular colors if no shininess is set - if ((material.Shininess != 0.0f) && - (material.ColorMaterial != video::ECM_SPECULAR)) - { -#ifdef GL_EXT_separate_specular_color - if (FeatureAvailable[IRR_EXT_separate_specular_color]) - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); -#endif - color[0] = material.SpecularColor.getRed() * inv; - color[1] = material.SpecularColor.getGreen() * inv; - color[2] = material.SpecularColor.getBlue() * inv; - color[3] = material.SpecularColor.getAlpha() * inv; - } -#ifdef GL_EXT_separate_specular_color - else if (FeatureAvailable[IRR_EXT_separate_specular_color]) - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); -#endif - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); - } - - // Texture filter - // Has to be checked always because it depends on the textures - // Filtering has to be set for each texture layer - for (u32 i=0; i0) - break; - -#ifdef GL_EXT_texture_lod_bias - if (FeatureAvailable[IRR_EXT_texture_lod_bias]) - { - if (material.TextureLayer[i].LODBias) - { - const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); - glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp); - } - else - glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f); - } -#endif - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); - - if (material.UseMipMaps && CurrentTexture[i]->hasMipMaps()) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR : - material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST : - GL_NEAREST_MIPMAP_NEAREST); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); - -#ifdef GL_EXT_texture_filter_anisotropic - if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic]) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1); -#endif - } - - // fillmode - if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud)) - glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL); - - // shademode - if (resetAllRenderStates || (lastmaterial.GouraudShading != material.GouraudShading)) - { - if (material.GouraudShading) - glShadeModel(GL_SMOOTH); - else - glShadeModel(GL_FLAT); - } - - // lighting - if (resetAllRenderStates || (lastmaterial.Lighting != material.Lighting)) - { - if (material.Lighting) - glEnable(GL_LIGHTING); - else - glDisable(GL_LIGHTING); - } - - // zbuffer - if (resetAllRenderStates || lastmaterial.ZBuffer != material.ZBuffer) - { - switch (material.ZBuffer) - { - case ECFN_NEVER: - glDisable(GL_DEPTH_TEST); - break; - case ECFN_LESSEQUAL: - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - break; - case ECFN_EQUAL: - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_EQUAL); - break; - case ECFN_LESS: - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - break; - case ECFN_NOTEQUAL: - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_NOTEQUAL); - break; - case ECFN_GREATEREQUAL: - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_GEQUAL); - break; - case ECFN_GREATER: - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_GREATER); - break; - case ECFN_ALWAYS: - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - break; - } - } - - // zwrite -// if (resetAllRenderStates || lastmaterial.ZWriteEnable != material.ZWriteEnable) - { - if (material.ZWriteEnable && (AllowZWriteOnTransparent || !material.isTransparent())) - { - glDepthMask(GL_TRUE); - } - else - glDepthMask(GL_FALSE); - } - - // back face culling - if (resetAllRenderStates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling)) - { - if ((material.FrontfaceCulling) && (material.BackfaceCulling)) - { - glCullFace(GL_FRONT_AND_BACK); - glEnable(GL_CULL_FACE); - } - else - if (material.BackfaceCulling) - { - glCullFace(GL_BACK); - glEnable(GL_CULL_FACE); - } - else - if (material.FrontfaceCulling) - { - glCullFace(GL_FRONT); - glEnable(GL_CULL_FACE); - } - else - glDisable(GL_CULL_FACE); - } - - // fog - if (resetAllRenderStates || lastmaterial.FogEnable != material.FogEnable) - { - if (material.FogEnable) - glEnable(GL_FOG); - else - glDisable(GL_FOG); - } - - // normalization - if (resetAllRenderStates || lastmaterial.NormalizeNormals != material.NormalizeNormals) - { - if (material.NormalizeNormals) - glEnable(GL_NORMALIZE); - else - glDisable(GL_NORMALIZE); - } - - // Color Mask - if (resetAllRenderStates || lastmaterial.ColorMask != material.ColorMask) - { - glColorMask( - (material.ColorMask & ECP_RED)?GL_TRUE:GL_FALSE, - (material.ColorMask & ECP_GREEN)?GL_TRUE:GL_FALSE, - (material.ColorMask & ECP_BLUE)?GL_TRUE:GL_FALSE, - (material.ColorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE); - } - - if (queryFeature(EVDF_BLEND_OPERATIONS) && - (resetAllRenderStates|| lastmaterial.BlendOperation != material.BlendOperation)) - { - if (material.BlendOperation==EBO_NONE) - glDisable(GL_BLEND); - else - { - glEnable(GL_BLEND); -#if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) || defined(GL_VERSION_1_2) - switch (material.BlendOperation) - { - case EBO_SUBTRACT: -#if defined(GL_EXT_blend_subtract) - if (FeatureAvailable[IRR_EXT_blend_subtract] || (Version>=120)) - extGlBlendEquation(GL_FUNC_SUBTRACT_EXT); -#elif defined(GL_VERSION_1_2) - if (Version>=120) - extGlBlendEquation(GL_FUNC_SUBTRACT); -#endif - break; - case EBO_REVSUBTRACT: -#if defined(GL_EXT_blend_subtract) - if (FeatureAvailable[IRR_EXT_blend_subtract] || (Version>=120)) - extGlBlendEquation(GL_FUNC_REVERSE_SUBTRACT_EXT); -#elif defined(GL_VERSION_1_2) - if (Version>=120) - extGlBlendEquation(GL_FUNC_REVERSE_SUBTRACT); -#endif - break; - case EBO_MIN: -#if defined(GL_EXT_blend_minmax) - if (FeatureAvailable[IRR_EXT_blend_minmax] || (Version>=120)) - extGlBlendEquation(GL_MIN_EXT); -#elif defined(GL_VERSION_1_2) - if (Version>=120) - extGlBlendEquation(GL_MIN); -#endif - break; - case EBO_MAX: -#if defined(GL_EXT_blend_minmax) - if (FeatureAvailable[IRR_EXT_blend_minmax] || (Version>=120)) - extGlBlendEquation(GL_MAX_EXT); -#elif defined(GL_VERSION_1_2) - if (Version>=120) - extGlBlendEquation(GL_MAX); -#endif - break; - case EBO_MIN_FACTOR: -#if defined(GL_AMD_blend_minmax_factor) - if (FeatureAvailable[IRR_AMD_blend_minmax_factor]) - extGlBlendEquation(GL_FACTOR_MIN_AMD); -#endif - // fallback in case of missing extension -#if defined(GL_VERSION_1_2) -#if defined(GL_AMD_blend_minmax_factor) - else -#endif - if (Version>=120) - extGlBlendEquation(GL_MIN); -#endif - break; - case EBO_MAX_FACTOR: -#if defined(GL_AMD_blend_minmax_factor) - if (FeatureAvailable[IRR_AMD_blend_minmax_factor]) - extGlBlendEquation(GL_FACTOR_MAX_AMD); -#endif - // fallback in case of missing extension -#if defined(GL_VERSION_1_2) -#if defined(GL_AMD_blend_minmax_factor) - else -#endif - if (Version>=120) - extGlBlendEquation(GL_MAX); -#endif - break; - case EBO_MIN_ALPHA: -#if defined(GL_SGIX_blend_alpha_minmax) - if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax]) - extGlBlendEquation(GL_ALPHA_MIN_SGIX); - // fallback in case of missing extension - else - if (FeatureAvailable[IRR_EXT_blend_minmax]) - extGlBlendEquation(GL_MIN_EXT); -#endif - break; - case EBO_MAX_ALPHA: -#if defined(GL_SGIX_blend_alpha_minmax) - if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax]) - extGlBlendEquation(GL_ALPHA_MAX_SGIX); - // fallback in case of missing extension - else - if (FeatureAvailable[IRR_EXT_blend_minmax]) - extGlBlendEquation(GL_MAX_EXT); -#endif - break; - default: -#if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) - extGlBlendEquation(GL_FUNC_ADD_EXT); -#elif defined(GL_VERSION_1_2) - extGlBlendEquation(GL_FUNC_ADD); -#endif - break; - } -#endif - } - } - - // Polygon Offset - if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderStates || - lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection || - lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor)) - { - glDisable(lastmaterial.Wireframe?GL_POLYGON_OFFSET_LINE:lastmaterial.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL); - if (material.PolygonOffsetFactor) - { - glDisable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL); - glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL); - } - if (material.PolygonOffsetDirection==EPO_BACK) - glPolygonOffset(1.0f, (GLfloat)material.PolygonOffsetFactor); - else - glPolygonOffset(-1.0f, (GLfloat)-material.PolygonOffsetFactor); - } - - // thickness - if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness) - { - if (AntiAlias) - { -// glPointSize(core::clamp(static_cast(material.Thickness), DimSmoothedPoint[0], DimSmoothedPoint[1])); - // we don't use point smoothing - glPointSize(core::clamp(static_cast(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1])); - glLineWidth(core::clamp(static_cast(material.Thickness), DimSmoothedLine[0], DimSmoothedLine[1])); - } - else - { - glPointSize(core::clamp(static_cast(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1])); - glLineWidth(core::clamp(static_cast(material.Thickness), DimAliasedLine[0], DimAliasedLine[1])); - } - } - - // Anti aliasing - if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing) - { - if (FeatureAvailable[IRR_ARB_multisample]) - { - if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) - glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); - else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) - glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); - - if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY))) - { - glEnable(GL_MULTISAMPLE_ARB); -#ifdef GL_NV_multisample_filter_hint - if (FeatureAvailable[IRR_NV_multisample_filter_hint]) - { - if ((material.AntiAliasing & EAAM_QUALITY) == EAAM_QUALITY) - glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST); - else - glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST); - } -#endif - } - else - glDisable(GL_MULTISAMPLE_ARB); - } - if ((material.AntiAliasing & EAAM_LINE_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH)) - { - if (material.AntiAliasing & EAAM_LINE_SMOOTH) - glEnable(GL_LINE_SMOOTH); - else if (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH) - glDisable(GL_LINE_SMOOTH); - } - if ((material.AntiAliasing & EAAM_POINT_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH)) - { - if (material.AntiAliasing & EAAM_POINT_SMOOTH) - // often in software, and thus very slow - glEnable(GL_POINT_SMOOTH); - else if (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH) - glDisable(GL_POINT_SMOOTH); - } - } - - setWrapMode(material); - - // be sure to leave in texture stage 0 - if (MultiTextureExtension) - extGlActiveTexture(GL_TEXTURE0_ARB); -} - - -//! Enable the 2d override material -void COpenGLDriver::enableMaterial2D(bool enable) -{ - if (!enable) - CurrentRenderMode = ERM_NONE; - CNullDriver::enableMaterial2D(enable); -} - - -//! sets the needed renderstates -void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel) -{ - if (CurrentRenderMode != ERM_2D || Transformation3DChanged) - { - // unset last 3d material - if (CurrentRenderMode == ERM_3D) - { - if (static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) - MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); - } - if (Transformation3DChanged) - { - glMatrixMode(GL_PROJECTION); - - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - core::matrix4 m(core::matrix4::EM4CONST_NOTHING); - m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f); - m.setTranslation(core::vector3df(-1,1,0)); - glLoadMatrixf(m.pointer()); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.375f, 0.375f, 0.0f); - - // Make sure we set first texture matrix - if (MultiTextureExtension) - extGlActiveTexture(GL_TEXTURE0_ARB); - - Transformation3DChanged = false; - } - if (!OverrideMaterial2DEnabled) - { - setBasicRenderStates(InitMaterial2D, LastMaterial, true); - LastMaterial = InitMaterial2D; - } - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -#ifdef GL_EXT_clip_volume_hint - if (FeatureAvailable[IRR_EXT_clip_volume_hint]) - glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST); -#endif - - } - if (OverrideMaterial2DEnabled) - { - OverrideMaterial2D.Lighting=false; - setBasicRenderStates(OverrideMaterial2D, LastMaterial, false); - LastMaterial = OverrideMaterial2D; - } - - // no alphaChannel without texture - alphaChannel &= texture; - - if (alphaChannel || alpha) - { - glEnable(GL_BLEND); - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.f); - } - else - { - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - } - - if (texture) - { - if (!OverrideMaterial2DEnabled) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - Material.setTexture(0, const_cast(CurrentTexture[0])); - setTransform(ETS_TEXTURE_0, core::IdentityMatrix); - // Due to the transformation change, the previous line would call a reset each frame - // but we can safely reset the variable as it was false before - Transformation3DChanged=false; - - if (alphaChannel) - { - // if alpha and alpha texture just modulate, otherwise use only the alpha channel - if (alpha) - { - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - else - { -#if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine) - if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine]) - { -#ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); - // rgb always modulates - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); -#else - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); - // rgb always modulates - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); -#endif - } - else -#endif - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - } - else - { - if (alpha) - { -#if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine) - if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine]) - { -#ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); - // rgb always modulates - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); -#else - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); - // rgb always modulates - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); -#endif - } - else -#endif - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - else - { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - } - } - - CurrentRenderMode = ERM_2D; -} - - -//! \return Returns the name of the video driver. -const wchar_t* COpenGLDriver::getName() const -{ - return Name.c_str(); -} - - -//! deletes all dynamic lights there are -void COpenGLDriver::deleteAllDynamicLights() -{ - for (s32 i=0; i= (s32)RequestedLights.size()) - return; - - RequestedLight & requestedLight = RequestedLights[lightIndex]; - - requestedLight.DesireToBeOn = turnOn; - - if(turnOn) - { - if(-1 == requestedLight.HardwareLightIndex) - assignHardwareLight(lightIndex); - } - else - { - if(-1 != requestedLight.HardwareLightIndex) - { - // It's currently assigned, so free up the hardware light - glDisable(requestedLight.HardwareLightIndex); - requestedLight.HardwareLightIndex = -1; - - // Now let the first light that's waiting on a free hardware light grab it - for(u32 requested = 0; requested < RequestedLights.size(); ++requested) - if(RequestedLights[requested].DesireToBeOn - && - -1 == RequestedLights[requested].HardwareLightIndex) - { - assignHardwareLight(requested); - break; - } - } - } -} - - -//! returns the maximal amount of dynamic lights the device can handle -u32 COpenGLDriver::getMaximalDynamicLightAmount() const -{ - return MaxLights; -} - - -//! Sets the dynamic ambient light color. The default color is -//! (0,0,0,0) which means it is dark. -//! \param color: New color of the ambient light. -void COpenGLDriver::setAmbientLight(const SColorf& color) -{ - GLfloat data[4] = {color.r, color.g, color.b, color.a}; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data); -} - - -// this code was sent in by Oliver Klems, thank you! (I modified the glViewport -// method just a bit. -void COpenGLDriver::setViewPort(const core::rect& area) -{ - if (area == ViewPort) - return; - core::rect vp = area; - core::rect rendert(0,0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height); - vp.clipAgainst(rendert); - - if (vp.getHeight()>0 && vp.getWidth()>0) - { - glViewport(vp.UpperLeftCorner.X, - getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), - vp.getWidth(), vp.getHeight()); - - ViewPort = vp; - } -} - - -//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do -//! this: First, draw all geometry. Then use this method, to draw the shadow -//! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow. -void COpenGLDriver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) -{ - const u32 count=triangles.size(); - if (!StencilBuffer || !count) - return; - - // unset last 3d material - if (CurrentRenderMode == ERM_3D && - static_cast(Material.MaterialType) < MaterialRenderers.size()) - { - MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial(); - ResetRenderStates = true; - } - - // store current OpenGL state - glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | - GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT); - - glDisable(GL_LIGHTING); - glDisable(GL_FOG); - glDepthFunc(GL_LESS); - glDepthMask(GL_FALSE); // no depth buffer writing - if (debugDataVisible & scene::EDS_MESH_WIRE_OVERLAY) - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY))) - { - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color buffer drawing - glEnable(GL_STENCIL_TEST); - } - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3,GL_FLOAT,sizeof(core::vector3df),triangles.const_pointer()); - glStencilMask(~0); - glStencilFunc(GL_ALWAYS, 0, ~0); - - GLenum incr = GL_INCR; - GLenum decr = GL_DECR; -#ifdef GL_EXT_stencil_wrap - if (FeatureAvailable[IRR_EXT_stencil_wrap]) - { - incr = GL_INCR_WRAP_EXT; - decr = GL_DECR_WRAP_EXT; - } -#endif -#ifdef GL_NV_depth_clamp - if (FeatureAvailable[IRR_NV_depth_clamp]) - glEnable(GL_DEPTH_CLAMP_NV); -#endif - - // The first parts are not correctly working, yet. -#if 0 -#ifdef GL_EXT_stencil_two_side - if (FeatureAvailable[IRR_EXT_stencil_two_side]) - { - glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT); - glDisable(GL_CULL_FACE); - if (zfail) - { - extGlActiveStencilFace(GL_BACK); - glStencilOp(GL_KEEP, incr, GL_KEEP); - glStencilMask(~0); - glStencilFunc(GL_ALWAYS, 0, ~0); - - extGlActiveStencilFace(GL_FRONT); - glStencilOp(GL_KEEP, decr, GL_KEEP); - } - else // zpass - { - extGlActiveStencilFace(GL_BACK); - glStencilOp(GL_KEEP, GL_KEEP, decr); - glStencilMask(~0); - glStencilFunc(GL_ALWAYS, 0, ~0); - - extGlActiveStencilFace(GL_FRONT); - glStencilOp(GL_KEEP, GL_KEEP, incr); - } - glStencilMask(~0); - glStencilFunc(GL_ALWAYS, 0, ~0); - glDrawArrays(GL_TRIANGLES,0,count); - glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); - } - else -#endif - if (FeatureAvailable[IRR_ATI_separate_stencil]) - { - glDisable(GL_CULL_FACE); - if (zfail) - { - extGlStencilOpSeparate(GL_BACK, GL_KEEP, incr, GL_KEEP); - extGlStencilOpSeparate(GL_FRONT, GL_KEEP, decr, GL_KEEP); - } - else // zpass - { - extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, decr); - extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, incr); - } - extGlStencilFuncSeparate(GL_ALWAYS, GL_ALWAYS, 0, ~0); - glStencilMask(~0); - glDrawArrays(GL_TRIANGLES,0,count); - } - else -#endif - { - glEnable(GL_CULL_FACE); - if (zfail) - { - glCullFace(GL_FRONT); - glStencilOp(GL_KEEP, incr, GL_KEEP); - glDrawArrays(GL_TRIANGLES,0,count); - - glCullFace(GL_BACK); - glStencilOp(GL_KEEP, decr, GL_KEEP); - glDrawArrays(GL_TRIANGLES,0,count); - } - else // zpass - { - glCullFace(GL_BACK); - glStencilOp(GL_KEEP, GL_KEEP, incr); - glDrawArrays(GL_TRIANGLES,0,count); - - glCullFace(GL_FRONT); - glStencilOp(GL_KEEP, GL_KEEP, decr); - glDrawArrays(GL_TRIANGLES,0,count); - } - } -#ifdef GL_NV_depth_clamp - if (FeatureAvailable[IRR_NV_depth_clamp]) - glDisable(GL_DEPTH_CLAMP_NV); -#endif - - glDisable(GL_POLYGON_OFFSET_FILL); - glDisableClientState(GL_VERTEX_ARRAY); //not stored on stack - glPopAttrib(); -} - -//! Fills the stencil shadow with color. After the shadow volume has been drawn -//! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this -//! to draw the color of the shadow. -void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, - video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) -{ - if (!StencilBuffer) - return; - - disableTextures(); - - // store attributes - glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT | GL_LIGHTING_BIT); - - glDisable(GL_LIGHTING); - glDisable(GL_FOG); - glDepthMask(GL_FALSE); - - glShadeModel(GL_FLAT); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_NOTEQUAL, 0, ~0); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - - // draw a shadow rectangle covering the entire screen using stencil buffer - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - glBegin(GL_QUADS); - - glColor4ub(leftDownEdge.getRed(), leftDownEdge.getGreen(), leftDownEdge.getBlue(), leftDownEdge.getAlpha()); - glVertex3f(-1.f,-1.f,-0.9f); - - glColor4ub(leftUpEdge.getRed(), leftUpEdge.getGreen(), leftUpEdge.getBlue(), leftUpEdge.getAlpha()); - glVertex3f(-1.f, 1.f,-0.9f); - - glColor4ub(rightUpEdge.getRed(), rightUpEdge.getGreen(), rightUpEdge.getBlue(), rightUpEdge.getAlpha()); - glVertex3f(1.f, 1.f,-0.9f); - - glColor4ub(rightDownEdge.getRed(), rightDownEdge.getGreen(), rightDownEdge.getBlue(), rightDownEdge.getAlpha()); - glVertex3f(1.f,-1.f,-0.9f); - - glEnd(); - - clearBuffers(false, false, clearStencilBuffer, 0x0); - - // restore settings - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glPopAttrib(); -} - - -//! Sets the fog mode. -void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start, - f32 end, f32 density, bool pixelFog, bool rangeFog) -{ - CNullDriver::setFog(c, fogType, start, end, density, pixelFog, rangeFog); - - glFogf(GL_FOG_MODE, GLfloat((fogType==EFT_FOG_LINEAR)? GL_LINEAR : (fogType==EFT_FOG_EXP)?GL_EXP:GL_EXP2)); - -#ifdef GL_EXT_fog_coord - if (FeatureAvailable[IRR_EXT_fog_coord]) - glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH); -#endif -#ifdef GL_NV_fog_distance - if (FeatureAvailable[IRR_NV_fog_distance]) - { - if (rangeFog) - glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV); - else - glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV); - } -#endif - - if (fogType==EFT_FOG_LINEAR) - { - glFogf(GL_FOG_START, start); - glFogf(GL_FOG_END, end); - } - else - glFogf(GL_FOG_DENSITY, density); - - if (pixelFog) - glHint(GL_FOG_HINT, GL_NICEST); - else - glHint(GL_FOG_HINT, GL_FASTEST); - - SColorf color(c); - GLfloat data[4] = {color.r, color.g, color.b, color.a}; - glFogfv(GL_FOG_COLOR, data); -} - - -//! Draws a 3d line. -void COpenGLDriver::draw3DLine(const core::vector3df& start, - const core::vector3df& end, SColor color) -{ - setRenderStates3DMode(); - - glBegin(GL_LINES); - glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); - glVertex3f(start.X, start.Y, start.Z); - - glVertex3f(end.X, end.Y, end.Z); - glEnd(); -} - - -//! Removes a texture from the texture cache and deletes it, freeing lot of memory. -void COpenGLDriver::removeTexture(ITexture* texture) -{ - if (!texture) - return; - - CNullDriver::removeTexture(texture); - // Remove this texture from CurrentTexture as well - CurrentTexture.remove(texture); -} - - -//! Only used by the internal engine. Used to notify the driver that -//! the window was resized. -void COpenGLDriver::OnResize(const core::dimension2d& size) -{ - CNullDriver::OnResize(size); - glViewport(0, 0, size.Width, size.Height); - Transformation3DChanged = true; -} - - -//! Returns type of video driver -E_DRIVER_TYPE COpenGLDriver::getDriverType() const -{ - return EDT_OPENGL; -} - - -//! returns color format -ECOLOR_FORMAT COpenGLDriver::getColorFormat() const -{ - return ColorFormat; -} - - -//! Sets a vertex shader constant. -void COpenGLDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) -{ -#ifdef GL_ARB_vertex_program - for (s32 i=0; isetPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); - return false; -} - -//! Bool interface for the above. -bool COpenGLDriver::setPixelShaderConstant(const c8* name, const bool* bools, int count) -{ - os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); - return false; -} - -//! Int interface for the above. -bool COpenGLDriver::setPixelShaderConstant(const c8* name, const s32* ints, int count) -{ - os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); - return false; -} - - -//! Adds a new material renderer to the VideoDriver, using pixel and/or -//! vertex shaders to render geometry. -s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram, - const c8* pixelShaderProgram, - IShaderConstantSetCallBack* callback, - E_MATERIAL_TYPE baseMaterial, s32 userData) -{ - s32 nr = -1; - COpenGLShaderMaterialRenderer* r = new COpenGLShaderMaterialRenderer( - this, nr, vertexShaderProgram, pixelShaderProgram, - callback, getMaterialRenderer(baseMaterial), userData); - - r->drop(); - return nr; -} - - -//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry. -s32 COpenGLDriver::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) -{ - s32 nr = -1; - - #ifdef _IRR_COMPILE_WITH_CG_ - if (shadingLang == EGSL_CG) - { - COpenGLCgMaterialRenderer* r = new COpenGLCgMaterialRenderer( - this, nr, - vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget, - pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget, - geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget, - inType, outType, verticesOut, - callback,getMaterialRenderer(baseMaterial), userData); - - r->drop(); - } - else - #endif - { - COpenGLSLMaterialRenderer* r = new COpenGLSLMaterialRenderer( - this, nr, - vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget, - pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget, - geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget, - inType, outType, verticesOut, - callback,getMaterialRenderer(baseMaterial), userData); - - r->drop(); - } - - return nr; -} - - -//! Returns a pointer to the IVideoDriver interface. (Implementation for -//! IMaterialRendererServices) -IVideoDriver* COpenGLDriver::getVideoDriver() -{ - return this; -} - - -ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d& size, - const io::path& name, - const ECOLOR_FORMAT format) -{ - //disable mip-mapping - bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); - setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); - - video::ITexture* rtt = 0; -#if defined(GL_EXT_framebuffer_object) - // if driver supports FrameBufferObjects, use them - if (queryFeature(EVDF_FRAMEBUFFER_OBJECT)) - { - rtt = new COpenGLFBOTexture(size, name, this, format); - if (rtt) - { - bool success = false; - addTexture(rtt); - ITexture* tex = createDepthTexture(rtt); - if (tex) - { - success = static_cast(tex)->attach(rtt); - if ( !success ) - { - removeDepthTexture(tex); - } - tex->drop(); - } - rtt->drop(); - if (!success) - { - removeTexture(rtt); - rtt=0; - } - } - } - else -#endif - { - // the simple texture is only possible for size <= screensize - // we try to find an optimal size with the original constraints - core::dimension2du destSize(core::min_(size.Width,ScreenSize.Width), core::min_(size.Height,ScreenSize.Height)); - destSize = destSize.getOptimalSize((size==size.getOptimalSize()), false, false); - rtt = addTexture(destSize, name, ECF_A8R8G8B8); - if (rtt) - { - static_cast(rtt)->setIsRenderTarget(true); - } - } - - //restore mip-mapping - setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels); - - return rtt; -} - - -//! Returns the maximum amount of primitives (mostly vertices) which -//! the device is able to render with one drawIndexedTriangleList -//! call. -u32 COpenGLDriver::getMaximalPrimitiveCount() const -{ - return 0x7fffffff; -} - - -//! set or reset render target -bool COpenGLDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget, - bool clearZBuffer, SColor color) -{ - if (target != CurrentTarget) - setRenderTarget(0, false, false, 0x0); - - if (ERT_RENDER_TEXTURE == target) - { - os::Printer::log("For render textures call setRenderTarget with the actual texture as first parameter.", ELL_ERROR); - return false; - } - if (ERT_MULTI_RENDER_TEXTURES == target) - { - os::Printer::log("For multiple render textures call setRenderTarget with the texture array as first parameter.", ELL_ERROR); - return false; - } - - if (Params.Stereobuffer && (ERT_STEREO_RIGHT_BUFFER == target)) - { - if (Params.Doublebuffer) - glDrawBuffer(GL_BACK_RIGHT); - else - glDrawBuffer(GL_FRONT_RIGHT); - } - else if (Params.Stereobuffer && ERT_STEREO_BOTH_BUFFERS == target) - { - if (Params.Doublebuffer) - glDrawBuffer(GL_BACK); - else - glDrawBuffer(GL_FRONT); - } - else if ((target >= ERT_AUX_BUFFER0) && (target-ERT_AUX_BUFFER0 < MaxAuxBuffers)) - { - glDrawBuffer(GL_AUX0+target-ERT_AUX_BUFFER0); - } - else - { - if (Params.Doublebuffer) - glDrawBuffer(GL_BACK_LEFT); - else - glDrawBuffer(GL_FRONT_LEFT); - // exit with false, but also with working color buffer - if (target != ERT_FRAME_BUFFER) - return false; - } - CurrentTarget=target; - clearBuffers(clearTarget, clearZBuffer, false, color); - return true; -} - - -//! set or reset render target -bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, - bool clearZBuffer, SColor color) -{ - // check for right driver type - - if (texture && texture->getDriverType() != EDT_OPENGL) - { - os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); - return false; - } - -#if defined(GL_EXT_framebuffer_object) - if (CurrentTarget==ERT_MULTI_RENDER_TEXTURES) - { - for (u32 i=0; iunbindRTT(); - } - - if (texture) - { - // we want to set a new target. so do this. - glViewport(0, 0, texture->getSize().Width, texture->getSize().Height); - RenderTargetTexture = static_cast(texture); - // calls glDrawBuffer as well - RenderTargetTexture->bindRTT(); - CurrentRendertargetSize = texture->getSize(); - CurrentTarget=ERT_RENDER_TEXTURE; - } - else - { - glViewport(0,0,ScreenSize.Width,ScreenSize.Height); - RenderTargetTexture = 0; - CurrentRendertargetSize = core::dimension2d(0,0); - CurrentTarget=ERT_FRAME_BUFFER; - glDrawBuffer(Params.Doublebuffer?GL_BACK_LEFT:GL_FRONT_LEFT); - } - // we need to update the matrices due to the rendersize change. - Transformation3DChanged=true; - } - - clearBuffers(clearBackBuffer, clearZBuffer, false, color); - - return true; -} - - -//! Sets multiple render targets -bool COpenGLDriver::setRenderTarget(const core::array& targets, - bool clearBackBuffer, bool clearZBuffer, SColor color) -{ - // if simply disabling the MRT via array call - if (targets.size()==0) - return setRenderTarget(0, clearBackBuffer, clearZBuffer, color); - // if disabling old MRT, but enabling new one as well - if ((MRTargets.size()!=0) && (targets != MRTargets)) - setRenderTarget(0, clearBackBuffer, clearZBuffer, color); - // if no change, simply clear buffers - else if (targets == MRTargets) - { - clearBuffers(clearBackBuffer, clearZBuffer, false, color); - return true; - } - - // copy to storage for correct disabling - MRTargets=targets; - - u32 maxMultipleRTTs = core::min_(static_cast(MaxMultipleRenderTargets), targets.size()); - - // determine common size - core::dimension2du rttSize = CurrentRendertargetSize; - if (targets[0].TargetType==ERT_RENDER_TEXTURE) - { - if (!targets[0].RenderTexture) - { - os::Printer::log("Missing render texture for MRT.", ELL_ERROR); - return false; - } - rttSize=targets[0].RenderTexture->getSize(); - } - - for (u32 i = 0; i < maxMultipleRTTs; ++i) - { - // check for right driver type - if (targets[i].TargetType==ERT_RENDER_TEXTURE) - { - if (!targets[i].RenderTexture) - { - maxMultipleRTTs=i; - os::Printer::log("Missing render texture for MRT.", ELL_WARNING); - break; - } - if (targets[i].RenderTexture->getDriverType() != EDT_OPENGL) - { - maxMultipleRTTs=i; - os::Printer::log("Tried to set a texture not owned by this driver.", ELL_WARNING); - break; - } - - // check for valid render target - if (!targets[i].RenderTexture->isRenderTarget() || !static_cast(targets[i].RenderTexture)->isFrameBufferObject()) - { - maxMultipleRTTs=i; - os::Printer::log("Tried to set a non FBO-RTT as render target.", ELL_WARNING); - break; - } - - // check for valid size - if (rttSize != targets[i].RenderTexture->getSize()) - { - maxMultipleRTTs=i; - os::Printer::log("Render target texture has wrong size.", ELL_WARNING); - break; - } - } - } - if (maxMultipleRTTs==0) - { - os::Printer::log("No valid MRTs.", ELL_ERROR); - return false; - } - - // init FBO, if any - for (u32 i=0; i 1) - { - CurrentTarget=ERT_MULTI_RENDER_TEXTURES; - core::array MRTs; - MRTs.set_used(maxMultipleRTTs); - for(u32 i = 0; i < maxMultipleRTTs; i++) - { - if (FeatureAvailable[IRR_EXT_draw_buffers2]) - { - extGlColorMaskIndexed(i, - (targets[i].ColorMask & ECP_RED)?GL_TRUE:GL_FALSE, - (targets[i].ColorMask & ECP_GREEN)?GL_TRUE:GL_FALSE, - (targets[i].ColorMask & ECP_BLUE)?GL_TRUE:GL_FALSE, - (targets[i].ColorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE); - if (targets[i].BlendOp==EBO_NONE) - extGlDisableIndexed(GL_BLEND, i); - else - extGlEnableIndexed(GL_BLEND, i); - } -#if defined(GL_AMD_draw_buffers_blend) || defined(GL_ARB_draw_buffers_blend) - if (FeatureAvailable[IRR_AMD_draw_buffers_blend] || FeatureAvailable[IRR_ARB_draw_buffers_blend]) - { - extGlBlendFuncIndexed(i, getGLBlend(targets[i].BlendFuncSrc), getGLBlend(targets[i].BlendFuncDst)); - switch(targets[i].BlendOp) - { - case EBO_SUBTRACT: - extGlBlendEquationIndexed(i, GL_FUNC_SUBTRACT); - break; - case EBO_REVSUBTRACT: - extGlBlendEquationIndexed(i, GL_FUNC_REVERSE_SUBTRACT); - break; - case EBO_MIN: - extGlBlendEquationIndexed(i, GL_MIN); - break; - case EBO_MAX: - extGlBlendEquationIndexed(i, GL_MAX); - break; - case EBO_MIN_FACTOR: - case EBO_MIN_ALPHA: -#if defined(GL_AMD_blend_minmax_factor) - if (FeatureAvailable[IRR_AMD_blend_minmax_factor]) - extGlBlendEquationIndexed(i, GL_FACTOR_MIN_AMD); - // fallback in case of missing extension - else -#endif - extGlBlendEquation(GL_MIN); - break; - case EBO_MAX_FACTOR: - case EBO_MAX_ALPHA: -#if defined(GL_AMD_blend_minmax_factor) - if (FeatureAvailable[IRR_AMD_blend_minmax_factor]) - extGlBlendEquationIndexed(i, GL_FACTOR_MAX_AMD); - // fallback in case of missing extension - else -#endif - extGlBlendEquation(GL_MAX); - break; - default: - extGlBlendEquationIndexed(i, GL_FUNC_ADD); - break; - } - } -#endif - if (targets[i].TargetType==ERT_RENDER_TEXTURE) - { - GLenum attachment = GL_NONE; -#ifdef GL_EXT_framebuffer_object - // attach texture to FrameBuffer Object on Color [i] - attachment = GL_COLOR_ATTACHMENT0_EXT+i; - if ((i != 0) && (targets[i].RenderTexture != RenderTargetTexture)) - extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_2D, static_cast(targets[i].RenderTexture)->getOpenGLTextureName(), 0); -#endif - MRTs[i]=attachment; - } - else - { - switch(targets[i].TargetType) - { - case ERT_FRAME_BUFFER: - MRTs[i]=GL_BACK_LEFT; - break; - case ERT_STEREO_BOTH_BUFFERS: - MRTs[i]=GL_BACK; - break; - case ERT_STEREO_RIGHT_BUFFER: - MRTs[i]=GL_BACK_RIGHT; - break; - case ERT_STEREO_LEFT_BUFFER: - MRTs[i]=GL_BACK_LEFT; - break; - default: - MRTs[i]=GL_AUX0+(targets[i].TargetType-ERT_AUX_BUFFER0); - break; - } - } - } - - extGlDrawBuffers(maxMultipleRTTs, MRTs.const_pointer()); - } - - clearBuffers(clearBackBuffer, clearZBuffer, false, color); - return true; -} - - -// returns the current size of the screen or rendertarget -const core::dimension2d& COpenGLDriver::getCurrentRenderTargetSize() const -{ - if (CurrentRendertargetSize.Width == 0) - return ScreenSize; - else - return CurrentRendertargetSize; -} - - -//! Clears the ZBuffer. -void COpenGLDriver::clearZBuffer() -{ - clearBuffers(false, true, false, 0x0); -} - - -//! Returns an image created from the last rendered frame. -IImage* COpenGLDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) -{ - if (target==video::ERT_MULTI_RENDER_TEXTURES || target==video::ERT_RENDER_TEXTURE || target==video::ERT_STEREO_BOTH_BUFFERS) - return 0; - - // allows to read pixels in top-to-bottom order -#ifdef GL_MESA_pack_invert - if (FeatureAvailable[IRR_MESA_pack_invert]) - glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); -#endif - - if (format==video::ECF_UNKNOWN) - format=getColorFormat(); - GLenum fmt; - GLenum type; - switch (format) - { - case ECF_A1R5G5B5: - fmt = GL_BGRA; - type = GL_UNSIGNED_SHORT_1_5_5_5_REV; - break; - case ECF_R5G6B5: - fmt = GL_RGB; - type = GL_UNSIGNED_SHORT_5_6_5; - break; - case ECF_R8G8B8: - fmt = GL_RGB; - type = GL_UNSIGNED_BYTE; - break; - case ECF_A8R8G8B8: - fmt = GL_BGRA; - if (Version > 101) - type = GL_UNSIGNED_INT_8_8_8_8_REV; - else - type = GL_UNSIGNED_BYTE; - break; - case ECF_R16F: - if (FeatureAvailable[IRR_ARB_texture_rg]) - fmt = GL_RED; - else - fmt = GL_LUMINANCE; -#ifdef GL_ARB_half_float_pixel - if (FeatureAvailable[IRR_ARB_half_float_pixel]) - type = GL_HALF_FLOAT_ARB; - else -#endif - { - type = GL_FLOAT; - format = ECF_R32F; - } - break; - case ECF_G16R16F: -#ifdef GL_ARB_texture_rg - if (FeatureAvailable[IRR_ARB_texture_rg]) - fmt = GL_RG; - else -#endif - fmt = GL_LUMINANCE_ALPHA; -#ifdef GL_ARB_half_float_pixel - if (FeatureAvailable[IRR_ARB_half_float_pixel]) - type = GL_HALF_FLOAT_ARB; - else -#endif - { - type = GL_FLOAT; - format = ECF_G32R32F; - } - break; - case ECF_A16B16G16R16F: - fmt = GL_BGRA; -#ifdef GL_ARB_half_float_pixel - if (FeatureAvailable[IRR_ARB_half_float_pixel]) - type = GL_HALF_FLOAT_ARB; - else -#endif - { - type = GL_FLOAT; - format = ECF_A32B32G32R32F; - } - break; - case ECF_R32F: - if (FeatureAvailable[IRR_ARB_texture_rg]) - fmt = GL_RED; - else - fmt = GL_LUMINANCE; - type = GL_FLOAT; - break; - case ECF_G32R32F: -#ifdef GL_ARB_texture_rg - if (FeatureAvailable[IRR_ARB_texture_rg]) - fmt = GL_RG; - else -#endif - fmt = GL_LUMINANCE_ALPHA; - type = GL_FLOAT; - break; - case ECF_A32B32G32R32F: - fmt = GL_BGRA; - type = GL_FLOAT; - break; - default: - fmt = GL_BGRA; - type = GL_UNSIGNED_BYTE; - break; - } - IImage* newImage = createImage(format, ScreenSize); - - u8* pixels = 0; - if (newImage) - pixels = static_cast(newImage->lock()); - if (pixels) - { - GLenum tgt=GL_FRONT; - switch (target) - { - case video::ERT_FRAME_BUFFER: - break; - case video::ERT_STEREO_LEFT_BUFFER: - tgt=GL_FRONT_LEFT; - break; - case video::ERT_STEREO_RIGHT_BUFFER: - tgt=GL_FRONT_RIGHT; - break; - default: - tgt=GL_AUX0+(target-video::ERT_AUX_BUFFER0); - break; - } - glReadBuffer(tgt); - glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, fmt, type, pixels); - testGLError(); - glReadBuffer(GL_BACK); - } - -#ifdef GL_MESA_pack_invert - if (FeatureAvailable[IRR_MESA_pack_invert]) - glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE); - else -#endif - if (pixels) - { - // opengl images are horizontally flipped, so we have to fix that here. - const s32 pitch=newImage->getPitch(); - u8* p2 = pixels + (ScreenSize.Height - 1) * pitch; - u8* tmpBuffer = new u8[pitch]; - for (u32 i=0; i < ScreenSize.Height; i += 2) - { - memcpy(tmpBuffer, pixels, pitch); -// for (u32 j=0; junlock(); - if (testGLError() || !pixels) - { - newImage->drop(); - return 0; - } - } - return newImage; -} - - -//! get depth texture for the given render target texture -ITexture* COpenGLDriver::createDepthTexture(ITexture* texture, bool shared) -{ - if ((texture->getDriverType() != EDT_OPENGL) || (!texture->isRenderTarget())) - return 0; - COpenGLTexture* tex = static_cast(texture); - - if (!tex->isFrameBufferObject()) - return 0; - - if (shared) - { - for (u32 i=0; igetSize()==texture->getSize()) - { - DepthTextures[i]->grab(); - return DepthTextures[i]; - } - } - DepthTextures.push_back(new COpenGLFBODepthTexture(texture->getSize(), "depth1", this)); - return DepthTextures.getLast(); - } - return (new COpenGLFBODepthTexture(texture->getSize(), "depth1", this)); -} - - -void COpenGLDriver::removeDepthTexture(ITexture* texture) -{ - for (u32 i=0; i= MaxUserClipPlanes) - return false; - - UserClipPlanes[index].Plane=plane; - enableClipPlane(index, enable); - return true; -} - - -void COpenGLDriver::uploadClipPlane(u32 index) -{ - // opengl needs an array of doubles for the plane equation - GLdouble clip_plane[4]; - clip_plane[0] = UserClipPlanes[index].Plane.Normal.X; - clip_plane[1] = UserClipPlanes[index].Plane.Normal.Y; - clip_plane[2] = UserClipPlanes[index].Plane.Normal.Z; - clip_plane[3] = UserClipPlanes[index].Plane.D; - glClipPlane(GL_CLIP_PLANE0 + index, clip_plane); -} - - -//! Enable/disable a clipping plane. -void COpenGLDriver::enableClipPlane(u32 index, bool enable) -{ - if (index >= MaxUserClipPlanes) - return; - if (enable) - { - if (!UserClipPlanes[index].Enabled) - { - uploadClipPlane(index); - glEnable(GL_CLIP_PLANE0 + index); - } - } - else - glDisable(GL_CLIP_PLANE0 + index); - - UserClipPlanes[index].Enabled=enable; -} - - -core::dimension2du COpenGLDriver::getMaxTextureSize() const -{ - return core::dimension2du(MaxTextureSize, MaxTextureSize); -} - - -//! Convert E_PRIMITIVE_TYPE to OpenGL equivalent -GLenum COpenGLDriver::primitiveTypeToGL(scene::E_PRIMITIVE_TYPE type) const -{ - switch (type) - { - case scene::EPT_POINTS: - return GL_POINTS; - case scene::EPT_LINE_STRIP: - return GL_LINE_STRIP; - case scene::EPT_LINE_LOOP: - return GL_LINE_LOOP; - case scene::EPT_LINES: - return GL_LINES; - case scene::EPT_TRIANGLE_STRIP: - return GL_TRIANGLE_STRIP; - case scene::EPT_TRIANGLE_FAN: - return GL_TRIANGLE_FAN; - case scene::EPT_TRIANGLES: - return GL_TRIANGLES; - case scene::EPT_QUAD_STRIP: - return GL_QUAD_STRIP; - case scene::EPT_QUADS: - return GL_QUADS; - case scene::EPT_POLYGON: - return GL_POLYGON; - case scene::EPT_POINT_SPRITES: -#ifdef GL_ARB_point_sprite - return GL_POINT_SPRITE_ARB; -#else - return GL_POINTS; -#endif - } - return GL_TRIANGLES; -} - - -GLenum COpenGLDriver::getGLBlend(E_BLEND_FACTOR factor) const -{ - GLenum r = 0; - switch (factor) - { - case EBF_ZERO: r = GL_ZERO; break; - case EBF_ONE: r = GL_ONE; break; - case EBF_DST_COLOR: r = GL_DST_COLOR; break; - case EBF_ONE_MINUS_DST_COLOR: r = GL_ONE_MINUS_DST_COLOR; break; - case EBF_SRC_COLOR: r = GL_SRC_COLOR; break; - case EBF_ONE_MINUS_SRC_COLOR: r = GL_ONE_MINUS_SRC_COLOR; break; - case EBF_SRC_ALPHA: r = GL_SRC_ALPHA; break; - case EBF_ONE_MINUS_SRC_ALPHA: r = GL_ONE_MINUS_SRC_ALPHA; break; - case EBF_DST_ALPHA: r = GL_DST_ALPHA; break; - case EBF_ONE_MINUS_DST_ALPHA: r = GL_ONE_MINUS_DST_ALPHA; break; - case EBF_SRC_ALPHA_SATURATE: r = GL_SRC_ALPHA_SATURATE; break; - } - return r; -} - -GLenum COpenGLDriver::getZBufferBits() const -{ - GLenum bits = 0; - switch (Params.ZBufferBits) - { - case 16: - bits = GL_DEPTH_COMPONENT16; - break; - case 24: - bits = GL_DEPTH_COMPONENT24; - break; - case 32: - bits = GL_DEPTH_COMPONENT32; - break; - default: - bits = GL_DEPTH_COMPONENT; - break; - } - return bits; -} - -#ifdef _IRR_COMPILE_WITH_CG_ -const CGcontext& COpenGLDriver::getCgContext() -{ - return CgContext; -} -#endif - - -} // end namespace -} // end namespace - -#endif // _IRR_COMPILE_WITH_OPENGL_ - -namespace irr -{ -namespace video -{ - - -// ----------------------------------- -// WINDOWS VERSION -// ----------------------------------- -#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ -IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, - io::IFileSystem* io, CIrrDeviceWin32* device) -{ -#ifdef _IRR_COMPILE_WITH_OPENGL_ - COpenGLDriver* ogl = new COpenGLDriver(params, io, device); - if (!ogl->initDriver(device)) - { - ogl->drop(); - ogl = 0; - } - return ogl; -#else - return 0; -#endif // _IRR_COMPILE_WITH_OPENGL_ -} -#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_ - -// ----------------------------------- -// MACOSX VERSION -// ----------------------------------- -#if defined(_IRR_COMPILE_WITH_OSX_DEVICE_) -IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, - io::IFileSystem* io, CIrrDeviceMacOSX *device) -{ -#ifdef _IRR_COMPILE_WITH_OPENGL_ - return new COpenGLDriver(params, io, device); -#else - return 0; -#endif // _IRR_COMPILE_WITH_OPENGL_ -} -#endif // _IRR_COMPILE_WITH_OSX_DEVICE_ - -// ----------------------------------- -// X11 VERSION -// ----------------------------------- -#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ -IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, - io::IFileSystem* io, CIrrDeviceLinux* device) -{ -#ifdef _IRR_COMPILE_WITH_OPENGL_ - COpenGLDriver* ogl = new COpenGLDriver(params, io, device); - if (!ogl->initDriver(device)) - { - ogl->drop(); - ogl = 0; - } - return ogl; -#else - return 0; -#endif // _IRR_COMPILE_WITH_OPENGL_ -} -#endif // _IRR_COMPILE_WITH_X11_DEVICE_ - - -// ----------------------------------- -// SDL VERSION -// ----------------------------------- -#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ -IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, - io::IFileSystem* io, CIrrDeviceSDL* device) -{ -#ifdef _IRR_COMPILE_WITH_OPENGL_ - return new COpenGLDriver(params, io, device); -#else - return 0; -#endif // _IRR_COMPILE_WITH_OPENGL_ -} -#endif // _IRR_COMPILE_WITH_SDL_DEVICE_ - -} // end namespace -} // end namespace - - +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COpenGLDriver.h" +// needed here also because of the create methods' parameters +#include "CNullDriver.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "COpenGLTexture.h" +#include "COpenGLMaterialRenderer.h" +#include "COpenGLShaderMaterialRenderer.h" +#include "COpenGLSLMaterialRenderer.h" +#include "COpenGLCgMaterialRenderer.h" +#include "COpenGLNormalMapRenderer.h" +#include "COpenGLParallaxMapRenderer.h" +#include "os.h" + +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ +#include +#endif + +namespace irr +{ +namespace video +{ + +// ----------------------------------------------------------------------- +// WINDOWS CONSTRUCTOR +// ----------------------------------------------------------------------- +#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ +//! Windows constructor and init code +COpenGLDriver::COpenGLDriver(const irr::SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceWin32* device) +: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), + CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), + AntiAlias(params.AntiAlias), RenderTargetTexture(0), + CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), + CurrentTarget(ERT_FRAME_BUFFER), Params(params), + HDc(0), Window(static_cast(params.WindowId)), Win32Device(device), + DeviceType(EIDT_WIN32) +{ + #ifdef _DEBUG + setDebugName("COpenGLDriver"); + #endif + + #ifdef _IRR_COMPILE_WITH_CG_ + CgContext = 0; + #endif +} + + +bool COpenGLDriver::changeRenderContext(const SExposedVideoData& videoData, CIrrDeviceWin32* device) +{ + if (videoData.OpenGLWin32.HWnd && videoData.OpenGLWin32.HDc && videoData.OpenGLWin32.HRc) + { + if (!wglMakeCurrent((HDC)videoData.OpenGLWin32.HDc, (HGLRC)videoData.OpenGLWin32.HRc)) + { + os::Printer::log("Render Context switch failed."); + return false; + } + else + { + HDc = (HDC)videoData.OpenGLWin32.HDc; + } + } + // set back to main context + else if (HDc != ExposedData.OpenGLWin32.HDc) + { + if (!wglMakeCurrent((HDC)ExposedData.OpenGLWin32.HDc, (HGLRC)ExposedData.OpenGLWin32.HRc)) + { + os::Printer::log("Render Context switch failed."); + return false; + } + else + { + HDc = (HDC)ExposedData.OpenGLWin32.HDc; + } + } + return true; +} + +//! inits the open gl driver +bool COpenGLDriver::initDriver(CIrrDeviceWin32* device) +{ + // Create a window to test antialiasing support + const fschar_t* ClassName = __TEXT("GLCIrrDeviceWin32"); + HINSTANCE lhInstance = GetModuleHandle(0); + + // Register Class + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)DefWindowProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = lhInstance; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = 0; + wcex.lpszClassName = ClassName; + wcex.hIconSm = 0; + wcex.hIcon = 0; + RegisterClassEx(&wcex); + + RECT clientSize; + clientSize.top = 0; + clientSize.left = 0; + clientSize.right = Params.WindowSize.Width; + clientSize.bottom = Params.WindowSize.Height; + + DWORD style = WS_POPUP; + if (!Params.Fullscreen) + style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + + AdjustWindowRect(&clientSize, style, FALSE); + + const s32 realWidth = clientSize.right - clientSize.left; + const s32 realHeight = clientSize.bottom - clientSize.top; + + const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2; + const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; + + HWND temporary_wnd=CreateWindow(ClassName, __TEXT(""), style, windowLeft, + windowTop, realWidth, realHeight, NULL, NULL, lhInstance, NULL); + + if (!temporary_wnd) + { + os::Printer::log("Cannot create a temporary window.", ELL_ERROR); + UnregisterClass(ClassName, lhInstance); + return false; + } + + HDc = GetDC(temporary_wnd); + + // Set up pixel format descriptor with desired parameters + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + (Params.Doublebuffer?PFD_DOUBLEBUFFER:0) | // Must Support Double Buffering + (Params.Stereobuffer?PFD_STEREO:0), // Must Support Stereo Buffer + PFD_TYPE_RGBA, // Request An RGBA Format + Params.Bits, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + Params.ZBufferBits, // Z-Buffer (Depth Buffer) + BYTE(Params.Stencilbuffer ? 1 : 0), // Stencil Buffer Depth + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + GLuint PixelFormat; + + for (u32 i=0; i<6; ++i) + { + if (i == 1) + { + if (Params.Stencilbuffer) + { + os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING); + Params.Stencilbuffer = false; + pfd.cStencilBits = 0; + } + else + continue; + } + else + if (i == 2) + { + pfd.cDepthBits = 24; + } + else + if (i == 3) + { + if (Params.Bits!=16) + pfd.cDepthBits = 16; + else + continue; + } + else + if (i == 4) + { + // try single buffer + if (Params.Doublebuffer) + pfd.dwFlags &= ~PFD_DOUBLEBUFFER; + else + continue; + } + else + if (i == 5) + { + os::Printer::log("Cannot create a GL device context", "No suitable format for temporary window.", ELL_ERROR); + ReleaseDC(temporary_wnd, HDc); + DestroyWindow(temporary_wnd); + UnregisterClass(ClassName, lhInstance); + return false; + } + + // choose pixelformat + PixelFormat = ChoosePixelFormat(HDc, &pfd); + if (PixelFormat) + break; + } + + SetPixelFormat(HDc, PixelFormat, &pfd); + HGLRC hrc=wglCreateContext(HDc); + if (!hrc) + { + os::Printer::log("Cannot create a temporary GL rendering context.", ELL_ERROR); + ReleaseDC(temporary_wnd, HDc); + DestroyWindow(temporary_wnd); + UnregisterClass(ClassName, lhInstance); + return false; + } + + SExposedVideoData data; + data.OpenGLWin32.HDc = HDc; + data.OpenGLWin32.HRc = hrc; + data.OpenGLWin32.HWnd = temporary_wnd; + + + if (!changeRenderContext(data, device)) + { + os::Printer::log("Cannot activate a temporary GL rendering context.", ELL_ERROR); + wglDeleteContext(hrc); + ReleaseDC(temporary_wnd, HDc); + DestroyWindow(temporary_wnd); + UnregisterClass(ClassName, lhInstance); + return false; + } + + core::stringc wglExtensions; +#ifdef WGL_ARB_extensions_string + PFNWGLGETEXTENSIONSSTRINGARBPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); + if (irrGetExtensionsString) + wglExtensions = irrGetExtensionsString(HDc); +#elif defined(WGL_EXT_extensions_string) + PFNWGLGETEXTENSIONSSTRINGEXTPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"); + if (irrGetExtensionsString) + wglExtensions = irrGetExtensionsString(HDc); +#endif + const bool pixel_format_supported = (wglExtensions.find("WGL_ARB_pixel_format") != -1); + const bool multi_sample_supported = ((wglExtensions.find("WGL_ARB_multisample") != -1) || + (wglExtensions.find("WGL_EXT_multisample") != -1) || (wglExtensions.find("WGL_3DFX_multisample") != -1) ); +#ifdef _DEBUG + os::Printer::log("WGL_extensions", wglExtensions); +#endif + +#ifdef WGL_ARB_pixel_format + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat_ARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); + if (pixel_format_supported && wglChoosePixelFormat_ARB) + { + // This value determines the number of samples used for antialiasing + // My experience is that 8 does not show a big + // improvement over 4, but 4 shows a big improvement + // over 2. + + if(AntiAlias > 32) + AntiAlias = 32; + + f32 fAttributes[] = {0.0, 0.0}; + s32 iAttributes[] = + { + WGL_DRAW_TO_WINDOW_ARB,1, + WGL_SUPPORT_OPENGL_ARB,1, + WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB, + WGL_COLOR_BITS_ARB,(Params.Bits==32) ? 24 : 15, + WGL_ALPHA_BITS_ARB,(Params.Bits==32) ? 8 : 1, + WGL_DEPTH_BITS_ARB,Params.ZBufferBits, // 10,11 + WGL_STENCIL_BITS_ARB,Params.Stencilbuffer ? 1 : 0, + WGL_DOUBLE_BUFFER_ARB,Params.Doublebuffer ? 1 : 0, + WGL_STEREO_ARB,Params.Stereobuffer ? 1 : 0, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, +#ifdef WGL_ARB_multisample + WGL_SAMPLES_ARB,AntiAlias, // 20,21 + WGL_SAMPLE_BUFFERS_ARB, 1, +#elif defined(WGL_EXT_multisample) + WGL_SAMPLES_EXT,AntiAlias, // 20,21 + WGL_SAMPLE_BUFFERS_EXT, 1, +#elif defined(WGL_3DFX_multisample) + WGL_SAMPLES_3DFX,AntiAlias, // 20,21 + WGL_SAMPLE_BUFFERS_3DFX, 1, +#endif +#ifdef WGL_ARB_framebuffer_sRGB + WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, Params.HandleSRGB ? 1:0, +#elif defined(WGL_EXT_framebuffer_sRGB) + WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT, Params.HandleSRGB ? 1:0, +#endif +// WGL_DEPTH_FLOAT_EXT, 1, + 0,0,0,0 + }; + int iAttrSize = sizeof(iAttributes)/sizeof(int); + const bool framebuffer_srgb_supported = ((wglExtensions.find("WGL_ARB_framebuffer_sRGB") != -1) || + (wglExtensions.find("WGL_EXT_framebuffer_sRGB") != -1)); + if (!framebuffer_srgb_supported) + { + memmove(&iAttributes[24],&iAttributes[26],sizeof(int)*(iAttrSize-26)); + iAttrSize -= 2; + } + if (!multi_sample_supported) + { + memmove(&iAttributes[20],&iAttributes[24],sizeof(int)*(iAttrSize-24)); + iAttrSize -= 4; + } + + s32 rv=0; + // Try to get an acceptable pixel format + do + { + int pixelFormat=0; + UINT numFormats=0; + const BOOL valid = wglChoosePixelFormat_ARB(HDc,iAttributes,fAttributes,1,&pixelFormat,&numFormats); + + if (valid && numFormats) + rv = pixelFormat; + else + iAttributes[21] -= 1; + } + while(rv==0 && iAttributes[21]>1); + if (rv) + { + PixelFormat=rv; + AntiAlias=iAttributes[21]; + } + } + else +#endif + AntiAlias=0; + + wglMakeCurrent(HDc, NULL); + wglDeleteContext(hrc); + ReleaseDC(temporary_wnd, HDc); + DestroyWindow(temporary_wnd); + UnregisterClass(ClassName, lhInstance); + + // get hdc + HDc=GetDC(Window); + if (!HDc) + { + os::Printer::log("Cannot create a GL device context.", ELL_ERROR); + return false; + } + + // search for pixel format the simple way + if (PixelFormat==0 || (!SetPixelFormat(HDc, PixelFormat, &pfd))) + { + for (u32 i=0; i<5; ++i) + { + if (i == 1) + { + if (Params.Stencilbuffer) + { + os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING); + Params.Stencilbuffer = false; + pfd.cStencilBits = 0; + } + else + continue; + } + else + if (i == 2) + { + pfd.cDepthBits = 24; + } + if (i == 3) + { + if (Params.Bits!=16) + pfd.cDepthBits = 16; + else + continue; + } + else + if (i == 4) + { + os::Printer::log("Cannot create a GL device context", "No suitable format.", ELL_ERROR); + return false; + } + + // choose pixelformat + PixelFormat = ChoosePixelFormat(HDc, &pfd); + if (PixelFormat) + break; + } + } + + // set pixel format + if (!SetPixelFormat(HDc, PixelFormat, &pfd)) + { + os::Printer::log("Cannot set the pixel format.", ELL_ERROR); + return false; + } + os::Printer::log("Pixel Format", core::stringc(PixelFormat).c_str(), ELL_DEBUG); + + // create rendering context +#ifdef WGL_ARB_create_context + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs_ARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + if (wglCreateContextAttribs_ARB) + { + int iAttribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, + WGL_CONTEXT_MINOR_VERSION_ARB, 1, + 0 + }; + hrc=wglCreateContextAttribs_ARB(HDc, 0, iAttribs); + } + else +#endif + hrc=wglCreateContext(HDc); + + if (!hrc) + { + os::Printer::log("Cannot create a GL rendering context.", ELL_ERROR); + return false; + } + + // set exposed data + ExposedData.OpenGLWin32.HDc = HDc; + ExposedData.OpenGLWin32.HRc = hrc; + ExposedData.OpenGLWin32.HWnd = Window; + + // activate rendering context + + if (!changeRenderContext(ExposedData, device)) + { + os::Printer::log("Cannot activate GL rendering context", ELL_ERROR); + wglDeleteContext(hrc); + return false; + } + + int pf = GetPixelFormat(HDc); + DescribePixelFormat(HDc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + if (pfd.cAlphaBits != 0) + { + if (pfd.cRedBits == 8) + ColorFormat = ECF_A8R8G8B8; + else + ColorFormat = ECF_A1R5G5B5; + } + else + { + if (pfd.cRedBits == 8) + ColorFormat = ECF_R8G8B8; + else + ColorFormat = ECF_R5G6B5; + } + + genericDriverInit(); + + extGlSwapInterval(Params.Vsync ? 1 : 0); + return true; +} + +#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + +// ----------------------------------------------------------------------- +// MacOSX CONSTRUCTOR +// ----------------------------------------------------------------------- +#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ +//! Windows constructor and init code +COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceMacOSX *device) +: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), + CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), + AntiAlias(params.AntiAlias), RenderTargetTexture(0), + CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), + CurrentTarget(ERT_FRAME_BUFFER), Params(params), + OSXDevice(device), DeviceType(EIDT_OSX) +{ + #ifdef _DEBUG + setDebugName("COpenGLDriver"); + #endif + + #ifdef _IRR_COMPILE_WITH_CG_ + CgContext = 0; + #endif + + genericDriverInit(); +} + +#endif + +// ----------------------------------------------------------------------- +// LINUX CONSTRUCTOR +// ----------------------------------------------------------------------- +#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ +//! Linux constructor and init code +COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceLinux* device) +: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), + CurrentRenderMode(ERM_NONE), ResetRenderStates(true), + Transformation3DChanged(true), AntiAlias(params.AntiAlias), + RenderTargetTexture(0), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), + CurrentTarget(ERT_FRAME_BUFFER), Params(params), + X11Device(device), DeviceType(EIDT_X11) +{ + #ifdef _DEBUG + setDebugName("COpenGLDriver"); + #endif + + #ifdef _IRR_COMPILE_WITH_CG_ + CgContext = 0; + #endif +} + + +bool COpenGLDriver::changeRenderContext(const SExposedVideoData& videoData, CIrrDeviceLinux* device) +{ + if (videoData.OpenGLLinux.X11Window) + { + if (videoData.OpenGLLinux.X11Display && videoData.OpenGLLinux.X11Context) + { + if (!glXMakeCurrent((Display*)videoData.OpenGLLinux.X11Display, videoData.OpenGLLinux.X11Window, (GLXContext)videoData.OpenGLLinux.X11Context)) + { + os::Printer::log("Render Context switch failed."); + return false; + } + else + { + Drawable = videoData.OpenGLLinux.X11Window; + X11Display = (Display*)videoData.OpenGLLinux.X11Display; + } + } + else + { + // in case we only got a window ID, try with the existing values for display and context + if (!glXMakeCurrent((Display*)ExposedData.OpenGLLinux.X11Display, videoData.OpenGLLinux.X11Window, (GLXContext)ExposedData.OpenGLLinux.X11Context)) + { + os::Printer::log("Render Context switch failed."); + return false; + } + else + { + Drawable = videoData.OpenGLLinux.X11Window; + X11Display = (Display*)ExposedData.OpenGLLinux.X11Display; + } + } + } + // set back to main context + else if (X11Display != ExposedData.OpenGLLinux.X11Display) + { + if (!glXMakeCurrent((Display*)ExposedData.OpenGLLinux.X11Display, ExposedData.OpenGLLinux.X11Window, (GLXContext)ExposedData.OpenGLLinux.X11Context)) + { + os::Printer::log("Render Context switch failed."); + return false; + } + else + { + Drawable = ExposedData.OpenGLLinux.X11Window; + X11Display = (Display*)ExposedData.OpenGLLinux.X11Display; + } + } + return true; +} + + +//! inits the open gl driver +bool COpenGLDriver::initDriver(CIrrDeviceLinux* device) +{ + ExposedData.OpenGLLinux.X11Context = glXGetCurrentContext(); + ExposedData.OpenGLLinux.X11Display = glXGetCurrentDisplay(); + ExposedData.OpenGLLinux.X11Window = (unsigned long)Params.WindowId; + Drawable = glXGetCurrentDrawable(); + X11Display = (Display*)ExposedData.OpenGLLinux.X11Display; + + genericDriverInit(); + + // set vsync + extGlSwapInterval(Params.Vsync ? 1 : 0); + return true; +} + +#endif // _IRR_COMPILE_WITH_X11_DEVICE_ + + +// ----------------------------------------------------------------------- +// SDL CONSTRUCTOR +// ----------------------------------------------------------------------- +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ +//! SDL constructor and init code +COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceSDL* device) +: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), + CurrentRenderMode(ERM_NONE), ResetRenderStates(true), + Transformation3DChanged(true), AntiAlias(params.AntiAlias), + RenderTargetTexture(0), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), + CurrentTarget(ERT_FRAME_BUFFER), Params(params), + SDLDevice(device), DeviceType(EIDT_SDL) +{ + #ifdef _DEBUG + setDebugName("COpenGLDriver"); + #endif + + #ifdef _IRR_COMPILE_WITH_CG_ + CgContext = 0; + #endif + + genericDriverInit(); +} + +#endif // _IRR_COMPILE_WITH_SDL_DEVICE_ + + +//! destructor +COpenGLDriver::~COpenGLDriver() +{ + #ifdef _IRR_COMPILE_WITH_CG_ + if (CgContext) + cgDestroyContext(CgContext); + #endif + + RequestedLights.clear(); + + deleteMaterialRenders(); + + CurrentTexture.clear(); + // I get a blue screen on my laptop, when I do not delete the + // textures manually before releasing the dc. Oh how I love this. + deleteAllTextures(); + removeAllOcclusionQueries(); + removeAllHardwareBuffers(); + +#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + if (DeviceType == EIDT_WIN32) + { + + if (ExposedData.OpenGLWin32.HRc) + { + if (!wglMakeCurrent(HDc, 0)) + os::Printer::log("Release of dc and rc failed.", ELL_WARNING); + + if (!wglDeleteContext((HGLRC)ExposedData.OpenGLWin32.HRc)) + os::Printer::log("Release of rendering context failed.", ELL_WARNING); + } + + if (HDc) + ReleaseDC(Window, HDc); + } +#endif +} + +// ----------------------------------------------------------------------- +// METHODS +// ----------------------------------------------------------------------- + +bool COpenGLDriver::genericDriverInit() +{ + Name=L"OpenGL "; + Name.append(glGetString(GL_VERSION)); + s32 pos=Name.findNext(L' ', 7); + if (pos != -1) + Name=Name.subString(0, pos); + printVersion(); + + // print renderer information + const GLubyte* renderer = glGetString(GL_RENDERER); + const GLubyte* vendor = glGetString(GL_VENDOR); + if (renderer && vendor) + { + os::Printer::log(reinterpret_cast(renderer), reinterpret_cast(vendor), ELL_INFORMATION); + VendorName = reinterpret_cast(vendor); + } + + u32 i; + CurrentTexture.clear(); + // load extensions + initExtensions(Params.Stencilbuffer); + if (queryFeature(EVDF_ARB_GLSL)) + { + char buf[32]; + const u32 maj = ShaderLanguageVersion/100; + snprintf(buf, 32, "%u.%u", maj, ShaderLanguageVersion-maj*100); + os::Printer::log("GLSL version", buf, ELL_INFORMATION); + } + else + os::Printer::log("GLSL not available.", ELL_INFORMATION); + DriverAttributes->setAttribute("MaxTextures", MaxTextureUnits); + DriverAttributes->setAttribute("MaxSupportedTextures", MaxSupportedTextures); + DriverAttributes->setAttribute("MaxLights", MaxLights); + DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy); + DriverAttributes->setAttribute("MaxUserClipPlanes", MaxUserClipPlanes); + DriverAttributes->setAttribute("MaxAuxBuffers", MaxAuxBuffers); + DriverAttributes->setAttribute("MaxMultipleRenderTargets", MaxMultipleRenderTargets); + DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices); + DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize); + DriverAttributes->setAttribute("MaxGeometryVerticesOut", (s32)MaxGeometryVerticesOut); + DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias); + DriverAttributes->setAttribute("Version", Version); + DriverAttributes->setAttribute("ShaderLanguageVersion", ShaderLanguageVersion); + DriverAttributes->setAttribute("AntiAlias", AntiAlias); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + // Reset The Current Viewport + glViewport(0, 0, Params.WindowSize.Width, Params.WindowSize.Height); + + UserClipPlanes.reallocate(MaxUserClipPlanes); + for (i=0; i(i), core::IdentityMatrix); + + setAmbientLight(SColorf(0.0f,0.0f,0.0f,0.0f)); +#ifdef GL_EXT_separate_specular_color + if (FeatureAvailable[IRR_EXT_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); +#endif + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); + + Params.HandleSRGB &= ((FeatureAvailable[IRR_ARB_framebuffer_sRGB] || FeatureAvailable[IRR_EXT_framebuffer_sRGB]) && + FeatureAvailable[IRR_EXT_texture_sRGB]); +#if defined(GL_ARB_framebuffer_sRGB) + if (Params.HandleSRGB) + glEnable(GL_FRAMEBUFFER_SRGB); +#elif defined(GL_EXT_framebuffer_sRGB) + if (Params.HandleSRGB) + glEnable(GL_FRAMEBUFFER_SRGB_EXT); +#endif + +// This is a fast replacement for NORMALIZE_NORMALS +// if ((Version>101) || FeatureAvailable[IRR_EXT_rescale_normal]) +// glEnable(GL_RESCALE_NORMAL_EXT); + + glClearDepth(1.0); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST); + glDepthFunc(GL_LEQUAL); + glFrontFace(GL_CW); + // adjust flat coloring scheme to DirectX version +#if defined(GL_ARB_provoking_vertex) || defined(GL_EXT_provoking_vertex) + extGlProvokingVertex(GL_FIRST_VERTEX_CONVENTION_EXT); +#endif + + // create material renderers + createMaterialRenderers(); + + // set the renderstates + setRenderStates3DMode(); + + glAlphaFunc(GL_GREATER, 0.f); + + // set fog mode + setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); + + // create matrix for flipping textures + TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0,0), core::vector2df(0,1.0f), core::vector2df(1.0f,-1.0f)); + + // We need to reset once more at the beginning of the first rendering. + // This fixes problems with intermediate changes to the material during texture load. + ResetRenderStates = true; + + #ifdef _IRR_COMPILE_WITH_CG_ + CgContext = cgCreateContext(); + #endif + + return true; +} + + +void COpenGLDriver::createMaterialRenderers() +{ + // create OpenGL material renderers + + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID_2_LAYER(this)); + + // add the same renderer for all lightmap types + COpenGLMaterialRenderer_LIGHTMAP* lmr = new COpenGLMaterialRenderer_LIGHTMAP(this); + addMaterialRenderer(lmr); // for EMT_LIGHTMAP: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4: + lmr->drop(); + + // add remaining material renderer + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_DETAIL_MAP(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SPHERE_MAP(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_REFLECTION_2_LAYER(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(this)); + + // add normal map renderers + s32 tmp = 0; + video::IMaterialRenderer* renderer = 0; + renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_SOLID].Renderer); + renderer->drop(); + renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); + renderer->drop(); + renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); + renderer->drop(); + + // add parallax map renderers + renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_SOLID].Renderer); + renderer->drop(); + renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); + renderer->drop(); + renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); + renderer->drop(); + + // add basic 1 texture blending + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_ONETEXTURE_BLEND(this)); +} + + +//! presents the rendered scene on the screen, returns false if failed +bool COpenGLDriver::endScene() +{ + CNullDriver::endScene(); + + glFlush(); + +#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + if (DeviceType == EIDT_WIN32) + return SwapBuffers(HDc) == TRUE; +#endif + +#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ + if (DeviceType == EIDT_X11) + { + glXSwapBuffers(X11Display, Drawable); + return true; + } +#endif + +#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ + if (DeviceType == EIDT_OSX) + { + OSXDevice->flush(); + return true; + } +#endif + +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ + if (DeviceType == EIDT_SDL) + { + SDL_GL_SwapBuffers(); + return true; + } +#endif + + // todo: console device present + + return false; +} + + +//! clears the zbuffer and color buffer +void COpenGLDriver::clearBuffers(bool backBuffer, bool zBuffer, bool stencilBuffer, SColor color) +{ + GLbitfield mask = 0; + if (backBuffer) + { + const f32 inv = 1.0f / 255.0f; + glClearColor(color.getRed() * inv, color.getGreen() * inv, + color.getBlue() * inv, color.getAlpha() * inv); + + mask |= GL_COLOR_BUFFER_BIT; + } + + if (zBuffer) + { + glDepthMask(GL_TRUE); + LastMaterial.ZWriteEnable=true; + mask |= GL_DEPTH_BUFFER_BIT; + } + + if (stencilBuffer) + mask |= GL_STENCIL_BUFFER_BIT; + + if (mask) + glClear(mask); +} + + +//! init call for rendering start +bool COpenGLDriver::beginScene(bool backBuffer, bool zBuffer, SColor color, + const SExposedVideoData& videoData, core::rect* sourceRect) +{ + CNullDriver::beginScene(backBuffer, zBuffer, color, videoData, sourceRect); + + switch (DeviceType) + { +#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + case EIDT_WIN32: + changeRenderContext(videoData, Win32Device); + break; +#endif +#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ + case EIDT_X11: + changeRenderContext(videoData, X11Device); + break; +#endif + default: + changeRenderContext(videoData, (void*)0); + break; + } + +#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) + if (DeviceType == EIDT_SDL) + { + // todo: SDL sets glFrontFace(GL_CCW) after driver creation, + // it would be better if this was fixed elsewhere. + glFrontFace(GL_CW); + } +#endif + + clearBuffers(backBuffer, zBuffer, false, color); + return true; +} + + +//! Returns the transformation set by setTransform +const core::matrix4& COpenGLDriver::getTransform(E_TRANSFORMATION_STATE state) const +{ + return Matrices[state]; +} + + +//! sets transformation +void COpenGLDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) +{ + Matrices[state] = mat; + Transformation3DChanged = true; + + switch (state) + { + case ETS_VIEW: + case ETS_WORLD: + { + // OpenGL only has a model matrix, view and world is not existent. so lets fake these two. + glMatrixMode(GL_MODELVIEW); + + // first load the viewing transformation for user clip planes + glLoadMatrixf((Matrices[ETS_VIEW]).pointer()); + + // we have to update the clip planes to the latest view matrix + for (u32 i=0; i= MATERIAL_MAX_TEXTURES) + break; + + const bool isRTT = Material.getTexture(i) && Material.getTexture(i)->isRenderTarget(); + + if (MultiTextureExtension) + extGlActiveTexture(GL_TEXTURE0_ARB + i); + + glMatrixMode(GL_TEXTURE); + if (!isRTT && mat.isIdentity() ) + glLoadIdentity(); + else + { + GLfloat glmat[16]; + if (isRTT) + getGLTextureMatrix(glmat, mat * TextureFlipMatrix); + else + getGLTextureMatrix(glmat, mat); + glLoadMatrixf(glmat); + } + break; + } + } +} + + +bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (!FeatureAvailable[IRR_ARB_vertex_buffer_object]) + return false; + +#if defined(GL_ARB_vertex_buffer_object) + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const void* vertices=mb->getVertices(); + const u32 vertexCount=mb->getVertexCount(); + const E_VERTEX_TYPE vType=mb->getVertexType(); + const u32 vertexSize = getVertexPitchFromType(vType); + + const c8* vbuf = static_cast(vertices); + core::array buffer; + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + { + //buffer vertex data, and convert colors... + buffer.set_used(vertexSize * vertexCount); + memcpy(buffer.pointer(), vertices, vertexSize * vertexCount); + vbuf = buffer.const_pointer(); + + // in order to convert the colors into opengl format (RGBA) + switch (vType) + { + case EVT_STANDARD: + { + S3DVertex* pb = reinterpret_cast(buffer.pointer()); + const S3DVertex* po = static_cast(vertices); + for (u32 i=0; i(buffer.pointer()); + const S3DVertex2TCoords* po = static_cast(vertices); + for (u32 i=0; i(buffer.pointer()); + const S3DVertexTangents* po = static_cast(vertices); + for (u32 i=0; ivbo_verticesID) + { + extGlGenBuffers(1, &HWBuffer->vbo_verticesID); + if (!HWBuffer->vbo_verticesID) + return false; + newBuffer=true; + } + else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize) + { + newBuffer=true; + } + + extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); + + //copy data to graphics card + glGetError(); // clear error storage + if (!newBuffer) + extGlBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, vbuf); + else + { + HWBuffer->vbo_verticesSize = vertexCount*vertexSize; + + if (HWBuffer->Mapped_Vertex==scene::EHM_STATIC) + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STATIC_DRAW); + else if (HWBuffer->Mapped_Vertex==scene::EHM_DYNAMIC) + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_DYNAMIC_DRAW); + else //scene::EHM_STREAM + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STREAM_DRAW); + } + + extGlBindBuffer(GL_ARRAY_BUFFER, 0); + + return (glGetError() == GL_NO_ERROR); +#else + return false; +#endif +} + + +bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (!FeatureAvailable[IRR_ARB_vertex_buffer_object]) + return false; + +#if defined(GL_ARB_vertex_buffer_object) + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + + const void* indices=mb->getIndices(); + u32 indexCount= mb->getIndexCount(); + + GLenum indexSize; + switch (mb->getIndexType()) + { + case EIT_16BIT: + { + indexSize=sizeof(u16); + break; + } + case EIT_32BIT: + { + indexSize=sizeof(u32); + break; + } + default: + { + return false; + } + } + + + //get or create buffer + bool newBuffer=false; + if (!HWBuffer->vbo_indicesID) + { + extGlGenBuffers(1, &HWBuffer->vbo_indicesID); + if (!HWBuffer->vbo_indicesID) + return false; + newBuffer=true; + } + else if (HWBuffer->vbo_indicesSize < indexCount*indexSize) + { + newBuffer=true; + } + + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + + //copy data to graphics card + glGetError(); // clear error storage + if (!newBuffer) + extGlBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices); + else + { + HWBuffer->vbo_indicesSize = indexCount*indexSize; + + if (HWBuffer->Mapped_Index==scene::EHM_STATIC) + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW); + else if (HWBuffer->Mapped_Index==scene::EHM_DYNAMIC) + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW); + else //scene::EHM_STREAM + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STREAM_DRAW); + } + + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + return (glGetError() == GL_NO_ERROR); +#else + return false; +#endif +} + + +//! updates hardware buffer if needed +bool COpenGLDriver::updateHardwareBuffer(SHWBufferLink *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex() + || !((SHWBufferLink_opengl*)HWBuffer)->vbo_verticesID) + { + + HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); + + if (!updateVertexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) + return false; + } + } + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index() + || !((SHWBufferLink_opengl*)HWBuffer)->vbo_indicesID) + { + + HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); + + if (!updateIndexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) + return false; + } + } + + return true; +} + + +//! Create hardware buffer from meshbuffer +COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::IMeshBuffer* mb) +{ +#if defined(GL_ARB_vertex_buffer_object) + if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER)) + return 0; + + SHWBufferLink_opengl *HWBuffer=new SHWBufferLink_opengl(mb); + + //add to map + HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer); + + HWBuffer->ChangedID_Vertex=HWBuffer->MeshBuffer->getChangedID_Vertex(); + HWBuffer->ChangedID_Index=HWBuffer->MeshBuffer->getChangedID_Index(); + HWBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex(); + HWBuffer->Mapped_Index=mb->getHardwareMappingHint_Index(); + HWBuffer->LastUsed=0; + HWBuffer->vbo_verticesID=0; + HWBuffer->vbo_indicesID=0; + HWBuffer->vbo_verticesSize=0; + HWBuffer->vbo_indicesSize=0; + + if (!updateHardwareBuffer(HWBuffer)) + { + deleteHardwareBuffer(HWBuffer); + return 0; + } + + return HWBuffer; +#else + return 0; +#endif +} + + +void COpenGLDriver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) + return; + +#if defined(GL_ARB_vertex_buffer_object) + SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; + if (HWBuffer->vbo_verticesID) + { + extGlDeleteBuffers(1, &HWBuffer->vbo_verticesID); + HWBuffer->vbo_verticesID=0; + } + if (HWBuffer->vbo_indicesID) + { + extGlDeleteBuffers(1, &HWBuffer->vbo_indicesID); + HWBuffer->vbo_indicesID=0; + } +#endif + + CNullDriver::deleteHardwareBuffer(_HWBuffer); +} + + +//! Draw hardware buffer +void COpenGLDriver::drawHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) + return; + + updateHardwareBuffer(_HWBuffer); //check if update is needed + _HWBuffer->LastUsed=0; //reset count + +#if defined(GL_ARB_vertex_buffer_object) + SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; + + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const void *vertices=mb->getVertices(); + const void *indexList=mb->getIndices(); + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); + vertices=0; + } + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + { + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + indexList=0; + } + + drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList, mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType()); + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + extGlBindBuffer(GL_ARRAY_BUFFER, 0); + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +#endif +} + + +//! Create occlusion query. +/** Use node for identification and mesh for occlusion test. */ +void COpenGLDriver::addOcclusionQuery(scene::ISceneNode* node, + const scene::IMesh* mesh) +{ + if (!queryFeature(EVDF_OCCLUSION_QUERY)) + return; + + CNullDriver::addOcclusionQuery(node, mesh); + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if ((index != -1) && (OcclusionQueries[index].UID == 0)) + extGlGenQueries(1, reinterpret_cast(&OcclusionQueries[index].UID)); +} + + +//! Remove occlusion query. +void COpenGLDriver::removeOcclusionQuery(scene::ISceneNode* node) +{ + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + if (OcclusionQueries[index].UID != 0) + extGlDeleteQueries(1, reinterpret_cast(&OcclusionQueries[index].UID)); + CNullDriver::removeOcclusionQuery(node); + } +} + + +//! Run occlusion query. Draws mesh stored in query. +/** If the mesh shall not be rendered visible, use +overrideMaterial to disable the color and depth buffer. */ +void COpenGLDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible) +{ + if (!node) + return; + + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + if (OcclusionQueries[index].UID) + extGlBeginQuery( +#ifdef GL_ARB_occlusion_query + GL_SAMPLES_PASSED_ARB, +#else + 0, +#endif + OcclusionQueries[index].UID); + CNullDriver::runOcclusionQuery(node,visible); + if (OcclusionQueries[index].UID) + extGlEndQuery( +#ifdef GL_ARB_occlusion_query + GL_SAMPLES_PASSED_ARB); +#else + 0); +#endif + testGLError(); + } +} + + +//! Update occlusion query. Retrieves results from GPU. +/** If the query shall not block, set the flag to false. +Update might not occur in this case, though */ +void COpenGLDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block) +{ + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + // not yet started + if (OcclusionQueries[index].Run==u32(~0)) + return; + GLint available = block?GL_TRUE:GL_FALSE; + if (!block) + extGlGetQueryObjectiv(OcclusionQueries[index].UID, +#ifdef GL_ARB_occlusion_query + GL_QUERY_RESULT_AVAILABLE_ARB, +#elif defined(GL_NV_occlusion_query) + GL_PIXEL_COUNT_AVAILABLE_NV, +#else + 0, +#endif + &available); + testGLError(); + if (available==GL_TRUE) + { + extGlGetQueryObjectiv(OcclusionQueries[index].UID, +#ifdef GL_ARB_occlusion_query + GL_QUERY_RESULT_ARB, +#elif defined(GL_NV_occlusion_query) + GL_PIXEL_COUNT_NV, +#else + 0, +#endif + &available); + if (queryFeature(EVDF_OCCLUSION_QUERY)) + OcclusionQueries[index].Result = available; + } + testGLError(); + } +} + + +//! Return query result. +/** Return value is the number of visible pixels/fragments. +The value is a safe approximation, i.e. can be larger than the +actual value of pixels. */ +u32 COpenGLDriver::getOcclusionQueryResult(scene::ISceneNode* node) const +{ + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + return OcclusionQueries[index].Result; + else + return ~0; +} + + +// small helper function to create vertex buffer object adress offsets +static inline u8* buffer_offset(const long offset) +{ + return ((u8*)0 + offset); +} + + +//! draws a vertex primitive list +void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + if (!primitiveCount || !vertexCount) + return; + + if (!checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + + if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(vertices, vertexCount, vType); + + // draw everything + setRenderStates3DMode(); + + if (MultiTextureExtension) + extGlClientActiveTexture(GL_TEXTURE0_ARB); + + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + glEnableClientState(GL_NORMAL_ARRAY); + +//due to missing defines in OSX headers, we have to be more specific with this check +//#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra) +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (vertices) + { + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + { + switch (vType) + { + case EVT_STANDARD: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + break; + case EVT_2TCOORDS: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Color); + break; + case EVT_TANGENTS: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Color); + break; + } + } + else + { + // avoid passing broken pointer to OpenGL + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + } + + switch (vType) + { + case EVT_STANDARD: + if (vertices) + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex), buffer_offset(12)); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), 0); + } + + if (MultiTextureExtension && CurrentTexture[1]) + { + extGlClientActiveTexture(GL_TEXTURE1_ARB); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + } + break; + case EVT_2TCOORDS: + if (vertices) + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(12)); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0)); + } + + + if (MultiTextureExtension) + { + extGlClientActiveTexture(GL_TEXTURE1_ARB); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords2); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36)); + } + break; + case EVT_TANGENTS: + if (vertices) + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].TCoords); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12)); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0)); + } + + if (MultiTextureExtension) + { + extGlClientActiveTexture(GL_TEXTURE1_ARB); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Tangent); + else + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36)); + + extGlClientActiveTexture(GL_TEXTURE2_ARB); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Binormal); + else + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48)); + } + break; + } + + renderArray(indexList, primitiveCount, pType, iType); + + if (MultiTextureExtension) + { + if (vType==EVT_TANGENTS) + { + extGlClientActiveTexture(GL_TEXTURE2_ARB); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + if ((vType!=EVT_STANDARD) || CurrentTexture[1]) + { + extGlClientActiveTexture(GL_TEXTURE1_ARB); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + extGlClientActiveTexture(GL_TEXTURE0_ARB); + } + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + + +void COpenGLDriver::getColorBuffer(const void* vertices, u32 vertexCount, E_VERTEX_TYPE vType) +{ + // convert colors to gl color format. + vertexCount *= 4; //reused as color component count + ColorBuffer.set_used(vertexCount); + u32 i; + + switch (vType) + { + case EVT_STANDARD: + { + const S3DVertex* p = static_cast(vertices); + for (i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + case EVT_2TCOORDS: + { + const S3DVertex2TCoords* p = static_cast(vertices); + for (i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + case EVT_TANGENTS: + { + const S3DVertexTangents* p = static_cast(vertices); + for (i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + } +} + + +void COpenGLDriver::renderArray(const void* indexList, u32 primitiveCount, + scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + GLenum indexSize=0; + + switch (iType) + { + case EIT_16BIT: + { + indexSize=GL_UNSIGNED_SHORT; + break; + } + case EIT_32BIT: + { + indexSize=GL_UNSIGNED_INT; + break; + } + } + + switch (pType) + { + case scene::EPT_POINTS: + case scene::EPT_POINT_SPRITES: + { +#ifdef GL_ARB_point_sprite + if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) + glEnable(GL_POINT_SPRITE_ARB); +#endif + + // prepare size and attenuation (where supported) + GLfloat particleSize=Material.Thickness; +// if (AntiAlias) +// particleSize=core::clamp(particleSize, DimSmoothedPoint[0], DimSmoothedPoint[1]); +// else + particleSize=core::clamp(particleSize, DimAliasedPoint[0], DimAliasedPoint[1]); +#if defined(GL_VERSION_1_4) || defined(GL_ARB_point_parameters) || defined(GL_EXT_point_parameters) || defined(GL_SGIS_point_parameters) + const float att[] = {1.0f, 1.0f, 0.0f}; +#if defined(GL_VERSION_1_4) + extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, att); +// extGlPointParameterf(GL_POINT_SIZE_MIN,1.f); + extGlPointParameterf(GL_POINT_SIZE_MAX, particleSize); + extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE, 1.0f); +#elif defined(GL_ARB_point_parameters) + extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION_ARB, att); +// extGlPointParameterf(GL_POINT_SIZE_MIN_ARB,1.f); + extGlPointParameterf(GL_POINT_SIZE_MAX_ARB, particleSize); + extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0f); +#elif defined(GL_EXT_point_parameters) + extGlPointParameterfv(GL_DISTANCE_ATTENUATION_EXT, att); +// extGlPointParameterf(GL_POINT_SIZE_MIN_EXT,1.f); + extGlPointParameterf(GL_POINT_SIZE_MAX_EXT, particleSize); + extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0f); +#elif defined(GL_SGIS_point_parameters) + extGlPointParameterfv(GL_DISTANCE_ATTENUATION_SGIS, att); +// extGlPointParameterf(GL_POINT_SIZE_MIN_SGIS,1.f); + extGlPointParameterf(GL_POINT_SIZE_MAX_SGIS, particleSize); + extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_SGIS, 1.0f); +#endif +#endif + glPointSize(particleSize); + +#ifdef GL_ARB_point_sprite + if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) + glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_TRUE); +#endif + glDrawArrays(GL_POINTS, 0, primitiveCount); +#ifdef GL_ARB_point_sprite + if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) + { + glDisable(GL_POINT_SPRITE_ARB); + glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_FALSE); + } +#endif + } + break; + case scene::EPT_LINE_STRIP: + glDrawElements(GL_LINE_STRIP, primitiveCount+1, indexSize, indexList); + break; + case scene::EPT_LINE_LOOP: + glDrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList); + break; + case scene::EPT_LINES: + glDrawElements(GL_LINES, primitiveCount*2, indexSize, indexList); + break; + case scene::EPT_TRIANGLE_STRIP: + glDrawElements(GL_TRIANGLE_STRIP, primitiveCount+2, indexSize, indexList); + break; + case scene::EPT_TRIANGLE_FAN: + glDrawElements(GL_TRIANGLE_FAN, primitiveCount+2, indexSize, indexList); + break; + case scene::EPT_TRIANGLES: + glDrawElements(GL_TRIANGLES, primitiveCount*3, indexSize, indexList); + break; + case scene::EPT_QUAD_STRIP: + glDrawElements(GL_QUAD_STRIP, primitiveCount*2+2, indexSize, indexList); + break; + case scene::EPT_QUADS: + glDrawElements(GL_QUADS, primitiveCount*4, indexSize, indexList); + break; + case scene::EPT_POLYGON: + glDrawElements(GL_POLYGON, primitiveCount, indexSize, indexList); + break; + } +} + + +//! draws a vertex primitive list in 2d +void COpenGLDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + if (!primitiveCount || !vertexCount) + return; + + if (!checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + + if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(vertices, vertexCount, vType); + + // draw everything + this->setActiveTexture(0, Material.getTexture(0)); + if (Material.MaterialType==EMT_ONETEXTURE_BLEND) + { + E_BLEND_FACTOR srcFact; + E_BLEND_FACTOR dstFact; + E_MODULATE_FUNC modulo; + u32 alphaSource; + unpack_textureBlendFunc ( srcFact, dstFact, modulo, alphaSource, Material.MaterialTypeParam); + setRenderStates2DMode(alphaSource&video::EAS_VERTEX_COLOR, (Material.getTexture(0) != 0), (alphaSource&video::EAS_TEXTURE) != 0); + } + else + setRenderStates2DMode(Material.MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA, (Material.getTexture(0) != 0), Material.MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL); + + if (MultiTextureExtension) + extGlClientActiveTexture(GL_TEXTURE0_ARB); + + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + +//due to missing defines in OSX headers, we have to be more specific with this check +//#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra) +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (vertices) + { + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + { + switch (vType) + { + case EVT_STANDARD: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + break; + case EVT_2TCOORDS: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Color); + break; + case EVT_TANGENTS: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Color); + break; + } + } + else + { + // avoid passing broken pointer to OpenGL + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + } + + switch (vType) + { + case EVT_STANDARD: + if (vertices) + { + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + } + else + { + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), 0); + } + + if (MultiTextureExtension && CurrentTexture[1]) + { + extGlClientActiveTexture(GL_TEXTURE1_ARB); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + } + break; + case EVT_2TCOORDS: + if (vertices) + { + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Pos); + } + else + { + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28)); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0)); + } + + if (MultiTextureExtension) + { + extGlClientActiveTexture(GL_TEXTURE1_ARB); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords2); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36)); + } + break; + case EVT_TANGENTS: + if (vertices) + { + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].TCoords); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Pos); + } + else + { + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28)); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0)); + } + + break; + } + + renderArray(indexList, primitiveCount, pType, iType); + + if (MultiTextureExtension) + { + if ((vType!=EVT_STANDARD) || CurrentTexture[1]) + { + extGlClientActiveTexture(GL_TEXTURE1_ARB); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + extGlClientActiveTexture(GL_TEXTURE0_ARB); + } + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + + +//! draws a set of 2d images, using a color and the alpha channel of the +//! texture if desired. +void COpenGLDriver::draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + const u32 drawCount = core::min_(positions.size(), sourceRects.size()); + + const core::dimension2d& ss = texture->getOriginalSize(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + disableTextures(1); + if (!setActiveTexture(0, texture)) + return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glBegin(GL_QUADS); + + for (u32 i=0; i targetPos(positions[i]); + core::position2d sourcePos(sourceRects[i].UpperLeftCorner); + // This needs to be signed as it may go negative. + core::dimension2d sourceSize(sourceRects[i].getSize()); + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + continue; + } + } + + // clip these coordinates + + if (targetPos.X<0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y<0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + continue; + } + + // ok, we've clipped everything. + // now draw it. + + const core::rect tcoords( + sourcePos.X * invW, + sourcePos.Y * invH, + (sourcePos.X + sourceSize.Width) * invW, + (sourcePos.Y + sourceSize.Height) * invH); + + const core::rect poss(targetPos, sourceSize); + + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y)); + + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y)); + + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y)); + + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y)); + } + glEnd(); +} + + +//! draws a 2d image, using a color and the alpha channel of the texture if +//! desired. The image is drawn at pos, clipped against clipRect (if != 0). +//! Only the subtexture defined by sourceRect is used. +void COpenGLDriver::draw2DImage(const video::ITexture* texture, + const core::position2d& pos, + const core::rect& sourceRect, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + if (!sourceRect.isValid()) + return; + + core::position2d targetPos(pos); + core::position2d sourcePos(sourceRect.UpperLeftCorner); + // This needs to be signed as it may go negative. + core::dimension2d sourceSize(sourceRect.getSize()); + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + return; + } + } + + // clip these coordinates + + if (targetPos.X<0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y<0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + return; + } + + // ok, we've clipped everything. + // now draw it. + + const core::dimension2d& ss = texture->getOriginalSize(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + const core::rect tcoords( + sourcePos.X * invW, + sourcePos.Y * invH, + (sourcePos.X + sourceSize.Width) * invW, + (sourcePos.Y + sourceSize.Height) * invH); + + const core::rect poss(targetPos, sourceSize); + + disableTextures(1); + if (!setActiveTexture(0, texture)) + return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glBegin(GL_QUADS); + + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y)); + + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y)); + + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y)); + + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y)); + + glEnd(); +} + + +//! The same, but with a four element array of colors, one for each vertex +void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + const core::dimension2d& ss = texture->getOriginalSize(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + const core::rect tcoords( + sourceRect.UpperLeftCorner.X * invW, + sourceRect.UpperLeftCorner.Y * invH, + sourceRect.LowerRightCorner.X * invW, + sourceRect.LowerRightCorner.Y *invH); + + const video::SColor temp[4] = + { + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF + }; + + const video::SColor* const useColor = colors ? colors : temp; + + disableTextures(1); + setActiveTexture(0, texture); + setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 || + useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255, + true, useAlphaChannelOfTexture); + + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight()); + } + + glBegin(GL_QUADS); + + glColor4ub(useColor[0].getRed(), useColor[0].getGreen(), useColor[0].getBlue(), useColor[0].getAlpha()); + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(destRect.UpperLeftCorner.X), GLfloat(destRect.UpperLeftCorner.Y)); + + glColor4ub(useColor[3].getRed(), useColor[3].getGreen(), useColor[3].getBlue(), useColor[3].getAlpha()); + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(destRect.LowerRightCorner.X), GLfloat(destRect.UpperLeftCorner.Y)); + + glColor4ub(useColor[2].getRed(), useColor[2].getGreen(), useColor[2].getBlue(), useColor[2].getAlpha()); + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(destRect.LowerRightCorner.X), GLfloat(destRect.LowerRightCorner.Y)); + + glColor4ub(useColor[1].getRed(), useColor[1].getGreen(), useColor[1].getBlue(), useColor[1].getAlpha()); + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(destRect.UpperLeftCorner.X), GLfloat(destRect.LowerRightCorner.Y)); + + glEnd(); + + if (clipRect) + glDisable(GL_SCISSOR_TEST); +} + + +//! draws a set of 2d images, using a color and the alpha channel of the +//! texture if desired. The images are drawn beginning at pos and concatenated +//! in one line. All drawings are clipped against clipRect (if != 0). +//! The subtextures are defined by the array of sourceRects and are chosen +//! by the indices given. +void COpenGLDriver::draw2DImage(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + disableTextures(1); + if (!setActiveTexture(0, texture)) + return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, + clipRect->getWidth(),clipRect->getHeight()); + } + + const core::dimension2d& ss = texture->getOriginalSize(); + core::position2d targetPos(pos); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + + for (u32 i=0; i tcoords( + sourceRects[currentIndex].UpperLeftCorner.X * invW, + sourceRects[currentIndex].UpperLeftCorner.Y * invH, + sourceRects[currentIndex].LowerRightCorner.X * invW, + sourceRects[currentIndex].LowerRightCorner.Y * invH); + + const core::rect poss(targetPos, sourceRects[currentIndex].getSize()); + + glBegin(GL_QUADS); + + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y)); + + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y)); + + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y)); + + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y)); + + glEnd(); + targetPos.X += sourceRects[currentIndex].getWidth(); + } + if (clipRect) + glDisable(GL_SCISSOR_TEST); +} + + +//! draw a 2d rectangle +void COpenGLDriver::draw2DRectangle(SColor color, const core::rect& position, + const core::rect* clip) +{ + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glRectf(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y), + GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y)); +} + + +//! draw an 2d rectangle +void COpenGLDriver::draw2DRectangle(const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) +{ + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + disableTextures(); + + setRenderStates2DMode(colorLeftUp.getAlpha() < 255 || + colorRightUp.getAlpha() < 255 || + colorLeftDown.getAlpha() < 255 || + colorRightDown.getAlpha() < 255, false, false); + + glBegin(GL_QUADS); + glColor4ub(colorLeftUp.getRed(), colorLeftUp.getGreen(), + colorLeftUp.getBlue(), colorLeftUp.getAlpha()); + glVertex2f(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y)); + + glColor4ub(colorRightUp.getRed(), colorRightUp.getGreen(), + colorRightUp.getBlue(), colorRightUp.getAlpha()); + glVertex2f(GLfloat(pos.LowerRightCorner.X), GLfloat(pos.UpperLeftCorner.Y)); + + glColor4ub(colorRightDown.getRed(), colorRightDown.getGreen(), + colorRightDown.getBlue(), colorRightDown.getAlpha()); + glVertex2f(GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y)); + + glColor4ub(colorLeftDown.getRed(), colorLeftDown.getGreen(), + colorLeftDown.getBlue(), colorLeftDown.getAlpha()); + glVertex2f(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.LowerRightCorner.Y)); + + glEnd(); +} + + +//! Draws a 2d line. +void COpenGLDriver::draw2DLine(const core::position2d& start, + const core::position2d& end, SColor color) +{ + if (start==end) + drawPixel(start.X, start.Y, color); + else + { + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + glBegin(GL_LINES); + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + GLfloat x=(GLfloat)start.X; + GLfloat y=(GLfloat)start.Y; + if (x>end.X) + x += 0.5f; + if (y>end.Y) + y += 0.5f; + glVertex2f(GLfloat(x), GLfloat(y)); + x=(GLfloat)end.X; + y=(GLfloat)end.Y; + if (x>start.X) + x += 0.5f; + if (y>start.Y) + y += 0.5f; + glVertex2f(GLfloat(x), GLfloat(y)); + glEnd(); + } +} + +//! Draws a pixel +void COpenGLDriver::drawPixel(u32 x, u32 y, const SColor &color) +{ + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) + return; + + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + glBegin(GL_POINTS); + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glVertex2i(x, y); + glEnd(); +} + +bool COpenGLDriver::setActiveTexture(u32 stage, const video::ITexture* texture) +{ + if (stage >= MaxSupportedTextures) + return false; + + if (CurrentTexture[stage]==texture) + return true; + + if (MultiTextureExtension) + extGlActiveTexture(GL_TEXTURE0_ARB + stage); + + CurrentTexture.set(stage,texture); + + if (!texture) + { + glDisable(GL_TEXTURE_2D); + return true; + } + else + { + if (texture->getDriverType() != EDT_OPENGL) + { + glDisable(GL_TEXTURE_2D); + CurrentTexture.set(stage, 0); + os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); + return false; + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, + static_cast(texture)->getOpenGLTextureName()); + } + return true; +} + + +//! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled. +//! Returns whether disabling was successful or not. +bool COpenGLDriver::disableTextures(u32 fromStage) +{ + bool result=true; + for (u32 i=fromStage; i= 0; --i) + { + setActiveTexture(i, material.getTexture(i)); + setTransform ((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i), + Material.getTextureMatrix(i)); + } +} + + +//! prints error if an error happened. +bool COpenGLDriver::testGLError() +{ +#ifdef _DEBUG + GLenum g = glGetError(); + switch (g) + { + case GL_NO_ERROR: + return false; + case GL_INVALID_ENUM: + os::Printer::log("GL_INVALID_ENUM", ELL_ERROR); break; + case GL_INVALID_VALUE: + os::Printer::log("GL_INVALID_VALUE", ELL_ERROR); break; + case GL_INVALID_OPERATION: + os::Printer::log("GL_INVALID_OPERATION", ELL_ERROR); break; + case GL_STACK_OVERFLOW: + os::Printer::log("GL_STACK_OVERFLOW", ELL_ERROR); break; + case GL_STACK_UNDERFLOW: + os::Printer::log("GL_STACK_UNDERFLOW", ELL_ERROR); break; + case GL_OUT_OF_MEMORY: + os::Printer::log("GL_OUT_OF_MEMORY", ELL_ERROR); break; + case GL_TABLE_TOO_LARGE: + os::Printer::log("GL_TABLE_TOO_LARGE", ELL_ERROR); break; +#if defined(GL_EXT_framebuffer_object) + case GL_INVALID_FRAMEBUFFER_OPERATION_EXT: + os::Printer::log("GL_INVALID_FRAMEBUFFER_OPERATION", ELL_ERROR); break; +#endif + }; +// _IRR_DEBUG_BREAK_IF(true); + return true; +#else + return false; +#endif +} + + +//! sets the needed renderstates +void COpenGLDriver::setRenderStates3DMode() +{ + if (CurrentRenderMode != ERM_3D) + { + // Reset Texture Stages + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // switch back the matrices + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer()); + + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(Matrices[ETS_PROJECTION].pointer()); + + ResetRenderStates = true; +#ifdef GL_EXT_clip_volume_hint + if (FeatureAvailable[IRR_EXT_clip_volume_hint]) + glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_NICEST); +#endif + } + + if (ResetRenderStates || LastMaterial != Material) + { + // unset old material + + if (LastMaterial.MaterialType != Material.MaterialType && + static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + + // set new material. + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial( + Material, LastMaterial, ResetRenderStates, this); + + LastMaterial = Material; + ResetRenderStates = false; + } + + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD); + + CurrentRenderMode = ERM_3D; +} + + +//! Get native wrap mode value +GLint COpenGLDriver::getTextureWrapMode(const u8 clamp) +{ + GLint mode=GL_REPEAT; + switch (clamp) + { + case ETC_REPEAT: + mode=GL_REPEAT; + break; + case ETC_CLAMP: + mode=GL_CLAMP; + break; + case ETC_CLAMP_TO_EDGE: +#ifdef GL_VERSION_1_2 + if (Version>101) + mode=GL_CLAMP_TO_EDGE; + else +#endif +#ifdef GL_SGIS_texture_edge_clamp + if (FeatureAvailable[IRR_SGIS_texture_edge_clamp]) + mode=GL_CLAMP_TO_EDGE_SGIS; + else +#endif + // fallback + mode=GL_CLAMP; + break; + case ETC_CLAMP_TO_BORDER: +#ifdef GL_VERSION_1_3 + if (Version>102) + mode=GL_CLAMP_TO_BORDER; + else +#endif +#ifdef GL_ARB_texture_border_clamp + if (FeatureAvailable[IRR_ARB_texture_border_clamp]) + mode=GL_CLAMP_TO_BORDER_ARB; + else +#endif +#ifdef GL_SGIS_texture_border_clamp + if (FeatureAvailable[IRR_SGIS_texture_border_clamp]) + mode=GL_CLAMP_TO_BORDER_SGIS; + else +#endif + // fallback + mode=GL_CLAMP; + break; + case ETC_MIRROR: +#ifdef GL_VERSION_1_4 + if (Version>103) + mode=GL_MIRRORED_REPEAT; + else +#endif +#ifdef GL_ARB_texture_border_clamp + if (FeatureAvailable[IRR_ARB_texture_mirrored_repeat]) + mode=GL_MIRRORED_REPEAT_ARB; + else +#endif +#ifdef GL_IBM_texture_mirrored_repeat + if (FeatureAvailable[IRR_IBM_texture_mirrored_repeat]) + mode=GL_MIRRORED_REPEAT_IBM; + else +#endif + mode=GL_REPEAT; + break; + case ETC_MIRROR_CLAMP: +#ifdef GL_EXT_texture_mirror_clamp + if (FeatureAvailable[IRR_EXT_texture_mirror_clamp]) + mode=GL_MIRROR_CLAMP_EXT; + else +#endif +#if defined(GL_ATI_texture_mirror_once) + if (FeatureAvailable[IRR_ATI_texture_mirror_once]) + mode=GL_MIRROR_CLAMP_ATI; + else +#endif + mode=GL_CLAMP; + break; + case ETC_MIRROR_CLAMP_TO_EDGE: +#ifdef GL_EXT_texture_mirror_clamp + if (FeatureAvailable[IRR_EXT_texture_mirror_clamp]) + mode=GL_MIRROR_CLAMP_TO_EDGE_EXT; + else +#endif +#if defined(GL_ATI_texture_mirror_once) + if (FeatureAvailable[IRR_ATI_texture_mirror_once]) + mode=GL_MIRROR_CLAMP_TO_EDGE_ATI; + else +#endif + mode=GL_CLAMP; + break; + case ETC_MIRROR_CLAMP_TO_BORDER: +#ifdef GL_EXT_texture_mirror_clamp + if (FeatureAvailable[IRR_EXT_texture_mirror_clamp]) + mode=GL_MIRROR_CLAMP_TO_BORDER_EXT; + else +#endif + mode=GL_CLAMP; + break; + } + return mode; +} + + +void COpenGLDriver::setWrapMode(const SMaterial& material) +{ + // texture address mode + // Has to be checked always because it depends on the textures + for (u32 u=0; u0) + break; // stop loop + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[u].TextureWrapU)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[u].TextureWrapV)); + } +} + + +//! Can be called by an IMaterialRenderer to make its work easier. +void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderStates) +{ + if (resetAllRenderStates || + lastmaterial.ColorMaterial != material.ColorMaterial) + { + switch (material.ColorMaterial) + { + case ECM_NONE: + glDisable(GL_COLOR_MATERIAL); + break; + case ECM_DIFFUSE: + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + break; + case ECM_AMBIENT: + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT); + break; + case ECM_EMISSIVE: + glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION); + break; + case ECM_SPECULAR: + glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR); + break; + case ECM_DIFFUSE_AND_AMBIENT: + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + break; + } + if (material.ColorMaterial != ECM_NONE) + glEnable(GL_COLOR_MATERIAL); + } + + if (resetAllRenderStates || + lastmaterial.AmbientColor != material.AmbientColor || + lastmaterial.DiffuseColor != material.DiffuseColor || + lastmaterial.EmissiveColor != material.EmissiveColor || + lastmaterial.ColorMaterial != material.ColorMaterial) + { + GLfloat color[4]; + + const f32 inv = 1.0f / 255.0f; + + if ((material.ColorMaterial != video::ECM_AMBIENT) && + (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT)) + { + color[0] = material.AmbientColor.getRed() * inv; + color[1] = material.AmbientColor.getGreen() * inv; + color[2] = material.AmbientColor.getBlue() * inv; + color[3] = material.AmbientColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); + } + + if ((material.ColorMaterial != video::ECM_DIFFUSE) && + (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT)) + { + color[0] = material.DiffuseColor.getRed() * inv; + color[1] = material.DiffuseColor.getGreen() * inv; + color[2] = material.DiffuseColor.getBlue() * inv; + color[3] = material.DiffuseColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color); + } + + if (material.ColorMaterial != video::ECM_EMISSIVE) + { + color[0] = material.EmissiveColor.getRed() * inv; + color[1] = material.EmissiveColor.getGreen() * inv; + color[2] = material.EmissiveColor.getBlue() * inv; + color[3] = material.EmissiveColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color); + } + } + + if (resetAllRenderStates || + lastmaterial.SpecularColor != material.SpecularColor || + lastmaterial.Shininess != material.Shininess || + lastmaterial.ColorMaterial != material.ColorMaterial) + { + GLfloat color[4]={0.f,0.f,0.f,1.f}; + const f32 inv = 1.0f / 255.0f; + + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess); + // disable Specular colors if no shininess is set + if ((material.Shininess != 0.0f) && + (material.ColorMaterial != video::ECM_SPECULAR)) + { +#ifdef GL_EXT_separate_specular_color + if (FeatureAvailable[IRR_EXT_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); +#endif + color[0] = material.SpecularColor.getRed() * inv; + color[1] = material.SpecularColor.getGreen() * inv; + color[2] = material.SpecularColor.getBlue() * inv; + color[3] = material.SpecularColor.getAlpha() * inv; + } +#ifdef GL_EXT_separate_specular_color + else if (FeatureAvailable[IRR_EXT_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); +#endif + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); + } + + // Texture filter + // Has to be checked always because it depends on the textures + // Filtering has to be set for each texture layer + for (u32 i=0; i0) + break; + +#ifdef GL_EXT_texture_lod_bias + if (FeatureAvailable[IRR_EXT_texture_lod_bias]) + { + if (material.TextureLayer[i].LODBias) + { + const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp); + } + else + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f); + } +#endif + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + + if (material.UseMipMaps && CurrentTexture[i]->hasMipMaps()) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR : + material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST : + GL_NEAREST_MIPMAP_NEAREST); + else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + +#ifdef GL_EXT_texture_filter_anisotropic + if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic]) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, + material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1); +#endif + } + + // fillmode + if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud)) + glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL); + + // shademode + if (resetAllRenderStates || (lastmaterial.GouraudShading != material.GouraudShading)) + { + if (material.GouraudShading) + glShadeModel(GL_SMOOTH); + else + glShadeModel(GL_FLAT); + } + + // lighting + if (resetAllRenderStates || (lastmaterial.Lighting != material.Lighting)) + { + if (material.Lighting) + glEnable(GL_LIGHTING); + else + glDisable(GL_LIGHTING); + } + + // zbuffer + if (resetAllRenderStates || lastmaterial.ZBuffer != material.ZBuffer) + { + switch (material.ZBuffer) + { + case ECFN_NEVER: + glDisable(GL_DEPTH_TEST); + break; + case ECFN_LESSEQUAL: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + break; + case ECFN_EQUAL: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_EQUAL); + break; + case ECFN_LESS: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + break; + case ECFN_NOTEQUAL: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_NOTEQUAL); + break; + case ECFN_GREATEREQUAL: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_GEQUAL); + break; + case ECFN_GREATER: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_GREATER); + break; + case ECFN_ALWAYS: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + break; + } + } + + // zwrite +// if (resetAllRenderStates || lastmaterial.ZWriteEnable != material.ZWriteEnable) + { + if (material.ZWriteEnable && (AllowZWriteOnTransparent || !material.isTransparent())) + { + glDepthMask(GL_TRUE); + } + else + glDepthMask(GL_FALSE); + } + + // back face culling + if (resetAllRenderStates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling)) + { + if ((material.FrontfaceCulling) && (material.BackfaceCulling)) + { + glCullFace(GL_FRONT_AND_BACK); + glEnable(GL_CULL_FACE); + } + else + if (material.BackfaceCulling) + { + glCullFace(GL_BACK); + glEnable(GL_CULL_FACE); + } + else + if (material.FrontfaceCulling) + { + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + } + else + glDisable(GL_CULL_FACE); + } + + // fog + if (resetAllRenderStates || lastmaterial.FogEnable != material.FogEnable) + { + if (material.FogEnable) + glEnable(GL_FOG); + else + glDisable(GL_FOG); + } + + // normalization + if (resetAllRenderStates || lastmaterial.NormalizeNormals != material.NormalizeNormals) + { + if (material.NormalizeNormals) + glEnable(GL_NORMALIZE); + else + glDisable(GL_NORMALIZE); + } + + // Color Mask + if (resetAllRenderStates || lastmaterial.ColorMask != material.ColorMask) + { + glColorMask( + (material.ColorMask & ECP_RED)?GL_TRUE:GL_FALSE, + (material.ColorMask & ECP_GREEN)?GL_TRUE:GL_FALSE, + (material.ColorMask & ECP_BLUE)?GL_TRUE:GL_FALSE, + (material.ColorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE); + } + + if (queryFeature(EVDF_BLEND_OPERATIONS) && + (resetAllRenderStates|| lastmaterial.BlendOperation != material.BlendOperation)) + { + if (material.BlendOperation==EBO_NONE) + glDisable(GL_BLEND); + else + { + glEnable(GL_BLEND); +#if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) || defined(GL_VERSION_1_2) + switch (material.BlendOperation) + { + case EBO_SUBTRACT: +#if defined(GL_EXT_blend_subtract) + if (FeatureAvailable[IRR_EXT_blend_subtract] || (Version>=120)) + extGlBlendEquation(GL_FUNC_SUBTRACT_EXT); +#elif defined(GL_VERSION_1_2) + if (Version>=120) + extGlBlendEquation(GL_FUNC_SUBTRACT); +#endif + break; + case EBO_REVSUBTRACT: +#if defined(GL_EXT_blend_subtract) + if (FeatureAvailable[IRR_EXT_blend_subtract] || (Version>=120)) + extGlBlendEquation(GL_FUNC_REVERSE_SUBTRACT_EXT); +#elif defined(GL_VERSION_1_2) + if (Version>=120) + extGlBlendEquation(GL_FUNC_REVERSE_SUBTRACT); +#endif + break; + case EBO_MIN: +#if defined(GL_EXT_blend_minmax) + if (FeatureAvailable[IRR_EXT_blend_minmax] || (Version>=120)) + extGlBlendEquation(GL_MIN_EXT); +#elif defined(GL_VERSION_1_2) + if (Version>=120) + extGlBlendEquation(GL_MIN); +#endif + break; + case EBO_MAX: +#if defined(GL_EXT_blend_minmax) + if (FeatureAvailable[IRR_EXT_blend_minmax] || (Version>=120)) + extGlBlendEquation(GL_MAX_EXT); +#elif defined(GL_VERSION_1_2) + if (Version>=120) + extGlBlendEquation(GL_MAX); +#endif + break; + case EBO_MIN_FACTOR: +#if defined(GL_AMD_blend_minmax_factor) + if (FeatureAvailable[IRR_AMD_blend_minmax_factor]) + extGlBlendEquation(GL_FACTOR_MIN_AMD); +#endif + // fallback in case of missing extension +#if defined(GL_VERSION_1_2) +#if defined(GL_AMD_blend_minmax_factor) + else +#endif + if (Version>=120) + extGlBlendEquation(GL_MIN); +#endif + break; + case EBO_MAX_FACTOR: +#if defined(GL_AMD_blend_minmax_factor) + if (FeatureAvailable[IRR_AMD_blend_minmax_factor]) + extGlBlendEquation(GL_FACTOR_MAX_AMD); +#endif + // fallback in case of missing extension +#if defined(GL_VERSION_1_2) +#if defined(GL_AMD_blend_minmax_factor) + else +#endif + if (Version>=120) + extGlBlendEquation(GL_MAX); +#endif + break; + case EBO_MIN_ALPHA: +#if defined(GL_SGIX_blend_alpha_minmax) + if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax]) + extGlBlendEquation(GL_ALPHA_MIN_SGIX); + // fallback in case of missing extension + else + if (FeatureAvailable[IRR_EXT_blend_minmax]) + extGlBlendEquation(GL_MIN_EXT); +#endif + break; + case EBO_MAX_ALPHA: +#if defined(GL_SGIX_blend_alpha_minmax) + if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax]) + extGlBlendEquation(GL_ALPHA_MAX_SGIX); + // fallback in case of missing extension + else + if (FeatureAvailable[IRR_EXT_blend_minmax]) + extGlBlendEquation(GL_MAX_EXT); +#endif + break; + default: +#if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) + extGlBlendEquation(GL_FUNC_ADD_EXT); +#elif defined(GL_VERSION_1_2) + extGlBlendEquation(GL_FUNC_ADD); +#endif + break; + } +#endif + } + } + + // Polygon Offset + if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderStates || + lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection || + lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor)) + { + glDisable(lastmaterial.Wireframe?GL_POLYGON_OFFSET_LINE:lastmaterial.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL); + if (material.PolygonOffsetFactor) + { + glDisable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL); + glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL); + } + if (material.PolygonOffsetDirection==EPO_BACK) + glPolygonOffset(1.0f, (GLfloat)material.PolygonOffsetFactor); + else + glPolygonOffset(-1.0f, (GLfloat)-material.PolygonOffsetFactor); + } + + // thickness + if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness) + { + if (AntiAlias) + { +// glPointSize(core::clamp(static_cast(material.Thickness), DimSmoothedPoint[0], DimSmoothedPoint[1])); + // we don't use point smoothing + glPointSize(core::clamp(static_cast(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1])); + glLineWidth(core::clamp(static_cast(material.Thickness), DimSmoothedLine[0], DimSmoothedLine[1])); + } + else + { + glPointSize(core::clamp(static_cast(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1])); + glLineWidth(core::clamp(static_cast(material.Thickness), DimAliasedLine[0], DimAliasedLine[1])); + } + } + + // Anti aliasing + if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing) + { + if (FeatureAvailable[IRR_ARB_multisample]) + { + if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) + glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); + else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); + + if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY))) + { + glEnable(GL_MULTISAMPLE_ARB); +#ifdef GL_NV_multisample_filter_hint + if (FeatureAvailable[IRR_NV_multisample_filter_hint]) + { + if ((material.AntiAliasing & EAAM_QUALITY) == EAAM_QUALITY) + glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST); + else + glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST); + } +#endif + } + else + glDisable(GL_MULTISAMPLE_ARB); + } + if ((material.AntiAliasing & EAAM_LINE_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH)) + { + if (material.AntiAliasing & EAAM_LINE_SMOOTH) + glEnable(GL_LINE_SMOOTH); + else if (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH) + glDisable(GL_LINE_SMOOTH); + } + if ((material.AntiAliasing & EAAM_POINT_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH)) + { + if (material.AntiAliasing & EAAM_POINT_SMOOTH) + // often in software, and thus very slow + glEnable(GL_POINT_SMOOTH); + else if (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH) + glDisable(GL_POINT_SMOOTH); + } + } + + setWrapMode(material); + + // be sure to leave in texture stage 0 + if (MultiTextureExtension) + extGlActiveTexture(GL_TEXTURE0_ARB); +} + + +//! Enable the 2d override material +void COpenGLDriver::enableMaterial2D(bool enable) +{ + if (!enable) + CurrentRenderMode = ERM_NONE; + CNullDriver::enableMaterial2D(enable); +} + + +//! sets the needed renderstates +void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel) +{ + if (CurrentRenderMode != ERM_2D || Transformation3DChanged) + { + // unset last 3d material + if (CurrentRenderMode == ERM_3D) + { + if (static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + } + if (Transformation3DChanged) + { + glMatrixMode(GL_PROJECTION); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + core::matrix4 m(core::matrix4::EM4CONST_NOTHING); + m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f); + m.setTranslation(core::vector3df(-1,1,0)); + glLoadMatrixf(m.pointer()); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.375f, 0.375f, 0.0f); + + // Make sure we set first texture matrix + if (MultiTextureExtension) + extGlActiveTexture(GL_TEXTURE0_ARB); + + Transformation3DChanged = false; + } + if (!OverrideMaterial2DEnabled) + { + setBasicRenderStates(InitMaterial2D, LastMaterial, true); + LastMaterial = InitMaterial2D; + } + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#ifdef GL_EXT_clip_volume_hint + if (FeatureAvailable[IRR_EXT_clip_volume_hint]) + glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST); +#endif + + } + if (OverrideMaterial2DEnabled) + { + OverrideMaterial2D.Lighting=false; + setBasicRenderStates(OverrideMaterial2D, LastMaterial, false); + LastMaterial = OverrideMaterial2D; + } + + // no alphaChannel without texture + alphaChannel &= texture; + + if (alphaChannel || alpha) + { + glEnable(GL_BLEND); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.f); + } + else + { + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + } + + if (texture) + { + if (!OverrideMaterial2DEnabled) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + Material.setTexture(0, const_cast(CurrentTexture[0])); + setTransform(ETS_TEXTURE_0, core::IdentityMatrix); + // Due to the transformation change, the previous line would call a reset each frame + // but we can safely reset the variable as it was false before + Transformation3DChanged=false; + + if (alphaChannel) + { + // if alpha and alpha texture just modulate, otherwise use only the alpha channel + if (alpha) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + else + { +#if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine) + if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine]) + { +#ifdef GL_ARB_texture_env_combine + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); + // rgb always modulates + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); +#else + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); + // rgb always modulates + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); +#endif + } + else +#endif + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + else + { + if (alpha) + { +#if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine) + if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine]) + { +#ifdef GL_ARB_texture_env_combine + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + // rgb always modulates + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); +#else + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); + // rgb always modulates + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); +#endif + } + else +#endif + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + else + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + } + + CurrentRenderMode = ERM_2D; +} + + +//! \return Returns the name of the video driver. +const wchar_t* COpenGLDriver::getName() const +{ + return Name.c_str(); +} + + +//! deletes all dynamic lights there are +void COpenGLDriver::deleteAllDynamicLights() +{ + for (s32 i=0; i= (s32)RequestedLights.size()) + return; + + RequestedLight & requestedLight = RequestedLights[lightIndex]; + + requestedLight.DesireToBeOn = turnOn; + + if(turnOn) + { + if(-1 == requestedLight.HardwareLightIndex) + assignHardwareLight(lightIndex); + } + else + { + if(-1 != requestedLight.HardwareLightIndex) + { + // It's currently assigned, so free up the hardware light + glDisable(requestedLight.HardwareLightIndex); + requestedLight.HardwareLightIndex = -1; + + // Now let the first light that's waiting on a free hardware light grab it + for(u32 requested = 0; requested < RequestedLights.size(); ++requested) + if(RequestedLights[requested].DesireToBeOn + && + -1 == RequestedLights[requested].HardwareLightIndex) + { + assignHardwareLight(requested); + break; + } + } + } +} + + +//! returns the maximal amount of dynamic lights the device can handle +u32 COpenGLDriver::getMaximalDynamicLightAmount() const +{ + return MaxLights; +} + + +//! Sets the dynamic ambient light color. The default color is +//! (0,0,0,0) which means it is dark. +//! \param color: New color of the ambient light. +void COpenGLDriver::setAmbientLight(const SColorf& color) +{ + GLfloat data[4] = {color.r, color.g, color.b, color.a}; + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data); +} + + +// this code was sent in by Oliver Klems, thank you! (I modified the glViewport +// method just a bit. +void COpenGLDriver::setViewPort(const core::rect& area) +{ + if (area == ViewPort) + return; + core::rect vp = area; + core::rect rendert(0,0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height); + vp.clipAgainst(rendert); + + if (vp.getHeight()>0 && vp.getWidth()>0) + { + glViewport(vp.UpperLeftCorner.X, + getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), + vp.getWidth(), vp.getHeight()); + + ViewPort = vp; + } +} + + +//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do +//! this: First, draw all geometry. Then use this method, to draw the shadow +//! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow. +void COpenGLDriver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) +{ + const u32 count=triangles.size(); + if (!StencilBuffer || !count) + return; + + // unset last 3d material + if (CurrentRenderMode == ERM_3D && + static_cast(Material.MaterialType) < MaterialRenderers.size()) + { + MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial(); + ResetRenderStates = true; + } + + // store current OpenGL state + glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | + GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT); + + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glDepthFunc(GL_LESS); + glDepthMask(GL_FALSE); // no depth buffer writing + if (debugDataVisible & scene::EDS_MESH_WIRE_OVERLAY) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY))) + { + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color buffer drawing + glEnable(GL_STENCIL_TEST); + } + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3,GL_FLOAT,sizeof(core::vector3df),triangles.const_pointer()); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + GLenum incr = GL_INCR; + GLenum decr = GL_DECR; +#ifdef GL_EXT_stencil_wrap + if (FeatureAvailable[IRR_EXT_stencil_wrap]) + { + incr = GL_INCR_WRAP_EXT; + decr = GL_DECR_WRAP_EXT; + } +#endif +#ifdef GL_NV_depth_clamp + if (FeatureAvailable[IRR_NV_depth_clamp]) + glEnable(GL_DEPTH_CLAMP_NV); +#endif + + // The first parts are not correctly working, yet. +#if 0 +#ifdef GL_EXT_stencil_two_side + if (FeatureAvailable[IRR_EXT_stencil_two_side]) + { + glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT); + glDisable(GL_CULL_FACE); + if (zfail) + { + extGlActiveStencilFace(GL_BACK); + glStencilOp(GL_KEEP, incr, GL_KEEP); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + extGlActiveStencilFace(GL_FRONT); + glStencilOp(GL_KEEP, decr, GL_KEEP); + } + else // zpass + { + extGlActiveStencilFace(GL_BACK); + glStencilOp(GL_KEEP, GL_KEEP, decr); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + extGlActiveStencilFace(GL_FRONT); + glStencilOp(GL_KEEP, GL_KEEP, incr); + } + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + glDrawArrays(GL_TRIANGLES,0,count); + glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); + } + else +#endif + if (FeatureAvailable[IRR_ATI_separate_stencil]) + { + glDisable(GL_CULL_FACE); + if (zfail) + { + extGlStencilOpSeparate(GL_BACK, GL_KEEP, incr, GL_KEEP); + extGlStencilOpSeparate(GL_FRONT, GL_KEEP, decr, GL_KEEP); + } + else // zpass + { + extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, decr); + extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, incr); + } + extGlStencilFuncSeparate(GL_ALWAYS, GL_ALWAYS, 0, ~0); + glStencilMask(~0); + glDrawArrays(GL_TRIANGLES,0,count); + } + else +#endif + { + glEnable(GL_CULL_FACE); + if (zfail) + { + glCullFace(GL_FRONT); + glStencilOp(GL_KEEP, incr, GL_KEEP); + glDrawArrays(GL_TRIANGLES,0,count); + + glCullFace(GL_BACK); + glStencilOp(GL_KEEP, decr, GL_KEEP); + glDrawArrays(GL_TRIANGLES,0,count); + } + else // zpass + { + glCullFace(GL_BACK); + glStencilOp(GL_KEEP, GL_KEEP, incr); + glDrawArrays(GL_TRIANGLES,0,count); + + glCullFace(GL_FRONT); + glStencilOp(GL_KEEP, GL_KEEP, decr); + glDrawArrays(GL_TRIANGLES,0,count); + } + } +#ifdef GL_NV_depth_clamp + if (FeatureAvailable[IRR_NV_depth_clamp]) + glDisable(GL_DEPTH_CLAMP_NV); +#endif + + glDisable(GL_POLYGON_OFFSET_FILL); + glDisableClientState(GL_VERTEX_ARRAY); //not stored on stack + glPopAttrib(); +} + +//! Fills the stencil shadow with color. After the shadow volume has been drawn +//! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this +//! to draw the color of the shadow. +void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, + video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) +{ + if (!StencilBuffer) + return; + + disableTextures(); + + // store attributes + glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT | GL_LIGHTING_BIT); + + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glDepthMask(GL_FALSE); + + glShadeModel(GL_FLAT); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_NOTEQUAL, 0, ~0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + // draw a shadow rectangle covering the entire screen using stencil buffer + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glBegin(GL_QUADS); + + glColor4ub(leftDownEdge.getRed(), leftDownEdge.getGreen(), leftDownEdge.getBlue(), leftDownEdge.getAlpha()); + glVertex3f(-1.f,-1.f,-0.9f); + + glColor4ub(leftUpEdge.getRed(), leftUpEdge.getGreen(), leftUpEdge.getBlue(), leftUpEdge.getAlpha()); + glVertex3f(-1.f, 1.f,-0.9f); + + glColor4ub(rightUpEdge.getRed(), rightUpEdge.getGreen(), rightUpEdge.getBlue(), rightUpEdge.getAlpha()); + glVertex3f(1.f, 1.f,-0.9f); + + glColor4ub(rightDownEdge.getRed(), rightDownEdge.getGreen(), rightDownEdge.getBlue(), rightDownEdge.getAlpha()); + glVertex3f(1.f,-1.f,-0.9f); + + glEnd(); + + clearBuffers(false, false, clearStencilBuffer, 0x0); + + // restore settings + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopAttrib(); +} + + +//! Sets the fog mode. +void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) +{ + CNullDriver::setFog(c, fogType, start, end, density, pixelFog, rangeFog); + + glFogf(GL_FOG_MODE, GLfloat((fogType==EFT_FOG_LINEAR)? GL_LINEAR : (fogType==EFT_FOG_EXP)?GL_EXP:GL_EXP2)); + +#ifdef GL_EXT_fog_coord + if (FeatureAvailable[IRR_EXT_fog_coord]) + glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH); +#endif +#ifdef GL_NV_fog_distance + if (FeatureAvailable[IRR_NV_fog_distance]) + { + if (rangeFog) + glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV); + else + glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV); + } +#endif + + if (fogType==EFT_FOG_LINEAR) + { + glFogf(GL_FOG_START, start); + glFogf(GL_FOG_END, end); + } + else + glFogf(GL_FOG_DENSITY, density); + + if (pixelFog) + glHint(GL_FOG_HINT, GL_NICEST); + else + glHint(GL_FOG_HINT, GL_FASTEST); + + SColorf color(c); + GLfloat data[4] = {color.r, color.g, color.b, color.a}; + glFogfv(GL_FOG_COLOR, data); +} + + +//! Draws a 3d line. +void COpenGLDriver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) +{ + setRenderStates3DMode(); + + glBegin(GL_LINES); + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glVertex3f(start.X, start.Y, start.Z); + + glVertex3f(end.X, end.Y, end.Z); + glEnd(); +} + + +//! Removes a texture from the texture cache and deletes it, freeing lot of memory. +void COpenGLDriver::removeTexture(ITexture* texture) +{ + if (!texture) + return; + + CNullDriver::removeTexture(texture); + // Remove this texture from CurrentTexture as well + CurrentTexture.remove(texture); +} + + +//! Only used by the internal engine. Used to notify the driver that +//! the window was resized. +void COpenGLDriver::OnResize(const core::dimension2d& size) +{ + CNullDriver::OnResize(size); + glViewport(0, 0, size.Width, size.Height); + Transformation3DChanged = true; +} + + +//! Returns type of video driver +E_DRIVER_TYPE COpenGLDriver::getDriverType() const +{ + return EDT_OPENGL; +} + + +//! returns color format +ECOLOR_FORMAT COpenGLDriver::getColorFormat() const +{ + return ColorFormat; +} + + +//! Sets a vertex shader constant. +void COpenGLDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ +#ifdef GL_ARB_vertex_program + for (s32 i=0; isetPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + return false; +} + +//! Bool interface for the above. +bool COpenGLDriver::setPixelShaderConstant(const c8* name, const bool* bools, int count) +{ + os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + return false; +} + +//! Int interface for the above. +bool COpenGLDriver::setPixelShaderConstant(const c8* name, const s32* ints, int count) +{ + os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + return false; +} + + +//! Adds a new material renderer to the VideoDriver, using pixel and/or +//! vertex shaders to render geometry. +s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) +{ + s32 nr = -1; + COpenGLShaderMaterialRenderer* r = new COpenGLShaderMaterialRenderer( + this, nr, vertexShaderProgram, pixelShaderProgram, + callback, getMaterialRenderer(baseMaterial), userData); + + r->drop(); + return nr; +} + + +//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry. +s32 COpenGLDriver::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) +{ + s32 nr = -1; + + #ifdef _IRR_COMPILE_WITH_CG_ + if (shadingLang == EGSL_CG) + { + COpenGLCgMaterialRenderer* r = new COpenGLCgMaterialRenderer( + this, nr, + vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget, + pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget, + geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget, + inType, outType, verticesOut, + callback,getMaterialRenderer(baseMaterial), userData); + + r->drop(); + } + else + #endif + { + COpenGLSLMaterialRenderer* r = new COpenGLSLMaterialRenderer( + this, nr, + vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget, + pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget, + geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget, + inType, outType, verticesOut, + callback,getMaterialRenderer(baseMaterial), userData); + + r->drop(); + } + + return nr; +} + + +//! Returns a pointer to the IVideoDriver interface. (Implementation for +//! IMaterialRendererServices) +IVideoDriver* COpenGLDriver::getVideoDriver() +{ + return this; +} + + +ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, + const ECOLOR_FORMAT format) +{ + //disable mip-mapping + bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); + + video::ITexture* rtt = 0; +#if defined(GL_EXT_framebuffer_object) + // if driver supports FrameBufferObjects, use them + if (queryFeature(EVDF_FRAMEBUFFER_OBJECT)) + { + rtt = new COpenGLFBOTexture(size, name, this, format); + if (rtt) + { + bool success = false; + addTexture(rtt); + ITexture* tex = createDepthTexture(rtt); + if (tex) + { + success = static_cast(tex)->attach(rtt); + if ( !success ) + { + removeDepthTexture(tex); + } + tex->drop(); + } + rtt->drop(); + if (!success) + { + removeTexture(rtt); + rtt=0; + } + } + } + else +#endif + { + // the simple texture is only possible for size <= screensize + // we try to find an optimal size with the original constraints + core::dimension2du destSize(core::min_(size.Width,ScreenSize.Width), core::min_(size.Height,ScreenSize.Height)); + destSize = destSize.getOptimalSize((size==size.getOptimalSize()), false, false); + rtt = addTexture(destSize, name, ECF_A8R8G8B8); + if (rtt) + { + static_cast(rtt)->setIsRenderTarget(true); + } + } + + //restore mip-mapping + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels); + + return rtt; +} + + +//! Returns the maximum amount of primitives (mostly vertices) which +//! the device is able to render with one drawIndexedTriangleList +//! call. +u32 COpenGLDriver::getMaximalPrimitiveCount() const +{ + return 0x7fffffff; +} + + +//! set or reset render target +bool COpenGLDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget, + bool clearZBuffer, SColor color) +{ + if (target != CurrentTarget) + setRenderTarget(0, false, false, 0x0); + + if (ERT_RENDER_TEXTURE == target) + { + os::Printer::log("For render textures call setRenderTarget with the actual texture as first parameter.", ELL_ERROR); + return false; + } + if (ERT_MULTI_RENDER_TEXTURES == target) + { + os::Printer::log("For multiple render textures call setRenderTarget with the texture array as first parameter.", ELL_ERROR); + return false; + } + + if (Params.Stereobuffer && (ERT_STEREO_RIGHT_BUFFER == target)) + { + if (Params.Doublebuffer) + glDrawBuffer(GL_BACK_RIGHT); + else + glDrawBuffer(GL_FRONT_RIGHT); + } + else if (Params.Stereobuffer && ERT_STEREO_BOTH_BUFFERS == target) + { + if (Params.Doublebuffer) + glDrawBuffer(GL_BACK); + else + glDrawBuffer(GL_FRONT); + } + else if ((target >= ERT_AUX_BUFFER0) && (target-ERT_AUX_BUFFER0 < MaxAuxBuffers)) + { + glDrawBuffer(GL_AUX0+target-ERT_AUX_BUFFER0); + } + else + { + if (Params.Doublebuffer) + glDrawBuffer(GL_BACK_LEFT); + else + glDrawBuffer(GL_FRONT_LEFT); + // exit with false, but also with working color buffer + if (target != ERT_FRAME_BUFFER) + return false; + } + CurrentTarget=target; + clearBuffers(clearTarget, clearZBuffer, false, color); + return true; +} + + +//! set or reset render target +bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, + bool clearZBuffer, SColor color) +{ + // check for right driver type + + if (texture && texture->getDriverType() != EDT_OPENGL) + { + os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); + return false; + } + +#if defined(GL_EXT_framebuffer_object) + if (CurrentTarget==ERT_MULTI_RENDER_TEXTURES) + { + for (u32 i=0; iunbindRTT(); + } + + if (texture) + { + // we want to set a new target. so do this. + glViewport(0, 0, texture->getSize().Width, texture->getSize().Height); + RenderTargetTexture = static_cast(texture); + // calls glDrawBuffer as well + RenderTargetTexture->bindRTT(); + CurrentRendertargetSize = texture->getSize(); + CurrentTarget=ERT_RENDER_TEXTURE; + } + else + { + glViewport(0,0,ScreenSize.Width,ScreenSize.Height); + RenderTargetTexture = 0; + CurrentRendertargetSize = core::dimension2d(0,0); + CurrentTarget=ERT_FRAME_BUFFER; + glDrawBuffer(Params.Doublebuffer?GL_BACK_LEFT:GL_FRONT_LEFT); + } + // we need to update the matrices due to the rendersize change. + Transformation3DChanged=true; + } + + clearBuffers(clearBackBuffer, clearZBuffer, false, color); + + return true; +} + + +//! Sets multiple render targets +bool COpenGLDriver::setRenderTarget(const core::array& targets, + bool clearBackBuffer, bool clearZBuffer, SColor color) +{ + // if simply disabling the MRT via array call + if (targets.size()==0) + return setRenderTarget(0, clearBackBuffer, clearZBuffer, color); + // if disabling old MRT, but enabling new one as well + if ((MRTargets.size()!=0) && (targets != MRTargets)) + setRenderTarget(0, clearBackBuffer, clearZBuffer, color); + // if no change, simply clear buffers + else if (targets == MRTargets) + { + clearBuffers(clearBackBuffer, clearZBuffer, false, color); + return true; + } + + // copy to storage for correct disabling + MRTargets=targets; + + u32 maxMultipleRTTs = core::min_(static_cast(MaxMultipleRenderTargets), targets.size()); + + // determine common size + core::dimension2du rttSize = CurrentRendertargetSize; + if (targets[0].TargetType==ERT_RENDER_TEXTURE) + { + if (!targets[0].RenderTexture) + { + os::Printer::log("Missing render texture for MRT.", ELL_ERROR); + return false; + } + rttSize=targets[0].RenderTexture->getSize(); + } + + for (u32 i = 0; i < maxMultipleRTTs; ++i) + { + // check for right driver type + if (targets[i].TargetType==ERT_RENDER_TEXTURE) + { + if (!targets[i].RenderTexture) + { + maxMultipleRTTs=i; + os::Printer::log("Missing render texture for MRT.", ELL_WARNING); + break; + } + if (targets[i].RenderTexture->getDriverType() != EDT_OPENGL) + { + maxMultipleRTTs=i; + os::Printer::log("Tried to set a texture not owned by this driver.", ELL_WARNING); + break; + } + + // check for valid render target + if (!targets[i].RenderTexture->isRenderTarget() || !static_cast(targets[i].RenderTexture)->isFrameBufferObject()) + { + maxMultipleRTTs=i; + os::Printer::log("Tried to set a non FBO-RTT as render target.", ELL_WARNING); + break; + } + + // check for valid size + if (rttSize != targets[i].RenderTexture->getSize()) + { + maxMultipleRTTs=i; + os::Printer::log("Render target texture has wrong size.", ELL_WARNING); + break; + } + } + } + if (maxMultipleRTTs==0) + { + os::Printer::log("No valid MRTs.", ELL_ERROR); + return false; + } + + // init FBO, if any + for (u32 i=0; i 1) + { + CurrentTarget=ERT_MULTI_RENDER_TEXTURES; + core::array MRTs; + MRTs.set_used(maxMultipleRTTs); + for(u32 i = 0; i < maxMultipleRTTs; i++) + { + if (FeatureAvailable[IRR_EXT_draw_buffers2]) + { + extGlColorMaskIndexed(i, + (targets[i].ColorMask & ECP_RED)?GL_TRUE:GL_FALSE, + (targets[i].ColorMask & ECP_GREEN)?GL_TRUE:GL_FALSE, + (targets[i].ColorMask & ECP_BLUE)?GL_TRUE:GL_FALSE, + (targets[i].ColorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE); + if (targets[i].BlendOp==EBO_NONE) + extGlDisableIndexed(GL_BLEND, i); + else + extGlEnableIndexed(GL_BLEND, i); + } +#if defined(GL_AMD_draw_buffers_blend) || defined(GL_ARB_draw_buffers_blend) + if (FeatureAvailable[IRR_AMD_draw_buffers_blend] || FeatureAvailable[IRR_ARB_draw_buffers_blend]) + { + extGlBlendFuncIndexed(i, getGLBlend(targets[i].BlendFuncSrc), getGLBlend(targets[i].BlendFuncDst)); + switch(targets[i].BlendOp) + { + case EBO_SUBTRACT: + extGlBlendEquationIndexed(i, GL_FUNC_SUBTRACT); + break; + case EBO_REVSUBTRACT: + extGlBlendEquationIndexed(i, GL_FUNC_REVERSE_SUBTRACT); + break; + case EBO_MIN: + extGlBlendEquationIndexed(i, GL_MIN); + break; + case EBO_MAX: + extGlBlendEquationIndexed(i, GL_MAX); + break; + case EBO_MIN_FACTOR: + case EBO_MIN_ALPHA: +#if defined(GL_AMD_blend_minmax_factor) + if (FeatureAvailable[IRR_AMD_blend_minmax_factor]) + extGlBlendEquationIndexed(i, GL_FACTOR_MIN_AMD); + // fallback in case of missing extension + else +#endif + extGlBlendEquation(GL_MIN); + break; + case EBO_MAX_FACTOR: + case EBO_MAX_ALPHA: +#if defined(GL_AMD_blend_minmax_factor) + if (FeatureAvailable[IRR_AMD_blend_minmax_factor]) + extGlBlendEquationIndexed(i, GL_FACTOR_MAX_AMD); + // fallback in case of missing extension + else +#endif + extGlBlendEquation(GL_MAX); + break; + default: + extGlBlendEquationIndexed(i, GL_FUNC_ADD); + break; + } + } +#endif + if (targets[i].TargetType==ERT_RENDER_TEXTURE) + { + GLenum attachment = GL_NONE; +#ifdef GL_EXT_framebuffer_object + // attach texture to FrameBuffer Object on Color [i] + attachment = GL_COLOR_ATTACHMENT0_EXT+i; + if ((i != 0) && (targets[i].RenderTexture != RenderTargetTexture)) + extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_2D, static_cast(targets[i].RenderTexture)->getOpenGLTextureName(), 0); +#endif + MRTs[i]=attachment; + } + else + { + switch(targets[i].TargetType) + { + case ERT_FRAME_BUFFER: + MRTs[i]=GL_BACK_LEFT; + break; + case ERT_STEREO_BOTH_BUFFERS: + MRTs[i]=GL_BACK; + break; + case ERT_STEREO_RIGHT_BUFFER: + MRTs[i]=GL_BACK_RIGHT; + break; + case ERT_STEREO_LEFT_BUFFER: + MRTs[i]=GL_BACK_LEFT; + break; + default: + MRTs[i]=GL_AUX0+(targets[i].TargetType-ERT_AUX_BUFFER0); + break; + } + } + } + + extGlDrawBuffers(maxMultipleRTTs, MRTs.const_pointer()); + } + + clearBuffers(clearBackBuffer, clearZBuffer, false, color); + return true; +} + + +// returns the current size of the screen or rendertarget +const core::dimension2d& COpenGLDriver::getCurrentRenderTargetSize() const +{ + if (CurrentRendertargetSize.Width == 0) + return ScreenSize; + else + return CurrentRendertargetSize; +} + + +//! Clears the ZBuffer. +void COpenGLDriver::clearZBuffer() +{ + clearBuffers(false, true, false, 0x0); +} + + +//! Returns an image created from the last rendered frame. +IImage* COpenGLDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) +{ + if (target==video::ERT_MULTI_RENDER_TEXTURES || target==video::ERT_RENDER_TEXTURE || target==video::ERT_STEREO_BOTH_BUFFERS) + return 0; + + // allows to read pixels in top-to-bottom order +#ifdef GL_MESA_pack_invert + if (FeatureAvailable[IRR_MESA_pack_invert]) + glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); +#endif + + if (format==video::ECF_UNKNOWN) + format=getColorFormat(); + GLenum fmt; + GLenum type; + switch (format) + { + case ECF_A1R5G5B5: + fmt = GL_BGRA; + type = GL_UNSIGNED_SHORT_1_5_5_5_REV; + break; + case ECF_R5G6B5: + fmt = GL_RGB; + type = GL_UNSIGNED_SHORT_5_6_5; + break; + case ECF_R8G8B8: + fmt = GL_RGB; + type = GL_UNSIGNED_BYTE; + break; + case ECF_A8R8G8B8: + fmt = GL_BGRA; + if (Version > 101) + type = GL_UNSIGNED_INT_8_8_8_8_REV; + else + type = GL_UNSIGNED_BYTE; + break; + case ECF_R16F: + if (FeatureAvailable[IRR_ARB_texture_rg]) + fmt = GL_RED; + else + fmt = GL_LUMINANCE; +#ifdef GL_ARB_half_float_pixel + if (FeatureAvailable[IRR_ARB_half_float_pixel]) + type = GL_HALF_FLOAT_ARB; + else +#endif + { + type = GL_FLOAT; + format = ECF_R32F; + } + break; + case ECF_G16R16F: +#ifdef GL_ARB_texture_rg + if (FeatureAvailable[IRR_ARB_texture_rg]) + fmt = GL_RG; + else +#endif + fmt = GL_LUMINANCE_ALPHA; +#ifdef GL_ARB_half_float_pixel + if (FeatureAvailable[IRR_ARB_half_float_pixel]) + type = GL_HALF_FLOAT_ARB; + else +#endif + { + type = GL_FLOAT; + format = ECF_G32R32F; + } + break; + case ECF_A16B16G16R16F: + fmt = GL_BGRA; +#ifdef GL_ARB_half_float_pixel + if (FeatureAvailable[IRR_ARB_half_float_pixel]) + type = GL_HALF_FLOAT_ARB; + else +#endif + { + type = GL_FLOAT; + format = ECF_A32B32G32R32F; + } + break; + case ECF_R32F: + if (FeatureAvailable[IRR_ARB_texture_rg]) + fmt = GL_RED; + else + fmt = GL_LUMINANCE; + type = GL_FLOAT; + break; + case ECF_G32R32F: +#ifdef GL_ARB_texture_rg + if (FeatureAvailable[IRR_ARB_texture_rg]) + fmt = GL_RG; + else +#endif + fmt = GL_LUMINANCE_ALPHA; + type = GL_FLOAT; + break; + case ECF_A32B32G32R32F: + fmt = GL_BGRA; + type = GL_FLOAT; + break; + default: + fmt = GL_BGRA; + type = GL_UNSIGNED_BYTE; + break; + } + IImage* newImage = createImage(format, ScreenSize); + + u8* pixels = 0; + if (newImage) + pixels = static_cast(newImage->lock()); + if (pixels) + { + GLenum tgt=GL_FRONT; + switch (target) + { + case video::ERT_FRAME_BUFFER: + break; + case video::ERT_STEREO_LEFT_BUFFER: + tgt=GL_FRONT_LEFT; + break; + case video::ERT_STEREO_RIGHT_BUFFER: + tgt=GL_FRONT_RIGHT; + break; + default: + tgt=GL_AUX0+(target-video::ERT_AUX_BUFFER0); + break; + } + glReadBuffer(tgt); + glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, fmt, type, pixels); + testGLError(); + glReadBuffer(GL_BACK); + } + +#ifdef GL_MESA_pack_invert + if (FeatureAvailable[IRR_MESA_pack_invert]) + glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE); + else +#endif + if (pixels) + { + // opengl images are horizontally flipped, so we have to fix that here. + const s32 pitch=newImage->getPitch(); + u8* p2 = pixels + (ScreenSize.Height - 1) * pitch; + u8* tmpBuffer = new u8[pitch]; + for (u32 i=0; i < ScreenSize.Height; i += 2) + { + memcpy(tmpBuffer, pixels, pitch); +// for (u32 j=0; junlock(); + if (testGLError() || !pixels) + { + newImage->drop(); + return 0; + } + } + return newImage; +} + + +//! get depth texture for the given render target texture +ITexture* COpenGLDriver::createDepthTexture(ITexture* texture, bool shared) +{ + if ((texture->getDriverType() != EDT_OPENGL) || (!texture->isRenderTarget())) + return 0; + COpenGLTexture* tex = static_cast(texture); + + if (!tex->isFrameBufferObject()) + return 0; + + if (shared) + { + for (u32 i=0; igetSize()==texture->getSize()) + { + DepthTextures[i]->grab(); + return DepthTextures[i]; + } + } + DepthTextures.push_back(new COpenGLFBODepthTexture(texture->getSize(), "depth1", this)); + return DepthTextures.getLast(); + } + return (new COpenGLFBODepthTexture(texture->getSize(), "depth1", this)); +} + + +void COpenGLDriver::removeDepthTexture(ITexture* texture) +{ + for (u32 i=0; i= MaxUserClipPlanes) + return false; + + UserClipPlanes[index].Plane=plane; + enableClipPlane(index, enable); + return true; +} + + +void COpenGLDriver::uploadClipPlane(u32 index) +{ + // opengl needs an array of doubles for the plane equation + GLdouble clip_plane[4]; + clip_plane[0] = UserClipPlanes[index].Plane.Normal.X; + clip_plane[1] = UserClipPlanes[index].Plane.Normal.Y; + clip_plane[2] = UserClipPlanes[index].Plane.Normal.Z; + clip_plane[3] = UserClipPlanes[index].Plane.D; + glClipPlane(GL_CLIP_PLANE0 + index, clip_plane); +} + + +//! Enable/disable a clipping plane. +void COpenGLDriver::enableClipPlane(u32 index, bool enable) +{ + if (index >= MaxUserClipPlanes) + return; + if (enable) + { + if (!UserClipPlanes[index].Enabled) + { + uploadClipPlane(index); + glEnable(GL_CLIP_PLANE0 + index); + } + } + else + glDisable(GL_CLIP_PLANE0 + index); + + UserClipPlanes[index].Enabled=enable; +} + + +core::dimension2du COpenGLDriver::getMaxTextureSize() const +{ + return core::dimension2du(MaxTextureSize, MaxTextureSize); +} + + +//! Convert E_PRIMITIVE_TYPE to OpenGL equivalent +GLenum COpenGLDriver::primitiveTypeToGL(scene::E_PRIMITIVE_TYPE type) const +{ + switch (type) + { + case scene::EPT_POINTS: + return GL_POINTS; + case scene::EPT_LINE_STRIP: + return GL_LINE_STRIP; + case scene::EPT_LINE_LOOP: + return GL_LINE_LOOP; + case scene::EPT_LINES: + return GL_LINES; + case scene::EPT_TRIANGLE_STRIP: + return GL_TRIANGLE_STRIP; + case scene::EPT_TRIANGLE_FAN: + return GL_TRIANGLE_FAN; + case scene::EPT_TRIANGLES: + return GL_TRIANGLES; + case scene::EPT_QUAD_STRIP: + return GL_QUAD_STRIP; + case scene::EPT_QUADS: + return GL_QUADS; + case scene::EPT_POLYGON: + return GL_POLYGON; + case scene::EPT_POINT_SPRITES: +#ifdef GL_ARB_point_sprite + return GL_POINT_SPRITE_ARB; +#else + return GL_POINTS; +#endif + } + return GL_TRIANGLES; +} + + +GLenum COpenGLDriver::getGLBlend(E_BLEND_FACTOR factor) const +{ + GLenum r = 0; + switch (factor) + { + case EBF_ZERO: r = GL_ZERO; break; + case EBF_ONE: r = GL_ONE; break; + case EBF_DST_COLOR: r = GL_DST_COLOR; break; + case EBF_ONE_MINUS_DST_COLOR: r = GL_ONE_MINUS_DST_COLOR; break; + case EBF_SRC_COLOR: r = GL_SRC_COLOR; break; + case EBF_ONE_MINUS_SRC_COLOR: r = GL_ONE_MINUS_SRC_COLOR; break; + case EBF_SRC_ALPHA: r = GL_SRC_ALPHA; break; + case EBF_ONE_MINUS_SRC_ALPHA: r = GL_ONE_MINUS_SRC_ALPHA; break; + case EBF_DST_ALPHA: r = GL_DST_ALPHA; break; + case EBF_ONE_MINUS_DST_ALPHA: r = GL_ONE_MINUS_DST_ALPHA; break; + case EBF_SRC_ALPHA_SATURATE: r = GL_SRC_ALPHA_SATURATE; break; + } + return r; +} + +GLenum COpenGLDriver::getZBufferBits() const +{ + GLenum bits = 0; + switch (Params.ZBufferBits) + { + case 16: + bits = GL_DEPTH_COMPONENT16; + break; + case 24: + bits = GL_DEPTH_COMPONENT24; + break; + case 32: + bits = GL_DEPTH_COMPONENT32; + break; + default: + bits = GL_DEPTH_COMPONENT; + break; + } + return bits; +} + +#ifdef _IRR_COMPILE_WITH_CG_ +const CGcontext& COpenGLDriver::getCgContext() +{ + return CgContext; +} +#endif + + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_OPENGL_ + +namespace irr +{ +namespace video +{ + + +// ----------------------------------- +// WINDOWS VERSION +// ----------------------------------- +#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ +IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceWin32* device) +{ +#ifdef _IRR_COMPILE_WITH_OPENGL_ + COpenGLDriver* ogl = new COpenGLDriver(params, io, device); + if (!ogl->initDriver(device)) + { + ogl->drop(); + ogl = 0; + } + return ogl; +#else + return 0; +#endif // _IRR_COMPILE_WITH_OPENGL_ +} +#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + +// ----------------------------------- +// MACOSX VERSION +// ----------------------------------- +#if defined(_IRR_COMPILE_WITH_OSX_DEVICE_) +IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceMacOSX *device) +{ +#ifdef _IRR_COMPILE_WITH_OPENGL_ + return new COpenGLDriver(params, io, device); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OPENGL_ +} +#endif // _IRR_COMPILE_WITH_OSX_DEVICE_ + +// ----------------------------------- +// X11 VERSION +// ----------------------------------- +#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ +IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceLinux* device) +{ +#ifdef _IRR_COMPILE_WITH_OPENGL_ + COpenGLDriver* ogl = new COpenGLDriver(params, io, device); + if (!ogl->initDriver(device)) + { + ogl->drop(); + ogl = 0; + } + return ogl; +#else + return 0; +#endif // _IRR_COMPILE_WITH_OPENGL_ +} +#endif // _IRR_COMPILE_WITH_X11_DEVICE_ + + +// ----------------------------------- +// SDL VERSION +// ----------------------------------- +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ +IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceSDL* device) +{ +#ifdef _IRR_COMPILE_WITH_OPENGL_ + return new COpenGLDriver(params, io, device); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OPENGL_ +} +#endif // _IRR_COMPILE_WITH_SDL_DEVICE_ + +} // end namespace +} // end namespace + + -- cgit v1.1