forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			1074 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			1074 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | #include "OpenGL.h"
 | ||
|  | #include "VertexBufferImpl.h"
 | ||
|  | #include "ogl.h"
 | ||
|  | #include <Kore/Log.h>
 | ||
|  | #include <Kore/Math/Core.h>
 | ||
|  | #include <Kore/System.h>
 | ||
|  | #include <cassert>
 | ||
|  | #include <cstdio>
 | ||
|  | 
 | ||
|  | #ifdef KINC_IOS
 | ||
|  | #include <OpenGLES/ES1/glext.h>
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #ifdef KINC_WINDOWS
 | ||
|  | #include <GL/wglew.h>
 | ||
|  | 
 | ||
|  | #define WIN32_LEAN_AND_MEAN
 | ||
|  | #define NOMINMAX
 | ||
|  | #include <Windows.h>
 | ||
|  | 
 | ||
|  | #pragma comment(lib, "opengl32.lib")
 | ||
|  | #pragma comment(lib, "glu32.lib")
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | using namespace Kore; | ||
|  | 
 | ||
|  | namespace Kore { | ||
|  | #if !defined(KINC_IOS) && !defined(KINC_ANDROID)
 | ||
|  | 	extern bool programUsesTessellation; | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | namespace { | ||
|  | #ifdef KINC_WINDOWS
 | ||
|  | 	HINSTANCE instance = 0; | ||
|  | 	HDC deviceContexts[10] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; | ||
|  | 	HGLRC glContexts[10] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 	Graphics3::TextureFilter minFilters[10][32]; | ||
|  | 	Graphics3::MipmapFilter mipFilters[10][32]; | ||
|  | 	int originalFramebuffer[10] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; | ||
|  | 	uint arrayId[10]; | ||
|  | 
 | ||
|  | 	int _width; | ||
|  | 	int _height; | ||
|  | 	int _renderTargetWidth; | ||
|  | 	int _renderTargetHeight; | ||
|  | 	bool renderToBackbuffer; | ||
|  | 
 | ||
|  | 	bool depthTest = false; | ||
|  | 	bool depthMask = false; | ||
|  | 
 | ||
|  | 	struct wvpTransform_t { | ||
|  | 		mat4 projection; | ||
|  | 		mat4 view; | ||
|  | 		mat4 world; | ||
|  | 	} g_wvpTransform; | ||
|  | 
 | ||
|  | #if defined(KINC_OPENGL_ES) && defined(KINC_ANDROID) && KINC_ANDROID_API >= 18
 | ||
|  | 	void *glesDrawBuffers; | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::destroy(int windowId) { | ||
|  | #ifdef KINC_WINDOWS
 | ||
|  | 	if (glContexts[windowId]) { | ||
|  | 		if (!wglMakeCurrent(nullptr, nullptr)) { | ||
|  | 			// MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
 | ||
|  | 		} | ||
|  | 		if (!wglDeleteContext(glContexts[windowId])) { | ||
|  | 			// MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
 | ||
|  | 		} | ||
|  | 		glContexts[windowId] = nullptr; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	HWND windowHandle = (HWND)System::windowHandle(windowId); | ||
|  | 
 | ||
|  | 	// TODO (DK) shouldn't 'deviceContexts[windowId] = nullptr;' be moved out of here?
 | ||
|  | 	if (deviceContexts[windowId] && !ReleaseDC(windowHandle, deviceContexts[windowId])) { | ||
|  | 		// MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
 | ||
|  | 		deviceContexts[windowId] = nullptr; | ||
|  | 	} | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 	System::destroyWindow(windowId); | ||
|  | } | ||
|  | 
 | ||
|  | #undef CreateWindow
 | ||
|  | 
 | ||
|  | #ifdef KINC_WINDOWS
 | ||
|  | namespace Kore { | ||
|  | 	namespace System { | ||
|  | 		extern int currentDeviceId; | ||
|  | 	} | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #ifdef KINC_WINDOWS
 | ||
|  | void Graphics3::setup() {} | ||
|  | #endif
 | ||
|  | 
 | ||
|  | void Graphics3::init(int windowId, int depthBufferBits, int stencilBufferBits, bool vsync) { | ||
|  | #ifdef KINC_WINDOWS
 | ||
|  | 	HWND windowHandle = (HWND)System::windowHandle(windowId); | ||
|  | 
 | ||
|  | #ifndef VR_RIFT
 | ||
|  | 	// TODO (DK) use provided settings for depth/stencil buffer
 | ||
|  | 
 | ||
|  | 	PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be
 | ||
|  | 	    { | ||
|  | 	        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
 | ||
|  | 	            PFD_DOUBLEBUFFER,          // Must Support Double Buffering
 | ||
|  | 	        PFD_TYPE_RGBA,                 // Request An RGBA Format
 | ||
|  | 	        32,                            // 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
 | ||
|  | 	        static_cast<BYTE>(depthBufferBits),   // 16Bit Z-Buffer (Depth Buffer)
 | ||
|  | 	        static_cast<BYTE>(stencilBufferBits), // 8Bit Stencil Buffer
 | ||
|  | 	        0,                                    // No Auxiliary Buffer
 | ||
|  | 	        PFD_MAIN_PLANE,                       // Main Drawing Layer
 | ||
|  | 	        0,                                    // Reserved
 | ||
|  | 	        0, | ||
|  | 	        0, | ||
|  | 	        0 // Layer Masks Ignored
 | ||
|  | 	    }; | ||
|  | 
 | ||
|  | 	deviceContexts[windowId] = GetDC(windowHandle); | ||
|  | 	GLuint pixelFormat = ChoosePixelFormat(deviceContexts[windowId], &pfd); | ||
|  | 	SetPixelFormat(deviceContexts[windowId], pixelFormat, &pfd); | ||
|  | 	HGLRC tempGlContext = wglCreateContext(deviceContexts[windowId]); | ||
|  | 	wglMakeCurrent(deviceContexts[windowId], tempGlContext); | ||
|  | 	Kore::System::currentDeviceId = windowId; | ||
|  | 
 | ||
|  | 	// TODO (DK) make a Graphics3::setup() (called from System::setup()) and call it there only once?
 | ||
|  | 	if (windowId == 0) { | ||
|  | 		glewInit(); | ||
|  | 	} | ||
|  | 
 | ||
|  | #if 0
 | ||
|  | 	if (wglewIsSupported("WGL_ARB_create_context") == 1) { | ||
|  | 		int attributes[] = { | ||
|  | 			WGL_CONTEXT_MAJOR_VERSION_ARB, 4, | ||
|  | 			WGL_CONTEXT_MINOR_VERSION_ARB, 2, | ||
|  | 			WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, | ||
|  | 			WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, | ||
|  | 			0 | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		glContexts[windowId] = wglCreateContextAttribsARB(deviceContexts[windowId], glContexts[0], attributes); | ||
|  | 		glCheckErrors(); | ||
|  | 		wglMakeCurrent(nullptr, nullptr); | ||
|  | 		wglDeleteContext(tempGlContext); | ||
|  | 		wglMakeCurrent(deviceContexts[windowId], glContexts[windowId]); | ||
|  | 		glCheckErrors(); | ||
|  | 	} | ||
|  | 	else | ||
|  | #endif
 | ||
|  | 	{ glContexts[windowId] = tempGlContext; } | ||
|  | 
 | ||
|  | 	ShowWindow(windowHandle, SW_SHOW); | ||
|  | 	SetForegroundWindow(windowHandle); // Slightly Higher Priority
 | ||
|  | 	SetFocus(windowHandle);            // Sets Keyboard Focus To The Window
 | ||
|  | #else
 | ||
|  | 	deviceContexts[windowId] = GetDC(windowHandle); | ||
|  | 	glContexts[windowId] = wglGetCurrentContext(); | ||
|  | 	glewInit(); | ||
|  | #endif
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #ifndef VR_RIFT
 | ||
|  | 	glEnable(GL_BLEND); | ||
|  | 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
|  | 	setRenderState(DepthTest, false); | ||
|  | 	glViewport(0, 0, System::windowWidth(windowId), System::windowHeight(windowId)); | ||
|  | 	glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originalFramebuffer[windowId]); | ||
|  | 
 | ||
|  | 	for (int i = 0; i < 32; ++i) { | ||
|  | 		minFilters[windowId][i] = LinearFilter; | ||
|  | 		mipFilters[windowId][i] = NoMipFilter; | ||
|  | 	} | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #ifdef KINC_WINDOWS
 | ||
|  | 	if (windowId == 0) { | ||
|  | 		// TODO (DK) check if we actually want vsync
 | ||
|  | 		if (wglSwapIntervalEXT != nullptr) | ||
|  | 			wglSwapIntervalEXT(1); | ||
|  | 	} | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(KINC_IOS)
 | ||
|  | 	glGenVertexArraysOES(1, &arrayId[windowId]); | ||
|  | #elif defined(KINC_MACOS)
 | ||
|  | 	glGenVertexArraysAPPLE(1, &arrayId[windowId]); | ||
|  | #elif !defined(KINC_ANDROID) && !defined(KINC_EMSCRIPTEN) && !defined(KINC_RASPBERRY_PI)
 | ||
|  | 	glGenVertexArrays(1, &arrayId[windowId]); | ||
|  | #endif
 | ||
|  | 	glCheckErrors(); | ||
|  | 
 | ||
|  | 	_width = System::windowWidth(0); | ||
|  | 	_height = System::windowHeight(0); | ||
|  | 	_renderTargetWidth = _width; | ||
|  | 	_renderTargetHeight = _height; | ||
|  | 	renderToBackbuffer = true; | ||
|  | 
 | ||
|  | #if defined(KINC_OPENGL_ES) && defined(KINC_ANDROID) && KINC_ANDROID_API >= 18
 | ||
|  | 	glesDrawBuffers = (void *)eglGetProcAddress("glDrawBuffers"); | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::changeResolution(int width, int height) { | ||
|  | 	_width = width; | ||
|  | 	_height = height; | ||
|  | 	if (renderToBackbuffer) { | ||
|  | 		_renderTargetWidth = _width; | ||
|  | 		_renderTargetHeight = _height; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // TODO (DK) should return displays refreshrate?
 | ||
|  | unsigned Graphics3::refreshRate() { | ||
|  | 	return 60; | ||
|  | } | ||
|  | 
 | ||
|  | // TODO (DK) should check the extension and return wheter it's enabled (wglSwapIntervalEXT(1)) or not?
 | ||
|  | bool Graphics3::vsynced() { | ||
|  | 	return true; | ||
|  | } | ||
|  | 
 | ||
|  | static void invertMatrixEntry(mat4 &m, int row, int col) { | ||
|  | 	m.Set(row, col, -m.get(row, col)); | ||
|  | } | ||
|  | 
 | ||
|  | // Invert matrix Z-axis (for view matrices)
 | ||
|  | static void invertMatrixZ(mat4 &m) { | ||
|  | 	invertMatrixEntry(m, 2, 0); | ||
|  | 	invertMatrixEntry(m, 2, 1); | ||
|  | 	invertMatrixEntry(m, 2, 2); | ||
|  | 	invertMatrixEntry(m, 2, 3); | ||
|  | } | ||
|  | 
 | ||
|  | /*
 | ||
|  | Converts the specified left-handed projection matrix | ||
|  | into a right-handed projection matrix (required for OpenGL). | ||
|  | */ | ||
|  | static void convertToRightHandedProjection(mat4 &m) { | ||
|  | 	// Invert Z-axis of projection matrix (along 3rd column, i.e. zero-based-index 2)
 | ||
|  | 	invertMatrixEntry(m, 0, 2); | ||
|  | 	invertMatrixEntry(m, 1, 2); | ||
|  | 	invertMatrixEntry(m, 2, 2); | ||
|  | 	invertMatrixEntry(m, 3, 2); | ||
|  | } | ||
|  | 
 | ||
|  | static void uploadModelViewMatrix() { | ||
|  | 	// Compute: modelViewMatrix = viewMatrix * worldMatrix
 | ||
|  | 	mat4 modelViewMatrix = g_wvpTransform.view; | ||
|  | 	modelViewMatrix *= g_wvpTransform.world; | ||
|  | 
 | ||
|  | 	// Update GL model-view matrix
 | ||
|  | 	glMatrixMode(GL_MODELVIEW); | ||
|  | 	glLoadMatrixf(modelViewMatrix.data); | ||
|  | } | ||
|  | 
 | ||
|  | static void uploadProjectionMatrix() { | ||
|  | 	// Update GL projection matrix
 | ||
|  | 	glMatrixMode(GL_PROJECTION); | ||
|  | 	glLoadMatrixf(g_wvpTransform.projection.data); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setFogColor(const Graphics1::Color &color) { | ||
|  | 	glFogfv(GL_FOG_COLOR, &(color.R)); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setViewMatrix(const mat4 &value) { | ||
|  | 	// Convert view matrix from left-handed to right-handed coordinate system
 | ||
|  | 	g_wvpTransform.view = value; | ||
|  | #ifndef G3_DISABLE_AUTO_PROJECTION
 | ||
|  | 	invertMatrixZ(g_wvpTransform.view); | ||
|  | #endif
 | ||
|  | 	uploadModelViewMatrix(); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setWorldMatrix(const mat4 &value) { | ||
|  | 	g_wvpTransform.world = value; | ||
|  | 	uploadModelViewMatrix(); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setProjectionMatrix(const mat4 &value) { | ||
|  | 	g_wvpTransform.projection = value; | ||
|  | #ifndef G3_DISABLE_AUTO_PROJECTION
 | ||
|  | 	convertToRightHandedProjection(g_wvpTransform.projection); | ||
|  | #endif
 | ||
|  | 	uploadProjectionMatrix(); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::drawIndexedVertices() { | ||
|  | 	drawIndexedVertices(0, IndexBufferImpl::current->count()); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::drawIndexedVertices(int start, int count) { | ||
|  | #ifdef KINC_OPENGL_ES
 | ||
|  | #if defined(KINC_ANDROID) || defined(KINC_RASPBERRY_PI)
 | ||
|  | 	glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (void *)(start * sizeof(GL_UNSIGNED_SHORT))); | ||
|  | #else
 | ||
|  | 	glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, (void *)(start * sizeof(GL_UNSIGNED_INT))); | ||
|  | #endif
 | ||
|  | 	glCheckErrors(); | ||
|  | #else
 | ||
|  | 	{ | ||
|  | 		glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, (void *)(start * sizeof(GL_UNSIGNED_INT))); | ||
|  | 		glCheckErrors(); | ||
|  | 	} | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::swapBuffers(int contextId) { | ||
|  | #ifdef KINC_WINDOWS
 | ||
|  | 	::SwapBuffers(deviceContexts[contextId]); | ||
|  | #else
 | ||
|  | 	System::swapBuffers(contextId); | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | #ifdef KINC_IOS
 | ||
|  | void beginGL(); | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(KINC_WINDOWS)
 | ||
|  | void Graphics3::makeCurrent(int contextId) { | ||
|  | 	wglMakeCurrent(deviceContexts[contextId], glContexts[contextId]); | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | void Graphics3::begin(int contextId) { | ||
|  | 	if (System::currentDevice() != -1) { | ||
|  | 		if (System::currentDevice() != contextId) { | ||
|  | 			log(Warning, "begin: wrong glContext is active"); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			//**log(Warning, "begin: a glContext is still active");
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// return; // TODO (DK) return here?
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// System::setCurrentDevice(contextId);
 | ||
|  | 	System::makeCurrent(contextId); | ||
|  | 
 | ||
|  | 	glViewport(0, 0, _width, _height); | ||
|  | 
 | ||
|  | #ifdef KINC_IOS
 | ||
|  | 	beginGL(); | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #ifdef KINC_ANDROID
 | ||
|  | 	// if rendered to a texture, strange things happen if the backbuffer is not cleared
 | ||
|  | 	glClearColor(0.0f, 0.0f, 0.0f, 1.0f); | ||
|  | 	glClear(GL_COLOR_BUFFER_BIT); | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::viewport(int x, int y, int width, int height) { | ||
|  | 	glViewport(x, _renderTargetHeight - y - height, width, height); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::scissor(int x, int y, int width, int height) { | ||
|  | 	glEnable(GL_SCISSOR_TEST); | ||
|  | 	glScissor(x, _renderTargetHeight - y - height, width, height); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::disableScissor() { | ||
|  | 	glDisable(GL_SCISSOR_TEST); | ||
|  | } | ||
|  | 
 | ||
|  | namespace { | ||
|  | 	GLenum convert(Graphics3::StencilAction action) { | ||
|  | 		switch (action) { | ||
|  | 		case Graphics3::Decrement: | ||
|  | 			return GL_DECR; | ||
|  | 		case Graphics3::DecrementWrap: | ||
|  | 			return GL_DECR_WRAP; | ||
|  | 		case Graphics3::Increment: | ||
|  | 			return GL_INCR; | ||
|  | 		case Graphics3::IncrementWrap: | ||
|  | 			return GL_INCR_WRAP; | ||
|  | 		case Graphics3::Invert: | ||
|  | 			return GL_INVERT; | ||
|  | 		case Graphics3::Keep: | ||
|  | 			return GL_KEEP; | ||
|  | 		case Graphics3::Replace: | ||
|  | 			return GL_REPLACE; | ||
|  | 		case Graphics3::Zero: | ||
|  | 			return GL_ZERO; | ||
|  | 		} | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setStencilParameters(ZCompareMode compareMode, StencilAction bothPass, StencilAction depthFail, StencilAction stencilFail, int referenceValue, | ||
|  |                                      int readMask, int writeMask) { | ||
|  | 	if (compareMode == ZCompareAlways && bothPass == Keep && depthFail == Keep && stencilFail == Keep) { | ||
|  | 		glDisable(GL_STENCIL_TEST); | ||
|  | 	} | ||
|  | 	else { | ||
|  | 		glEnable(GL_STENCIL_TEST); | ||
|  | 		int stencilFunc = 0; | ||
|  | 		switch (compareMode) { | ||
|  | 		case ZCompareAlways: | ||
|  | 			stencilFunc = GL_ALWAYS; | ||
|  | 			break; | ||
|  | 		case ZCompareEqual: | ||
|  | 			stencilFunc = GL_EQUAL; | ||
|  | 			break; | ||
|  | 		case ZCompareGreater: | ||
|  | 			stencilFunc = GL_GREATER; | ||
|  | 			break; | ||
|  | 		case ZCompareGreaterEqual: | ||
|  | 			stencilFunc = GL_GEQUAL; | ||
|  | 			break; | ||
|  | 		case ZCompareLess: | ||
|  | 			stencilFunc = GL_LESS; | ||
|  | 			break; | ||
|  | 		case ZCompareLessEqual: | ||
|  | 			stencilFunc = GL_LEQUAL; | ||
|  | 			break; | ||
|  | 		case ZCompareNever: | ||
|  | 			stencilFunc = GL_NEVER; | ||
|  | 			break; | ||
|  | 		case ZCompareNotEqual: | ||
|  | 			stencilFunc = GL_NOTEQUAL; | ||
|  | 			break; | ||
|  | 		} | ||
|  | 		glStencilMask(writeMask); | ||
|  | 		glStencilOp(convert(stencilFail), convert(depthFail), convert(bothPass)); | ||
|  | 		glStencilFunc(stencilFunc, referenceValue, readMask); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | /*void glCheckErrors() {
 | ||
|  |     if (System::currentDevice() == -1) { | ||
|  |         log(Warning, "no OpenGL device context is set"); | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  | //#ifdef _DEBUG
 | ||
|  |     GLenum code = glGetError(); | ||
|  |     while (code != GL_NO_ERROR) { | ||
|  |         //std::printf("GLError: %s\n", glewGetErrorString(code));
 | ||
|  |         switch (code) { | ||
|  |         case GL_INVALID_VALUE: | ||
|  |             log(Warning, "OpenGL: Invalid value"); | ||
|  |             break; | ||
|  |         case GL_INVALID_OPERATION: | ||
|  |             log(Warning, "OpenGL: Invalid operation"); | ||
|  |             break; | ||
|  |         default: | ||
|  |             log(Warning, "OpenGL: Error code %i", code); | ||
|  |             break; | ||
|  |         } | ||
|  |         code = glGetError(); | ||
|  |     } | ||
|  | //#endif
 | ||
|  | }*/ | ||
|  | 
 | ||
|  | #ifdef KINC_WINDOWS
 | ||
|  | void Graphics3::clearCurrent() { | ||
|  | 	wglMakeCurrent(nullptr, nullptr); | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | // TODO (DK) this never gets called on some targets, needs investigation?
 | ||
|  | void Graphics3::end(int windowId) { | ||
|  | 	// glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
 | ||
|  | 	// glClear(GL_COLOR_BUFFER_BIT);
 | ||
|  | 	glCheckErrors(); | ||
|  | 
 | ||
|  | 	if (System::currentDevice() == -1) { | ||
|  | 		log(Warning, "end: a glContext wasn't active"); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (System::currentDevice() != windowId) { | ||
|  | 		log(Warning, "end: wrong glContext is active"); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	System::clearCurrent(); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::clear(uint flags, uint color, float depth, int stencil) { | ||
|  | 	glClearColor(((color & 0x00ff0000) >> 16) / 255.0f, ((color & 0x0000ff00) >> 8) / 255.0f, (color & 0x000000ff) / 255.0f, (color & 0xff000000) / 255.0f); | ||
|  | 	glCheckErrors(); | ||
|  | 	if (flags & ClearDepthFlag) { | ||
|  | 		glEnable(GL_DEPTH_TEST); | ||
|  | 		glDepthMask(GL_TRUE); | ||
|  | 		glCheckErrors(); | ||
|  | 	} | ||
|  | #ifdef KINC_OPENGL_ES
 | ||
|  | 	glClearDepthf(depth); | ||
|  | #else
 | ||
|  | 	glClearDepth(depth); | ||
|  | #endif
 | ||
|  | 	glCheckErrors(); | ||
|  | 	glStencilMask(0xff); | ||
|  | 	glCheckErrors(); | ||
|  | 	glClearStencil(stencil); | ||
|  | 	glCheckErrors(); | ||
|  | 	GLbitfield oglflags = ((flags & ClearColorFlag) ? GL_COLOR_BUFFER_BIT : 0) | ((flags & ClearDepthFlag) ? GL_DEPTH_BUFFER_BIT : 0) | | ||
|  | 	                      ((flags & ClearStencilFlag) ? GL_STENCIL_BUFFER_BIT : 0); | ||
|  | 	glClear(oglflags); | ||
|  | 	glCheckErrors(); | ||
|  | 	if (depthTest) { | ||
|  | 		glEnable(GL_DEPTH_TEST); | ||
|  | 	} | ||
|  | 	else { | ||
|  | 		glDisable(GL_DEPTH_TEST); | ||
|  | 	} | ||
|  | 	glCheckErrors(); | ||
|  | 	if (depthMask) { | ||
|  | 		glDepthMask(GL_TRUE); | ||
|  | 	} | ||
|  | 	else { | ||
|  | 		glDepthMask(GL_FALSE); | ||
|  | 	} | ||
|  | 	glCheckErrors(); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setColorMask(bool red, bool green, bool blue, bool alpha) { | ||
|  | 	glColorMask(red, green, blue, alpha); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setMaterialState(MaterialState state, const vec4 &value) { | ||
|  | 	switch (state) { | ||
|  | 	case AmbientColor: | ||
|  | 		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, value.values); | ||
|  | 		break; | ||
|  | 	case DiffuseColor: | ||
|  | 		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, value.values); | ||
|  | 		break; | ||
|  | 	case SpecularColor: | ||
|  | 		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, value.values); | ||
|  | 		break; | ||
|  | 	case EmissionColor: | ||
|  | 		glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, value.values); | ||
|  | 		break; | ||
|  | 	case SolidColor: | ||
|  | 		glColor4fv(value.values); | ||
|  | 		break; | ||
|  | 	default: | ||
|  | 		break; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setMaterialState(MaterialState state, float value) { | ||
|  | 	switch (state) { | ||
|  | 	case ShininessExponent: | ||
|  | 		glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, max(0.0f, min(value, 180.0f))); | ||
|  | 		break; | ||
|  | 	default: | ||
|  | 		break; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setTextureMapping(TextureUnit texunit, TextureMapping mapping, bool on) { | ||
|  | 	glActiveTexture(GL_TEXTURE0 + texunit.unit); | ||
|  | 	switch (mapping) { | ||
|  | 	case Texture1D: | ||
|  | 		// Enable/disabled 1D texture mapping for active texture layer
 | ||
|  | 		if (on) | ||
|  | 			glEnable(GL_TEXTURE_1D); | ||
|  | 		else | ||
|  | 			glDisable(GL_TEXTURE_1D); | ||
|  | 		break; | ||
|  | 	case Texture2D: | ||
|  | 		// Enable/disabled 2D texture mapping for active texture layer
 | ||
|  | 		if (on) | ||
|  | 			glEnable(GL_TEXTURE_2D); | ||
|  | 		else | ||
|  | 			glDisable(GL_TEXTURE_2D); | ||
|  | 		break; | ||
|  | 	case Texture3D: | ||
|  | 		// Enable/disabled 3D texture mapping for active texture layer
 | ||
|  | 		if (on) | ||
|  | 			glEnable(GL_TEXTURE_3D); | ||
|  | 		else | ||
|  | 			glDisable(GL_TEXTURE_3D); | ||
|  | 		break; | ||
|  | 	case TextureCubeMap: | ||
|  | 		// Enable/disabled cube texture mapping for active texture layer
 | ||
|  | 		if (on) | ||
|  | 			glEnable(GL_TEXTURE_CUBE_MAP); | ||
|  | 		else | ||
|  | 			glDisable(GL_TEXTURE_CUBE_MAP); | ||
|  | 		break; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | static GLenum texCoordToGLenum(Graphics3::TextureCoordinate texcoord) { | ||
|  | 	switch (texcoord) { | ||
|  | 	case Graphics3::TexCoordX: | ||
|  | 		return GL_S; | ||
|  | 	case Graphics3::TexCoordY: | ||
|  | 		return GL_T; | ||
|  | 	case Graphics3::TexCoordZ: | ||
|  | 		return GL_R; | ||
|  | 	case Graphics3::TexCoordW: | ||
|  | 		return GL_Q; | ||
|  | 	} | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static GLenum texGenCoordToGLenum(Graphics3::TextureCoordinate texcoord) { | ||
|  | 	switch (texcoord) { | ||
|  | 	case Graphics3::TexCoordX: | ||
|  | 		return GL_TEXTURE_GEN_S; | ||
|  | 	case Graphics3::TexCoordY: | ||
|  | 		return GL_TEXTURE_GEN_T; | ||
|  | 	case Graphics3::TexCoordZ: | ||
|  | 		return GL_TEXTURE_GEN_R; | ||
|  | 	case Graphics3::TexCoordW: | ||
|  | 		return GL_TEXTURE_GEN_Q; | ||
|  | 	} | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setTexCoordGeneration(TextureUnit texunit, TextureCoordinate texcoord, TexCoordGeneration generation) { | ||
|  | 	glActiveTexture(GL_TEXTURE0 + texunit.unit); | ||
|  | 	switch (generation) { | ||
|  | 	case TexGenDisabled: | ||
|  | 		// Disable texture coordinate generation for 'texcoord'
 | ||
|  | 		glDisable(texGenCoordToGLenum(texcoord)); | ||
|  | 		break; | ||
|  | 	case TexGenObjectLinear: | ||
|  | 		// Enable and configure texture coordinate generation for 'texcoord' with 'generation' mode
 | ||
|  | 		glEnable(texGenCoordToGLenum(texcoord)); | ||
|  | 		glTexGeni(texCoordToGLenum(texcoord), GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); | ||
|  | 		break; | ||
|  | 	case TexGenViewLinear: | ||
|  | 		// Enable and configure texture coordinate generation for 'texcoord' with 'generation' mode
 | ||
|  | 		glEnable(texGenCoordToGLenum(texcoord)); | ||
|  | 		glTexGeni(texCoordToGLenum(texcoord), GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); | ||
|  | 		break; | ||
|  | 	case TexGenSphereMap: | ||
|  | 		// Enable and configure texture coordinate generation for 'texcoord' with 'generation' mode
 | ||
|  | 		glEnable(texGenCoordToGLenum(texcoord)); | ||
|  | 		glTexGeni(texCoordToGLenum(texcoord), GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); | ||
|  | 		break; | ||
|  | 	case TexGenNormalMap: | ||
|  | 		// Enable and configure texture coordinate generation for 'texcoord' with 'generation' mode
 | ||
|  | 		glEnable(texGenCoordToGLenum(texcoord)); | ||
|  | 		glTexGeni(texCoordToGLenum(texcoord), GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP); | ||
|  | 		break; | ||
|  | 	case TexGenReflectionMap: | ||
|  | 		// Enable and configure texture coordinate generation for 'texcoord' with 'generation' mode
 | ||
|  | 		glEnable(texGenCoordToGLenum(texcoord)); | ||
|  | 		glTexGeni(texCoordToGLenum(texcoord), GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); | ||
|  | 		break; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setRenderState(RenderState state, bool on) { | ||
|  | 	switch (state) { | ||
|  | 	case DepthWrite: | ||
|  | 		if (on) | ||
|  | 			glDepthMask(GL_TRUE); | ||
|  | 		else | ||
|  | 			glDepthMask(GL_FALSE); | ||
|  | 		depthMask = on; | ||
|  | 		break; | ||
|  | 	case DepthTest: | ||
|  | 		if (on) | ||
|  | 			glEnable(GL_DEPTH_TEST); | ||
|  | 		else | ||
|  | 			glDisable(GL_DEPTH_TEST); | ||
|  | 		depthTest = on; | ||
|  | 		break; | ||
|  | 	case BlendingState: | ||
|  | 		if (on) | ||
|  | 			glEnable(GL_BLEND); | ||
|  | 		else | ||
|  | 			glDisable(GL_BLEND); | ||
|  | 		break; | ||
|  | 	case Lighting: | ||
|  | 		// Enable/Disable lighting
 | ||
|  | 		if (on) | ||
|  | 			glEnable(GL_LIGHTING); | ||
|  | 		else | ||
|  | 			glDisable(GL_LIGHTING); | ||
|  | 		break; | ||
|  | 	case Normalize: | ||
|  | 		// Enable/disable automatic normalize of normal vectors for non-uniform scaled models
 | ||
|  | 		if (on) | ||
|  | 			glEnable(GL_NORMALIZE); | ||
|  | 		else | ||
|  | 			glDisable(GL_NORMALIZE); | ||
|  | 		break; | ||
|  | 	case FogState: | ||
|  | 		// Enable/disable fog
 | ||
|  | 		if (on) | ||
|  | 			glEnable(GL_FOG); | ||
|  | 		else | ||
|  | 			glDisable(GL_FOG); | ||
|  | 		break; | ||
|  | 	default: | ||
|  | 		break; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	glCheckErrors(); | ||
|  | 
 | ||
|  | 	/*switch (state) {
 | ||
|  | 	    case Normalize: | ||
|  | 	        device->SetRenderState(D3DRS_NORMALIZENORMALS, on ? TRUE : FALSE); | ||
|  | 	        break; | ||
|  | 	    case BackfaceCulling: | ||
|  | 	        if (on) device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); | ||
|  | 	        else device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); | ||
|  | 	        break; | ||
|  | 	    case FogState: | ||
|  | 	        device->SetRenderState(D3DRS_FOGENABLE, on ? TRUE : FALSE); | ||
|  | 	        break; | ||
|  | 	    case ScissorTestState: | ||
|  | 	        device->SetRenderState(D3DRS_SCISSORTESTENABLE, on ? TRUE : FALSE); | ||
|  | 	        break; | ||
|  | 	    case AlphaTestState: | ||
|  | 	        device->SetRenderState(D3DRS_ALPHATESTENABLE, on ? TRUE : FALSE); | ||
|  | 	        device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); | ||
|  | 	        break; | ||
|  | 	    default: | ||
|  | 	        throw Exception(); | ||
|  | 	}*/ | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setRenderState(RenderState state, int v) { | ||
|  | 	switch (state) { | ||
|  | 	case DepthTestCompare: | ||
|  | 		switch (v) { | ||
|  | 		default: | ||
|  | 		case ZCompareAlways: | ||
|  | 			v = GL_ALWAYS; | ||
|  | 			break; | ||
|  | 		case ZCompareNever: | ||
|  | 			v = GL_NEVER; | ||
|  | 			break; | ||
|  | 		case ZCompareEqual: | ||
|  | 			v = GL_EQUAL; | ||
|  | 			break; | ||
|  | 		case ZCompareNotEqual: | ||
|  | 			v = GL_NOTEQUAL; | ||
|  | 			break; | ||
|  | 		case ZCompareLess: | ||
|  | 			v = GL_LESS; | ||
|  | 			break; | ||
|  | 		case ZCompareLessEqual: | ||
|  | 			v = GL_LEQUAL; | ||
|  | 			break; | ||
|  | 		case ZCompareGreater: | ||
|  | 			v = GL_GREATER; | ||
|  | 			break; | ||
|  | 		case ZCompareGreaterEqual: | ||
|  | 			v = GL_GEQUAL; | ||
|  | 			break; | ||
|  | 		} | ||
|  | 		glDepthFunc(v); | ||
|  | 		glCheckErrors(); | ||
|  | 		break; | ||
|  | 	case BackfaceCulling: | ||
|  | 		switch (v) { | ||
|  | 		case Clockwise: | ||
|  | 			glEnable(GL_CULL_FACE); | ||
|  | 			glCullFace(GL_BACK); | ||
|  | 			glCheckErrors(); | ||
|  | 			break; | ||
|  | 		case CounterClockwise: | ||
|  | 			glEnable(GL_CULL_FACE); | ||
|  | 			glCullFace(GL_FRONT); | ||
|  | 			glCheckErrors(); | ||
|  | 			break; | ||
|  | 		case NoCulling: | ||
|  | 			glDisable(GL_CULL_FACE); | ||
|  | 			glCheckErrors(); | ||
|  | 			break; | ||
|  | 		default: | ||
|  | 			break; | ||
|  | 		} | ||
|  | 		break; | ||
|  | 	case FogType: | ||
|  | 		switch (v) { | ||
|  | 		case LinearFog: | ||
|  | 			glFogi(GL_FOG_MODE, GL_LINEAR); | ||
|  | 			break; | ||
|  | 		case ExpFog: | ||
|  | 			glFogi(GL_FOG_MODE, GL_EXP); | ||
|  | 			break; | ||
|  | 		case Exp2Fog: | ||
|  | 			glFogi(GL_FOG_MODE, GL_EXP2); | ||
|  | 			break; | ||
|  | 		} | ||
|  | 		glCheckErrors(); | ||
|  | 		break; | ||
|  | 	default: | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	/*switch (state) {
 | ||
|  | 	    case DepthTestCompare: | ||
|  | 	        switch (v) { | ||
|  | 	                // TODO: Cmp-Konstanten systemabhaengig abgleichen
 | ||
|  | 	            default: | ||
|  | 	            case ZCmp_Always      : v = D3DCMP_ALWAYS; break; | ||
|  | 	            case ZCmp_Never       : v = D3DCMP_NEVER; break; | ||
|  | 	            case ZCmp_Equal       : v = D3DCMP_EQUAL; break; | ||
|  | 	            case ZCmp_NotEqual    : v = D3DCMP_NOTEQUAL; break; | ||
|  | 	            case ZCmp_Less        : v = D3DCMP_LESS; break; | ||
|  | 	            case ZCmp_LessEqual   : v = D3DCMP_LESSEQUAL; break; | ||
|  | 	            case ZCmp_Greater     : v = D3DCMP_GREATER; break; | ||
|  | 	            case ZCmp_GreaterEqual: v = D3DCMP_GREATEREQUAL; break; | ||
|  | 	        } | ||
|  | 	        device->SetRenderState(D3DRS_ZFUNC, v); | ||
|  | 	        break; | ||
|  | 	    case FogTypeState: | ||
|  | 	        switch (v) { | ||
|  | 	            case LinearFog: | ||
|  | 	                device->SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR); | ||
|  | 	        } | ||
|  | 	        break; | ||
|  | 	    case AlphaReferenceState: | ||
|  | 	        device->SetRenderState(D3DRS_ALPHAREF, (DWORD)v); | ||
|  | 	        break; | ||
|  | 	    default: | ||
|  | 	        throw Exception(); | ||
|  | 	}*/ | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setRenderState(RenderState state, float value) { | ||
|  | 	switch (state) { | ||
|  | 	case FogStart: | ||
|  | 		glFogf(GL_FOG_START, value); | ||
|  | 		glCheckErrors(); | ||
|  | 		break; | ||
|  | 	case FogEnd: | ||
|  | 		glFogf(GL_FOG_END, value); | ||
|  | 		glCheckErrors(); | ||
|  | 		break; | ||
|  | 	case FogDensity: | ||
|  | 		glFogf(GL_FOG_DENSITY, value); | ||
|  | 		glCheckErrors(); | ||
|  | 		break; | ||
|  | 	default: | ||
|  | 		break; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // "vertex arrays" are not supported in OpenGL 1.x
 | ||
|  | // -> "glBindVertexArray" replaced with "glBindBuffer" and several calls to "gl[...]Pointer"
 | ||
|  | // -> see VertexBufferImpl::setVertexAttributes
 | ||
|  | void Graphics3::setVertexBuffers(VertexBuffer **vertexBuffers, int count) { | ||
|  | 	int offset = 0; | ||
|  | 	for (int i = 0; i < count; ++i) { | ||
|  | 		offset += vertexBuffers[i]->_set(offset); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setIndexBuffer(IndexBuffer &indexBuffer) { | ||
|  | 	indexBuffer._set(); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setTexture(TextureUnit unit, Texture *texture) { | ||
|  | 	texture->_set(unit); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setTextureAddressing(TextureUnit unit, TexDir dir, TextureAddressing addressing) { | ||
|  | 	glActiveTexture(GL_TEXTURE0 + unit.unit); | ||
|  | 	GLenum texDir; | ||
|  | 	switch (dir) { | ||
|  | 	case U: | ||
|  | 		texDir = GL_TEXTURE_WRAP_S; | ||
|  | 		break; | ||
|  | 	case V: | ||
|  | 		texDir = GL_TEXTURE_WRAP_T; | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	switch (addressing) { | ||
|  | 	case Clamp: | ||
|  | 		glTexParameteri(GL_TEXTURE_2D, texDir, GL_CLAMP_TO_EDGE); | ||
|  | 		break; | ||
|  | 	case Repeat: | ||
|  | 		glTexParameteri(GL_TEXTURE_2D, texDir, GL_REPEAT); | ||
|  | 		break; | ||
|  | 	case Border: | ||
|  | 		// unsupported
 | ||
|  | 		glTexParameteri(GL_TEXTURE_2D, texDir, GL_CLAMP_TO_EDGE); | ||
|  | 		break; | ||
|  | 	case Mirror: | ||
|  | 		// unsupported
 | ||
|  | 		glTexParameteri(GL_TEXTURE_2D, texDir, GL_REPEAT); | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	glCheckErrors(); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setTextureMagnificationFilter(TextureUnit texunit, TextureFilter filter) { | ||
|  | 	glActiveTexture(GL_TEXTURE0 + texunit.unit); | ||
|  | 	glCheckErrors(); | ||
|  | 	switch (filter) { | ||
|  | 	case PointFilter: | ||
|  | 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
|  | 		break; | ||
|  | 	case LinearFilter: | ||
|  | 	case AnisotropicFilter: | ||
|  | 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	glCheckErrors(); | ||
|  | } | ||
|  | 
 | ||
|  | namespace { | ||
|  | 	void setMinMipFilters(int unit) { | ||
|  | 		glActiveTexture(GL_TEXTURE0 + unit); | ||
|  | 		glCheckErrors(); | ||
|  | 		switch (minFilters[System::currentDevice()][unit]) { | ||
|  | 		case Graphics3::PointFilter: | ||
|  | 			switch (mipFilters[System::currentDevice()][unit]) { | ||
|  | 			case Graphics3::NoMipFilter: | ||
|  | 				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
|  | 				break; | ||
|  | 			case Graphics3::PointMipFilter: | ||
|  | 				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); | ||
|  | 				break; | ||
|  | 			case Graphics3::LinearMipFilter: | ||
|  | 				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); | ||
|  | 				break; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		case Graphics3::LinearFilter: | ||
|  | 		case Graphics3::AnisotropicFilter: | ||
|  | 			switch (mipFilters[System::currentDevice()][unit]) { | ||
|  | 			case Graphics3::NoMipFilter: | ||
|  | 				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
|  | 				break; | ||
|  | 			case Graphics3::PointMipFilter: | ||
|  | 				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); | ||
|  | 				break; | ||
|  | 			case Graphics3::LinearMipFilter: | ||
|  | 				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | ||
|  | 				break; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 		} | ||
|  | 		glCheckErrors(); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setTextureMinificationFilter(TextureUnit texunit, TextureFilter filter) { | ||
|  | 	minFilters[System::currentDevice()][texunit.unit] = filter; | ||
|  | 	setMinMipFilters(texunit.unit); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setTextureMipmapFilter(TextureUnit texunit, MipmapFilter filter) { | ||
|  | 	mipFilters[System::currentDevice()][texunit.unit] = filter; | ||
|  | 	setMinMipFilters(texunit.unit); | ||
|  | } | ||
|  | 
 | ||
|  | namespace { | ||
|  | 	GLenum convert(Graphics3::BlendingOperation operation) { | ||
|  | 		switch (operation) { | ||
|  | 		case Graphics3::BlendZero: | ||
|  | 			return GL_ZERO; | ||
|  | 		case Graphics3::BlendOne: | ||
|  | 			return GL_ONE; | ||
|  | 		case Graphics3::SourceAlpha: | ||
|  | 			return GL_SRC_ALPHA; | ||
|  | 		case Graphics3::DestinationAlpha: | ||
|  | 			return GL_DST_ALPHA; | ||
|  | 		case Graphics3::InverseSourceAlpha: | ||
|  | 			return GL_ONE_MINUS_SRC_ALPHA; | ||
|  | 		case Graphics3::InverseDestinationAlpha: | ||
|  | 			return GL_ONE_MINUS_DST_ALPHA; | ||
|  | 		case Graphics3::SourceColor: | ||
|  | 			return GL_SRC_COLOR; | ||
|  | 		case Graphics3::DestinationColor: | ||
|  | 			return GL_DST_COLOR; | ||
|  | 		case Graphics3::InverseSourceColor: | ||
|  | 			return GL_ONE_MINUS_SRC_COLOR; | ||
|  | 		case Graphics3::InverseDestinationColor: | ||
|  | 			return GL_ONE_MINUS_DST_COLOR; | ||
|  | 		default: | ||
|  | 			return GL_ONE; | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setTextureOperation(TextureOperation operation, TextureArgument arg1, TextureArgument arg2) { | ||
|  | 	// glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setBlendingMode(BlendingOperation source, BlendingOperation destination) { | ||
|  | 	glBlendFunc(convert(source), convert(destination)); | ||
|  | 	glCheckErrors(); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setRenderTarget(RenderTarget *texture, int num, int additionalTargets) { | ||
|  | 	if (num == 0) { | ||
|  | 		// TODO (DK) uneccessary?
 | ||
|  | 		// System::makeCurrent(texture->contextId);
 | ||
|  | 		glBindFramebuffer(GL_FRAMEBUFFER, texture->_framebuffer); | ||
|  | 		glCheckErrors(); | ||
|  | 		glViewport(0, 0, texture->width, texture->height); | ||
|  | 		_renderTargetWidth = texture->width; | ||
|  | 		_renderTargetHeight = texture->height; | ||
|  | 		renderToBackbuffer = false; | ||
|  | 		glCheckErrors(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (additionalTargets > 0) { | ||
|  | 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + num, GL_TEXTURE_2D, texture->_texture, 0); | ||
|  | 		if (num == additionalTargets) { | ||
|  | 			GLenum buffers[16]; | ||
|  | 			for (int i = 0; i <= additionalTargets; ++i) | ||
|  | 				buffers[i] = GL_COLOR_ATTACHMENT0 + i; | ||
|  | #if defined(KINC_OPENGL_ES) && defined(KINC_ANDROID) && KINC_ANDROID_API >= 18
 | ||
|  | 			((void (*)(GLsizei, GLenum *))glesDrawBuffers)(additionalTargets + 1, buffers); | ||
|  | #elif !defined(KINC_OPENGL_ES)
 | ||
|  | 			glDrawBuffers(additionalTargets + 1, buffers); | ||
|  | #endif
 | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::restoreRenderTarget() { | ||
|  | 	glBindFramebuffer(GL_FRAMEBUFFER, originalFramebuffer[System::currentDevice()]); | ||
|  | 	glCheckErrors(); | ||
|  | 	int w = System::windowWidth(System::currentDevice()); | ||
|  | 	int h = System::windowHeight(System::currentDevice()); | ||
|  | 	glViewport(0, 0, w, h); | ||
|  | 	_renderTargetWidth = w; | ||
|  | 	_renderTargetHeight = h; | ||
|  | 	renderToBackbuffer = true; | ||
|  | 	glCheckErrors(); | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::setLight(Light *light, int num) { | ||
|  | 	if (light) { | ||
|  | 		light->_set(num); | ||
|  | 	} | ||
|  | 	else { | ||
|  | 		glDisable(GL_LIGHT0 + num); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | bool Graphics3::renderTargetsInvertedY() { | ||
|  | 	return true; | ||
|  | } | ||
|  | 
 | ||
|  | bool Graphics3::nonPow2TexturesSupported() { | ||
|  | 	return true; | ||
|  | } | ||
|  | 
 | ||
|  | void Graphics3::flush() { | ||
|  | 	glFlush(); | ||
|  | 	glCheckErrors(); | ||
|  | } |