2006-04-02 14:20:45 +00:00
|
|
|
/* Residual - Virtual machine to run LucasArts' 3D adventure games
|
|
|
|
* Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
2005-01-12 18:06:43 +00:00
|
|
|
|
2008-01-26 11:47:23 +00:00
|
|
|
#include "common/debug.h"
|
2005-01-12 18:06:43 +00:00
|
|
|
|
2008-01-26 11:47:23 +00:00
|
|
|
#include "engine/colormap.h"
|
|
|
|
#include "engine/material.h"
|
|
|
|
#include "engine/backend/sdl/driver_tinygl.h"
|
|
|
|
|
|
|
|
#include "engine/tinygl/gl.h"
|
|
|
|
#include "engine/tinygl/zgl.h"
|
2005-01-12 18:06:43 +00:00
|
|
|
|
|
|
|
// func below is from Mesa glu sources
|
|
|
|
static void lookAt(TGLfloat eyex, TGLfloat eyey, TGLfloat eyez, TGLfloat centerx,
|
|
|
|
TGLfloat centery, TGLfloat centerz, TGLfloat upx, TGLfloat upy, TGLfloat upz) {
|
|
|
|
TGLfloat m[16];
|
|
|
|
TGLfloat x[3], y[3], z[3];
|
|
|
|
TGLfloat mag;
|
|
|
|
|
|
|
|
z[0] = eyex - centerx;
|
|
|
|
z[1] = eyey - centery;
|
|
|
|
z[2] = eyez - centerz;
|
|
|
|
mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
|
|
|
|
if (mag) {
|
|
|
|
z[0] /= mag;
|
|
|
|
z[1] /= mag;
|
|
|
|
z[2] /= mag;
|
|
|
|
}
|
|
|
|
|
|
|
|
y[0] = upx;
|
|
|
|
y[1] = upy;
|
|
|
|
y[2] = upz;
|
|
|
|
|
|
|
|
x[0] = y[1] * z[2] - y[2] * z[1];
|
|
|
|
x[1] = -y[0] * z[2] + y[2] * z[0];
|
|
|
|
x[2] = y[0] * z[1] - y[1] * z[0];
|
|
|
|
|
|
|
|
y[0] = z[1] * x[2] - z[2] * x[1];
|
|
|
|
y[1] = -z[0] * x[2] + z[2] * x[0];
|
|
|
|
y[2] = z[0] * x[1] - z[1] * x[0];
|
|
|
|
|
|
|
|
mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
|
|
|
|
if (mag) {
|
|
|
|
x[0] /= mag;
|
|
|
|
x[1] /= mag;
|
|
|
|
x[2] /= mag;
|
|
|
|
}
|
|
|
|
|
|
|
|
mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
|
|
|
|
if (mag) {
|
|
|
|
y[0] /= mag;
|
|
|
|
y[1] /= mag;
|
|
|
|
y[2] /= mag;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define M(row,col) m[col * 4 + row]
|
|
|
|
M(0, 0) = x[0];
|
|
|
|
M(0, 1) = x[1];
|
|
|
|
M(0, 2) = x[2];
|
|
|
|
M(0, 3) = 0.0;
|
|
|
|
M(1, 0) = y[0];
|
|
|
|
M(1, 1) = y[1];
|
|
|
|
M(1, 2) = y[2];
|
|
|
|
M(1, 3) = 0.0;
|
|
|
|
M(2, 0) = z[0];
|
|
|
|
M(2, 1) = z[1];
|
|
|
|
M(2, 2) = z[2];
|
|
|
|
M(2, 3) = 0.0;
|
|
|
|
M(3, 0) = 0.0;
|
|
|
|
M(3, 1) = 0.0;
|
|
|
|
M(3, 2) = 0.0;
|
|
|
|
M(3, 3) = 1.0;
|
|
|
|
#undef M
|
|
|
|
tglMultMatrixf(m);
|
|
|
|
|
|
|
|
tglTranslatef(-eyex, -eyey, -eyez);
|
|
|
|
}
|
|
|
|
|
2005-03-28 01:54:21 +00:00
|
|
|
DriverTinyGL::DriverTinyGL(int screenW, int screenH, int screenBPP, bool fullscreen) {
|
2005-04-08 09:33:21 +00:00
|
|
|
uint32 flags = SDL_HWSURFACE;
|
2005-08-10 14:45:23 +00:00
|
|
|
|
2005-03-28 01:54:21 +00:00
|
|
|
if (fullscreen)
|
|
|
|
flags |= SDL_FULLSCREEN;
|
|
|
|
_screen = SDL_SetVideoMode(screenW, screenH, screenBPP, flags);
|
2005-01-12 18:06:43 +00:00
|
|
|
if (_screen == NULL)
|
|
|
|
error("Could not initialize video");
|
2005-08-10 14:45:23 +00:00
|
|
|
|
2005-03-28 01:54:21 +00:00
|
|
|
_screenWidth = screenW;
|
|
|
|
_screenHeight = screenH;
|
|
|
|
_screenBPP = screenBPP;
|
|
|
|
_isFullscreen = fullscreen;
|
2005-01-12 18:06:43 +00:00
|
|
|
|
2005-08-13 16:25:51 +00:00
|
|
|
SDL_WM_SetCaption("Residual: Software 3D Renderer", "Residual");
|
2005-01-12 18:06:43 +00:00
|
|
|
|
2006-05-16 10:02:27 +00:00
|
|
|
_zb = ZB_open(screenW, screenH, ZB_MODE_5R6G5B, _screen->pixels);
|
2005-01-12 18:06:43 +00:00
|
|
|
tglInit(_zb);
|
2005-08-13 11:33:12 +00:00
|
|
|
|
2005-08-13 20:14:46 +00:00
|
|
|
_storedDisplay = new byte[640 * 480 * 2];
|
|
|
|
memset(_storedDisplay, 0, 640 * 480 * 2);
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DriverTinyGL::~DriverTinyGL() {
|
2005-08-13 20:14:46 +00:00
|
|
|
delete []_storedDisplay;
|
2005-01-12 18:06:43 +00:00
|
|
|
tglClose();
|
|
|
|
ZB_close(_zb);
|
|
|
|
}
|
|
|
|
|
2005-03-28 01:54:21 +00:00
|
|
|
void DriverTinyGL::toggleFullscreenMode() {
|
2007-12-26 23:16:13 +00:00
|
|
|
// We used to use SDL_WM_ToggleFullScreen() to switch to fullscreen
|
|
|
|
// mode, but since that was deemed too buggy for ScummVM it's probably
|
|
|
|
// too buggy for Residual as well.
|
|
|
|
|
|
|
|
if (_screen)
|
|
|
|
SDL_FreeSurface(_screen);
|
|
|
|
|
|
|
|
uint32 flags = SDL_HWSURFACE;
|
|
|
|
if (!_isFullscreen)
|
|
|
|
flags |= SDL_FULLSCREEN;
|
|
|
|
|
|
|
|
_screen = SDL_SetVideoMode(_screenWidth, _screenHeight, _screenBPP, flags);
|
|
|
|
if (_screen == NULL)
|
|
|
|
error("Could not change fullscreen mode");
|
2005-03-28 01:54:21 +00:00
|
|
|
|
2007-12-26 23:16:13 +00:00
|
|
|
_isFullscreen = !_isFullscreen;
|
2005-03-28 01:54:21 +00:00
|
|
|
}
|
|
|
|
|
2005-01-12 18:06:43 +00:00
|
|
|
void DriverTinyGL::setupCamera(float fov, float nclip, float fclip, float roll) {
|
|
|
|
tglMatrixMode(TGL_PROJECTION);
|
|
|
|
tglLoadIdentity();
|
|
|
|
|
|
|
|
float right = nclip * std::tan(fov / 2 * (M_PI / 180));
|
|
|
|
tglFrustum(-right, right, -right * 0.75, right * 0.75, nclip, fclip);
|
|
|
|
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglLoadIdentity();
|
|
|
|
|
|
|
|
tglRotatef(roll, 0, 0, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::positionCamera(Vector3d pos, Vector3d interest) {
|
|
|
|
Vector3d up_vec(0, 0, 1);
|
|
|
|
|
|
|
|
if (pos.x() == interest.x() && pos.y() == interest.y())
|
|
|
|
up_vec = Vector3d(0, 1, 0);
|
|
|
|
|
|
|
|
lookAt(pos.x(), pos.y(), pos.z(), interest.x(), interest.y(), interest.z(), up_vec.x(), up_vec.y(), up_vec.z());
|
2005-08-10 14:45:23 +00:00
|
|
|
}
|
2005-01-12 18:06:43 +00:00
|
|
|
|
|
|
|
void DriverTinyGL::clearScreen() {
|
2005-08-10 14:45:23 +00:00
|
|
|
memset(_zb->pbuf, 0, 640 * 480 * 2);
|
|
|
|
memset(_zb->zbuf, 0, 640 * 480 * 2);
|
2006-05-16 07:28:47 +00:00
|
|
|
memset(_zb->zbuf2, 0, 640 * 480 * 4);
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::flipBuffer() {
|
|
|
|
SDL_Flip(_screen);
|
|
|
|
}
|
|
|
|
|
2005-04-07 20:06:27 +00:00
|
|
|
bool DriverTinyGL::isHardwareAccelerated() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-01-12 18:06:43 +00:00
|
|
|
void DriverTinyGL::startActorDraw(Vector3d pos, float yaw, float pitch, float roll) {
|
|
|
|
tglEnable(TGL_TEXTURE_2D);
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglPushMatrix();
|
|
|
|
tglTranslatef(pos.x(), pos.y(), pos.z());
|
|
|
|
tglRotatef(yaw, 0, 0, 1);
|
|
|
|
tglRotatef(pitch, 1, 0, 0);
|
|
|
|
tglRotatef(roll, 0, 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::finishActorDraw() {
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglPopMatrix();
|
|
|
|
tglDisable(TGL_TEXTURE_2D);
|
2007-03-12 21:50:44 +00:00
|
|
|
|
|
|
|
/* // enable to draw shadow planes (Special Sectors)
|
|
|
|
int k, r;
|
|
|
|
if (!_currentShadowArray)
|
|
|
|
return;
|
|
|
|
|
|
|
|
tglColor3f(0.8,0.8,0.8);
|
|
|
|
for (r = 0; r < 5; r++) {
|
|
|
|
_currentShadowArray[r].planeList.begin();
|
|
|
|
for (SectorListType::iterator i = _currentShadowArray[r].planeList.begin(); i != _currentShadowArray[r].planeList.end(); i++) {
|
|
|
|
Sector *shadowSector = *i;
|
|
|
|
tglBegin(TGL_POLYGON);
|
|
|
|
tglNormal3f(shadowSector->getNormal().x(), shadowSector->getNormal().y(), shadowSector->getNormal().z());
|
|
|
|
for (k = 0; k < shadowSector->getNumVertices(); k++) {
|
|
|
|
tglVertex3f(shadowSector->getVertices()[k].x(), shadowSector->getVertices()[k].y(), shadowSector->getVertices()[k].z());
|
|
|
|
}
|
|
|
|
tglEnd();
|
|
|
|
}
|
|
|
|
}*/
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::set3DMode() {
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglEnable(TGL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
|
2007-03-12 21:50:44 +00:00
|
|
|
void DriverTinyGL::setupShadower(Shadow *shadow) {
|
|
|
|
_currentShadowArray = shadow;
|
|
|
|
}
|
|
|
|
|
2005-01-12 18:06:43 +00:00
|
|
|
void DriverTinyGL::drawModelFace(const Model::Face *face, float *vertices, float *vertNormals, float *textureVerts) {
|
|
|
|
tglNormal3fv((float *)face->_normal._coords);
|
|
|
|
tglBegin(TGL_POLYGON);
|
|
|
|
for (int i = 0; i < face->_numVertices; i++) {
|
|
|
|
tglNormal3fv(vertNormals + 3 * face->_vertices[i]);
|
|
|
|
|
|
|
|
if (face->_texVertices != NULL)
|
|
|
|
tglTexCoord2fv(textureVerts + 2 * face->_texVertices[i]);
|
|
|
|
|
|
|
|
tglVertex3fv(vertices + 3 * face->_vertices[i]);
|
|
|
|
}
|
|
|
|
tglEnd();
|
|
|
|
}
|
|
|
|
|
2006-01-05 02:40:26 +00:00
|
|
|
void DriverTinyGL::translateViewpoint(Vector3d pos, float pitch, float yaw, float roll) {
|
|
|
|
tglPushMatrix();
|
2005-01-12 18:06:43 +00:00
|
|
|
|
2006-01-05 02:40:26 +00:00
|
|
|
tglTranslatef(pos.x(), pos.y(), pos.z());
|
|
|
|
tglRotatef(yaw, 0, 0, 1);
|
|
|
|
tglRotatef(pitch, 1, 0, 0);
|
|
|
|
tglRotatef(roll, 0, 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::translateViewpoint() {
|
|
|
|
tglPopMatrix();
|
|
|
|
}
|
2005-01-12 18:06:43 +00:00
|
|
|
|
2006-01-05 02:40:26 +00:00
|
|
|
void DriverTinyGL::drawHierachyNode(const Model::HierNode *node) {
|
|
|
|
translateViewpoint(node->_animPos / node->_totalWeight, node->_animPitch / node->_totalWeight, node->_animYaw / node->_totalWeight, node->_animRoll / node->_totalWeight);
|
|
|
|
if (node->_hierVisible) {
|
2005-01-12 18:06:43 +00:00
|
|
|
if (node->_mesh != NULL && node->_meshVisible) {
|
|
|
|
tglPushMatrix();
|
|
|
|
tglTranslatef(node->_pivot.x(), node->_pivot.y(), node->_pivot.z());
|
|
|
|
node->_mesh->draw();
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglPopMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->_child != NULL) {
|
|
|
|
node->_child->draw();
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
}
|
|
|
|
}
|
2006-01-05 02:40:26 +00:00
|
|
|
translateViewpoint();
|
2005-01-12 18:06:43 +00:00
|
|
|
|
|
|
|
if (node->_sibling != NULL)
|
|
|
|
node->_sibling->draw();
|
|
|
|
}
|
|
|
|
|
2005-01-18 17:25:04 +00:00
|
|
|
void DriverTinyGL::disableLights() {
|
|
|
|
tglDisable(TGL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::setupLight(Scene::Light *light, int lightId) {
|
2006-02-05 16:14:19 +00:00
|
|
|
assert(lightId < TGL_MAX_LIGHTS);
|
2005-01-18 17:25:04 +00:00
|
|
|
tglEnable(TGL_LIGHTING);
|
2006-05-16 19:04:09 +00:00
|
|
|
float ambientLight[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
|
|
float lightColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
|
|
float lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
2005-01-18 17:25:04 +00:00
|
|
|
float lightDir[] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
2006-05-16 19:04:09 +00:00
|
|
|
|
2005-01-18 17:25:04 +00:00
|
|
|
lightPos[0] = light->_pos.x();
|
|
|
|
lightPos[1] = light->_pos.y();
|
|
|
|
lightPos[2] = light->_pos.z();
|
2006-05-16 19:04:09 +00:00
|
|
|
// lightColor[0] = (float)light->_color.red() / 256.0f;
|
|
|
|
// lightColor[1] = (float)light->_color.blue() / 256.0f;
|
|
|
|
// lightColor[2] = (float)light->_color.green() / 256.0f;
|
2005-01-18 17:25:04 +00:00
|
|
|
|
|
|
|
if (strcmp(light->_type.c_str(), "omni") == 0) {
|
2006-05-16 19:04:09 +00:00
|
|
|
ambientLight[0] = (float)light->_color.red() / 256.0f;
|
|
|
|
ambientLight[1] = (float)light->_color.blue() / 256.0f;
|
|
|
|
ambientLight[2] = (float)light->_color.green() / 256.0f;
|
|
|
|
lightColor[0] = light->_intensity / 2;
|
|
|
|
lightColor[1] = light->_intensity / 2;
|
|
|
|
lightColor[2] = light->_intensity / 2;
|
|
|
|
tglDisable(TGL_LIGHT0 + lightId);
|
2005-01-18 17:25:04 +00:00
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_POSITION, lightPos);
|
2006-05-16 19:04:09 +00:00
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_DIFFUSE, lightColor);
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_AMBIENT, ambientLight);
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_SPECULAR, lightColor);
|
2005-01-18 17:25:04 +00:00
|
|
|
tglEnable(TGL_LIGHT0 + lightId);
|
|
|
|
} else if (strcmp(light->_type.c_str(), "direct") == 0) {
|
2006-05-16 19:04:09 +00:00
|
|
|
tglDisable(TGL_LIGHT0 + lightId);
|
|
|
|
ambientLight[0] = (float)light->_color.red() / 256.0f;
|
|
|
|
ambientLight[1] = (float)light->_color.blue() / 256.0f;
|
|
|
|
ambientLight[2] = (float)light->_color.green() / 256.0f;
|
|
|
|
lightColor[0] = light->_intensity;
|
|
|
|
lightColor[1] = light->_intensity;
|
|
|
|
lightColor[2] = light->_intensity;
|
2005-01-18 17:25:04 +00:00
|
|
|
lightDir[0] = light->_dir.x();
|
|
|
|
lightDir[1] = light->_dir.y();
|
|
|
|
lightDir[2] = light->_dir.z();
|
2006-05-16 19:04:09 +00:00
|
|
|
// tglLightfv(TGL_LIGHT0 + lightId, TGL_POSITION, lightPos);
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_DIFFUSE, lightColor);
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_AMBIENT, ambientLight);
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_SPECULAR, lightColor);
|
2005-01-18 17:25:04 +00:00
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_SPOT_DIRECTION, lightDir);
|
2006-05-16 19:04:09 +00:00
|
|
|
// tglLightf(TGL_LIGHT0 + lightId, TGL_CONSTANT_ATTENUATION, 0.0f);
|
|
|
|
// tglLightf(TGL_LIGHT0 + lightId, TGL_LINEAR_ATTENUATION, 0.0f);
|
|
|
|
// tglLightf(TGL_LIGHT0 + lightId, TGL_QUADRATIC_ATTENUATION, 1.0f);
|
2005-01-19 09:24:40 +00:00
|
|
|
tglEnable(TGL_LIGHT0 + lightId);
|
2005-01-26 19:25:29 +00:00
|
|
|
} else if (strcmp(light->_type.c_str(), "spot") == 0) {
|
2006-05-16 19:04:09 +00:00
|
|
|
tglDisable(TGL_LIGHT0 + lightId);
|
|
|
|
lightColor[0] = (float)light->_color.red() / 256.0f;
|
|
|
|
lightColor[1] = (float)light->_color.blue() / 256.0f;
|
|
|
|
lightColor[2] = (float)light->_color.green() / 256.0f;
|
2005-01-19 09:24:40 +00:00
|
|
|
lightDir[0] = light->_dir.x();
|
|
|
|
lightDir[1] = light->_dir.y();
|
|
|
|
lightDir[2] = light->_dir.z();
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_POSITION, lightPos);
|
2006-05-16 19:04:09 +00:00
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_DIFFUSE, lightColor);
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_AMBIENT, ambientLight);
|
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_SPECULAR, lightColor);
|
2005-01-19 09:24:40 +00:00
|
|
|
tglLightfv(TGL_LIGHT0 + lightId, TGL_SPOT_DIRECTION, lightDir);
|
2006-05-16 19:04:09 +00:00
|
|
|
tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_EXPONENT, 64.0f * light->_intensity);
|
|
|
|
tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_CUTOFF, 90.0f);
|
|
|
|
tglLightf(TGL_LIGHT0 + lightId, TGL_CONSTANT_ATTENUATION, 0.0f);
|
|
|
|
tglLightf(TGL_LIGHT0 + lightId, TGL_LINEAR_ATTENUATION, 0.0f);
|
|
|
|
tglLightf(TGL_LIGHT0 + lightId, TGL_QUADRATIC_ATTENUATION, 1.0f);
|
2005-01-18 17:25:04 +00:00
|
|
|
tglEnable(TGL_LIGHT0 + lightId);
|
|
|
|
} else {
|
2005-03-06 15:28:45 +00:00
|
|
|
error("Scene::setupLights() Unknown type of light: %s", light->_type.c_str());
|
2005-01-18 17:25:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-12 18:06:43 +00:00
|
|
|
void DriverTinyGL::createBitmap(Bitmap *bitmap) {
|
2005-08-13 11:33:12 +00:00
|
|
|
if (bitmap->_format != 1) {
|
2005-01-12 18:06:43 +00:00
|
|
|
for (int pic = 0; pic < bitmap->_numImages; pic++) {
|
2005-08-13 11:33:12 +00:00
|
|
|
uint16 *bufPtr = reinterpret_cast<uint16 *>(bitmap->_data[pic]);
|
2005-01-12 18:06:43 +00:00
|
|
|
for (int i = 0; i < (bitmap->_width * bitmap->_height); i++) {
|
|
|
|
uint16 val = READ_LE_UINT16(bitmap->_data[pic] + 2 * i);
|
2005-08-13 11:33:12 +00:00
|
|
|
bufPtr[i] = ((uint32) val) * 0x10000 / 100 / (0x10000 - val);
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-10 14:45:23 +00:00
|
|
|
void TinyGLBlit(byte *dst, byte *src, int x, int y, int width, int height, bool trans) {
|
|
|
|
int srcPitch = width * 2;
|
|
|
|
int dstPitch = 640 * 2;
|
|
|
|
int srcX, srcY;
|
|
|
|
int l, r;
|
2005-01-12 18:06:43 +00:00
|
|
|
|
2005-08-11 13:49:49 +00:00
|
|
|
if (x > 639 || y > 479)
|
|
|
|
return;
|
|
|
|
|
2005-08-10 14:45:23 +00:00
|
|
|
if (x < 0) {
|
|
|
|
x = 0;
|
|
|
|
srcX = -x;
|
|
|
|
} else {
|
|
|
|
srcX = 0;
|
|
|
|
}
|
|
|
|
if (y < 0) {
|
|
|
|
y = 0;
|
|
|
|
srcY = -y;
|
2005-01-12 18:06:43 +00:00
|
|
|
} else {
|
2005-08-10 14:45:23 +00:00
|
|
|
srcY = 0;
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
2005-08-10 14:45:23 +00:00
|
|
|
|
2008-01-10 23:03:49 +00:00
|
|
|
if (x + width > 640)
|
|
|
|
width -= (x + width) - 640;
|
2005-08-10 14:45:23 +00:00
|
|
|
|
2008-01-10 23:03:49 +00:00
|
|
|
if (y + height > 480)
|
|
|
|
height -= (y + height) - 480;
|
2005-08-10 14:45:23 +00:00
|
|
|
|
|
|
|
dst += (x + (y * 640)) * 2;
|
|
|
|
src += (srcX + (srcY * width)) * 2;
|
|
|
|
|
|
|
|
int copyWidth = width * 2;
|
|
|
|
|
|
|
|
if (!trans) {
|
|
|
|
for (l = 0; l < height; l++) {
|
|
|
|
memcpy(dst, src, copyWidth);
|
|
|
|
dst += dstPitch;
|
|
|
|
src += srcPitch;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (l = 0; l < height; l++) {
|
2005-08-11 13:49:49 +00:00
|
|
|
for (r = 0; r < copyWidth; r += 2) {
|
2005-08-10 14:45:23 +00:00
|
|
|
uint16 pixel = READ_LE_UINT16(src + r);
|
|
|
|
if (pixel != 0xf81f)
|
|
|
|
WRITE_LE_UINT16(dst + r, pixel);
|
|
|
|
}
|
|
|
|
dst += dstPitch;
|
|
|
|
src += srcPitch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::drawBitmap(const Bitmap *bitmap) {
|
|
|
|
assert(bitmap->_currImage > 0);
|
|
|
|
if (bitmap->_format == 1)
|
|
|
|
TinyGLBlit((byte *)_zb->pbuf, (byte *)bitmap->_data[bitmap->_currImage - 1],
|
|
|
|
bitmap->x(), bitmap->y(), bitmap->width(), bitmap->height(), true);
|
|
|
|
else
|
|
|
|
TinyGLBlit((byte *)_zb->zbuf, (byte *)bitmap->_data[bitmap->_currImage - 1],
|
|
|
|
bitmap->x(), bitmap->y(), bitmap->width(), bitmap->height(), false);
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
|
|
|
|
2005-01-12 23:28:47 +00:00
|
|
|
void DriverTinyGL::destroyBitmap(Bitmap *) { }
|
|
|
|
|
|
|
|
void DriverTinyGL::drawDepthBitmap(int, int, int, int, char *) { }
|
2005-01-12 18:06:43 +00:00
|
|
|
|
|
|
|
void DriverTinyGL::createMaterial(Material *material, const char *data, const CMap *cmap) {
|
|
|
|
material->_textures = new TGLuint[material->_numImages];
|
|
|
|
tglGenTextures(material->_numImages, (TGLuint *)material->_textures);
|
|
|
|
char *texdata = new char[material->_width * material->_height * 4];
|
|
|
|
for (int i = 0; i < material->_numImages; i++) {
|
|
|
|
char *texdatapos = texdata;
|
|
|
|
for (int y = 0; y < material->_height; y++) {
|
|
|
|
for (int x = 0; x < material->_width; x++) {
|
|
|
|
int col = *(uint8 *)(data);
|
|
|
|
if (col == 0)
|
|
|
|
memset(texdatapos, 0, 3); // transparent
|
|
|
|
else {
|
|
|
|
memcpy(texdatapos, cmap->_colors + 3 * (*(uint8 *)(data)), 3);
|
|
|
|
}
|
|
|
|
texdatapos += 3;
|
|
|
|
data++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TGLuint *textures = (TGLuint *)material->_textures;
|
|
|
|
tglBindTexture(TGL_TEXTURE_2D, textures[i]);
|
|
|
|
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_WRAP_S, TGL_REPEAT);
|
|
|
|
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_WRAP_T, TGL_REPEAT);
|
|
|
|
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MAG_FILTER, TGL_LINEAR);
|
|
|
|
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MIN_FILTER, TGL_LINEAR);
|
|
|
|
tglTexImage2D(TGL_TEXTURE_2D, 0, 3, material->_width, material->_height, 0, TGL_RGB, TGL_UNSIGNED_BYTE, texdata);
|
|
|
|
data += 24;
|
|
|
|
}
|
|
|
|
delete[] texdata;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::selectMaterial(const Material *material) {
|
|
|
|
TGLuint *textures = (TGLuint *)material->_textures;
|
|
|
|
tglBindTexture(TGL_TEXTURE_2D, textures[material->_currImage]);
|
|
|
|
tglPushMatrix();
|
|
|
|
tglMatrixMode(TGL_TEXTURE);
|
|
|
|
tglLoadIdentity();
|
|
|
|
tglScalef(1.0f / material->_width, 1.0f / material->_height, 1);
|
|
|
|
tglMatrixMode(TGL_MODELVIEW);
|
|
|
|
tglPopMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::destroyMaterial(Material *material) {
|
|
|
|
tglDeleteTextures(material->_numImages, (TGLuint *)material->_textures);
|
2005-01-12 23:28:47 +00:00
|
|
|
delete[] (TGLuint *)material->_textures;
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::prepareSmushFrame(int width, int height, byte *bitmap) {
|
|
|
|
_smushWidth = width;
|
|
|
|
_smushHeight = height;
|
2005-08-10 14:45:23 +00:00
|
|
|
_smushBitmap = bitmap;
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::drawSmushFrame(int offsetX, int offsetY) {
|
2005-08-10 14:45:23 +00:00
|
|
|
if (_smushWidth == 640 && _smushHeight == 480) {
|
|
|
|
memcpy(_zb->pbuf, _smushBitmap, 640 * 480 * 2);
|
|
|
|
} else {
|
2005-08-11 13:49:49 +00:00
|
|
|
TinyGLBlit((byte *)_zb->pbuf, _smushBitmap, offsetX, offsetY, _smushWidth, _smushHeight, false);
|
2005-08-10 14:45:23 +00:00
|
|
|
}
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::loadEmergFont() {
|
|
|
|
}
|
|
|
|
|
2005-01-12 23:28:47 +00:00
|
|
|
void DriverTinyGL::drawEmergString(int /*x*/, int /*y*/, const char * /*text*/, const Color &/*fgColor*/) {
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
2005-03-19 21:48:23 +00:00
|
|
|
|
2005-03-20 14:03:08 +00:00
|
|
|
Driver::TextObjectHandle *DriverTinyGL::createTextBitmap(uint8 *data, int width, int height, const Color &fgColor) {
|
2005-03-20 18:43:56 +00:00
|
|
|
TextObjectHandle *handle = new TextObjectHandle;
|
2005-03-19 21:48:23 +00:00
|
|
|
handle->width = width;
|
|
|
|
handle->height = height;
|
|
|
|
handle->numTex = 0;
|
|
|
|
handle->texIds = NULL;
|
|
|
|
|
|
|
|
// Convert data to 16-bit RGB 565 format
|
|
|
|
uint16 *texData = new uint16[width * height];
|
|
|
|
uint16 *texDataPtr = texData;
|
|
|
|
handle->bitmapData = texData;
|
|
|
|
uint8 *bitmapData = data;
|
2005-04-05 04:33:56 +00:00
|
|
|
uint8 r = fgColor.red();
|
|
|
|
uint8 g = fgColor.green();
|
|
|
|
uint8 b = fgColor.blue();
|
|
|
|
|
2005-03-19 21:48:23 +00:00
|
|
|
for (int i = 0; i < width * height; i++, texDataPtr++, bitmapData++) {
|
|
|
|
byte pixel = *bitmapData;
|
|
|
|
if (pixel == 0x00) {
|
|
|
|
WRITE_LE_UINT16(texDataPtr, 0xf81f);
|
|
|
|
} else if (pixel == 0x80) {
|
|
|
|
*texDataPtr = 0;
|
|
|
|
} else if (pixel == 0xFF) {
|
2005-04-05 04:33:56 +00:00
|
|
|
WRITE_LE_UINT16(texDataPtr, ((r & 0xF8) << 8) |
|
|
|
|
((g & 0xFC) << 3) | (b >> 3));
|
2005-03-19 21:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::drawTextBitmap(int x, int y, TextObjectHandle *handle) {
|
2005-08-10 14:45:23 +00:00
|
|
|
TinyGLBlit((byte *)_zb->pbuf, (byte *)handle->bitmapData, x, y, handle->width, handle->height, true);
|
2005-03-19 21:48:23 +00:00
|
|
|
}
|
2005-03-20 13:51:40 +00:00
|
|
|
|
|
|
|
void DriverTinyGL::destroyTextBitmap(TextObjectHandle *handle) {
|
2005-08-10 05:30:58 +00:00
|
|
|
delete[] handle->bitmapData;
|
2005-03-20 13:51:40 +00:00
|
|
|
}
|
2005-04-07 07:04:36 +00:00
|
|
|
|
2005-04-08 18:29:13 +00:00
|
|
|
Bitmap *DriverTinyGL::getScreenshot(int w, int h) {
|
|
|
|
uint16 *buffer = new uint16[w * h];
|
2005-08-14 14:30:18 +00:00
|
|
|
uint16 *src = (uint16 *)_storedDisplay;
|
2005-04-08 18:29:13 +00:00
|
|
|
assert(buffer);
|
|
|
|
|
|
|
|
int step = 0;
|
2006-05-14 07:51:41 +00:00
|
|
|
for (int y = 0; y <= 479; y++) {
|
|
|
|
for (int x = 0; x <= 639; x++) {
|
|
|
|
uint16 pixel = *(src + y * 640 + x);
|
2005-08-28 23:25:14 +00:00
|
|
|
uint8 r = (pixel & 0xF800) >> 8;
|
|
|
|
uint8 g = (pixel & 0x07E0) >> 3;
|
|
|
|
uint8 b = (pixel & 0x001F) << 3;
|
|
|
|
uint32 color = (r + g + b) / 3;
|
2006-05-14 07:51:41 +00:00
|
|
|
src[step++] = ((color & 0xF8) << 8) | ((color & 0xFC) << 3) | (color >> 3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float step_x = 640.0 / w;
|
|
|
|
float step_y = 480.0 / h;
|
|
|
|
step = 0;
|
|
|
|
for (float y = 0; y < 479; y += step_y) {
|
|
|
|
for (float x = 0; x < 639; x += step_x) {
|
|
|
|
uint16 pixel = *(src + (int)y * 640 + (int)x);
|
|
|
|
buffer[step++] = pixel;
|
2005-04-08 18:29:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Bitmap *screenshot = new Bitmap((char *)buffer, w, h, "screenshot");
|
|
|
|
delete []buffer;
|
|
|
|
return screenshot;
|
2005-04-07 07:04:36 +00:00
|
|
|
}
|
|
|
|
|
2005-08-13 11:33:12 +00:00
|
|
|
void DriverTinyGL::storeDisplay() {
|
|
|
|
memcpy(_storedDisplay, _zb->pbuf, 640 * 480 * 2);
|
|
|
|
}
|
|
|
|
|
2005-08-13 20:14:46 +00:00
|
|
|
void DriverTinyGL::copyStoredToDisplay() {
|
|
|
|
memcpy(_zb->pbuf, _storedDisplay, 640 * 480 * 2);
|
2005-08-13 11:33:12 +00:00
|
|
|
}
|
|
|
|
|
2005-08-28 23:25:14 +00:00
|
|
|
void DriverTinyGL::dimScreen() {
|
|
|
|
uint16 *data = (uint16 *)_storedDisplay;
|
|
|
|
for (int l = 0; l < 640 * 480; l++) {
|
|
|
|
uint16 pixel = data[l];
|
|
|
|
uint8 r = (pixel & 0xF800) >> 8;
|
|
|
|
uint8 g = (pixel & 0x07E0) >> 3;
|
|
|
|
uint8 b = (pixel & 0x001F) << 3;
|
2007-01-29 21:21:21 +00:00
|
|
|
uint32 color = (r + g + b) / 10;
|
2005-08-28 23:25:14 +00:00
|
|
|
data[l] = ((color & 0xF8) << 8) | ((color & 0xFC) << 3) | (color >> 3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::dimRegion(int x, int y, int w, int h, float level) {
|
|
|
|
uint16 *data = (uint16 *)_zb->pbuf;
|
|
|
|
for (int ly = y; ly < y + h; ly++) {
|
|
|
|
for (int lx = x; lx < x + w; lx++) {
|
|
|
|
uint16 pixel = data[ly * 640 + lx];
|
|
|
|
uint8 r = (pixel & 0xF800) >> 8;
|
|
|
|
uint8 g = (pixel & 0x07E0) >> 3;
|
|
|
|
uint8 b = (pixel & 0x001F) << 3;
|
|
|
|
uint16 color = (uint16)(((r + g + b) / 3) * level);
|
|
|
|
data[ly * 640 + lx] = ((color & 0xF8) << 8) | ((color & 0xFC) << 3) | (color >> 3);
|
|
|
|
}
|
|
|
|
}
|
2005-04-07 07:04:36 +00:00
|
|
|
}
|
2005-04-07 19:29:06 +00:00
|
|
|
|
|
|
|
void DriverTinyGL::drawRectangle(PrimitiveObject *primitive) {
|
2005-08-10 14:45:23 +00:00
|
|
|
uint16 *dst = (uint16 *)_zb->pbuf;
|
2005-04-07 19:29:06 +00:00
|
|
|
int x1 = primitive->getX1();
|
|
|
|
int x2 = primitive->getX2();
|
|
|
|
int y1 = primitive->getY1();
|
|
|
|
int y2 = primitive->getY2();
|
|
|
|
|
|
|
|
Color color = primitive->getColor();
|
|
|
|
uint16 c = ((color.red() & 0xF8) << 8) | ((color.green() & 0xFC) << 3) | (color.blue() >> 3);
|
|
|
|
|
|
|
|
if (primitive->isFilled()) {
|
2005-04-09 05:03:39 +00:00
|
|
|
for (; y1 <= y2; y1++) {
|
|
|
|
for (int x = x1; x <= x2; x++) {
|
2005-04-07 19:29:06 +00:00
|
|
|
WRITE_LE_UINT16(dst + 640 * y1 + x, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2005-04-09 05:03:39 +00:00
|
|
|
for (int x = x1; x <= x2; x++) {
|
2005-04-07 19:29:06 +00:00
|
|
|
WRITE_LE_UINT16(dst + 640 * y1 + x, c);
|
|
|
|
}
|
2005-04-09 05:03:39 +00:00
|
|
|
for (int x = x1; x <= x2; x++) {
|
2005-04-07 19:29:06 +00:00
|
|
|
WRITE_LE_UINT16(dst + 640 * y2 + x, c);
|
|
|
|
}
|
2005-04-09 05:03:39 +00:00
|
|
|
for (int y = y1; y <= y2; y++) {
|
2005-04-07 19:29:06 +00:00
|
|
|
WRITE_LE_UINT16(dst + 640 * y + x1, c);
|
|
|
|
}
|
2005-04-09 05:03:39 +00:00
|
|
|
for (int y = y1; y <= y2; y++) {
|
2005-04-07 19:29:06 +00:00
|
|
|
WRITE_LE_UINT16(dst + 640 * y + x2, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-05-05 21:23:17 +00:00
|
|
|
|
|
|
|
void DriverTinyGL::drawLine(PrimitiveObject *primitive) {
|
2005-08-10 14:45:23 +00:00
|
|
|
uint16 *dst = (uint16 *)_zb->pbuf;
|
2005-05-05 21:23:17 +00:00
|
|
|
int x1 = primitive->getX1();
|
|
|
|
int x2 = primitive->getX2();
|
|
|
|
int y1 = primitive->getY1();
|
|
|
|
int y2 = primitive->getY2();
|
|
|
|
float m = (y2 - y1) / (x2 - x1);
|
2005-08-10 08:33:45 +00:00
|
|
|
int b = (int)(-m * x1 + y1);
|
2005-05-05 21:23:17 +00:00
|
|
|
|
|
|
|
Color color = primitive->getColor();
|
|
|
|
uint16 c = ((color.red() & 0xF8) << 8) | ((color.green() & 0xFC) << 3) | (color.blue() >> 3);
|
|
|
|
|
|
|
|
for (int x = x1; x <= x2; x++) {
|
2007-01-30 12:38:26 +00:00
|
|
|
int y = (int)(m * x) + b;
|
|
|
|
WRITE_LE_UINT16(dst + 640 * y + x, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DriverTinyGL::drawPolygon(PrimitiveObject *primitive) {
|
|
|
|
uint16 *dst = (uint16 *)_zb->pbuf;
|
|
|
|
int x1 = primitive->getX1();
|
|
|
|
int y1 = primitive->getY1();
|
|
|
|
int x2 = primitive->getX2();
|
|
|
|
int y2 = primitive->getY2();
|
|
|
|
int x3 = primitive->getX3();
|
|
|
|
int y3 = primitive->getY3();
|
|
|
|
int x4 = primitive->getX4();
|
|
|
|
int y4 = primitive->getY4();
|
|
|
|
float m;
|
|
|
|
int b;
|
|
|
|
|
|
|
|
Color color = primitive->getColor();
|
|
|
|
uint16 c = ((color.red() & 0xF8) << 8) | ((color.green() & 0xFC) << 3) | (color.blue() >> 3);
|
|
|
|
|
|
|
|
m = (y2 - y1) / (x2 - x1);
|
|
|
|
b = (int)(-m * x1 + y1);
|
|
|
|
for (int x = x1; x <= x2; x++) {
|
|
|
|
int y = (int)(m * x) + b;
|
|
|
|
WRITE_LE_UINT16(dst + 640 * y + x, c);
|
|
|
|
}
|
|
|
|
m = (y4 - y3) / (x4 - x3);
|
|
|
|
b = (int)(-m * x3 + y3);
|
|
|
|
for (int x = x3; x <= x4; x++) {
|
|
|
|
int y = (int)(m * x) + b;
|
2005-05-05 21:23:17 +00:00
|
|
|
WRITE_LE_UINT16(dst + 640 * y + x, c);
|
|
|
|
}
|
|
|
|
}
|