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
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2017-05-03 02:47:29 +00:00
|
|
|
#include "common/config-manager.h"
|
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),
|
GRIM: Drop off-screen buffers
These were present to implement actor freezing in software rendering mode
in the way original engine was intended for performance reason.
In residualvm, software rendering will generalise the principle through
dirty-rectangles management, so off-screen buffers should not be needed.
Also, properly implementing them requires invasive changes (move previous
draw call list from global OpenGL context to individual off-screen buffers,
along with associated linear vertex allocator, adding a new draw call to
track requested buffer changes until final on-screen frame buffer
presentation).
So instead of such added complexity, lie to lua API about actor not being
in set but keep it in so it is part of normal redraw sequence.
Fixes disappearing actors in cn, bi.
Likely also fixes at, ly, sh, mn, dd which uses free/thaw lua API, but
which I did not check.
2017-04-25 00:00:33 +00:00
|
|
|
_currentActor(nullptr), _smushImage(nullptr) {
|
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() {
|
2016-07-17 15:05:16 +00:00
|
|
|
releaseMovieFrame();
|
2014-12-31 01:42:44 +01:00
|
|
|
for (unsigned int i = 0; i < _numSpecialtyTextures; i++) {
|
|
|
|
destroyTexture(&_specialtyTextures[i]);
|
|
|
|
}
|
2016-07-17 14:24:14 +00:00
|
|
|
for (int i = 0; i < 96; i++) {
|
|
|
|
Graphics::tglDeleteBlitImage(_emergFont[i]);
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
if (_zb) {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-14 06:49:28 +01:00
|
|
|
void GfxTinyGL::setupScreen(int screenW, int screenH) {
|
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;
|
|
|
|
|
2020-10-14 06:49:28 +01:00
|
|
|
g_system->showMouse(false);
|
2011-06-02 12:16:04 +02:00
|
|
|
|
2020-10-13 21:12:10 +01:00
|
|
|
_pixelFormat = g_system->getScreenFormat();
|
2017-05-02 13:05:33 +00:00
|
|
|
debug("INFO: TinyGL front buffer pixel format: %s", _pixelFormat.toString().c_str());
|
2020-10-13 21:12:10 +01:00
|
|
|
_zb = new TinyGL::FrameBuffer(screenW, screenH, _pixelFormat);
|
2014-07-05 13:08:34 +02:00
|
|
|
TinyGL::glInit(_zb, 256);
|
2017-05-03 02:47:29 +00:00
|
|
|
tglEnableDirtyRects(ConfMan.getBool("dirtyrects"));
|
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-07 19:06:31 +00:00
|
|
|
}
|
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();
|
|
|
|
|
2020-09-23 23:20:23 +02:00
|
|
|
float right = nclip * tan(fov / 2 * ((float)M_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() {
|
2017-04-29 08:28:28 +00:00
|
|
|
tglClear(TGL_COLOR_BUFFER_BIT | TGL_DEPTH_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
|
|
|
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();
|
2020-10-13 21:12:10 +01:00
|
|
|
g_system->copyRectToScreen(_zb->getPixelBuffer(), _zb->linesize,
|
|
|
|
0, 0, _zb->xsize, _zb->ysize);
|
2009-05-07 19:06:31 +00:00
|
|
|
g_system->updateScreen();
|
2009-05-05 11:34:43 +00: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);
|
2017-04-29 07:22:09 +00:00
|
|
|
tglDisable(TGL_LIGHTING);
|
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);
|
2017-04-29 07:22:09 +00: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];
|
2017-04-29 07:22:09 +00:00
|
|
|
|
2014-07-20 20:58:22 +03:00
|
|
|
if (!_currentShadowArray) {
|
|
|
|
if (face->_hasTexture) {
|
|
|
|
tglTexCoord2f(model->_texVerts[index].getX(), model->_texVerts[index].getY());
|
|
|
|
}
|
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);
|
2017-04-29 07:22:09 +00:00
|
|
|
tglEnable(TGL_LIGHTING);
|
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) {
|
2016-07-14 15:27:51 +00:00
|
|
|
// Support transparency in actor objects, such as the message tube
|
|
|
|
// in Manny's Office
|
2012-12-27 19:08:46 +01:00
|
|
|
float *vertices = mesh->_vertices;
|
|
|
|
float *vertNormals = mesh->_vertNormals;
|
|
|
|
float *textureVerts = mesh->_textureVerts;
|
2016-07-14 15:27:51 +00:00
|
|
|
tglAlphaFunc(TGL_GREATER, 0.5);
|
|
|
|
tglEnable(TGL_ALPHA_TEST);
|
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-03-30 14:38:52 -07:00
|
|
|
tglVertex3fv(vertices + 3 * face->getVertex(i));
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
tglEnd();
|
2016-07-14 15:27:51 +00:00
|
|
|
// Done with transparency-capable objects
|
|
|
|
tglDisable(TGL_ALPHA_TEST);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2016-07-15 01:10:08 +00:00
|
|
|
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() {
|
2016-07-10 13:14:32 +00:00
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
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) {
|
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 {
|
|
|
|
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;
|
2017-04-29 09:42:49 +00:00
|
|
|
Graphics::tglUploadBlitImage(imgs[i], sourceSurface, sourceSurface.format.ARGBToColor(0, 255, 0, 255), 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) {
|
2016-07-16 12:06:49 +00:00
|
|
|
if (bitmap->getHasTransparency()) {
|
|
|
|
tglEnable(TGL_BLEND);
|
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
}
|
2014-07-15 16:35:04 +02:00
|
|
|
Graphics::tglBlit(b[num], x, y);
|
2016-07-16 12:06:49 +00:00
|
|
|
if (bitmap->getHasTransparency()) {
|
|
|
|
tglDisable(TGL_BLEND);
|
|
|
|
}
|
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);
|
2016-07-21 16:17:32 +02:00
|
|
|
uint32 kKitmapColorkey = _pixelFormat.RGBToColor(0, 255, 0);
|
|
|
|
const uint32 blackColor = _pixelFormat.RGBToColor(0, 0, 0);
|
|
|
|
const uint32 color = _pixelFormat.RGBToColor(fgColor.getRed(), fgColor.getGreen(), fgColor.getBlue());
|
|
|
|
while (color == kKitmapColorkey || blackColor == kKitmapColorkey) {
|
|
|
|
kKitmapColorkey += 1;
|
|
|
|
}
|
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;
|
2011-05-23 15:08:27 -07:00
|
|
|
|
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) {
|
2016-07-21 16:17:32 +02:00
|
|
|
buf.setPixelAt(txData, kKitmapColorkey);
|
2011-05-23 15:08:27 -07:00
|
|
|
} else if (pixel == 0x80) {
|
2016-07-21 16:17:32 +02:00
|
|
|
buf.setPixelAt(txData, blackColor);
|
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();
|
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) {
|
2016-07-16 12:06:49 +00:00
|
|
|
tglEnable(TGL_BLEND);
|
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
|
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
|
|
|
}
|
2016-07-16 12:06:49 +00:00
|
|
|
tglDisable(TGL_BLEND);
|
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) {
|
|
|
|
tglMatrixMode(TGL_TEXTURE);
|
|
|
|
tglLoadIdentity();
|
2014-06-30 22:13:40 +02:00
|
|
|
tglScalef(1.0f / texture->_width, 1.0f / texture->_height, 1);
|
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) {
|
2016-07-17 06:38:35 +00:00
|
|
|
if (_smushImage == nullptr)
|
|
|
|
_smushImage = Graphics::tglGenBlitImage();
|
2014-07-14 18:15:51 +02:00
|
|
|
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 {
|
2017-04-26 11:45:00 +00:00
|
|
|
Graphics::PixelBuffer src(_pixelFormat, _screenWidth * _screenHeight, DisposeAfterUse::YES);
|
2014-06-30 22:46:50 +02:00
|
|
|
_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() {
|
2017-04-25 00:41:07 +00:00
|
|
|
TinyGL::tglPresentBuffer();
|
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() {
|
2017-05-02 12:42:21 +00:00
|
|
|
Bitmap *bitmap = getScreenshot(_gameWidth, _gameHeight, true);
|
|
|
|
drawBitmap(bitmap, 0, 0, 0);
|
|
|
|
delete bitmap;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxTinyGL::dimScreen() {
|
2016-07-23 09:17:26 +02:00
|
|
|
dimRegion(0, 0, _gameWidth, _gameHeight, 0.2f);
|
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) {
|
2016-07-23 09:17:26 +02:00
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglLoadIdentity();
|
|
|
|
tglOrtho(0, _gameWidth, _gameHeight, 0, 0, 1);
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglLoadIdentity();
|
|
|
|
|
|
|
|
tglDisable(TGL_LIGHTING);
|
|
|
|
tglDisable(TGL_DEPTH_TEST);
|
|
|
|
tglDepthMask(TGL_FALSE);
|
|
|
|
tglEnable(TGL_BLEND);
|
|
|
|
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
|
|
tglColor4f(0, 0, 0, 1 - level);
|
|
|
|
|
|
|
|
tglBegin(TGL_QUADS);
|
|
|
|
tglVertex2f(x, y);
|
|
|
|
tglVertex2f(x + w, y);
|
|
|
|
tglVertex2f(x + w, y + h);
|
|
|
|
tglVertex2f(x, y + h);
|
|
|
|
tglEnd();
|
|
|
|
|
|
|
|
tglColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
|
|
|
|
tglDisable(TGL_BLEND);
|
|
|
|
tglDepthMask(TGL_TRUE);
|
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
|
|
|
tglEnable(TGL_LIGHTING);
|
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) {
|
2016-07-23 09:17:26 +02:00
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglLoadIdentity();
|
|
|
|
tglOrtho(0.0, _gameWidth, _gameHeight, 0.0, 0.0, 1.0);
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglLoadIdentity();
|
|
|
|
|
|
|
|
tglDisable(TGL_DEPTH_TEST);
|
|
|
|
tglDisable(TGL_TEXTURE_2D);
|
|
|
|
tglDisable(TGL_BLEND);
|
|
|
|
tglDisable(TGL_LIGHTING);
|
|
|
|
tglDepthMask(TGL_FALSE);
|
|
|
|
|
|
|
|
tglColor3f(0.0f, 0.0f, 0.0f);
|
|
|
|
|
|
|
|
//Explicitly cast to avoid problems with C++11
|
|
|
|
float fx1 = x1;
|
|
|
|
float fx2 = x2;
|
|
|
|
float fy1 = y1;
|
|
|
|
float fy2 = y2;
|
|
|
|
float width = _screenWidth;
|
|
|
|
float height = _screenHeight;
|
|
|
|
float points[20] = {
|
|
|
|
0.0f, 0.0f,
|
|
|
|
0.0f, fy1,
|
|
|
|
width, 0.0f,
|
|
|
|
fx2, fy1,
|
|
|
|
width, height,
|
|
|
|
fx2, fy2,
|
|
|
|
0.0f, height,
|
|
|
|
fx1, fy2,
|
|
|
|
0.0f, fy1,
|
|
|
|
fx1, fy1
|
|
|
|
};
|
|
|
|
|
|
|
|
tglEnableClientState(TGL_VERTEX_ARRAY);
|
|
|
|
tglVertexPointer(2, TGL_FLOAT, 0, points);
|
|
|
|
tglDrawArrays(TGL_TRIANGLE_STRIP, 0, 10);
|
|
|
|
tglDisableClientState(TGL_VERTEX_ARRAY);
|
|
|
|
|
|
|
|
tglColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
|
|
|
tglEnable(TGL_LIGHTING);
|
|
|
|
tglDepthMask(TGL_TRUE);
|
2011-07-28 01:36:27 +02:00
|
|
|
}
|
|
|
|
|
2012-05-05 18:03:04 -07:00
|
|
|
void GfxTinyGL::drawRectangle(const PrimitiveObject *primitive) {
|
2016-07-11 00:09:39 +00:00
|
|
|
float x1 = primitive->getP1().x * _scaleW;
|
|
|
|
float y1 = primitive->getP1().y * _scaleH;
|
|
|
|
float x2 = primitive->getP2().x * _scaleW;
|
|
|
|
float y2 = primitive->getP2().y * _scaleH;
|
|
|
|
const Color color(primitive->getColor());
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2016-07-11 00:09:39 +00:00
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglLoadIdentity();
|
|
|
|
tglOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglLoadIdentity();
|
|
|
|
|
|
|
|
tglDisable(TGL_LIGHTING);
|
|
|
|
tglDisable(TGL_DEPTH_TEST);
|
|
|
|
tglDepthMask(TGL_FALSE);
|
|
|
|
|
|
|
|
tglColor3ub(color.getRed(), color.getGreen(), color.getBlue());
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
if (primitive->isFilled()) {
|
2016-07-11 00:09:39 +00:00
|
|
|
tglBegin(TGL_QUADS);
|
|
|
|
tglVertex2f(x1, y1);
|
|
|
|
tglVertex2f(x2 + 1, y1);
|
|
|
|
tglVertex2f(x2 + 1, y2 + 1);
|
|
|
|
tglVertex2f(x1, y2 + 1);
|
|
|
|
tglEnd();
|
2009-05-05 11:34:43 +00:00
|
|
|
} else {
|
2016-07-11 14:51:39 +00:00
|
|
|
tglBegin(TGL_LINE_LOOP);
|
2016-07-11 00:09:39 +00:00
|
|
|
tglVertex2f(x1, y1);
|
|
|
|
tglVertex2f(x2 + 1, y1);
|
|
|
|
tglVertex2f(x2 + 1, y2 + 1);
|
|
|
|
tglVertex2f(x1, y2 + 1);
|
|
|
|
tglEnd();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2016-07-11 00:09:39 +00:00
|
|
|
|
|
|
|
tglColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
|
|
|
|
tglDepthMask(TGL_TRUE);
|
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
|
|
|
tglEnable(TGL_LIGHTING);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2012-05-05 18:03:04 -07:00
|
|
|
void GfxTinyGL::drawLine(const PrimitiveObject *primitive) {
|
2016-07-11 00:09:39 +00:00
|
|
|
float x1 = primitive->getP1().x * _scaleW;
|
|
|
|
float y1 = primitive->getP1().y * _scaleH;
|
|
|
|
float x2 = primitive->getP2().x * _scaleW;
|
|
|
|
float y2 = primitive->getP2().y * _scaleH;
|
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
|
|
|
|
2016-07-11 00:09:39 +00:00
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglLoadIdentity();
|
|
|
|
tglOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglLoadIdentity();
|
|
|
|
|
|
|
|
tglDisable(TGL_LIGHTING);
|
|
|
|
tglDisable(TGL_DEPTH_TEST);
|
|
|
|
tglDepthMask(TGL_FALSE);
|
|
|
|
|
|
|
|
tglColor3ub(color.getRed(), color.getGreen(), color.getBlue());
|
|
|
|
|
|
|
|
// tglLineWidth(_scaleW); // Not implemented in TinyGL
|
|
|
|
|
|
|
|
tglBegin(TGL_LINES);
|
|
|
|
tglVertex2f(x1, y1);
|
|
|
|
tglVertex2f(x2, y2);
|
|
|
|
tglEnd();
|
|
|
|
|
|
|
|
tglColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
|
|
|
|
tglDepthMask(TGL_TRUE);
|
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
|
|
|
tglEnable(TGL_LIGHTING);
|
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) {
|
2016-07-11 00:09:39 +00:00
|
|
|
float x1 = primitive->getP1().x * _scaleW;
|
|
|
|
float y1 = primitive->getP1().y * _scaleH;
|
|
|
|
float x2 = primitive->getP2().x * _scaleW;
|
|
|
|
float y2 = primitive->getP2().y * _scaleH;
|
|
|
|
float x3 = primitive->getP3().x * _scaleW;
|
|
|
|
float y3 = primitive->getP3().y * _scaleH;
|
|
|
|
float x4 = primitive->getP4().x * _scaleW;
|
|
|
|
float y4 = primitive->getP4().y * _scaleH;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2012-01-27 11:47:28 -08:00
|
|
|
const Color &color = primitive->getColor();
|
2016-07-11 00:09:39 +00:00
|
|
|
|
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglLoadIdentity();
|
|
|
|
tglOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglLoadIdentity();
|
|
|
|
|
|
|
|
tglDisable(TGL_LIGHTING);
|
|
|
|
tglDisable(TGL_DEPTH_TEST);
|
|
|
|
tglDepthMask(TGL_FALSE);
|
|
|
|
|
|
|
|
tglColor3ub(color.getRed(), color.getGreen(), color.getBlue());
|
|
|
|
|
|
|
|
tglBegin(TGL_LINES);
|
|
|
|
tglVertex2f(x1, y1);
|
|
|
|
tglVertex2f(x2 + 1, y2 + 1);
|
|
|
|
tglVertex2f(x3, y3 + 1);
|
|
|
|
tglVertex2f(x4 + 1, y4);
|
|
|
|
tglEnd();
|
|
|
|
|
|
|
|
tglColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
|
|
|
|
tglDepthMask(TGL_TRUE);
|
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
|
|
|
tglEnable(TGL_LIGHTING);
|
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
|