[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