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

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 Texture *Renderer::copyScreenshotToTexture() {
00099     Graphics::Surface *surface = getScreenshot();
00100 
00101     Texture *texture = createTexture(surface);
00102 
00103     surface->free();
00104     delete surface;
00105 
00106     return texture;
00107 }
00108 
00109 Common::Rect Renderer::getFontCharacterRect(uint8 character) {
00110     uint index = 0;
00111 
00112     if (character == ' ')
00113         index = 0;
00114     else if (character >= '0' && character <= '9')
00115         index = 1 + character - '0';
00116     else if (character >= 'A' && character <= 'Z')
00117         index = 1 + 10 + character - 'A';
00118     else if (character == '|')
00119         index = 1 + 10 + 26;
00120     else if (character == '/')
00121         index = 2 + 10 + 26;
00122     else if (character == ':')
00123         index = 3 + 10 + 26;
00124 
00125     return Common::Rect(16 * index, 0, 16 * (index + 1), 32);
00126 }
00127 
00128 Common::Rect Renderer::viewport() const {
00129     return _screenViewport;
00130 }
00131 
00132 void Renderer::computeScreenViewport() {
00133     int32 screenWidth = _system->getWidth();
00134     int32 screenHeight = _system->getHeight();
00135 
00136     if (ConfMan.getBool("widescreen_mod")) {
00137         _screenViewport = Common::Rect(screenWidth, screenHeight);
00138     } else {
00139         // Aspect ratio correction
00140         int32 viewportWidth = MIN<int32>(screenWidth, screenHeight * kOriginalWidth / kOriginalHeight);
00141         int32 viewportHeight = MIN<int32>(screenHeight, screenWidth * kOriginalHeight / kOriginalWidth);
00142         _screenViewport = Common::Rect(viewportWidth, viewportHeight);
00143 
00144         // Pillarboxing
00145         _screenViewport.translate((screenWidth - viewportWidth) / 2,
00146             (screenHeight - viewportHeight) / 2);
00147     }
00148 }
00149 
00150 Math::Matrix4 Renderer::makeProjectionMatrix(float fov) const {
00151     static const float nearClipPlane = 1.0;
00152     static const float farClipPlane = 10000.0;
00153 
00154     float aspectRatio = kOriginalWidth / (float) kFrameHeight;
00155 
00156     float xmaxValue = nearClipPlane * tan(fov * M_PI / 360.0);
00157     float ymaxValue = xmaxValue / aspectRatio;
00158 
00159     return Math::makeFrustumMatrix(-xmaxValue, xmaxValue, -ymaxValue, ymaxValue, nearClipPlane, farClipPlane);
00160 }
00161 
00162 void Renderer::setupCameraPerspective(float pitch, float heading, float fov) {
00163     _projectionMatrix = makeProjectionMatrix(fov);
00164     _modelViewMatrix = Math::Matrix4(180.0f - heading, pitch, 0.0f, Math::EO_YXZ);
00165 
00166     Math::Matrix4 proj = _projectionMatrix;
00167     Math::Matrix4 model = _modelViewMatrix;
00168     proj.transpose();
00169     model.transpose();
00170 
00171     _mvpMatrix = proj * model;
00172 
00173     _frustum.setup(_mvpMatrix);
00174 
00175     _mvpMatrix.transpose();
00176 }
00177 
00178 bool Renderer::isCubeFaceVisible(uint face) {
00179     assert(face < 6);
00180 
00181     return _frustum.isInside(_cubeFacesAABB[face]);
00182 }
00183 
00184 void Renderer::flipVertical(Graphics::Surface *s) {
00185     for (int y = 0; y < s->h / 2; ++y) {
00186         // Flip the lines
00187         byte *line1P = (byte *)s->getBasePtr(0, y);
00188         byte *line2P = (byte *)s->getBasePtr(0, s->h - y - 1);
00189 
00190         for (int x = 0; x < s->pitch; ++x)
00191             SWAP(line1P[x], line2P[x]);
00192     }
00193 }
00194 
00195 Renderer *createRenderer(OSystem *system) {
00196     Common::String rendererConfig = ConfMan.get("renderer");
00197     Graphics::RendererType desiredRendererType = Graphics::parseRendererTypeCode(rendererConfig);
00198     Graphics::RendererType matchingRendererType = Graphics::getBestMatchingAvailableRendererType(desiredRendererType);
00199 
00200     bool fullscreen = ConfMan.getBool("fullscreen");
00201     bool isAccelerated = matchingRendererType != Graphics::kRendererTypeTinyGL;
00202 
00203     uint width;
00204     uint height = Renderer::kOriginalHeight;
00205     if (ConfMan.getBool("widescreen_mod")) {
00206         width = Renderer::kOriginalWidth * Renderer::kOriginalHeight / Renderer::kFrameHeight;
00207     } else {
00208         width = Renderer::kOriginalWidth;
00209     }
00210 
00211     system->setupScreen(width, height, fullscreen, isAccelerated);
00212 
00213 #if defined(USE_OPENGL)
00214     // Check the OpenGL context actually supports shaders
00215     if (matchingRendererType == Graphics::kRendererTypeOpenGLShaders && !OpenGLContext.shadersSupported) {
00216         matchingRendererType = Graphics::kRendererTypeOpenGL;
00217     }
00218 #endif
00219 
00220     if (matchingRendererType != desiredRendererType && desiredRendererType != Graphics::kRendererTypeDefault) {
00221         // Display a warning if unable to use the desired renderer
00222         warning("Unable to create a '%s' renderer", rendererConfig.c_str());
00223     }
00224 
00225 #if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
00226     if (matchingRendererType == Graphics::kRendererTypeOpenGLShaders) {
00227         return CreateGfxOpenGLShader(system);
00228     }
00229 #endif
00230 #if defined(USE_OPENGL) && !defined(USE_GLES2)
00231     if (matchingRendererType == Graphics::kRendererTypeOpenGL) {
00232         return CreateGfxOpenGL(system);
00233     }
00234 #endif
00235     if (matchingRendererType == Graphics::kRendererTypeTinyGL) {
00236         return CreateGfxTinyGL(system);
00237     }
00238 
00239     error("Unable to create a '%s' renderer", rendererConfig.c_str());
00240 }
00241 
00242 void Renderer::toggleFullscreen() {
00243     if (!_system->hasFeature(OSystem::kFeatureFullscreenToggleKeepsContext)) {
00244         warning("Unable to toggle the fullscreen state because the current backend would destroy the graphics context");
00245         return;
00246     }
00247 
00248     bool oldFullscreen = _system->getFeatureState(OSystem::kFeatureFullscreenMode);
00249     _system->setFeatureState(OSystem::kFeatureFullscreenMode, !oldFullscreen);
00250 }
00251 
00252 void Renderer::renderDrawable(Drawable *drawable, Window *window) {
00253     if (drawable->isConstrainedToWindow()) {
00254         selectTargetWindow(window, drawable->is3D(), drawable->isScaled());
00255     } else {
00256         selectTargetWindow(nullptr, drawable->is3D(), drawable->isScaled());
00257     }
00258     drawable->draw();
00259 }
00260 
00261 void Renderer::renderDrawableOverlay(Drawable *drawable, Window *window) {
00262     // Overlays are always 2D
00263     if (drawable->isConstrainedToWindow()) {
00264         selectTargetWindow(window, drawable->is3D(), drawable->isScaled());
00265     } else {
00266         selectTargetWindow(nullptr, drawable->is3D(), drawable->isScaled());
00267     }
00268     drawable->drawOverlay();
00269 }
00270 
00271 void Renderer::renderWindow(Window *window) {
00272     renderDrawable(window, window);
00273 }
00274 
00275 void Renderer::renderWindowOverlay(Window *window) {
00276     renderDrawableOverlay(window, window);
00277 }
00278 
00279 Drawable::Drawable() :
00280         _isConstrainedToWindow(true),
00281         _is3D(false),
00282         _scaled(true) {
00283 }
00284 
00285 Common::Point Window::getCenter() const {
00286     Common::Rect frame = getPosition();
00287 
00288     return Common::Point((frame.left + frame.right) / 2, (frame.top + frame.bottom) / 2);
00289 }
00290 
00291 Common::Point Window::screenPosToWindowPos(const Common::Point &screen) const {
00292     Common::Rect frame = getPosition();
00293 
00294     return Common::Point(screen.x - frame.left, screen.y - frame.top);
00295 }
00296 
00297 Common::Point Window::scalePoint(const Common::Point &screen) const {
00298     Common::Rect viewport = getPosition();
00299     Common::Rect originalViewport = getOriginalPosition();
00300 
00301     Common::Point scaledPosition = screen;
00302     scaledPosition.x -= viewport.left;
00303     scaledPosition.y -= viewport.top;
00304     scaledPosition.x = CLIP<int16>(scaledPosition.x, 0, viewport.width());
00305     scaledPosition.y = CLIP<int16>(scaledPosition.y, 0, viewport.height());
00306 
00307     if (_scaled) {
00308         scaledPosition.x *= originalViewport.width() / (float) viewport.width();
00309         scaledPosition.y *= originalViewport.height() / (float) viewport.height();
00310     }
00311 
00312     return scaledPosition;
00313 }
00314 
00315 FrameLimiter::FrameLimiter(OSystem *system, const uint framerate) :
00316     _system(system),
00317     _speedLimitMs(0),
00318     _startFrameTime(0) {
00319     // The frame limiter is disabled when vsync is enabled.
00320     _enabled = !_system->getFeatureState(OSystem::kFeatureVSync) && framerate != 0;
00321 
00322     if (_enabled) {
00323         _speedLimitMs = 1000 / CLIP<uint>(framerate, 0, 100);
00324     }
00325 }
00326 
00327 void FrameLimiter::startFrame() {
00328     _startFrameTime = _system->getMillis();
00329 }
00330 
00331 void FrameLimiter::delayBeforeSwap() {
00332     uint endFrameTime = _system->getMillis();
00333     uint frameDuration = endFrameTime - _startFrameTime;
00334 
00335     if (_enabled && frameDuration < _speedLimitMs) {
00336         _system->delayMillis(_speedLimitMs - frameDuration);
00337     }
00338 }
00339 
00340 const Graphics::PixelFormat Texture::getRGBAPixelFormat() {
00341 #ifdef SCUMM_BIG_ENDIAN
00342     return Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
00343 #else
00344     return Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
00345 #endif
00346 }
00347 } // End of namespace Myst3


Generated on Sat Nov 30 2019 05:00:23 for ResidualVM by doxygen 1.7.1
curved edge   curved edge