[Scummvm-git-logs] scummvm master -> 045918c38c17fa7912bf73acbaefeb26c6e84e87

aquadran aquadran at gmail.com
Sat Apr 3 23:00:39 UTC 2021


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:
045918c38c STARK: Added initial non-shader OpenGL renderer. Lights needs to be fixed.


Commit: 045918c38c17fa7912bf73acbaefeb26c6e84e87
    https://github.com/scummvm/scummvm/commit/045918c38c17fa7912bf73acbaefeb26c6e84e87
Author: Paweł Kołodziejski (aquadran at gmail.com)
Date: 2021-04-04T01:00:30+02:00

Commit Message:
STARK: Added initial non-shader OpenGL renderer. Lights needs to be fixed.

Changed paths:
  A engines/stark/gfx/opengl.cpp
  A engines/stark/gfx/opengl.h
  A engines/stark/gfx/openglactor.cpp
  A engines/stark/gfx/openglactor.h
  A engines/stark/gfx/openglfade.cpp
  A engines/stark/gfx/openglfade.h
  A engines/stark/gfx/openglprop.cpp
  A engines/stark/gfx/openglprop.h
  A engines/stark/gfx/openglsurface.cpp
  A engines/stark/gfx/openglsurface.h
    engines/stark/gfx/driver.cpp
    engines/stark/module.mk


diff --git a/engines/stark/gfx/driver.cpp b/engines/stark/gfx/driver.cpp
index 9928460a29..0bfb6eddf7 100644
--- a/engines/stark/gfx/driver.cpp
+++ b/engines/stark/gfx/driver.cpp
@@ -21,10 +21,12 @@
  */
 
 #include "engines/stark/gfx/driver.h"
+#include "engines/stark/gfx/opengl.h"
 #include "engines/stark/gfx/opengls.h"
 
 #include "common/config-manager.h"
 
+#include "graphics/renderer.h"
 #include "graphics/surface.h"
 #if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS) || defined(USE_GLES2)
 #include "graphics/opengl/context.h"
