/* 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 . * */ // Based on Phantasma code by Thomas Harte (2013), // available at https://github.com/TomHarte/Phantasma/ (MIT) #include "common/config-manager.h" #include "common/system.h" #include "math/glmath.h" #include "freescape/objects/object.h" #include "freescape/gfx_opengl_shaders.h" #include "freescape/gfx_opengl_texture.h" namespace Freescape { static const GLfloat bitmapVertices[] = { // XS YT 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, }; Renderer *CreateGfxOpenGLShader(int screenW, int screenH, Common::RenderMode renderMode, bool authenticGraphics) { return new OpenGLShaderRenderer(screenW, screenH, renderMode, authenticGraphics); } OpenGLShaderRenderer::OpenGLShaderRenderer(int screenW, int screenH, Common::RenderMode renderMode, bool authenticGraphics) : Renderer(screenW, screenH, renderMode, authenticGraphics) { _verts = nullptr; _triangleShader = nullptr; _triangleVBO = 0; _bitmapShader = nullptr; _bitmapVBO = 0; _cubemapShader = nullptr; _cubemapVertVBO = 0; _cubemapTexCoordVBO = 0; _cubemapEBO = 0; _texturePixelFormat = getRGBAPixelFormat(); _isAccelerated = true; } OpenGLShaderRenderer::~OpenGLShaderRenderer() { OpenGL::Shader::freeBuffer(_triangleVBO); delete _triangleShader; OpenGL::Shader::freeBuffer(_bitmapVBO); delete _bitmapShader; OpenGL::Shader::freeBuffer(_cubemapVertVBO); OpenGL::Shader::freeBuffer(_cubemapTexCoordVBO); OpenGL::Shader::freeBuffer(_cubemapEBO); delete _cubemapShader; free(_verts); } Texture *OpenGLShaderRenderer::createTexture(const Graphics::Surface *surface, bool is3D) { return new OpenGLTexture(surface); } void OpenGLShaderRenderer::freeTexture(Texture *texture) { delete texture; } Common::Point OpenGLShaderRenderer::nativeResolution() { GLint vect[4]; glGetIntegerv(GL_VIEWPORT, vect); return Common::Point(vect[2], vect[3]); } void OpenGLShaderRenderer::init() { computeScreenViewport(); _verts = (Vertex *)malloc(sizeof(Vertex) * kVertexArraySize); static const char *triangleAttributes[] = { "position", nullptr }; _triangleShader = OpenGL::Shader::fromFiles("freescape_triangle", triangleAttributes); _triangleVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(Vertex) * kVertexArraySize, _verts, GL_DYNAMIC_DRAW); // TODO: Check if 3 * sizeof(float) == sizeof(Vertex) _triangleShader->enableVertexAttribute("position", _triangleVBO, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0); static const char *bitmapAttributes[] = { "position", "texcoord", nullptr }; _bitmapShader = OpenGL::Shader::fromFiles("freescape_bitmap", bitmapAttributes); _bitmapVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(bitmapVertices), bitmapVertices); _bitmapShader->enableVertexAttribute("position", _bitmapVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0); _bitmapShader->enableVertexAttribute("texcoord", _bitmapVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0); static const char *cubemapAttributes[] = { "position", "texcoord", nullptr }; _cubemapShader = OpenGL::Shader::fromFiles("freescape_cubemap", cubemapAttributes); _cubemapVertVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(_skyVertices), _skyVertices); _cubemapTexCoordVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(_skyUvs1008), _skyUvs1008); _cubemapEBO = OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(_skyIndices), _skyIndices); _cubemapShader->enableVertexAttribute("position", _cubemapVertVBO, 3, GL_FLOAT, GL_TRUE, 3 * sizeof(float), 0); _cubemapShader->enableVertexAttribute("texcoord", _cubemapTexCoordVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0); // populate default stipple data for shader rendering for (int i = 0; i < 128; i++) _defaultShaderStippleArray[i] = _defaultStippleArray[i]; glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glEnable(GL_SCISSOR_TEST); setViewport(_viewport); } void OpenGLShaderRenderer::setViewport(const Common::Rect &rect) { _viewport = Common::Rect( _screenViewport.width() * rect.width() / _screenW, _screenViewport.height() * rect.height() / _screenH ); _viewport.translate( _screenViewport.left + _screenViewport.width() * rect.left / _screenW, _screenViewport.top + _screenViewport.height() * rect.top / _screenH ); _unscaledViewport = rect; glViewport(_viewport.left, g_system->getHeight() - _viewport.bottom, _viewport.width(), _viewport.height()); glScissor(_viewport.left, g_system->getHeight() - _viewport.bottom, _viewport.width(), _viewport.height()); } void OpenGLShaderRenderer::drawTexturedRect2D(const Common::Rect &screenRect, const Common::Rect &textureRect, Texture *texture) { OpenGLTexture *glTexture = static_cast(texture); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); _bitmapShader->use(); _bitmapShader->setUniform("flipY", glTexture->_upsideDown); glDepthMask(GL_FALSE); glBindTexture(GL_TEXTURE_2D, glTexture->_id); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisable(GL_BLEND); glDepthMask(GL_TRUE); _bitmapShader->unbind(); } void OpenGLShaderRenderer::drawSkybox(Texture *texture, Math::Vector3d camera) { OpenGLTexture *glTexture = static_cast(texture); Math::Matrix4 proj = _projectionMatrix; Math::Matrix4 model = _modelViewMatrix; // remove translation model(3, 0) = 0.0f; model(3, 1) = 0.0f; model(3, 2) = 0.0f; proj.transpose(); model.transpose(); Math::Matrix4 skyboxMVP = proj * model; skyboxMVP.transpose(); _cubemapShader->use(); _cubemapShader->setUniform("mvpMatrix", skyboxMVP); glDisable(GL_DEPTH_TEST); glBindBuffer(GL_ARRAY_BUFFER, _cubemapTexCoordVBO); if (texture->_width == 1008) glBufferData(GL_ARRAY_BUFFER, sizeof(_skyUvs1008), _skyUvs1008, GL_DYNAMIC_DRAW); else if (texture->_width == 128) glBufferData(GL_ARRAY_BUFFER, sizeof(_skyUvs128), _skyUvs128, GL_DYNAMIC_DRAW); else error("Unsupported skybox texture width %d", texture->_width); glBindTexture(GL_TEXTURE_2D, glTexture->_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, 0); glEnable(GL_DEPTH_TEST); _cubemapShader->unbind(); } void OpenGLShaderRenderer::updateProjectionMatrix(float fov, float aspectRatio, float nearClipPlane, float farClipPlane) { float xmaxValue = nearClipPlane * tan(Math::deg2rad(fov) / 2); float ymaxValue = xmaxValue / aspectRatio; _projectionMatrix = Math::makeFrustumMatrix(xmaxValue, -xmaxValue, -ymaxValue, ymaxValue, nearClipPlane, farClipPlane); } void OpenGLShaderRenderer::positionCamera(const Math::Vector3d &pos, const Math::Vector3d &interest, float rollAngle) { Math::Vector3d up_vec(0, 1, 0); Math::Matrix4 lookMatrix = Math::makeLookAtMatrix(pos, interest, up_vec); Math::Matrix4 viewMatrix; viewMatrix.translate(-pos); viewMatrix.transpose(); _modelViewMatrix = viewMatrix * lookMatrix; Math::Matrix4 proj = _projectionMatrix; Math::Matrix4 model = _modelViewMatrix; proj.transpose(); model.transpose(); _mvpMatrix = proj * model; _mvpMatrix.transpose(); } void OpenGLShaderRenderer::renderSensorShoot(byte color, const Math::Vector3d sensor, const Math::Vector3d target, const Common::Rect &viewArea) { glEnable(GL_BLEND); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); useColor(255, 255, 255); glLineWidth(20); copyToVertexArray(0, sensor); copyToVertexArray(1, target); glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO); glBufferData(GL_ARRAY_BUFFER, 8 * 3 * sizeof(float), _verts, GL_DYNAMIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); glDrawArrays(GL_LINES, 0, 2); glLineWidth(1); glDisable(GL_BLEND); glDepthMask(GL_TRUE); } // TODO: move inside the shader? float remap(float f, float s) { return 2. * f / s - 1; } void OpenGLShaderRenderer::renderPlayerShootBall(byte color, const Common::Point &_position, int frame, const Common::Rect &viewArea) { uint8 r, g, b; Math::Matrix4 identity; identity(0, 0) = 1.0; identity(1, 1) = 1.0; identity(2, 2) = 1.0; identity(3, 3) = 1.0; _triangleShader->use(); _triangleShader->setUniform("useStipple", false); _triangleShader->setUniform("mvpMatrix", identity); if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderZX) { r = g = b = 255; } else { if (_renderMode == Common::kRenderHercG) { // Hercules Green r = b = 0; g = 255; } else if (_renderMode == Common::kRenderHercA) { // Hercules Amber r = 255; g = 191; b = 0; } else r = g = b = 255; glEnable(GL_BLEND); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); } glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); useColor(r, g, b); int triangleAmount = 20; float twicePi = (float)(2.0 * M_PI); float coef = (9 - frame) / 9.0; float radius = (1 - coef) * 4.0; Common::Point position(_position.x, _screenH - _position.y); Common::Point initial_position(viewArea.left + viewArea.width() / 2 + 2, _screenH - (viewArea.height() + viewArea.top)); Common::Point ball_position = coef * position + (1 - coef) * initial_position; copyToVertexArray(0, Math::Vector3d(remap(ball_position.x, _screenW), remap(ball_position.y, _screenH), 0)); for (int i = 0; i <= triangleAmount; i++) { float x = remap(ball_position.x + (radius * cos(i * twicePi / triangleAmount)), _screenW); float y = remap(ball_position.y + (radius * sin(i * twicePi / triangleAmount)), _screenH); copyToVertexArray(i + 1, Math::Vector3d(x, y, 0)); } glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO); glBufferData(GL_ARRAY_BUFFER, (triangleAmount + 2) * 3 * sizeof(float), _verts, GL_DYNAMIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); glDrawArrays(GL_TRIANGLE_FAN, 0, (triangleAmount + 2)); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); } void OpenGLShaderRenderer::renderPlayerShootRay(byte color, const Common::Point &position, const Common::Rect &viewArea) { uint8 r, g, b; Math::Matrix4 identity; identity(0, 0) = 1.0; identity(1, 1) = 1.0; identity(2, 2) = 1.0; identity(3, 3) = 1.0; _triangleShader->use(); _triangleShader->setUniform("useStipple", false); _triangleShader->setUniform("mvpMatrix", identity); if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderZX) { r = g = b = 255; } else { if (_renderMode == Common::kRenderHercG) { // Hercules Green r = b = 0; g = 255; } else if (_renderMode == Common::kRenderHercA) { // Hercules Amber r = 255; g = 191; b = 0; } else r = g = b = 255; glEnable(GL_BLEND); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); } glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); useColor(r, g, b); glLineWidth(5); // It will not work in every OpenGL implementation since the // spec doesn't require support for line widths other than 1 copyToVertexArray(0, Math::Vector3d(remap(viewArea.left, _screenW), remap(viewArea.height() - viewArea.top, _screenH), 0)); copyToVertexArray(1, Math::Vector3d(remap(position.x, _screenW), remap(_screenH - position.y, _screenH), 0)); copyToVertexArray(2, Math::Vector3d(remap(viewArea.left, _screenW), remap(viewArea.height() - viewArea.top + 3, _screenH), 0)); copyToVertexArray(3, Math::Vector3d(remap(position.x, _screenW), remap(_screenH - position.y, _screenH), 0)); copyToVertexArray(4, Math::Vector3d(remap(viewArea.right, _screenW), remap(_screenH - viewArea.bottom, _screenH), 0)); copyToVertexArray(5, Math::Vector3d(remap(position.x, _screenW), remap(_screenH - position.y, _screenH), 0)); copyToVertexArray(6, Math::Vector3d(remap(viewArea.right, _screenW), remap(_screenH - viewArea.bottom + 3, _screenH), 0)); copyToVertexArray(7, Math::Vector3d(remap(position.x, _screenW), remap(_screenH - position.y, _screenH), 0)); glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO); glBufferData(GL_ARRAY_BUFFER, 8 * 3 * sizeof(float), _verts, GL_DYNAMIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); glDrawArrays(GL_LINES, 0, 8); glLineWidth(1); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); } void OpenGLShaderRenderer::drawCelestialBody(const Math::Vector3d position, float radius, byte color) { // === Safety checks === if (!_triangleShader || radius <= 0.0f) return; // === Decode color from palette === uint8 r1, g1, b1, r2, g2, b2; byte *stipple = nullptr; getRGBAt(color, 0, r1, g1, b1, r2, g2, b2, stipple); useColor(r1, g1, b1); // === Build circular vertex fan === const int triangleAmount = 20; const float twicePi = 2.0f * static_cast(M_PI); const float adj = 1.25f; Common::Array verts; // Center vertex verts.push_back(static_cast(position.x())); verts.push_back(static_cast(position.y())); verts.push_back(static_cast(position.z())); // Circle vertices in YZ plane (same as legacy code) for (int i = 0; i <= triangleAmount; i++) { float x = static_cast(position.x()); float y = static_cast(position.y()) + radius * cosf(i * twicePi / triangleAmount); float z = static_cast(position.z()) + adj * radius * sinf(i * twicePi / triangleAmount); verts.push_back(x); verts.push_back(y); verts.push_back(z); } // === Apply billboard effect to MVP matrix === // Replicate the legacy code's matrix modification Math::Matrix4 billboardMVP = _mvpMatrix; // Zero out rotation for rows 1, 3 (skip row 2), set diagonal to 1.0 // This matches: for (int i = 1; i < 4; i++) for (int j = 0; j < 4; j++) for (int i = 1; i < 4; i++) { for (int j = 0; j < 4; j++) { if (i == 2) continue; if (i == j) billboardMVP(i, j) = 2.5f; else billboardMVP(i, j) = 0.0f; } } // === Bind VBO === glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO); glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(float), verts.data(), GL_DYNAMIC_DRAW); // === Set vertex attribute 0 (position) === glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); // === Shader uniforms === _triangleShader->use(); _triangleShader->setUniform("mvpMatrix", billboardMVP); _triangleShader->setUniform("useStipple", false); // === Render settings === glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); // === Draw vertex fan === glDrawArrays(GL_TRIANGLE_FAN, 0, verts.size() / 3); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); glDrawArrays(GL_TRIANGLE_FAN, 0, verts.size() / 3); useStipple(false); } // === Restore state === glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); // === Cleanup binding === glDisableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); _triangleShader->unbind(); } void OpenGLShaderRenderer::renderCrossair(const Common::Point &crossairPosition) { Math::Matrix4 identity; identity(0, 0) = 1.0; identity(1, 1) = 1.0; identity(2, 2) = 1.0; identity(3, 3) = 1.0; _triangleShader->use(); _triangleShader->setUniform("useStipple", false); _triangleShader->setUniform("mvpMatrix", identity); glEnable(GL_BLEND); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); useColor(255, 255, 255); glLineWidth(MAX(2, g_system->getWidth() / 640)); // It will not work in every OpenGL implementation since the // spec doesn't require support for line widths other than 1 copyToVertexArray(0, Math::Vector3d(remap(crossairPosition.x - 3, _screenW), remap(_screenH - crossairPosition.y, _screenH), 0)); copyToVertexArray(1, Math::Vector3d(remap(crossairPosition.x - 1, _screenW), remap(_screenH - crossairPosition.y, _screenH), 0)); copyToVertexArray(2, Math::Vector3d(remap(crossairPosition.x + 1, _screenW), remap(_screenH - crossairPosition.y, _screenH), 0)); copyToVertexArray(3, Math::Vector3d(remap(crossairPosition.x + 3, _screenW), remap(_screenH - crossairPosition.y, _screenH), 0)); copyToVertexArray(4, Math::Vector3d(remap(crossairPosition.x, _screenW), remap(_screenH - crossairPosition.y - 3, _screenH), 0)); copyToVertexArray(5, Math::Vector3d(remap(crossairPosition.x, _screenW), remap(_screenH - crossairPosition.y - 1, _screenH), 0)); copyToVertexArray(6, Math::Vector3d(remap(crossairPosition.x, _screenW), remap(_screenH - crossairPosition.y + 1, _screenH), 0)); copyToVertexArray(7, Math::Vector3d(remap(crossairPosition.x, _screenW), remap(_screenH - crossairPosition.y + 3, _screenH), 0)); glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO); glBufferData(GL_ARRAY_BUFFER, 8 * 3 * sizeof(float), _verts, GL_DYNAMIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); glDrawArrays(GL_LINES, 0, 8); glLineWidth(1); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); } void OpenGLShaderRenderer::renderFace(const Common::Array &vertices) { assert(vertices.size() >= 2); const Math::Vector3d &v0 = vertices[0]; _triangleShader->use(); _triangleShader->setUniform("mvpMatrix", _mvpMatrix); if (vertices.size() == 2) { const Math::Vector3d &v1 = vertices[1]; if (v0 == v1) return; copyToVertexArray(0, v0); copyToVertexArray(1, v1); glLineWidth(MAX(1, g_system->getWidth() / 640)); glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO); glBufferData(GL_ARRAY_BUFFER, 2 * 3 * sizeof(float), _verts, GL_DYNAMIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); glDrawArrays(GL_LINES, 0, 2); glLineWidth(1); return; } uint vi = 0; for (uint i = 1; i < vertices.size() - 1; i++) { // no underflow since vertices.size() > 2 const Math::Vector3d &v1 = vertices[i]; const Math::Vector3d &v2 = vertices[i + 1]; vi = 3 * (i - 1); // no underflow since i >= 1 copyToVertexArray(vi + 0, v0); copyToVertexArray(vi + 1, v1); copyToVertexArray(vi + 2, v2); } glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO); glBufferData(GL_ARRAY_BUFFER, (vi + 3) * 3 * sizeof(float), _verts, GL_DYNAMIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); glDrawArrays(GL_TRIANGLES, 0, vi + 3); } void OpenGLShaderRenderer::depthTesting(bool enabled) { if (enabled) { // If we re-enable depth testing, we need to clear the depth buffer glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } void OpenGLShaderRenderer::polygonOffset(bool enabled) { if (enabled) { glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-10.0f, 1.0f); } else { glPolygonOffset(0, 0); glDisable(GL_POLYGON_OFFSET_FILL); } } void OpenGLShaderRenderer::setStippleData(byte *data) { if (!data) data = _defaultStippleArray; for (int i = 0; i < 128; i++) _variableStippleArray[i] = data[i]; } void OpenGLShaderRenderer::useStipple(bool enabled) { _triangleShader->use(); _triangleShader->setUniform("useStipple", enabled); if (enabled) { GLfloat factor = 0; glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &factor); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(factor - 0.5f, -1.0f); if (_renderMode == Common::kRenderZX || _renderMode == Common::kRenderCPC || _renderMode == Common::kRenderCGA || _renderMode == Common::kRenderHercG) _triangleShader->setUniform("stipple", 128, _variableStippleArray); else _triangleShader->setUniform("stipple", 128, _defaultShaderStippleArray); } else { glPolygonOffset(0, 0); glDisable(GL_POLYGON_OFFSET_FILL); } } void OpenGLShaderRenderer::useColor(uint8 r, uint8 g, uint8 b) { Math::Vector3d color(r / 256.0, g / 256.0, b / 256.0); _triangleShader->use(); _triangleShader->setUniform("color", color); } void OpenGLShaderRenderer::clear(uint8 r, uint8 g, uint8 b, bool ignoreViewport) { if (ignoreViewport) glDisable(GL_SCISSOR_TEST); glClearColor(r / 255., g / 255., b / 255., 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (ignoreViewport) glEnable(GL_SCISSOR_TEST); } void OpenGLShaderRenderer::drawFloor(uint8 color) { /*uint8 r1, g1, b1, r2, g2, b2; byte *stipple; assert(getRGBAt(color, r1, g1, b1, r2, g2, b2, stipple)); // TODO: move check inside this function glColor4ub(r1, g1, b1, 255); glEnableClientState(GL_VERTEX_ARRAY); copyToVertexArray(0, Math::Vector3d(-100000.0, 0.0, -100000.0)); copyToVertexArray(1, Math::Vector3d(100000.0, 0.0, -100000.0)); copyToVertexArray(2, Math::Vector3d(100000.0, 0.0, 100000.0)); copyToVertexArray(3, Math::Vector3d(-100000.0, 0.0, 100000.0)); glVertexPointer(3, GL_FLOAT, 0, _verts); glDrawArrays(GL_QUADS, 0, 4); glDisableClientState(GL_VERTEX_ARRAY);*/ } void OpenGLShaderRenderer::flipBuffer() {} Graphics::Surface *OpenGLShaderRenderer::getScreenshot() { Common::Rect screen = viewport(); Graphics::Surface *s = new Graphics::Surface(); s->create(screen.width(), screen.height(), getRGBAPixelFormat()); glReadPixels(screen.left, screen.top, screen.width(), screen.height(), GL_RGBA, GL_UNSIGNED_BYTE, s->getPixels()); flipVertical(s); return s; } } // End of namespace Freescape