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();
 | 
						|
}
 |