ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

engines/myst3/gfx.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #if defined(WIN32)
00024 #include <windows.h>
00025 // winnt.h defines ARRAYSIZE, but we want our own one...
00026 #undef ARRAYSIZE
00027 #endif
00028 
00029 #include "engines/myst3/gfx.h"
00030 
00031 #include "common/config-manager.h"
00032 
00033 #include "graphics/renderer.h"
00034 #include "graphics/surface.h"
00035 
00036 #ifdef USE_OPENGL
00037 #include "graphics/opengl/context.h"
00038 #endif
00039 
00040 #include "math/glmath.h"
00041 
00042 namespace Myst3 {
00043 
00044 const float Renderer::cubeVertices[] = {
00045     // S     T      X      Y      Z
00046     0.0f, 1.0f, -320.0f, -320.0f, -320.0f,
00047     1.0f, 1.0f,  320.0f, -320.0f, -320.0f,
00048     0.0f, 0.0f, -320.0f,  320.0f, -320.0f,
00049     1.0f, 0.0f,  320.0f,  320.0f, -320.0f,
00050     0.0f, 1.0f,  320.0f, -320.0f, -320.0f,
00051     1.0f, 1.0f, -320.0f, -320.0f, -320.0f,
00052     0.0f, 0.0f,  320.0f, -320.0f,  320.0f,
00053     1.0f, 0.0f, -320.0f, -320.0f,  320.0f,
00054     0.0f, 1.0f,  320.0f, -320.0f,  320.0f,
00055     1.0f, 1.0f, -320.0f, -320.0f,  320.0f,
00056     0.0f, 0.0f,  320.0f,  320.0f,  320.0f,
00057     1.0f, 0.0f, -320.0f,  320.0f,  320.0f,
00058     0.0f, 1.0f,  320.0f, -320.0f, -320.0f,
00059     1.0f, 1.0f,  320.0f, -320.0f,  320.0f,
00060     0.0f, 0.0f,  320.0f,  320.0f, -320.0f,
00061     1.0f, 0.0f,  320.0f,  320.0f,  320.0f,
00062     0.0f, 1.0f, -320.0f, -320.0f,  320.0f,
00063     1.0f, 1.0f, -320.0f, -320.0f, -320.0f,
00064     0.0f, 0.0f, -320.0f,  320.0f,  320.0f,
00065     1.0f, 0.0f, -320.0f,  320.0f, -320.0f,
00066     0.0f, 1.0f,  320.0f,  320.0f,  320.0f,
00067     1.0f, 1.0f, -320.0f,  320.0f,  320.0f,
00068     0.0f, 0.0f,  320.0f,  320.0f, -320.0f,
00069     1.0f, 0.0f, -320.0f,  320.0f, -320.0f
00070 };
00071 
00072 Renderer::Renderer(OSystem *system)
00073         : _system(system),
00074           _font(nullptr) {
00075 
00076     // Compute the cube faces Axis Aligned Bounding Boxes
00077     for (uint i = 0; i < ARRAYSIZE(_cubeFacesAABB); i++) {
00078         for (uint j = 0; j < 4; j++) {
00079             _cubeFacesAABB[i].expand(Math::Vector3d(cubeVertices[5 * (4 * i + j) + 2], cubeVertices[5 * (4 * i + j) + 3], cubeVertices[5 * (4 * i + j) + 4]));
00080         }
00081     }
00082 }
00083 
00084 Renderer::~Renderer() {
00085 }
00086 
00087 void Renderer::initFont(const Graphics::Surface *surface) {
00088     _font = createTexture(surface);
00089 }
00090 
00091 void Renderer::freeFont() {
00092     if (_font) {
00093         freeTexture(_font);
00094         _font = nullptr;
00095     }
00096 }
00097 
00098 Common::Rect Renderer::getFontCharacterRect(uint8 character) {
00099     uint index = 0;
00100 
00101     if (character == ' ')
00102         index = 0;
00103     else if (character >= '0' && character <= '9')
00104         index = 1 + character - '0';
00105     else if (character >= 'A' && character <= 'Z')
00106         index = 1 + 10 + character - 'A';
00107     else if (character == '|')
00108         index = 1 + 10 + 26;
00109     else if (character == '/')
00110         index = 2 + 10 + 26;
00111     else if (character == ':')
00112         index = 3 + 10 + 26;
00113 
00114     return Common::Rect(16 * index, 0, 16 * (index + 1), 32);
00115 }
00116 
00117 Common::Rect Renderer::viewport() const {
00118     return _screenViewport;
00119 }
00120 
00121 void Renderer::computeScreenViewport() {
00122     int32 screenWidth = _system->getWidth();
00123     int32 screenHeight = _system->getHeight();
00124 
00125     if (ConfMan.getBool("widescreen_mod")) {
00126         _screenViewport = Common::Rect(screenWidth, screenHeight);
00127     } else {
00128         // Aspect ratio correction
00129         int32 viewportWidth = MIN<int32>(screenWidth, screenHeight * kOriginalWidth / kOriginalHeight);
00130         int32 viewportHeight = MIN<int32>(screenHeight, screenWidth * kOriginalHeight / kOriginalWidth);
00131         _screenViewport = Common::Rect(viewportWidth, viewportHeight);
00132 
00133         // Pillarboxing
00134         _screenViewport.translate((screenWidth - viewportWidth) / 2,
00135             (screenHeight - viewportHeight) / 2);
00136     }
00137 }
00138 
00139 Math::Matrix4 Renderer::makeProjectionMatrix(float fov) const {
00140     static const float nearClipPlane = 1.0;
00141     static const float farClipPlane = 10000.0;
00142 
00143     float aspectRatio = kOriginalWidth / (float) kFrameHeight;
00144 
00145     float xmaxValue = nearClipPlane * tan(fov * M_PI / 360.0);
00146     float ymaxValue = xmaxValue / aspectRatio;
00147 
00148     return Math::makeFrustumMatrix(-xmaxValue, xmaxValue, -ymaxValue, ymaxValue, nearClipPlane, farClipPlane);
00149 }
00150 
00151 void Renderer::setupCameraPerspective(float pitch, float heading, float fov) {
00152     _projectionMatrix = makeProjectionMatrix(fov);
00153     _modelViewMatrix = Math::Matrix4(180.0f - heading, pitch, 0.0f, Math::EO_YXZ);
00154 
00155     Math::Matrix4 proj = _projectionMatrix;
00156     Math::Matrix4 model = _modelViewMatrix;
00157     proj.transpose();
00158     model.transpose();
00159 
00160     _mvpMatrix = proj * model;
00161 
00162     _frustum.setup(_mvpMatrix);
00163 
00164     _mvpMatrix.transpose();
00165 }
00166 
00167 bool Renderer::isCubeFaceVisible(uint face) {
00168     assert(face < 6);
00169 
00170     return _frustum.isInside(_cubeFacesAABB[face]);
00171 }
00172 
00173 void Renderer::flipVertical(Graphics::Surface *s) {
00174     for (int y = 0; y < s->h / 2; ++y) {
00175         // Flip the lines
00176         byte *line1P = (byte *)s->getBasePtr(0, y);
00177         byte *line2P = (byte *)s->getBasePtr(0, s->h - y - 1);
00178 
00179         for (int x = 0; x < s->pitch; ++x)
00180             SWAP(line1P[x], line2P[x]);
00181     }
00182 }
00183 
00184 Renderer *createRenderer(OSystem *system) {
00185     Common::String rendererConfig = ConfMan.get("renderer");
00186     Graphics::RendererType desiredRendererType = Graphics::parseRendererTypeCode(rendererConfig);
00187     Graphics::RendererType matchingRendererType = Graphics::getBestMatchingAvailableRendererType(desiredRendererType);
00188 
00189     bool fullscreen = ConfMan.getBool("fullscreen");
00190     bool isAccelerated = matchingRendererType != Graphics::kRendererTypeTinyGL;
00191 
00192     uint width;
00193     uint height = Renderer::kOriginalHeight;
00194     if (ConfMan.getBool("widescreen_mod")) {
00195         width = Renderer::kOriginalWidth * Renderer::kOriginalHeight / Renderer::kFrameHeight;
00196     } else {
00197         width = Renderer::kOriginalWidth;
00198     }
00199 
00200     system->setupScreen(width, height, fullscreen, isAccelerated);
00201 
00202 #if defined(USE_OPENGL)
00203     // Check the OpenGL context actually supports shaders
00204     if (matchingRendererType == Graphics::kRendererTypeOpenGLShaders && !OpenGLContext.shadersSupported) {
00205         matchingRendererType = Graphics::kRendererTypeOpenGL;
00206     }
00207 #endif
00208 
00209     if (matchingRendererType != desiredRendererType && desiredRendererType != Graphics::kRendererTypeDefault) {
00210         // Display a warning if unable to use the desired renderer
00211         warning("Unable to create a '%s' renderer", rendererConfig.c_str());
00212     }
00213 
00214 #if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
00215     if (matchingRendererType == Graphics::kRendererTypeOpenGLShaders) {
00216         return CreateGfxOpenGLShader(system);
00217     }
00218 #endif
00219 #if defined(USE_OPENGL) && !defined(USE_GLES2)
00220     if (matchingRendererType == Graphics::kRendererTypeOpenGL) {
00221         return CreateGfxOpenGL(system);
00222     }
00223 #endif
00224     if (matchingRendererType == Graphics::kRendererTypeTinyGL) {
00225         return CreateGfxTinyGL(system);
00226     }
00227 
00228     error("Unable to create a '%s' renderer", rendererConfig.c_str());
00229 }
00230 
00231 void Renderer::toggleFullscreen() {
00232     if (!_system->hasFeature(OSystem::kFeatureFullscreenToggleKeepsContext)) {
00233         warning("Unable to toggle the fullscreen state because the current backend would destroy the graphics context");
00234         return;
00235     }
00236 
00237     bool oldFullscreen = _system->getFeatureState(OSystem::kFeatureFullscreenMode);
00238     _system->setFeatureState(OSystem::kFeatureFullscreenMode, !oldFullscreen);
00239 }
00240 
00241 void Renderer::renderDrawable(Drawable *drawable, Window *window) {
00242     if (drawable->isConstrainedToWindow()) {
00243         selectTargetWindow(window, drawable->is3D(), drawable->isScaled());
00244     } else {
00245         selectTargetWindow(nullptr, drawable->is3D(), drawable->isScaled());
00246     }
00247     drawable->draw();
00248 }
00249 
00250 void Renderer::renderDrawableOverlay(Drawable *drawable, Window *window) {
00251     // Overlays are always 2D
00252     if (drawable->isConstrainedToWindow()) {
00253         selectTargetWindow(window, drawable->is3D(), drawable->isScaled());
00254     } else {
00255         selectTargetWindow(nullptr, drawable->is3D(), drawable->isScaled());
00256     }
00257     drawable->drawOverlay();
00258 }
00259 
00260 void Renderer::renderWindow(Window *window) {
00261     renderDrawable(window, window);
00262 }
00263 
00264 void Renderer::renderWindowOverlay(Window *window) {
00265     renderDrawableOverlay(window, window);
00266 }
00267 
00268 Drawable::Drawable() :
00269         _isConstrainedToWindow(true),
00270         _is3D(false),
00271         _scaled(true) {
00272 }
00273 
00274 Common::Point Window::getCenter() const {
00275     Common::Rect frame = getPosition();
00276 
00277     return Common::Point((frame.left + frame.right) / 2, (frame.top + frame.bottom) / 2);
00278 }
00279 
00280 Common::Point Window::screenPosToWindowPos(const Common::Point &screen) const {
00281     Common::Rect frame = getPosition();
00282 
00283     return Common::Point(screen.x - frame.left, screen.y - frame.top);
00284 }
00285 
00286 Common::Point Window::scalePoint(const Common::Point &screen) const {
00287     Common::Rect viewport = getPosition();
00288     Common::Rect originalViewport = getOriginalPosition();
00289 
00290     Common::Point scaledPosition = screen;
00291     scaledPosition.x -= viewport.left;
00292     scaledPosition.y -= viewport.top;
00293     scaledPosition.x = CLIP<int16>(scaledPosition.x, 0, viewport.width());
00294     scaledPosition.y = CLIP<int16>(scaledPosition.y, 0, viewport.height());
00295 
00296     if (_scaled) {
00297         scaledPosition.x *= originalViewport.width() / (float) viewport.width();
00298         scaledPosition.y *= originalViewport.height() / (float) viewport.height();
00299     }
00300 
00301     return scaledPosition;
00302 }
00303 
00304 FrameLimiter::FrameLimiter(OSystem *system, const uint framerate) :
00305     _system(system),
00306     _speedLimitMs(0),
00307     _startFrameTime(0) {
00308     // The frame limiter is disabled when vsync is enabled.
00309     _enabled = !_system->getFeatureState(OSystem::kFeatureVSync) && framerate != 0;
00310 
00311     if (_enabled) {
00312         _speedLimitMs = 1000 / CLIP<uint>(framerate, 0, 100);
00313     }
00314 }
00315 
00316 void FrameLimiter::startFrame() {
00317     _startFrameTime = _system->getMillis();
00318 }
00319 
00320 void FrameLimiter::delayBeforeSwap() {
00321     uint endFrameTime = _system->getMillis();
00322     uint frameDuration = endFrameTime - _startFrameTime;
00323 
00324     if (_enabled && frameDuration < _speedLimitMs) {
00325         _system->delayMillis(_speedLimitMs - frameDuration);
00326     }
00327 }
00328 
00329 const Graphics::PixelFormat Texture::getRGBAPixelFormat() {
00330 #ifdef SCUMM_BIG_ENDIAN
00331     return Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
00332 #else
00333     return Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
00334 #endif
00335 }
00336 } // End of namespace Myst3


Generated on Sat Feb 16 2019 05:00:51 for ResidualVM by doxygen 1.7.1
curved edge   curved edge