@@ -36,22 +38,48 @@ namespace Stark {
 namespace Gfx {
 
 Driver *Driver::create() {
-	Driver *driver = nullptr;
-#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS) || defined(USE_GLES2)
-	initGraphics3d(kOriginalWidth, kOriginalHeight);
+	Common::String rendererConfig = ConfMan.get("renderer");
+	Graphics::RendererType desiredRendererType = Graphics::parseRendererTypeCode(rendererConfig);
+	Graphics::RendererType matchingRendererType = Graphics::getBestMatchingAvailableRendererType(desiredRendererType);
 
+#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS) || defined(USE_GLES2)
+	bool softRenderer = matchingRendererType == Graphics::kRendererTypeTinyGL;
+	if (!softRenderer) {
+		initGraphics3d(kOriginalWidth, kOriginalHeight);
+	} else {
+#endif
+		initGraphics(kOriginalWidth, kOriginalHeight, nullptr);
+#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS) || defined(USE_GLES2)
+	}
 	bool backendCapableOpenGL = g_system->hasFeature(OSystem::kFeatureOpenGLForGame);
+#endif
 
-	if (backendCapableOpenGL) {
+	if (matchingRendererType != desiredRendererType && desiredRendererType != Graphics::kRendererTypeDefault) {
+		// Display a warning if unable to use the desired renderer
+		warning("Unable to create a '%s' renderer", rendererConfig.c_str());
+	}
+
+	Driver *driver = nullptr;
 #if defined(USE_OPENGL_SHADERS) || defined(USE_GLES2)
-		if (OpenGLContext.shadersSupported) {
-			driver = new OpenGLSDriver();
-		} else {
-			error("Your system does not have the required OpenGL capabilities");
-		}
+	if (!OpenGLContext.shadersSupported) {
+		error("Your system does not have the required OpenGL capabilities");
+	}
+#endif
+
+#if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
+	if (backendCapableOpenGL && matchingRendererType == Graphics::kRendererTypeOpenGLShaders) {
+		driver = new OpenGLSDriver();
+	}
 #endif
+#if defined(USE_OPENGL_GAME) && !defined(USE_GLES2)
+	if (backendCapableOpenGL && matchingRendererType == Graphics::kRendererTypeOpenGL) {
+		driver = new OpenGLDriver();
 	}
 #endif
+	if (matchingRendererType == Graphics::kRendererTypeTinyGL) {
+		//driver = CreateTinyGLDriver();
+	}
+
 	if (driver)
 		return driver;
 	error("No renderers have been found for this game");
diff --git a/engines/stark/gfx/opengl.cpp b/engines/stark/gfx/opengl.cpp
new file mode 100644
index 0000000000..8c054e65b7
--- /dev/null
+++ b/engines/stark/gfx/opengl.cpp
@@ -0,0 +1,287 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the AUTHORS
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "engines/stark/gfx/opengl.h"
+
+#include "common/system.h"
+
+#include "math/matrix4.h"
+
+#if defined(USE_OPENGL_GAME)
+
+#include "engines/stark/gfx/openglactor.h"
+#include "engines/stark/gfx/openglprop.h"
+#include "engines/stark/gfx/openglsurface.h"
+#include "engines/stark/gfx/openglfade.h"
+#include "engines/stark/gfx/opengltexture.h"
+#include "engines/stark/scene.h"
+#include "engines/stark/services/services.h"
+
+#include "graphics/pixelbuffer.h"
+#include "graphics/surface.h"
+
+namespace Stark {
+namespace Gfx {
+
+OpenGLDriver::OpenGLDriver() {
+}
+
+OpenGLDriver::~OpenGLDriver() {
+}
+
+void OpenGLDriver::init() {
+	computeScreenViewport();
+
+#if defined(USE_OPENGL_SHADERS)
+	// The ShaderSurfaceRenderer sets an array buffer which conflict with fixed pipeline rendering
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
+#endif // defined(USE_OPENGL_SHADERS)
+
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+}
+
+void OpenGLDriver::setScreenViewport(bool noScaling) {
+	if (noScaling) {
+		_viewport = Common::Rect(g_system->getWidth(), g_system->getHeight());
+		_unscaledViewport = _viewport;
+	} else {
+		_viewport = _screenViewport;
+		_unscaledViewport = Common::Rect(kOriginalWidth, kOriginalHeight);
+	}
+
+	glViewport(_viewport.left, _viewport.top, _viewport.width(), _viewport.height());
+}
+
+void OpenGLDriver::setViewport(const Common::Rect &rect) {
+	_viewport = Common::Rect(
+			_screenViewport.width() * rect.width() / kOriginalWidth,
+			_screenViewport.height() * rect.height() / kOriginalHeight
+			);
+
+	_viewport.translate(
+			_screenViewport.left + _screenViewport.width() * rect.left / kOriginalWidth,
+			_screenViewport.top + _screenViewport.height() * rect.top / kOriginalHeight
+			);
+
+	_unscaledViewport = rect;
+
+	glViewport(_viewport.left, g_system->getHeight() - _viewport.bottom, _viewport.width(), _viewport.height());
+}
+
+void OpenGLDriver::clearScreen() {
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+}
+
+void OpenGLDriver::flipBuffer() {
+	g_system->updateScreen();
+}
+
+void OpenGLDriver::setupLights(const LightEntryArray &lights) {
+	static const uint maxLights = 10;
+
+	assert(lights.size() >= 1);
+	assert(lights.size() <= maxLights);
+
+	const LightEntry *ambient = lights[0];
+	assert(ambient->type == LightEntry::kAmbient); // The first light must be the ambient light
+
+	Math::Matrix4 viewMatrix = StarkScene->getViewMatrix();
+	Math::Matrix3 viewMatrixRot = viewMatrix.getRotation();
+
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+
+	for (uint i = 0; i < lights.size(); i++) {
+		const LightEntry *l = lights[i];
+		GLfloat ambientColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
+		GLfloat lightColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
+		GLfloat lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f };
+		GLfloat lightDir[] = { 0.0f, 0.0f, -1.0f };
+		GLfloat cutoff = 180.0f;
+		GLfloat spotExp = 0.0f;
+		GLfloat q_attenuation = 0.0f;
+
+		Math::Vector4d worldPosition;
+		worldPosition.x() = l->position.x();
+		worldPosition.y() = l->position.y();
+		worldPosition.z() = l->position.z();
+		worldPosition.w() = 1.0;
+
+		Math::Vector4d eyePosition = viewMatrix * worldPosition;
+
+		Math::Vector3d worldDirection = l->direction;
+		Math::Vector3d eyeDirection = viewMatrixRot * worldDirection;
+		eyeDirection.normalize();
+
+		Math::Vector4d params;
+		params.x() = l->falloffNear;
+		params.y() = l->falloffFar;
+		params.z() = l->innerConeAngle.getCosine();
+		params.w() = l->outerConeAngle.getCosine();
+
+		glDisable(GL_LIGHT0 + i);
+		switch (l->type) {
+			case LightEntry::kPoint:
+				lightColor[0] = (GLfloat)l->color.x();
+				lightColor[1] = (GLfloat)l->color.y();
+				lightColor[2] = (GLfloat)l->color.z();
+				lightPos[0] = (GLfloat)eyePosition.x();
+				lightPos[1] = (GLfloat)eyePosition.y();
+				lightPos[2] = (GLfloat)eyePosition.z();
+				break;
+			case LightEntry::kDirectional:
+				lightColor[0] = (GLfloat)l->color.x();
+				lightColor[1] = (GLfloat)l->color.y();
+				lightColor[2] = (GLfloat)l->color.z();
+				lightPos[0] = -(GLfloat)eyeDirection.x();
+				lightPos[1] = -(GLfloat)eyeDirection.y();
+				lightPos[2] = -(GLfloat)eyeDirection.z();
+				lightPos[3] = 0;
+				break;
+			case LightEntry::kSpot:
+				lightColor[0] = (GLfloat)l->color.x();
+				lightColor[1] = (GLfloat)l->color.y();
+				lightColor[2] = (GLfloat)l->color.z();
+				lightPos[0] = (GLfloat)eyePosition.x();
+				lightPos[1] = (GLfloat)eyePosition.y();
+				lightPos[2] = (GLfloat)eyePosition.z();
+				lightDir[0] = (GLfloat)eyeDirection.x();
+				lightDir[1] = (GLfloat)eyeDirection.y();
+				lightDir[2] = (GLfloat)eyeDirection.z();
+				// FIXME
+				q_attenuation = 1.0f;
+				spotExp = 1.0f;
+				cutoff = 180.f;
+				break;
+			case LightEntry::kAmbient:
+				ambientColor[0] = (GLfloat)l->color.x();
+				ambientColor[1] = (GLfloat)l->color.y();
+				ambientColor[2] = (GLfloat)l->color.z();
+				break;
+			default:
+				break;
+		}
+
+		glLightfv(GL_LIGHT0 + i, GL_AMBIENT, ambientColor);
+		glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lightColor);
+		glLightfv(GL_LIGHT0 + i, GL_POSITION, lightPos);
+		glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, lightDir);
+		glLightf(GL_LIGHT0 + i, GL_SPOT_EXPONENT, spotExp);
+		glLightf(GL_LIGHT0 + i, GL_SPOT_CUTOFF, cutoff);
+		glLightf(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, q_attenuation);
+		glEnable(GL_LIGHT0 + i);
+	}
+
+	for (uint i = lights.size() - 1; i < maxLights; i++) {
+		// Make sure unused lights are disabled
+		glDisable(GL_LIGHT0 + i + 1);
+	}
+}
+
+Texture *OpenGLDriver::createTexture(const Graphics::Surface *surface, const byte *palette) {
+	OpenGlTexture *texture = new OpenGlTexture();
+
+	if (surface) {
+		texture->update(surface, palette);
+	}
+
+	return texture;
+}
+
+VisualActor *OpenGLDriver::createActorRenderer() {
+	return new OpenGLActorRenderer(this);
+}
+
+VisualProp *OpenGLDriver::createPropRenderer() {
+	return new OpenGLPropRenderer(this);
+}
+
+SurfaceRenderer *OpenGLDriver::createSurfaceRenderer() {
+	return new OpenGLSurfaceRenderer(this);
+}
+
+FadeRenderer *OpenGLDriver::createFadeRenderer() {
+	return new OpenGLFadeRenderer(this);
+}
+
+void OpenGLDriver::start2DMode() {
+	// Enable alpha blending
+	glEnable(GL_BLEND);
+	//glBlendEquation(GL_FUNC_ADD); // It's the default
+
+	// This blend mode prevents color fringes due to filtering.
+	// It requires the textures to have their color values pre-multiplied
+	// with their alpha value. This is the "Premultiplied Alpha" technique.
+	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+	glDisable(GL_DEPTH_TEST);
+	glDepthMask(GL_FALSE);
+	glDisable(GL_LIGHTING);
+}
+
+void OpenGLDriver::end2DMode() {
+	// Disable alpha blending
+	glDisable(GL_BLEND);
+
+	glEnable(GL_DEPTH_TEST);
+	glDepthMask(GL_TRUE);
+	glEnable(GL_LIGHTING);
+}
+
+void OpenGLDriver::set3DMode() {
+	glEnable(GL_DEPTH_TEST);
+	glDepthFunc(GL_LESS);
+
+	// Blending and stencil test are only used in rendering shadows
+	// They are manually enabled and disabled there
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glStencilFunc(GL_EQUAL, 0, 0xFF);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+}
+
+Common::Rect OpenGLDriver::getViewport() const {
+	return _viewport;
+}
+
+Common::Rect OpenGLDriver::getUnscaledViewport() const {
+	return _unscaledViewport;
+}
+
+Graphics::Surface *OpenGLDriver::getViewportScreenshot() const {
+	Graphics::Surface *s = new Graphics::Surface();
+	s->create(_viewport.width(), _viewport.height(), getRGBAPixelFormat());
+
+	glReadPixels(_viewport.left, g_system->getHeight() - _viewport.bottom, _viewport.width(), _viewport.height(),
+	             GL_RGBA, GL_UNSIGNED_BYTE, s->getPixels());
+
+	flipVertical(s);
+
+	return s;
+}
+
+} // End of namespace Gfx
+} // End of namespace Stark
+
+#endif // defined(USE_OPENGL_GAME)
diff --git a/engines/stark/gfx/opengl.h b/engines/stark/gfx/opengl.h
new file mode 100644
index 0000000000..07e86bc35d
--- /dev/null
+++ b/engines/stark/gfx/opengl.h
@@ -0,0 +1,78 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the AUTHORS
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef STARK_GFX_OPENGL_H
+#define STARK_GFX_OPENGL_H
+
+#include "common/system.h"
+#include "math/vector3d.h"
+
+#if defined(USE_OPENGL_GAME)
+
+#include "engines/stark/gfx/driver.h"
+#include "engines/stark/gfx/renderentry.h"
+
+#include "graphics/opengl/system_headers.h"
+
+namespace Stark {
+namespace Gfx {
+
+class OpenGLDriver : public Driver {
+public:
+	OpenGLDriver();
+	~OpenGLDriver();
+
+	void init() override;
+
+	void setScreenViewport(bool noScaling) override;
+	void setViewport(const Common::Rect &rect) override;
+
+	void clearScreen() override;
+	void flipBuffer() override;
+
+	Texture *createTexture(const Graphics::Surface *surface = nullptr, const byte *palette = nullptr) override;
+	VisualActor *createActorRenderer() override;
+	VisualProp *createPropRenderer() override;
+	SurfaceRenderer *createSurfaceRenderer() override;
+	FadeRenderer *createFadeRenderer() override;
+
+	void start2DMode();
+	void end2DMode();
+	void set3DMode() override;
+
+	Common::Rect getViewport() const;
+	Common::Rect getUnscaledViewport() const;
+	void setupLights(const LightEntryArray &lights);
+
+	Graphics::Surface *getViewportScreenshot() const override;
+
+private:
+	Common::Rect _viewport;
+	Common::Rect _unscaledViewport;
+};
+
+} // End of namespace Gfx
+} // End of namespace Stark
+
+#endif // defined(USE_OPENGL_GAME)
+
+#endif // STARK_GFX_OPENGL_H
diff --git a/engines/stark/gfx/openglactor.cpp b/engines/stark/gfx/openglactor.cpp
new file mode 100644
index 0000000000..70b9ebe332
--- /dev/null
+++ b/engines/stark/gfx/openglactor.cpp
@@ -0,0 +1,393 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the AUTHORS
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "engines/stark/gfx/openglactor.h"
+
+#include "engines/stark/model/model.h"
+#include "engines/stark/model/animhandler.h"
+#include "engines/stark/scene.h"
+#include "engines/stark/services/services.h"
+#include "engines/stark/services/settings.h"
+#include "engines/stark/gfx/texture.h"
+
+#include "math/vector2d.h"
+
+#if defined(USE_OPENGL_GAME)
+
+namespace Stark {
+namespace Gfx {
+
+OpenGLActorRenderer::OpenGLActorRenderer(OpenGLDriver *gfx) :
+		VisualActor(),
+		_gfx(gfx),
+		_faceVBO(nullptr) {
+}
+
+OpenGLActorRenderer::~OpenGLActorRenderer() {
+	clearVertices();
+}
+
+void OpenGLActorRenderer::render(const Math::Vector3d &position, float direction, const LightEntryArray &lights) {
+	if (_modelIsDirty) {
+		clearVertices();
+		uploadVertices();
+		_modelIsDirty = false;
+	}
+
+	// TODO: Move updates outside of the rendering code
+	_animHandler->animate(_time);
+	_model->updateBoundingBox();
+
+	bool drawShadow = false;
+	if (_castsShadow
+			&& StarkScene->shouldRenderShadows()
+			&& StarkSettings->getBoolSetting(Settings::kShadow)) {
+		drawShadow = true;
+	}
+	Math::Vector3d lightDirection;
+
+	_gfx->set3DMode();
+	_gfx->setupLights(lights);
+
+	Math::Matrix4 model = getModelMatrix(position, direction);
+	Math::Matrix4 view = StarkScene->getViewMatrix();
+	Math::Matrix4 projection = StarkScene->getProjectionMatrix();
+
+	Math::Matrix4 modelViewMatrix = view * model;
+	modelViewMatrix.transpose(); // OpenGL expects matrices transposed when compared to ScummVM's
+
+	Math::Matrix4 projectionMatrix = projection;
+	projectionMatrix.transpose(); // OpenGL expects matrices transposed when compared to ScummVM's
+
+	Math::Matrix4 mvp;
+	if (drawShadow) {
+		mvp = view * model;
+		mvp.transpose();
+		Math::Matrix4 modelInverse = model;
+		modelInverse.inverse();
+		lightDirection = getShadowLightDirection(lights, position, modelInverse.getRotation());
+	}
+
+	glMatrixMode(GL_PROJECTION);
+	glLoadMatrixf(projectionMatrix.getData());
+
+	glMatrixMode(GL_MODELVIEW);
+	glLoadMatrixf(modelViewMatrix.getData());
+
+	glEnable(GL_TEXTURE_2D);
+
+	Common::Array<Face *> faces = _model->getFaces();
+	Common::Array<Material *> mats = _model->getMaterials();
+	const Common::Array<BoneNode *> &bones = _model->getBones();
+
+	for (Common::Array<Face *>::const_iterator face = faces.begin(); face != faces.end(); ++face) {
+		const Material *material = mats[(*face)->materialId];
+		const Gfx::Texture *tex = resolveTexture(material);
+		glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+		glEnable(GL_COLOR_MATERIAL);
+		if (tex) {
+			tex->bind();
+			glColor3f(1.0f, 1.0f, 1.0f);
+		} else {
+			glBindTexture(GL_TEXTURE_2D, 0);
+			glColor3f(material->r, material->g, material->b);
+		}
+
+		auto vertexIndices = _faceEBO[*face];
+		auto numVertexIndices = (*face)->vertexIndices.size();
+		for (uint32 i = 0; i < numVertexIndices; i++) {
+			uint32 index = vertexIndices[i];
+			auto vertex = _faceVBO[index];
+			uint32 bone1 = vertex.bone1;
+			uint32 bone2 = vertex.bone2;
+			Math::Vector3d position1 = vertex.pos1;
+			Math::Vector3d position2 = vertex.pos2;
+			Math::Vector3d bone1Position = Math::Vector3d(bones[bone1]->_animPos.x(),
+														  bones[bone1]->_animPos.y(),
+														  bones[bone1]->_animPos.z());
+			Math::Vector3d bone2Position = Math::Vector3d(bones[bone2]->_animPos.x(),
+														  bones[bone2]->_animPos.y(),
+														  bones[bone2]->_animPos.z());
+			Math::Quaternion bone1Rotation = Math::Quaternion(bones[bone1]->_animRot.x(),
+														  bones[bone1]->_animRot.y(),
+														  bones[bone1]->_animRot.z(),
+														  bones[bone1]->_animRot.w());
+			Math::Quaternion bone2Rotation = Math::Quaternion(bones[bone2]->_animRot.x(),
+														  bones[bone2]->_animRot.y(),
+														  bones[bone2]->_animRot.z(),
+														  bones[bone2]->_animRot.w());
+			float boneWeight = vertex.boneWeight;
+			Math::Vector3d normal = vertex.normal;
+
+			// Compute the vertex position in eye-space
+			bone1Rotation.transform(position1);
+			position1 += bone1Position;
+			bone2Rotation.transform(position2);
+			position2 += bone2Position;
+			Math::Vector3d modelPosition = position2 * (1.0 - boneWeight) + position1 * boneWeight;
+			vertex.x = modelPosition.x();
+			vertex.y = modelPosition.y();
+			vertex.z = modelPosition.z();
+
+			// Compute the vertex normal in eye-space
+			Math::Vector3d n1 = normal;
+			bone1Rotation.transform(n1);
+			Math::Vector3d n2 = normal;
+			bone2Rotation.transform(n2);
+			Math::Vector3d modelNormal = Math::Vector3d(n2 * (1.0 - boneWeight) + n1 * boneWeight).getNormalized();
+			vertex.nx = modelNormal.x();
+			vertex.ny = modelNormal.y();
+			vertex.nz = modelNormal.z();
+
+			if (drawShadow) {
+				Math::Vector3d shadowPosition = modelPosition + lightDirection * (-modelPosition.y() / lightDirection.y());
+				vertex.sx = shadowPosition.x();
+				vertex.sy = 0.0f;
+				vertex.sz = shadowPosition.z();
+			}
+
+			_faceVBO[index] = vertex;
+		}
+
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		glEnableClientState(GL_NORMAL_ARRAY);
+
+		glVertexPointer(3, GL_FLOAT, sizeof(ActorVertex), &_faceVBO[0].x);
+		if (tex)
+			glTexCoordPointer(2, GL_FLOAT, sizeof(ActorVertex), &_faceVBO[0].texS);
+		glNormalPointer(GL_FLOAT, sizeof(ActorVertex), &_faceVBO[0].nx);
+
+		glDrawElements(GL_TRIANGLES, numVertexIndices, GL_UNSIGNED_INT, vertexIndices);
+
+		glDisableClientState(GL_VERTEX_ARRAY);
+		glDisableClientState(GL_NORMAL_ARRAY);
+		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+		glDisable(GL_COLOR_MATERIAL);
+	}
+
+
+	if (drawShadow) {
+		glEnable(GL_BLEND);
+		glEnable(GL_STENCIL_TEST);
+		glDisable(GL_TEXTURE_2D);
+		glDisable(GL_LIGHTING);
+
+		glMatrixMode(GL_PROJECTION);
+		glLoadMatrixf(projectionMatrix.getData());
+
+		glMatrixMode(GL_MODELVIEW);
+		glLoadMatrixf(mvp.getData());
+
+		glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
+
+		for (Common::Array<Face *>::const_iterator face = faces.begin(); face != faces.end(); ++face) {
+			auto vertexIndices = _faceEBO[*face];
+
+			glEnableClientState(GL_VERTEX_ARRAY);
+
+			glVertexPointer(3, GL_FLOAT, sizeof(ActorVertex), &_faceVBO[0].sx);
+
+			glDrawElements(GL_TRIANGLES, (*face)->vertexIndices.size(), GL_UNSIGNED_INT, vertexIndices);
+
+			glDisableClientState(GL_VERTEX_ARRAY);
+		}
+
+		glEnable(GL_LIGHTING);
+		glEnable(GL_TEXTURE_2D);
+		glDisable(GL_BLEND);
+		glDisable(GL_STENCIL_TEST);
+	}
+}
+
+void OpenGLActorRenderer::clearVertices() {
+	delete[] _faceVBO;
+	_faceVBO = nullptr;
+
+	for (FaceBufferMap::iterator it = _faceEBO.begin(); it != _faceEBO.end(); ++it) {
+		delete[] it->_value;
+	}
+
+	_faceEBO.clear();
+}
+
+void OpenGLActorRenderer::uploadVertices() {
+	_faceVBO = createModelVBO(_model);
+
+	Common::Array<Face *> faces = _model->getFaces();
+	for (Common::Array<Face *>::const_iterator face = faces.begin(); face != faces.end(); ++face) {
+		_faceEBO[*face] = createFaceEBO(*face);
+	}
+}
+
+ActorVertex *OpenGLActorRenderer::createModelVBO(const Model *model) {
+	const Common::Array<VertNode *> &modelVertices = model->getVertices();
+
+	auto vertices = new ActorVertex[modelVertices.size()];
+	// Build a vertex array
+	int i = 0;
+	for (Common::Array<VertNode *>::const_iterator tri = modelVertices.begin(); tri != modelVertices.end(); ++tri, i++) {
+		vertices[i].pos1 = Math::Vector3d((*tri)->_pos1.x(), (*tri)->_pos1.y(), (*tri)->_pos1.z());
+		vertices[i].pos2 = Math::Vector3d((*tri)->_pos2.x(), (*tri)->_pos2.y(), (*tri)->_pos2.z());
+		vertices[i].bone1 = (*tri)->_bone1;
+		vertices[i].bone2 = (*tri)->_bone2;
+		vertices[i].boneWeight = (*tri)->_boneWeight;
+		vertices[i].normal = Math::Vector3d((*tri)->_normal.x(), (*tri)->_normal.y(), (*tri)->_normal.z());
+		vertices[i].texS = -(*tri)->_texS;
+		vertices[i].texT = (*tri)->_texT;
+	}
+
+	return vertices;
+}
+
+uint32 *OpenGLActorRenderer::createFaceEBO(const Face *face) {
+	auto indices = new uint32[face->vertexIndices.size()];
+	for (uint32 index = 0; index < face->vertexIndices.size(); index++) {
+		indices[index] = face->vertexIndices[index];
+	}
+
+	return indices;
+}
+
+Math::Vector3d OpenGLActorRenderer::getShadowLightDirection(const LightEntryArray &lights,
+		const Math::Vector3d &actorPosition, Math::Matrix3 worldToModelRot) {
+	Math::Vector3d sumDirection;
+	bool hasLight = false;
+
+	// Compute the contribution from each lights
+	// The ambient light is skipped intentionally
+	for (uint i = 1; i < lights.size(); ++i) {
+		LightEntry *light = lights[i];
+		bool contributes = false;
+
+		Math::Vector3d lightDirection;
+		switch (light->type) {
+			case LightEntry::kPoint:
+				contributes = getPointLightContribution(light, actorPosition, lightDirection);
+				break;
+			case LightEntry::kDirectional:
+				contributes = getDirectionalLightContribution(light, lightDirection);
+				break;
+			case LightEntry::kSpot:
+				contributes = getSpotLightContribution(light, actorPosition, lightDirection);
+				break;
+			case LightEntry::kAmbient:
+			default:
+				break;
+		}
+
+		if (contributes) {
+			sumDirection += lightDirection;
+			hasLight = true;
+		}
+	}
+
+	if (hasLight) {
+		// Clip the horizontal length
+		Math::Vector2d horizontalProjection(sumDirection.x(), sumDirection.y());
+		float shadowLength = MIN(horizontalProjection.getMagnitude(), StarkScene->getMaxShadowLength());
+
+		horizontalProjection.normalize();
+		horizontalProjection *= shadowLength;
+
+		sumDirection.x() = horizontalProjection.getX();
+		sumDirection.y() = horizontalProjection.getY();
+		sumDirection.z() = -1;
+	} else {
+		// Cast from above by default
+		sumDirection.x() = 0;
+		sumDirection.y() = 0;
+		sumDirection.z() = -1;
+	}
+
+	//Transform the direction to the model space and pass to the shader
+	return worldToModelRot * sumDirection;
+}
+
+bool OpenGLActorRenderer::getPointLightContribution(LightEntry *light,
+		const Math::Vector3d &actorPosition, Math::Vector3d &direction, float weight) {
+	float distance = light->position.getDistanceTo(actorPosition);
+
+	if (distance > light->falloffFar) {
+		return false;
+	}
+
+	float factor;
+	if (distance > light->falloffNear) {
+		if (light->falloffFar - light->falloffNear > 1) {
+			factor = 1 - (distance - light->falloffNear) / (light->falloffFar - light->falloffNear);
+		} else {
+			factor = 0;
+		}
+	} else {
+		factor = 1;
+	}
+
+	float brightness = (light->color.x() + light->color.y() + light->color.z()) / 3.0f;
+
+	if (factor <= 0 || brightness <= 0) {
+		return false;
+	}
+
+	direction = actorPosition - light->position;
+	direction.normalize();
+	direction *= factor * brightness * weight;
+
+	return true;
+}
+
+bool OpenGLActorRenderer::getDirectionalLightContribution(LightEntry *light, Math::Vector3d &direction) {
+	float brightness = (light->color.x() + light->color.y() + light->color.z()) / 3.0f;
+
+	if (brightness <= 0) {
+		return false;
+	}
+
+	direction = light->direction;
+	direction.normalize();
+	direction *= brightness;
+
+	return true;
+}
+
+bool OpenGLActorRenderer::getSpotLightContribution(LightEntry *light,
+		const Math::Vector3d &actorPosition, Math::Vector3d &direction) {
+	Math::Vector3d lightToActor = actorPosition - light->position;
+	lightToActor.normalize();
+
+	float cosAngle = MAX(0.0f, lightToActor.dotProduct(light->direction));
+	float cone = (cosAngle - light->innerConeAngle.getCosine()) /
+			MAX(0.001f, light->outerConeAngle.getCosine() - light->innerConeAngle.getCosine());
+	cone = CLIP(cone, 0.0f, 1.0f);
+
+	if (cone <= 0) {
+		return false;
+	}
+
+	return getPointLightContribution(light, actorPosition, direction, cone);
+}
+
+} // End of namespace Gfx
+} // End of namespace Stark
+
+#endif // defined(USE_OPENGL_GAME)
diff --git a/engines/stark/gfx/openglactor.h b/engines/stark/gfx/openglactor.h
new file mode 100644
index 0000000000..a4f80bc16b
--- /dev/null
+++ b/engines/stark/gfx/openglactor.h
@@ -0,0 +1,101 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the AUTHORS
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef STARK_GFX_OPENGL_ACTOR_H
+#define STARK_GFX_OPENGL_ACTOR_H
+
+#include "engines/stark/gfx/renderentry.h"
+#include "engines/stark/visual/actor.h"
+#include "engines/stark/gfx/opengl.h"
+
+#include "common/hashmap.h"
+#include "common/hash-ptr.h"
+
+#include "graphics/opengl/system_headers.h"
+
+#if defined(USE_OPENGL_GAME)
+
+namespace Stark {
+namespace Gfx {
+
+class OpenGLDriver;
+
+#include "common/pack-start.h"
+
+struct _ActorVertex {
+	Math::Vector3d pos1;
+	Math::Vector3d pos2;
+	uint32 bone1;
+	uint32 bone2;
+	float boneWeight;
+	Math::Vector3d normal;
+	float texS;
+	float texT;
+	float x;
+	float y;
+	float z;
+	float nx;
+	float ny;
+	float nz;
+	float sx;
+	float sy;
+	float sz;
+} PACKED_STRUCT;
+typedef _ActorVertex ActorVertex;
+
+#include "common/pack-end.h"
+
+class OpenGLActorRenderer : public VisualActor {
+public:
+	OpenGLActorRenderer(OpenGLDriver *gfx);
+	virtual ~OpenGLActorRenderer();
+
+	void render(const Math::Vector3d &position, float direction, const LightEntryArray &lights) override;
+
+protected:
+	typedef Common::HashMap<Face *, uint32 *> FaceBufferMap;
+
+	OpenGLDriver *_gfx;
+
+	ActorVertex *_faceVBO;
+	FaceBufferMap _faceEBO;
+
+	void clearVertices();
+	void uploadVertices();
+	ActorVertex *createModelVBO(const Model *model);
+	uint32 *createFaceEBO(const Face *face);
+	void setLightArrayUniform(const LightEntryArray &lights);
+
+	Math::Vector3d getShadowLightDirection(const LightEntryArray &lights, const Math::Vector3d &actorPosition, Math::Matrix3 worldToModelRot);
+
+	bool getPointLightContribution(LightEntry *light, const Math::Vector3d &actorPosition,
+			Math::Vector3d &direction, float weight = 1.0f);
+	bool getDirectionalLightContribution(LightEntry *light, Math::Vector3d &direction);
+	bool getSpotLightContribution(LightEntry *light, const Math::Vector3d &actorPosition, Math::Vector3d &direction);
+};
+
+} // End of namespace Gfx
+} // End of namespace Stark
+
+#endif // defined(USE_OPENGL_GAME)
+
+#endif // STARK_GFX_OPENGL_ACTOR_H
diff --git a/engines/stark/gfx/openglfade.cpp b/engines/stark/gfx/openglfade.cpp
new file mode 100644
index 0000000000..ca7747b66d
--- /dev/null
+++ b/engines/stark/gfx/openglfade.cpp
@@ -0,0 +1,82 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the AUTHORS
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "engines/stark/gfx/openglfade.h"
+
+#include "engines/stark/gfx/opengl.h"
+
+#if defined(USE_OPENGL_GAME)
+
+namespace Stark {
+namespace Gfx {
+
+static const GLfloat fadeVertices[] = {
+	// X   Y
+	-1.0f,  1.0f,
+	 1.0f,  1.0f,
+	-1.0f, -1.0f,
+	 1.0f, -1.0f,
+};
+
+OpenGLFadeRenderer::OpenGLFadeRenderer(OpenGLDriver *gfx) :
+	FadeRenderer(),
+	_gfx(gfx) {
+}
+
+OpenGLFadeRenderer::~OpenGLFadeRenderer() {
+}
+
+void OpenGLFadeRenderer::render(float fadeLevel) {
+	_gfx->start2DMode();
+
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glLoadIdentity();
+
+	glMatrixMode(GL_MODELVIEW);
+	glPushMatrix();
+	glLoadIdentity();
+
+	glDisable(GL_TEXTURE_2D);
+
+	glEnableClientState(GL_VERTEX_ARRAY);
+
+	glColor4f(0.0f, 0.0f, 0.0f, 1.0f - fadeLevel);
+	glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), &fadeVertices[0]);
+
+	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+	glDisableClientState(GL_VERTEX_ARRAY);
+
+	glMatrixMode(GL_MODELVIEW);
+	glPopMatrix();
+
+	glMatrixMode(GL_PROJECTION);
+	glPopMatrix();
+
+	_gfx->end2DMode();
+}
+
+} // End of namespace Gfx
+} // End of namespace Stark
+
+#endif // defined(USE_OPENGL_GAME)
diff --git a/engines/stark/gfx/openglfade.h b/engines/stark/gfx/openglfade.h
new file mode 100644
index 0000000000..588d5aea0e
--- /dev/null
+++ b/engines/stark/gfx/openglfade.h
@@ -0,0 +1,57 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the AUTHORS
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef STARK_GFX_OPENGL_FADE_H
+#define STARK_GFX_OPENGL_FADE_H
+
+#include "graphics/opengl/system_headers.h"
+
+#if defined(USE_OPENGL_GAME)
+
+#include "engines/stark/gfx/faderenderer.h"
+
+namespace Stark {
+namespace Gfx {
+
+class OpenGLDriver;
+
+/**
+ * An programmable pipeline OpenGL fade screen renderer
+ */
+class OpenGLFadeRenderer : public FadeRenderer {
+public:
+	OpenGLFadeRenderer(OpenGLDriver *gfx);
+	~OpenGLFadeRenderer();
+
+	// FadeRenderer API
+	void render(float fadeLevel);
+
+private:
+	OpenGLDriver *_gfx;
+};
+
+} // End of namespace Gfx
+} // End of namespace Stark
+
+#endif // defined(USE_OPENGL_GAME)
+
+#endif // STARK_GFX_OPENGL_FADE_H
diff --git a/engines/stark/gfx/openglprop.cpp b/engines/stark/gfx/openglprop.cpp
new file mode 100644
index 0000000000..decdbbcb12
--- /dev/null
+++ b/engines/stark/gfx/openglprop.cpp
@@ -0,0 +1,160 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the AUTHORS
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "engines/stark/gfx/openglprop.h"
+
+#include "engines/stark/gfx/texture.h"
+#include "engines/stark/formats/biffmesh.h"
+#include "engines/stark/scene.h"
+#include "engines/stark/services/services.h"
+
+#if defined(USE_OPENGL_GAME)
+
+namespace Stark {
+namespace Gfx {
+
+OpenGLPropRenderer::OpenGLPropRenderer(OpenGLDriver *gfx) :
+		VisualProp(),
+		_gfx(gfx),
+		_faceVBO(nullptr),
+		_modelIsDirty(true) {
+}
+
+OpenGLPropRenderer::~OpenGLPropRenderer() {
+	clearVertices();
+}
+
+void OpenGLPropRenderer::render(const Math::Vector3d &position, float direction, const LightEntryArray &lights) {
+	if (_modelIsDirty) {
+		// Update the OpenGL Buffer Objects if required
+		clearVertices();
+		uploadVertices();
+		_modelIsDirty = false;
+	}
+
+	_gfx->set3DMode();
+	_gfx->setupLights(lights);
+
+	Math::Matrix4 model = getModelMatrix(position, direction);
+	Math::Matrix4 view = StarkScene->getViewMatrix();
+	Math::Matrix4 projection = StarkScene->getProjectionMatrix();
+
+	Math::Matrix4 modelViewMatrix = view * model;
+	modelViewMatrix.transpose(); // OpenGL expects matrices transposed when compared to ScummVM's
+
+	Math::Matrix4 projectionMatrix = projection;
+	projectionMatrix.transpose(); // OpenGL expects matrices transposed when compared to ScummVM's
+
+	const Common::Array<Face> &faces = _model->getFaces();
+	const Common::Array<Material> &materials = _model->getMaterials();
+
+	for (Common::Array<Face>::const_iterator face = faces.begin(); face != faces.end(); ++face) {
+		const Material &material = materials[face->materialId];
+
+		// For each face draw its vertices from the VBO, indexed by the EBO
+		const Gfx::Texture *tex = _texture->getTexture(material.texture);
+		if (material.doubleSided)
+			glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+		else
+			glColorMaterial(GL_FRONT, GL_DIFFUSE);
+		glEnable(GL_COLOR_MATERIAL);
+		if (tex) {
+			tex->bind();
+			glColor3f(1.0f, 1.0f, 1.0f);
+		} else {
+			glBindTexture(GL_TEXTURE_2D, 0);
+			glColor3f(material.r, material.g, material.b);
+		}
+
+		auto vertexIndices = _faceEBO[face];
+
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		glEnableClientState(GL_NORMAL_ARRAY);
+
+		glVertexPointer(3, GL_FLOAT, sizeof(PropVertex), &_faceVBO[0].x);
+		if (tex)
+			glTexCoordPointer(2, GL_FLOAT, sizeof(PropVertex), &_faceVBO[0].texS);
+		glNormalPointer(GL_FLOAT, sizeof(PropVertex), &_faceVBO[0].nx);
+
+		glDrawElements(GL_TRIANGLES, face->vertexIndices.size(), GL_UNSIGNED_INT, vertexIndices);
+
+		glDisableClientState(GL_VERTEX_ARRAY);
+		glDisableClientState(GL_NORMAL_ARRAY);
+		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+		glDisable(GL_COLOR_MATERIAL);
+	}
+
+}
+
+void OpenGLPropRenderer::clearVertices() {
+	delete[] _faceVBO;
+	_faceVBO = nullptr;
+
+	for (FaceBufferMap::iterator it = _faceEBO.begin(); it != _faceEBO.end(); ++it) {
+		delete[] it->_value;
+	}
+
+	_faceEBO.clear();
+}
+
+void OpenGLPropRenderer::uploadVertices() {
+	_faceVBO = createFaceVBO();
+
+	const Common::Array<Face> &faces = _model->getFaces();
+	for (Common::Array<Face>::const_iterator face = faces.begin(); face != faces.end(); ++face) {
+		_faceEBO[face] = createFaceEBO(face);
+	}
+}
+
+PropVertex *OpenGLPropRenderer::createFaceVBO() {
+	const Common::Array<Formats::BiffMesh::Vertex> &modelVertices = _model->getVertices();
+	auto vertices = new PropVertex[modelVertices.size()];
+	// Build a vertex array
+	for (uint32 i = 0; i < modelVertices.size(); i++) {
+		vertices[i].x = modelVertices[i].position.x();
+		vertices[i].y = modelVertices[i].position.y();
+		vertices[i].z = modelVertices[i].position.z();
+		vertices[i].nx = modelVertices[i].normal.x();
+		vertices[i].ny = modelVertices[i].normal.y();
+		vertices[i].nz = modelVertices[i].normal.z();
+		vertices[i].texS = modelVertices[i].texturePosition.x();
+		vertices[i].texT = modelVertices[i].texturePosition.y();
+	}
+
+	return vertices;
+}
+
+uint32 *OpenGLPropRenderer::createFaceEBO(const Face *face) {
+	auto indices = new uint32[face->vertexIndices.size()];
+	for (uint32 index = 0; index < face->vertexIndices.size(); index++) {
+		indices[index] = face->vertexIndices[index];
+	}
+
+	return indices;
+}
+
+} // End of namespace Gfx
+} // End of namespace Stark
+
+#endif // defined(USE_OPENGL_GAME)
diff --git a/engines/stark/gfx/openglprop.h b/engines/stark/gfx/openglprop.h
new file mode 100644
index 0000000000..2c3cbe33c6
--- /dev/null
+++ b/engines/stark/gfx/openglprop.h
@@ -0,0 +1,86 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the AUTHORS
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef STARK_GFX_OPENGL_RENDERED_H
+#define STARK_GFX_OPENGL_RENDERED_H
+
+#include "engines/stark/model/model.h"
+#include "engines/stark/visual/prop.h"
+#include "engines/stark/gfx/opengl.h"
+
+#include "common/hashmap.h"
+#include "common/hash-ptr.h"
+
+#include "graphics/opengl/system_headers.h"
+
+#if defined(USE_OPENGL_GAME)
+
+namespace Stark {
+
+namespace Gfx {
+
+class Driver;
+
+#include "common/pack-start.h"
+
+struct _PropVertex {
+	float x;
+	float y;
+	float z;
+	float nx;
+	float ny;
+	float nz;
+	float texS;
+	float texT;
+} PACKED_STRUCT;
+typedef _PropVertex PropVertex;
+
+#include "common/pack-end.h"
+
+class OpenGLPropRenderer : public VisualProp {
+public:
+	explicit OpenGLPropRenderer(OpenGLDriver *gfx);
+	~OpenGLPropRenderer() override;
+
+	void render(const Math::Vector3d &position, float direction, const LightEntryArray &lights) override;
+
+protected:
+	typedef Common::HashMap<const Face *, uint32 *> FaceBufferMap;
+
+	OpenGLDriver *_gfx;
+
+	bool _modelIsDirty;
+	PropVertex *_faceVBO;
+	FaceBufferMap _faceEBO;
+
+	void clearVertices();
+	void uploadVertices();
+	PropVertex *createFaceVBO();
+	uint32 *createFaceEBO(const Face *face);
+};
+
+} // End of namespace Gfx
+} // End of namespace Stark
+
+#endif // STARK_GFX_OPENGL_S_RENDERED_H
+
+#endif // defined(USE_OPENGL_GAME)
diff --git a/engines/stark/gfx/openglsurface.cpp b/engines/stark/gfx/openglsurface.cpp
new file mode 100644
index 0000000000..a89bf16c72
--- /dev/null
+++ b/engines/stark/gfx/openglsurface.cpp
@@ -0,0 +1,136 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the AUTHORS
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "engines/stark/gfx/openglsurface.h"
+#include "engines/stark/gfx/texture.h"
+
+#if defined(USE_OPENGL_GAME)
+
+namespace Stark {
+namespace Gfx {
+
+static const GLfloat textCords[] = {
+	// S   T
+	0.0f, 0.0f,
+	1.0f, 0.0f,
+	0.0f, 1.0f,
+	1.0f, 1.0f,
+};
+
+OpenGLSurfaceRenderer::OpenGLSurfaceRenderer(OpenGLDriver *gfx) :
+		SurfaceRenderer(),
+		_gfx(gfx) {
+}
+
+OpenGLSurfaceRenderer::~OpenGLSurfaceRenderer() {
+}
+
+void OpenGLSurfaceRenderer::render(const Texture *texture, const Common::Point &dest) {
+	render(texture, dest, texture->width(), texture->height());
+}
+
+void OpenGLSurfaceRenderer::render(const Texture *texture, const Common::Point &dest, uint width, uint height) {
+	// Destination rectangle with given width and height
+	_gfx->start2DMode();
+
+	const Math::Vector2d surfaceVertices[] = {
+		// X   Y
+		{ 0.0f, 0.0f },
+		{ 1.0f, 0.0f },
+		{ 0.0f, 1.0f },
+		{ 1.0f, 1.0f },
+	};
+
+	Math::Vector2d verSizeWH;
+	if (_noScalingOverride) {
+		verSizeWH = normalizeCurrentCoordinates(width, height);
+	} else {
+		verSizeWH = normalizeOriginalCoordinates(width, height);
+	}
+	auto verOffsetXY = normalizeOriginalCoordinates(dest.x, dest.y);
+	auto nativeViewport = _gfx->getViewport();
+	auto viewport = Math::Vector2d(nativeViewport.width(), nativeViewport.height());
+
+	SurfaceVertex vertices[4] = {};
+	for (int32 v = 0; v < 4; v++) {
+		Math::Vector2d pos = verOffsetXY + (surfaceVertices[v] * verSizeWH);
+
+		if (_snapToGrid) {
+			// Align vertex coordinates to the native pixel grid
+			// This ensures text does not get garbled by nearest neighbors scaling
+			pos.setX(floor(pos.getX() * viewport.getX() + 0.5) / viewport.getX());
+			pos.setY(floor(pos.getY() * viewport.getY() + 0.5) / viewport.getY());
+		}
+
+		// position coords
+		vertices[v].x = pos.getX() * 2.0 - 1.0;
+		vertices[v].y = -1.0 * (pos.getY() * 2.0 - 1.0);
+	}
+
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glLoadIdentity();
+
+	glMatrixMode(GL_MODELVIEW);
+	glPushMatrix();
+	glLoadIdentity();
+
+	glEnable(GL_TEXTURE_2D);
+
+	glDisableClientState(GL_COLOR_ARRAY);
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glDisableClientState(GL_NORMAL_ARRAY);
+
+	glVertexPointer(2, GL_FLOAT, sizeof(SurfaceVertex), &vertices[0].x);
+	glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(float), textCords);
+	glColor3f(1.0f - _fadeLevel, 1.0f - _fadeLevel, 1.0f - _fadeLevel);
+
+	texture->bind();
+	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	glMatrixMode(GL_MODELVIEW);
+	glPopMatrix();
+
+	glMatrixMode(GL_PROJECTION);
+	glPopMatrix();
+
+	_gfx->end2DMode();
+}
+
+Math::Vector2d OpenGLSurfaceRenderer::normalizeOriginalCoordinates(int x, int y) const {
+	Common::Rect viewport = _gfx->getUnscaledViewport();
+	return Math::Vector2d(x / (float)viewport.width(), y / (float)viewport.height());
+}
+
+Math::Vector2d OpenGLSurfaceRenderer::normalizeCurrentCoordinates(int x, int y) const {
+	Common::Rect viewport = _gfx->getViewport();
+	return Math::Vector2d(x / (float)viewport.width(), y / (float)viewport.height());
+}
+
+} // End of namespace Gfx
+} // End of namespace Stark
+
+#endif // if defined(USE_OPENGL_GAME)
diff --git a/engines/stark/gfx/openglsurface.h b/engines/stark/gfx/openglsurface.h
new file mode 100644
index 0000000000..427b6fa9cf
--- /dev/null
+++ b/engines/stark/gfx/openglsurface.h
@@ -0,0 +1,73 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the AUTHORS
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef STARK_GFX_OPENGL_SURFACE_H
+#define STARK_GFX_OPENGL_SURFACE_H
+
+#include "engines/stark/gfx/surfacerenderer.h"
+#include "engines/stark/gfx/opengl.h"
+
+#include "math/vector2d.h"
+
+#if defined(USE_OPENGL_GAME)
+
+namespace Stark {
+namespace Gfx {
+
+class OpenGLDriver;
+class Texture;
+
+#include "common/pack-start.h"
+
+struct _SurfaceVertex {
+	float x;
+	float y;
+} PACKED_STRUCT;
+typedef _SurfaceVertex SurfaceVertex;
+
+#include "common/pack-end.h"
+
+/**
+ * An programmable pipeline OpenGL surface renderer
+ */
+class OpenGLSurfaceRenderer : public SurfaceRenderer {
+public:
+	OpenGLSurfaceRenderer(OpenGLDriver *gfx);
+	virtual ~OpenGLSurfaceRenderer();
+
+	// SurfaceRenderer API
+	void render(const Texture *texture, const Common::Point &dest) override;
+	void render(const Texture *texture, const Common::Point &dest, uint width, uint height) override;
+
+private:
+	Math::Vector2d normalizeOriginalCoordinates(int x, int y) const;
+	Math::Vector2d normalizeCurrentCoordinates(int x, int y) const;
+
+	OpenGLDriver *_gfx;
+};
+
+} // End of namespace Gfx
+} // End of namespace Stark
+
+#endif // defined(USE_OPENGL_GAME)
+
+#endif // STARK_GFX_OPENGL_SURFACE_H
diff --git a/engines/stark/module.mk b/engines/stark/module.mk
index 1bfca1b09b..2ce9615d19 100644
--- a/engines/stark/module.mk
+++ b/engines/stark/module.mk
@@ -9,6 +9,11 @@ MODULE_OBJS := \
 	gfx/openglsfade.o \
 	gfx/openglsprop.o \
 	gfx/openglssurface.o \
+	gfx/opengl.o \
+	gfx/openglactor.o \
+	gfx/openglfade.o \
+	gfx/openglprop.o \
+	gfx/openglsurface.o \
 	gfx/opengltexture.o \
 	gfx/renderentry.o \
 	gfx/surfacerenderer.o \




More information about the Scummvm-git-logs mailing list