[Scummvm-git-logs] scummvm master -> 7dbed4d4f644d425a344ad2ea960ff679f8f2481

aquadran noreply at scummvm.org
Thu Oct 31 14:28:54 UTC 2024


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
7dbed4d4f6 WINTERMUTE: Rearrange functions to match original code


Commit: 7dbed4d4f644d425a344ad2ea960ff679f8f2481
    https://github.com/scummvm/scummvm/commit/7dbed4d4f644d425a344ad2ea960ff679f8f2481
Author: Paweł Kołodziejski (aquadran at gmail.com)
Date: 2024-10-31T15:28:48+01:00

Commit Message:
WINTERMUTE: Rearrange functions to match original code

Changed paths:
    engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp
    engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
    engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h


diff --git a/engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp b/engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp
index fea1891f7f4..373229e2abd 100644
--- a/engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp
+++ b/engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp
@@ -44,382 +44,31 @@
 
 namespace Wintermute {
 
-BaseRenderer3D *makeOpenGL3DRenderer(BaseGame *inGame) {
-	return new BaseRenderOpenGL3D(inGame);
-}
-
-BaseRenderOpenGL3D::BaseRenderOpenGL3D(BaseGame *inGame) : BaseRenderer3D(inGame) {
-	setDefaultAmbientLightColor();
-
-	_lightPositions.resize(getMaxActiveLights());
-	_lightDirections.resize(getMaxActiveLights());
-}
-
-BaseRenderOpenGL3D::~BaseRenderOpenGL3D() {
-	_camera = nullptr;
-}
-
-void BaseRenderOpenGL3D::setSpriteBlendMode(Graphics::TSpriteBlendMode blendMode) {
-	switch (blendMode) {
-	case Graphics::BLEND_NORMAL:
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		break;
-
-	case Graphics::BLEND_ADDITIVE:
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
-		break;
-
-	case Graphics::BLEND_SUBTRACTIVE:
-		// wme3d takes the color value here
-		glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
-		break;
-
-	default:
-		warning("BaseRenderOpenGL3D::setSpriteBlendMode unsupported blend mode %i", blendMode);
-	}
-}
-
-void BaseRenderOpenGL3D::setAmbientLightRenderState() {
-	byte a = 0;
-	byte r = 0;
-	byte g = 0;
-	byte b = 0;
-
-	if (_ambientLightOverride) {
-		a = RGBCOLGetA(_ambientLightColor);
-		r = RGBCOLGetR(_ambientLightColor);
-		g = RGBCOLGetG(_ambientLightColor);
-		b = RGBCOLGetB(_ambientLightColor);
-	} else {
-		uint32 color = _gameRef->getAmbientLightColor();
-
-		a = RGBCOLGetA(color);
-		r = RGBCOLGetR(color);
-		g = RGBCOLGetG(color);
-		b = RGBCOLGetB(color);
-	}
-
-	float value[] = { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f };
-	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, value);
-}
-
-int BaseRenderOpenGL3D::getMaxActiveLights() {
-	GLint maxLightCount = 0;
-	glGetIntegerv(GL_MAX_LIGHTS, &maxLightCount);
-	return maxLightCount;
-}
-
-void BaseRenderOpenGL3D::lightEnable(int index, bool enable) {
-	if (enable)
-		glEnable(GL_LIGHT0 + index);
-	else
-		glDisable(GL_LIGHT0 + index);
-}
-
-void BaseRenderOpenGL3D::setLightParameters(int index, const DXVector3 &position, const DXVector3 &direction, const DXVector4 &diffuse, bool spotlight) {
-	float zero[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
-
-	glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, diffuse);
-	glLightfv(GL_LIGHT0 + index, GL_AMBIENT, zero);
-	glLightfv(GL_LIGHT0 + index, GL_SPECULAR, zero);
-
-	_lightPositions[index]._x = position._x;
-	_lightPositions[index]._y = position._y;
-	_lightPositions[index]._z = position._z;
-	_lightPositions[index]._w = 1.0f;
-
-	if (spotlight) {
-		_lightDirections[index] = direction;
-		glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction);
-
-		glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, 0.0f);
-		// WME sets the theta angle to 0.5 (radians) and (28.64789 degree) - inner cone
-		// WME sets the phi angle to 1.0 (radians) and (57.29578 degree) - outer cone
-		// inner cone - angle within which the spotlight has maximum intensity
-		// outer cone - angle at the edge of the spotlight's cone
-		// 0 <-> 28.64789 - maximum light intensity
-		// 28.64789 <-> 57.29578 - light fades smoothly to zero
-		// 57.29578 <-> 90 - there is no light
-		// The smooth transition between inner code and outer cone create soft spotlight
-		// There is no replacement for smooth transition in fixed OpenGL lights.
-		// So, inner cone angle is used instead for better visual match
-		glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, 0.5f * (180.0f / (float)M_PI));
-	} else {
-		glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, 180.0f);
-	}
-}
-
-void BaseRenderOpenGL3D::enableCulling() {
-	glFrontFace(GL_CW);
-	glEnable(GL_CULL_FACE);
-}
-
-void BaseRenderOpenGL3D::disableCulling() {
-	glDisable(GL_CULL_FACE);
-}
-
-bool BaseRenderOpenGL3D::enableShadows() {
-	warning("BaseRenderOpenGL3D::enableShadows not implemented yet");
-	return true;
-}
-
-bool BaseRenderOpenGL3D::disableShadows() {
-	warning("BaseRenderOpenGL3D::disableShadows not implemented yet");
-	return true;
-}
-
-void BaseRenderOpenGL3D::displayShadow(BaseObject *object, const DXVector3 *lightPos, bool lightPosRelative) {
-	BaseSurface *shadowImage;
-	if (object->_shadowImage) {
-		shadowImage = object->_shadowImage;
-	} else {
-		shadowImage = _gameRef->_shadowImage;
-	}
-
-	if (!shadowImage) {
-		return;
-	}
-
-
-	DXMatrix scale, trans, rot, finalm;
-	DXMatrixScaling(&scale, object->_shadowSize * object->_scale3D, 1.0f, object->_shadowSize * object->_scale3D);
-	DXMatrixRotationY(&rot, degToRad(object->_angle));
-	DXMatrixTranslation(&trans, object->_posVector._x, object->_posVector._y, object->_posVector._z);
-	DXMatrixMultiply(&finalm, &scale, &rot);
-	DXMatrixMultiply(&finalm, &finalm, &trans);
-	setWorldTransform(finalm);
-
-	glDepthMask(GL_FALSE);
-	glEnable(GL_TEXTURE_2D);
-	static_cast<BaseSurfaceOpenGL3D *>(shadowImage)->setTexture();
-
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
-	glVertexPointer(3, GL_FLOAT, sizeof(SimpleShadowVertex), &_simpleShadow[0].x);
-	glNormalPointer(GL_FLOAT, sizeof(SimpleShadowVertex), &_simpleShadow[0].nx);
-	glTexCoordPointer(2, GL_FLOAT, sizeof(SimpleShadowVertex), &_simpleShadow[0].u);
-
-	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
-	glDepthMask(GL_TRUE);
-}
-
-bool BaseRenderOpenGL3D::stencilSupported() {
-	// assume that we have a stencil buffer
-	return true;
-}
-
-BaseImage *BaseRenderOpenGL3D::takeScreenshot() {
-	BaseImage *screenshot = new BaseImage();
-	Graphics::Surface *surface = new Graphics::Surface();
-#ifdef SCUMM_BIG_ENDIAN
-	Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
-#else
-	Graphics::PixelFormat format(4, 8, 8, 8, 8, 0, 8, 16, 24);
-#endif
-	surface->create(_viewportRect.width(), _viewportRect.height(), format);
-
-	glReadPixels(_viewportRect.left, _viewportRect.height() - _viewportRect.bottom, _viewportRect.width(), _viewportRect.height(),
-	             GL_RGBA, GL_UNSIGNED_BYTE, surface->getPixels());
-	flipVertical(surface);
-	Graphics::Surface *converted = surface->convertTo(getPixelFormat());
-	screenshot->copyFrom(converted);
-	delete surface;
-	delete converted;
-	return screenshot;
-}
-
-void BaseRenderOpenGL3D::setWindowed(bool windowed) {
-	ConfMan.setBool("fullscreen", !windowed);
-	g_system->beginGFXTransaction();
-	g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !windowed);
-	g_system->endGFXTransaction();
-}
-
-void BaseRenderOpenGL3D::fadeToColor(byte r, byte g, byte b, byte a) {
-	setProjection2D();
-
-	const int vertexSize = 16;
-	byte vertices[4 * vertexSize];
-	float *vertexCoords = reinterpret_cast<float *>(vertices);
-
-	vertexCoords[0 * 4 + 1] = _viewportRect.left;
-	vertexCoords[0 * 4 + 2] = _viewportRect.bottom;
-	vertexCoords[0 * 4 + 3] = 0.0f;
-	vertexCoords[1 * 4 + 1] = _viewportRect.left;
-	vertexCoords[1 * 4 + 2] = _viewportRect.top;
-	vertexCoords[1 * 4 + 3] = 0.0f;
-	vertexCoords[2 * 4 + 1] = _viewportRect.right;
-	vertexCoords[2 * 4 + 2] = _viewportRect.bottom;
-	vertexCoords[2 * 4 + 3] = 0.0f;
-	vertexCoords[3 * 4 + 1] = _viewportRect.right;
-	vertexCoords[3 * 4 + 2] = _viewportRect.top;
-	vertexCoords[3 * 4 + 3] = 0.0f;
-
-	vertices[0 * vertexSize + 0] = r;
-	vertices[0 * vertexSize + 1] = g;
-	vertices[0 * vertexSize + 2] = b;
-	vertices[0 * vertexSize + 3] = a;
-	vertices[1 * vertexSize + 0] = r;
-	vertices[1 * vertexSize + 1] = g;
-	vertices[1 * vertexSize + 2] = b;
-	vertices[1 * vertexSize + 3] = a;
-	vertices[2 * vertexSize + 0] = r;
-	vertices[2 * vertexSize + 1] = g;
-	vertices[2 * vertexSize + 2] = b;
-	vertices[2 * vertexSize + 3] = a;
-	vertices[3 * vertexSize + 0] = r;
-	vertices[3 * vertexSize + 1] = g;
-	vertices[3 * vertexSize + 2] = b;
-	vertices[3 * vertexSize + 3] = a;
-
-	glDisable(GL_DEPTH_TEST);
-	glEnable(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	glBindTexture(GL_TEXTURE_2D, 0);
-	glDisable(GL_TEXTURE_2D);
-
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-
-	glVertexPointer(3, GL_FLOAT, vertexSize, vertices + 4);
-	glColorPointer(4, GL_UNSIGNED_BYTE, vertexSize, vertices);
-
-	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-
-	setup2D(true);
-}
-
-bool BaseRenderOpenGL3D::fill(byte r, byte g, byte b, Common::Rect *rect) {
-	glClearColor(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-	return true;
-}
-
-bool BaseRenderOpenGL3D::setViewport(int left, int top, int right, int bottom) {
-	_viewportRect.setRect(left, top, right, bottom);
-	_viewport._x = left;
-	_viewport._y = top;
-	_viewport._width = right - left;
-	_viewport._height = bottom - top;
-	_viewport._minZ = 0.0f;
-	_viewport._maxZ = 1.0f;
-	glViewport(left, _height - bottom, right - left, bottom - top);
-	glDepthRange(_viewport._minZ, _viewport._maxZ);
-	return true;
-}
-
-bool BaseRenderOpenGL3D::setViewport3D(DXViewport *viewport) {
-	_viewport = *viewport;
-	glViewport(_viewport._x, _height - _viewport._height, _viewport._width, _viewport._height);
-	glDepthRange(_viewport._minZ, _viewport._maxZ);
-	return true;
-}
-
-bool BaseRenderOpenGL3D::drawLine(int x1, int y1, int x2, int y2, uint32 color) {
-	byte a = RGBCOLGetA(color);
-	byte r = RGBCOLGetR(color);
-	byte g = RGBCOLGetG(color);
-	byte b = RGBCOLGetB(color);
-
-	glBegin(GL_LINES);
-		glColor4ub(r, g, b, a);
-		glVertex3f(x1, _height - y1, 0.9f);
-		glVertex3f(x2, _height - y2, 0.9f);
-	glEnd();
-
-	return true;
-}
-
-bool BaseRenderOpenGL3D::setProjection() {
-	DXMatrix matProj;
-
-	float resWidth, resHeight;
-	float layerWidth, layerHeight;
-	float modWidth, modHeight;
-	bool customViewport;
-	getProjectionParams(&resWidth, &resHeight, &layerWidth, &layerHeight, &modWidth, &modHeight, &customViewport);
-
-	Rect32 rc;
-	_gameRef->getCurrentViewportRect(&rc);
-	float viewportWidth = (float)rc.right - (float)rc.left;
-	float viewportHeight = (float)rc.bottom - (float)rc.top;
-
-	// margins
-	int mleft = rc.left;
-	int mright = resWidth - viewportWidth - rc.left;
-	int mtop = rc.top;
-	int mbottom = resHeight - viewportHeight - rc.top;
-
-	DXMatrixPerspectiveFovLH(&matProj, _fov, viewportWidth / viewportHeight, _nearClipPlane, _farClipPlane);
-
-	float scaleMod = resHeight / viewportHeight;
-	float scaleRatio = MAX(layerWidth / resWidth, layerHeight / resHeight) /** 1.05*/;
-
-	float offsetX = (float)_gameRef->_offsetX;
-	float offsetY = (float)_gameRef->_offsetY;
-
-	if (!customViewport) {
-		offsetX -= _drawOffsetX;
-		offsetY -= _drawOffsetY;
-	}
-
-	matProj.matrix._11 *= scaleRatio * scaleMod;
-	matProj.matrix._22 *= scaleRatio * scaleMod;
-	matProj.matrix._31 = -(offsetX + (mleft - mright) / 2 - modWidth) / viewportWidth * 2.0f;
-	matProj.matrix._32 =  (offsetY + (mtop - mbottom) / 2 - modHeight) / viewportHeight * 2.0f;
-
-	return setProjectionTransform(matProj);
-}
-
-bool BaseRenderOpenGL3D::setProjection2D() {
-	glMatrixMode(GL_PROJECTION);
-	glLoadIdentity();
-	glOrtho(0, _width, 0, _height, -1.0, 100.0);
-	glMatrixMode(GL_MODELVIEW);
-	glLoadIdentity();
-	return true;
-}
-
-bool BaseRenderOpenGL3D::setWorldTransform(const DXMatrix &transform) {
-	_worldMatrix = transform;
-	DXMatrix newModelViewTransform, world = transform;
-	DXMatrixMultiply(&newModelViewTransform, &world, &_viewMatrix);
-	glMatrixMode(GL_MODELVIEW);
-	glLoadMatrixf(newModelViewTransform);
-	return true;
-}
-
-bool BaseRenderOpenGL3D::setViewTransform(const DXMatrix &transform) {
-	_viewMatrix = transform;
-	glMatrixMode(GL_MODELVIEW);
-	glLoadMatrixf(transform);
-	return true;
-}
+struct SpriteVertex {
+	float u;
+	float v;
+	float x;
+	float y;
+	float z;
+	uint8 r;
+	uint8 g;
+	uint8 b;
+	uint8 a;
+};
 
-bool BaseRenderOpenGL3D::setProjectionTransform(const DXMatrix &transform) {
-	_projectionMatrix = transform;
-	glMatrixMode(GL_PROJECTION);
-	glLoadMatrixf(transform);
-	return true;
+BaseRenderer3D *makeOpenGL3DRenderer(BaseGame *inGame) {
+	return new BaseRenderOpenGL3D(inGame);
 }
 
-bool BaseRenderOpenGL3D::windowedBlt() {
-	flip();
-	return true;
+BaseRenderOpenGL3D::BaseRenderOpenGL3D(BaseGame *inGame) : BaseRenderer3D(inGame) {
+	setDefaultAmbientLightColor();
+
+	_lightPositions.resize(getMaxActiveLights());
+	_lightDirections.resize(getMaxActiveLights());
 }
 
-void Wintermute::BaseRenderOpenGL3D::onWindowChange() {
-	_windowed = !g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
+BaseRenderOpenGL3D::~BaseRenderOpenGL3D() {
+	_camera = nullptr;
 }
 
 bool BaseRenderOpenGL3D::initRenderer(int width, int height, bool windowed) {
@@ -477,18 +126,18 @@ bool BaseRenderOpenGL3D::initRenderer(int width, int height, bool windowed) {
 	return true;
 }
 
-bool Wintermute::BaseRenderOpenGL3D::flip() {
-	g_system->updateScreen();
-	return true;
+void Wintermute::BaseRenderOpenGL3D::onWindowChange() {
+	_windowed = !g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
 }
 
-bool BaseRenderOpenGL3D::indicatorFlip() {
-	flip();
+bool Wintermute::BaseRenderOpenGL3D::flip() {
+	g_system->updateScreen();
 	return true;
 }
 
-bool BaseRenderOpenGL3D::forcedFlip() {
-	flip();
+bool BaseRenderOpenGL3D::fill(byte r, byte g, byte b, Common::Rect *rect) {
+	glClearColor(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 	return true;
 }
 
@@ -626,6 +275,30 @@ bool BaseRenderOpenGL3D::setup3D(Camera3D *camera, bool force) {
 	return true;
 }
 
+void BaseRenderOpenGL3D::setAmbientLightRenderState() {
+	byte a = 0;
+	byte r = 0;
+	byte g = 0;
+	byte b = 0;
+
+	if (_ambientLightOverride) {
+		a = RGBCOLGetA(_ambientLightColor);
+		r = RGBCOLGetR(_ambientLightColor);
+		g = RGBCOLGetG(_ambientLightColor);
+		b = RGBCOLGetB(_ambientLightColor);
+	} else {
+		uint32 color = _gameRef->getAmbientLightColor();
+
+		a = RGBCOLGetA(color);
+		r = RGBCOLGetR(color);
+		g = RGBCOLGetG(color);
+		b = RGBCOLGetB(color);
+	}
+
+	float value[] = { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f };
+	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, value);
+}
+
 bool BaseRenderOpenGL3D::setupLines() {
 	if (_state != RSTATE_LINES) {
 		_state = RSTATE_LINES;
@@ -641,26 +314,10 @@ bool BaseRenderOpenGL3D::setupLines() {
 	return true;
 }
 
-BaseSurface *Wintermute::BaseRenderOpenGL3D::createSurface() {
-	return new BaseSurfaceOpenGL3D(_gameRef, this);
-}
-
-struct SpriteVertex {
-	float u;
-	float v;
-	float x;
-	float y;
-	float z;
-	uint8 r;
-	uint8 g;
-	uint8 b;
-	uint8 a;
-};
-
 bool BaseRenderOpenGL3D::drawSpriteEx(BaseSurfaceOpenGL3D &tex, const Wintermute::Rect32 &rect,
-	                              const Wintermute::Vector2 &pos, const Wintermute::Vector2 &rot, const Wintermute::Vector2 &scale,
-	                              float angle, uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode,
-	                              bool mirrorX, bool mirrorY) {
+								  const Wintermute::Vector2 &pos, const Wintermute::Vector2 &rot, const Wintermute::Vector2 &scale,
+								  float angle, uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode,
+								  bool mirrorX, bool mirrorY) {
 	// original wme has a batch mode for sprites, we ignore this for the moment
 
 	if (_forceAlphaColor != 0) {
@@ -709,84 +366,348 @@ bool BaseRenderOpenGL3D::drawSpriteEx(BaseSurfaceOpenGL3D &tex, const Wintermute
 	vertices[2].u = texRight;
 	vertices[2].v = texTop;
 
-	vertices[3].u = texRight;
-	vertices[3].v = texBottom;
+	vertices[3].u = texRight;
+	vertices[3].v = texBottom;
+
+	// position coords
+	vertices[0].x = pos.x;
+	vertices[0].y = correctedYPos;
+	vertices[0].z = -0.9f;
+
+	vertices[1].x = pos.x;
+	vertices[1].y = correctedYPos - height;
+	vertices[1].z = -0.9f;
+
+	vertices[2].x = pos.x + width;
+	vertices[2].y = correctedYPos;
+	vertices[2].z = -0.9f;
+
+	vertices[3].x = pos.x + width;
+	vertices[3].y = correctedYPos - height;
+	vertices[3].z = -0.9f;
+
+	// not exactly sure about the color format, but this seems to work
+	byte a = RGBCOLGetA(color);
+	byte r = RGBCOLGetR(color);
+	byte g = RGBCOLGetG(color);
+	byte b = RGBCOLGetB(color);
+
+	for (int i = 0; i < 4; ++i) {
+		vertices[i].r = r;
+		vertices[i].g = g;
+		vertices[i].b = b;
+		vertices[i].a = a;
+	}
+
+	if (angle != 0) {
+		Vector2 correctedRot(rot.x, (rot.y - offset) * -1.0f + offset);
+		Math::Matrix3 transform = build2dTransformation(correctedRot, angle);
+
+		for (int i = 0; i < 4; ++i) {
+			Math::Vector3d vertexPostion(vertices[i].x, vertices[i].y, 1.0f);
+			transform.transformVector(&vertexPostion);
+
+			vertices[i].x = vertexPostion.x();
+			vertices[i].y = vertexPostion.y();
+		}
+	}
+
+	if (alphaDisable) {
+		glDisable(GL_ALPHA_TEST);
+	}
+
+	setSpriteBlendMode(blendMode);
+
+	glEnable(GL_TEXTURE_2D);
+
+	glEnableClientState(GL_COLOR_ARRAY);
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glDisableClientState(GL_NORMAL_ARRAY);
+
+	glVertexPointer(3, GL_FLOAT, sizeof(SpriteVertex), &vertices[0].x);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(SpriteVertex), &vertices[0].u);
+	glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(SpriteVertex), &vertices[0].r);
+
+	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+	glDisableClientState(GL_COLOR_ARRAY);
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	if (alphaDisable) {
+		glEnable(GL_ALPHA_TEST);
+	}
+
+	return true;
+}
+
+bool BaseRenderOpenGL3D::setProjection() {
+	DXMatrix matProj;
+
+	float resWidth, resHeight;
+	float layerWidth, layerHeight;
+	float modWidth, modHeight;
+	bool customViewport;
+	getProjectionParams(&resWidth, &resHeight, &layerWidth, &layerHeight, &modWidth, &modHeight, &customViewport);
+
+	Rect32 rc;
+	_gameRef->getCurrentViewportRect(&rc);
+	float viewportWidth = (float)rc.right - (float)rc.left;
+	float viewportHeight = (float)rc.bottom - (float)rc.top;
+
+	// margins
+	int mleft = rc.left;
+	int mright = resWidth - viewportWidth - rc.left;
+	int mtop = rc.top;
+	int mbottom = resHeight - viewportHeight - rc.top;
+
+	DXMatrixPerspectiveFovLH(&matProj, _fov, viewportWidth / viewportHeight, _nearClipPlane, _farClipPlane);
+
+	float scaleMod = resHeight / viewportHeight;
+	float scaleRatio = MAX(layerWidth / resWidth, layerHeight / resHeight) /** 1.05*/;
+
+	float offsetX = (float)_gameRef->_offsetX;
+	float offsetY = (float)_gameRef->_offsetY;
+
+	if (!customViewport) {
+		offsetX -= _drawOffsetX;
+		offsetY -= _drawOffsetY;
+	}
+
+	matProj.matrix._11 *= scaleRatio * scaleMod;
+	matProj.matrix._22 *= scaleRatio * scaleMod;
+	matProj.matrix._31 = -(offsetX + (mleft - mright) / 2 - modWidth) / viewportWidth * 2.0f;
+	matProj.matrix._32 =  (offsetY + (mtop - mbottom) / 2 - modHeight) / viewportHeight * 2.0f;
+
+	return setProjectionTransform(matProj);
+}
+
+bool BaseRenderOpenGL3D::drawLine(int x1, int y1, int x2, int y2, uint32 color) {
+	byte a = RGBCOLGetA(color);
+	byte r = RGBCOLGetR(color);
+	byte g = RGBCOLGetG(color);
+	byte b = RGBCOLGetB(color);
+
+	glBegin(GL_LINES);
+		glColor4ub(r, g, b, a);
+		glVertex3f(x1, _height - y1, 0.9f);
+		glVertex3f(x2, _height - y2, 0.9f);
+	glEnd();
+
+	return true;
+}
+
+bool BaseRenderOpenGL3D::windowedBlt() {
+	flip();
+	return true;
+}
+
+void BaseRenderOpenGL3D::fadeToColor(byte r, byte g, byte b, byte a) {
+	setProjection2D();
+
+	const int vertexSize = 16;
+	byte vertices[4 * vertexSize];
+	float *vertexCoords = reinterpret_cast<float *>(vertices);
+
+	vertexCoords[0 * 4 + 1] = _viewportRect.left;
+	vertexCoords[0 * 4 + 2] = _viewportRect.bottom;
+	vertexCoords[0 * 4 + 3] = 0.0f;
+	vertexCoords[1 * 4 + 1] = _viewportRect.left;
+	vertexCoords[1 * 4 + 2] = _viewportRect.top;
+	vertexCoords[1 * 4 + 3] = 0.0f;
+	vertexCoords[2 * 4 + 1] = _viewportRect.right;
+	vertexCoords[2 * 4 + 2] = _viewportRect.bottom;
+	vertexCoords[2 * 4 + 3] = 0.0f;
+	vertexCoords[3 * 4 + 1] = _viewportRect.right;
+	vertexCoords[3 * 4 + 2] = _viewportRect.top;
+	vertexCoords[3 * 4 + 3] = 0.0f;
+
+	vertices[0 * vertexSize + 0] = r;
+	vertices[0 * vertexSize + 1] = g;
+	vertices[0 * vertexSize + 2] = b;
+	vertices[0 * vertexSize + 3] = a;
+	vertices[1 * vertexSize + 0] = r;
+	vertices[1 * vertexSize + 1] = g;
+	vertices[1 * vertexSize + 2] = b;
+	vertices[1 * vertexSize + 3] = a;
+	vertices[2 * vertexSize + 0] = r;
+	vertices[2 * vertexSize + 1] = g;
+	vertices[2 * vertexSize + 2] = b;
+	vertices[2 * vertexSize + 3] = a;
+	vertices[3 * vertexSize + 0] = r;
+	vertices[3 * vertexSize + 1] = g;
+	vertices[3 * vertexSize + 2] = b;
+	vertices[3 * vertexSize + 3] = a;
+
+	glDisable(GL_DEPTH_TEST);
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glDisable(GL_TEXTURE_2D);
+
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_COLOR_ARRAY);
 
-	// position coords
-	vertices[0].x = pos.x;
-	vertices[0].y = correctedYPos;
-	vertices[0].z = -0.9f;
+	glVertexPointer(3, GL_FLOAT, vertexSize, vertices + 4);
+	glColorPointer(4, GL_UNSIGNED_BYTE, vertexSize, vertices);
 
-	vertices[1].x = pos.x;
-	vertices[1].y = correctedYPos - height;
-	vertices[1].z = -0.9f;
+	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
-	vertices[2].x = pos.x + width;
-	vertices[2].y = correctedYPos;
-	vertices[2].z = -0.9f;
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_COLOR_ARRAY);
 
-	vertices[3].x = pos.x + width;
-	vertices[3].y = correctedYPos - height;
-	vertices[3].z = -0.9f;
+	setup2D(true);
+}
 
-	// not exactly sure about the color format, but this seems to work
-	byte a = RGBCOLGetA(color);
-	byte r = RGBCOLGetR(color);
-	byte g = RGBCOLGetG(color);
-	byte b = RGBCOLGetB(color);
+BaseImage *BaseRenderOpenGL3D::takeScreenshot() {
+	BaseImage *screenshot = new BaseImage();
+	Graphics::Surface *surface = new Graphics::Surface();
+#ifdef SCUMM_BIG_ENDIAN
+	Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
+#else
+	Graphics::PixelFormat format(4, 8, 8, 8, 8, 0, 8, 16, 24);
+#endif
+	surface->create(_viewportRect.width(), _viewportRect.height(), format);
 
-	for (int i = 0; i < 4; ++i) {
-		vertices[i].r = r;
-		vertices[i].g = g;
-		vertices[i].b = b;
-		vertices[i].a = a;
-	}
+	glReadPixels(_viewportRect.left, _viewportRect.height() - _viewportRect.bottom, _viewportRect.width(), _viewportRect.height(),
+				 GL_RGBA, GL_UNSIGNED_BYTE, surface->getPixels());
+	flipVertical(surface);
+	Graphics::Surface *converted = surface->convertTo(getPixelFormat());
+	screenshot->copyFrom(converted);
+	delete surface;
+	delete converted;
+	return screenshot;
+}
 
-	if (angle != 0) {
-		Vector2 correctedRot(rot.x, (rot.y - offset) * -1.0f + offset);
-		Math::Matrix3 transform = build2dTransformation(correctedRot, angle);
+bool BaseRenderOpenGL3D::enableShadows() {
+	warning("BaseRenderOpenGL3D::enableShadows not implemented yet");
+	return true;
+}
 
-		for (int i = 0; i < 4; ++i) {
-			Math::Vector3d vertexPostion(vertices[i].x, vertices[i].y, 1.0f);
-			transform.transformVector(&vertexPostion);
+bool BaseRenderOpenGL3D::disableShadows() {
+	warning("BaseRenderOpenGL3D::disableShadows not implemented yet");
+	return true;
+}
 
-			vertices[i].x = vertexPostion.x();
-			vertices[i].y = vertexPostion.y();
-		}
+void BaseRenderOpenGL3D::displayShadow(BaseObject *object, const DXVector3 *lightPos, bool lightPosRelative) {
+	BaseSurface *shadowImage;
+	if (object->_shadowImage) {
+		shadowImage = object->_shadowImage;
+	} else {
+		shadowImage = _gameRef->_shadowImage;
 	}
 
-	if (alphaDisable) {
-		glDisable(GL_ALPHA_TEST);
+	if (!shadowImage) {
+		return;
 	}
 
-	setSpriteBlendMode(blendMode);
 
+	DXMatrix scale, trans, rot, finalm;
+	DXMatrixScaling(&scale, object->_shadowSize * object->_scale3D, 1.0f, object->_shadowSize * object->_scale3D);
+	DXMatrixRotationY(&rot, degToRad(object->_angle));
+	DXMatrixTranslation(&trans, object->_posVector._x, object->_posVector._y, object->_posVector._z);
+	DXMatrixMultiply(&finalm, &scale, &rot);
+	DXMatrixMultiply(&finalm, &finalm, &trans);
+	setWorldTransform(finalm);
+
+	glDepthMask(GL_FALSE);
 	glEnable(GL_TEXTURE_2D);
+	static_cast<BaseSurfaceOpenGL3D *>(shadowImage)->setTexture();
 
-	glEnableClientState(GL_COLOR_ARRAY);
 	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_NORMAL_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
 
-	glVertexPointer(3, GL_FLOAT, sizeof(SpriteVertex), &vertices[0].x);
-	glTexCoordPointer(2, GL_FLOAT, sizeof(SpriteVertex), &vertices[0].u);
-	glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(SpriteVertex), &vertices[0].r);
+	glVertexPointer(3, GL_FLOAT, sizeof(SimpleShadowVertex), &_simpleShadow[0].x);
+	glNormalPointer(GL_FLOAT, sizeof(SimpleShadowVertex), &_simpleShadow[0].nx);
+	glTexCoordPointer(2, GL_FLOAT, sizeof(SimpleShadowVertex), &_simpleShadow[0].u);
 
 	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
-	glDisableClientState(GL_COLOR_ARRAY);
 	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_NORMAL_ARRAY);
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
-	if (alphaDisable) {
-		glEnable(GL_ALPHA_TEST);
+	glDepthMask(GL_TRUE);
+}
+
+void BaseRenderOpenGL3D::setSpriteBlendMode(Graphics::TSpriteBlendMode blendMode) {
+	switch (blendMode) {
+	case Graphics::BLEND_NORMAL:
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		break;
+
+	case Graphics::BLEND_ADDITIVE:
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+		break;
+
+	case Graphics::BLEND_SUBTRACTIVE:
+		// wme3d takes the color value here
+		glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+		break;
+
+	default:
+		warning("BaseRenderOpenGL3D::setSpriteBlendMode unsupported blend mode %i", blendMode);
 	}
+}
 
+bool BaseRenderOpenGL3D::stencilSupported() {
+	// assume that we have a stencil buffer
 	return true;
 }
 
+int BaseRenderOpenGL3D::getMaxActiveLights() {
+	GLint maxLightCount = 0;
+	glGetIntegerv(GL_MAX_LIGHTS, &maxLightCount);
+	return maxLightCount;
+}
+
+// implements D3D LightEnable()
+void BaseRenderOpenGL3D::lightEnable(int index, bool enable) {
+	if (enable)
+		glEnable(GL_LIGHT0 + index);
+	else
+		glDisable(GL_LIGHT0 + index);
+}
+
+// backend layer 3DLight::SetLight
+void BaseRenderOpenGL3D::setLightParameters(int index, const DXVector3 &position, const DXVector3 &direction, const DXVector4 &diffuse, bool spotlight) {
+	float zero[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+
+	glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, diffuse);
+	glLightfv(GL_LIGHT0 + index, GL_AMBIENT, zero);
+	glLightfv(GL_LIGHT0 + index, GL_SPECULAR, zero);
+
+	_lightPositions[index]._x = position._x;
+	_lightPositions[index]._y = position._y;
+	_lightPositions[index]._z = position._z;
+	_lightPositions[index]._w = 1.0f;
+
+	if (spotlight) {
+		_lightDirections[index] = direction;
+		glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction);
+
+		glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, 0.0f);
+		// WME sets the theta angle to 0.5 (radians) and (28.64789 degree) - inner cone
+		// WME sets the phi angle to 1.0 (radians) and (57.29578 degree) - outer cone
+		// inner cone - angle within which the spotlight has maximum intensity
+		// outer cone - angle at the edge of the spotlight's cone
+		// 0 <-> 28.64789 - maximum light intensity
+		// 28.64789 <-> 57.29578 - light fades smoothly to zero
+		// 57.29578 <-> 90 - there is no light
+		// The smooth transition between inner code and outer cone create soft spotlight
+		// There is no replacement for smooth transition in fixed OpenGL lights.
+		// So, inner cone angle is used instead for better visual match
+		glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, 0.5f * (180.0f / (float)M_PI));
+	} else {
+		glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, 180.0f);
+	}
+}
+
+// backend layer AdSceneGeometry::Render
 void BaseRenderOpenGL3D::renderSceneGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks,
-	                                     const BaseArray<AdGeneric *> &generics, const BaseArray<Light3D *> &lights, Camera3D *camera) {
+										 const BaseArray<AdGeneric *> &generics, const BaseArray<Light3D *> &lights, Camera3D *camera) {
 	DXMatrix matIdentity;
 	DXMatrixIdentity(&matIdentity);
 
@@ -857,9 +778,10 @@ void BaseRenderOpenGL3D::renderSceneGeometry(const BaseArray<AdWalkplane *> &pla
 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 }
 
+// backend layer 3DShadowVolume::Render()
 void BaseRenderOpenGL3D::renderShadowGeometry(const BaseArray<AdWalkplane *> &planes,
-                                              const BaseArray<AdBlock *> &blocks,
-                                              const BaseArray<AdGeneric *> &generics, Camera3D *camera) {
+											  const BaseArray<AdBlock *> &blocks,
+											  const BaseArray<AdGeneric *> &generics, Camera3D *camera) {
 	DXMatrix matIdentity;
 	DXMatrixIdentity(&matIdentity);
 
@@ -899,6 +821,95 @@ void BaseRenderOpenGL3D::renderShadowGeometry(const BaseArray<AdWalkplane *> &pl
 	setSpriteBlendMode(Graphics::BLEND_NORMAL);
 }
 
+// implements D3D SetRenderState() D3DRS_CULLMODE - CCW
+void BaseRenderOpenGL3D::enableCulling() {
+	glFrontFace(GL_CW);
+	glEnable(GL_CULL_FACE);
+}
+
+// implements D3D SetRenderState() D3DRS_CULLMODE - NONE
+void BaseRenderOpenGL3D::disableCulling() {
+	glDisable(GL_CULL_FACE);
+}
+
+void BaseRenderOpenGL3D::setWindowed(bool windowed) {
+	ConfMan.setBool("fullscreen", !windowed);
+	g_system->beginGFXTransaction();
+	g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !windowed);
+	g_system->endGFXTransaction();
+}
+
+// implements D3D SetViewport() for 2D viewport
+bool BaseRenderOpenGL3D::setViewport(int left, int top, int right, int bottom) {
+	_viewportRect.setRect(left, top, right, bottom);
+	_viewport._x = left;
+	_viewport._y = top;
+	_viewport._width = right - left;
+	_viewport._height = bottom - top;
+	_viewport._minZ = 0.0f;
+	_viewport._maxZ = 1.0f;
+	glViewport(left, _height - bottom, right - left, bottom - top);
+	glDepthRange(_viewport._minZ, _viewport._maxZ);
+	return true;
+}
+
+// implements D3D SetViewport() for 3D viewport
+bool BaseRenderOpenGL3D::setViewport3D(DXViewport *viewport) {
+	_viewport = *viewport;
+	glViewport(_viewport._x, _height - _viewport._height, _viewport._width, _viewport._height);
+	glDepthRange(_viewport._minZ, _viewport._maxZ);
+	return true;
+}
+
+bool BaseRenderOpenGL3D::setProjection2D() {
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+	glOrtho(0, _width, 0, _height, -1.0, 100.0);
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+	return true;
+}
+
+// implements SetTransform() D3DTS_WORLD
+bool BaseRenderOpenGL3D::setWorldTransform(const DXMatrix &transform) {
+	_worldMatrix = transform;
+	DXMatrix newModelViewTransform, world = transform;
+	DXMatrixMultiply(&newModelViewTransform, &world, &_viewMatrix);
+	glMatrixMode(GL_MODELVIEW);
+	glLoadMatrixf(newModelViewTransform);
+	return true;
+}
+
+// implements SetTransform() D3DTS_WIEW
+bool BaseRenderOpenGL3D::setViewTransform(const DXMatrix &transform) {
+	_viewMatrix = transform;
+	glMatrixMode(GL_MODELVIEW);
+	glLoadMatrixf(transform);
+	return true;
+}
+
+// implements SetTransform() D3DTS_PROJECTION
+bool BaseRenderOpenGL3D::setProjectionTransform(const DXMatrix &transform) {
+	_projectionMatrix = transform;
+	glMatrixMode(GL_PROJECTION);
+	glLoadMatrixf(transform);
+	return true;
+}
+
+bool BaseRenderOpenGL3D::indicatorFlip() {
+	flip();
+	return true;
+}
+
+bool BaseRenderOpenGL3D::forcedFlip() {
+	flip();
+	return true;
+}
+
+BaseSurface *Wintermute::BaseRenderOpenGL3D::createSurface() {
+	return new BaseSurfaceOpenGL3D(_gameRef, this);
+}
+
 Mesh3DS *BaseRenderOpenGL3D::createMesh3DS() {
 	return new Mesh3DSOpenGL(_gameRef);
 }
@@ -911,6 +922,8 @@ ShadowVolume *BaseRenderOpenGL3D::createShadowVolume() {
 	return new ShadowVolumeOpenGL(_gameRef);
 }
 
+// ScummVM specific ends <--
+
 } // namespace Wintermute
 
 #endif // defined(USE_OPENGL_GAME)
diff --git a/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp b/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
index d3cd3917b83..4efc5edb45e 100644
--- a/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
+++ b/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
@@ -42,10 +42,6 @@
 
 namespace Wintermute {
 
-BaseRenderer3D *makeOpenGL3DShaderRenderer(BaseGame *inGame) {
-	return new BaseRenderOpenGL3DShader(inGame);
-}
-
 struct SpriteVertexShader {
 	float x;
 	float y;
@@ -57,6 +53,10 @@ struct SpriteVertexShader {
 	float a;
 };
 
+BaseRenderer3D *makeOpenGL3DShaderRenderer(BaseGame *inGame) {
+	return new BaseRenderOpenGL3DShader(inGame);
+}
+
 BaseRenderOpenGL3DShader::BaseRenderOpenGL3DShader(BaseGame *inGame) : BaseRenderer3D(inGame) {
 	_flatShadowMaskShader = nullptr;
 }
@@ -70,396 +70,344 @@ BaseRenderOpenGL3DShader::~BaseRenderOpenGL3DShader() {
 	glDeleteFramebuffers(1, &_flatShadowFrameBuffer);
 }
 
-void BaseRenderOpenGL3DShader::setSpriteBlendMode(Graphics::TSpriteBlendMode blendMode) {
-	switch (blendMode) {
-	case Graphics::BLEND_NORMAL:
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		break;
-
-	case Graphics::BLEND_ADDITIVE:
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
-		break;
-
-	case Graphics::BLEND_SUBTRACTIVE:
-		// wme3d takes the color value here
-		glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
-		break;
-
-	default:
-		warning("BaseRenderOpenGL3DShader::setSpriteBlendMode unsupported blend mode %i", blendMode);
-	}
-}
-
-void BaseRenderOpenGL3DShader::setAmbientLightRenderState() {
-	byte a = RGBCOLGetA(_ambientLightColor);
-	byte r = RGBCOLGetR(_ambientLightColor);
-	byte g = RGBCOLGetG(_ambientLightColor);
-	byte b = RGBCOLGetB(_ambientLightColor);
+bool BaseRenderOpenGL3DShader::initRenderer(int width, int height, bool windowed) {
+	glGenBuffers(1, &_spriteVBO);
+	glBindBuffer(GL_ARRAY_BUFFER, _spriteVBO);
+	glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(SpriteVertexShader), nullptr, GL_DYNAMIC_DRAW);
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
 
-	if (!_ambientLightOverride) {
-		uint32 color = _gameRef->getAmbientLightColor();
+	static const char *spriteAttributes[] = {"position", "texcoord", "color", nullptr};
+	_spriteShader = OpenGL::Shader::fromFiles("wme_sprite", spriteAttributes);
 
-		a = RGBCOLGetA(color);
-		r = RGBCOLGetR(color);
-		g = RGBCOLGetG(color);
-		b = RGBCOLGetB(color);
-	}
+	_spriteShader->enableVertexAttribute("position", _spriteVBO, 2, GL_FLOAT, false, sizeof(SpriteVertexShader), 0);
+	_spriteShader->enableVertexAttribute("texcoord", _spriteVBO, 2, GL_FLOAT, false, sizeof(SpriteVertexShader), 8);
+	_spriteShader->enableVertexAttribute("color", _spriteVBO, 4, GL_FLOAT, false, sizeof(SpriteVertexShader), 16);
 
-	Math::Vector4d value;
-	value.x() = r / 255.0f;
-	value.y() = g / 255.0f;
-	value.z() = b / 255.0f;
-	value.w() = a / 255.0f;
+	static const char *geometryAttributes[] = { "position", "color", nullptr };
+	_geometryShader = OpenGL::Shader::fromFiles("wme_geometry", geometryAttributes);
 
-	_xmodelShader->use();
-	_xmodelShader->setUniform("ambientLight", value);
-}
+	static const char *shadowVolumeAttributes[] = { "position", nullptr };
+	_shadowVolumeShader = OpenGL::Shader::fromFiles("wme_shadow_volume", shadowVolumeAttributes);
 
-int BaseRenderOpenGL3DShader::getMaxActiveLights() {
-	return 8;
-}
+	static const char *shadowMaskAttributes[] = { "position", nullptr };
+	_shadowMaskShader = OpenGL::Shader::fromFiles("wme_shadow_mask", shadowMaskAttributes);
 
-void BaseRenderOpenGL3DShader::lightEnable(int index, bool enable) {
-	_xmodelShader->use();
-	Common::String uniform = Common::String::format("lights[%i].enabled", index);
-	if (enable)
-		_xmodelShader->setUniform1f(uniform.c_str(), 1.0f);
-	else
-		_xmodelShader->setUniform1f(uniform.c_str(), -1.0f);
-}
+	DXMatrix m;
+	DXMatrixIdentity(&m);
+	_transformStack.push_back(m);
 
-void BaseRenderOpenGL3DShader::setLightParameters(int index, const DXVector3 &position,
-                                                  const DXVector3 &direction,
-                                                  const DXVector4 &diffuse, bool spotlight) {
-	Math::Vector4d position4d;
-	position4d.x() = position._x;
-	position4d.y() = position._y;
-	position4d.z() = position._z;
-	position4d.w() = 1.0f;
+	static const char *XModelAttributes[] = {"position", "texcoord", "normal", nullptr};
+	_xmodelShader = OpenGL::Shader::fromFiles("wme_modelx", XModelAttributes);
 
-	Math::Vector4d direction4d;
-	direction4d.x() = direction._x;
-	direction4d.y() = direction._y;
-	direction4d.z() = direction._z;
-	direction4d.w() = 0.0f;
+	setDefaultAmbientLightColor();
 
-	if (spotlight) {
-		direction4d.w() = -1.0f;
+	for (int i = 0; i < getMaxActiveLights(); ++i) {
+		setLightParameters(i, DXVector3(0, 0, 0), DXVector3(0, 0, 0), DXVector4(0, 0, 0, 0), false);
+		lightEnable(i, false);
 	}
 
-	Math::Vector4d diffuse4d;
-	diffuse4d.x() = diffuse._x;
-	diffuse4d.y() = diffuse._y;
-	diffuse4d.z() = diffuse._z;
-	diffuse4d.w() = 0.0f;
-
-
-	_xmodelShader->use();
-
-	Common::String uniform = Common::String::format("lights[%i]._position", index);
-	_xmodelShader->setUniform(uniform.c_str(), position4d);
-
-	uniform = Common::String::format("lights[%i]._direction", index);
-	_xmodelShader->setUniform(uniform.c_str(), direction4d);
-
-	uniform = Common::String::format("lights[%i]._color", index);
-	_xmodelShader->setUniform(uniform.c_str(), diffuse4d);
-}
+	_windowed = !ConfMan.getBool("fullscreen");
+	_width = width;
+	_height = height;
 
-void BaseRenderOpenGL3DShader::enableCulling() {
-	glFrontFace(GL_CW);
-	glEnable(GL_CULL_FACE);
-}
+	_nearClipPlane = 90.0f;
+	_farClipPlane = 10000.0f;
 
-void BaseRenderOpenGL3DShader::disableCulling() {
-	glDisable(GL_CULL_FACE);
-}
+	setViewport(0, 0, width, height);
 
-bool BaseRenderOpenGL3DShader::enableShadows() {
-	return true; // TODO: reimplement. Shadows are broken for a while since it use not allowed binding to frame buffer
-	if (_flatShadowMaskShader == nullptr) {
-		_flatShadowColor = Math::Vector4d(0.0f, 0.0f, 0.0f, 0.5f);
+	float fadeVertexCoords[8];
 
-		_shadowTextureWidth = 512;
-		_shadowTextureHeight = 512;
+	fadeVertexCoords[0 * 2 + 0] = _viewportRect.left;
+	fadeVertexCoords[0 * 2 + 1] = _viewportRect.bottom;
+	fadeVertexCoords[1 * 2 + 0] = _viewportRect.left;
+	fadeVertexCoords[1 * 2 + 1] = _viewportRect.top;
+	fadeVertexCoords[2 * 2 + 0] = _viewportRect.right;
+	fadeVertexCoords[2 * 2 + 1] = _viewportRect.bottom;
+	fadeVertexCoords[3 * 2 + 0] = _viewportRect.right;
+	fadeVertexCoords[3 * 2 + 1] = _viewportRect.top;
 
-		float nearPlane = 1.0f;
-		float farPlane = 10000.0f;
-		float fovy = static_cast<float>(M_PI / 4.0f);
+	glGenBuffers(1, &_fadeVBO);
+	glBindBuffer(GL_ARRAY_BUFFER, _fadeVBO);
+	glBufferData(GL_ARRAY_BUFFER, 4 * 8, fadeVertexCoords, GL_STATIC_DRAW);
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
 
-		float top = nearPlane *  tanf(fovy * 0.5f);
-		float bottom = -top;
-		float right = top;
-		float left = -right;
+	static const char *fadeAttributes[] = { "position", nullptr };
+	_fadeShader = OpenGL::Shader::fromFiles("wme_fade", fadeAttributes);
+	_fadeShader->enableVertexAttribute("position", _fadeVBO, 2, GL_FLOAT, false, 8, 0);
 
-		float deltaX = (-0.5f * (right - left)) / _shadowTextureWidth;
-		float deltaY = (0.5f * (top - bottom)) / _shadowTextureHeight;
+	glGenBuffers(1, &_lineVBO);
+	glBindBuffer(GL_ARRAY_BUFFER, _lineVBO);
+	glBufferData(GL_ARRAY_BUFFER, 2 * 8, nullptr, GL_DYNAMIC_DRAW);
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
 
-		Math::Matrix4 lightProjection = Math::makeFrustumMatrix(left + deltaX, right + deltaX, bottom + deltaY, top + deltaY, nearPlane, farPlane);
+	static const char *lineAttributes[] = { "position", nullptr };
+	_lineShader = OpenGL::Shader::fromFiles("wme_line", lineAttributes);
+	_lineShader->enableVertexAttribute("position", _lineVBO, 2, GL_FLOAT, false, 8, 0);
 
-		_flatShadowXModelShader->use();
-		_flatShadowXModelShader->setUniform("projMatrix", lightProjection);
+	static const char *flatShadowXModelAttributes[] = { "position", nullptr };
+	_flatShadowXModelShader = OpenGL::Shader::fromFiles("wme_flat_shadow_modelx", flatShadowXModelAttributes);
 
-		glGenTextures(1, &_flatShadowRenderTexture);
-		glBindTexture(GL_TEXTURE_2D, _flatShadowRenderTexture);
-		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _shadowTextureWidth, _shadowTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	_active = true;
 
-		glGenRenderbuffers(1, &_flatShadowDepthBuffer);
-		glBindRenderbuffer(GL_RENDERBUFFER, _flatShadowDepthBuffer);
-		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _shadowTextureWidth, _shadowTextureHeight);
+	setProjection();
 
-		glGenFramebuffers(1, &_flatShadowFrameBuffer);
-		glBindFramebuffer(GL_FRAMEBUFFER, _flatShadowFrameBuffer);
-		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _flatShadowRenderTexture, 0);
-		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _flatShadowDepthBuffer);
+	return true;
+}
 
-		glBindFramebuffer(GL_FRAMEBUFFER, 0);
+void Wintermute::BaseRenderOpenGL3DShader::onWindowChange() {
+	_windowed = !g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
+}
 
-		float flatShadowMaskVertices[12];
-		flatShadowMaskVertices[0] = -250.0f;
-		flatShadowMaskVertices[1] = 0.0f;
-		flatShadowMaskVertices[2] = -250.0f;
+bool Wintermute::BaseRenderOpenGL3DShader::flip() {
+	g_system->updateScreen();
+	return true;
+}
 
-		flatShadowMaskVertices[3] = -250.0f;
-		flatShadowMaskVertices[4] = 0.0f;
-		flatShadowMaskVertices[5] = 250.0f;
+bool BaseRenderOpenGL3DShader::fill(byte r, byte g, byte b, Common::Rect *rect) {
+	glClearColor(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+	return true;
+}
 
-		flatShadowMaskVertices[6] = 250.0f;
-		flatShadowMaskVertices[7] = 0.0f;
-		flatShadowMaskVertices[8] = -250.0f;
+bool BaseRenderOpenGL3DShader::setup2D(bool force) {
+	if (_state != RSTATE_2D || force) {
+		_state = RSTATE_2D;
 
-		flatShadowMaskVertices[9] = 250.0f;
-		flatShadowMaskVertices[10] = 0.0f;
-		flatShadowMaskVertices[11] = 250.0f;
+		// some states are still missing here
 
-		glGenBuffers(1, &_flatShadowMaskVBO);
-		glBindBuffer(GL_ARRAY_BUFFER, _flatShadowMaskVBO);
-		glBufferData(GL_ARRAY_BUFFER, 4 * 12, flatShadowMaskVertices, GL_STATIC_DRAW);
+		glDisable(GL_DEPTH_TEST);
+		glDisable(GL_STENCIL_TEST);
 
-		static const char *flatShadowMaskAttributes[] = { "position", nullptr };
-		_flatShadowMaskShader = OpenGL::Shader::fromFiles("wme_flat_shadow_mask", flatShadowMaskAttributes);
-		_flatShadowMaskShader->enableVertexAttribute("position", _flatShadowMaskVBO, 3, GL_FLOAT, false, 12, 0);
+		glEnable(GL_CULL_FACE);
+		glFrontFace(GL_CCW);
+		glEnable(GL_BLEND);
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
-		_flatShadowMaskShader->use();
-		_flatShadowMaskShader->setUniform("lightProjMatrix", lightProjection);
+		glViewport(0, 0, _width, _height);
 
-		_gameRef->_supportsRealTimeShadows = true;
+		setProjection2D();
 	}
 
 	return true;
 }
 
-bool BaseRenderOpenGL3DShader::disableShadows() {
-	warning("BaseRenderOpenGL3DShader::disableShadows not implemented yet");
-	return true;
-}
-
-void BaseRenderOpenGL3DShader::displayShadow(BaseObject *object, const DXVector3 *lightPos, bool lightPosRelative) {
-	return; // TODO: reimplement. Shadows are broken for a while since it use not allowed binding to frame buffer
-	if (_flatShadowMaskShader) {
-		if (object->_shadowType <= SHADOW_SIMPLE) {
-			// TODO: Display simple shadow here
-			return;
-		}
+bool BaseRenderOpenGL3DShader::setup3D(Camera3D *camera, bool force) {
+	if (_state != RSTATE_3D || force) {
+		_state = RSTATE_3D;
 
-		DXVector3 position = *lightPos;
+		glEnable(GL_DEPTH_TEST);
+		glEnable(GL_BLEND);
 
-		if (lightPosRelative) {
-			position = object->_posVector + *lightPos;
-		}
+		setAmbientLightRenderState();
 
-		DXMatrix lightView = DXMatrix(Math::makeLookAtMatrix(Math::Vector3d(position),
-																   Math::Vector3d(object->_posVector),
-																   Math::Vector3d(0.0f, 1.0f, 0.0f)).getData());
-		DXMatrix translation;
-		DXMatrixTranslation(&translation, -position._x, -position._y, -position._z);
-		DXMatrixTranspose(&translation, &translation);
-		DXMatrixMultiply(&lightView, &translation, &lightView);
+		if (camera)
+			_camera = camera;
+		if (_camera) {
+			DXMatrix viewMatrix;
+			_camera->getViewMatrix(&viewMatrix);
+			setViewTransform(viewMatrix);
 
-		Math::Matrix4 lightViewMatrix;
-		lightViewMatrix.setData(lightView);
-		_flatShadowXModelShader->use();
-		_flatShadowXModelShader->setUniform("viewMatrix", lightViewMatrix);
+			_fov = _camera->_fov;
 
-		Math::Matrix4 worldMatrix;
-		worldMatrix.setData(object->_worldMatrix);
-		worldMatrix.transpose();
-		_flatShadowXModelShader->setUniform("modelMatrix", worldMatrix);
+			if (_camera->_nearClipPlane >= 0.0f) {
+				_nearClipPlane = _camera->_nearClipPlane;
+			} else {
+				_nearClipPlane = DEFAULT_NEAR_PLANE;
+			}
 
-		byte a = RGBCOLGetA(object->_shadowColor);
-		byte r = RGBCOLGetR(object->_shadowColor);
-		byte g = RGBCOLGetG(object->_shadowColor);
-		byte b = RGBCOLGetB(object->_shadowColor);
+			if (_camera->_farClipPlane >= 0.0f) {
+				_farClipPlane = _camera->_farClipPlane;
+			} else {
+				_farClipPlane = DEFAULT_FAR_PLANE;
+			}
+		} else {
+			_nearClipPlane = DEFAULT_NEAR_PLANE;
+			_farClipPlane = DEFAULT_FAR_PLANE;
+		}
 
-		_flatShadowColor.x() = r / 255.0f;
-		_flatShadowColor.y() = g / 255.0f;
-		_flatShadowColor.z() = b / 255.0f;
-		_flatShadowColor.w() = a / 255.0f;
-		_flatShadowXModelShader->setUniform("shadowColor", _flatShadowColor);
+		bool fogEnabled;
+		uint32 fogColor;
+		float fogStart, fogEnd;
 
-		glBindFramebuffer(GL_FRAMEBUFFER, _flatShadowFrameBuffer);
+		_gameRef->getFogParams(&fogEnabled, &fogColor, &fogStart, &fogEnd);
+		if (fogEnabled) {
+			// TODO: Implement fog
+			GLfloat color[4];
+			color[0] = RGBCOLGetR(fogColor) / 255.0f;
+			color[1] = RGBCOLGetG(fogColor) / 255.0f;
+			color[2] = RGBCOLGetB(fogColor) / 255.0f;
+			color[3] = RGBCOLGetA(fogColor) / 255.0f;
+			debug(5, "BaseRenderOpenGL3DShader::setup3D fog not yet implemented! [%f %f %f %f]", color[0], color[1], color[2], color[3]);
+		} else {
+			// TODO: Disable fog in shader
+		}
 
-		GLint currentViewport[4];
-		glGetIntegerv(GL_VIEWPORT, currentViewport);
-		glViewport(1, 1, _shadowTextureWidth - 2, _shadowTextureHeight - 2);
+		glViewport(_viewportRect.left, _height - _viewportRect.bottom, _viewportRect.width(), _viewportRect.height());
 
-		glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
-		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+		setProjection();
+	}
 
-		object->_xmodel->renderFlatShadowModel();
+	Math::Matrix4 viewMatrix, projectionMatrix;
+	viewMatrix.setData(_viewMatrix);
+	projectionMatrix.setData(_projectionMatrix);
+	_xmodelShader->use();
+	_xmodelShader->setUniform("viewMatrix", viewMatrix);
+	_xmodelShader->setUniform("projMatrix", projectionMatrix);
+	// this is 8 / 255, since 8 is the value used by wme (as a DWORD)
+	_xmodelShader->setUniform1f("alphaRef", 0.031f);
 
-		glBindFramebuffer(GL_FRAMEBUFFER, 0);
+	_geometryShader->use();
+	_geometryShader->setUniform("viewMatrix", viewMatrix);
+	_geometryShader->setUniform("projMatrix", projectionMatrix);
 
-		glViewport(currentViewport[0], currentViewport[1], currentViewport[2], currentViewport[3]);
+	_shadowVolumeShader->use();
+	_shadowVolumeShader->setUniform("viewMatrix", viewMatrix);
+	_shadowVolumeShader->setUniform("projMatrix", projectionMatrix);
 
-		glDisable(GL_DEPTH_WRITEMASK);
+	return true;
+}
 
-		DXMatrix shadowPos;
-		DXMatrixTranslation(&shadowPos, object->_posVector._x, object->_posVector._y, object->_posVector._z);
-		DXMatrixTranspose(&shadowPos, &shadowPos);
+void BaseRenderOpenGL3DShader::setAmbientLightRenderState() {
+	byte a = RGBCOLGetA(_ambientLightColor);
+	byte r = RGBCOLGetR(_ambientLightColor);
+	byte g = RGBCOLGetG(_ambientLightColor);
+	byte b = RGBCOLGetB(_ambientLightColor);
 
-		Math::Matrix4 viewMatrix, projectionMatrix, shadowPosition;
-		viewMatrix.setData(_viewMatrix);
-		projectionMatrix.setData(_projectionMatrix);
-		shadowPosition.setData(shadowPos);
-		_flatShadowMaskShader->use();
-		_flatShadowMaskShader->setUniform("lightViewMatrix", lightViewMatrix);
-		_flatShadowMaskShader->setUniform("worldMatrix", shadowPosition);
-		_flatShadowMaskShader->setUniform("viewMatrix", viewMatrix);
-		_flatShadowMaskShader->setUniform("projMatrix", projectionMatrix);
-		_flatShadowMaskShader->setUniform("shadowColor", _flatShadowColor);
+	if (!_ambientLightOverride) {
+		uint32 color = _gameRef->getAmbientLightColor();
 
-		glBindBuffer(GL_ARRAY_BUFFER, _flatShadowMaskVBO);
-		glBindTexture(GL_TEXTURE_2D, _flatShadowRenderTexture);
+		a = RGBCOLGetA(color);
+		r = RGBCOLGetR(color);
+		g = RGBCOLGetG(color);
+		b = RGBCOLGetB(color);
+	}
 
-		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+	Math::Vector4d value;
+	value.x() = r / 255.0f;
+	value.y() = g / 255.0f;
+	value.z() = b / 255.0f;
+	value.w() = a / 255.0f;
 
-		glBindTexture(GL_TEXTURE_2D, 0);
+	_xmodelShader->use();
+	_xmodelShader->setUniform("ambientLight", value);
+}
 
-		glEnable(GL_DEPTH_WRITEMASK);
+bool BaseRenderOpenGL3DShader::setupLines() {
+	if (_state != RSTATE_LINES) {
+		_state = RSTATE_LINES;
+
+		glDisable(GL_DEPTH_TEST);
+		glEnable(GL_BLEND);
+		glBindTexture(GL_TEXTURE_2D, 0);
 	}
-}
 
-bool BaseRenderOpenGL3DShader::stencilSupported() {
-	// assume that we have a stencil buffer
 	return true;
 }
 
-BaseImage *BaseRenderOpenGL3DShader::takeScreenshot() {
-	BaseImage *screenshot = new BaseImage();
-	Graphics::Surface *surface = new Graphics::Surface();
-#ifdef SCUMM_BIG_ENDIAN
-	Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
-#else
-	Graphics::PixelFormat format(4, 8, 8, 8, 8, 0, 8, 16, 24);
-#endif
-	surface->create(_viewportRect.width(), _viewportRect.height(), format);
+bool BaseRenderOpenGL3DShader::drawSpriteEx(BaseSurfaceOpenGL3D &tex, const Wintermute::Rect32 &rect,
+										const Wintermute::Vector2 &pos, const Wintermute::Vector2 &rot,
+										const Wintermute::Vector2 &scale, float angle, uint32 color,
+										bool alphaDisable, Graphics::TSpriteBlendMode blendMode,
+										bool mirrorX, bool mirrorY) {
+	// original wme has a batch mode for sprites, we ignore this for the moment
 
-	glReadPixels(_viewportRect.left, _viewportRect.height() - _viewportRect.bottom, _viewportRect.width(), _viewportRect.height(),
-	             GL_RGBA, GL_UNSIGNED_BYTE, surface->getPixels());
-	flipVertical(surface);
-	Graphics::Surface *converted = surface->convertTo(getPixelFormat());
-	screenshot->copyFrom(converted);
-	delete surface;
-	delete converted;
-	return screenshot;
-}
+	if (_forceAlphaColor != 0) {
+		color = _forceAlphaColor;
+	}
 
-void BaseRenderOpenGL3DShader::setWindowed(bool windowed) {
-	ConfMan.setBool("fullscreen", !windowed);
-	g_system->beginGFXTransaction();
-	g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !windowed);
-	g_system->endGFXTransaction();
-}
+	float width = (rect.right - rect.left) * scale.x;
+	float height = (rect.bottom - rect.top) * scale.y;
 
-void BaseRenderOpenGL3DShader::fadeToColor(byte r, byte g, byte b, byte a) {
-	setProjection2D();
+	glBindTexture(GL_TEXTURE_2D, tex.getTextureName());
 
-	Math::Vector4d color;
-	color.x() = r / 255.0f;
-	color.y() = g / 255.0f;
-	color.z() = b / 255.0f;
-	color.w() = a / 255.0f;
+	// for sprites we clamp to the edge, to avoid line fragments at the edges
+	// this is not done by wme, though
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
-	glDisable(GL_DEPTH_TEST);
-	glEnable(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	glBindTexture(GL_TEXTURE_2D, 0);
-	glBindBuffer(GL_ARRAY_BUFFER, _fadeVBO);
+	int texWidth = tex.getGLTextureWidth();
+	int texHeight = tex.getGLTextureHeight();
 
-	Math::Matrix4 projectionMatrix2d;
-	projectionMatrix2d.setData(_projectionMatrix2d);
-	_fadeShader->use();
-	_fadeShader->setUniform("color", color);
-	_fadeShader->setUniform("projMatrix", projectionMatrix2d);
+	float texLeft = (float)rect.left / (float)texWidth;
+	float texTop = (float)rect.top / (float)texHeight;
+	float texRight = (float)rect.right / (float)texWidth;
+	float texBottom = (float)rect.bottom / (float)texHeight;
 
-	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+	float offset = _height / 2.0f;
+	float correctedYPos = (pos.y - offset) * -1.0f + offset;
 
-	setup2D(true);
-}
+	if (mirrorX) {
+		SWAP(texLeft, texRight);
+	}
 
-bool BaseRenderOpenGL3DShader::fill(byte r, byte g, byte b, Common::Rect *rect) {
-	glClearColor(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-	return true;
-}
+	if (mirrorY) {
+		SWAP(texTop, texBottom);
+	}
 
-bool BaseRenderOpenGL3DShader::setViewport(int left, int top, int right, int bottom) {
-	_viewportRect.setRect(left, top, right, bottom);
-	_viewport._x = left;
-	_viewport._y = top;
-	_viewport._width = right - left;
-	_viewport._height = bottom - top;
-	_viewport._minZ = 0.0f;
-	_viewport._maxZ = 1.0f;
-	glViewport(left, _height - bottom, right - left, bottom - top);
-	glDepthRange(_viewport._minZ, _viewport._maxZ);
-	return true;
-}
+	SpriteVertexShader vertices[4] = {};
 
-bool BaseRenderOpenGL3DShader::setViewport3D(DXViewport *viewport) {
-	_viewport = *viewport;
-	glViewport(_viewport._x, _height - _viewport._height, _viewport._width, _viewport._height);
-	glDepthRange(_viewport._minZ, _viewport._maxZ);
-	return true;
-}
+	// texture coords
+	vertices[0].u = texLeft;
+	vertices[0].v = texTop;
 
-bool BaseRenderOpenGL3DShader::drawLine(int x1, int y1, int x2, int y2, uint32 color) {
-	glBindBuffer(GL_ARRAY_BUFFER, _lineVBO);
+	vertices[1].u = texLeft;
+	vertices[1].v = texBottom;
 
-	float lineCoords[4];
+	vertices[2].u = texRight;
+	vertices[2].v = texTop;
 
-	lineCoords[0] = x1;
-	lineCoords[1] = _height - y1;
-	lineCoords[2] = x2;
-	lineCoords[3] = _height - y2;
+	vertices[3].u = texRight;
+	vertices[3].v = texBottom;
 
-	glBufferSubData(GL_ARRAY_BUFFER, 0, 2 * 8, lineCoords);
+	// position coords
+	vertices[0].x = pos.x;
+	vertices[0].y = correctedYPos;
+
+	vertices[1].x = pos.x;
+	vertices[1].y = correctedYPos - height;
+
+	vertices[2].x = pos.x + width;
+	vertices[2].y = correctedYPos;
+
+	vertices[3].x = pos.x + width;
+	vertices[3].y = correctedYPos - height;
 
+	// not exactly sure about the color format, but this seems to work
 	byte a = RGBCOLGetA(color);
 	byte r = RGBCOLGetR(color);
 	byte g = RGBCOLGetG(color);
 	byte b = RGBCOLGetB(color);
 
-	Math::Vector4d colorValue;
-	colorValue.x() = r / 255.0f;
-	colorValue.y() = g / 255.0f;
-	colorValue.z() = b / 255.0f;
-	colorValue.w() = a / 255.0f;
+	for (int i = 0; i < 4; ++i) {
+		vertices[i].r = r / 255.0f;
+		vertices[i].g = g / 255.0f;
+		vertices[i].b = b / 255.0f;
+		vertices[i].a = a / 255.0f;
+	}
+
+	Math::Matrix3 transform;
+	transform.setToIdentity();
+
+	if (angle != 0) {
+		Vector2 correctedRot(rot.x, (rot.y - offset) * -1.0f + offset);
+		transform = build2dTransformation(correctedRot, angle);
+		transform.transpose();
+	}
 
 	Math::Matrix4 projectionMatrix2d;
 	projectionMatrix2d.setData(_projectionMatrix2d);
-	_lineShader->use();
-	_lineShader->setUniform("color", colorValue);
-	_lineShader->setUniform("projMatrix", projectionMatrix2d);
+	_spriteShader->use();
+	_spriteShader->setUniform("alphaTest", !alphaDisable);
+	_spriteShader->setUniform("transform", transform);
+	_spriteShader->setUniform("projMatrix", projectionMatrix2d);
 
-	glDrawArrays(GL_LINES, 0, 2);
+	glBindBuffer(GL_ARRAY_BUFFER, _spriteVBO);
+	glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * sizeof(SpriteVertexShader), vertices);
+
+	setSpriteBlendMode(blendMode);
+
+	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
 	return true;
 }
 
@@ -504,55 +452,38 @@ bool BaseRenderOpenGL3DShader::setProjection() {
 	return setProjectionTransform(matProj);
 }
 
-bool BaseRenderOpenGL3DShader::setProjection2D() {
-	float nearPlane = -1.0f;
-	float farPlane = 100.0f;
-
-	DXMatrixIdentity(&_projectionMatrix2d);
-
-	_projectionMatrix2d.matrix._11 = 2.0f / _width;
-	_projectionMatrix2d.matrix._22 = 2.0f / _height;
-	_projectionMatrix2d.matrix._33 = 2.0f / (farPlane - nearPlane);
-
-	_projectionMatrix2d.matrix._41 = -1.0f;
-	_projectionMatrix2d.matrix._42 = -1.0f;
-	_projectionMatrix2d.matrix._43 = -(farPlane + nearPlane) / (farPlane - nearPlane);
+bool BaseRenderOpenGL3DShader::drawLine(int x1, int y1, int x2, int y2, uint32 color) {
+	glBindBuffer(GL_ARRAY_BUFFER, _lineVBO);
 
-	Math::Matrix4 projectionMatrix2d;
-	projectionMatrix2d.setData(_projectionMatrix2d);
-	_shadowMaskShader->use();
-	_shadowMaskShader->setUniform("projMatrix", projectionMatrix2d);
-	return true;
-}
+	float lineCoords[4];
 
-bool BaseRenderOpenGL3DShader::setWorldTransform(const DXMatrix &transform) {
-	_worldMatrix = transform;
-	DXMatrix newInvertedTranspose, world = transform;
-	DXMatrixMultiply(&newInvertedTranspose, &world, &_viewMatrix);
-	DXMatrixInverse(&newInvertedTranspose, nullptr, &newInvertedTranspose);
-	DXMatrixTranspose(&newInvertedTranspose, &newInvertedTranspose);
+	lineCoords[0] = x1;
+	lineCoords[1] = _height - y1;
+	lineCoords[2] = x2;
+	lineCoords[3] = _height - y2;
 
-	Math::Matrix4 modelMatrix, normalMatrix;
-	modelMatrix.setData(world);
-	normalMatrix.setData(newInvertedTranspose);
+	glBufferSubData(GL_ARRAY_BUFFER, 0, 2 * 8, lineCoords);
 
-	_xmodelShader->use();
-	_xmodelShader->setUniform("modelMatrix", modelMatrix);
-	_xmodelShader->setUniform("normalMatrix", normalMatrix);
+	byte a = RGBCOLGetA(color);
+	byte r = RGBCOLGetR(color);
+	byte g = RGBCOLGetG(color);
+	byte b = RGBCOLGetB(color);
 
-	_shadowVolumeShader->use();
-	_shadowVolumeShader->setUniform("modelMatrix", modelMatrix);
+	Math::Vector4d colorValue;
+	colorValue.x() = r / 255.0f;
+	colorValue.y() = g / 255.0f;
+	colorValue.z() = b / 255.0f;
+	colorValue.w() = a / 255.0f;
 
-	return true;
-}
+	Math::Matrix4 projectionMatrix2d;
+	projectionMatrix2d.setData(_projectionMatrix2d);
+	_lineShader->use();
+	_lineShader->setUniform("color", colorValue);
+	_lineShader->setUniform("projMatrix", projectionMatrix2d);
 
-bool BaseRenderOpenGL3DShader::setViewTransform(const DXMatrix &transform) {
-	_viewMatrix = transform;
-	return true;
-}
+	glDrawArrays(GL_LINES, 0, 2);
 
-bool BaseRenderOpenGL3DShader::setProjectionTransform(const DXMatrix &transform) {
-	_projectionMatrix = transform;
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
 	return true;
 }
 
@@ -561,337 +492,154 @@ bool BaseRenderOpenGL3DShader::windowedBlt() {
 	return true;
 }
 
-void Wintermute::BaseRenderOpenGL3DShader::onWindowChange() {
-	_windowed = !g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
-}
+void BaseRenderOpenGL3DShader::fadeToColor(byte r, byte g, byte b, byte a) {
+	setProjection2D();
 
-bool BaseRenderOpenGL3DShader::initRenderer(int width, int height, bool windowed) {
-	glGenBuffers(1, &_spriteVBO);
-	glBindBuffer(GL_ARRAY_BUFFER, _spriteVBO);
-	glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(SpriteVertexShader), nullptr, GL_DYNAMIC_DRAW);
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-	static const char *spriteAttributes[] = {"position", "texcoord", "color", nullptr};
-	_spriteShader = OpenGL::Shader::fromFiles("wme_sprite", spriteAttributes);
-
-	_spriteShader->enableVertexAttribute("position", _spriteVBO, 2, GL_FLOAT, false, sizeof(SpriteVertexShader), 0);
-	_spriteShader->enableVertexAttribute("texcoord", _spriteVBO, 2, GL_FLOAT, false, sizeof(SpriteVertexShader), 8);
-	_spriteShader->enableVertexAttribute("color", _spriteVBO, 4, GL_FLOAT, false, sizeof(SpriteVertexShader), 16);
-
-	static const char *geometryAttributes[] = { "position", "color", nullptr };
-	_geometryShader = OpenGL::Shader::fromFiles("wme_geometry", geometryAttributes);
-
-	static const char *shadowVolumeAttributes[] = { "position", nullptr };
-	_shadowVolumeShader = OpenGL::Shader::fromFiles("wme_shadow_volume", shadowVolumeAttributes);
-
-	static const char *shadowMaskAttributes[] = { "position", nullptr };
-	_shadowMaskShader = OpenGL::Shader::fromFiles("wme_shadow_mask", shadowMaskAttributes);
-
-	DXMatrix m;
-	DXMatrixIdentity(&m);
-	_transformStack.push_back(m);
-
-	static const char *XModelAttributes[] = {"position", "texcoord", "normal", nullptr};
-	_xmodelShader = OpenGL::Shader::fromFiles("wme_modelx", XModelAttributes);
-
-	setDefaultAmbientLightColor();
-
-	for (int i = 0; i < getMaxActiveLights(); ++i) {
-		setLightParameters(i, DXVector3(0, 0, 0), DXVector3(0, 0, 0), DXVector4(0, 0, 0, 0), false);
-		lightEnable(i, false);
-	}
-
-	_windowed = !ConfMan.getBool("fullscreen");
-	_width = width;
-	_height = height;
-
-	_nearClipPlane = 90.0f;
-	_farClipPlane = 10000.0f;
-
-	setViewport(0, 0, width, height);
-
-	float fadeVertexCoords[8];
-
-	fadeVertexCoords[0 * 2 + 0] = _viewportRect.left;
-	fadeVertexCoords[0 * 2 + 1] = _viewportRect.bottom;
-	fadeVertexCoords[1 * 2 + 0] = _viewportRect.left;
-	fadeVertexCoords[1 * 2 + 1] = _viewportRect.top;
-	fadeVertexCoords[2 * 2 + 0] = _viewportRect.right;
-	fadeVertexCoords[2 * 2 + 1] = _viewportRect.bottom;
-	fadeVertexCoords[3 * 2 + 0] = _viewportRect.right;
-	fadeVertexCoords[3 * 2 + 1] = _viewportRect.top;
+	Math::Vector4d color;
+	color.x() = r / 255.0f;
+	color.y() = g / 255.0f;
+	color.z() = b / 255.0f;
+	color.w() = a / 255.0f;
 
-	glGenBuffers(1, &_fadeVBO);
+	glDisable(GL_DEPTH_TEST);
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glBindTexture(GL_TEXTURE_2D, 0);
 	glBindBuffer(GL_ARRAY_BUFFER, _fadeVBO);
-	glBufferData(GL_ARRAY_BUFFER, 4 * 8, fadeVertexCoords, GL_STATIC_DRAW);
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
 
-	static const char *fadeAttributes[] = { "position", nullptr };
-	_fadeShader = OpenGL::Shader::fromFiles("wme_fade", fadeAttributes);
-	_fadeShader->enableVertexAttribute("position", _fadeVBO, 2, GL_FLOAT, false, 8, 0);
-
-	glGenBuffers(1, &_lineVBO);
-	glBindBuffer(GL_ARRAY_BUFFER, _lineVBO);
-	glBufferData(GL_ARRAY_BUFFER, 2 * 8, nullptr, GL_DYNAMIC_DRAW);
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-	static const char *lineAttributes[] = { "position", nullptr };
-	_lineShader = OpenGL::Shader::fromFiles("wme_line", lineAttributes);
-	_lineShader->enableVertexAttribute("position", _lineVBO, 2, GL_FLOAT, false, 8, 0);
+	Math::Matrix4 projectionMatrix2d;
+	projectionMatrix2d.setData(_projectionMatrix2d);
+	_fadeShader->use();
+	_fadeShader->setUniform("color", color);
+	_fadeShader->setUniform("projMatrix", projectionMatrix2d);
 
-	static const char *flatShadowXModelAttributes[] = { "position", nullptr };
-	_flatShadowXModelShader = OpenGL::Shader::fromFiles("wme_flat_shadow_modelx", flatShadowXModelAttributes);
+	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
-	_active = true;
+	setup2D(true);
+}
 
-	setProjection();
+BaseImage *BaseRenderOpenGL3DShader::takeScreenshot() {
+	BaseImage *screenshot = new BaseImage();
+	Graphics::Surface *surface = new Graphics::Surface();
+#ifdef SCUMM_BIG_ENDIAN
+	Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
+#else
+	Graphics::PixelFormat format(4, 8, 8, 8, 8, 0, 8, 16, 24);
+#endif
+	surface->create(_viewportRect.width(), _viewportRect.height(), format);
 
-	return true;
+	glReadPixels(_viewportRect.left, _viewportRect.height() - _viewportRect.bottom, _viewportRect.width(), _viewportRect.height(),
+				 GL_RGBA, GL_UNSIGNED_BYTE, surface->getPixels());
+	flipVertical(surface);
+	Graphics::Surface *converted = surface->convertTo(getPixelFormat());
+	screenshot->copyFrom(converted);
+	delete surface;
+	delete converted;
+	return screenshot;
 }
 
-bool Wintermute::BaseRenderOpenGL3DShader::flip() {
-	g_system->updateScreen();
+bool BaseRenderOpenGL3DShader::enableShadows() {
+	warning("BaseRenderOpenGL3DShader::disableShadows not implemented yet");
 	return true;
 }
 
-bool BaseRenderOpenGL3DShader::indicatorFlip() {
-	flip();
+bool BaseRenderOpenGL3DShader::disableShadows() {
+	warning("BaseRenderOpenGL3DShader::disableShadows not implemented yet");
 	return true;
 }
 
-bool BaseRenderOpenGL3DShader::forcedFlip() {
-	flip();
-	return true;
+void BaseRenderOpenGL3DShader::displayShadow(BaseObject *object, const DXVector3 *lightPos, bool lightPosRelative) {
+	// TODO: to be implemented
+	return;
 }
 
-bool BaseRenderOpenGL3DShader::setup2D(bool force) {
-	if (_state != RSTATE_2D || force) {
-		_state = RSTATE_2D;
-
-		// some states are still missing here
-
-		glDisable(GL_DEPTH_TEST);
-		glDisable(GL_STENCIL_TEST);
-
-		glEnable(GL_CULL_FACE);
-		glFrontFace(GL_CCW);
-		glEnable(GL_BLEND);
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-		glViewport(0, 0, _width, _height);
-
-		setProjection2D();
-	}
-
+bool BaseRenderOpenGL3DShader::stencilSupported() {
+	// assume that we have a stencil buffer
 	return true;
 }
 
-bool BaseRenderOpenGL3DShader::setup3D(Camera3D *camera, bool force) {
-	if (_state != RSTATE_3D || force) {
-		_state = RSTATE_3D;
-
-		glEnable(GL_DEPTH_TEST);
-		glEnable(GL_BLEND);
-
-		setAmbientLightRenderState();
-
-		if (camera)
-			_camera = camera;
-		if (_camera) {
-			DXMatrix viewMatrix;
-			_camera->getViewMatrix(&viewMatrix);
-			setViewTransform(viewMatrix);
-
-			_fov = _camera->_fov;
-
-			if (_camera->_nearClipPlane >= 0.0f) {
-				_nearClipPlane = _camera->_nearClipPlane;
-			} else {
-				_nearClipPlane = DEFAULT_NEAR_PLANE;
-			}
-
-			if (_camera->_farClipPlane >= 0.0f) {
-				_farClipPlane = _camera->_farClipPlane;
-			} else {
-				_farClipPlane = DEFAULT_FAR_PLANE;
-			}
-		} else {
-			_nearClipPlane = DEFAULT_NEAR_PLANE;
-			_farClipPlane = DEFAULT_FAR_PLANE;
-		}
-
-		bool fogEnabled;
-		uint32 fogColor;
-		float fogStart, fogEnd;
+void BaseRenderOpenGL3DShader::setSpriteBlendMode(Graphics::TSpriteBlendMode blendMode) {
+	switch (blendMode) {
+	case Graphics::BLEND_NORMAL:
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		break;
 
-		_gameRef->getFogParams(&fogEnabled, &fogColor, &fogStart, &fogEnd);
-		if (fogEnabled) {
-			// TODO: Implement fog
-			GLfloat color[4];
-			color[0] = RGBCOLGetR(fogColor) / 255.0f;
-			color[1] = RGBCOLGetG(fogColor) / 255.0f;
-			color[2] = RGBCOLGetB(fogColor) / 255.0f;
-			color[3] = RGBCOLGetA(fogColor) / 255.0f;
-			debug(5, "BaseRenderOpenGL3DShader::setup3D fog not yet implemented! [%f %f %f %f]", color[0], color[1], color[2], color[3]);
-		} else {
-			// TODO: Disable fog in shader
-		}
+	case Graphics::BLEND_ADDITIVE:
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+		break;
 
-		glViewport(_viewportRect.left, _height - _viewportRect.bottom, _viewportRect.width(), _viewportRect.height());
+	case Graphics::BLEND_SUBTRACTIVE:
+		// wme3d takes the color value here
+		glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+		break;
 
-		setProjection();
+	default:
+		warning("BaseRenderOpenGL3DShader::setSpriteBlendMode unsupported blend mode %i", blendMode);
 	}
-
-	Math::Matrix4 viewMatrix, projectionMatrix;
-	viewMatrix.setData(_viewMatrix);
-	projectionMatrix.setData(_projectionMatrix);
-	_xmodelShader->use();
-	_xmodelShader->setUniform("viewMatrix", viewMatrix);
-	_xmodelShader->setUniform("projMatrix", projectionMatrix);
-	// this is 8 / 255, since 8 is the value used by wme (as a DWORD)
-	_xmodelShader->setUniform1f("alphaRef", 0.031f);
-
-	_geometryShader->use();
-	_geometryShader->setUniform("viewMatrix", viewMatrix);
-	_geometryShader->setUniform("projMatrix", projectionMatrix);
-
-	_shadowVolumeShader->use();
-	_shadowVolumeShader->setUniform("viewMatrix", viewMatrix);
-	_shadowVolumeShader->setUniform("projMatrix", projectionMatrix);
-
-	return true;
 }
 
-bool BaseRenderOpenGL3DShader::setupLines() {
-	if (_state != RSTATE_LINES) {
-		_state = RSTATE_LINES;
-
-		glDisable(GL_DEPTH_TEST);
-		glEnable(GL_BLEND);
-		glBindTexture(GL_TEXTURE_2D, 0);
-	}
-
-	return true;
+int BaseRenderOpenGL3DShader::getMaxActiveLights() {
+	return 8;
 }
 
-BaseSurface *Wintermute::BaseRenderOpenGL3DShader::createSurface() {
-	return new BaseSurfaceOpenGL3D(_gameRef, this);
+// implements D3D LightEnable()
+void BaseRenderOpenGL3DShader::lightEnable(int index, bool enable) {
+	_xmodelShader->use();
+	Common::String uniform = Common::String::format("lights[%i].enabled", index);
+	if (enable)
+		_xmodelShader->setUniform1f(uniform.c_str(), 1.0f);
+	else
+		_xmodelShader->setUniform1f(uniform.c_str(), -1.0f);
 }
 
-bool BaseRenderOpenGL3DShader::drawSpriteEx(BaseSurfaceOpenGL3D &tex, const Wintermute::Rect32 &rect,
-	                                    const Wintermute::Vector2 &pos, const Wintermute::Vector2 &rot,
-	                                    const Wintermute::Vector2 &scale, float angle, uint32 color,
-	                                    bool alphaDisable, Graphics::TSpriteBlendMode blendMode,
-	                                    bool mirrorX, bool mirrorY) {
-	// original wme has a batch mode for sprites, we ignore this for the moment
-
-	if (_forceAlphaColor != 0) {
-		color = _forceAlphaColor;
-	}
-
-	float width = (rect.right - rect.left) * scale.x;
-	float height = (rect.bottom - rect.top) * scale.y;
-
-	glBindTexture(GL_TEXTURE_2D, tex.getTextureName());
-
-	// for sprites we clamp to the edge, to avoid line fragments at the edges
-	// this is not done by wme, though
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-	int texWidth = tex.getGLTextureWidth();
-	int texHeight = tex.getGLTextureHeight();
-
-	float texLeft = (float)rect.left / (float)texWidth;
-	float texTop = (float)rect.top / (float)texHeight;
-	float texRight = (float)rect.right / (float)texWidth;
-	float texBottom = (float)rect.bottom / (float)texHeight;
-
-	float offset = _height / 2.0f;
-	float correctedYPos = (pos.y - offset) * -1.0f + offset;
-
-	if (mirrorX) {
-		SWAP(texLeft, texRight);
-	}
-
-	if (mirrorY) {
-		SWAP(texTop, texBottom);
-	}
-
-	SpriteVertexShader vertices[4] = {};
-
-	// texture coords
-	vertices[0].u = texLeft;
-	vertices[0].v = texTop;
-
-	vertices[1].u = texLeft;
-	vertices[1].v = texBottom;
-
-	vertices[2].u = texRight;
-	vertices[2].v = texTop;
-
-	vertices[3].u = texRight;
-	vertices[3].v = texBottom;
-
-	// position coords
-	vertices[0].x = pos.x;
-	vertices[0].y = correctedYPos;
-
-	vertices[1].x = pos.x;
-	vertices[1].y = correctedYPos - height;
-
-	vertices[2].x = pos.x + width;
-	vertices[2].y = correctedYPos;
-
-	vertices[3].x = pos.x + width;
-	vertices[3].y = correctedYPos - height;
+// backend layer 3DLight::SetLight
+void BaseRenderOpenGL3DShader::setLightParameters(int index, const DXVector3 &position,
+												  const DXVector3 &direction,
+												  const DXVector4 &diffuse, bool spotlight) {
+	Math::Vector4d position4d;
+	position4d.x() = position._x;
+	position4d.y() = position._y;
+	position4d.z() = position._z;
+	position4d.w() = 1.0f;
 
-	// not exactly sure about the color format, but this seems to work
-	byte a = RGBCOLGetA(color);
-	byte r = RGBCOLGetR(color);
-	byte g = RGBCOLGetG(color);
-	byte b = RGBCOLGetB(color);
+	Math::Vector4d direction4d;
+	direction4d.x() = direction._x;
+	direction4d.y() = direction._y;
+	direction4d.z() = direction._z;
+	direction4d.w() = 0.0f;
 
-	for (int i = 0; i < 4; ++i) {
-		vertices[i].r = r / 255.0f;
-		vertices[i].g = g / 255.0f;
-		vertices[i].b = b / 255.0f;
-		vertices[i].a = a / 255.0f;
+	if (spotlight) {
+		direction4d.w() = -1.0f;
 	}
 
-	Math::Matrix3 transform;
-	transform.setToIdentity();
+	Math::Vector4d diffuse4d;
+	diffuse4d.x() = diffuse._x;
+	diffuse4d.y() = diffuse._y;
+	diffuse4d.z() = diffuse._z;
+	diffuse4d.w() = 0.0f;
 
-	if (angle != 0) {
-		Vector2 correctedRot(rot.x, (rot.y - offset) * -1.0f + offset);
-		transform = build2dTransformation(correctedRot, angle);
-		transform.transpose();
-	}
 
-	Math::Matrix4 projectionMatrix2d;
-	projectionMatrix2d.setData(_projectionMatrix2d);
-	_spriteShader->use();
-	_spriteShader->setUniform("alphaTest", !alphaDisable);
-	_spriteShader->setUniform("transform", transform);
-	_spriteShader->setUniform("projMatrix", projectionMatrix2d);
-
-	glBindBuffer(GL_ARRAY_BUFFER, _spriteVBO);
-	glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * sizeof(SpriteVertexShader), vertices);
+	_xmodelShader->use();
 
-	setSpriteBlendMode(blendMode);
+	Common::String uniform = Common::String::format("lights[%i]._position", index);
+	_xmodelShader->setUniform(uniform.c_str(), position4d);
 
-	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+	uniform = Common::String::format("lights[%i]._direction", index);
+	_xmodelShader->setUniform(uniform.c_str(), direction4d);
 
-	return true;
+	uniform = Common::String::format("lights[%i]._color", index);
+	_xmodelShader->setUniform(uniform.c_str(), diffuse4d);
 }
 
+// backend layer AdSceneGeometry::Render
 void BaseRenderOpenGL3DShader::renderSceneGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks,
-	                                           const BaseArray<AdGeneric *> &generics, const BaseArray<Light3D *> &lights, Camera3D *camera) {
+											   const BaseArray<AdGeneric *> &generics, const BaseArray<Light3D *> &lights, Camera3D *camera) {
 	// don't render scene geometry, as OpenGL ES 2 has no wireframe rendering and we don't have a shader alternative yet
 }
 
+// backend layer 3DShadowVolume::Render()
 void BaseRenderOpenGL3DShader::renderShadowGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks,
-                                                    const BaseArray<AdGeneric *> &generics, Camera3D *camera) {
+													const BaseArray<AdGeneric *> &generics, Camera3D *camera) {
 	DXMatrix matIdentity;
 	DXMatrixIdentity(&matIdentity);
 
@@ -930,6 +678,115 @@ void BaseRenderOpenGL3DShader::renderShadowGeometry(const BaseArray<AdWalkplane
 	setSpriteBlendMode(Graphics::BLEND_NORMAL);
 }
 
+// implements D3D SetRenderState() D3DRS_CULLMODE - CCW
+void BaseRenderOpenGL3DShader::enableCulling() {
+	glFrontFace(GL_CW);
+	glEnable(GL_CULL_FACE);
+}
+
+// implements D3D SetRenderState() D3DRS_CULLMODE - NONE
+void BaseRenderOpenGL3DShader::disableCulling() {
+	glDisable(GL_CULL_FACE);
+}
+
+void BaseRenderOpenGL3DShader::setWindowed(bool windowed) {
+	ConfMan.setBool("fullscreen", !windowed);
+	g_system->beginGFXTransaction();
+	g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !windowed);
+	g_system->endGFXTransaction();
+}
+
+// implements D3D SetViewport() for 2D viewport
+bool BaseRenderOpenGL3DShader::setViewport(int left, int top, int right, int bottom) {
+	_viewportRect.setRect(left, top, right, bottom);
+	_viewport._x = left;
+	_viewport._y = top;
+	_viewport._width = right - left;
+	_viewport._height = bottom - top;
+	_viewport._minZ = 0.0f;
+	_viewport._maxZ = 1.0f;
+	glViewport(left, _height - bottom, right - left, bottom - top);
+	glDepthRange(_viewport._minZ, _viewport._maxZ);
+	return true;
+}
+
+// implements D3D SetViewport() for 3D viewport
+bool BaseRenderOpenGL3DShader::setViewport3D(DXViewport *viewport) {
+	_viewport = *viewport;
+	glViewport(_viewport._x, _height - _viewport._height, _viewport._width, _viewport._height);
+	glDepthRange(_viewport._minZ, _viewport._maxZ);
+	return true;
+}
+
+bool BaseRenderOpenGL3DShader::setProjection2D() {
+	float nearPlane = -1.0f;
+	float farPlane = 100.0f;
+
+	DXMatrixIdentity(&_projectionMatrix2d);
+
+	_projectionMatrix2d.matrix._11 = 2.0f / _width;
+	_projectionMatrix2d.matrix._22 = 2.0f / _height;
+	_projectionMatrix2d.matrix._33 = 2.0f / (farPlane - nearPlane);
+
+	_projectionMatrix2d.matrix._41 = -1.0f;
+	_projectionMatrix2d.matrix._42 = -1.0f;
+	_projectionMatrix2d.matrix._43 = -(farPlane + nearPlane) / (farPlane - nearPlane);
+
+	Math::Matrix4 projectionMatrix2d;
+	projectionMatrix2d.setData(_projectionMatrix2d);
+	_shadowMaskShader->use();
+	_shadowMaskShader->setUniform("projMatrix", projectionMatrix2d);
+	return true;
+}
+
+// implements SetTransform() D3DTS_WORLD
+bool BaseRenderOpenGL3DShader::setWorldTransform(const DXMatrix &transform) {
+	_worldMatrix = transform;
+	DXMatrix newInvertedTranspose, world = transform;
+	DXMatrixMultiply(&newInvertedTranspose, &world, &_viewMatrix);
+	DXMatrixInverse(&newInvertedTranspose, nullptr, &newInvertedTranspose);
+	DXMatrixTranspose(&newInvertedTranspose, &newInvertedTranspose);
+
+	Math::Matrix4 modelMatrix, normalMatrix;
+	modelMatrix.setData(world);
+	normalMatrix.setData(newInvertedTranspose);
+
+	_xmodelShader->use();
+	_xmodelShader->setUniform("modelMatrix", modelMatrix);
+	_xmodelShader->setUniform("normalMatrix", normalMatrix);
+
+	_shadowVolumeShader->use();
+	_shadowVolumeShader->setUniform("modelMatrix", modelMatrix);
+
+	return true;
+}
+
+// implements SetTransform() D3DTS_WIEW
+bool BaseRenderOpenGL3DShader::setViewTransform(const DXMatrix &transform) {
+	_viewMatrix = transform;
+	return true;
+}
+
+// implements SetTransform() D3DTS_PROJECTION
+bool BaseRenderOpenGL3DShader::setProjectionTransform(const DXMatrix &transform) {
+	_projectionMatrix = transform;
+	return true;
+}
+
+bool BaseRenderOpenGL3DShader::indicatorFlip() {
+	flip();
+	return true;
+}
+
+bool BaseRenderOpenGL3DShader::forcedFlip() {
+	flip();
+	return true;
+}
+
+BaseSurface *Wintermute::BaseRenderOpenGL3DShader::createSurface() {
+	return new BaseSurfaceOpenGL3D(_gameRef, this);
+}
+
 Mesh3DS *BaseRenderOpenGL3DShader::createMesh3DS() {
 	return new Mesh3DSOpenGLShader(_gameRef, _geometryShader);
 }
diff --git a/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h b/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h
index 443abfb84e2..c9d0c432a3b 100644
--- a/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h
+++ b/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h
@@ -133,13 +133,10 @@ private:
 	Common::Array<DXMatrix> _transformStack;
 
 	Math::Vector4d _flatShadowColor;
-	int _shadowTextureWidth;
-	int _shadowTextureHeight;
 
 	GLuint _spriteVBO;
 	GLuint _fadeVBO;
 	GLuint _lineVBO;
-	GLuint _flatShadowMaskVBO;
 	GLuint _flatShadowFrameBuffer;
 	GLuint _flatShadowRenderTexture;
 	GLuint _flatShadowDepthBuffer;




More information about the Scummvm-git-logs mailing list