[Scummvm-git-logs] scummvm master -> b483f9f22b6212981cfe4e362e1bb75c4b579ee8
Helco
noreply at scummvm.org
Sun Sep 14 06:43:01 UTC 2025
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
b483f9f22b ALCACHOFA: Add TinyGLRenderer
Commit: b483f9f22b6212981cfe4e362e1bb75c4b579ee8
https://github.com/scummvm/scummvm/commit/b483f9f22b6212981cfe4e362e1bb75c4b579ee8
Author: Helco (hermann.noll at hotmail.com)
Date: 2025-09-14T08:42:48+02:00
Commit Message:
ALCACHOFA: Add TinyGLRenderer
Changed paths:
A engines/alcachofa/graphics-tinygl.cpp
engines/alcachofa/configure.engine
engines/alcachofa/graphics-opengl-classic.cpp
engines/alcachofa/graphics-opengl-shaders.cpp
engines/alcachofa/graphics-opengl.cpp
engines/alcachofa/graphics-opengl.h
engines/alcachofa/module.mk
diff --git a/engines/alcachofa/configure.engine b/engines/alcachofa/configure.engine
index 3904b6543c3..d1f40219a55 100644
--- a/engines/alcachofa/configure.engine
+++ b/engines/alcachofa/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine alcachofa "Alcachofa" no "" "" "highres opengl_game_classic mpeg2"
+add_engine alcachofa "Alcachofa" no "" "" "highres mpeg2" "tinygl"
diff --git a/engines/alcachofa/graphics-opengl-classic.cpp b/engines/alcachofa/graphics-opengl-classic.cpp
index 53e21ce3bc1..df10ab5ea13 100644
--- a/engines/alcachofa/graphics-opengl-classic.cpp
+++ b/engines/alcachofa/graphics-opengl-classic.cpp
@@ -40,6 +40,7 @@ public:
GL_CALL(glDisableClientState(GL_INDEX_ARRAY));
GL_CALL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
resetState();
+ _currentTexture = nullptr;
}
void setTexture(ITexture *texture) override {
diff --git a/engines/alcachofa/graphics-opengl-shaders.cpp b/engines/alcachofa/graphics-opengl-shaders.cpp
index ea12fd0ee16..2f06d294544 100644
--- a/engines/alcachofa/graphics-opengl-shaders.cpp
+++ b/engines/alcachofa/graphics-opengl-shaders.cpp
@@ -65,7 +65,7 @@ public:
for (int i = 0; i < 4; i++)
_vbos.emplace_back(Shader::createBuffer(GL_ARRAY_BUFFER, 0, nullptr, GL_STREAM_DRAW));
- _vertices.resize(8 * 6);
+ _vertices.resize(8 * 6); // heuristic, we should be lucky if we can batch 8 quads together
_whiteTexture.reset(new OpenGLTexture(1, 1, false));
const byte whiteData[] = { 0xff, 0xff, 0xff, 0xff };
@@ -74,6 +74,7 @@ public:
void begin() override {
resetState();
+ _currentTexture = nullptr;
_needsNewBatch = true;
}
diff --git a/engines/alcachofa/graphics-opengl.cpp b/engines/alcachofa/graphics-opengl.cpp
index 5d5eb1401df..57e7f4866be 100644
--- a/engines/alcachofa/graphics-opengl.cpp
+++ b/engines/alcachofa/graphics-opengl.cpp
@@ -45,24 +45,15 @@ static bool isCompatibleFormat(const PixelFormat &format) {
areComponentsInOrder(format, 3, 2, 1, 0);
}
-OpenGLTexture::OpenGLTexture(int32 w, int32 h, bool withMipmaps)
- : ITexture({ (int16)w, (int16)h })
- , _withMipmaps(withMipmaps) {
- glEnable(GL_TEXTURE_2D); // will error on GLES2, but that is okay
- OpenGL::clearGLError(); // we will just ignore it
- GL_CALL(glGenTextures(1, &_handle));
- GL_CALL(glBindTexture(GL_TEXTURE_2D, _handle));
- GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
- GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
- setMirrorWrap(false);
-}
+//
+// Base classes, no calls to gl* or tgl* in this area
+//
-OpenGLTexture::~OpenGLTexture() {
- if (_handle != 0)
- GL_CALL(glDeleteTextures(1, &_handle));
-}
+OpenGLTextureBase::OpenGLTextureBase(int32 w, int32 h, bool withMipmaps)
+ : ITexture({ (int16)w, (int16)h })
+ , _withMipmaps(withMipmaps) { }
-void OpenGLTexture::update(const Surface &surface) {
+void OpenGLTextureBase::update(const Surface &surface) {
assert(isCompatibleFormat(surface.format));
assert(surface.w == size().x && surface.h == size().y);
@@ -83,17 +74,10 @@ void OpenGLTexture::update(const Surface &surface) {
surface.format);
pixels = _tmpSurface.getPixels();
} else {
- glEnable(GL_TEXTURE_2D);
- OpenGL::clearGLError();
pixels = surface.getPixels();
}
- GL_CALL(glBindTexture(GL_TEXTURE_2D, _handle));
- GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface.w, surface.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
- if (_withMipmaps)
- GL_CALL(glGenerateMipmap(GL_TEXTURE_2D));
- else
- GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
+ updateInner(pixels);
if (!_tmpSurface.empty()) {
if (!_didConvertOnce)
@@ -102,6 +86,80 @@ void OpenGLTexture::update(const Surface &surface) {
}
}
+OpenGLRendererBase::OpenGLRendererBase(Point resolution) : _resolution(resolution) {}
+
+bool OpenGLRendererBase::hasOutput() const {
+ return _currentOutput != nullptr;
+}
+
+void OpenGLRendererBase::resetState() {
+ setViewportToScreen();
+ _currentOutput = nullptr;
+ _currentLodBias = -1000.0f;
+ _currentBlendMode = (BlendMode)-1;
+ _isFirstDrawCommand = true;
+}
+
+void OpenGLRendererBase::setViewportToScreen() {
+ int32 screenWidth = g_system->getWidth();
+ int32 screenHeight = g_system->getHeight();
+ Rect viewport(
+ MIN<int32>(screenWidth, screenHeight * (float)_resolution.x / _resolution.y),
+ MIN<int32>(screenHeight, screenWidth * (float)_resolution.y / _resolution.x));
+ viewport.translate(
+ (screenWidth - viewport.width()) / 2,
+ (screenHeight - viewport.height()) / 2);
+
+ setViewportInner(viewport.left, viewport.top, viewport.width(), viewport.height());
+ setMatrices(true);
+}
+
+void OpenGLRendererBase::setViewportToRect(int16 outputWidth, int16 outputHeight) {
+ _outputSize.x = MIN(outputWidth, g_system->getWidth());
+ _outputSize.y = MIN(outputHeight, g_system->getHeight());
+ setViewportInner(0, 0, _outputSize.x, _outputSize.y);
+ setMatrices(false);
+}
+
+void OpenGLRendererBase::getQuadPositions(Vector2d topLeft, Vector2d size, Angle rotation, Vector2d positions[]) const {
+ positions[0] = topLeft + Vector2d(0, 0);
+ positions[1] = topLeft + Vector2d(0, +size.getY());
+ positions[2] = topLeft + Vector2d(+size.getX(), +size.getY());
+ positions[3] = topLeft + Vector2d(+size.getX(), 0);
+ if (abs(rotation.getDegrees()) > epsilon) {
+ const Vector2d zero(0, 0);
+ for (int i = 0; i < 4; i++)
+ positions[i].rotateAround(zero, rotation);
+ }
+}
+
+void OpenGLRendererBase::getQuadTexCoords(Vector2d texMin, Vector2d texMax, Vector2d texCoords[]) const {
+ texCoords[0] = { texMin.getX(), texMin.getY() };
+ texCoords[1] = { texMin.getX(), texMax.getY() };
+ texCoords[2] = { texMax.getX(), texMax.getY() };
+ texCoords[3] = { texMax.getX(), texMin.getY() };
+}
+
+OpenGLTexture::OpenGLTexture(int32 w, int32 h, bool withMipmaps)
+ : OpenGLTextureBase(w, h, withMipmaps) {
+ glEnable(GL_TEXTURE_2D); // will error on GLES2, but that is okay
+ OpenGL::clearGLError(); // we will just ignore it
+ GL_CALL(glGenTextures(1, &_handle));
+ GL_CALL(glBindTexture(GL_TEXTURE_2D, _handle));
+ GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
+ GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+ setMirrorWrap(false);
+}
+
+//
+// OpenGL classes, calls to gl* are allowed here
+//
+
+OpenGLTexture::~OpenGLTexture() {
+ if (_handle != 0)
+ GL_CALL(glDeleteTextures(1, &_handle));
+}
+
void OpenGLTexture::setMirrorWrap(bool wrap) {
if (_mirrorWrap == wrap)
return;
@@ -110,14 +168,29 @@ void OpenGLTexture::setMirrorWrap(bool wrap) {
if (wrap)
wrapMode = OpenGLContext.textureMirrorRepeatSupported ? GL_MIRRORED_REPEAT : GL_REPEAT;
else
+#if USE_FORCED_GLES2 // GLES2 does not define GL_CLAMP
+ wrapMode = GL_CLAMP_TO_EDGE;
+#else
wrapMode = OpenGLContext.textureEdgeClampSupported ? GL_CLAMP_TO_EDGE : GL_CLAMP;
+#endif
GL_CALL(glBindTexture(GL_TEXTURE_2D, _handle));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode));
}
-OpenGLRenderer::OpenGLRenderer(Point resolution) : _resolution(resolution) {
+void OpenGLTexture::updateInner(const void *pixels) {
+ glEnable(GL_TEXTURE_2D);
+ OpenGL::clearGLError();
+ GL_CALL(glBindTexture(GL_TEXTURE_2D, _handle));
+ GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size().x, size().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
+ if (_withMipmaps)
+ GL_CALL(glGenerateMipmap(GL_TEXTURE_2D));
+ else
+ GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
+}
+
+OpenGLRenderer::OpenGLRenderer(Point resolution) : OpenGLRendererBase(resolution) {
initGraphics3d(resolution.x, resolution.y);
GL_CALL(glDisable(GL_DEPTH_TEST));
GL_CALL(glDisable(GL_SCISSOR_TEST));
@@ -136,15 +209,6 @@ ScopedPtr<ITexture> OpenGLRenderer::createTexture(int32 w, int32 h, bool withMip
return ScopedPtr<ITexture>(new OpenGLTexture(w, h, withMipmaps));
}
-void OpenGLRenderer::resetState() {
- setViewportToScreen();
- _currentOutput = nullptr;
- _currentLodBias = -1000.0f;
- _currentTexture = nullptr;
- _currentBlendMode = (BlendMode)-1;
- _isFirstDrawCommand = true;
-}
-
void OpenGLRenderer::end() {
GL_CALL(glFlush());
@@ -214,34 +278,13 @@ void OpenGLRenderer::setOutput(Surface &output) {
}
}
-bool OpenGLRenderer::hasOutput() const {
- return _currentOutput != nullptr;
-}
-
-void OpenGLRenderer::setViewportToScreen() {
- int32 screenWidth = g_system->getWidth();
- int32 screenHeight = g_system->getHeight();
- Rect viewport(
- MIN<int32>(screenWidth, screenHeight * (float)_resolution.x / _resolution.y),
- MIN<int32>(screenHeight, screenWidth * (float)_resolution.y / _resolution.x));
- viewport.translate(
- (screenWidth - viewport.width()) / 2,
- (screenHeight - viewport.height()) / 2);
-
- GL_CALL(glViewport(viewport.left, viewport.top, viewport.width(), viewport.height()));
- setMatrices(true);
-}
-
-void OpenGLRenderer::setViewportToRect(int16 outputWidth, int16 outputHeight) {
- _outputSize.x = MIN(outputWidth, g_system->getWidth());
- _outputSize.y = MIN(outputHeight, g_system->getHeight());
- GL_CALL(glViewport(0, 0, _outputSize.x, _outputSize.y));
- setMatrices(false);
+void OpenGLRenderer::setViewportInner(int x, int y, int width, int height) {
+ GL_CALL(glViewport(x, y, width, height));
}
void OpenGLRenderer::checkFirstDrawCommand() {
// We delay clearing the screen. It is much easier for the game
- // to switch to a framebuffer before
+ // to switch to a framebuffer before
if (!_isFirstDrawCommand)
return;
_isFirstDrawCommand = false;
@@ -249,27 +292,8 @@ void OpenGLRenderer::checkFirstDrawCommand() {
GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
}
-void OpenGLRenderer::getQuadPositions(Vector2d topLeft, Vector2d size, Angle rotation, Vector2d positions[]) const {
- positions[0] = topLeft + Vector2d(0, 0);
- positions[1] = topLeft + Vector2d(0, +size.getY());
- positions[2] = topLeft + Vector2d(+size.getX(), +size.getY());
- positions[3] = topLeft + Vector2d(+size.getX(), 0);
- if (abs(rotation.getDegrees()) > epsilon) {
- const Vector2d zero(0, 0);
- for (int i = 0; i < 4; i++)
- positions[i].rotateAround(zero, rotation);
- }
-}
-
-void OpenGLRenderer::getQuadTexCoords(Vector2d texMin, Vector2d texMax, Vector2d texCoords[]) const {
- texCoords[0] = { texMin.getX(), texMin.getY() };
- texCoords[1] = { texMin.getX(), texMax.getY() };
- texCoords[2] = { texMax.getX(), texMax.getY() };
- texCoords[3] = { texMax.getX(), texMin.getY() };
-}
-
IRenderer *IRenderer::createOpenGLRenderer(Point resolution) {
- const auto available = Renderer::getAvailableTypes() & ~kRendererTypeTinyGL;
+ const auto available = Renderer::getAvailableTypes();
const auto &rendererCode = ConfMan.get("renderer");
RendererType rendererType = Renderer::parseTypeCode(rendererCode);
rendererType = (RendererType)(rendererType & available);
@@ -282,11 +306,16 @@ IRenderer *IRenderer::createOpenGLRenderer(Point resolution) {
case kRendererTypeOpenGL:
renderer = createOpenGLRendererClassic(resolution);
break;
+ case kRendererTypeTinyGL:
+ renderer = createTinyGLRenderer(resolution);
+ break;
default:
if (available & kRendererTypeOpenGLShaders)
renderer = createOpenGLRendererShaders(resolution);
else if (available & kRendererTypeOpenGL)
renderer = createOpenGLRendererClassic(resolution);
+ else if (available & kRendererTypeTinyGL)
+ renderer = createTinyGLRenderer(resolution);
break;
}
@@ -309,4 +338,11 @@ IRenderer *createOpenGLRendererClassic(Point _) {
}
#endif
+#ifndef USE_TINYGL
+IRenderer *createTinyGLRenderer(Point _) {
+ (void)_;
+ return nullptr;
+}
+#endif
+
}
diff --git a/engines/alcachofa/graphics-opengl.h b/engines/alcachofa/graphics-opengl.h
index 92c842a4826..6badc386fb3 100644
--- a/engines/alcachofa/graphics-opengl.h
+++ b/engines/alcachofa/graphics-opengl.h
@@ -30,52 +30,78 @@
namespace Alcachofa {
-class OpenGLTexture : public ITexture {
+/** This base class does not call any gl* functions so we can use it for TinyGL as well */
+class OpenGLTextureBase : public ITexture {
public:
- OpenGLTexture(int32 w, int32 h, bool withMipmaps);
- ~OpenGLTexture() override;
+ OpenGLTextureBase(int32 w, int32 h, bool withMipmaps);
+ ~OpenGLTextureBase() override = default;
void update(const Graphics::Surface &surface) override;
- void setMirrorWrap(bool wrap);
inline GLuint handle() const { return _handle; }
-private:
- GLuint _handle;
+protected:
+ virtual void updateInner(const void *pixels) = 0; ///< expects pixels to be RGBA32
+
+ GLuint _handle = 0;
bool _withMipmaps;
bool _mirrorWrap = true;
bool _didConvertOnce = false;
Graphics::ManagedSurface _tmpSurface;
};
-class OpenGLRenderer : public virtual IRenderer {
+class OpenGLTexture : public OpenGLTextureBase {
public:
- OpenGLRenderer(Common::Point resolution);
+ OpenGLTexture(int32 w, int32 h, bool withMipmaps);
+ ~OpenGLTexture() override;
+
+ void setMirrorWrap(bool wrap);
+
+protected:
+ void updateInner(const void *pixels) override;
+};
+
+class OpenGLRendererBase : public virtual IRenderer {
+public:
+ OpenGLRendererBase(Common::Point resolution);
- Common::ScopedPtr<ITexture> createTexture(int32 w, int32 h, bool withMipmaps) override;
- void end() override;
- void setOutput(Graphics::Surface &output) override;
bool hasOutput() const override;
protected:
+ virtual void setViewportInner(int x, int y, int width, int height) = 0;
+ virtual void setMatrices(bool flipped) = 0;
+
void resetState();
- void setBlendFunc(BlendMode blendMode); ///< just the blend-func, not texenv/shader uniform
void setViewportToScreen();
void setViewportToRect(int16 outputWidth, int16 outputHeight);
- virtual void setMatrices(bool flipped) = 0;
- void checkFirstDrawCommand();
void getQuadPositions(Math::Vector2d topLeft, Math::Vector2d size, Math::Angle rotation, Math::Vector2d positions[]) const;
void getQuadTexCoords(Math::Vector2d texMin, Math::Vector2d texMax, Math::Vector2d texCoords[]) const;
Common::Point _resolution, _outputSize;
Graphics::Surface *_currentOutput = nullptr;
- OpenGLTexture *_currentTexture = nullptr;
BlendMode _currentBlendMode = (BlendMode)-1;
float _currentLodBias = 0.0f;
bool _isFirstDrawCommand = false;
};
+class OpenGLRenderer : public OpenGLRendererBase {
+public:
+ OpenGLRenderer(Common::Point resolution);
+
+ Common::ScopedPtr<ITexture> createTexture(int32 w, int32 h, bool withMipmaps) override;
+ void end() override;
+ void setOutput(Graphics::Surface &output) override;
+
+protected:
+ void setViewportInner(int x, int y, int width, int height) override;
+ void setBlendFunc(BlendMode blendMode); ///< just the blend-func, not texenv/shader uniform
+ void checkFirstDrawCommand();
+
+ OpenGLTexture *_currentTexture = nullptr;
+};
+
IRenderer *createOpenGLRendererClassic(Common::Point resolution);
IRenderer *createOpenGLRendererShaders(Common::Point resolution);
+IRenderer *createTinyGLRenderer(Common::Point resolution);
}
diff --git a/engines/alcachofa/graphics-tinygl.cpp b/engines/alcachofa/graphics-tinygl.cpp
new file mode 100644
index 00000000000..3c28184d44c
--- /dev/null
+++ b/engines/alcachofa/graphics-tinygl.cpp
@@ -0,0 +1,290 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "alcachofa/graphics.h"
+#include "alcachofa/detection.h"
+#include "alcachofa/graphics-opengl.h"
+
+#include "common/system.h"
+#include "common/config-manager.h"
+#include "engines/util.h"
+#include "graphics/tinygl/tinygl.h"
+
+using namespace Common;
+using namespace Math;
+using namespace Graphics;
+
+namespace Alcachofa {
+
+class TinyGLTexture : public OpenGLTextureBase {
+public:
+ TinyGLTexture(int32 w, int32 h, bool withMipmaps)
+ : OpenGLTextureBase(w, h, withMipmaps) {
+ tglEnable(TGL_TEXTURE_2D);
+ tglGenTextures(1, &_handle);
+ tglBindTexture(TGL_TEXTURE_2D, _handle);
+ tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MIN_FILTER, TGL_LINEAR_MIPMAP_LINEAR);
+ tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MAG_FILTER, TGL_LINEAR);
+ tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_WRAP_S, TGL_MIRRORED_REPEAT);
+ tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_WRAP_T, TGL_MIRRORED_REPEAT);
+ }
+
+ ~TinyGLTexture() override {
+ if (_handle != 0)
+ tglDeleteTextures(1, &_handle);
+ }
+
+protected:
+ void updateInner(const void *pixels) override {
+ tglEnable(TGL_TEXTURE_2D);
+ tglBindTexture(TGL_TEXTURE_2D, _handle);
+ tglTexImage2D(TGL_TEXTURE_2D, 0, TGL_RGBA, size().x, size().y, 0, TGL_RGBA, TGL_UNSIGNED_BYTE, pixels);
+ if (_withMipmaps && false)
+ warning("NO TINYGL MIPMAPS IMPLEMENTED YET");
+ else
+ tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MAX_LEVEL, 0);
+ }
+};
+
+class TinyGLRenderer : public OpenGLRendererBase {
+public:
+ TinyGLRenderer(Point resolution) : OpenGLRendererBase(resolution) {
+ initGraphics(resolution.x, resolution.y, nullptr);
+ debug("Using framebuffer format: %s", g_system->getScreenFormat().toString().c_str());
+ if (g_system->getScreenFormat().bytesPerPixel < 2)
+ error("Alcachofa needs at least 16bit colors");
+ _context = TinyGL::createContext(
+ resolution.x, resolution.y,
+ g_system->getScreenFormat(),
+ 1024, // some background images are even larger than this
+ false, false);
+ TinyGL::setContext(_context);
+
+ tglDisable(TGL_DEPTH_TEST);
+ tglDisable(TGL_SCISSOR_TEST);
+ tglDisable(TGL_STENCIL_TEST);
+ tglDisable(TGL_CULL_FACE);
+ tglEnable(TGL_BLEND);
+ tglDepthMask(TGL_FALSE);
+ }
+
+ ~TinyGLRenderer() override {
+ if (_context != nullptr)
+ TinyGL::destroyContext(_context);
+ }
+
+ ScopedPtr<ITexture> createTexture(int32 w, int32 h, bool withMipmaps) override {
+ assert(w >= 0 && h >= 0);
+ return ScopedPtr<ITexture>(new TinyGLTexture(w, h, withMipmaps));
+ }
+
+ void begin() override {
+ resetState();
+ _currentTexture = nullptr;
+ }
+
+ void setTexture(ITexture *texture) override {
+ if (texture == _currentTexture)
+ return;
+ else if (texture == nullptr) {
+ tglDisable(TGL_TEXTURE_2D);
+ _currentTexture = nullptr;
+ } else {
+ if (_currentTexture == nullptr) {
+ tglEnable(TGL_TEXTURE_2D);
+ }
+ auto glTexture = dynamic_cast<TinyGLTexture *>(texture);
+ assert(glTexture != nullptr);
+ tglBindTexture(TGL_TEXTURE_2D, glTexture->handle());
+ _currentTexture = glTexture;
+ }
+ }
+
+ void setBlendMode(BlendMode blendMode) override {
+ if (blendMode == _currentBlendMode)
+ return;
+ switch (blendMode) {
+ case BlendMode::AdditiveAlpha:
+ tglBlendFunc(TGL_ONE, TGL_ONE_MINUS_SRC_ALPHA);
+ break;
+ case BlendMode::Additive:
+ tglBlendFunc(TGL_ONE, TGL_ONE);
+ break;
+ case BlendMode::Multiply:
+ tglBlendFunc(TGL_DST_COLOR, TGL_ONE);
+ break;
+ case BlendMode::Alpha:
+ tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
+ break;
+ case BlendMode::Tinted:
+ tglBlendFunc(TGL_ONE, TGL_ONE_MINUS_SRC_ALPHA);
+ break;
+ default: assert(false && "Invalid blend mode"); break;
+ }
+
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_COMBINE);
+ switch (blendMode) {
+ case BlendMode::AdditiveAlpha:
+ case BlendMode::Additive:
+ case BlendMode::Multiply:
+ // TintAlpha * TexColor, TexAlpha
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_COMBINE_RGB, TGL_MODULATE);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_COMBINE_ALPHA, TGL_REPLACE);
+
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_SOURCE0_RGB, TGL_TEXTURE);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_OPERAND0_RGB, TGL_SRC_COLOR);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_SOURCE0_ALPHA, TGL_TEXTURE);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_OPERAND0_ALPHA, TGL_SRC_ALPHA);
+
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_SOURCE1_RGB, TGL_PRIMARY_COLOR);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_OPERAND1_RGB, TGL_SRC_ALPHA); // alpha replaces color
+ break;
+ case BlendMode::Alpha:
+ // TexColor, TintAlpha
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_COMBINE_RGB, TGL_REPLACE);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_COMBINE_ALPHA, TGL_REPLACE);
+
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_SOURCE0_RGB, TGL_TEXTURE);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_OPERAND0_RGB, TGL_SRC_COLOR);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_SOURCE0_ALPHA, TGL_PRIMARY_COLOR);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_OPERAND0_ALPHA, TGL_SRC_ALPHA);
+ break;
+ case BlendMode::Tinted:
+ // (TintColor * TintAlpha) * TexColor, TexAlpha
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_COMBINE_RGB, TGL_MODULATE);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_COMBINE_ALPHA, TGL_REPLACE);
+
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_SOURCE0_RGB, TGL_TEXTURE);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_OPERAND0_RGB, TGL_SRC_COLOR);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_SOURCE0_ALPHA, TGL_TEXTURE);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_OPERAND0_ALPHA, TGL_SRC_ALPHA);
+
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_SOURCE1_RGB, TGL_PRIMARY_COLOR);
+ tglTexEnvi(TGL_TEXTURE_ENV, TGL_OPERAND1_RGB, TGL_SRC_COLOR); // we have to pre-multiply
+ break;
+ default:
+ assert(false && "Invalid blend mode");
+ break;
+ }
+ _currentBlendMode = blendMode;
+ }
+
+ void setLodBias(float lodBias) override {
+ _currentLodBias = lodBias;
+ // TinyGL does not support lod bias
+ }
+
+ void setOutput(Surface &output) override {
+ assert(_isFirstDrawCommand);
+ setViewportToRect(output.w, output.h);
+ _currentOutput = &output;
+
+ if (output.w > _resolution.x || output.h > _resolution.y)
+ debugC(0, kDebugGraphics, "Output is larger than screen, output will be cropped (%d, %d) > (%d, %d)",
+ output.w, output.h, _resolution.x, _resolution.y);
+
+ // no need to check format for TinyGL, we need to be prepared for conversion anyways
+ }
+
+ void end() override {
+ tglFlush();
+ TinyGL::presentBuffer();
+
+ Surface framebuffer;
+ TinyGL::getSurfaceRef(framebuffer);
+ if (_currentOutput == nullptr) {
+ g_system->copyRectToScreen(framebuffer.getPixels(), framebuffer.pitch, 0, 0, framebuffer.w, framebuffer.h);
+ g_system->updateScreen();
+ } else {
+ framebuffer = framebuffer.getSubArea(Rect(0, 0, _currentOutput->w, _currentOutput->h));
+ crossBlit(
+ (byte *)_currentOutput->getPixels(),
+ (const byte *)framebuffer.getPixels(),
+ _currentOutput->pitch,
+ framebuffer.pitch,
+ framebuffer.w,
+ framebuffer.h,
+ _currentOutput->format,
+ framebuffer.format);
+ }
+ }
+
+ void quad(
+ Vector2d topLeft,
+ Vector2d size,
+ Color color,
+ Angle rotation,
+ Vector2d texMin,
+ Vector2d texMax) override {
+ Vector2d positions[4], texCoords[4];
+ getQuadPositions(topLeft, size, rotation, positions);
+ getQuadTexCoords(texMin, texMax, texCoords);
+
+ float colors[] = { color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f };
+ if (_currentBlendMode == BlendMode::Tinted) {
+ colors[0] *= colors[3];
+ colors[1] *= colors[3];
+ colors[2] *= colors[3];
+ }
+
+ if (_isFirstDrawCommand) {
+ _isFirstDrawCommand = false;
+ tglClearColor(0, 0, 0, 0);
+ tglClear(TGL_COLOR_BUFFER_BIT);
+ }
+
+ tglColor4fv(colors);
+ tglBegin(TGL_QUADS);
+ for (int i = 0; i < 4; i++) {
+ tglTexCoord2f(texCoords[i].getX(), texCoords[i].getY());
+ tglVertex2f(positions[i].getX(), positions[i].getY());
+ }
+ tglEnd();
+ TinyGL::presentBuffer();
+ }
+
+protected:
+ void setViewportInner(int x, int y, int width, int height) override {
+ tglViewport(x, y, width, height);
+ }
+
+ void setMatrices(bool flipped) override {
+ float bottom = flipped ? _resolution.y : 0.0f;
+ float top = flipped ? 0.0f : _resolution.y;
+
+ tglMatrixMode(TGL_PROJECTION);
+ tglLoadIdentity();
+ tglOrtho(0.0f, _resolution.x, bottom, top, -1.0f, 1.0f);
+ tglMatrixMode(TGL_MODELVIEW);
+ tglLoadIdentity();
+ }
+
+private:
+ TinyGL::ContextHandle *_context = nullptr;
+ TinyGLTexture *_currentTexture = nullptr;
+};
+
+IRenderer *createTinyGLRenderer(Point resolution) {
+ debug("Use TinyGL renderer");
+ return new TinyGLRenderer(resolution);
+}
+
+}
diff --git a/engines/alcachofa/module.mk b/engines/alcachofa/module.mk
index 575ad2fa363..d4e01639654 100644
--- a/engines/alcachofa/module.mk
+++ b/engines/alcachofa/module.mk
@@ -33,6 +33,11 @@ MODULE_OBJS += \
graphics-opengl-shaders.o
endif
+ifdef USE_TINYGL
+MODULE_OBJS += \
+ graphics-tinygl.o
+endif
+
# This module can be built as a plugin
ifeq ($(ENABLE_ALCACHOFA), DYNAMIC_PLUGIN)
PLUGIN := 1
More information about the Scummvm-git-logs
mailing list