/* 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 . * */ #include "common/config-manager.h" #include "common/system.h" #include "gui/message.h" #include "engines/util.h" #if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS) || defined(USE_GLES2) #include "graphics/opengl/context.h" #endif #include "freescape/gfx.h" #include "freescape/objects/object.h" namespace Freescape { Renderer::Renderer(int screenW, int screenH, Common::RenderMode renderMode) { _screenW = screenW; _screenH = screenH; _currentPixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); _palettePixelFormat = Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0); _keyColor = -1; _inkColor = -1; _paperColor = -1; _underFireBackgroundColor = -1; _palette = nullptr; _colorMap = nullptr; _colorRemaps = nullptr; _renderMode = renderMode; _isAccelerated = false; } Renderer::~Renderer() {} void Renderer::readFromPalette(uint8 index, uint8 &r, uint8 &g, uint8 &b) { r = _palette[3 * index + 0]; g = _palette[3 * index + 1]; b = _palette[3 * index + 2]; } uint8 Renderer::indexFromColor(uint8 r, uint8 g, uint8 b) { for (int i = 0; i < 16; i++) { if (r == _palette[3 * i + 0] && g == _palette[3 * i + 1] && b == _palette[3 * i + 2]) return i; } warning("color %x %x %x not found", r, g, b); return 0; } void Renderer::setColorRemaps(ColorReMap *colorRemaps) { _colorRemaps = colorRemaps; } bool Renderer::getRGBAtCGA(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2) { if (index == _keyColor) return false; assert (_renderMode == Common::kRenderCGA); if (index <= 4) { // Solid colors readFromPalette(index - 1, r1, g1, b1); r2 = r1; g2 = g1; b2 = b1; return true; } byte *entry = (*_colorMap)[index - 1]; byte be = *(entry); readFromPalette((be >> 4) % 4, r1, g1, b1); entry++; be = *(entry); readFromPalette((be >> 4) % 4, r2, g2, b2); return true; } void Renderer::extractC64Indexes(uint8 cm1, uint8 cm2, uint8 &i1, uint8 &i2) { if (cm1 == 0xaa && cm2 == 0x5a) { i1 = 2; i2 = 3; } else if (cm1 == 0x4f && cm2 == 0x46) { i1 = 0; i2 = 2; } else if (cm1 == 0x56 && cm2 == 0x45) { i1 = 0; i2 = 1; } else if (cm1 == 0xa0 && cm2 == 0x55) { i1 = 1; i2 = 3; } else if (cm1 == 0x4c && cm2 == 0x54) { i1 = 1; i2 = 2; } else if (cm1 == 0x41 && cm2 == 0x52) { i1 = 0; i2 = 3; // Covered by the default of i1 = 0, i2 = 0 #if 0 } else if (cm1 == 0x5a && cm2 == 0xa5) { i1 = 0; i2 = 0; } else if (cm1 == 0xbb && cm2 == 0xee) { i1 = 0; i2 = 0; } else if (cm1 == 0x5f && cm2 == 0xaf) { i1 = 0; i2 = 0; } else if (cm1 == 0xfb && cm2 == 0xfe) { i1 = 0; i2 = 0; #endif } else { i1 = 0; i2 = 0; } } bool Renderer::getRGBAtC64(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2) { if (index == _keyColor) return false; if (index <= 4) { // Solid colors selectColorFromFourColorPalette(index - 1, r1, g1, b1); r2 = r1; g2 = g1; b2 = b1; return true; } uint8 i1, i2; byte *entry = (*_colorMap)[index - 1]; uint8 cm1 = *(entry); entry++; uint8 cm2 = *(entry); extractC64Indexes(cm1, cm2, i1, i2); selectColorFromFourColorPalette(i1, r1, g1, b1); selectColorFromFourColorPalette(i2, r2, g2, b2); return true; } bool Renderer::getRGBAtZX(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2, byte *stipple) { if (index == _keyColor) return false; byte *entry = (*_colorMap)[index - 1]; if (entry[0] == 0 && entry[1] == 0 && entry[2] == 0 && entry[3] == 0) { readFromPalette(_paperColor, r1, g1, b1); readFromPalette(_paperColor, r2, g2, b2); return true; } if (entry[0] == 0xff && entry[1] == 0xff && entry[2] == 0xff && entry[3] == 0xff) { readFromPalette(_inkColor, r1, g1, b1); readFromPalette(_inkColor, r2, g2, b2); return true; } if (stipple) { stipple[0] = entry[0]; stipple[1] = entry[1]; stipple[2] = entry[2]; stipple[3] = entry[3]; } readFromPalette(_paperColor, r1, g1, b1); readFromPalette(_inkColor, r2, g2, b2); return true; } void Renderer::extractCPCIndexes(uint8 cm1, uint8 cm2, uint8 &i1, uint8 &i2) { if (cm1 == 0xb4 && cm2 == 0xe1) { i1 = 1; i2 = 2; } else if (cm1 == 0xb0 && cm2 == 0xe0) { i1 = 1; i2 = 0; } else if (cm1 == 0x05 && cm2 == 0x0a) { i1 = 2; i2 = 0; } else if (cm1 == 0x50 && cm2 == 0xa0) { i1 = 1; i2 = 0; } else if (cm1 == 0x55 && cm2 == 0xaa) { i1 = 3; i2 = 0; } else if (cm1 == 0xf5 && cm2 == 0xfa) { i1 = 3; i2 = 1; } else if (cm1 == 0x5a && cm2 == 0xa5) { i1 = 1; i2 = 2; } else if (cm1 == 0xbb && cm2 == 0xee) { i1 = 3; i2 = 0; } else if (cm1 == 0x5f && cm2 == 0xaf) { i1 = 3; i2 = 2; } else if (cm1 == 0xfb && cm2 == 0xfe) { // TODO i1 = 0; i2 = 0; } else if (cm1 == 0x40 && cm2 == 0x20) { // This one has a special stapple pattern i1 = 1; i2 = 0; } else error("%x %x", cm1, cm2); } void Renderer::selectColorFromFourColorPalette(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1) { if (index == 0) { r1 = 0; g1 = 0; b1 = 0; } else if (index == 1) { readFromPalette(_underFireBackgroundColor, r1, g1, b1); } else if (index == 2) { readFromPalette(_paperColor, r1, g1, b1); } else if (index == 3) { readFromPalette(_inkColor, r1, g1, b1); } else error("Invalid color"); } bool Renderer::getRGBAtCPC(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2) { if (index == _keyColor) return false; assert (_renderMode == Common::kRenderCPC); if (index <= 4) { // Solid colors selectColorFromFourColorPalette(index - 1, r1, g1, b1); r2 = r1; g2 = g1; b2 = b1; return true; } uint8 i1, i2; byte *entry = (*_colorMap)[index - 1]; uint8 cm1 = *(entry); entry++; uint8 cm2 = *(entry); extractCPCIndexes(cm1, cm2, i1, i2); selectColorFromFourColorPalette(i1, r1, g1, b1); selectColorFromFourColorPalette(i2, r2, g2, b2); return true; } bool Renderer::getRGBAtEGA(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2) { // assert(index-1 < _colorMap->size()); byte *entry = (*_colorMap)[index - 1]; uint8 color = 0; uint8 acc = 1; for (int i = 0; i < 4; i++) { byte be = *entry; assert (be == 0 || be == 0xff); if (be == 0xff) color = color + acc; acc = acc << 1; entry++; } assert(color < 16); readFromPalette(color, r1, g1, b1); r2 = r1; g2 = g1; b2 = b1; return true; } bool Renderer::getRGBAt(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2, byte *stipple) { if (_colorRemaps && _colorRemaps->contains(index)) { index = (*_colorRemaps)[index]; readFromPalette(index, r1, g1, b1); r2 = r1; g2 = g1; b2 = b1; return true; } if (index == _keyColor) return false; if (index == 0) { readFromPalette(0, r1, g1, b1); r2 = r1; g2 = g1; b2 = b1; return true; } if (_renderMode == Common::kRenderAmiga || _renderMode == Common::kRenderAtariST) { readFromPalette(index, r1, g1, b1); r2 = r1; g2 = g1; b2 = b1; return true; } else if (_renderMode == Common::kRenderEGA) return getRGBAtEGA(index, r1, g1, b1, r2, g2, b2); else if (_renderMode == Common::kRenderC64) return getRGBAtC64(index, r1, g1, b1, r2, g2, b2); else if (_renderMode == Common::kRenderCGA) return getRGBAtCGA(index, r1, g1, b1, r2, g2, b2); else if (_renderMode == Common::kRenderCPC) return getRGBAtCPC(index, r1, g1, b1, r2, g2, b2); else if (_renderMode == Common::kRenderZX) return getRGBAtZX(index, r1, g1, b1, r2, g2, b2, stipple); error("Invalid or unsupported render mode"); } void Renderer::flipVertical(Graphics::Surface *s) { for (int y = 0; y < s->h / 2; ++y) { // Flip the lines byte *line1P = (byte *)s->getBasePtr(0, y); byte *line2P = (byte *)s->getBasePtr(0, s->h - y - 1); for (int x = 0; x < s->pitch; ++x) SWAP(line1P[x], line2P[x]); } } void Renderer::convertImageFormatIfNecessary(Graphics::Surface *surface) { if (!surface) return; if (surface->format != _texturePixelFormat) surface->convertToInPlace(_texturePixelFormat); } Common::Rect Renderer::viewport() const { return _screenViewport; } bool Renderer::computeScreenViewport() { int32 screenWidth = g_system->getWidth(); int32 screenHeight = g_system->getHeight(); Common::Rect viewport; if (g_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection)) { // Aspect ratio correction int32 viewportWidth = MIN(screenWidth, screenHeight * float(_screenW) / _screenH); int32 viewportHeight = MIN(screenHeight, screenWidth * float(_screenH) / _screenW); viewport = Common::Rect(viewportWidth, viewportHeight); // Pillarboxing viewport.translate((screenWidth - viewportWidth) / 2, (screenHeight - viewportHeight) / 2); } else { // Aspect ratio correction disabled, just stretch viewport = Common::Rect(screenWidth, screenHeight); } if (viewport == _screenViewport) { return false; } _screenViewport = viewport; return true; } void Renderer::renderPyramid(const Math::Vector3d &origin, const Math::Vector3d &size, const Common::Array *ordinates, Common::Array *colours, int type) { Math::Vector3d vertices[8] = { origin, origin, origin, origin, origin, origin, origin, origin }; switch (type) { default: error("Invalid pyramid type: %d", type); case kEastPyramidType: vertices[0] += Math::Vector3d(0, 0, size.z()); vertices[1] += Math::Vector3d(0, size.y(), size.z()); vertices[2] += Math::Vector3d(0, size.y(), 0); vertices[4] += Math::Vector3d(size.x(), (*ordinates)[0], (*ordinates)[3]); vertices[5] += Math::Vector3d(size.x(), (*ordinates)[2], (*ordinates)[3]); vertices[6] += Math::Vector3d(size.x(), (*ordinates)[2], (*ordinates)[1]); vertices[7] += Math::Vector3d(size.x(), (*ordinates)[0], (*ordinates)[1]); break; case kWestPyramidType: vertices[0] += Math::Vector3d(size.x(), 0, 0); vertices[1] += Math::Vector3d(size.x(), size.y(), 0); vertices[2] += Math::Vector3d(size.x(), size.y(), size.z()); vertices[3] += Math::Vector3d(size.x(), 0, size.z()); vertices[4] += Math::Vector3d(0, (*ordinates)[0], (*ordinates)[1]); vertices[5] += Math::Vector3d(0, (*ordinates)[2], (*ordinates)[1]); vertices[6] += Math::Vector3d(0, (*ordinates)[2], (*ordinates)[3]); vertices[7] += Math::Vector3d(0, (*ordinates)[0], (*ordinates)[3]); break; case kUpPyramidType: vertices[1] += Math::Vector3d(size.x(), 0, 0); vertices[2] += Math::Vector3d(size.x(), 0, size.z()); vertices[3] += Math::Vector3d(0, 0, size.z()); vertices[4] += Math::Vector3d((*ordinates)[0], size.y(), (*ordinates)[1]); vertices[5] += Math::Vector3d((*ordinates)[2], size.y(), (*ordinates)[1]); vertices[6] += Math::Vector3d((*ordinates)[2], size.y(), (*ordinates)[3]); vertices[7] += Math::Vector3d((*ordinates)[0], size.y(), (*ordinates)[3]); break; case kDownPyramidType: vertices[0] += Math::Vector3d(size.x(), size.y(), 0); vertices[1] += Math::Vector3d(0, size.y(), 0); vertices[2] += Math::Vector3d(0, size.y(), size.z()); vertices[3] += Math::Vector3d(size.x(), size.y(), size.z()); vertices[4] += Math::Vector3d((*ordinates)[2], 0, (*ordinates)[1]); vertices[5] += Math::Vector3d((*ordinates)[0], 0, (*ordinates)[1]); vertices[6] += Math::Vector3d((*ordinates)[0], 0, (*ordinates)[3]); vertices[7] += Math::Vector3d((*ordinates)[2], 0, (*ordinates)[3]); break; case kNorthPyramidType: vertices[0] += Math::Vector3d(0, size.y(), 0); vertices[1] += Math::Vector3d(size.x(), size.y(), 0); vertices[2] += Math::Vector3d(size.x(), 0, 0); vertices[4] += Math::Vector3d((*ordinates)[0], (*ordinates)[3], size.z()); vertices[5] += Math::Vector3d((*ordinates)[2], (*ordinates)[3], size.z()); vertices[6] += Math::Vector3d((*ordinates)[2], (*ordinates)[1], size.z()); vertices[7] += Math::Vector3d((*ordinates)[0], (*ordinates)[1], size.z()); break; case kSouthPyramidType: vertices[0] += Math::Vector3d(0, 0, size.z()); vertices[1] += Math::Vector3d(size.x(), 0, size.z()); vertices[2] += Math::Vector3d(size.x(), size.y(), size.z()); vertices[3] += Math::Vector3d(0, size.y(), size.z()); vertices[4] += Math::Vector3d((*ordinates)[0], (*ordinates)[1], 0); vertices[5] += Math::Vector3d((*ordinates)[2], (*ordinates)[1], 0); vertices[6] += Math::Vector3d((*ordinates)[2], (*ordinates)[3], 0); vertices[7] += Math::Vector3d((*ordinates)[0], (*ordinates)[3], 0); break; } Common::Array face; uint32 stipple = 0; uint8 r1, g1, b1, r2, g2, b2; if (getRGBAt((*colours)[0], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.push_back(vertices[4]); face.push_back(vertices[5]); face.push_back(vertices[1]); face.push_back(vertices[0]); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } face.clear(); } if (getRGBAt((*colours)[1], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.push_back(vertices[5]); face.push_back(vertices[6]); face.push_back(vertices[2]); face.push_back(vertices[1]); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } face.clear(); } if (getRGBAt((*colours)[2], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.push_back(vertices[6]); face.push_back(vertices[7]); face.push_back(vertices[3]); face.push_back(vertices[2]); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } face.clear(); } if (getRGBAt((*colours)[3], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.push_back(vertices[7]); face.push_back(vertices[4]); face.push_back(vertices[0]); face.push_back(vertices[3]); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } face.clear(); } if (getRGBAt((*colours)[4], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.push_back(vertices[0]); face.push_back(vertices[1]); face.push_back(vertices[2]); face.push_back(vertices[3]); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } face.clear(); } if (getRGBAt((*colours)[5], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.push_back(vertices[7]); face.push_back(vertices[6]); face.push_back(vertices[5]); face.push_back(vertices[4]); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } } } void Renderer::renderCube(const Math::Vector3d &origin, const Math::Vector3d &size, Common::Array *colours) { uint32 stipple = 0; uint8 r1, g1, b1, r2, g2, b2; Common::Array face; if (getRGBAt((*colours)[0], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.push_back(origin); face.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z())); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } } if (getRGBAt((*colours)[1], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.clear(); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z())); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z())); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } } if (getRGBAt((*colours)[2], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.clear(); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z())); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z())); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } } if (getRGBAt((*colours)[3], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.clear(); face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z())); face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z())); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } } if (getRGBAt((*colours)[4], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.clear(); face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z())); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z())); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z())); face.push_back(origin); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } } if (getRGBAt((*colours)[5], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); face.clear(); face.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z() + size.z())); face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z() + size.z())); renderFace(face); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(face); useStipple(false); } } } void Renderer::renderRectangle(const Math::Vector3d &origin, const Math::Vector3d &size, Common::Array *colours) { assert(size.x() == 0 || size.y() == 0 || size.z() == 0); polygonOffset(true); float dx, dy, dz; uint8 r1, g1, b1, r2, g2, b2; uint32 stipple = 0; Common::Array vertices; for (int i = 0; i < 2; i++) { // debug("rec color: %d", (*colours)[i]); if (getRGBAt((*colours)[i], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); vertices.clear(); vertices.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z())); dx = dy = dz = 0.0; if (size.x() == 0) { dy = size.y(); } else if (size.y() == 0) { dx = size.x(); } else if (size.z() == 0) { dx = size.x(); } vertices.push_back(Math::Vector3d(origin.x() + dx, origin.y() + dy, origin.z() + dz)); vertices.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z() + size.z())); renderFace(vertices); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(vertices); useStipple(false); } vertices.clear(); vertices.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z())); dx = dy = dz = 0.0; if (size.x() == 0) { dz = size.z(); } else if (size.y() == 0) { dz = size.z(); } else if (size.z() == 0) { dy = size.y(); } vertices.push_back(Math::Vector3d(origin.x() + dx, origin.y() + dy, origin.z() + dz)); vertices.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z() + size.z())); renderFace(vertices); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(vertices); useStipple(false); } } } polygonOffset(false); } void Renderer::renderPolygon(const Math::Vector3d &origin, const Math::Vector3d &size, const Common::Array *ordinates, Common::Array *colours) { uint8 r1, g1, b1, r2, g2, b2; uint32 stipple = 0; if (ordinates->size() % 3 > 0 && ordinates->size() > 0) error("Invalid polygon with size %f %f %f and ordinates %d", size.x(), size.y(), size.z(), ordinates->size()); Common::Array vertices; polygonOffset(true); if (ordinates->size() == 6) { // Line assert(getRGBAt((*colours)[0], r1, g1, b1, r2, g2, b2, (byte *)&stipple)); // It will never return false? setStippleData((byte *)&stipple); useColor(r1, g1, b1); for (uint i = 0; i < ordinates->size(); i = i + 3) vertices.push_back(Math::Vector3d((*ordinates)[i], (*ordinates)[i + 1], (*ordinates)[i + 2])); renderFace(vertices); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(vertices); useStipple(false); } vertices.clear(); assert(getRGBAt((*colours)[1], r1, g1, b1, r2, g2, b2, (byte *)&stipple)); // It will never return false? setStippleData((byte *)&stipple); useColor(r1, g1, b1); for (int i = ordinates->size(); i > 0; i = i - 3) vertices.push_back(Math::Vector3d((*ordinates)[i - 3], (*ordinates)[i - 2], (*ordinates)[i - 1])); renderFace(vertices); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(vertices); useStipple(false); } } else { if (getRGBAt((*colours)[0], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); for (uint i = 0; i < ordinates->size(); i = i + 3) { vertices.push_back(Math::Vector3d((*ordinates)[i], (*ordinates)[i + 1], (*ordinates)[i + 2])); } renderFace(vertices); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(vertices); useStipple(false); } } vertices.clear(); if (getRGBAt((*colours)[1], r1, g1, b1, r2, g2, b2, (byte *)&stipple)) { setStippleData((byte *)&stipple); useColor(r1, g1, b1); for (int i = ordinates->size(); i > 0; i = i - 3) { vertices.push_back(Math::Vector3d((*ordinates)[i - 3], (*ordinates)[i - 2], (*ordinates)[i - 1])); } renderFace(vertices); if (r1 != r2 || g1 != g2 || b1 != b2) { useStipple(true); useColor(r2, g2, b2); renderFace(vertices); useStipple(false); } } } polygonOffset(false); } Graphics::RendererType determinateRenderType() { Common::String rendererConfig = ConfMan.get("renderer"); Graphics::RendererType desiredRendererType = Graphics::Renderer::parseTypeCode(rendererConfig); Graphics::RendererType matchingRendererType = Graphics::Renderer::getBestMatchingAvailableType(desiredRendererType, #if defined(USE_OPENGL_GAME) Graphics::kRendererTypeOpenGL | #endif #if defined(USE_TINYGL) Graphics::kRendererTypeTinyGL | #endif 0); 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()); } #if defined(USE_OPENGL_GAME) && !defined(USE_GLES2) if (matchingRendererType == Graphics::kRendererTypeOpenGL) return matchingRendererType; #endif #if defined(USE_TINYGL) if (desiredRendererType == Graphics::kRendererTypeTinyGL) return desiredRendererType; #endif return Graphics::kRendererTypeDefault; } Renderer *createRenderer(int screenW, int screenH, Common::RenderMode renderMode) { Graphics::PixelFormat pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); Graphics::RendererType rendererType = determinateRenderType(); bool isAccelerated = rendererType != Graphics::kRendererTypeTinyGL; if (isAccelerated) { initGraphics3d(screenW, screenH); } else { initGraphics(screenW, screenH, &pixelFormat); } #if defined(USE_OPENGL_GAME) && !defined(USE_GLES2) if (rendererType == Graphics::kRendererTypeOpenGL) { return CreateGfxOpenGL(screenW, screenH, renderMode); } #endif #if defined(USE_TINYGL) if (rendererType == Graphics::kRendererTypeTinyGL) { return CreateGfxTinyGL(screenW, screenH, renderMode); } #endif GUI::MessageDialog dialog("No available renderers enabled"); // TODO: improve message with other renders dialog.runModal(); return nullptr; } } // End of namespace Freescape