2012-01-06 23:29:45 +01:00
|
|
|
/* ResidualVM - A 3D game interpreter
|
2009-05-05 11:34:43 +00:00
|
|
|
*
|
2012-01-06 23:29:45 +01:00
|
|
|
* ResidualVM is the legal property of its developers, whose names
|
2011-04-16 14:12:44 +02:00
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
2009-05-05 11:34:43 +00:00
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
2012-12-19 23:15:43 +01:00
|
|
|
* 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 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2014-04-05 18:18:42 +02:00
|
|
|
*
|
2012-12-19 23:15:43 +01:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
2009-05-05 11:34:43 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2012-12-19 23:15:43 +01:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2014-04-05 18:18:42 +02:00
|
|
|
*
|
2012-12-19 23:15:43 +01:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2009-05-05 11:34:43 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common/endian.h"
|
2009-05-07 19:06:31 +00:00
|
|
|
#include "common/system.h"
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2011-10-01 22:40:31 +02:00
|
|
|
#include "graphics/surface.h"
|
2012-01-16 17:12:14 +01:00
|
|
|
#include "graphics/colormasks.h"
|
2011-10-01 22:40:31 +02:00
|
|
|
|
2014-07-10 07:29:01 +02:00
|
|
|
#include "math/glmath.h"
|
|
|
|
|
2009-05-24 19:13:58 +00:00
|
|
|
#include "engines/grim/actor.h"
|
|
|
|
#include "engines/grim/colormap.h"
|
|
|
|
#include "engines/grim/material.h"
|
|
|
|
#include "engines/grim/font.h"
|
|
|
|
#include "engines/grim/gfx_tinygl.h"
|
2009-06-26 16:13:11 +00:00
|
|
|
#include "engines/grim/grim.h"
|
2011-05-13 17:55:14 -07:00
|
|
|
#include "engines/grim/bitmap.h"
|
|
|
|
#include "engines/grim/primitives.h"
|
2011-07-23 12:14:33 +02:00
|
|
|
#include "engines/grim/model.h"
|
2013-07-07 17:18:30 -07:00
|
|
|
#include "engines/grim/sprite.h"
|
2011-09-19 16:53:08 +02:00
|
|
|
#include "engines/grim/set.h"
|
2012-01-29 16:14:36 +01:00
|
|
|
#include "engines/grim/emi/modelemi.h"
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2009-05-25 06:49:57 +00:00
|
|
|
namespace Grim {
|
|
|
|
|
2011-05-21 18:18:27 +02:00
|
|
|
GfxBase *CreateGfxTinyGL() {
|
|
|
|
return new GfxTinyGL();
|
|
|
|
}
|
|
|
|
|
2013-10-26 13:57:55 -07:00
|
|
|
GfxTinyGL::GfxTinyGL() :
|
2014-07-14 18:15:51 +02:00
|
|
|
_zb(nullptr), _alpha(1.f),
|
2014-05-29 15:35:46 -07:00
|
|
|
_bufferId(0), _currentActor(nullptr) {
|
2011-05-21 18:18:27 +02:00
|
|
|
g_driver = this;
|
2014-05-29 15:35:46 -07:00
|
|
|
_storedDisplay = nullptr;
|
2014-07-04 23:14:44 +02:00
|
|
|
// TGL_LEQUAL as tglDepthFunc ensures that subsequent drawing attempts for
|
|
|
|
// the same triangles are not ignored by the depth test.
|
|
|
|
// That's necessary for EMI where some models have multiple faces which
|
|
|
|
// refer to the same vertices. The first face is usually using the
|
|
|
|
// color map and the following are using textures.
|
|
|
|
_depthFunc = (g_grim->getGameType() == GType_MONKEY4) ? TGL_LEQUAL : TGL_LESS;
|
2014-08-13 15:39:03 +02:00
|
|
|
for (int i = 0; i < 96; i++) {
|
|
|
|
_emergFont[i] = nullptr;
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
GfxTinyGL::~GfxTinyGL() {
|
2014-12-31 01:42:44 +01:00
|
|
|
for (unsigned int i = 0; i < _numSpecialtyTextures; i++) {
|
|
|
|
destroyTexture(&_specialtyTextures[i]);
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
if (_zb) {
|
2013-01-11 12:39:12 +01:00
|
|
|
delBuffer(1);
|
2009-05-25 13:19:29 +00:00
|
|
|
TinyGL::glClose();
|
2014-06-06 01:34:10 +02:00
|
|
|
delete _zb;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2014-08-13 15:39:03 +02:00
|
|
|
for (int i = 0; i < 96; i++) {
|
|
|
|
Graphics::tglDeleteBlitImage(_emergFont[i]);
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-31 08:55:57 +00:00
|
|
|
byte *GfxTinyGL::setupScreen(int screenW, int screenH, bool fullscreen) {
|
2012-01-16 17:12:14 +01:00
|
|
|
Graphics::PixelBuffer buf = g_system->setupScreen(screenW, screenH, fullscreen, false);
|
|
|
|
byte *buffer = buf.getRawBuffer();
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
_screenWidth = screenW;
|
|
|
|
_screenHeight = screenH;
|
2012-11-13 22:26:31 +01:00
|
|
|
_scaleW = _screenWidth / (float)_gameWidth;
|
|
|
|
_scaleH = _screenHeight / (float)_gameHeight;
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
_isFullscreen = g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2011-06-02 12:16:04 +02:00
|
|
|
g_system->showMouse(!fullscreen);
|
|
|
|
|
2012-01-06 11:37:57 +01:00
|
|
|
g_system->setWindowCaption("ResidualVM: Software 3D Renderer");
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2012-01-16 17:12:14 +01:00
|
|
|
_pixelFormat = buf.getFormat();
|
2014-06-13 14:58:07 +02:00
|
|
|
_zb = new TinyGL::FrameBuffer(screenW, screenH, buf);
|
2014-07-05 13:08:34 +02:00
|
|
|
TinyGL::glInit(_zb, 256);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2012-01-25 23:02:24 +01:00
|
|
|
_storedDisplay.create(_pixelFormat, _gameWidth * _gameHeight, DisposeAfterUse::YES);
|
|
|
|
_storedDisplay.clear(_gameWidth * _gameHeight);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-05-29 15:35:46 -07:00
|
|
|
_currentShadowArray = nullptr;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2011-05-20 00:12:43 +02:00
|
|
|
TGLfloat ambientSource[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
2009-05-05 11:34:43 +00:00
|
|
|
tglLightModelfv(TGL_LIGHT_MODEL_AMBIENT, ambientSource);
|
2015-03-16 22:53:52 +01:00
|
|
|
TGLfloat diffuseReflectance[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
|
|
tglMaterialfv(TGL_FRONT, TGL_DIFFUSE, diffuseReflectance);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2013-01-11 12:39:12 +01:00
|
|
|
// we now generate a buffer (id 1), which we will use as a backing buffer, where the actors' clean buffers
|
|
|
|
// will blit to. everu frame this will be blitted to screen, but the actors' buffers will be blitted to
|
|
|
|
// this only when they change.
|
|
|
|
genBuffer();
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
return buffer;
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
const char *GfxTinyGL::getVideoDeviceName() {
|
|
|
|
return "TinyGL Software Renderer";
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2014-07-19 22:42:43 -04:00
|
|
|
void GfxTinyGL::setupCameraFrustum(float fov, float nclip, float fclip) {
|
2009-05-05 11:34:43 +00:00
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglLoadIdentity();
|
|
|
|
|
2009-05-10 14:15:07 +00:00
|
|
|
float right = nclip * tan(fov / 2 * (LOCAL_PI / 180));
|
2009-05-05 11:34:43 +00:00
|
|
|
tglFrustum(-right, right, -right * 0.75, right * 0.75, nclip, fclip);
|
|
|
|
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglLoadIdentity();
|
|
|
|
}
|
|
|
|
|
2012-06-08 00:03:05 +02:00
|
|
|
void GfxTinyGL::positionCamera(const Math::Vector3d &pos, const Math::Vector3d &interest, float roll) {
|
2014-08-05 15:43:39 -04:00
|
|
|
Math::Vector3d up_vec(0, 0, 1);
|
2012-07-03 00:09:24 +02:00
|
|
|
|
2014-08-05 15:43:39 -04:00
|
|
|
tglRotatef(roll, 0, 0, -1);
|
2012-07-03 00:09:24 +02:00
|
|
|
|
2014-08-05 15:43:39 -04:00
|
|
|
if (pos.x() == interest.x() && pos.y() == interest.y())
|
|
|
|
up_vec = Math::Vector3d(0, 1, 0);
|
2012-01-29 22:04:45 +01:00
|
|
|
|
2014-08-05 15:43:39 -04:00
|
|
|
Math::Matrix4 lookMatrix = Math::makeLookAtMatrix(pos, interest, up_vec);
|
|
|
|
tglMultMatrixf(lookMatrix.getData());
|
|
|
|
tglTranslatef(-pos.x(), -pos.y(), -pos.z());
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-08-05 15:43:39 -04:00
|
|
|
void GfxTinyGL::positionCamera(const Math::Vector3d &pos, const Math::Matrix4 &rot) {
|
|
|
|
tglScalef(1.0, 1.0, -1.0);
|
|
|
|
_currentPos = pos;
|
|
|
|
_currentRot = rot;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2014-06-09 18:41:01 +03:00
|
|
|
Math::Matrix4 GfxTinyGL::getModelView() {
|
|
|
|
Math::Matrix4 modelView;
|
|
|
|
|
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglPushMatrix();
|
|
|
|
|
2014-08-05 15:43:39 -04:00
|
|
|
tglMultMatrixf(_currentRot.getData());
|
2014-06-09 18:41:01 +03:00
|
|
|
tglTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
|
|
|
|
|
|
|
|
tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView.getData());
|
|
|
|
|
|
|
|
tglPopMatrix();
|
2014-07-03 21:02:01 +02:00
|
|
|
} else {
|
2014-06-09 18:41:01 +03:00
|
|
|
tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView.getData());
|
|
|
|
}
|
|
|
|
|
|
|
|
modelView.transpose();
|
|
|
|
return modelView;
|
|
|
|
}
|
|
|
|
|
|
|
|
Math::Matrix4 GfxTinyGL::getProjection() {
|
|
|
|
Math::Matrix4 projection;
|
|
|
|
tglGetFloatv(TGL_PROJECTION_MATRIX, projection.getData());
|
|
|
|
projection.transpose();
|
|
|
|
return projection;
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::clearScreen() {
|
2014-07-25 15:42:34 +02:00
|
|
|
tglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
tglClearDepth(0);
|
|
|
|
tglClear(TGL_DEPTH_BUFFER_BIT | TGL_COLOR_BUFFER_BIT);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2014-06-17 21:00:17 +02:00
|
|
|
void GfxTinyGL::clearDepthBuffer() {
|
2014-07-25 15:42:34 +02:00
|
|
|
tglClearDepth(0);
|
|
|
|
tglClear(TGL_DEPTH_BUFFER_BIT);
|
2014-06-17 21:00:17 +02:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::flipBuffer() {
|
2014-08-09 12:10:26 +02:00
|
|
|
TinyGL::tglPresentBuffer();
|
2009-05-07 19:06:31 +00:00
|
|
|
g_system->updateScreen();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2013-01-11 12:39:12 +01:00
|
|
|
int GfxTinyGL::genBuffer() {
|
2014-06-06 01:34:10 +02:00
|
|
|
TinyGL::Buffer *buf = _zb->genOffscreenBuffer();
|
2013-02-04 12:33:17 +01:00
|
|
|
_buffers[++_bufferId] = buf;
|
2013-01-11 12:39:12 +01:00
|
|
|
|
2013-02-04 12:33:17 +01:00
|
|
|
return _bufferId;
|
2013-01-11 12:39:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void GfxTinyGL::delBuffer(int id) {
|
2014-06-06 01:34:10 +02:00
|
|
|
_zb->delOffscreenBuffer(_buffers[id]);
|
2013-01-11 12:39:12 +01:00
|
|
|
_buffers.erase(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GfxTinyGL::selectBuffer(int id) {
|
|
|
|
if (id == 0) {
|
2014-06-06 01:34:10 +02:00
|
|
|
_zb->selectOffscreenBuffer(NULL);
|
2013-01-11 12:39:12 +01:00
|
|
|
} else {
|
2014-06-06 01:34:10 +02:00
|
|
|
_zb->selectOffscreenBuffer(_buffers[id]);
|
2013-01-11 12:39:12 +01:00
|
|
|
}
|
2012-02-13 18:01:03 +01:00
|
|
|
}
|
|
|
|
|
2013-01-11 12:39:12 +01:00
|
|
|
void GfxTinyGL::clearBuffer(int id) {
|
|
|
|
TinyGL::Buffer *buf = _buffers[id];
|
2014-06-06 01:34:10 +02:00
|
|
|
_zb->clearOffscreenBuffer(buf);
|
2012-02-13 18:01:03 +01:00
|
|
|
}
|
|
|
|
|
2013-01-11 12:39:12 +01:00
|
|
|
void GfxTinyGL::drawBuffers() {
|
|
|
|
selectBuffer(1);
|
|
|
|
Common::HashMap<int, TinyGL::Buffer *>::iterator i = _buffers.begin();
|
|
|
|
for (++i; i != _buffers.end(); ++i) {
|
|
|
|
TinyGL::Buffer *buf = i->_value;
|
2014-06-06 01:34:10 +02:00
|
|
|
_zb->blitOffscreenBuffer(buf);
|
2013-01-11 12:39:12 +01:00
|
|
|
//this is not necessary, but it prevents the buffers to be blitted every frame, if it is not needed
|
|
|
|
buf->used = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
selectBuffer(0);
|
2014-06-06 01:34:10 +02:00
|
|
|
_zb->blitOffscreenBuffer(_buffers[1]);
|
2012-02-13 18:01:03 +01:00
|
|
|
}
|
|
|
|
|
2013-01-11 12:39:12 +01:00
|
|
|
void GfxTinyGL::refreshBuffers() {
|
|
|
|
clearBuffer(1);
|
|
|
|
Common::HashMap<int, TinyGL::Buffer *>::iterator i = _buffers.begin();
|
|
|
|
for (++i; i != _buffers.end(); ++i) {
|
|
|
|
TinyGL::Buffer *buf = i->_value;
|
|
|
|
buf->used = true;
|
|
|
|
}
|
2012-05-28 15:18:58 +02:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
bool GfxTinyGL::isHardwareAccelerated() {
|
2009-05-05 11:34:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-06-23 00:24:43 +03:00
|
|
|
bool GfxTinyGL::supportsShaders() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-02-04 18:07:24 -08:00
|
|
|
static void tglShadowProjection(const Math::Vector3d &light, const Math::Vector3d &plane, const Math::Vector3d &normal, bool dontNegate) {
|
2009-05-05 11:34:43 +00:00
|
|
|
// Based on GPL shadow projection example by
|
|
|
|
// (c) 2002-2003 Phaetos <phaetos@gaffga.de>
|
|
|
|
float d, c;
|
|
|
|
float mat[16];
|
|
|
|
float nx, ny, nz, lx, ly, lz, px, py, pz;
|
|
|
|
|
2011-05-01 06:15:37 +08:00
|
|
|
nx = normal.x();
|
|
|
|
ny = normal.y();
|
|
|
|
nz = normal.z();
|
2009-05-05 11:34:43 +00:00
|
|
|
// for some unknown for me reason normal need negation
|
2011-05-01 06:15:37 +08:00
|
|
|
if (!dontNegate) {
|
2009-05-05 11:34:43 +00:00
|
|
|
nx = -nx;
|
|
|
|
ny = -ny;
|
|
|
|
nz = -nz;
|
|
|
|
}
|
|
|
|
lx = light.x();
|
|
|
|
ly = light.y();
|
|
|
|
lz = light.z();
|
|
|
|
px = plane.x();
|
|
|
|
py = plane.y();
|
|
|
|
pz = plane.z();
|
|
|
|
|
|
|
|
d = nx * lx + ny * ly + nz * lz;
|
|
|
|
c = px * nx + py * ny + pz * nz - d;
|
|
|
|
|
|
|
|
mat[0] = lx * nx + c;
|
|
|
|
mat[4] = ny * lx;
|
|
|
|
mat[8] = nz * lx;
|
|
|
|
mat[12] = -lx * c - lx * d;
|
|
|
|
|
|
|
|
mat[1] = nx * ly;
|
|
|
|
mat[5] = ly * ny + c;
|
|
|
|
mat[9] = nz * ly;
|
|
|
|
mat[13] = -ly * c - ly * d;
|
|
|
|
|
|
|
|
mat[2] = nx * lz;
|
|
|
|
mat[6] = ny * lz;
|
|
|
|
mat[10] = lz * nz + c;
|
|
|
|
mat[14] = -lz * c - lz * d;
|
|
|
|
|
|
|
|
mat[3] = nx;
|
|
|
|
mat[7] = ny;
|
|
|
|
mat[11] = nz;
|
|
|
|
mat[15] = -d;
|
|
|
|
|
|
|
|
tglMultMatrixf(mat);
|
|
|
|
}
|
|
|
|
|
2014-07-22 19:13:29 -04:00
|
|
|
void GfxTinyGL::getScreenBoundingBox(const Mesh *model, int *x1, int *y1, int *x2, int *y2) {
|
2009-05-05 11:34:43 +00:00
|
|
|
if (_currentShadowArray) {
|
|
|
|
*x1 = -1;
|
|
|
|
*y1 = -1;
|
|
|
|
*x2 = -1;
|
|
|
|
*y2 = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TGLfloat top = 1000;
|
|
|
|
TGLfloat right = -1000;
|
|
|
|
TGLfloat left = 1000;
|
|
|
|
TGLfloat bottom = -1000;
|
|
|
|
|
|
|
|
for (int i = 0; i < model->_numFaces; i++) {
|
2014-07-10 07:29:01 +02:00
|
|
|
Math::Vector3d obj;
|
2013-07-09 21:12:55 +02:00
|
|
|
float *pVertices;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-03-30 14:38:52 -07:00
|
|
|
for (int j = 0; j < model->_faces[i].getNumVertices(); j++) {
|
2009-05-05 11:34:43 +00:00
|
|
|
TGLfloat modelView[16], projection[16];
|
|
|
|
TGLint viewPort[4];
|
|
|
|
|
|
|
|
tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView);
|
|
|
|
tglGetFloatv(TGL_PROJECTION_MATRIX, projection);
|
|
|
|
tglGetIntegerv(TGL_VIEWPORT, viewPort);
|
|
|
|
|
2014-03-30 14:38:52 -07:00
|
|
|
pVertices = model->_vertices + 3 * model->_faces[i].getVertex(j);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-10 07:29:01 +02:00
|
|
|
obj.set(*(pVertices), *(pVertices + 1), *(pVertices + 2));
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-10 07:29:01 +02:00
|
|
|
Math::Vector3d win;
|
2014-08-15 12:25:48 +02:00
|
|
|
Math::gluMathProject<TGLfloat, TGLint>(obj, modelView, projection, viewPort, win);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-10 07:29:01 +02:00
|
|
|
if (win.x() > right)
|
|
|
|
right = win.x();
|
|
|
|
if (win.x() < left)
|
|
|
|
left = win.x();
|
|
|
|
if (win.y() < top)
|
|
|
|
top = win.y();
|
|
|
|
if (win.y() > bottom)
|
|
|
|
bottom = win.y();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float t = bottom;
|
2012-01-25 23:02:24 +01:00
|
|
|
bottom = _gameHeight - top;
|
|
|
|
top = _gameHeight - t;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
if (left < 0)
|
|
|
|
left = 0;
|
2012-01-25 23:02:24 +01:00
|
|
|
if (right >= _gameWidth)
|
|
|
|
right = _gameWidth - 1;
|
2009-05-05 11:34:43 +00:00
|
|
|
if (top < 0)
|
|
|
|
top = 0;
|
2012-01-25 23:02:24 +01:00
|
|
|
if (bottom >= _gameHeight)
|
|
|
|
bottom = _gameHeight - 1;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2012-01-25 23:02:24 +01:00
|
|
|
if (top >= _gameHeight || left >= _gameWidth || bottom < 0 || right < 0) {
|
2009-05-05 11:34:43 +00:00
|
|
|
*x1 = -1;
|
|
|
|
*y1 = -1;
|
|
|
|
*x2 = -1;
|
|
|
|
*y2 = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*x1 = (int)left;
|
|
|
|
*y1 = (int)top;
|
|
|
|
*x2 = (int)right;
|
|
|
|
*y2 = (int)bottom;
|
|
|
|
}
|
|
|
|
|
2014-07-22 19:13:29 -04:00
|
|
|
void GfxTinyGL::getScreenBoundingBox(const EMIModel *model, int *x1, int *y1, int *x2, int *y2) {
|
2013-12-10 15:52:33 +01:00
|
|
|
if (_currentShadowArray) {
|
|
|
|
*x1 = -1;
|
|
|
|
*y1 = -1;
|
|
|
|
*x2 = -1;
|
|
|
|
*y2 = -1;
|
|
|
|
return;
|
|
|
|
}
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
TGLfloat top = 1000;
|
|
|
|
TGLfloat right = -1000;
|
|
|
|
TGLfloat left = 1000;
|
|
|
|
TGLfloat bottom = -1000;
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
TGLfloat modelView[16], projection[16];
|
|
|
|
TGLint viewPort[4];
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView);
|
|
|
|
tglGetFloatv(TGL_PROJECTION_MATRIX, projection);
|
|
|
|
tglGetIntegerv(TGL_VIEWPORT, viewPort);
|
|
|
|
|
2013-12-31 15:30:15 +01:00
|
|
|
for (uint i = 0; i < model->_numFaces; i++) {
|
2013-12-10 15:52:33 +01:00
|
|
|
int *indices = (int *)model->_faces[i]._indexes;
|
|
|
|
|
|
|
|
for (uint j = 0; j < model->_faces[i]._faceLength * 3; j++) {
|
|
|
|
int index = indices[j];
|
2014-07-10 07:29:01 +02:00
|
|
|
|
|
|
|
Math::Vector3d obj = model->_drawVertices[index];
|
|
|
|
Math::Vector3d win;
|
2014-08-15 12:25:48 +02:00
|
|
|
Math::gluMathProject<TGLfloat, TGLint>(obj, modelView, projection, viewPort, win);
|
2014-07-10 07:29:01 +02:00
|
|
|
|
|
|
|
if (win.x() > right)
|
|
|
|
right = win.x();
|
|
|
|
if (win.x() < left)
|
|
|
|
left = win.x();
|
|
|
|
if (win.y() < top)
|
|
|
|
top = win.y();
|
|
|
|
if (win.y() > bottom)
|
|
|
|
bottom = win.y();
|
2013-12-10 15:52:33 +01:00
|
|
|
}
|
|
|
|
}
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
float t = bottom;
|
|
|
|
bottom = _gameHeight - top;
|
|
|
|
top = _gameHeight - t;
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
if (left < 0)
|
|
|
|
left = 0;
|
|
|
|
if (right >= _gameWidth)
|
|
|
|
right = _gameWidth - 1;
|
|
|
|
if (top < 0)
|
|
|
|
top = 0;
|
|
|
|
if (bottom >= _gameHeight)
|
|
|
|
bottom = _gameHeight - 1;
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
if (top >= _gameHeight || left >= _gameWidth || bottom < 0 || right < 0) {
|
|
|
|
*x1 = -1;
|
|
|
|
*y1 = -1;
|
|
|
|
*x2 = -1;
|
|
|
|
*y2 = -1;
|
|
|
|
return;
|
|
|
|
}
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
*x1 = (int)left;
|
|
|
|
*y1 = (int)(_gameHeight - bottom);
|
|
|
|
*x2 = (int)right;
|
|
|
|
*y2 = (int)(_gameHeight - top);
|
|
|
|
}
|
|
|
|
|
2014-08-03 13:16:01 -04:00
|
|
|
void GfxTinyGL::getActorScreenBBox(const Actor *actor, Common::Point &p1, Common::Point &p2) {
|
|
|
|
// Get the actor's bounding box information (describes a 3D box)
|
|
|
|
Math::Vector3d bboxPos, bboxSize;
|
|
|
|
actor->getBBoxInfo(bboxPos, bboxSize);
|
|
|
|
|
|
|
|
// Translate the bounding box to the actor's position
|
|
|
|
Math::Matrix4 m = actor->getFinalMatrix();
|
|
|
|
bboxPos = bboxPos + actor->getWorldPos();
|
|
|
|
|
|
|
|
// Set up the coordinate system
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglPushMatrix();
|
|
|
|
|
|
|
|
// Apply the view transform.
|
2014-08-05 15:43:39 -04:00
|
|
|
Math::Matrix4 worldRot = _currentRot;
|
2014-08-03 13:16:01 -04:00
|
|
|
tglMultMatrixf(worldRot.getData());
|
|
|
|
tglTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
|
|
|
|
|
|
|
|
// Get the current OpenGL state
|
|
|
|
TGLfloat modelView[16], projection[16];
|
|
|
|
TGLint viewPort[4];
|
|
|
|
tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView);
|
|
|
|
tglGetFloatv(TGL_PROJECTION_MATRIX, projection);
|
|
|
|
tglGetIntegerv(TGL_VIEWPORT, viewPort);
|
|
|
|
|
|
|
|
// Set values outside of the screen range
|
|
|
|
p1.x = 1000;
|
|
|
|
p1.y = 1000;
|
|
|
|
p2.x = -1000;
|
|
|
|
p2.y = -1000;
|
|
|
|
|
|
|
|
// Project all of the points in the 3D bounding box
|
|
|
|
Math::Vector3d p, projected;
|
|
|
|
for (int x = 0; x < 2; x++) {
|
|
|
|
for (int y = 0; y < 2; y++) {
|
|
|
|
for (int z = 0; z < 2; z++) {
|
|
|
|
Math::Vector3d added(bboxSize.x() * 0.5f * (x * 2 - 1), bboxSize.y() * 0.5f * (y * 2 - 1), bboxSize.z() * 0.5f * (z * 2 - 1));
|
|
|
|
m.transform(&added, false);
|
|
|
|
p = bboxPos + added;
|
2014-08-15 12:25:48 +02:00
|
|
|
Math::gluMathProject<TGLfloat, TGLint>(p, modelView, projection, viewPort, projected);
|
2014-08-03 13:16:01 -04:00
|
|
|
|
|
|
|
// Find the points
|
|
|
|
if (projected.x() < p1.x)
|
|
|
|
p1.x = projected.x();
|
|
|
|
if (projected.y() < p1.y)
|
|
|
|
p1.y = projected.y();
|
|
|
|
if (projected.x() > p2.x)
|
|
|
|
p2.x = projected.x();
|
|
|
|
if (projected.y() > p2.y)
|
|
|
|
p2.y = projected.y();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Swap the p1/p2 y coorindates
|
|
|
|
int16 tmp = p1.y;
|
|
|
|
p1.y = 480 - p2.y;
|
|
|
|
p2.y = 480 - tmp;
|
|
|
|
|
|
|
|
// Restore the state
|
|
|
|
tglPopMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-04 14:26:44 +01:00
|
|
|
void GfxTinyGL::startActorDraw(const Actor *actor) {
|
|
|
|
_currentActor = actor;
|
2009-05-05 11:34:43 +00:00
|
|
|
tglEnable(TGL_TEXTURE_2D);
|
2012-04-13 20:39:26 +02:00
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglPushMatrix();
|
2009-05-05 11:34:43 +00:00
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglPushMatrix();
|
2014-07-20 20:58:22 +03:00
|
|
|
|
|
|
|
if (g_grim->getGameType() == GType_MONKEY4 && !actor->isInOverworld()) {
|
|
|
|
// Apply the view transform.
|
2014-08-05 15:43:39 -04:00
|
|
|
tglMultMatrixf(_currentRot.getData());
|
2014-07-20 20:58:22 +03:00
|
|
|
tglTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
|
|
|
|
}
|
|
|
|
|
2009-06-18 21:07:51 +00:00
|
|
|
if (_currentShadowArray) {
|
2014-07-20 20:58:22 +03:00
|
|
|
tglDepthMask(TGL_FALSE);
|
2009-06-18 20:23:46 +00:00
|
|
|
// TODO find out why shadowMask at device in woods is null
|
2009-06-18 21:07:51 +00:00
|
|
|
if (!_currentShadowArray->shadowMask) {
|
2012-01-28 09:06:22 +01:00
|
|
|
_currentShadowArray->shadowMask = new byte[_gameWidth * _gameHeight];
|
|
|
|
_currentShadowArray->shadowMaskSize = _gameWidth * _gameHeight;
|
2009-06-18 21:07:51 +00:00
|
|
|
}
|
2009-06-18 21:35:29 +00:00
|
|
|
assert(_currentShadowArray->shadowMask);
|
|
|
|
//tglSetShadowColor(255, 255, 255);
|
2014-07-20 20:58:22 +03:00
|
|
|
if (g_grim->getGameType() == GType_GRIM) {
|
|
|
|
tglSetShadowColor(_shadowColorR, _shadowColorG, _shadowColorB);
|
|
|
|
} else {
|
|
|
|
tglSetShadowColor(_currentShadowArray->color.getRed(), _currentShadowArray->color.getGreen(), _currentShadowArray->color.getBlue());
|
|
|
|
}
|
2009-06-18 21:35:29 +00:00
|
|
|
tglSetShadowMaskBuf(_currentShadowArray->shadowMask);
|
|
|
|
SectorListType::iterator i = _currentShadowArray->planeList.begin();
|
2011-06-07 22:58:42 +02:00
|
|
|
Sector *shadowSector = i->sector;
|
2009-06-18 21:35:29 +00:00
|
|
|
tglShadowProjection(_currentShadowArray->pos, shadowSector->getVertices()[0], shadowSector->getNormal(), _currentShadowArray->dontNegate);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2014-06-20 14:13:52 +02:00
|
|
|
const float alpha = actor->getEffectiveAlpha();
|
2012-04-13 19:45:33 +02:00
|
|
|
if (alpha < 1.f) {
|
|
|
|
_alpha = alpha;
|
2014-06-20 14:13:52 +02:00
|
|
|
tglEnable(TGL_BLEND);
|
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
|
2012-04-13 19:45:33 +02:00
|
|
|
}
|
|
|
|
|
2014-01-19 03:36:59 +01:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
2014-06-10 22:45:01 +03:00
|
|
|
tglEnable(TGL_CULL_FACE);
|
|
|
|
tglFrontFace(TGL_CW);
|
|
|
|
|
2014-01-19 03:36:59 +01:00
|
|
|
if (actor->isInOverworld()) {
|
|
|
|
const Math::Vector3d &pos = actor->getWorldPos();
|
2014-07-03 21:55:10 +02:00
|
|
|
const Math::Quaternion &quat = actor->getRotationQuat();
|
|
|
|
// At distance 3.2, a 6.4x4.8 actor fills the screen.
|
2014-01-19 03:36:59 +01:00
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglLoadIdentity();
|
|
|
|
float right = 1;
|
|
|
|
float top = right * 0.75;
|
2014-06-17 21:01:16 +02:00
|
|
|
float div = 6.0f;
|
2014-07-13 20:33:02 +02:00
|
|
|
tglFrustum(-right / div, right / div, -top / div, top / div, 1.0f / div, 3276.8f);
|
2014-01-19 03:36:59 +01:00
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglLoadIdentity();
|
|
|
|
tglScalef(1.0, 1.0, -1.0);
|
|
|
|
tglTranslatef(pos.x(), pos.y(), pos.z());
|
|
|
|
tglMultMatrixf(quat.toMatrix().getData());
|
|
|
|
} else {
|
|
|
|
Math::Matrix4 m = actor->getFinalMatrix();
|
|
|
|
m.transpose();
|
2014-07-03 21:55:10 +02:00
|
|
|
tglMultMatrixf(m.getData());
|
2014-01-19 03:36:59 +01:00
|
|
|
}
|
2012-07-03 20:03:17 +02:00
|
|
|
} else {
|
2014-01-19 03:36:59 +01:00
|
|
|
// Grim
|
|
|
|
Math::Vector3d pos = actor->getWorldPos();
|
2014-07-03 21:55:10 +02:00
|
|
|
const Math::Quaternion &quat = actor->getRotationQuat();
|
|
|
|
const float &scale = actor->getScale();
|
|
|
|
|
2014-01-19 03:36:59 +01:00
|
|
|
tglTranslatef(pos.x(), pos.y(), pos.z());
|
2012-07-03 00:09:24 +02:00
|
|
|
tglScalef(scale, scale, scale);
|
2012-07-07 20:33:33 +02:00
|
|
|
tglMultMatrixf(quat.toMatrix().getData());
|
2012-01-29 22:04:45 +01:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::finishActorDraw() {
|
2009-05-05 11:34:43 +00:00
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglPopMatrix();
|
2012-04-13 20:39:26 +02:00
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglPopMatrix();
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-03 21:55:10 +02:00
|
|
|
tglDisable(TGL_TEXTURE_2D);
|
2012-04-13 19:45:33 +02:00
|
|
|
if (_alpha < 1.f) {
|
2014-06-20 14:13:52 +02:00
|
|
|
tglDisable(TGL_BLEND);
|
2012-04-13 19:45:33 +02:00
|
|
|
_alpha = 1.f;
|
|
|
|
}
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
if (_currentShadowArray) {
|
2014-05-29 15:35:46 -07:00
|
|
|
tglSetShadowMaskBuf(nullptr);
|
2014-07-03 20:48:54 +02:00
|
|
|
}
|
2013-07-02 00:13:00 +02:00
|
|
|
|
2014-06-10 22:45:01 +03:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
|
|
|
tglDisable(TGL_CULL_FACE);
|
|
|
|
}
|
|
|
|
|
2013-07-02 00:13:00 +02:00
|
|
|
tglColorMask(TGL_TRUE, TGL_TRUE, TGL_TRUE, TGL_TRUE);
|
2014-05-29 15:35:46 -07:00
|
|
|
_currentActor = nullptr;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::drawShadowPlanes() {
|
2009-05-05 11:34:43 +00:00
|
|
|
tglEnable(TGL_SHADOW_MASK_MODE);
|
2014-07-20 20:58:22 +03:00
|
|
|
tglDepthMask(TGL_FALSE);
|
|
|
|
tglPushMatrix();
|
|
|
|
|
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
|
|
|
// Apply the view transform.
|
2014-08-05 15:43:39 -04:00
|
|
|
tglMultMatrixf(_currentRot.getData());
|
2014-07-20 20:58:22 +03:00
|
|
|
tglTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
|
|
|
|
}
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
if (!_currentShadowArray->shadowMask) {
|
2012-01-28 09:06:22 +01:00
|
|
|
_currentShadowArray->shadowMask = new byte[_gameWidth * _gameHeight];
|
|
|
|
_currentShadowArray->shadowMaskSize = _gameWidth * _gameHeight;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2012-01-28 09:06:22 +01:00
|
|
|
memset(_currentShadowArray->shadowMask, 0, _gameWidth * _gameHeight);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
tglSetShadowMaskBuf(_currentShadowArray->shadowMask);
|
|
|
|
_currentShadowArray->planeList.begin();
|
2010-02-04 19:43:50 +00:00
|
|
|
for (SectorListType::iterator i = _currentShadowArray->planeList.begin(); i != _currentShadowArray->planeList.end(); ++i) {
|
2011-06-07 22:58:42 +02:00
|
|
|
Sector *shadowSector = i->sector;
|
2009-05-05 11:34:43 +00:00
|
|
|
tglBegin(TGL_POLYGON);
|
|
|
|
for (int k = 0; k < shadowSector->getNumVertices(); k++) {
|
|
|
|
tglVertex3f(shadowSector->getVertices()[k].x(), shadowSector->getVertices()[k].y(), shadowSector->getVertices()[k].z());
|
|
|
|
}
|
|
|
|
tglEnd();
|
|
|
|
}
|
2014-05-29 15:35:46 -07:00
|
|
|
tglSetShadowMaskBuf(nullptr);
|
2009-05-05 11:34:43 +00:00
|
|
|
tglDisable(TGL_SHADOW_MASK_MODE);
|
2014-12-28 16:50:53 +01:00
|
|
|
tglDepthMask(TGL_TRUE);
|
2014-07-20 20:58:22 +03:00
|
|
|
|
|
|
|
tglPopMatrix();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::setShadowMode() {
|
2011-12-12 18:57:17 +01:00
|
|
|
GfxBase::setShadowMode();
|
2009-05-05 11:34:43 +00:00
|
|
|
tglEnable(TGL_SHADOW_MODE);
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::clearShadowMode() {
|
2011-12-12 18:57:17 +01:00
|
|
|
GfxBase::clearShadowMode();
|
2009-05-05 11:34:43 +00:00
|
|
|
tglDisable(TGL_SHADOW_MODE);
|
2014-07-20 20:58:22 +03:00
|
|
|
tglDepthMask(TGL_TRUE);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::set3DMode() {
|
2009-05-05 11:34:43 +00:00
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
2014-07-04 23:14:44 +02:00
|
|
|
tglDepthFunc(_depthFunc);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::setShadow(Shadow *shadow) {
|
2009-05-05 11:34:43 +00:00
|
|
|
_currentShadowArray = shadow;
|
|
|
|
if (shadow)
|
|
|
|
tglDisable(TGL_LIGHTING);
|
2014-07-20 20:58:22 +03:00
|
|
|
else if (g_grim->getGameType() == GType_GRIM)
|
2009-05-05 11:34:43 +00:00
|
|
|
tglEnable(TGL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::setShadowColor(byte r, byte g, byte b) {
|
2009-05-05 11:34:43 +00:00
|
|
|
_shadowColorR = r;
|
|
|
|
_shadowColorG = g;
|
|
|
|
_shadowColorB = b;
|
|
|
|
}
|
|
|
|
|
2011-04-24 15:41:40 +02:00
|
|
|
void GfxTinyGL::getShadowColor(byte *r, byte *g, byte *b) {
|
|
|
|
*r = _shadowColorR;
|
|
|
|
*g = _shadowColorG;
|
|
|
|
*b = _shadowColorB;
|
|
|
|
}
|
|
|
|
|
2013-07-09 21:12:55 +02:00
|
|
|
void GfxTinyGL::drawEMIModelFace(const EMIModel *model, const EMIMeshFace *face) {
|
|
|
|
int *indices = (int *)face->_indexes;
|
2014-07-03 21:55:10 +02:00
|
|
|
|
2012-01-10 09:10:59 +01:00
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
2011-12-30 12:53:49 +01:00
|
|
|
tglDisable(TGL_ALPHA_TEST);
|
2014-07-03 21:55:10 +02:00
|
|
|
//tglDisable(TGL_LIGHTING); // not apply here in TinyGL
|
2014-07-20 20:58:22 +03:00
|
|
|
if (!_currentShadowArray && face->_hasTexture)
|
2012-01-10 09:10:59 +01:00
|
|
|
tglEnable(TGL_TEXTURE_2D);
|
|
|
|
else
|
|
|
|
tglDisable(TGL_TEXTURE_2D);
|
2014-09-17 01:30:40 +02:00
|
|
|
if (face->_flags & EMIMeshFace::kAlphaBlend || face->_flags & EMIMeshFace::kUnknownBlend || _currentActor->hasLocalAlpha() || _alpha < 1.0f )
|
2014-08-05 18:54:34 +03:00
|
|
|
tglEnable(TGL_BLEND);
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2014-07-03 21:55:10 +02:00
|
|
|
tglBegin(TGL_TRIANGLES);
|
2015-02-12 22:33:07 +01:00
|
|
|
float alpha = _alpha;
|
|
|
|
if (model->_meshAlphaMode == Actor::AlphaReplace) {
|
|
|
|
alpha *= model->_meshAlpha;
|
|
|
|
}
|
2015-02-24 22:44:10 +01:00
|
|
|
Math::Vector3d noLighting(1.f, 1.f, 1.f);
|
2012-01-27 19:58:17 +01:00
|
|
|
for (uint j = 0; j < face->_faceLength * 3; j++) {
|
2011-12-30 12:53:49 +01:00
|
|
|
int index = indices[j];
|
2014-07-20 20:58:22 +03:00
|
|
|
if (!_currentShadowArray) {
|
|
|
|
if (face->_hasTexture) {
|
|
|
|
tglTexCoord2f(model->_texVerts[index].getX(), model->_texVerts[index].getY());
|
|
|
|
}
|
2014-06-09 18:39:29 +03:00
|
|
|
|
2015-02-24 22:44:10 +01:00
|
|
|
Math::Vector3d lighting = (face->_flags & EMIMeshFace::kNoLighting) ? noLighting : model->_lighting[index];
|
2014-07-08 21:04:25 +02:00
|
|
|
byte r = (byte)(model->_colorMap[index].r * lighting.x());
|
|
|
|
byte g = (byte)(model->_colorMap[index].g * lighting.y());
|
|
|
|
byte b = (byte)(model->_colorMap[index].b * lighting.z());
|
2015-02-12 22:33:07 +01:00
|
|
|
byte a = (int)(model->_colorMap[index].a * alpha * _currentActor->getLocalAlpha(index));
|
2014-07-20 20:58:22 +03:00
|
|
|
tglColor4ub(r, g, b, a);
|
|
|
|
}
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2011-12-30 12:53:49 +01:00
|
|
|
Math::Vector3d normal = model->_normals[index];
|
2012-01-31 00:14:26 +01:00
|
|
|
Math::Vector3d vertex = model->_drawVertices[index];
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2012-01-10 09:10:59 +01:00
|
|
|
tglNormal3fv(normal.getData());
|
|
|
|
tglVertex3fv(vertex.getData());
|
2011-12-30 12:53:49 +01:00
|
|
|
}
|
|
|
|
tglEnd();
|
2014-07-03 21:55:10 +02:00
|
|
|
|
2014-08-19 17:10:10 -07:00
|
|
|
if (!_currentShadowArray) {
|
|
|
|
tglColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
}
|
|
|
|
|
2012-01-16 17:12:14 +01:00
|
|
|
tglEnable(TGL_TEXTURE_2D);
|
2011-12-30 12:53:49 +01:00
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
2012-01-16 17:12:14 +01:00
|
|
|
tglEnable(TGL_ALPHA_TEST);
|
2014-07-05 20:54:14 +02:00
|
|
|
//tglEnable(TGL_LIGHTING); // not apply here in TinyGL
|
2014-06-20 14:13:52 +02:00
|
|
|
tglDisable(TGL_BLEND);
|
2014-07-20 20:58:22 +03:00
|
|
|
|
|
|
|
if (!_currentShadowArray)
|
|
|
|
tglDepthMask(TGL_TRUE);
|
2011-12-30 12:53:49 +01:00
|
|
|
}
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2012-12-27 19:08:46 +01:00
|
|
|
void GfxTinyGL::drawModelFace(const Mesh *mesh, const MeshFace *face) {
|
|
|
|
float *vertices = mesh->_vertices;
|
|
|
|
float *vertNormals = mesh->_vertNormals;
|
|
|
|
float *textureVerts = mesh->_textureVerts;
|
2014-03-30 14:38:52 -07:00
|
|
|
tglNormal3fv(const_cast<float *>(face->getNormal().getData()));
|
2009-05-05 11:34:43 +00:00
|
|
|
tglBegin(TGL_POLYGON);
|
2014-03-30 14:38:52 -07:00
|
|
|
for (int i = 0; i < face->getNumVertices(); i++) {
|
|
|
|
tglNormal3fv(vertNormals + 3 * face->getVertex(i));
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-03-30 14:38:52 -07:00
|
|
|
if (face->hasTexture())
|
|
|
|
tglTexCoord2fv(textureVerts + 2 * face->getTextureVertex(i));
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-06-20 14:13:52 +02:00
|
|
|
tglColor4f(1.0f, 1.0f, 1.0f, _alpha);
|
2014-03-30 14:38:52 -07:00
|
|
|
tglVertex3fv(vertices + 3 * face->getVertex(i));
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
tglEnd();
|
|
|
|
}
|
|
|
|
|
2011-05-15 16:47:09 +03:00
|
|
|
void GfxTinyGL::drawSprite(const Sprite *sprite) {
|
|
|
|
tglMatrixMode(TGL_TEXTURE);
|
|
|
|
tglLoadIdentity();
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglPushMatrix();
|
2013-08-07 20:05:43 +02:00
|
|
|
|
2013-11-26 21:06:34 +01:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
2014-07-03 21:55:10 +02:00
|
|
|
TGLfloat modelview[16];
|
|
|
|
tglGetFloatv(TGL_MODELVIEW_MATRIX, modelview);
|
2014-06-21 08:43:55 -04:00
|
|
|
Math::Matrix4 act;
|
2014-07-03 21:55:10 +02:00
|
|
|
act.buildAroundZ(_currentActor->getYaw());
|
2013-11-26 21:06:34 +01:00
|
|
|
act.transpose();
|
2014-07-03 21:55:10 +02:00
|
|
|
act(3, 0) = modelview[12];
|
|
|
|
act(3, 1) = modelview[13];
|
|
|
|
act(3, 2) = modelview[14];
|
2013-11-26 21:06:34 +01:00
|
|
|
tglLoadMatrixf(act.getData());
|
2014-08-05 23:06:55 +03:00
|
|
|
tglTranslatef(sprite->_pos.x(), sprite->_pos.y(), -sprite->_pos.z());
|
2013-11-26 21:06:34 +01:00
|
|
|
} else {
|
2014-07-03 21:55:10 +02:00
|
|
|
tglTranslatef(sprite->_pos.x(), sprite->_pos.y(), sprite->_pos.z());
|
|
|
|
TGLfloat modelview[16];
|
|
|
|
tglGetFloatv(TGL_MODELVIEW_MATRIX, modelview);
|
|
|
|
|
2013-08-07 20:05:43 +02:00
|
|
|
// We want screen-aligned sprites so reset the rotation part of the matrix.
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
for (int j = 0; j < 3; j++) {
|
|
|
|
if (i == j) {
|
|
|
|
modelview[i * 4 + j] = 1.0f;
|
|
|
|
} else {
|
|
|
|
modelview[i * 4 + j] = 0.0f;
|
|
|
|
}
|
2011-05-15 16:47:09 +03:00
|
|
|
}
|
|
|
|
}
|
2013-11-26 21:06:34 +01:00
|
|
|
tglLoadMatrixf(modelview);
|
2013-08-07 20:05:43 +02:00
|
|
|
}
|
2011-05-15 16:47:09 +03:00
|
|
|
|
2014-08-05 23:19:18 +03:00
|
|
|
if (sprite->_flags1 & Sprite::BlendAdditive) {
|
2014-06-20 14:13:52 +02:00
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE);
|
2014-06-23 00:44:15 +03:00
|
|
|
} else {
|
2014-06-20 14:13:52 +02:00
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
|
2014-06-23 00:44:15 +03:00
|
|
|
}
|
|
|
|
|
2011-05-15 16:47:09 +03:00
|
|
|
tglDisable(TGL_LIGHTING);
|
|
|
|
|
2014-08-18 13:08:35 +03:00
|
|
|
if (g_grim->getGameType() == GType_GRIM) {
|
2014-12-28 17:10:56 +01:00
|
|
|
// Disable Alpha Test, doesn't work the same as OpenGL
|
|
|
|
// It was enabled to sync with OpenGL renderer while TinyGL refactoring
|
|
|
|
//tglEnable(TGL_ALPHA_TEST);
|
2014-08-18 13:08:35 +03:00
|
|
|
tglAlphaFunc(TGL_GEQUAL, 0.5f);
|
|
|
|
} else if (sprite->_flags2 & Sprite::AlphaTest) {
|
|
|
|
tglEnable(TGL_ALPHA_TEST);
|
|
|
|
tglAlphaFunc(TGL_GEQUAL, 0.1f);
|
2014-06-23 00:44:15 +03:00
|
|
|
} else {
|
2014-07-04 08:43:19 +02:00
|
|
|
tglDisable(TGL_ALPHA_TEST);
|
2014-06-23 00:44:15 +03:00
|
|
|
}
|
|
|
|
|
2014-08-05 23:19:18 +03:00
|
|
|
if (sprite->_flags2 & Sprite::DepthTest) {
|
2014-06-23 00:44:15 +03:00
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
|
|
|
} else {
|
|
|
|
tglDisable(TGL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
|
2013-01-02 02:20:51 +02:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
2014-08-05 23:09:16 +03:00
|
|
|
tglDepthMask(TGL_TRUE);
|
2014-07-03 21:55:10 +02:00
|
|
|
|
2014-01-05 16:44:51 +01:00
|
|
|
float halfWidth = sprite->_width / 2;
|
|
|
|
float halfHeight = sprite->_height / 2;
|
2014-07-08 21:04:25 +02:00
|
|
|
|
2014-08-03 20:25:31 +03:00
|
|
|
float vertexX[] = { -1.0f, 1.0f, 1.0f, -1.0f };
|
|
|
|
float vertexY[] = { 1.0f, 1.0f, -1.0f, -1.0f };
|
2012-11-13 22:26:31 +01:00
|
|
|
|
2013-01-02 00:50:26 +02:00
|
|
|
tglBegin(TGL_POLYGON);
|
2014-06-23 00:44:15 +03:00
|
|
|
for (int i = 0; i < 4; ++i) {
|
2014-07-08 21:04:25 +02:00
|
|
|
float r = sprite->_red[i] / 255.0f;
|
|
|
|
float g = sprite->_green[i] / 255.0f;
|
|
|
|
float b = sprite->_blue[i] / 255.0f;
|
|
|
|
float a = sprite->_alpha[i] * _alpha / 255.0f;
|
2014-06-23 00:44:15 +03:00
|
|
|
|
|
|
|
tglColor4f(r, g, b, a);
|
2014-08-03 20:25:31 +03:00
|
|
|
tglTexCoord2f(sprite->_texCoordX[i], sprite->_texCoordY[i]);
|
2014-06-23 00:44:15 +03:00
|
|
|
tglVertex3f(vertexX[i] * halfWidth, vertexY[i] * halfHeight, 0.0f);
|
|
|
|
}
|
2013-01-02 00:50:26 +02:00
|
|
|
tglEnd();
|
2014-08-03 20:25:31 +03:00
|
|
|
tglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
2013-01-02 02:20:51 +02:00
|
|
|
} else {
|
2013-01-02 00:50:26 +02:00
|
|
|
// In Grim, the bottom edge of the sprite is at y=0 and
|
|
|
|
// the texture is flipped along the X-axis.
|
2014-01-05 16:44:51 +01:00
|
|
|
float halfWidth = sprite->_width / 2;
|
|
|
|
float height = sprite->_height;
|
2012-11-13 22:26:31 +01:00
|
|
|
|
2013-01-02 00:50:26 +02:00
|
|
|
tglBegin(TGL_POLYGON);
|
|
|
|
tglTexCoord2f(0.0f, 1.0f);
|
|
|
|
tglVertex3f(+halfWidth, 0.0f, 0.0f);
|
|
|
|
tglTexCoord2f(0.0f, 0.0f);
|
|
|
|
tglVertex3f(+halfWidth, +height, 0.0f);
|
|
|
|
tglTexCoord2f(1.0f, 0.0f);
|
|
|
|
tglVertex3f(-halfWidth, +height, 0.0f);
|
|
|
|
tglTexCoord2f(1.0f, 1.0f);
|
|
|
|
tglVertex3f(-halfWidth, 0.0f, 0.0f);
|
|
|
|
tglEnd();
|
|
|
|
}
|
2011-05-15 16:47:09 +03:00
|
|
|
|
|
|
|
tglEnable(TGL_LIGHTING);
|
2014-06-23 00:44:15 +03:00
|
|
|
tglDisable(TGL_ALPHA_TEST);
|
2014-07-03 20:57:05 +02:00
|
|
|
tglDepthMask(TGL_TRUE);
|
2014-06-20 14:13:52 +02:00
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
tglDisable(TGL_BLEND);
|
2014-06-23 00:44:15 +03:00
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
2011-05-15 16:47:09 +03:00
|
|
|
|
|
|
|
tglPopMatrix();
|
|
|
|
}
|
|
|
|
|
2011-12-12 18:57:17 +01:00
|
|
|
void GfxTinyGL::translateViewpointStart() {
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
2009-05-05 11:34:43 +00:00
|
|
|
tglPushMatrix();
|
|
|
|
}
|
|
|
|
|
2011-12-12 18:57:17 +01:00
|
|
|
void GfxTinyGL::translateViewpoint(const Math::Vector3d &vec) {
|
|
|
|
tglTranslatef(vec.x(), vec.y(), vec.z());
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2011-12-12 18:57:17 +01:00
|
|
|
void GfxTinyGL::rotateViewpoint(const Math::Angle &angle, const Math::Vector3d &axis) {
|
|
|
|
tglRotatef(angle.getDegrees(), axis.x(), axis.y(), axis.z());
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-06-25 17:15:41 +03:00
|
|
|
void GfxTinyGL::rotateViewpoint(const Math::Matrix4 &rot) {
|
|
|
|
tglMultMatrixf(rot.getData());
|
|
|
|
}
|
|
|
|
|
2011-12-12 18:57:17 +01:00
|
|
|
void GfxTinyGL::translateViewpointFinish() {
|
2014-07-03 21:55:10 +02:00
|
|
|
//glMatrixMode(GL_MODELVIEW); // exist in opengl but doesn't work properly here
|
2011-12-12 18:57:17 +01:00
|
|
|
tglPopMatrix();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2011-07-13 14:09:32 +03:00
|
|
|
void GfxTinyGL::enableLights() {
|
|
|
|
tglEnable(TGL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::disableLights() {
|
2009-05-05 11:34:43 +00:00
|
|
|
tglDisable(TGL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2011-07-23 12:14:33 +02:00
|
|
|
void GfxTinyGL::setupLight(Light *light, int lightId) {
|
2009-05-05 11:34:43 +00:00
|
|
|
assert(lightId < T_MAX_LIGHTS);
|
|
|
|
tglEnable(TGL_LIGHTING);
|
|
|
|
float lightColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
|
|
float lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
2011-05-20 22:25:20 +02:00
|
|
|
float lightDir[] = { 0.0f, 0.0f, -1.0f };
|
2011-05-21 04:28:48 +08:00
|
|
|
float cutoff = 180.0f;
|
2015-03-15 19:55:49 +01:00
|
|
|
float spot_exp = 0.0f;
|
GRIM: Disable quadratic attenuation for spotlights.
Enabling quadratic atenuation, even with values as low as 0.1, reduces spot
lighting too much in (at least) sets "do" (see Domino), "al" (see Manny when
walking along the garage door), "hq" (see Salvador).
Disabling is not perfect either, as attenuation can be seen (at least) in
set "tu" (see fire extinguisher), but it should be overall better.
Also, it should be noted that perfect fidelity cannot be achieved with openGL
fixed pipeline, as DirectX spotlight have two angles (0 <= phi <= theta <= pi),
atenuation being null below phi, full above theta, transitioning with a
configurable exponent between both (defaults to angle-linear). OpenGL would
correspond to phi=0 and theta=pi (ie, transition is always done between fixed
angles), plus a configurable hard cutoff.
2015-03-17 00:17:30 +01:00
|
|
|
float q_attenuation = 1.0f;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2015-03-22 09:00:23 +01:00
|
|
|
float intensity = light->_scaledintensity;
|
2014-06-08 09:51:28 +02:00
|
|
|
lightColor[0] = (float)light->_color.getRed() * intensity;
|
|
|
|
lightColor[1] = (float)light->_color.getGreen() * intensity;
|
|
|
|
lightColor[2] = (float)light->_color.getBlue() * intensity;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2013-07-10 16:17:28 -07:00
|
|
|
if (light->_type == Light::Omni) {
|
2009-05-05 11:34:43 +00:00
|
|
|
lightPos[0] = light->_pos.x();
|
|
|
|
lightPos[1] = light->_pos.y();
|
|
|
|
lightPos[2] = light->_pos.z();
|
2013-07-10 16:17:28 -07:00
|
|
|
} else if (light->_type == Light::Direct) {
|
2011-05-20 22:44:12 +02:00
|
|
|
lightPos[0] = -light->_dir.x();
|
|
|
|
lightPos[1] = -light->_dir.y();
|
|
|
|
lightPos[2] = -light->_dir.z();
|
2011-04-30 15:55:54 +08:00
|
|
|
lightPos[3] = 0;
|
2013-07-10 16:17:28 -07:00
|
|
|
} else if (light->_type == Light::Spot) {
|
2009-05-05 11:34:43 +00:00
|
|
|
lightPos[0] = light->_pos.x();
|
|
|
|
lightPos[1] = light->_pos.y();
|
|
|
|
lightPos[2] = light->_pos.z();
|
|
|
|
lightDir[0] = light->_dir.x();
|
|
|
|
lightDir[1] = light->_dir.y();
|
|
|
|
lightDir[2] = light->_dir.z();
|
2015-03-15 19:55:49 +01:00
|
|
|
spot_exp = 2.0f;
|
|
|
|
cutoff = light->_penumbraangle;
|
GRIM: Disable quadratic attenuation for spotlights.
Enabling quadratic atenuation, even with values as low as 0.1, reduces spot
lighting too much in (at least) sets "do" (see Domino), "al" (see Manny when
walking along the garage door), "hq" (see Salvador).
Disabling is not perfect either, as attenuation can be seen (at least) in
set "tu" (see fire extinguisher), but it should be overall better.
Also, it should be noted that perfect fidelity cannot be achieved with openGL
fixed pipeline, as DirectX spotlight have two angles (0 <= phi <= theta <= pi),
atenuation being null below phi, full above theta, transitioning with a
configurable exponent between both (defaults to angle-linear). OpenGL would
correspond to phi=0 and theta=pi (ie, transition is always done between fixed
angles), plus a configurable hard cutoff.
2015-03-17 00:17:30 +01:00
|
|
|
q_attenuation = 0.0f;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2013-07-10 16:17:28 -07:00
|
|
|
|
2011-05-21 04:28:48 +08:00
|
|
|
tglDisable(TGL_LIGHT0 + lightId);
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_DIFFUSE, lightColor);
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_POSITION, lightPos);
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_SPOT_DIRECTION, lightDir);
|
2015-03-15 19:55:49 +01:00
|
|
|
tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_EXPONENT, spot_exp);
|
2011-05-21 04:28:48 +08:00
|
|
|
tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_CUTOFF, cutoff);
|
GRIM: Disable quadratic attenuation for spotlights.
Enabling quadratic atenuation, even with values as low as 0.1, reduces spot
lighting too much in (at least) sets "do" (see Domino), "al" (see Manny when
walking along the garage door), "hq" (see Salvador).
Disabling is not perfect either, as attenuation can be seen (at least) in
set "tu" (see fire extinguisher), but it should be overall better.
Also, it should be noted that perfect fidelity cannot be achieved with openGL
fixed pipeline, as DirectX spotlight have two angles (0 <= phi <= theta <= pi),
atenuation being null below phi, full above theta, transitioning with a
configurable exponent between both (defaults to angle-linear). OpenGL would
correspond to phi=0 and theta=pi (ie, transition is always done between fixed
angles), plus a configurable hard cutoff.
2015-03-17 00:17:30 +01:00
|
|
|
tglLightf(TGL_LIGHT0 + lightId, TGL_QUADRATIC_ATTENUATION, q_attenuation);
|
2011-05-21 04:28:48 +08:00
|
|
|
tglEnable(TGL_LIGHT0 + lightId);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2011-10-18 18:01:52 +02:00
|
|
|
void GfxTinyGL::turnOffLight(int lightId) {
|
|
|
|
tglDisable(TGL_LIGHT0 + lightId);
|
|
|
|
}
|
|
|
|
|
2011-05-09 19:20:47 +02:00
|
|
|
void GfxTinyGL::createBitmap(BitmapData *bitmap) {
|
2012-01-16 17:12:14 +01:00
|
|
|
if (bitmap->_format == 1) {
|
2012-01-24 18:20:33 +01:00
|
|
|
bitmap->convertToColorFormat(_pixelFormat);
|
2014-07-14 18:15:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Graphics::BlitImage **imgs = new Graphics::BlitImage*[bitmap->_numImages];
|
|
|
|
bitmap->_texIds = (void *)imgs;
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
if (bitmap->_format != 1) {
|
|
|
|
for (int pic = 0; pic < bitmap->_numImages; pic++) {
|
2012-03-07 11:31:04 +01:00
|
|
|
uint32 *buf = new uint32[bitmap->_width * bitmap->_height];
|
2012-01-24 19:02:50 +01:00
|
|
|
uint16 *bufPtr = reinterpret_cast<uint16 *>(bitmap->getImageData(pic).getRawBuffer());
|
2009-05-05 11:34:43 +00:00
|
|
|
for (int i = 0; i < (bitmap->_width * bitmap->_height); i++) {
|
2012-01-27 20:00:00 +01:00
|
|
|
uint16 val = READ_LE_UINT16(bufPtr + i);
|
2012-01-17 16:21:30 -08:00
|
|
|
// fix the value if it is incorrectly set to the bitmap transparency color
|
|
|
|
if (val == 0xf81f) {
|
|
|
|
val = 0;
|
|
|
|
}
|
2014-07-13 20:33:02 +02:00
|
|
|
buf[i] = ((uint32)val) * 0x10000 / 100 / (0x10000 - val) << 14;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2012-02-13 19:20:20 +01:00
|
|
|
delete[] bufPtr;
|
2013-07-09 21:12:55 +02:00
|
|
|
bitmap->_data[pic] = Graphics::PixelBuffer(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), (byte *)buf);
|
2014-07-25 15:50:48 +02:00
|
|
|
imgs[pic] = Graphics::tglGenBlitImage();
|
2014-08-13 21:00:18 +02:00
|
|
|
const Graphics::PixelBuffer &imageBuffer = bitmap->getImageData(pic);
|
2014-07-25 15:50:48 +02:00
|
|
|
Graphics::Surface sourceSurface;
|
|
|
|
sourceSurface.setPixels(imageBuffer.getRawBuffer());
|
|
|
|
sourceSurface.format = imageBuffer.getFormat();
|
|
|
|
sourceSurface.w = bitmap->_width;
|
|
|
|
sourceSurface.h = bitmap->_height;
|
|
|
|
sourceSurface.pitch = sourceSurface.w * imageBuffer.getFormat().bytesPerPixel;
|
|
|
|
Graphics::tglUploadBlitImage(imgs[pic], sourceSurface, 0, false);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2012-01-25 18:04:26 +01:00
|
|
|
} else {
|
2014-08-18 21:58:34 +03:00
|
|
|
const int colorKeyValue = 0xFFFF00FF;
|
2012-01-25 18:04:26 +01:00
|
|
|
for (int i = 0; i < bitmap->_numImages; ++i) {
|
2014-07-14 18:15:51 +02:00
|
|
|
imgs[i] = Graphics::tglGenBlitImage();
|
|
|
|
const Graphics::PixelBuffer &imageBuffer = bitmap->getImageData(i);
|
2014-07-18 19:56:26 +02:00
|
|
|
Graphics::Surface sourceSurface;
|
|
|
|
sourceSurface.setPixels(imageBuffer.getRawBuffer());
|
|
|
|
sourceSurface.format = imageBuffer.getFormat();
|
|
|
|
sourceSurface.w = bitmap->_width;
|
|
|
|
sourceSurface.h = bitmap->_height;
|
|
|
|
sourceSurface.pitch = sourceSurface.w * imageBuffer.getFormat().bytesPerPixel;
|
2014-08-15 22:55:20 +02:00
|
|
|
Graphics::tglUploadBlitImage(imgs[i], sourceSurface, colorKeyValue, true);
|
2012-01-25 18:04:26 +01:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
EMI: Draw background layers at intervals
Previously, we split the background layers into everything
before SO 15 and after, and drew like that. However, this caused
the pink ship in shi.setb to not be drawn.
This patch draws the layers of the background at intervals of ten.
So if a set has six layers, layer 5 is the background and 4,3,2,1,0
are rendered at sortorder 40,30,20,10,0.
2013-06-29 14:36:17 +02:00
|
|
|
void GfxTinyGL::drawBitmap(const Bitmap *bitmap, int x, int y, uint32 layer) {
|
2012-11-26 22:37:02 +01:00
|
|
|
// PS2 EMI uses a TGA for it's splash-screen, avoid using the following
|
|
|
|
// code for drawing that (as it has no tiles).
|
2015-05-05 02:06:21 +02:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4 && bitmap->_data && bitmap->_data->_texc) {
|
2014-07-16 16:46:56 +02:00
|
|
|
tglEnable(TGL_BLEND);
|
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
|
2014-07-08 21:04:25 +02:00
|
|
|
tglColor3f(1.0f, 1.0f, 1.0f);
|
2012-11-26 02:06:15 +01:00
|
|
|
|
|
|
|
BitmapData *data = bitmap->_data;
|
|
|
|
float *texc = data->_texc;
|
|
|
|
|
2014-07-14 18:15:51 +02:00
|
|
|
Graphics::BlitImage **b = (Graphics::BlitImage **)bitmap->getTexIds();
|
2012-11-26 02:06:15 +01:00
|
|
|
|
2015-05-16 10:32:36 +02:00
|
|
|
assert(layer < data->_numLayers);
|
EMI: Draw background layers at intervals
Previously, we split the background layers into everything
before SO 15 and after, and drew like that. However, this caused
the pink ship in shi.setb to not be drawn.
This patch draws the layers of the background at intervals of ten.
So if a set has six layers, layer 5 is the background and 4,3,2,1,0
are rendered at sortorder 40,30,20,10,0.
2013-06-29 14:36:17 +02:00
|
|
|
uint32 offset = data->_layers[layer]._offset;
|
|
|
|
for (uint32 i = offset; i < offset + data->_layers[layer]._numImages; ++i) {
|
2013-07-09 21:12:55 +02:00
|
|
|
const BitmapData::Vert &v = data->_verts[i];
|
EMI: Draw background layers at intervals
Previously, we split the background layers into everything
before SO 15 and after, and drew like that. However, this caused
the pink ship in shi.setb to not be drawn.
This patch draws the layers of the background at intervals of ten.
So if a set has six layers, layer 5 is the background and 4,3,2,1,0
are rendered at sortorder 40,30,20,10,0.
2013-06-29 14:36:17 +02:00
|
|
|
uint32 texId = v._texid;
|
|
|
|
uint32 ntex = data->_verts[i]._pos * 4;
|
|
|
|
uint32 numRects = data->_verts[i]._verts / 4;
|
|
|
|
while (numRects-- > 0) {
|
2014-07-06 07:05:27 +02:00
|
|
|
// TODO: better way to fix this:
|
|
|
|
// adding '+ 1' fixing broken lines at edges of bitmaps
|
|
|
|
// example: EMI ship scene
|
|
|
|
int dx1 = (((texc[ntex + 0] + 1) * _screenWidth) / 2) + 1;
|
|
|
|
int dy1 = (((1 - texc[ntex + 1]) * _screenHeight) / 2) + 1;
|
|
|
|
int dx2 = (((texc[ntex + 8] + 1) * _screenWidth) / 2) + 1;
|
|
|
|
int dy2 = (((1 - texc[ntex + 9]) * _screenHeight) / 2) + 1;
|
2013-07-09 21:12:55 +02:00
|
|
|
int srcX = texc[ntex + 2] * bitmap->getWidth();
|
|
|
|
int srcY = texc[ntex + 3] * bitmap->getHeight();
|
EMI: Draw background layers at intervals
Previously, we split the background layers into everything
before SO 15 and after, and drew like that. However, this caused
the pink ship in shi.setb to not be drawn.
This patch draws the layers of the background at intervals of ten.
So if a set has six layers, layer 5 is the background and 4,3,2,1,0
are rendered at sortorder 40,30,20,10,0.
2013-06-29 14:36:17 +02:00
|
|
|
|
2014-07-14 18:15:51 +02:00
|
|
|
Graphics::BlitTransform transform(x + dx1, y + dy1);
|
|
|
|
transform.sourceRectangle(srcX, srcY, dx2 - dx1, dy2 - dy1);
|
2014-07-16 16:46:56 +02:00
|
|
|
transform.tint(1.0f, 1.0f - _dimLevel, 1.0f - _dimLevel, 1.0f - _dimLevel);
|
2014-07-14 18:15:51 +02:00
|
|
|
Graphics::tglBlit(b[texId], transform);
|
EMI: Draw background layers at intervals
Previously, we split the background layers into everything
before SO 15 and after, and drew like that. However, this caused
the pink ship in shi.setb to not be drawn.
This patch draws the layers of the background at intervals of ten.
So if a set has six layers, layer 5 is the background and 4,3,2,1,0
are rendered at sortorder 40,30,20,10,0.
2013-06-29 14:36:17 +02:00
|
|
|
ntex += 16;
|
2012-11-26 02:06:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-16 16:46:56 +02:00
|
|
|
tglDisable(TGL_BLEND);
|
2012-11-26 02:06:15 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-29 23:02:52 +02:00
|
|
|
int format = bitmap->getFormat();
|
|
|
|
if ((format == 1 && !_renderBitmaps) || (format == 5 && !_renderZBitmaps)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-09-18 18:46:20 +02:00
|
|
|
assert(bitmap->getActiveImage() > 0);
|
2012-01-24 19:02:50 +01:00
|
|
|
const int num = bitmap->getActiveImage() - 1;
|
2012-01-25 18:04:26 +01:00
|
|
|
|
2014-07-14 18:15:51 +02:00
|
|
|
Graphics::BlitImage **b = (Graphics::BlitImage **)bitmap->getTexIds();
|
2012-01-25 18:04:26 +01:00
|
|
|
|
2014-07-14 18:15:51 +02:00
|
|
|
if (bitmap->getFormat() == 1) {
|
2014-07-15 16:35:04 +02:00
|
|
|
Graphics::tglBlit(b[num], x, y);
|
2014-07-14 18:15:51 +02:00
|
|
|
} else {
|
2014-07-25 15:50:48 +02:00
|
|
|
Graphics::tglBlitZBuffer(b[num], x, y);
|
2014-07-14 18:15:51 +02:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2012-01-25 18:04:26 +01:00
|
|
|
void GfxTinyGL::destroyBitmap(BitmapData *bitmap) {
|
2014-07-16 14:18:01 +02:00
|
|
|
Graphics::BlitImage **imgs = (Graphics::BlitImage **)bitmap->_texIds;
|
2012-03-31 15:03:56 -07:00
|
|
|
for (int pic = 0; pic < bitmap->_numImages; pic++) {
|
2014-07-16 14:18:01 +02:00
|
|
|
Graphics::tglDeleteBlitImage(imgs[pic]);
|
2012-03-31 15:03:56 -07:00
|
|
|
}
|
2014-08-07 21:49:47 +02:00
|
|
|
delete[] imgs;
|
2012-01-25 18:04:26 +01:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2011-05-23 15:08:27 -07:00
|
|
|
void GfxTinyGL::createFont(Font *font) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void GfxTinyGL::destroyFont(Font *font) {
|
|
|
|
}
|
|
|
|
|
2011-05-23 22:00:53 -07:00
|
|
|
struct TextObjectData {
|
2014-07-14 18:15:51 +02:00
|
|
|
Graphics::BlitImage *image;
|
2011-05-23 22:00:53 -07:00
|
|
|
int width, height, x, y;
|
|
|
|
};
|
2011-05-23 17:05:07 -07:00
|
|
|
|
2011-05-23 22:00:53 -07:00
|
|
|
void GfxTinyGL::createTextObject(TextObject *text) {
|
2011-05-23 17:05:07 -07:00
|
|
|
int numLines = text->getNumLines();
|
|
|
|
const Common::String *lines = text->getLines();
|
|
|
|
const Font *font = text->getFont();
|
2012-01-27 11:47:28 -08:00
|
|
|
const Color &fgColor = text->getFGColor();
|
2011-06-07 09:20:10 -07:00
|
|
|
TextObjectData *userData = new TextObjectData[numLines];
|
|
|
|
text->setUserData(userData);
|
2011-05-23 17:05:07 -07:00
|
|
|
for (int j = 0; j < numLines; j++) {
|
|
|
|
const Common::String ¤tLine = lines[j];
|
|
|
|
|
2014-08-20 09:36:31 -04:00
|
|
|
int width = font->getBitmapStringLength(currentLine) + 1;
|
2014-08-12 11:20:25 -04:00
|
|
|
int height = font->getStringHeight(currentLine) + 1;
|
2011-05-23 17:05:07 -07:00
|
|
|
|
|
|
|
uint8 *_textBitmap = new uint8[height * width];
|
|
|
|
memset(_textBitmap, 0, height * width);
|
|
|
|
|
2014-08-12 11:20:25 -04:00
|
|
|
int startColumn = 0;
|
2011-05-23 17:05:07 -07:00
|
|
|
for (unsigned int d = 0; d < currentLine.size(); d++) {
|
|
|
|
int ch = currentLine[d];
|
2014-07-30 21:35:38 -04:00
|
|
|
int32 charBitmapWidth = font->getCharBitmapWidth(ch);
|
2014-08-12 11:20:25 -04:00
|
|
|
int8 fontRow = font->getCharStartingLine(ch) + font->getBaseOffsetY();
|
|
|
|
int8 fontCol = font->getCharStartingCol(ch);
|
|
|
|
|
2014-07-30 21:35:38 -04:00
|
|
|
for (int line = 0; line < font->getCharBitmapHeight(ch); line++) {
|
2014-08-12 11:20:25 -04:00
|
|
|
int lineOffset = ((fontRow + line) * width);
|
|
|
|
for (int bitmapCol = 0; bitmapCol < charBitmapWidth; bitmapCol++) {
|
|
|
|
int columnOffset = startColumn + fontCol + bitmapCol;
|
|
|
|
int fontOffset = (charBitmapWidth * line) + bitmapCol;
|
|
|
|
int8 pixel = font->getCharData(ch)[fontOffset];
|
|
|
|
assert(lineOffset + columnOffset < width*height);
|
|
|
|
if (pixel != 0)
|
|
|
|
_textBitmap[lineOffset + columnOffset] = pixel;
|
2011-05-23 17:05:07 -07:00
|
|
|
}
|
|
|
|
}
|
2014-08-12 11:20:25 -04:00
|
|
|
startColumn += font->getCharKernedWidth(ch);
|
2011-05-23 17:05:07 -07:00
|
|
|
}
|
2011-05-23 15:08:27 -07:00
|
|
|
|
2014-07-14 20:15:44 +02:00
|
|
|
Graphics::PixelBuffer buf(_pixelFormat, width * height, DisposeAfterUse::YES);
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2011-05-23 17:05:07 -07:00
|
|
|
uint8 *bitmapData = _textBitmap;
|
2012-01-27 11:47:28 -08:00
|
|
|
uint8 r = fgColor.getRed();
|
|
|
|
uint8 g = fgColor.getGreen();
|
|
|
|
uint8 b = fgColor.getBlue();
|
2012-01-16 17:12:14 +01:00
|
|
|
uint32 color = _zb->cmode.RGBToColor(r, g, b);
|
|
|
|
|
2011-05-23 15:08:27 -07:00
|
|
|
if (color == 0xf81f)
|
|
|
|
color = 0xf81e;
|
|
|
|
|
2012-01-16 17:12:14 +01:00
|
|
|
int txData = 0;
|
|
|
|
for (int i = 0; i < width * height; i++, txData++, bitmapData++) {
|
2011-05-23 15:08:27 -07:00
|
|
|
byte pixel = *bitmapData;
|
|
|
|
if (pixel == 0x00) {
|
2012-01-16 17:12:14 +01:00
|
|
|
buf.setPixelAt(txData, 0xf81f);
|
2011-05-23 15:08:27 -07:00
|
|
|
} else if (pixel == 0x80) {
|
2012-01-16 17:12:14 +01:00
|
|
|
buf.setPixelAt(txData, 0);
|
2011-05-23 15:08:27 -07:00
|
|
|
} else if (pixel == 0xFF) {
|
2012-01-16 17:12:14 +01:00
|
|
|
buf.setPixelAt(txData, color);
|
2011-05-23 15:08:27 -07:00
|
|
|
}
|
|
|
|
}
|
2011-05-23 22:00:53 -07:00
|
|
|
|
2011-06-07 09:20:10 -07:00
|
|
|
userData[j].width = width;
|
|
|
|
userData[j].height = height;
|
2014-07-14 18:15:51 +02:00
|
|
|
|
2014-08-18 21:58:34 +03:00
|
|
|
const int kKitmapColorkey = 0xFFFF00FF;
|
2014-08-13 21:00:18 +02:00
|
|
|
|
2014-07-14 18:15:51 +02:00
|
|
|
Graphics::Surface sourceSurface;
|
|
|
|
sourceSurface.setPixels(buf.getRawBuffer());
|
|
|
|
sourceSurface.format = buf.getFormat();
|
|
|
|
sourceSurface.w = width;
|
|
|
|
sourceSurface.h = height;
|
|
|
|
sourceSurface.pitch = sourceSurface.w * buf.getFormat().bytesPerPixel;
|
|
|
|
userData[j].image = Graphics::tglGenBlitImage();
|
2014-08-13 21:00:18 +02:00
|
|
|
Graphics::tglUploadBlitImage(userData[j].image, sourceSurface, kKitmapColorkey, true);
|
2011-06-07 09:20:10 -07:00
|
|
|
userData[j].x = text->getLineX(j);
|
|
|
|
userData[j].y = text->getLineY(j);
|
|
|
|
|
2012-11-28 00:25:23 +01:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
2012-11-18 17:06:04 +01:00
|
|
|
userData[j].y -= font->getBaseOffsetY();
|
2012-11-28 00:25:23 +01:00
|
|
|
if (userData[j].y < 0)
|
|
|
|
userData[j].y = 0;
|
|
|
|
}
|
2012-11-18 17:06:04 +01:00
|
|
|
|
2011-05-23 17:05:07 -07:00
|
|
|
delete[] _textBitmap;
|
2011-05-23 15:08:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-05 18:08:47 -07:00
|
|
|
void GfxTinyGL::drawTextObject(const TextObject *text) {
|
2013-01-22 19:56:23 -08:00
|
|
|
const TextObjectData *userData = (const TextObjectData *)text->getUserData();
|
2011-05-23 22:00:53 -07:00
|
|
|
if (userData) {
|
2011-06-07 09:20:10 -07:00
|
|
|
int numLines = text->getNumLines();
|
|
|
|
for (int i = 0; i < numLines; ++i) {
|
2014-07-15 16:35:04 +02:00
|
|
|
Graphics::tglBlit(userData[i].image, userData[i].x, userData[i].y);
|
2011-06-07 09:20:10 -07:00
|
|
|
}
|
2011-05-23 22:00:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GfxTinyGL::destroyTextObject(TextObject *text) {
|
2013-01-22 19:56:23 -08:00
|
|
|
const TextObjectData *userData = (const TextObjectData *)text->getUserData();
|
2011-05-23 22:00:53 -07:00
|
|
|
if (userData) {
|
2011-06-07 09:20:10 -07:00
|
|
|
int numLines = text->getNumLines();
|
|
|
|
for (int i = 0; i < numLines; ++i) {
|
2014-07-14 18:15:51 +02:00
|
|
|
Graphics::tglDeleteBlitImage(userData[i].image);
|
2011-06-07 09:20:10 -07:00
|
|
|
}
|
|
|
|
delete[] userData;
|
2011-05-23 22:00:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-24 15:37:11 +02:00
|
|
|
void GfxTinyGL::createTexture(Texture *texture, const uint8 *data, const CMap *cmap, bool clamp) {
|
2014-06-30 22:13:40 +02:00
|
|
|
texture->_texture = new TGLuint[1];
|
|
|
|
tglGenTextures(1, (TGLuint *)texture->_texture);
|
2014-07-13 20:32:08 +02:00
|
|
|
uint8 *texdata = new uint8[texture->_width * texture->_height * 4];
|
|
|
|
uint8 *texdatapos = texdata;
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2014-05-29 15:35:46 -07:00
|
|
|
if (cmap != nullptr) { // EMI doesn't have colour-maps
|
2014-06-30 22:13:40 +02:00
|
|
|
for (int y = 0; y < texture->_height; y++) {
|
|
|
|
for (int x = 0; x < texture->_width; x++) {
|
2014-07-13 20:32:08 +02:00
|
|
|
uint8 col = *data;
|
2012-01-10 08:45:28 +01:00
|
|
|
if (col == 0) {
|
|
|
|
memset(texdatapos, 0, 4); // transparent
|
2014-06-30 22:13:40 +02:00
|
|
|
if (!texture->_hasAlpha) {
|
2012-01-10 08:45:28 +01:00
|
|
|
texdatapos[3] = '\xff'; // fully opaque
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
memcpy(texdatapos, cmap->_colors + 3 * (col), 3);
|
2009-05-05 11:34:43 +00:00
|
|
|
texdatapos[3] = '\xff'; // fully opaque
|
|
|
|
}
|
2012-01-10 08:45:28 +01:00
|
|
|
texdatapos += 4;
|
|
|
|
data++;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
2012-01-10 08:45:28 +01:00
|
|
|
} else {
|
2014-07-27 19:10:02 -04:00
|
|
|
#ifdef SCUMM_BIG_ENDIAN
|
|
|
|
// Copy and swap
|
|
|
|
for (int y = 0; y < texture->_height; y++) {
|
|
|
|
for (int x = 0; x < texture->_width; x++) {
|
|
|
|
uint32 pixel = (y * texture->_width + x) * texture->_bpp;
|
|
|
|
for (int b = 0; b < texture->_bpp; b++) {
|
|
|
|
texdata[pixel + b] = data[pixel + (texture->_bpp - 1) - b];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2014-06-30 22:13:40 +02:00
|
|
|
memcpy(texdata, data, texture->_width * texture->_height * texture->_bpp);
|
2014-07-27 19:10:02 -04:00
|
|
|
#endif
|
2012-01-10 08:45:28 +01:00
|
|
|
}
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2012-01-10 08:45:28 +01:00
|
|
|
TGLuint format = 0;
|
2012-04-12 02:54:10 +02:00
|
|
|
// TGLuint internalFormat = 0;
|
2014-06-30 22:13:40 +02:00
|
|
|
if (texture->_colorFormat == BM_RGBA) {
|
2012-01-10 08:45:28 +01:00
|
|
|
format = TGL_RGBA;
|
2012-04-12 02:54:10 +02:00
|
|
|
// internalFormat = TGL_RGBA;
|
2014-06-30 22:13:40 +02:00
|
|
|
} else if (texture->_colorFormat == BM_BGRA) {
|
2012-11-18 09:47:23 -08:00
|
|
|
format = TGL_BGRA;
|
2013-07-09 21:12:55 +02:00
|
|
|
} else { // The only other colorFormat we load right now is BGR
|
2012-01-10 08:45:28 +01:00
|
|
|
format = TGL_BGR;
|
2012-04-12 02:54:10 +02:00
|
|
|
// internalFormat = TGL_RGB;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2014-06-30 22:13:40 +02:00
|
|
|
TGLuint *textures = (TGLuint *)texture->_texture;
|
2011-07-28 22:21:16 +02:00
|
|
|
tglBindTexture(TGL_TEXTURE_2D, textures[0]);
|
2014-06-17 21:58:21 -04:00
|
|
|
|
2014-07-06 07:13:44 +02:00
|
|
|
// TinyGL doesn't have issues with dark lines in EMI intro so doesn't need TGL_CLAMP_TO_EDGE
|
2014-07-06 07:05:27 +02:00
|
|
|
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_WRAP_S, TGL_REPEAT);
|
|
|
|
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_WRAP_T, TGL_REPEAT);
|
2014-06-17 21:58:21 -04:00
|
|
|
|
2011-07-28 22:21:16 +02:00
|
|
|
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MAG_FILTER, TGL_LINEAR);
|
|
|
|
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MIN_FILTER, TGL_LINEAR);
|
2014-06-30 22:13:40 +02:00
|
|
|
tglTexImage2D(TGL_TEXTURE_2D, 0, 3, texture->_width, texture->_height, 0, format, TGL_UNSIGNED_BYTE, texdata);
|
2009-05-05 11:34:43 +00:00
|
|
|
delete[] texdata;
|
|
|
|
}
|
|
|
|
|
2014-06-30 22:13:40 +02:00
|
|
|
void GfxTinyGL::selectTexture(const Texture *texture) {
|
|
|
|
TGLuint *textures = (TGLuint *)texture->_texture;
|
2011-07-28 22:21:16 +02:00
|
|
|
tglBindTexture(TGL_TEXTURE_2D, textures[0]);
|
2014-06-20 14:13:52 +02:00
|
|
|
|
2014-06-30 22:13:40 +02:00
|
|
|
if (texture->_hasAlpha && g_grim->getGameType() == GType_MONKEY4) {
|
2014-06-23 00:44:15 +03:00
|
|
|
tglEnable(TGL_BLEND);
|
2014-06-20 14:13:52 +02:00
|
|
|
}
|
2014-06-23 00:44:15 +03:00
|
|
|
|
2012-01-10 08:45:28 +01:00
|
|
|
// Grim has inverted tex-coords, EMI doesn't
|
|
|
|
if (g_grim->getGameType() != GType_MONKEY4) {
|
2014-07-03 21:55:10 +02:00
|
|
|
tglPushMatrix(); // removed in opengl but here doesn't work properly after remove
|
2012-01-10 08:45:28 +01:00
|
|
|
tglMatrixMode(TGL_TEXTURE);
|
|
|
|
tglLoadIdentity();
|
2014-06-30 22:13:40 +02:00
|
|
|
tglScalef(1.0f / texture->_width, 1.0f / texture->_height, 1);
|
2014-07-03 21:55:10 +02:00
|
|
|
tglMatrixMode(TGL_MODELVIEW); // removed in opengl but here doesn't work properly after remove
|
|
|
|
tglPopMatrix(); // removed in opengl but here doesn't work properly after remove
|
2012-01-10 08:45:28 +01:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2014-06-30 22:13:40 +02:00
|
|
|
void GfxTinyGL::destroyTexture(Texture *texture) {
|
2015-01-13 20:37:02 +01:00
|
|
|
TGLuint *textures = (TGLuint *)texture->_texture;
|
|
|
|
if (textures) {
|
|
|
|
tglDeleteTextures(1, textures);
|
|
|
|
delete[] textures;
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2013-07-09 21:12:55 +02:00
|
|
|
void GfxTinyGL::prepareMovieFrame(Graphics::Surface *frame) {
|
2014-07-14 18:15:51 +02:00
|
|
|
_smushImage = Graphics::tglGenBlitImage();
|
|
|
|
Graphics::tglUploadBlitImage(_smushImage, *frame, 0, false);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2011-08-14 18:35:49 +02:00
|
|
|
void GfxTinyGL::drawMovieFrame(int offsetX, int offsetY) {
|
2014-07-14 18:15:51 +02:00
|
|
|
Graphics::tglBlitFast(_smushImage, offsetX, offsetY);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2011-08-14 18:35:49 +02:00
|
|
|
void GfxTinyGL::releaseMovieFrame() {
|
2014-07-14 18:15:51 +02:00
|
|
|
Graphics::tglDeleteBlitImage(_smushImage);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::loadEmergFont() {
|
2014-08-13 15:39:03 +02:00
|
|
|
Graphics::Surface characterSurface;
|
|
|
|
Graphics::PixelFormat textureFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
|
|
|
|
characterSurface.create(8, 13, textureFormat);
|
|
|
|
uint32 color = textureFormat.ARGBToColor(255, 255, 255, 255);
|
|
|
|
uint32 colorTransparent = textureFormat.ARGBToColor(0, 255, 255, 255);
|
|
|
|
for (int i = 0; i < 96; i++) {
|
|
|
|
_emergFont[i] = Graphics::tglGenBlitImage();
|
|
|
|
const uint8 *ptr = Font::emerFont[i];
|
|
|
|
for (int py = 0; py < 13; py++) {
|
|
|
|
int line = ptr[12 - py];
|
|
|
|
for (int px = 0; px < 8; px++) {
|
|
|
|
int pixel = line & 0x80;
|
|
|
|
line <<= 1;
|
|
|
|
*(uint32 *)characterSurface.getBasePtr(px, py) = pixel ? color : colorTransparent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Graphics::tglUploadBlitImage(_emergFont[i], characterSurface, 0, false);
|
|
|
|
}
|
|
|
|
characterSurface.free();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::drawEmergString(int x, int y, const char *text, const Color &fgColor) {
|
2013-10-24 19:10:28 -07:00
|
|
|
int length = strlen(text);
|
|
|
|
|
|
|
|
for (int l = 0; l < length; l++) {
|
2009-05-05 11:34:43 +00:00
|
|
|
int c = text[l];
|
|
|
|
assert(c >= 32 && c <= 127);
|
2014-08-13 15:39:03 +02:00
|
|
|
Graphics::BlitTransform transform(x, y);
|
|
|
|
transform.tint(1.0f, fgColor.getRed() / 255.0f, fgColor.getGreen() / 255.0f, fgColor.getBlue() / 255.0f);
|
|
|
|
Graphics::tglBlit(_emergFont[c - 32], transform);
|
2009-05-05 11:34:43 +00:00
|
|
|
x += 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-30 22:46:50 +02:00
|
|
|
Bitmap *GfxTinyGL::getScreenshot(int w, int h, bool useStored) {
|
|
|
|
if (useStored) {
|
|
|
|
return createScreenshotBitmap(_storedDisplay, w, h, true);
|
|
|
|
} else {
|
|
|
|
Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
|
|
|
|
_zb->copyToBuffer(src);
|
|
|
|
return createScreenshotBitmap(src, w, h, true);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2014-06-30 22:46:50 +02:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-24 15:37:11 +02:00
|
|
|
void GfxTinyGL::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height) {
|
|
|
|
readPixels(x, y, width, height, data);
|
2014-06-30 22:46:50 +02:00
|
|
|
createSpecialtyTexture(id, data, width, height);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::storeDisplay() {
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->copyToBuffer(_storedDisplay);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::copyStoredToDisplay() {
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->copyFromBuffer(_storedDisplay);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::dimScreen() {
|
2012-01-25 23:02:24 +01:00
|
|
|
for (int l = 0; l < _gameWidth * _gameHeight; l++) {
|
2012-01-16 17:12:14 +01:00
|
|
|
uint8 r, g, b;
|
2012-01-24 18:20:33 +01:00
|
|
|
_storedDisplay.getRGBAt(l, r, g, b);
|
|
|
|
uint32 color = (r + g + b) / 10;
|
|
|
|
_storedDisplay.setPixelAt(l, color, color, color);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::dimRegion(int x, int y, int w, int h, float level) {
|
2009-05-05 11:34:43 +00:00
|
|
|
for (int ly = y; ly < y + h; ly++) {
|
|
|
|
for (int lx = x; lx < x + w; lx++) {
|
2012-01-24 18:20:33 +01:00
|
|
|
uint8 r, g, b;
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->readPixelRGB(ly * _gameWidth + lx, r, g, b);
|
2012-01-27 13:48:36 +01:00
|
|
|
uint32 color = (uint32)(((r + g + b) / 3) * level);
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(ly * _gameWidth + lx, color, color, color);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-07-28 21:36:03 +02:00
|
|
|
|
2011-07-29 22:49:08 +02:00
|
|
|
void GfxTinyGL::irisAroundRegion(int x1, int y1, int x2, int y2) {
|
2012-01-28 09:06:22 +01:00
|
|
|
for (int ly = 0; ly < _gameHeight; ly++) {
|
|
|
|
for (int lx = 0; lx < _gameWidth; lx++) {
|
2011-07-28 01:56:28 +02:00
|
|
|
// Don't do anything with the data in the region we draw Around
|
2012-01-27 19:58:17 +01:00
|
|
|
if (lx > x1 && lx < x2 && ly > y1 && ly < y2)
|
2011-07-28 01:56:28 +02:00
|
|
|
continue;
|
|
|
|
// But set everything around it to black.
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(ly * _gameWidth + lx, 0);
|
2011-07-28 01:56:28 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-28 01:36:27 +02:00
|
|
|
}
|
|
|
|
|
2012-05-05 18:03:04 -07:00
|
|
|
void GfxTinyGL::drawRectangle(const PrimitiveObject *primitive) {
|
2009-05-10 10:11:55 +00:00
|
|
|
int x1 = primitive->getP1().x;
|
|
|
|
int y1 = primitive->getP1().y;
|
2009-05-10 15:47:58 +00:00
|
|
|
int x2 = primitive->getP2().x;
|
2009-05-10 10:11:55 +00:00
|
|
|
int y2 = primitive->getP2().y;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2012-01-27 11:47:28 -08:00
|
|
|
const Color &color = primitive->getColor();
|
2012-01-24 18:20:33 +01:00
|
|
|
uint32 c = _pixelFormat.RGBToColor(color.getRed(), color.getGreen(), color.getBlue());
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
if (primitive->isFilled()) {
|
2009-05-24 06:26:14 +00:00
|
|
|
for (; y1 <= y2; y1++)
|
2012-01-25 23:02:24 +01:00
|
|
|
if (y1 >= 0 && y1 < _gameHeight)
|
2009-05-24 06:26:14 +00:00
|
|
|
for (int x = x1; x <= x2; x++)
|
2012-01-25 23:02:24 +01:00
|
|
|
if (x >= 0 && x < _gameWidth)
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(_gameWidth * y1 + x, c);
|
2009-05-05 11:34:43 +00:00
|
|
|
} else {
|
2012-01-25 23:02:24 +01:00
|
|
|
if (y1 >= 0 && y1 < _gameHeight)
|
2009-05-24 06:26:14 +00:00
|
|
|
for (int x = x1; x <= x2; x++)
|
2012-01-25 23:02:24 +01:00
|
|
|
if (x >= 0 && x < _gameWidth)
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(_gameWidth * y1 + x, c);
|
2012-01-25 23:02:24 +01:00
|
|
|
if (y2 >= 0 && y2 < _gameHeight)
|
2009-05-24 06:26:14 +00:00
|
|
|
for (int x = x1; x <= x2; x++)
|
2012-01-25 23:02:24 +01:00
|
|
|
if (x >= 0 && x < _gameWidth)
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(_gameWidth * y2 + x, c);
|
2012-01-25 23:02:24 +01:00
|
|
|
if (x1 >= 0 && x1 < _gameWidth)
|
2009-05-24 06:26:14 +00:00
|
|
|
for (int y = y1; y <= y2; y++)
|
2012-01-25 23:02:24 +01:00
|
|
|
if (y >= 0 && y < _gameHeight)
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(_gameWidth * y + x1, c);
|
2012-01-25 23:02:24 +01:00
|
|
|
if (x2 >= 0 && x2 < _gameWidth)
|
2009-05-24 06:26:14 +00:00
|
|
|
for (int y = y1; y <= y2; y++)
|
2012-01-25 23:02:24 +01:00
|
|
|
if (y >= 0 && y < _gameHeight)
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(_gameWidth * y + x2, c);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-05 18:03:04 -07:00
|
|
|
void GfxTinyGL::drawLine(const PrimitiveObject *primitive) {
|
2009-05-10 10:11:55 +00:00
|
|
|
int x1 = primitive->getP1().x;
|
2009-05-10 15:47:58 +00:00
|
|
|
int y1 = primitive->getP1().y;
|
|
|
|
int x2 = primitive->getP2().x;
|
2009-05-10 10:11:55 +00:00
|
|
|
int y2 = primitive->getP2().y;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2012-01-27 11:47:28 -08:00
|
|
|
const Color &color = primitive->getColor();
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2011-04-15 21:55:07 +02:00
|
|
|
if (x2 == x1) {
|
|
|
|
for (int y = y1; y <= y2; y++) {
|
2012-01-25 23:02:24 +01:00
|
|
|
if (x1 >= 0 && x1 < _gameWidth && y >= 0 && y < _gameHeight)
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(_gameWidth * y + x1, color.getRed(), color.getGreen(), color.getBlue());
|
2011-04-15 21:55:07 +02:00
|
|
|
}
|
|
|
|
} else {
|
2014-11-29 16:01:40 -08:00
|
|
|
float m = (y2 - y1) / (float)(x2 - x1);
|
2011-04-15 21:55:07 +02:00
|
|
|
int b = (int)(-m * x1 + y1);
|
|
|
|
for (int x = x1; x <= x2; x++) {
|
|
|
|
int y = (int)(m * x) + b;
|
2012-01-25 23:02:24 +01:00
|
|
|
if (x >= 0 && x < _gameWidth && y >= 0 && y < _gameHeight)
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(_gameWidth * y + x, color.getRed(), color.getGreen(), color.getBlue());
|
2011-04-15 21:55:07 +02:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-08 21:04:25 +02:00
|
|
|
void GfxTinyGL::drawDimPlane() {
|
|
|
|
if (_dimLevel == 0.0f) return;
|
|
|
|
|
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglLoadIdentity();
|
|
|
|
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglLoadIdentity();
|
|
|
|
|
|
|
|
tglDisable(TGL_DEPTH_TEST);
|
|
|
|
tglDepthMask(TGL_FALSE);
|
|
|
|
|
|
|
|
tglDisable(TGL_LIGHTING);
|
|
|
|
tglEnable(TGL_BLEND);
|
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
|
|
tglColor4f(0.0f, 0.0f, 0.0f, _dimLevel);
|
2014-11-05 20:53:26 +01:00
|
|
|
|
2014-07-08 21:04:25 +02:00
|
|
|
tglBegin(TGL_QUADS);
|
|
|
|
tglVertex2f(-1, -1);
|
|
|
|
tglVertex2f(1.0, -1);
|
|
|
|
tglVertex2f(1.0, 1.0);
|
|
|
|
tglVertex2f(-1, 1.0);
|
|
|
|
tglEnd();
|
|
|
|
|
2014-11-05 20:53:26 +01:00
|
|
|
tglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
2014-07-08 21:04:25 +02:00
|
|
|
tglDisable(TGL_BLEND);
|
|
|
|
tglDepthMask(TGL_TRUE);
|
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
|
|
|
tglEnable(TGL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2012-05-05 18:03:04 -07:00
|
|
|
void GfxTinyGL::drawPolygon(const PrimitiveObject *primitive) {
|
2009-05-10 10:11:55 +00:00
|
|
|
int x1 = primitive->getP1().x;
|
|
|
|
int y1 = primitive->getP1().y;
|
|
|
|
int x2 = primitive->getP2().x;
|
|
|
|
int y2 = primitive->getP2().y;
|
|
|
|
int x3 = primitive->getP3().x;
|
|
|
|
int y3 = primitive->getP3().y;
|
|
|
|
int x4 = primitive->getP4().x;
|
|
|
|
int y4 = primitive->getP4().y;
|
2009-05-05 11:34:43 +00:00
|
|
|
float m;
|
|
|
|
int b;
|
|
|
|
|
2012-01-27 11:47:28 -08:00
|
|
|
const Color &color = primitive->getColor();
|
2012-01-24 18:20:33 +01:00
|
|
|
uint32 c = _pixelFormat.RGBToColor(color.getRed(), color.getGreen(), color.getBlue());
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
m = (y2 - y1) / (x2 - x1);
|
|
|
|
b = (int)(-m * x1 + y1);
|
|
|
|
for (int x = x1; x <= x2; x++) {
|
|
|
|
int y = (int)(m * x) + b;
|
2012-01-25 23:02:24 +01:00
|
|
|
if (x >= 0 && x < _gameWidth && y >= 0 && y < _gameHeight)
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(_gameWidth * y + x, c);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
m = (y4 - y3) / (x4 - x3);
|
|
|
|
b = (int)(-m * x3 + y3);
|
|
|
|
for (int x = x3; x <= x4; x++) {
|
|
|
|
int y = (int)(m * x) + b;
|
2012-01-25 23:02:24 +01:00
|
|
|
if (x >= 0 && x < _gameWidth && y >= 0 && y < _gameHeight)
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(_gameWidth * y + x, c);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
2009-05-25 06:49:57 +00:00
|
|
|
|
2012-04-13 09:48:16 -07:00
|
|
|
void GfxTinyGL::readPixels(int x, int y, int width, int height, uint8 *buffer) {
|
2014-07-24 15:37:11 +02:00
|
|
|
assert(x >= 0);
|
|
|
|
assert(y >= 0);
|
|
|
|
assert(x < _screenWidth);
|
|
|
|
assert(y < _screenHeight);
|
|
|
|
|
2012-04-13 09:48:16 -07:00
|
|
|
uint8 r, g, b;
|
2014-07-24 15:37:11 +02:00
|
|
|
int pos = x + y * _screenWidth;
|
2012-04-13 09:48:16 -07:00
|
|
|
for (int i = 0; i < height; ++i) {
|
|
|
|
for (int j = 0; j < width; ++j) {
|
2014-07-24 15:37:11 +02:00
|
|
|
if ((j + x) >= _screenWidth || (i + y) >= _screenHeight) {
|
|
|
|
buffer[0] = buffer[1] = buffer[2] = 0;
|
|
|
|
} else {
|
|
|
|
_zb->readPixelRGB(pos + j, r, g, b);
|
|
|
|
buffer[0] = r;
|
|
|
|
buffer[1] = g;
|
|
|
|
buffer[2] = b;
|
|
|
|
}
|
2012-04-13 09:48:16 -07:00
|
|
|
buffer[3] = 255;
|
|
|
|
buffer += 4;
|
|
|
|
}
|
2014-07-24 15:37:11 +02:00
|
|
|
pos += _screenWidth;
|
2012-04-13 09:48:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-05 18:03:39 +03:00
|
|
|
void GfxTinyGL::setBlendMode(bool additive) {
|
|
|
|
if (additive) {
|
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE);
|
|
|
|
} else {
|
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-25 06:49:57 +00:00
|
|
|
} // end of namespace Grim
|