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

grim/gfx_tinygl.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 COPYRIGHT
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 #include "common/config-manager.h"
00024 #include "common/endian.h"
00025 #include "common/system.h"
00026 
00027 #include "graphics/surface.h"
00028 #include "graphics/colormasks.h"
00029 
00030 #include "math/glmath.h"
00031 
00032 #include "engines/grim/actor.h"
00033 #include "engines/grim/colormap.h"
00034 #include "engines/grim/material.h"
00035 #include "engines/grim/font.h"
00036 #include "engines/grim/gfx_tinygl.h"
00037 #include "engines/grim/grim.h"
00038 #include "engines/grim/bitmap.h"
00039 #include "engines/grim/primitives.h"
00040 #include "engines/grim/model.h"
00041 #include "engines/grim/sprite.h"
00042 #include "engines/grim/set.h"
00043 #include "engines/grim/emi/modelemi.h"
00044 
00045 namespace Grim {
00046 
00047 GfxBase *CreateGfxTinyGL() {
00048     return new GfxTinyGL();
00049 }
00050 
00051 GfxTinyGL::GfxTinyGL() :
00052         _zb(nullptr), _alpha(1.f),
00053         _currentActor(nullptr), _smushImage(nullptr) {
00054     _storedDisplay = nullptr;
00055     // TGL_LEQUAL as tglDepthFunc ensures that subsequent drawing attempts for
00056     // the same triangles are not ignored by the depth test.
00057     // That's necessary for EMI where some models have multiple faces which
00058     // refer to the same vertices. The first face is usually using the
00059     // color map and the following are using textures.
00060     _depthFunc = (g_grim->getGameType() == GType_MONKEY4) ? TGL_LEQUAL : TGL_LESS;
00061     for (int i = 0; i < 96; i++) {
00062         _emergFont[i] = nullptr;
00063     }
00064 }
00065 
00066 GfxTinyGL::~GfxTinyGL() {
00067     releaseMovieFrame();
00068     for (unsigned int i = 0; i < _numSpecialtyTextures; i++) {
00069         destroyTexture(&_specialtyTextures[i]);
00070     }
00071     for (int i = 0; i < 96; i++) {
00072         Graphics::tglDeleteBlitImage(_emergFont[i]);
00073     }
00074     if (_zb) {
00075         TinyGL::glClose();
00076         delete _zb;
00077     }
00078 }
00079 
00080 byte *GfxTinyGL::setupScreen(int screenW, int screenH, bool fullscreen) {
00081     Graphics::PixelBuffer buf = g_system->getScreenPixelBuffer();
00082     byte *buffer = buf.getRawBuffer();
00083 
00084     _screenWidth = screenW;
00085     _screenHeight = screenH;
00086     _scaleW = _screenWidth / (float)_gameWidth;
00087     _scaleH = _screenHeight / (float)_gameHeight;
00088 
00089     g_system->showMouse(!fullscreen);
00090 
00091     g_system->setWindowCaption("ResidualVM: Software 3D Renderer");
00092 
00093     _pixelFormat = buf.getFormat();
00094     debug("INFO: TinyGL front buffer pixel format: %s", _pixelFormat.toString().c_str());
00095     _zb = new TinyGL::FrameBuffer(screenW, screenH, buf);
00096     TinyGL::glInit(_zb, 256);
00097     tglEnableDirtyRects(ConfMan.getBool("dirtyrects"));
00098 
00099     _storedDisplay.create(_pixelFormat, _gameWidth * _gameHeight, DisposeAfterUse::YES);
00100     _storedDisplay.clear(_gameWidth * _gameHeight);
00101 
00102     _currentShadowArray = nullptr;
00103 
00104     TGLfloat ambientSource[] = { 0.0f, 0.0f, 0.0f, 1.0f };
00105     tglLightModelfv(TGL_LIGHT_MODEL_AMBIENT, ambientSource);
00106     TGLfloat diffuseReflectance[] = { 1.0f, 1.0f, 1.0f, 1.0f };
00107     tglMaterialfv(TGL_FRONT, TGL_DIFFUSE, diffuseReflectance);
00108 
00109     return buffer;
00110 }
00111 
00112 const char *GfxTinyGL::getVideoDeviceName() {
00113     return "TinyGL Software Renderer";
00114 }
00115 
00116 void GfxTinyGL::setupCameraFrustum(float fov, float nclip, float fclip) {
00117     tglMatrixMode(TGL_PROJECTION);
00118     tglLoadIdentity();
00119 
00120     float right = nclip * tan(fov / 2 * (LOCAL_PI / 180));
00121     tglFrustum(-right, right, -right * 0.75, right * 0.75, nclip, fclip);
00122 
00123     tglMatrixMode(TGL_MODELVIEW);
00124     tglLoadIdentity();
00125 }
00126 
00127 void GfxTinyGL::positionCamera(const Math::Vector3d &pos, const Math::Vector3d &interest, float roll) {
00128     Math::Vector3d up_vec(0, 0, 1);
00129 
00130     tglRotatef(roll, 0, 0, -1);
00131 
00132     if (pos.x() == interest.x() && pos.y() == interest.y())
00133         up_vec = Math::Vector3d(0, 1, 0);
00134 
00135     Math::Matrix4 lookMatrix = Math::makeLookAtMatrix(pos, interest, up_vec);
00136     tglMultMatrixf(lookMatrix.getData());
00137     tglTranslatef(-pos.x(), -pos.y(), -pos.z());
00138 }
00139 
00140 void GfxTinyGL::positionCamera(const Math::Vector3d &pos, const Math::Matrix4 &rot) {
00141     tglScalef(1.0, 1.0, -1.0);
00142     _currentPos = pos;
00143     _currentRot = rot;
00144 }
00145 
00146 Math::Matrix4 GfxTinyGL::getModelView() {
00147     Math::Matrix4 modelView;
00148 
00149     if (g_grim->getGameType() == GType_MONKEY4) {
00150         tglMatrixMode(TGL_MODELVIEW);
00151         tglPushMatrix();
00152 
00153         tglMultMatrixf(_currentRot.getData());
00154         tglTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
00155 
00156         tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView.getData());
00157 
00158         tglPopMatrix();
00159     } else {
00160         tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView.getData());
00161     }
00162 
00163     modelView.transpose();
00164     return modelView;
00165 }
00166 
00167 Math::Matrix4 GfxTinyGL::getProjection() {
00168     Math::Matrix4 projection;
00169     tglGetFloatv(TGL_PROJECTION_MATRIX, projection.getData());
00170     projection.transpose();
00171     return projection;
00172 }
00173 
00174 void GfxTinyGL::clearScreen() {
00175     tglClear(TGL_COLOR_BUFFER_BIT | TGL_DEPTH_BUFFER_BIT);
00176 }
00177 
00178 void GfxTinyGL::clearDepthBuffer() {
00179     tglClear(TGL_DEPTH_BUFFER_BIT);
00180 }
00181 
00182 void GfxTinyGL::flipBuffer() {
00183     TinyGL::tglPresentBuffer();
00184     g_system->updateScreen();
00185 }
00186 
00187 bool GfxTinyGL::isHardwareAccelerated() {
00188     return false;
00189 }
00190 
00191 bool GfxTinyGL::supportsShaders() {
00192     return false;
00193 }
00194 
00195 static void tglShadowProjection(const Math::Vector3d &light, const Math::Vector3d &plane, const Math::Vector3d &normal, bool dontNegate) {
00196     // Based on GPL shadow projection example by
00197     // (c) 2002-2003 Phaetos <phaetos@gaffga.de>
00198     float d, c;
00199     float mat[16];
00200     float nx, ny, nz, lx, ly, lz, px, py, pz;
00201 
00202     nx = normal.x();
00203     ny = normal.y();
00204     nz = normal.z();
00205     // for some unknown for me reason normal need negation
00206     if (!dontNegate) {
00207         nx = -nx;
00208         ny = -ny;
00209         nz = -nz;
00210     }
00211     lx = light.x();
00212     ly = light.y();
00213     lz = light.z();
00214     px = plane.x();
00215     py = plane.y();
00216     pz = plane.z();
00217 
00218     d = nx * lx + ny * ly + nz * lz;
00219     c = px * nx + py * ny + pz * nz - d;
00220 
00221     mat[0] = lx * nx + c;
00222     mat[4] = ny * lx;
00223     mat[8] = nz * lx;
00224     mat[12] = -lx * c - lx * d;
00225 
00226     mat[1] = nx * ly;
00227     mat[5] = ly * ny + c;
00228     mat[9] = nz * ly;
00229     mat[13] = -ly * c - ly * d;
00230 
00231     mat[2] = nx * lz;
00232     mat[6] = ny * lz;
00233     mat[10] = lz * nz + c;
00234     mat[14] = -lz * c - lz * d;
00235 
00236     mat[3] = nx;
00237     mat[7] = ny;
00238     mat[11] = nz;
00239     mat[15] = -d;
00240 
00241     tglMultMatrixf(mat);
00242 }
00243 
00244 void GfxTinyGL::getScreenBoundingBox(const Mesh *model, int *x1, int *y1, int *x2, int *y2) {
00245     if (_currentShadowArray) {
00246         *x1 = -1;
00247         *y1 = -1;
00248         *x2 = -1;
00249         *y2 = -1;
00250         return;
00251     }
00252 
00253     TGLfloat top = 1000;
00254     TGLfloat right = -1000;
00255     TGLfloat left = 1000;
00256     TGLfloat bottom = -1000;
00257 
00258     for (int i = 0; i < model->_numFaces; i++) {
00259         Math::Vector3d obj;
00260         float *pVertices;
00261 
00262         for (int j = 0; j < model->_faces[i].getNumVertices(); j++) {
00263             TGLfloat modelView[16], projection[16];
00264             TGLint viewPort[4];
00265 
00266             tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView);
00267             tglGetFloatv(TGL_PROJECTION_MATRIX, projection);
00268             tglGetIntegerv(TGL_VIEWPORT, viewPort);
00269 
00270             pVertices = model->_vertices + 3 * model->_faces[i].getVertex(j);
00271 
00272             obj.set(*(pVertices), *(pVertices + 1), *(pVertices + 2));
00273 
00274             Math::Vector3d win;
00275             Math::gluMathProject<TGLfloat, TGLint>(obj, modelView, projection, viewPort, win);
00276 
00277             if (win.x() > right)
00278                 right = win.x();
00279             if (win.x() < left)
00280                 left = win.x();
00281             if (win.y() < top)
00282                 top = win.y();
00283             if (win.y() > bottom)
00284                 bottom = win.y();
00285         }
00286     }
00287 
00288     float t = bottom;
00289     bottom = _gameHeight - top;
00290     top = _gameHeight - t;
00291 
00292     if (left < 0)
00293         left = 0;
00294     if (right >= _gameWidth)
00295         right = _gameWidth - 1;
00296     if (top < 0)
00297         top = 0;
00298     if (bottom >= _gameHeight)
00299         bottom = _gameHeight - 1;
00300 
00301     if (top >= _gameHeight || left >= _gameWidth || bottom < 0 || right < 0) {
00302         *x1 = -1;
00303         *y1 = -1;
00304         *x2 = -1;
00305         *y2 = -1;
00306         return;
00307     }
00308 
00309     *x1 = (int)left;
00310     *y1 = (int)top;
00311     *x2 = (int)right;
00312     *y2 = (int)bottom;
00313 }
00314 
00315 void GfxTinyGL::getScreenBoundingBox(const EMIModel *model, int *x1, int *y1, int *x2, int *y2) {
00316     if (_currentShadowArray) {
00317         *x1 = -1;
00318         *y1 = -1;
00319         *x2 = -1;
00320         *y2 = -1;
00321         return;
00322     }
00323 
00324     TGLfloat top = 1000;
00325     TGLfloat right = -1000;
00326     TGLfloat left = 1000;
00327     TGLfloat bottom = -1000;
00328 
00329     TGLfloat modelView[16], projection[16];
00330     TGLint viewPort[4];
00331 
00332     tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView);
00333     tglGetFloatv(TGL_PROJECTION_MATRIX, projection);
00334     tglGetIntegerv(TGL_VIEWPORT, viewPort);
00335 
00336     for (uint i = 0; i < model->_numFaces; i++) {
00337         int *indices = (int *)model->_faces[i]._indexes;
00338         
00339         for (uint j = 0; j < model->_faces[i]._faceLength * 3; j++) {
00340             int index = indices[j];
00341 
00342             Math::Vector3d obj = model->_drawVertices[index];
00343             Math::Vector3d win;
00344             Math::gluMathProject<TGLfloat, TGLint>(obj, modelView, projection, viewPort, win);
00345 
00346             if (win.x() > right)
00347                 right = win.x();
00348             if (win.x() < left)
00349                 left = win.x();
00350             if (win.y() < top)
00351                 top = win.y();
00352             if (win.y() > bottom)
00353                 bottom = win.y();
00354         }
00355     }
00356 
00357     float t = bottom;
00358     bottom = _gameHeight - top;
00359     top = _gameHeight - t;
00360 
00361     if (left < 0)
00362         left = 0;
00363     if (right >= _gameWidth)
00364         right = _gameWidth - 1;
00365     if (top < 0)
00366         top = 0;
00367     if (bottom >= _gameHeight)
00368         bottom = _gameHeight - 1;
00369 
00370     if (top >= _gameHeight || left >= _gameWidth || bottom < 0 || right < 0) {
00371         *x1 = -1;
00372         *y1 = -1;
00373         *x2 = -1;
00374         *y2 = -1;
00375         return;
00376     }
00377 
00378     *x1 = (int)left;
00379     *y1 = (int)(_gameHeight - bottom);
00380     *x2 = (int)right;
00381     *y2 = (int)(_gameHeight - top);
00382 }
00383 
00384 void GfxTinyGL::getActorScreenBBox(const Actor *actor, Common::Point &p1, Common::Point &p2) {
00385     // Get the actor's bounding box information (describes a 3D box)
00386     Math::Vector3d bboxPos, bboxSize;
00387     actor->getBBoxInfo(bboxPos, bboxSize);
00388 
00389     // Translate the bounding box to the actor's position
00390     Math::Matrix4 m = actor->getFinalMatrix();
00391     bboxPos = bboxPos + actor->getWorldPos();
00392 
00393     // Set up the coordinate system
00394     tglMatrixMode(TGL_MODELVIEW);
00395     tglPushMatrix();
00396 
00397     // Apply the view transform.
00398     Math::Matrix4 worldRot = _currentRot;
00399     tglMultMatrixf(worldRot.getData());
00400     tglTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
00401 
00402     // Get the current OpenGL state
00403     TGLfloat modelView[16], projection[16];
00404     TGLint viewPort[4];
00405     tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView);
00406     tglGetFloatv(TGL_PROJECTION_MATRIX, projection);
00407     tglGetIntegerv(TGL_VIEWPORT, viewPort);
00408 
00409     // Set values outside of the screen range
00410     p1.x = 1000;
00411     p1.y = 1000;
00412     p2.x = -1000;
00413     p2.y = -1000;
00414 
00415     // Project all of the points in the 3D bounding box
00416     Math::Vector3d p, projected;
00417     for (int x = 0; x < 2; x++) {
00418         for (int y = 0; y < 2; y++) {
00419             for (int z = 0; z < 2; z++) {
00420                 Math::Vector3d added(bboxSize.x() * 0.5f * (x * 2 - 1), bboxSize.y() * 0.5f * (y * 2 - 1), bboxSize.z() * 0.5f * (z * 2 - 1));
00421                 m.transform(&added, false);
00422                 p = bboxPos + added;
00423                 Math::gluMathProject<TGLfloat, TGLint>(p, modelView, projection, viewPort, projected);
00424 
00425                 // Find the points
00426                 if (projected.x() < p1.x)
00427                     p1.x = projected.x();
00428                 if (projected.y() < p1.y)
00429                     p1.y = projected.y();
00430                 if (projected.x() > p2.x)
00431                     p2.x = projected.x();
00432                 if (projected.y() > p2.y)
00433                     p2.y = projected.y();
00434             }
00435         }
00436     }
00437 
00438     // Swap the p1/p2 y coorindates
00439     int16 tmp = p1.y;
00440     p1.y = 480 - p2.y;
00441     p2.y = 480 - tmp;
00442 
00443     // Restore the state
00444     tglPopMatrix();
00445 }
00446 
00447 
00448 void GfxTinyGL::startActorDraw(const Actor *actor) {
00449     _currentActor = actor;
00450     tglEnable(TGL_TEXTURE_2D);
00451     tglMatrixMode(TGL_PROJECTION);
00452     tglPushMatrix();
00453     tglMatrixMode(TGL_MODELVIEW);
00454     tglPushMatrix();
00455 
00456     if (g_grim->getGameType() == GType_MONKEY4 && !actor->isInOverworld()) {
00457         // Apply the view transform.
00458         tglMultMatrixf(_currentRot.getData());
00459         tglTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
00460     }
00461 
00462     if (_currentShadowArray) {
00463         tglDepthMask(TGL_FALSE);
00464         // TODO find out why shadowMask at device in woods is null
00465         if (!_currentShadowArray->shadowMask) {
00466             _currentShadowArray->shadowMask = new byte[_gameWidth * _gameHeight];
00467             _currentShadowArray->shadowMaskSize = _gameWidth * _gameHeight;
00468         }
00469         assert(_currentShadowArray->shadowMask);
00470         //tglSetShadowColor(255, 255, 255);
00471         if (g_grim->getGameType() == GType_GRIM) {
00472             tglSetShadowColor(_shadowColorR, _shadowColorG, _shadowColorB);
00473         } else {
00474             tglSetShadowColor(_currentShadowArray->color.getRed(), _currentShadowArray->color.getGreen(), _currentShadowArray->color.getBlue());
00475         }
00476         tglSetShadowMaskBuf(_currentShadowArray->shadowMask);
00477         SectorListType::iterator i = _currentShadowArray->planeList.begin();
00478         Sector *shadowSector = i->sector;
00479         tglShadowProjection(_currentShadowArray->pos, shadowSector->getVertices()[0], shadowSector->getNormal(), _currentShadowArray->dontNegate);
00480     }
00481 
00482     const float alpha = actor->getEffectiveAlpha();
00483     if (alpha < 1.f) {
00484         _alpha = alpha;
00485         tglEnable(TGL_BLEND);
00486         tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
00487     }
00488 
00489     if (g_grim->getGameType() == GType_MONKEY4) {
00490         tglEnable(TGL_CULL_FACE);
00491         tglFrontFace(TGL_CW);
00492 
00493         if (actor->isInOverworld()) {
00494             const Math::Vector3d &pos = actor->getWorldPos();
00495             const Math::Quaternion &quat = actor->getRotationQuat();
00496             // At distance 3.2, a 6.4x4.8 actor fills the screen.
00497             tglMatrixMode(TGL_PROJECTION);
00498             tglLoadIdentity();
00499             float right = 1;
00500             float top = right * 0.75;
00501             float div = 6.0f;
00502             tglFrustum(-right / div, right / div, -top / div, top / div, 1.0f / div, 3276.8f);
00503             tglMatrixMode(TGL_MODELVIEW);
00504             tglLoadIdentity();
00505             tglScalef(1.0, 1.0, -1.0);
00506             tglTranslatef(pos.x(), pos.y(), pos.z());
00507             tglMultMatrixf(quat.toMatrix().getData());
00508         } else {
00509             Math::Matrix4 m = actor->getFinalMatrix();
00510             m.transpose();
00511             tglMultMatrixf(m.getData());
00512         }
00513     } else {
00514         // Grim
00515         Math::Vector3d pos = actor->getWorldPos();
00516         const Math::Quaternion &quat = actor->getRotationQuat();
00517         const float &scale = actor->getScale();
00518 
00519         tglTranslatef(pos.x(), pos.y(), pos.z());
00520         tglScalef(scale, scale, scale);
00521         tglMultMatrixf(quat.toMatrix().getData());
00522     }
00523 }
00524 
00525 void GfxTinyGL::finishActorDraw() {
00526     tglMatrixMode(TGL_MODELVIEW);
00527     tglPopMatrix();
00528     tglMatrixMode(TGL_PROJECTION);
00529     tglPopMatrix();
00530     tglMatrixMode(TGL_MODELVIEW);
00531 
00532     tglDisable(TGL_TEXTURE_2D);
00533     if (_alpha < 1.f) {
00534         tglDisable(TGL_BLEND);
00535         _alpha = 1.f;
00536     }
00537 
00538     if (_currentShadowArray) {
00539         tglSetShadowMaskBuf(nullptr);
00540     }
00541 
00542     if (g_grim->getGameType() == GType_MONKEY4) {
00543         tglDisable(TGL_CULL_FACE);
00544     }
00545 
00546     tglColorMask(TGL_TRUE, TGL_TRUE, TGL_TRUE, TGL_TRUE);
00547     _currentActor = nullptr;
00548 }
00549 
00550 void GfxTinyGL::drawShadowPlanes() {
00551     tglEnable(TGL_SHADOW_MASK_MODE);
00552     tglDepthMask(TGL_FALSE);
00553     tglPushMatrix();
00554 
00555     if (g_grim->getGameType() == GType_MONKEY4) {
00556         // Apply the view transform.
00557         tglMultMatrixf(_currentRot.getData());
00558         tglTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
00559     }
00560 
00561     if (!_currentShadowArray->shadowMask) {
00562         _currentShadowArray->shadowMask = new byte[_gameWidth * _gameHeight];
00563         _currentShadowArray->shadowMaskSize = _gameWidth * _gameHeight;
00564     }
00565     memset(_currentShadowArray->shadowMask, 0, _gameWidth * _gameHeight);
00566 
00567     tglSetShadowMaskBuf(_currentShadowArray->shadowMask);
00568     _currentShadowArray->planeList.begin();
00569     for (SectorListType::iterator i = _currentShadowArray->planeList.begin(); i != _currentShadowArray->planeList.end(); ++i) {
00570         Sector *shadowSector = i->sector;
00571         tglBegin(TGL_POLYGON);
00572         for (int k = 0; k < shadowSector->getNumVertices(); k++) {
00573             tglVertex3f(shadowSector->getVertices()[k].x(), shadowSector->getVertices()[k].y(), shadowSector->getVertices()[k].z());
00574         }
00575         tglEnd();
00576     }
00577     tglSetShadowMaskBuf(nullptr);
00578     tglDisable(TGL_SHADOW_MASK_MODE);
00579     tglDepthMask(TGL_TRUE);
00580 
00581     tglPopMatrix();
00582 }
00583 
00584 void GfxTinyGL::setShadowMode() {
00585     GfxBase::setShadowMode();
00586     tglEnable(TGL_SHADOW_MODE);
00587 }
00588 
00589 void GfxTinyGL::clearShadowMode() {
00590     GfxBase::clearShadowMode();
00591     tglDisable(TGL_SHADOW_MODE);
00592     tglDepthMask(TGL_TRUE);
00593 }
00594 
00595 void GfxTinyGL::set3DMode() {
00596     tglMatrixMode(TGL_MODELVIEW);
00597     tglEnable(TGL_DEPTH_TEST);
00598     tglDepthFunc(_depthFunc);
00599 }
00600 
00601 void GfxTinyGL::setShadow(Shadow *shadow) {
00602     _currentShadowArray = shadow;
00603     if (shadow)
00604         tglDisable(TGL_LIGHTING);
00605     else if (g_grim->getGameType() == GType_GRIM)
00606         tglEnable(TGL_LIGHTING);
00607 }
00608 
00609 void GfxTinyGL::setShadowColor(byte r, byte g, byte b) {
00610     _shadowColorR = r;
00611     _shadowColorG = g;
00612     _shadowColorB = b;
00613 }
00614 
00615 void GfxTinyGL::getShadowColor(byte *r, byte *g, byte *b) {
00616     *r = _shadowColorR;
00617     *g = _shadowColorG;
00618     *b = _shadowColorB;
00619 }
00620 
00621 void GfxTinyGL::drawEMIModelFace(const EMIModel *model, const EMIMeshFace *face) {
00622     int *indices = (int *)face->_indexes;
00623 
00624     tglEnable(TGL_DEPTH_TEST);
00625     tglDisable(TGL_ALPHA_TEST);
00626     tglDisable(TGL_LIGHTING);
00627     if (!_currentShadowArray && face->_hasTexture)
00628         tglEnable(TGL_TEXTURE_2D);
00629     else
00630         tglDisable(TGL_TEXTURE_2D);
00631     if (face->_flags & EMIMeshFace::kAlphaBlend || face->_flags & EMIMeshFace::kUnknownBlend || _currentActor->hasLocalAlpha() || _alpha < 1.0f)
00632         tglEnable(TGL_BLEND);
00633 
00634     tglBegin(TGL_TRIANGLES);
00635     float alpha = _alpha;
00636     if (model->_meshAlphaMode == Actor::AlphaReplace) {
00637         alpha *= model->_meshAlpha;
00638     }
00639     Math::Vector3d noLighting(1.f, 1.f, 1.f);
00640     for (uint j = 0; j < face->_faceLength * 3; j++) {
00641         int index = indices[j];
00642 
00643         if (!_currentShadowArray) {
00644             if (face->_hasTexture) {
00645                 tglTexCoord2f(model->_texVerts[index].getX(), model->_texVerts[index].getY());
00646             }
00647             Math::Vector3d lighting = (face->_flags & EMIMeshFace::kNoLighting) ? noLighting : model->_lighting[index];
00648             byte r = (byte)(model->_colorMap[index].r * lighting.x());
00649             byte g = (byte)(model->_colorMap[index].g * lighting.y());
00650             byte b = (byte)(model->_colorMap[index].b * lighting.z());
00651             byte a = (int)(model->_colorMap[index].a * alpha * _currentActor->getLocalAlpha(index));
00652             tglColor4ub(r, g, b, a);
00653         }
00654 
00655         Math::Vector3d normal = model->_normals[index];
00656         Math::Vector3d vertex = model->_drawVertices[index];
00657 
00658         tglNormal3fv(normal.getData());
00659         tglVertex3fv(vertex.getData());
00660     }
00661     tglEnd();
00662 
00663     if (!_currentShadowArray) {
00664         tglColor3f(1.0f, 1.0f, 1.0f);
00665     }
00666 
00667     tglEnable(TGL_TEXTURE_2D);
00668     tglEnable(TGL_DEPTH_TEST);
00669     tglEnable(TGL_ALPHA_TEST);
00670     tglEnable(TGL_LIGHTING);
00671     tglDisable(TGL_BLEND);
00672 
00673     if (!_currentShadowArray)
00674         tglDepthMask(TGL_TRUE);
00675 }
00676 
00677 void GfxTinyGL::drawModelFace(const Mesh *mesh, const MeshFace *face) {
00678     // Support transparency in actor objects, such as the message tube
00679     // in Manny's Office
00680     float *vertices = mesh->_vertices;
00681     float *vertNormals = mesh->_vertNormals;
00682     float *textureVerts = mesh->_textureVerts;
00683     tglAlphaFunc(TGL_GREATER, 0.5);
00684     tglEnable(TGL_ALPHA_TEST);
00685     tglNormal3fv(const_cast<float *>(face->getNormal().getData()));
00686     tglBegin(TGL_POLYGON);
00687     for (int i = 0; i < face->getNumVertices(); i++) {
00688         tglNormal3fv(vertNormals + 3 * face->getVertex(i));
00689 
00690         if (face->hasTexture())
00691             tglTexCoord2fv(textureVerts + 2 * face->getTextureVertex(i));
00692 
00693         tglVertex3fv(vertices + 3 * face->getVertex(i));
00694     }
00695     tglEnd();
00696     // Done with transparency-capable objects
00697     tglDisable(TGL_ALPHA_TEST);
00698 }
00699 
00700 void GfxTinyGL::drawSprite(const Sprite *sprite) {
00701     tglMatrixMode(TGL_TEXTURE);
00702     tglLoadIdentity();
00703     tglMatrixMode(TGL_MODELVIEW);
00704     tglPushMatrix();
00705 
00706     if (g_grim->getGameType() == GType_MONKEY4) {
00707         TGLfloat modelview[16];
00708         tglGetFloatv(TGL_MODELVIEW_MATRIX, modelview);
00709         Math::Matrix4 act;
00710         act.buildAroundZ(_currentActor->getYaw());
00711         act.transpose();
00712         act(3, 0) = modelview[12];
00713         act(3, 1) = modelview[13];
00714         act(3, 2) = modelview[14];
00715         tglLoadMatrixf(act.getData());
00716         tglTranslatef(sprite->_pos.x(), sprite->_pos.y(), -sprite->_pos.z());
00717     } else {
00718         tglTranslatef(sprite->_pos.x(), sprite->_pos.y(), sprite->_pos.z());
00719         TGLfloat modelview[16];
00720         tglGetFloatv(TGL_MODELVIEW_MATRIX, modelview);
00721 
00722         // We want screen-aligned sprites so reset the rotation part of the matrix.
00723         for (int i = 0; i < 3; i++) {
00724             for (int j = 0; j < 3; j++) {
00725                 if (i == j) {
00726                     modelview[i * 4 + j] = 1.0f;
00727                 } else {
00728                     modelview[i * 4 + j] = 0.0f;
00729                 }
00730             }
00731         }
00732         tglLoadMatrixf(modelview);
00733     }
00734 
00735     if (sprite->_flags1 & Sprite::BlendAdditive) {
00736         tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE);
00737     } else {
00738         tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
00739     }
00740 
00741     tglDisable(TGL_LIGHTING);
00742 
00743     if (g_grim->getGameType() == GType_GRIM) {
00744         tglEnable(TGL_ALPHA_TEST);
00745         tglAlphaFunc(TGL_GEQUAL, 0.5f);
00746     } else if (sprite->_flags2 & Sprite::AlphaTest) {
00747         tglEnable(TGL_ALPHA_TEST);
00748         tglAlphaFunc(TGL_GEQUAL, 0.1f);
00749     } else {
00750         tglDisable(TGL_ALPHA_TEST);
00751     }
00752 
00753     if (sprite->_flags2 & Sprite::DepthTest) {
00754         tglEnable(TGL_DEPTH_TEST);
00755     } else {
00756         tglDisable(TGL_DEPTH_TEST);
00757     }
00758 
00759     if (g_grim->getGameType() == GType_MONKEY4) {
00760         tglDepthMask(TGL_TRUE);
00761 
00762         float halfWidth = sprite->_width / 2;
00763         float halfHeight = sprite->_height / 2;
00764 
00765         float vertexX[] = { -1.0f, 1.0f, 1.0f, -1.0f };
00766         float vertexY[] = { 1.0f, 1.0f, -1.0f, -1.0f };
00767 
00768         tglBegin(TGL_POLYGON);
00769         for (int i = 0; i < 4; ++i) {
00770             float r = sprite->_red[i] / 255.0f;
00771             float g = sprite->_green[i] / 255.0f;
00772             float b = sprite->_blue[i] / 255.0f;
00773             float a = sprite->_alpha[i] * _alpha / 255.0f;
00774 
00775             tglColor4f(r, g, b, a);
00776             tglTexCoord2f(sprite->_texCoordX[i], sprite->_texCoordY[i]);
00777             tglVertex3f(vertexX[i] * halfWidth, vertexY[i] * halfHeight, 0.0f);
00778         }
00779         tglEnd();
00780         tglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
00781     } else {
00782         // In Grim, the bottom edge of the sprite is at y=0 and
00783         // the texture is flipped along the X-axis.
00784         float halfWidth = sprite->_width / 2;
00785         float height = sprite->_height;
00786 
00787         tglBegin(TGL_POLYGON);
00788         tglTexCoord2f(0.0f, 1.0f);
00789         tglVertex3f(+halfWidth, 0.0f, 0.0f);
00790         tglTexCoord2f(0.0f, 0.0f);
00791         tglVertex3f(+halfWidth, +height, 0.0f);
00792         tglTexCoord2f(1.0f, 0.0f);
00793         tglVertex3f(-halfWidth, +height, 0.0f);
00794         tglTexCoord2f(1.0f, 1.0f);
00795         tglVertex3f(-halfWidth, 0.0f, 0.0f);
00796         tglEnd();
00797     }
00798 
00799     tglEnable(TGL_LIGHTING);
00800     tglDisable(TGL_ALPHA_TEST);
00801     tglDepthMask(TGL_TRUE);
00802     tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
00803     tglDisable(TGL_BLEND);
00804     tglEnable(TGL_DEPTH_TEST);
00805 
00806     tglPopMatrix();
00807 }
00808 
00809 void GfxTinyGL::translateViewpointStart() {
00810     tglMatrixMode(TGL_MODELVIEW);
00811     tglPushMatrix();
00812 }
00813 
00814 void GfxTinyGL::translateViewpoint(const Math::Vector3d &vec) {
00815     tglTranslatef(vec.x(), vec.y(), vec.z());
00816 }
00817 
00818 void GfxTinyGL::rotateViewpoint(const Math::Angle &angle, const Math::Vector3d &axis) {
00819     tglRotatef(angle.getDegrees(), axis.x(), axis.y(), axis.z());
00820 }
00821 
00822 void GfxTinyGL::rotateViewpoint(const Math::Matrix4 &rot) {
00823     tglMultMatrixf(rot.getData());
00824 }
00825 
00826 void GfxTinyGL::translateViewpointFinish() {
00827     tglMatrixMode(TGL_MODELVIEW);
00828     tglPopMatrix();
00829 }
00830 
00831 void GfxTinyGL::enableLights() {
00832     tglEnable(TGL_LIGHTING);
00833 }
00834 
00835 void GfxTinyGL::disableLights() {
00836     tglDisable(TGL_LIGHTING);
00837 }
00838 
00839 void GfxTinyGL::setupLight(Light *light, int lightId) {
00840     assert(lightId < T_MAX_LIGHTS);
00841     tglEnable(TGL_LIGHTING);
00842     float lightColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
00843     float lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f };
00844     float lightDir[] = { 0.0f, 0.0f, -1.0f };
00845     float cutoff = 180.0f;
00846     float spot_exp = 0.0f;
00847     float q_attenuation = 1.0f;
00848 
00849     float intensity = light->_scaledintensity;
00850     lightColor[0] = (float)light->_color.getRed() * intensity;
00851     lightColor[1] = (float)light->_color.getGreen() * intensity;
00852     lightColor[2] = (float)light->_color.getBlue() * intensity;
00853 
00854     if (light->_type == Light::Omni) {
00855         lightPos[0] = light->_pos.x();
00856         lightPos[1] = light->_pos.y();
00857         lightPos[2] = light->_pos.z();
00858     } else if (light->_type ==  Light::Direct) {
00859         lightPos[0] = -light->_dir.x();
00860         lightPos[1] = -light->_dir.y();
00861         lightPos[2] = -light->_dir.z();
00862         lightPos[3] = 0;
00863     } else if (light->_type ==  Light::Spot) {
00864         lightPos[0] = light->_pos.x();
00865         lightPos[1] = light->_pos.y();
00866         lightPos[2] = light->_pos.z();
00867         lightDir[0] = light->_dir.x();
00868         lightDir[1] = light->_dir.y();
00869         lightDir[2] = light->_dir.z();
00870         spot_exp = 2.0f;
00871         cutoff = light->_penumbraangle;
00872         q_attenuation = 0.0f;
00873     }
00874 
00875     tglDisable(TGL_LIGHT0 + lightId);
00876     tglLightfv(TGL_LIGHT0 + lightId, TGL_DIFFUSE, lightColor);
00877     tglLightfv(TGL_LIGHT0 + lightId, TGL_POSITION, lightPos);
00878     tglLightfv(TGL_LIGHT0 + lightId, TGL_SPOT_DIRECTION, lightDir);
00879     tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_EXPONENT, spot_exp);
00880     tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_CUTOFF, cutoff);
00881     tglLightf(TGL_LIGHT0 + lightId, TGL_QUADRATIC_ATTENUATION, q_attenuation);
00882     tglEnable(TGL_LIGHT0 + lightId);
00883 }
00884 
00885 void GfxTinyGL::turnOffLight(int lightId) {
00886     tglDisable(TGL_LIGHT0 + lightId);
00887 }
00888 
00889 void GfxTinyGL::createBitmap(BitmapData *bitmap) {
00890     Graphics::BlitImage **imgs = new Graphics::BlitImage*[bitmap->_numImages];
00891     bitmap->_texIds = (void *)imgs;
00892 
00893     if (bitmap->_format != 1) {
00894         for (int pic = 0; pic < bitmap->_numImages; pic++) {
00895             uint32 *buf = new uint32[bitmap->_width * bitmap->_height];
00896             uint16 *bufPtr = reinterpret_cast<uint16 *>(bitmap->getImageData(pic).getRawBuffer());
00897             for (int i = 0; i < (bitmap->_width * bitmap->_height); i++) {
00898                 uint16 val = READ_LE_UINT16(bufPtr + i);
00899                 // fix the value if it is incorrectly set to the bitmap transparency color
00900                 if (val == 0xf81f) {
00901                     val = 0;
00902                 }
00903                 buf[i] = ((uint32)val) * 0x10000 / 100 / (0x10000 - val) << 14;
00904             }
00905             delete[] bufPtr;
00906             bitmap->_data[pic] = Graphics::PixelBuffer(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), (byte *)buf);
00907             imgs[pic] = Graphics::tglGenBlitImage();
00908             const Graphics::PixelBuffer &imageBuffer = bitmap->getImageData(pic);
00909             Graphics::Surface sourceSurface;
00910             sourceSurface.setPixels(imageBuffer.getRawBuffer());
00911             sourceSurface.format = imageBuffer.getFormat();
00912             sourceSurface.w = bitmap->_width;
00913             sourceSurface.h = bitmap->_height;
00914             sourceSurface.pitch = sourceSurface.w * imageBuffer.getFormat().bytesPerPixel;
00915             Graphics::tglUploadBlitImage(imgs[pic], sourceSurface, 0, false);
00916         }
00917     } else {
00918         for (int i = 0; i < bitmap->_numImages; ++i) {
00919             imgs[i] = Graphics::tglGenBlitImage();
00920             const Graphics::PixelBuffer &imageBuffer = bitmap->getImageData(i);
00921             Graphics::Surface sourceSurface;
00922             sourceSurface.setPixels(imageBuffer.getRawBuffer());
00923             sourceSurface.format = imageBuffer.getFormat();
00924             sourceSurface.w = bitmap->_width;
00925             sourceSurface.h = bitmap->_height;
00926             sourceSurface.pitch = sourceSurface.w * imageBuffer.getFormat().bytesPerPixel;
00927             Graphics::tglUploadBlitImage(imgs[i], sourceSurface, sourceSurface.format.ARGBToColor(0, 255, 0, 255), true);
00928         }
00929     }
00930 }
00931 
00932 void GfxTinyGL::drawBitmap(const Bitmap *bitmap, int x, int y, uint32 layer) {
00933     // PS2 EMI uses a TGA for it's splash-screen, avoid using the following
00934     // code for drawing that (as it has no tiles).
00935     if (g_grim->getGameType() == GType_MONKEY4 && bitmap->_data && bitmap->_data->_texc) {
00936         tglEnable(TGL_BLEND);
00937         tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
00938         tglColor3f(1.0f, 1.0f, 1.0f);
00939 
00940         BitmapData *data = bitmap->_data;
00941         float *texc = data->_texc;
00942 
00943         Graphics::BlitImage **b = (Graphics::BlitImage **)bitmap->getTexIds();
00944 
00945         assert(layer < data->_numLayers);
00946         uint32 offset = data->_layers[layer]._offset;
00947         for (uint32 i = offset; i < offset + data->_layers[layer]._numImages; ++i) {
00948             const BitmapData::Vert &v = data->_verts[i];
00949             uint32 texId = v._texid;
00950             uint32 ntex = data->_verts[i]._pos * 4;
00951             uint32 numRects = data->_verts[i]._verts / 4;
00952             while (numRects-- > 0) {
00953                 // TODO: better way to fix this:
00954                 // adding '+ 1' fixing broken lines at edges of bitmaps
00955                 // example: EMI ship scene
00956                 int dx1 = (((texc[ntex + 0] + 1) * _screenWidth) / 2) + 1;
00957                 int dy1 = (((1 - texc[ntex + 1]) * _screenHeight) / 2) + 1;
00958                 int dx2 = (((texc[ntex + 8] + 1) * _screenWidth) / 2) + 1;
00959                 int dy2 = (((1 - texc[ntex + 9]) * _screenHeight) / 2) + 1;
00960                 int srcX = texc[ntex + 2] * bitmap->getWidth();
00961                 int srcY = texc[ntex + 3] * bitmap->getHeight();
00962 
00963                 Graphics::BlitTransform transform(x + dx1, y + dy1);
00964                 transform.sourceRectangle(srcX, srcY, dx2 - dx1, dy2 - dy1);
00965                 transform.tint(1.0f, 1.0f - _dimLevel, 1.0f - _dimLevel, 1.0f  - _dimLevel);
00966                 Graphics::tglBlit(b[texId], transform);
00967                 ntex += 16;
00968             }
00969         }
00970 
00971         tglDisable(TGL_BLEND);
00972         return;
00973     }
00974 
00975     int format = bitmap->getFormat();
00976     if ((format == 1 && !_renderBitmaps) || (format == 5 && !_renderZBitmaps)) {
00977         return;
00978     }
00979 
00980     assert(bitmap->getActiveImage() > 0);
00981     const int num = bitmap->getActiveImage() - 1;
00982 
00983     Graphics::BlitImage **b = (Graphics::BlitImage **)bitmap->getTexIds();
00984 
00985     if (bitmap->getFormat() == 1) {
00986         if (bitmap->getHasTransparency()) {
00987             tglEnable(TGL_BLEND);
00988             tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
00989         }
00990         Graphics::tglBlit(b[num], x, y);
00991         if (bitmap->getHasTransparency()) {
00992             tglDisable(TGL_BLEND);
00993         }
00994     } else {
00995         Graphics::tglBlitZBuffer(b[num], x, y);
00996     }
00997 }
00998 
00999 void GfxTinyGL::destroyBitmap(BitmapData *bitmap) {
01000     Graphics::BlitImage **imgs = (Graphics::BlitImage **)bitmap->_texIds;
01001     for (int pic = 0; pic < bitmap->_numImages; pic++) {
01002         Graphics::tglDeleteBlitImage(imgs[pic]);
01003     }
01004     delete[] imgs;
01005 }
01006 
01007 void GfxTinyGL::createFont(Font *font) {
01008 }
01009 
01010 void GfxTinyGL::destroyFont(Font *font) {
01011 }
01012 
01013 struct TextObjectData {
01014     Graphics::BlitImage *image;
01015     int width, height, x, y;
01016 };
01017 
01018 void GfxTinyGL::createTextObject(TextObject *text) {
01019     int numLines = text->getNumLines();
01020     const Common::String *lines = text->getLines();
01021     const Font *font = text->getFont();
01022     const Color &fgColor = text->getFGColor();
01023     TextObjectData *userData = new TextObjectData[numLines];
01024     text->setUserData(userData);
01025     uint32 kKitmapColorkey = _pixelFormat.RGBToColor(0, 255, 0);
01026     const uint32 blackColor = _pixelFormat.RGBToColor(0, 0, 0);
01027     const uint32 color = _pixelFormat.RGBToColor(fgColor.getRed(), fgColor.getGreen(), fgColor.getBlue());
01028     while (color == kKitmapColorkey || blackColor == kKitmapColorkey) {
01029         kKitmapColorkey += 1;
01030     }
01031     for (int j = 0; j < numLines; j++) {
01032         const Common::String &currentLine = lines[j];
01033 
01034         int width = font->getBitmapStringLength(currentLine) + 1;
01035         int height = font->getStringHeight(currentLine) + 1;
01036 
01037         uint8 *_textBitmap = new uint8[height * width];
01038         memset(_textBitmap, 0, height * width);
01039 
01040         int startColumn = 0;
01041         for (unsigned int d = 0; d < currentLine.size(); d++) {
01042             int ch = currentLine[d];
01043             int32 charBitmapWidth = font->getCharBitmapWidth(ch);
01044             int8 fontRow = font->getCharStartingLine(ch) + font->getBaseOffsetY();
01045             int8 fontCol = font->getCharStartingCol(ch);
01046 
01047             for (int line = 0; line < font->getCharBitmapHeight(ch); line++) {
01048                 int lineOffset = ((fontRow + line) * width);
01049                 for (int bitmapCol = 0; bitmapCol < charBitmapWidth; bitmapCol++) {
01050                     int columnOffset = startColumn + fontCol + bitmapCol;
01051                     int fontOffset = (charBitmapWidth * line) + bitmapCol;
01052                     int8 pixel = font->getCharData(ch)[fontOffset];
01053                     assert(lineOffset + columnOffset < width*height);
01054                     if (pixel != 0)
01055                         _textBitmap[lineOffset + columnOffset] = pixel;
01056                 }
01057             }
01058             startColumn += font->getCharKernedWidth(ch);
01059         }
01060 
01061         Graphics::PixelBuffer buf(_pixelFormat, width * height, DisposeAfterUse::YES);
01062 
01063         uint8 *bitmapData = _textBitmap;
01064 
01065         int txData = 0;
01066         for (int i = 0; i < width * height; i++, txData++, bitmapData++) {
01067             byte pixel = *bitmapData;
01068             if (pixel == 0x00) {
01069                 buf.setPixelAt(txData, kKitmapColorkey);
01070             } else if (pixel == 0x80) {
01071                 buf.setPixelAt(txData, blackColor);
01072             } else if (pixel == 0xFF) {
01073                 buf.setPixelAt(txData, color);
01074             }
01075         }
01076 
01077         userData[j].width = width;
01078         userData[j].height = height;
01079 
01080         Graphics::Surface sourceSurface;
01081         sourceSurface.setPixels(buf.getRawBuffer());
01082         sourceSurface.format = buf.getFormat();
01083         sourceSurface.w = width;
01084         sourceSurface.h = height;
01085         sourceSurface.pitch = sourceSurface.w * buf.getFormat().bytesPerPixel;
01086         userData[j].image = Graphics::tglGenBlitImage();
01087         Graphics::tglUploadBlitImage(userData[j].image, sourceSurface, kKitmapColorkey, true);
01088         userData[j].x = text->getLineX(j);
01089         userData[j].y = text->getLineY(j);
01090 
01091         if (g_grim->getGameType() == GType_MONKEY4) {
01092             userData[j].y -= font->getBaseOffsetY();
01093             if (userData[j].y < 0)
01094                 userData[j].y = 0;
01095         }
01096 
01097         delete[] _textBitmap;
01098     }
01099 }
01100 
01101 void GfxTinyGL::drawTextObject(const TextObject *text) {
01102     const TextObjectData *userData = (const TextObjectData *)text->getUserData();
01103     if (userData) {
01104         tglEnable(TGL_BLEND);
01105         tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
01106         int numLines = text->getNumLines();
01107         for (int i = 0; i < numLines; ++i) {
01108             Graphics::tglBlit(userData[i].image, userData[i].x, userData[i].y);
01109         }
01110         tglDisable(TGL_BLEND);
01111     }
01112 }
01113 
01114 void GfxTinyGL::destroyTextObject(TextObject *text) {
01115     const TextObjectData *userData = (const TextObjectData *)text->getUserData();
01116     if (userData) {
01117         int numLines = text->getNumLines();
01118         for (int i = 0; i < numLines; ++i) {
01119             Graphics::tglDeleteBlitImage(userData[i].image);
01120         }
01121         delete[] userData;
01122     }
01123 }
01124 
01125 void GfxTinyGL::createTexture(Texture *texture, const uint8 *data, const CMap *cmap, bool clamp) {
01126     texture->_texture = new TGLuint[1];
01127     tglGenTextures(1, (TGLuint *)texture->_texture);
01128     uint8 *texdata = new uint8[texture->_width * texture->_height * 4];
01129     uint8 *texdatapos = texdata;
01130 
01131     if (cmap != nullptr) { // EMI doesn't have colour-maps
01132         for (int y = 0; y < texture->_height; y++) {
01133             for (int x = 0; x < texture->_width; x++) {
01134                 uint8 col = *data;
01135                 if (col == 0) {
01136                     memset(texdatapos, 0, 4); // transparent
01137                     if (!texture->_hasAlpha) {
01138                         texdatapos[3] = '\xff'; // fully opaque
01139                     }
01140                 } else {
01141                     memcpy(texdatapos, cmap->_colors + 3 * (col), 3);
01142                     texdatapos[3] = '\xff'; // fully opaque
01143                 }
01144                 texdatapos += 4;
01145                 data++;
01146             }
01147         }
01148     } else {
01149 #ifdef SCUMM_BIG_ENDIAN
01150         // Copy and swap
01151         for (int y = 0; y < texture->_height; y++) {
01152             for (int x = 0; x < texture->_width; x++) {
01153                 uint32 pixel = (y * texture->_width + x) * texture->_bpp;
01154                 for (int b = 0; b < texture->_bpp; b++) {
01155                     texdata[pixel + b] = data[pixel + (texture->_bpp - 1) - b];
01156                 }
01157             }
01158         }
01159 #else
01160         memcpy(texdata, data, texture->_width * texture->_height * texture->_bpp);
01161 #endif
01162     }
01163 
01164     TGLuint format = 0;
01165 //  TGLuint internalFormat = 0;
01166     if (texture->_colorFormat == BM_RGBA) {
01167         format = TGL_RGBA;
01168 //      internalFormat = TGL_RGBA;
01169     } else if (texture->_colorFormat == BM_BGRA) {
01170         format = TGL_BGRA;
01171     } else {    // The only other colorFormat we load right now is BGR
01172         format = TGL_BGR;
01173 //      internalFormat = TGL_RGB;
01174     }
01175 
01176     TGLuint *textures = (TGLuint *)texture->_texture;
01177     tglBindTexture(TGL_TEXTURE_2D, textures[0]);
01178 
01179     // TinyGL doesn't have issues with dark lines in EMI intro so doesn't need TGL_CLAMP_TO_EDGE
01180     tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_WRAP_S, TGL_REPEAT);
01181     tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_WRAP_T, TGL_REPEAT);
01182 
01183     tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MAG_FILTER, TGL_LINEAR);
01184     tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MIN_FILTER, TGL_LINEAR);
01185     tglTexImage2D(TGL_TEXTURE_2D, 0, 3, texture->_width, texture->_height, 0, format, TGL_UNSIGNED_BYTE, texdata);
01186     delete[] texdata;
01187 }
01188 
01189 void GfxTinyGL::selectTexture(const Texture *texture) {
01190     TGLuint *textures = (TGLuint *)texture->_texture;
01191     tglBindTexture(TGL_TEXTURE_2D, textures[0]);
01192     
01193     if (texture->_hasAlpha && g_grim->getGameType() == GType_MONKEY4) {
01194         tglEnable(TGL_BLEND);
01195     }   
01196 
01197     // Grim has inverted tex-coords, EMI doesn't
01198     if (g_grim->getGameType() != GType_MONKEY4) {
01199         tglMatrixMode(TGL_TEXTURE);
01200         tglLoadIdentity();
01201         tglScalef(1.0f / texture->_width, 1.0f / texture->_height, 1);
01202     }
01203 }
01204 
01205 void GfxTinyGL::destroyTexture(Texture *texture) {
01206     TGLuint *textures = (TGLuint *)texture->_texture;
01207     if (textures) {
01208         tglDeleteTextures(1, textures);
01209         delete[] textures;
01210     }
01211 }
01212 
01213 void GfxTinyGL::prepareMovieFrame(Graphics::Surface *frame) {
01214     if (_smushImage == nullptr)
01215         _smushImage = Graphics::tglGenBlitImage();
01216     Graphics::tglUploadBlitImage(_smushImage, *frame, 0, false);
01217 }
01218 
01219 void GfxTinyGL::drawMovieFrame(int offsetX, int offsetY) {
01220     Graphics::tglBlitFast(_smushImage, offsetX, offsetY);
01221 }
01222 
01223 void GfxTinyGL::releaseMovieFrame() {
01224     Graphics::tglDeleteBlitImage(_smushImage);
01225 }
01226 
01227 void GfxTinyGL::loadEmergFont() {
01228     Graphics::Surface characterSurface;
01229     Graphics::PixelFormat textureFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
01230     characterSurface.create(8, 13, textureFormat);
01231     uint32 color = textureFormat.ARGBToColor(255, 255, 255, 255);
01232     uint32 colorTransparent = textureFormat.ARGBToColor(0, 255, 255, 255);
01233     for (int i = 0; i < 96; i++) {
01234         _emergFont[i] = Graphics::tglGenBlitImage();
01235         const uint8 *ptr = Font::emerFont[i];
01236         for (int py = 0; py < 13; py++) {
01237                 int line = ptr[12 - py];
01238                 for (int px = 0; px < 8; px++) {
01239                     int pixel = line & 0x80;
01240                     line <<= 1;
01241                     *(uint32 *)characterSurface.getBasePtr(px, py) = pixel ? color : colorTransparent;
01242                 }
01243         }
01244         Graphics::tglUploadBlitImage(_emergFont[i], characterSurface, 0, false);
01245     }
01246     characterSurface.free();
01247 }
01248 
01249 void GfxTinyGL::drawEmergString(int x, int y, const char *text, const Color &fgColor) {
01250     int length = strlen(text);
01251 
01252     for (int l = 0; l < length; l++) {
01253         int c = text[l];
01254         assert(c >= 32 && c <= 127);
01255         Graphics::BlitTransform transform(x, y);
01256         transform.tint(1.0f, fgColor.getRed() / 255.0f, fgColor.getGreen() / 255.0f, fgColor.getBlue() / 255.0f);
01257         Graphics::tglBlit(_emergFont[c - 32], transform);
01258         x += 10;
01259     }
01260 }
01261 
01262 Bitmap *GfxTinyGL::getScreenshot(int w, int h, bool useStored) {
01263     if (useStored) {
01264         return createScreenshotBitmap(_storedDisplay, w, h, true);
01265     } else {
01266         Graphics::PixelBuffer src(_pixelFormat, _screenWidth * _screenHeight, DisposeAfterUse::YES);
01267         _zb->copyToBuffer(src);
01268         return createScreenshotBitmap(src, w, h, true);
01269     }
01270 }
01271 
01272 void GfxTinyGL::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height) {
01273     readPixels(x, y, width, height, data);
01274     createSpecialtyTexture(id, data, width, height);
01275 }
01276 
01277 void GfxTinyGL::storeDisplay() {
01278     TinyGL::tglPresentBuffer();
01279     _zb->copyToBuffer(_storedDisplay);
01280 }
01281 
01282 void GfxTinyGL::copyStoredToDisplay() {
01283     Bitmap *bitmap = getScreenshot(_gameWidth, _gameHeight, true);
01284     drawBitmap(bitmap, 0, 0, 0);
01285     delete bitmap;
01286 }
01287 
01288 void GfxTinyGL::dimScreen() {
01289     dimRegion(0, 0, _gameWidth, _gameHeight, 0.2f);
01290 }
01291 
01292 void GfxTinyGL::dimRegion(int x, int y, int w, int h, float level) {
01293     tglMatrixMode(TGL_PROJECTION);
01294     tglLoadIdentity();
01295     tglOrtho(0, _gameWidth, _gameHeight, 0, 0, 1);
01296     tglMatrixMode(TGL_MODELVIEW);
01297     tglLoadIdentity();
01298 
01299     tglDisable(TGL_LIGHTING);
01300     tglDisable(TGL_DEPTH_TEST);
01301     tglDepthMask(TGL_FALSE);
01302     tglEnable(TGL_BLEND);
01303     tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
01304 
01305     tglColor4f(0, 0, 0, 1 - level);
01306 
01307     tglBegin(TGL_QUADS);
01308     tglVertex2f(x, y);
01309     tglVertex2f(x + w, y);
01310     tglVertex2f(x + w, y + h);
01311     tglVertex2f(x, y + h);
01312     tglEnd();
01313 
01314     tglColor3f(1.0f, 1.0f, 1.0f);
01315 
01316     tglDisable(TGL_BLEND);
01317     tglDepthMask(TGL_TRUE);
01318     tglEnable(TGL_DEPTH_TEST);
01319     tglEnable(TGL_LIGHTING);
01320 }
01321 
01322 void GfxTinyGL::irisAroundRegion(int x1, int y1, int x2, int y2) {
01323     tglMatrixMode(TGL_PROJECTION);
01324     tglLoadIdentity();
01325     tglOrtho(0.0, _gameWidth, _gameHeight, 0.0, 0.0, 1.0);
01326     tglMatrixMode(TGL_MODELVIEW);
01327     tglLoadIdentity();
01328 
01329     tglDisable(TGL_DEPTH_TEST);
01330     tglDisable(TGL_TEXTURE_2D);
01331     tglDisable(TGL_BLEND);
01332     tglDisable(TGL_LIGHTING);
01333     tglDepthMask(TGL_FALSE);
01334 
01335     tglColor3f(0.0f, 0.0f, 0.0f);
01336 
01337     //Explicitly cast to avoid problems with C++11
01338     float fx1 = x1;
01339     float fx2 = x2;
01340     float fy1 = y1;
01341     float fy2 = y2;
01342     float width = _screenWidth;
01343     float height = _screenHeight;
01344     float points[20] = {
01345         0.0f, 0.0f,
01346         0.0f, fy1,
01347         width, 0.0f,
01348         fx2, fy1,
01349         width, height,
01350         fx2, fy2,
01351         0.0f, height,
01352         fx1, fy2,
01353         0.0f, fy1,
01354         fx1, fy1
01355     };
01356 
01357     tglEnableClientState(TGL_VERTEX_ARRAY);
01358     tglVertexPointer(2, TGL_FLOAT, 0, points);
01359     tglDrawArrays(TGL_TRIANGLE_STRIP, 0, 10);
01360     tglDisableClientState(TGL_VERTEX_ARRAY);
01361 
01362     tglColor3f(1.0f, 1.0f, 1.0f);
01363     tglEnable(TGL_DEPTH_TEST);
01364     tglEnable(TGL_LIGHTING);
01365     tglDepthMask(TGL_TRUE);
01366 }
01367 
01368 void GfxTinyGL::drawRectangle(const PrimitiveObject *primitive) {
01369     float x1 = primitive->getP1().x * _scaleW;
01370     float y1 = primitive->getP1().y * _scaleH;
01371     float x2 = primitive->getP2().x * _scaleW;
01372     float y2 = primitive->getP2().y * _scaleH;
01373     const Color color(primitive->getColor());
01374 
01375     tglMatrixMode(TGL_PROJECTION);
01376     tglLoadIdentity();
01377     tglOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01378     tglMatrixMode(TGL_MODELVIEW);
01379     tglLoadIdentity();
01380 
01381     tglDisable(TGL_LIGHTING);
01382     tglDisable(TGL_DEPTH_TEST);
01383     tglDepthMask(TGL_FALSE);
01384 
01385     tglColor3ub(color.getRed(), color.getGreen(), color.getBlue());
01386 
01387     if (primitive->isFilled()) {
01388         tglBegin(TGL_QUADS);
01389         tglVertex2f(x1, y1);
01390         tglVertex2f(x2 + 1, y1);
01391         tglVertex2f(x2 + 1, y2 + 1);
01392         tglVertex2f(x1, y2 + 1);
01393         tglEnd();
01394     } else {
01395         tglBegin(TGL_LINE_LOOP);
01396         tglVertex2f(x1, y1);
01397         tglVertex2f(x2 + 1, y1);
01398         tglVertex2f(x2 + 1, y2 + 1);
01399         tglVertex2f(x1, y2 + 1);
01400         tglEnd();
01401     }
01402 
01403     tglColor3f(1.0f, 1.0f, 1.0f);
01404 
01405     tglDepthMask(TGL_TRUE);
01406     tglEnable(TGL_DEPTH_TEST);
01407     tglEnable(TGL_LIGHTING);
01408 }
01409 
01410 void GfxTinyGL::drawLine(const PrimitiveObject *primitive) {
01411     float x1 = primitive->getP1().x * _scaleW;
01412     float y1 = primitive->getP1().y * _scaleH;
01413     float x2 = primitive->getP2().x * _scaleW;
01414     float y2 = primitive->getP2().y * _scaleH;
01415 
01416     const Color &color = primitive->getColor();
01417 
01418     tglMatrixMode(TGL_PROJECTION);
01419     tglLoadIdentity();
01420     tglOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01421     tglMatrixMode(TGL_MODELVIEW);
01422     tglLoadIdentity();
01423 
01424     tglDisable(TGL_LIGHTING);
01425     tglDisable(TGL_DEPTH_TEST);
01426     tglDepthMask(TGL_FALSE);
01427 
01428     tglColor3ub(color.getRed(), color.getGreen(), color.getBlue());
01429 
01430 //  tglLineWidth(_scaleW); // Not implemented in TinyGL
01431 
01432     tglBegin(TGL_LINES);
01433     tglVertex2f(x1, y1);
01434     tglVertex2f(x2, y2);
01435     tglEnd();
01436 
01437     tglColor3f(1.0f, 1.0f, 1.0f);
01438 
01439     tglDepthMask(TGL_TRUE);
01440     tglEnable(TGL_DEPTH_TEST);
01441     tglEnable(TGL_LIGHTING);
01442 }
01443 
01444 void GfxTinyGL::drawDimPlane() {
01445     if (_dimLevel == 0.0f) return;
01446 
01447     tglMatrixMode(TGL_PROJECTION);
01448     tglLoadIdentity();
01449 
01450     tglMatrixMode(TGL_MODELVIEW);
01451     tglLoadIdentity();
01452 
01453     tglDisable(TGL_DEPTH_TEST);
01454     tglDepthMask(TGL_FALSE);
01455 
01456     tglDisable(TGL_LIGHTING);
01457     tglEnable(TGL_BLEND);
01458     tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
01459 
01460     tglColor4f(0.0f, 0.0f, 0.0f, _dimLevel);
01461 
01462     tglBegin(TGL_QUADS);
01463     tglVertex2f(-1, -1);
01464     tglVertex2f(1.0, -1);
01465     tglVertex2f(1.0, 1.0);
01466     tglVertex2f(-1, 1.0);
01467     tglEnd();
01468 
01469     tglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
01470 
01471     tglDisable(TGL_BLEND);
01472     tglDepthMask(TGL_TRUE);
01473     tglEnable(TGL_DEPTH_TEST);
01474     tglEnable(TGL_LIGHTING);
01475 }
01476 
01477 void GfxTinyGL::drawPolygon(const PrimitiveObject *primitive) {
01478     float x1 = primitive->getP1().x * _scaleW;
01479     float y1 = primitive->getP1().y * _scaleH;
01480     float x2 = primitive->getP2().x * _scaleW;
01481     float y2 = primitive->getP2().y * _scaleH;
01482     float x3 = primitive->getP3().x * _scaleW;
01483     float y3 = primitive->getP3().y * _scaleH;
01484     float x4 = primitive->getP4().x * _scaleW;
01485     float y4 = primitive->getP4().y * _scaleH;
01486 
01487     const Color &color = primitive->getColor();
01488 
01489     tglMatrixMode(TGL_PROJECTION);
01490     tglLoadIdentity();
01491     tglOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01492     tglMatrixMode(TGL_MODELVIEW);
01493     tglLoadIdentity();
01494 
01495     tglDisable(TGL_LIGHTING);
01496     tglDisable(TGL_DEPTH_TEST);
01497     tglDepthMask(TGL_FALSE);
01498 
01499     tglColor3ub(color.getRed(), color.getGreen(), color.getBlue());
01500 
01501     tglBegin(TGL_LINES);
01502     tglVertex2f(x1, y1);
01503     tglVertex2f(x2 + 1, y2 + 1);
01504     tglVertex2f(x3, y3 + 1);
01505     tglVertex2f(x4 + 1, y4);
01506     tglEnd();
01507 
01508     tglColor3f(1.0f, 1.0f, 1.0f);
01509 
01510     tglDepthMask(TGL_TRUE);
01511     tglEnable(TGL_DEPTH_TEST);
01512     tglEnable(TGL_LIGHTING);
01513 }
01514 
01515 void GfxTinyGL::readPixels(int x, int y, int width, int height, uint8 *buffer) {
01516     assert(x >= 0);
01517     assert(y >= 0);
01518     assert(x < _screenWidth);
01519     assert(y < _screenHeight);
01520 
01521     uint8 r, g, b;
01522     int pos = x + y * _screenWidth;
01523     for (int i = 0; i < height; ++i) {
01524         for (int j = 0; j < width; ++j) {
01525             if ((j + x) >= _screenWidth || (i + y) >= _screenHeight) {
01526                 buffer[0] = buffer[1] = buffer[2] = 0;
01527             } else {
01528                 _zb->readPixelRGB(pos + j, r, g, b);
01529                 buffer[0] = r;
01530                 buffer[1] = g;
01531                 buffer[2] = b;
01532             }
01533             buffer[3] = 255;
01534             buffer += 4;
01535         }
01536         pos += _screenWidth;
01537     }
01538 }
01539 
01540 void GfxTinyGL::setBlendMode(bool additive) {
01541     if (additive) {
01542         tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE);
01543     } else {
01544         tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
01545     }
01546 }
01547 
01548 } // end of namespace Grim


Generated on Sat Mar 16 2019 05:01:34 for ResidualVM by doxygen 1.7.1
curved edge   curved edge