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;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
GfxTinyGL::~GfxTinyGL() {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
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) {
|
2012-01-29 22:04:45 +01:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
2013-07-09 21:12:55 +02:00
|
|
|
tglScalef(1.0, 1.0, -1.0);
|
2012-07-03 00:09:24 +02:00
|
|
|
|
|
|
|
_currentPos = pos;
|
|
|
|
_currentQuat = Math::Quaternion(interest.x(), interest.y(), interest.z(), roll);
|
|
|
|
} else {
|
|
|
|
Math::Vector3d up_vec(0, 0, 1);
|
|
|
|
|
|
|
|
tglRotatef(roll, 0, 0, -1);
|
2012-01-29 22:04:45 +01:00
|
|
|
|
2012-07-03 00:09:24 +02:00
|
|
|
if (pos.x() == interest.x() && pos.y() == interest.y())
|
|
|
|
up_vec = Math::Vector3d(0, 1, 0);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-10 07:29:01 +02:00
|
|
|
Math::Matrix4 lookMatrix = Math::makeLookAtMatrix(pos, interest, up_vec);
|
|
|
|
tglMultMatrixf(lookMatrix.getData());
|
|
|
|
tglTranslatef(-pos.x(), -pos.y(), -pos.z());
|
2012-07-03 00:09:24 +02:00
|
|
|
}
|
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();
|
|
|
|
|
|
|
|
Math::Matrix4 worldRot = _currentQuat.toMatrix();
|
|
|
|
tglMultMatrixf(worldRot.getData());
|
|
|
|
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;
|
|
|
|
Math::gluMathProject<TGLfloat>(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;
|
|
|
|
Math::gluMathProject<TGLfloat>(obj, modelView, projection, viewPort, win);
|
|
|
|
|
|
|
|
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.
|
|
|
|
Math::Matrix4 worldRot = _currentQuat.toMatrix();
|
|
|
|
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;
|
|
|
|
Math::gluMathProject<TGLfloat>(p, modelView, projection, viewPort, projected);
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
Math::Matrix4 worldRot = _currentQuat.toMatrix();
|
|
|
|
tglMultMatrixf(worldRot.getData());
|
|
|
|
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
|
|
|
}
|
2013-07-02 00:13:00 +02:00
|
|
|
|
2014-07-20 20:58:22 +03:00
|
|
|
if (!_currentShadowArray && actor->getSortOrder() >= 100) {
|
2014-06-20 14:13:52 +02:00
|
|
|
tglColorMask(TGL_FALSE, TGL_FALSE, TGL_FALSE, TGL_FALSE);
|
2014-07-03 21:55:10 +02:00
|
|
|
tglDepthMask(TGL_TRUE);
|
2013-12-04 14:26:44 +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.
|
|
|
|
Math::Matrix4 worldRot = _currentQuat.toMatrix();
|
|
|
|
tglMultMatrixf(worldRot.getData());
|
|
|
|
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-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);
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2014-07-03 21:55:10 +02:00
|
|
|
tglBegin(TGL_TRIANGLES);
|
2012-11-21 18:17:24 +01:00
|
|
|
float dim = 1.0f - _dimLevel;
|
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
|
|
|
|
2014-07-20 20:58:22 +03:00
|
|
|
Math::Vector3d lighting = model->_lighting[index];
|
|
|
|
byte r = (byte)(model->_colorMap[index].r * lighting.x() * dim);
|
|
|
|
byte g = (byte)(model->_colorMap[index].g * lighting.y() * dim);
|
|
|
|
byte b = (byte)(model->_colorMap[index].b * lighting.z() * dim);
|
|
|
|
byte a = (int)(model->_colorMap[index].a * _alpha);
|
|
|
|
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
|
|
|
|
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-07-03 21:55:10 +02: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-06-23 00:44:15 +03:00
|
|
|
if (sprite->_blendMode == 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-06-23 00:44:15 +03:00
|
|
|
if (sprite->_alphaTest) {
|
2014-07-04 08:43:19 +02:00
|
|
|
tglEnable(TGL_ALPHA_TEST);
|
|
|
|
tglAlphaFunc(TGL_GEQUAL, g_grim->getGameType() == GType_MONKEY4 ? 0.1f : 0.5f);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
if (sprite->_writeDepth) {
|
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
|
|
|
} else {
|
|
|
|
tglDisable(TGL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
|
2013-01-02 02:20:51 +02:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
2014-06-17 21:00:17 +02:00
|
|
|
if (_currentActor->isInOverworld()) {
|
|
|
|
// The Overworld actors don't have a proper sort order
|
|
|
|
// so we rely on the z coordinates
|
2014-07-03 20:57:05 +02:00
|
|
|
tglDepthMask(TGL_TRUE);
|
2014-06-17 21:00:17 +02:00
|
|
|
} else {
|
2014-07-03 20:57:05 +02:00
|
|
|
tglDepthMask(TGL_FALSE);
|
2014-06-17 21:00:17 +02:00
|
|
|
}
|
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-06-23 00:44:15 +03:00
|
|
|
float dim = 1.0f - _dimLevel;
|
|
|
|
float texCoordsX[] = { 0.0f, 0.0f, 1.0f, 1.0f };
|
|
|
|
float texCoordsY[] = { 1.0f, 0.0f, 0.0f, 1.0f };
|
|
|
|
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) {
|
|
|
|
float r = sprite->_red[i] * dim / 255.0f;
|
|
|
|
float g = sprite->_green[i] * dim / 255.0f;
|
|
|
|
float b = sprite->_blue[i] * dim / 255.0f;
|
|
|
|
float a = sprite->_alpha[i] * dim * _alpha / 255.0f;
|
|
|
|
|
|
|
|
tglColor4f(r, g, b, a);
|
|
|
|
tglTexCoord2f(texCoordsX[i], texCoordsY[i]);
|
|
|
|
tglVertex3f(vertexX[i] * halfWidth, vertexY[i] * halfHeight, 0.0f);
|
|
|
|
}
|
2013-12-12 03:36:21 +01:00
|
|
|
tglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
2013-01-02 00:50:26 +02:00
|
|
|
tglEnd();
|
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;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
float intensity = light->_intensity / 1.3f;
|
2011-05-05 10:58:29 +02:00
|
|
|
lightColor[0] = ((float)light->_color.getRed() / 15.0f) * intensity;
|
2011-05-20 00:16:08 +02:00
|
|
|
lightColor[1] = ((float)light->_color.getGreen() / 15.0f) * intensity;
|
|
|
|
lightColor[2] = ((float)light->_color.getBlue() / 15.0f) * 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();
|
2011-05-20 00:21:53 +02:00
|
|
|
/* FIXME: TGL_SPOT_CUTOFF should be light->_penumbraangle, but there
|
|
|
|
seems to be a bug in tinygl as it renders differently from OpenGL.
|
|
|
|
Reproducing: turn off all lights (comment out), go to scene "al",
|
|
|
|
and walk along left wall under the lamp. */
|
2011-05-21 04:28:48 +08:00
|
|
|
cutoff = 90.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);
|
|
|
|
tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_CUTOFF, cutoff);
|
|
|
|
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();
|
|
|
|
const Graphics::PixelBuffer& imageBuffer = bitmap->getImageData(pic);
|
|
|
|
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 {
|
|
|
|
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;
|
|
|
|
Graphics::tglUploadBlitImage(imgs[i], sourceSurface, -524040, 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).
|
|
|
|
if (g_grim->getGameType() == GType_MONKEY4 && bitmap->_data->_numImages > 1) {
|
2014-07-16 16:46:56 +02:00
|
|
|
tglEnable(TGL_BLEND);
|
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
|
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
|
|
|
|
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];
|
|
|
|
|
|
|
|
int width = font->getStringLength(currentLine) + 1;
|
2014-07-30 21:35:38 -04:00
|
|
|
int height = font->getKernedHeight();
|
2011-05-23 17:05:07 -07:00
|
|
|
|
|
|
|
uint8 *_textBitmap = new uint8[height * width];
|
|
|
|
memset(_textBitmap, 0, height * width);
|
|
|
|
|
|
|
|
// Fill bitmap
|
|
|
|
int startOffset = 0;
|
|
|
|
for (unsigned int d = 0; d < currentLine.size(); d++) {
|
|
|
|
int ch = currentLine[d];
|
|
|
|
int8 startingLine = font->getCharStartingLine(ch) + font->getBaseOffsetY();
|
2014-07-30 21:35:38 -04:00
|
|
|
int32 charBitmapWidth = font->getCharBitmapWidth(ch);
|
|
|
|
int32 charKernedWidth = font->getCharKernedWidth(ch);
|
2011-05-23 17:05:07 -07:00
|
|
|
int8 startingCol = font->getCharStartingCol(ch);
|
2014-07-30 21:35:38 -04:00
|
|
|
for (int line = 0; line < font->getCharBitmapHeight(ch); line++) {
|
2011-05-23 17:05:07 -07:00
|
|
|
int offset = startOffset + (width * (line + startingLine));
|
2014-07-30 21:35:38 -04:00
|
|
|
for (int r = 0; r < charBitmapWidth; r++) {
|
|
|
|
const byte pixel = *(font->getCharData(ch) + r + (charBitmapWidth * line));
|
2011-05-23 17:05:07 -07:00
|
|
|
byte *dst = _textBitmap + offset + startingCol + r;
|
|
|
|
if (*dst == 0 && pixel != 0)
|
|
|
|
_textBitmap[offset + startingCol + r] = pixel;
|
|
|
|
}
|
2014-07-30 21:35:38 -04:00
|
|
|
if (line + startingLine >= font->getKernedHeight())
|
2011-05-23 17:05:07 -07:00
|
|
|
break;
|
|
|
|
}
|
2014-07-30 21:35:38 -04:00
|
|
|
startOffset += charKernedWidth;
|
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
|
|
|
|
|
|
|
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();
|
|
|
|
Graphics::tglUploadBlitImage(userData[j].image, sourceSurface, 0xFFF800F8, 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-06-30 22:13:40 +02:00
|
|
|
memcpy(texdata, data, texture->_width * texture->_height * texture->_bpp);
|
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) {
|
|
|
|
tglDeleteTextures(1, (TGLuint *)texture->_texture);
|
|
|
|
delete[] (TGLuint *)texture->_texture;
|
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() {
|
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) {
|
2012-01-16 17:12:14 +01:00
|
|
|
uint32 color = _pixelFormat.RGBToColor(fgColor.getRed(), fgColor.getGreen(), fgColor.getBlue());
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2013-10-24 19:10:28 -07:00
|
|
|
int length = strlen(text);
|
|
|
|
|
2014-07-27 19:55:59 +02:00
|
|
|
bool blendingEnabled = _zb->isBlendingEnabled();
|
2014-08-10 19:05:32 +02:00
|
|
|
bool alphaTestEnabled = _zb->isAlphaTestEnabled();
|
2014-07-27 19:55:59 +02:00
|
|
|
_zb->enableBlending(false);
|
|
|
|
_zb->enableAlphaTest(false);
|
|
|
|
|
2013-10-24 19:10:28 -07:00
|
|
|
for (int l = 0; l < length; l++) {
|
2009-05-05 11:34:43 +00:00
|
|
|
int c = text[l];
|
|
|
|
assert(c >= 32 && c <= 127);
|
|
|
|
const uint8 *ptr = Font::emerFont[c - 32];
|
|
|
|
for (int py = 0; py < 13; py++) {
|
2012-01-25 23:02:24 +01:00
|
|
|
if ((py + y) < _gameHeight && (py + y) >= 0) {
|
2009-05-05 11:34:43 +00:00
|
|
|
int line = ptr[12 - py];
|
|
|
|
for (int px = 0; px < 8; px++) {
|
2012-01-25 23:02:24 +01:00
|
|
|
if ((px + x) < _gameWidth && (px + x) >= 0) {
|
2009-05-05 11:34:43 +00:00
|
|
|
int pixel = line & 0x80;
|
|
|
|
line <<= 1;
|
2012-01-16 17:12:14 +01:00
|
|
|
if (pixel) {
|
2014-06-19 17:30:28 +02:00
|
|
|
_zb->writePixel(((py + y) * _gameWidth) + (px + x), color);
|
2012-01-16 17:12:14 +01:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
x += 10;
|
|
|
|
}
|
2014-07-27 19:55:59 +02:00
|
|
|
|
|
|
|
_zb->enableBlending(blendingEnabled);
|
|
|
|
_zb->enableAlphaTest(alphaTestEnabled);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
float m = (y2 - y1) / (x2 - x1);
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-25 06:49:57 +00:00
|
|
|
} // end of namespace Grim
|