From d0380d3ea3bf1ae2f8236d5b71858795eab8870c Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Mon, 25 Jan 2010 17:42:19 +0100 Subject: [PATCH] First step towards graphics abstraction and added a TinyGL driver. --- gfx/driver.cpp | 51 ++ gfx_base.h => gfx/driver.h | 54 +- gfx_opengl.cpp => gfx/opengl.cpp | 71 ++- gfx_opengl.h => gfx/opengl.h | 27 +- gfx/tinygl.cpp | 928 +++++++++++++++++++++++++++++++ gfx/tinygl.h | 119 ++++ module.mk | 4 +- stark.cpp | 36 +- stark.h | 7 +- 9 files changed, 1181 insertions(+), 116 deletions(-) create mode 100644 gfx/driver.cpp rename gfx_base.h => gfx/driver.h (82%) rename gfx_opengl.cpp => gfx/opengl.cpp (80%) rename gfx_opengl.h => gfx/opengl.h (86%) create mode 100644 gfx/tinygl.cpp create mode 100644 gfx/tinygl.h diff --git a/gfx/driver.cpp b/gfx/driver.cpp new file mode 100644 index 00000000000..8fed122a48b --- /dev/null +++ b/gfx/driver.cpp @@ -0,0 +1,51 @@ +/* Residual - A 3D game interpreter + * + * Residual is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the AUTHORS + * file distributed with this source distribution. + * + * 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$ + * + */ + +#include "engines/stark/gfx/driver.h" +#include "engines/stark/gfx/opengl.h" +#include "engines/stark/gfx/tinygl.h" + +namespace Stark { + +GfxDriver *GfxDriver::create() { + GfxDriver *driver = NULL; + +#ifdef USE_OPENGL + // OpenGL + driver = new OpenGLGfxDriver(); + if (driver) + return driver; +#endif // USE_OPENGL + + // TinyGL + driver = new TinyGLGfxDriver(); + if (driver) + return driver; + + error("Couldn't instance any graphics driver"); + return NULL; +} + +} // End of namespace Stark diff --git a/gfx_base.h b/gfx/driver.h similarity index 82% rename from gfx_base.h rename to gfx/driver.h index 9b52fb92d28..4b5498612b7 100644 --- a/gfx_base.h +++ b/gfx/driver.h @@ -23,49 +23,41 @@ * */ -#ifndef STARK_GFX_BASE_H -#define STARK_GFX_BASE_H +#ifndef STARK_GFX_DRIVER_H +#define STARK_GFX_DRIVER_H -#include "engines/stark/color.h" +//#include "engines/stark/color.h" #include "graphics/surface.h" -#include "graphics/vector3d.h" +//#include "graphics/vector3d.h" namespace Stark { -struct Shadow; - -class GfxBase { +class GfxDriver { public: - GfxBase() { } - virtual ~GfxBase() { } + static GfxDriver *create(); - struct TextObjectHandle { - uint16 *bitmapData; - void *surface; - int numTex; - void *texIds; - int width; - int height; - }; + virtual ~GfxDriver() {} - virtual byte *setupScreen(int screenW, int screenH, bool fullscreen) = 0; + virtual const char *getVideoDeviceName() = 0; - virtual bool isHardwareAccelerated() = 0; - - virtual void setupCamera(float fov, float nclip, float fclip, float roll) = 0; - virtual void positionCamera(Graphics::Vector3d pos, Graphics::Vector3d interest) = 0; + virtual void setupScreen(int screenW, int screenH, bool fullscreen) = 0; virtual void clearScreen() = 0; virtual void flipBuffer() = 0; + virtual void drawSurface(Graphics::Surface *surface) = 0; + + /* + virtual bool isHardwareAccelerated() = 0; + virtual void set3DMode() = 0; + virtual void setupCamera(float fov, float nclip, float fclip, float roll) = 0; + virtual void positionCamera(Graphics::Vector3d pos, Graphics::Vector3d interest) = 0; + virtual void translateViewpointStart(Graphics::Vector3d pos, float pitch, float yaw, float roll) = 0; virtual void translateViewpointFinish() = 0; - virtual void drawSurface(Graphics::Surface* surface) = 0; - -/* virtual void disableLights() = 0; virtual void setupLight(Scene::Light *light, int lightId) = 0; @@ -84,24 +76,20 @@ public: virtual void copyStoredToDisplay() = 0; virtual void dimScreen() = 0; virtual void dimRegion(int x, int y, int w, int h, float level) = 0; -*/ -/* virtual void drawRectangle(PrimitiveObject *primitive) = 0; + + virtual void drawRectangle(PrimitiveObject *primitive) = 0; virtual void drawLine(PrimitiveObject *primitive) = 0; virtual void drawPolygon(PrimitiveObject *primitive) = 0; virtual void prepareSmushFrame(int width, int height, byte *bitmap) = 0; virtual void drawSmushFrame(int offsetX, int offsetY) = 0; virtual void releaseSmushFrame() = 0; -*/ - virtual const char *getVideoDeviceName() = 0; + */ protected: int _screenWidth, _screenHeight, _screenBPP; - bool _isFullscreen; }; -extern GfxBase *g_driver; - } // End of namespace Stark -#endif // STARK_GFX_BASE_H +#endif // STARK_GFX_DRIVER_H diff --git a/gfx_opengl.cpp b/gfx/opengl.cpp similarity index 80% rename from gfx_opengl.cpp rename to gfx/opengl.cpp index 2ec3c9fc3e3..26fb73ea099 100644 --- a/gfx_opengl.cpp +++ b/gfx/opengl.cpp @@ -23,55 +23,66 @@ * */ -#include "engines/stark/gfx_opengl.h" +#ifdef USE_OPENGL + +#include "engines/stark/gfx/opengl.h" #include "common/system.h" -#ifdef USE_OPENGL - #ifdef SDL_BACKEND #include #else #include -#include +//#include #endif namespace Stark { -GfxOpenGL::GfxOpenGL() { - _storedDisplay = NULL; +OpenGLGfxDriver::OpenGLGfxDriver() { } -GfxOpenGL::~GfxOpenGL() { - delete[] _storedDisplay; +OpenGLGfxDriver::~OpenGLGfxDriver() { } -byte *GfxOpenGL::setupScreen(int screenW, int screenH, bool fullscreen) { +const char *OpenGLGfxDriver::getVideoDeviceName() { + return "OpenGL Renderer"; +} + +void OpenGLGfxDriver::setupScreen(int screenW, int screenH, bool fullscreen) { g_system->setupScreen(screenW, screenH, fullscreen, true); _screenWidth = screenW; _screenHeight = screenH; _screenBPP = 24; + /* _isFullscreen = g_system->getFeatureState(OSystem::kFeatureFullscreenMode); char GLDriver[1024]; sprintf(GLDriver, "Residual: %s/%s", glGetString(GL_VENDOR), glGetString(GL_RENDERER)); g_system->setWindowCaption(GLDriver); - _storedDisplay = new byte[_screenWidth * _screenHeight * 4]; - memset(_storedDisplay, 0, _screenWidth * _screenHeight * 4); - GLfloat ambientSource[] = { 0.6f, 0.6f, 0.6f, 1.0f }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientSource); - - return NULL; + */ } -const char *GfxOpenGL::getVideoDeviceName() { - return "OpenGL Renderer"; +void OpenGLGfxDriver::clearScreen() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void GfxOpenGL::setupCamera(float fov, float nclip, float fclip, float roll) { +void OpenGLGfxDriver::flipBuffer() { + g_system->updateScreen(); +} + +void OpenGLGfxDriver::drawSurface(Graphics::Surface *surface) { + glPixelZoom(1.0f, -1.0f); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glRasterPos2f(-1.0f, 0.75f); + glDrawPixels(surface->w, surface->h, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels); +} + +/* +void OpenGLGfxDriver::setupCamera(float fov, float nclip, float fclip, float roll) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -84,7 +95,7 @@ void GfxOpenGL::setupCamera(float fov, float nclip, float fclip, float roll) { glRotatef(roll, 0, 0, -1); } -void GfxOpenGL::positionCamera(Graphics::Vector3d pos, Graphics::Vector3d interest) { +void OpenGLGfxDriver::positionCamera(Graphics::Vector3d pos, Graphics::Vector3d interest) { Graphics::Vector3d up_vec(0, 0, 1); if (pos.x() == interest.x() && pos.y() == interest.y()) @@ -93,15 +104,7 @@ void GfxOpenGL::positionCamera(Graphics::Vector3d pos, Graphics::Vector3d intere gluLookAt(pos.x(), pos.y(), pos.z(), interest.x(), interest.y(), interest.z(), up_vec.x(), up_vec.y(), up_vec.z()); } -void GfxOpenGL::clearScreen() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -void GfxOpenGL::flipBuffer() { - g_system->updateScreen(); -} - -bool GfxOpenGL::isHardwareAccelerated() { +bool OpenGLGfxDriver::isHardwareAccelerated() { return true; } @@ -154,13 +157,13 @@ static void glShadowProjection(Graphics::Vector3d light, Graphics::Vector3d plan glMultMatrixf((GLfloat *)mat); } -void GfxOpenGL::set3DMode() { +void OpenGLGfxDriver::set3DMode() { glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); } -void GfxOpenGL::translateViewpointStart(Graphics::Vector3d pos, float pitch, float yaw, float roll) { +void OpenGLGfxDriver::translateViewpointStart(Graphics::Vector3d pos, float pitch, float yaw, float roll) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -170,16 +173,10 @@ void GfxOpenGL::translateViewpointStart(Graphics::Vector3d pos, float pitch, flo glRotatef(roll, 0, 1, 0); } -void GfxOpenGL::translateViewpointFinish() { +void OpenGLGfxDriver::translateViewpointFinish() { glPopMatrix(); } - -void GfxOpenGL::drawSurface(Graphics::Surface* surface) { - glPixelZoom(1.0f, -1.0f); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glRasterPos2f(-1.0f, 0.75f); - glDrawPixels(surface->w, surface->h, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels); -} +*/ } // End of namespace Stark diff --git a/gfx_opengl.h b/gfx/opengl.h similarity index 86% rename from gfx_opengl.h rename to gfx/opengl.h index 1f9774b9cc3..d999ede8695 100644 --- a/gfx_opengl.h +++ b/gfx/opengl.h @@ -26,38 +26,37 @@ #ifndef STARK_GFX_OPENGL_H #define STARK_GFX_OPENGL_H -#include "engines/stark/gfx_base.h" - #ifdef USE_OPENGL +#include "engines/stark/gfx/driver.h" + namespace Stark { -class GfxOpenGL : public GfxBase { +class OpenGLGfxDriver : public GfxDriver { public: - GfxOpenGL(); - virtual ~GfxOpenGL(); - - byte *setupScreen(int screenW, int screenH, bool fullscreen); + OpenGLGfxDriver(); + ~OpenGLGfxDriver(); const char *getVideoDeviceName(); - void setupCamera(float fov, float nclip, float fclip, float roll); - void positionCamera(Graphics::Vector3d pos, Graphics::Vector3d interest); + void setupScreen(int screenW, int screenH, bool fullscreen); void clearScreen(); void flipBuffer(); + void drawSurface(Graphics::Surface *surface); + +/* bool isHardwareAccelerated(); void set3DMode(); + void setupCamera(float fov, float nclip, float fclip, float roll); + void positionCamera(Graphics::Vector3d pos, Graphics::Vector3d interest); + void translateViewpointStart(Graphics::Vector3d pos, float pitch, float yaw, float roll); void translateViewpointFinish(); - - void drawSurface(Graphics::Surface *bmp); - -private: - byte *_storedDisplay; +*/ }; } // End of namespace Stark diff --git a/gfx/tinygl.cpp b/gfx/tinygl.cpp new file mode 100644 index 00000000000..33f649086c3 --- /dev/null +++ b/gfx/tinygl.cpp @@ -0,0 +1,928 @@ +/* Residual - A 3D game interpreter + * + * Residual is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the AUTHORS + * file distributed with this source distribution. + * + * 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: https://residual.svn.sourceforge.net/svnroot/residual/residual/trunk/engines/grim/gfx_tinygl.cpp $ + * $Id: gfx_tinygl.cpp 1499 2009-06-26 16:13:11Z aquadran $ + * + */ + +//#include "common/endian.h" +#include "common/system.h" + +//#include "engines/stark/actor.h" +//#include "engines/stark/colormap.h" +//#include "engines/stark/material.h" +//#include "engines/stark/font.h" +#include "engines/stark/gfx/tinygl.h" + +namespace Stark { + +TinyGLGfxDriver::TinyGLGfxDriver() { + _zb = NULL; + //_storedDisplay = NULL; +} + +TinyGLGfxDriver::~TinyGLGfxDriver() { + //delete[] _storedDisplay; + if (_zb) { + TinyGL::glClose(); + ZB_close(_zb); + } +} + +const char *TinyGLGfxDriver::getVideoDeviceName() { + return "TinyGL Software Renderer"; +} + +void TinyGLGfxDriver::setupScreen(int screenW, int screenH, bool fullscreen) { + byte *buffer = g_system->setupScreen(screenW, screenH, fullscreen, false); + + _screenWidth = screenW; + _screenHeight = screenH; + _screenBPP = 15; + //_isFullscreen = g_system->getFeatureState(OSystem::kFeatureFullscreenMode); + + //g_system->setWindowCaption("Residual: Software 3D Renderer"); + + _zb = TinyGL::ZB_open(screenW, screenH, ZB_MODE_5R6G5B, buffer); + TinyGL::glInit(_zb); + + /* + //_storedDisplay = new byte[640 * 480 * 2]; + //memset(_storedDisplay, 0, 640 * 480 * 2); + + _currentShadowArray = NULL; + + TGLfloat ambientSource[] = { 0.6f, 0.6f, 0.6f, 1.0f }; + tglLightModelfv(TGL_LIGHT_MODEL_AMBIENT, ambientSource); + + return buffer; + */ +} + +void TinyGLGfxDriver::clearScreen() { + memset(_zb->pbuf, 0, 640 * 480 * 2); + memset(_zb->zbuf, 0, 640 * 480 * 2); + memset(_zb->zbuf2, 0, 640 * 480 * 4); +} + +void TinyGLGfxDriver::flipBuffer() { + g_system->updateScreen(); +} + +void TinyGLGfxDriver::drawSurface(Graphics::Surface *surface) { + for (int i = 0; i < surface->w * surface->h; i++) { + byte *pixel = (byte *)surface->pixels + (i * 3); + byte r = pixel[0]; + byte g = pixel[1]; + byte b = pixel[2]; + uint16 color = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); + _zb->pbuf[i] = color; + } + + //memcpy(_zb->pbuf, surface->pixels, numPixels); +} + + +#if 0 + +// below funcs lookAt, transformPoint and tgluProject are 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); +} + +static void transformPoint(TGLfloat out[4], const TGLfloat m[16], const TGLfloat in[4]) { +#define M(row,col) m[col * 4 + row] + out[0] = M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3]; + out[1] = M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3]; + out[2] = M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3]; + out[3] = M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3]; +#undef M +} + +TGLint tgluProject(TGLfloat objx, TGLfloat objy, TGLfloat objz, const TGLfloat model[16], const TGLfloat proj[16], + const TGLint viewport[4], TGLfloat *winx, TGLfloat *winy, TGLfloat *winz) { + TGLfloat in[4], out[4]; + + in[0] = objx; + in[1] = objy; + in[2] = objz; + in[3] = 1.0; + transformPoint(out, model, in); + transformPoint(in, proj, out); + + if (in[3] == 0.0) + return TGL_FALSE; + + in[0] /= in[3]; + in[1] /= in[3]; + in[2] /= in[3]; + + *winx = viewport[0] + (1 + in[0]) * viewport[2] / 2; + *winy = viewport[1] + (1 + in[1]) * viewport[3] / 2; + *winz = (1 + in[2]) / 2; + + return TGL_TRUE; +} + +void TinyGLGfxDriver::setupCamera(float fov, float nclip, float fclip, float roll) { + tglMatrixMode(TGL_PROJECTION); + tglLoadIdentity(); + + float right = nclip * tan(fov / 2 * (LOCAL_PI / 180)); + tglFrustum(-right, right, -right * 0.75, right * 0.75, nclip, fclip); + + tglMatrixMode(TGL_MODELVIEW); + tglLoadIdentity(); + + tglRotatef(roll, 0, 0, -1); +} + +void TinyGLGfxDriver::positionCamera(Graphics::Vector3d pos, Graphics::Vector3d interest) { + Graphics::Vector3d up_vec(0, 0, 1); + + if (pos.x() == interest.x() && pos.y() == interest.y()) + up_vec = Graphics::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()); +} + +bool TinyGLGfxDriver::isHardwareAccelerated() { + return false; +} + +static void tglShadowProjection(Graphics::Vector3d light, Graphics::Vector3d plane, Graphics::Vector3d normal, bool dontNegate) { + // Based on GPL shadow projection example by + // (c) 2002-2003 Phaetos + float d, c; + float mat[16]; + float nx, ny, nz, lx, ly, lz, px, py, pz; + + // for some unknown for me reason normal need negation + nx = -normal.x(); + ny = -normal.y(); + nz = -normal.z(); + if (dontNegate) { + 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); +} + +void TinyGLGfxDriver::getBoundingBoxPos(const Model::Mesh *model, int *x1, int *y1, int *x2, int *y2) { + if (_currentShadowArray) { + *x1 = -1; + *y1 = -1; + *x2 = -1; + *y2 = -1; + return; + } + + TGLfloat top = 1000; + TGLfloat right = -1000; + TGLfloat left = 1000; + TGLfloat bottom = -1000; + TGLfloat winX, winY, winZ; + + for (int i = 0; i < model->_numFaces; i++) { + Graphics::Vector3d v; + float* pVertices; + + for (int j = 0; j < model->_faces[i]._numVertices; j++) { + TGLfloat modelView[16], projection[16]; + TGLint viewPort[4]; + + tglGetFloatv(TGL_MODELVIEW_MATRIX, modelView); + tglGetFloatv(TGL_PROJECTION_MATRIX, projection); + tglGetIntegerv(TGL_VIEWPORT, viewPort); + + pVertices = model->_vertices + 3 * model->_faces[i]._vertices[j]; + + v.set(*(pVertices), *(pVertices + 1), *(pVertices + 2)); + + tgluProject(v.x(), v.y(), v.z(), modelView, projection, viewPort, &winX, &winY, &winZ); + + if (winX > right) + right = winX; + if (winX < left) + left = winX; + if (winY < top) + top = winY; + if (winY > bottom) + bottom = winY; + } + } + + float t = bottom; + bottom = 480 - top; + top = 480 - t; + + if (left < 0) + left = 0; + if (right > 639) + right = 639; + if (top < 0) + top = 0; + if (bottom > 479) + bottom = 479; + + if (top > 479 || left > 639 || bottom < 0 || right < 0) { + *x1 = -1; + *y1 = -1; + *x2 = -1; + *y2 = -1; + return; + } + + *x1 = (int)left; + *y1 = (int)top; + *x2 = (int)right; + *y2 = (int)bottom; +/* + uint16 *dst = (uint16 *)_zb->pbuf; + uint16 c = 0xffff; + for (int x = left; x <= right; x++) { + WRITE_LE_UINT16(dst + 640 * (int)top + x, c); + } + for (int x = left; x <= right; x++) { + WRITE_LE_UINT16(dst + 640 * (int)bottom + x, c); + } + for (int y = top; y <= bottom; y++) { + WRITE_LE_UINT16(dst + 640 * y + (int)left, c); + } + for (int y = top; y <= bottom; y++) { + WRITE_LE_UINT16(dst + 640 * y + (int)right, c); + }*/ +} + +void TinyGLGfxDriver::startActorDraw(Graphics::Vector3d pos, float yaw, float pitch, float roll) { + tglEnable(TGL_TEXTURE_2D); + tglMatrixMode(TGL_MODELVIEW); + tglPushMatrix(); + if (_currentShadowArray) { + // TODO find out why shadowMask at device in woods is null + if (!_currentShadowArray->shadowMask) { + _currentShadowArray->shadowMask = new byte[_screenWidth * _screenHeight]; + } + assert(_currentShadowArray->shadowMask); + //tglSetShadowColor(255, 255, 255); + tglSetShadowColor(_shadowColorR, _shadowColorG, _shadowColorB); + tglSetShadowMaskBuf(_currentShadowArray->shadowMask); + SectorListType::iterator i = _currentShadowArray->planeList.begin(); + Sector *shadowSector = *i; + tglShadowProjection(_currentShadowArray->pos, shadowSector->getVertices()[0], shadowSector->getNormal(), _currentShadowArray->dontNegate); + } + + tglTranslatef(pos.x(), pos.y(), pos.z()); + tglRotatef(yaw, 0, 0, 1); + tglRotatef(pitch, 1, 0, 0); + tglRotatef(roll, 0, 1, 0); +} + +void TinyGLGfxDriver::finishActorDraw() { + tglMatrixMode(TGL_MODELVIEW); + tglPopMatrix(); + tglDisable(TGL_TEXTURE_2D); + + if (_currentShadowArray) { + tglSetShadowMaskBuf(NULL); + }/* else { + uint16 *dst = (uint16 *)_zb->pbuf; + uint16 c = 0xffff; + for (int x = g_winX1; x <= g_winX2; x++) { + WRITE_LE_UINT16(dst + 640 * g_winY1 + x, c); + } + for (int x = g_winX1; x <= g_winX2; x++) { + WRITE_LE_UINT16(dst + 640 * g_winY2 + x, c); + } + for (int y = g_winY1; y <= g_winY2; y++) { + WRITE_LE_UINT16(dst + 640 * y + g_winX1, c); + } + for (int y = g_winY1; y <= g_winY2; y++) { + WRITE_LE_UINT16(dst + 640 * y + g_winX2, c); + } + }*/ +} + +void TinyGLGfxDriver::drawShadowPlanes() { + tglEnable(TGL_SHADOW_MASK_MODE); + if (!_currentShadowArray->shadowMask) { + _currentShadowArray->shadowMask = new byte[_screenWidth * _screenHeight]; + } + memset(_currentShadowArray->shadowMask, 0, _screenWidth * _screenHeight); + + tglSetShadowMaskBuf(_currentShadowArray->shadowMask); + _currentShadowArray->planeList.begin(); + for (SectorListType::iterator i = _currentShadowArray->planeList.begin(); i != _currentShadowArray->planeList.end(); i++) { + Sector *shadowSector = *i; + 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(); + } + tglSetShadowMaskBuf(NULL); + tglDisable(TGL_SHADOW_MASK_MODE); +} + +void TinyGLGfxDriver::setShadowMode() { + tglEnable(TGL_SHADOW_MODE); +} + +void TinyGLGfxDriver::clearShadowMode() { + tglDisable(TGL_SHADOW_MODE); +} + +void TinyGLGfxDriver::set3DMode() { + tglMatrixMode(TGL_MODELVIEW); + tglEnable(TGL_DEPTH_TEST); +} + +void TinyGLGfxDriver::setShadow(Shadow *shadow) { + _currentShadowArray = shadow; + if (shadow) + tglDisable(TGL_LIGHTING); + else + tglEnable(TGL_LIGHTING); +} + +void TinyGLGfxDriver::setShadowColor(byte r, byte g, byte b) { + _shadowColorR = r; + _shadowColorG = g; + _shadowColorB = b; +} + +void TinyGLGfxDriver::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) + tglTexCoord2fv(textureVerts + 2 * face->_texVertices[i]); + + tglVertex3fv(vertices + 3 * face->_vertices[i]); + } + tglEnd(); +} + +void TinyGLGfxDriver::translateViewpointStart(Graphics::Vector3d pos, float pitch, float yaw, float roll) { + tglPushMatrix(); + + tglTranslatef(pos.x(), pos.y(), pos.z()); + tglRotatef(yaw, 0, 0, 1); + tglRotatef(pitch, 1, 0, 0); + tglRotatef(roll, 0, 1, 0); +} + +void TinyGLGfxDriver::translateViewpointFinish() { + tglPopMatrix(); +} + +void TinyGLGfxDriver::drawHierachyNode(const Model::HierNode *node) { + translateViewpointStart(node->_animPos / node->_totalWeight, node->_animPitch / node->_totalWeight, node->_animYaw / node->_totalWeight, node->_animRoll / node->_totalWeight); + if (node->_hierVisible) { + if (node->_mesh && node->_meshVisible) { + tglPushMatrix(); + tglTranslatef(node->_pivot.x(), node->_pivot.y(), node->_pivot.z()); + node->_mesh->draw(); + tglMatrixMode(TGL_MODELVIEW); + tglPopMatrix(); + } + + if (node->_child) { + node->_child->draw(); + tglMatrixMode(TGL_MODELVIEW); + } + } + translateViewpointFinish(); + + if (node->_sibling) + node->_sibling->draw(); +} + +void TinyGLGfxDriver::disableLights() { + tglDisable(TGL_LIGHTING); +} + +void TinyGLGfxDriver::setupLight(Scene::Light *light, int lightId) { + 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 }; + float lightDir[] = { 0.0f, 0.0f, 0.0f }; + + float intensity = light->_intensity / 1.3f; + lightColor[0] = ((float)light->_color.red() / 15.0f) * intensity; + lightColor[1] = ((float)light->_color.blue() / 15.0f) * intensity; + lightColor[2] = ((float)light->_color.green() / 15.0f) * intensity; + + if (strcmp(light->_type.c_str(), "omni") == 0) { + lightPos[0] = light->_pos.x(); + lightPos[1] = light->_pos.y(); + lightPos[2] = light->_pos.z(); + tglDisable(TGL_LIGHT0 + lightId); + tglLightfv(TGL_LIGHT0 + lightId, TGL_DIFFUSE, lightColor); + tglLightfv(TGL_LIGHT0 + lightId, TGL_POSITION, lightPos); + tglEnable(TGL_LIGHT0 + lightId); + } else if (strcmp(light->_type.c_str(), "direct") == 0) { + tglDisable(TGL_LIGHT0 + lightId); + lightDir[0] = -light->_dir.x(); + lightDir[1] = -light->_dir.y(); + lightDir[2] = -light->_dir.z(); + tglLightfv(TGL_LIGHT0 + lightId, TGL_DIFFUSE, lightColor); + tglLightfv(TGL_LIGHT0 + lightId, TGL_POSITION, lightDir); + tglEnable(TGL_LIGHT0 + lightId); + } else if (strcmp(light->_type.c_str(), "spot") == 0) { + tglDisable(TGL_LIGHT0 + lightId); + 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(); + tglLightfv(TGL_LIGHT0 + lightId, TGL_DIFFUSE, lightColor); + tglLightfv(TGL_LIGHT0 + lightId, TGL_POSITION, lightPos); + tglLightfv(TGL_LIGHT0 + lightId, TGL_SPOT_DIRECTION, lightDir); + tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_CUTOFF, 90); + tglEnable(TGL_LIGHT0 + lightId); + } else { + error("Scene::setupLights() Unknown type of light: %s", light->_type.c_str()); + } +} + +void TinyGLGfxDriver::createBitmap(Bitmap *bitmap) { + if (bitmap->_format != 1) { + for (int pic = 0; pic < bitmap->_numImages; pic++) { + uint16 *bufPtr = reinterpret_cast(bitmap->_data[pic]); + for (int i = 0; i < (bitmap->_width * bitmap->_height); i++) { + uint16 val = READ_LE_UINT16(bitmap->_data[pic] + 2 * i); + bufPtr[i] = ((uint32) val) * 0x10000 / 100 / (0x10000 - val); + } + } + } +} + +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; + + if (x > 639 || y > 479) + return; + + if (x < 0) { + x = 0; + srcX = -x; + } else { + srcX = 0; + } + if (y < 0) { + y = 0; + srcY = -y; + } else { + srcY = 0; + } + + if (x + width > 640) + width -= (x + width) - 640; + + if (y + height > 480) + height -= (y + height) - 480; + + 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++) { + for (r = 0; r < copyWidth; r += 2) { + uint16 pixel = READ_LE_UINT16(src + r); + if (pixel != 0xf81f) + WRITE_LE_UINT16(dst + r, pixel); + } + dst += dstPitch; + src += srcPitch; + } + } +} + +void TinyGLGfxDriver::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); +} + +void TinyGLGfxDriver::destroyBitmap(Bitmap *) { } + +void TinyGLGfxDriver::drawDepthBitmap(int, int, int, int, char *) { } + +void TinyGLGfxDriver::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, 4); // transparent + else { + memcpy(texdatapos, cmap->_colors + 3 * (*(uint8 *)(data)), 3); + texdatapos[3] = '\xff'; // fully opaque + } + texdatapos += 4; + 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_RGBA, TGL_UNSIGNED_BYTE, texdata); + data += 24; + } + delete[] texdata; +} + +void TinyGLGfxDriver::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 TinyGLGfxDriver::destroyMaterial(Material *material) { + tglDeleteTextures(material->_numImages, (TGLuint *)material->_textures); + delete[] (TGLuint *)material->_textures; +} + +void TinyGLGfxDriver::prepareSmushFrame(int width, int height, byte *bitmap) { + _smushWidth = width; + _smushHeight = height; + _smushBitmap = bitmap; +} + +void TinyGLGfxDriver::drawSmushFrame(int offsetX, int offsetY) { + if (_smushWidth == 640 && _smushHeight == 480) { + memcpy(_zb->pbuf, _smushBitmap, 640 * 480 * 2); + } else { + TinyGLBlit((byte *)_zb->pbuf, _smushBitmap, offsetX, offsetY, _smushWidth, _smushHeight, false); + } +} + +void TinyGLGfxDriver::releaseSmushFrame() { +} + +void TinyGLGfxDriver::loadEmergFont() { +} + +void TinyGLGfxDriver::drawEmergString(int x, int y, const char *text, const Color &fgColor) { + uint16 color = ((fgColor.red() & 0xF8) << 8) | ((fgColor.green() & 0xFC) << 3) | (fgColor.blue() >> 3); + + for (int l = 0; l < (int)strlen(text); l++) { + int c = text[l]; + assert(c >= 32 && c <= 127); + const uint8 *ptr = Font::emerFont[c - 32]; + for (int py = 0; py < 13; py++) { + if ((py + y) < 480 && (py + y) >= 0) { + int line = ptr[12 - py]; + for (int px = 0; px < 8; px++) { + if ((px + x) < 640 && (px + x) >= 0) { + int pixel = line & 0x80; + line <<= 1; + if (pixel) + WRITE_LE_UINT16(_zb->pbuf + ((py + y) * 640) + (px + x), color); + } + } + } + } + x += 10; + } +} + +GfxBase::TextObjectHandle *TinyGLGfxDriver::createTextBitmap(uint8 *data, int width, int height, const Color &fgColor) { + TextObjectHandle *handle = new TextObjectHandle; + 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; + uint8 r = fgColor.red(); + uint8 g = fgColor.green(); + uint8 b = fgColor.blue(); + uint16 color = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); + if (color == 0xf81f) + color = 0xf81e; + + 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) { + WRITE_LE_UINT16(texDataPtr, color); + } + } + + return handle; +} + +void TinyGLGfxDriver::drawTextBitmap(int x, int y, TextObjectHandle *handle) { + TinyGLBlit((byte *)_zb->pbuf, (byte *)handle->bitmapData, x, y, handle->width, handle->height, true); +} + +void TinyGLGfxDriver::destroyTextBitmap(TextObjectHandle *handle) { + delete[] handle->bitmapData; +} + +Bitmap *TinyGLGfxDriver::getScreenshot(int w, int h) { + uint16 *buffer = new uint16[w * h]; + //uint16 *src = (uint16 *)_storedDisplay; + assert(buffer); + + int step = 0; + for (int y = 0; y <= 479; y++) { + for (int x = 0; x <= 639; x++) { + uint16 pixel = *(src + y * 640 + x); + uint8 r = (pixel & 0xF800) >> 8; + uint8 g = (pixel & 0x07E0) >> 3; + uint8 b = (pixel & 0x001F) << 3; + uint32 color = (r + g + b) / 3; + 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; + } + } + + Bitmap *screenshot = g_grim->registerBitmap((char *)buffer, w, h, "screenshot"); + delete[] buffer; + return screenshot; +} + +void TinyGLGfxDriver::storeDisplay() { + //memcpy(_storedDisplay, _zb->pbuf, 640 * 480 * 2); +} + +void TinyGLGfxDriver::copyStoredToDisplay() { + //memcpy(_zb->pbuf, _storedDisplay, 640 * 480 * 2); +} + +void TinyGLGfxDriver::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; + uint32 color = (r + g + b) / 10; + data[l] = ((color & 0xF8) << 8) | ((color & 0xFC) << 3) | (color >> 3); + } +} + +void TinyGLGfxDriver::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); + } + } +} + +void TinyGLGfxDriver::drawRectangle(PrimitiveObject *primitive) { + uint16 *dst = (uint16 *)_zb->pbuf; + int x1 = primitive->getP1().x; + int y1 = primitive->getP1().y; + int x2 = primitive->getP2().x; + int y2 = primitive->getP2().y; + + Color color = primitive->getColor(); + uint16 c = ((color.red() & 0xF8) << 8) | ((color.green() & 0xFC) << 3) | (color.blue() >> 3); + + if (primitive->isFilled()) { + for (; y1 <= y2; y1++) + if (y1 >= 0 && y1 < 480) + for (int x = x1; x <= x2; x++) + if (x >= 0 && x < 640) + WRITE_LE_UINT16(dst + 640 * y1 + x, c); + } else { + if (y1 >= 0 && y1 < 480) + for (int x = x1; x <= x2; x++) + if (x >= 0 && x < 640) + WRITE_LE_UINT16(dst + 640 * y1 + x, c); + if (y2 >= 0 && y2 < 480) + for (int x = x1; x <= x2; x++) + if (x >= 0 && x < 640) + WRITE_LE_UINT16(dst + 640 * y2 + x, c); + if (x1 >= 0 && x1 < 640) + for (int y = y1; y <= y2; y++) + if (y >= 0 && y < 480) + WRITE_LE_UINT16(dst + 640 * y + x1, c); + if (x2 >= 0 && x2 < 640) + for (int y = y1; y <= y2; y++) + if (y >= 0 && y < 480) + WRITE_LE_UINT16(dst + 640 * y + x2, c); + } +} + +void TinyGLGfxDriver::drawLine(PrimitiveObject *primitive) { + uint16 *dst = (uint16 *)_zb->pbuf; + int x1 = primitive->getP1().x; + int y1 = primitive->getP1().y; + int x2 = primitive->getP2().x; + int y2 = primitive->getP2().y; + float m = (y2 - y1) / (x2 - x1); + int b = (int)(-m * x1 + y1); + + Color color = primitive->getColor(); + uint16 c = ((color.red() & 0xF8) << 8) | ((color.green() & 0xFC) << 3) | (color.blue() >> 3); + + for (int x = x1; x <= x2; x++) { + int y = (int)(m * x) + b; + if (x >= 0 && x < 640 && y >= 0 && y < 480) + WRITE_LE_UINT16(dst + 640 * y + x, c); + } +} + +void TinyGLGfxDriver::drawPolygon(PrimitiveObject *primitive) { + uint16 *dst = (uint16 *)_zb->pbuf; + int x1 = primitive->getP1().x; + int y1 = primitive->getP1().y; + int x2 = primitive->getP2().x; + int y2 = primitive->getP2().y; + int x3 = primitive->getP3().x; + int y3 = primitive->getP3().y; + int x4 = primitive->getP4().x; + int y4 = primitive->getP4().y; + 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; + if (x >= 0 && x < 640 && y >= 0 && y < 480) + 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; + if (x >= 0 && x < 640 && y >= 0 && y < 480) + WRITE_LE_UINT16(dst + 640 * y + x, c); + } +} + +#endif + +} // End of namespace Stark diff --git a/gfx/tinygl.h b/gfx/tinygl.h new file mode 100644 index 00000000000..132a5f437cd --- /dev/null +++ b/gfx/tinygl.h @@ -0,0 +1,119 @@ +/* Residual - A 3D game interpreter + * + * Residual is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the AUTHORS + * file distributed with this source distribution. + * + * 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: https://residual.svn.sourceforge.net/svnroot/residual/residual/trunk/engines/grim/gfx_tinygl.h $ + * $Id: gfx_tinygl.h 1452 2009-06-08 10:27:20Z aquadran $ + * + */ + +#ifndef STARK_GFX_TINYGL_H +#define STARK_GFX_TINYGL_H + +#include "engines/stark/gfx/driver.h" + +#include "graphics/tinygl/zgl.h" + +namespace Stark { + +class TinyGLGfxDriver : public GfxDriver { +public: + TinyGLGfxDriver(); + ~TinyGLGfxDriver(); + + const char *getVideoDeviceName(); + + void setupScreen(int screenW, int screenH, bool fullscreen); + + void clearScreen(); + void flipBuffer(); + + void drawSurface(Graphics::Surface *surface); + + /* + bool isHardwareAccelerated(); + + void set3DMode(); + + void setupCamera(float fov, float nclip, float fclip, float roll); + void positionCamera(Graphics::Vector3d pos, Graphics::Vector3d interest); + + void translateViewpointStart(Graphics::Vector3d pos, float pitch, float yaw, float roll); + void translateViewpointFinish(); + + void getBoundingBoxPos(const Model::Mesh *model, int *x1, int *y1, int *x2, int *y2); + + void startActorDraw(Graphics::Vector3d pos, float yaw, float pitch, float roll); + void finishActorDraw(); + void setShadow(Shadow *shadow); + void drawShadowPlanes(); + void setShadowMode(); + void clearShadowMode(); + void setShadowColor(byte r, byte g, byte b); + + void drawHierachyNode(const Model::HierNode *node); + void drawModelFace(const Model::Face *face, float *vertices, float *vertNormals, float *textureVerts); + + void disableLights(); + void setupLight(Scene::Light *light, int lightId); + + void createMaterial(Material *material, const char *data, const CMap *cmap); + void selectMaterial(const Material *material); + void destroyMaterial(Material *material); + + void createBitmap(Bitmap *bitmap); + void drawBitmap(const Bitmap *bitmap); + void destroyBitmap(Bitmap *bitmap); + + void drawDepthBitmap(int x, int y, int w, int h, char *data); + void drawBitmap(); + void dimScreen(); + void dimRegion(int x, int y, int w, int h, float level); + + Bitmap *getScreenshot(int w, int h); + void storeDisplay(); + void copyStoredToDisplay(); + + void drawEmergString(int x, int y, const char *text, const Color &fgColor); + void loadEmergFont(); + TextObjectHandle *createTextBitmap(uint8 *bitmap, int width, int height, const Color &fgColor); + void drawTextBitmap(int x, int y, TextObjectHandle *handle); + void destroyTextBitmap(TextObjectHandle *handle); + + void drawRectangle(PrimitiveObject *primitive); + void drawLine(PrimitiveObject *primitive); + void drawPolygon(PrimitiveObject *primitive); + + void prepareSmushFrame(int width, int height, byte *bitmap); + void drawSmushFrame(int offsetX, int offsetY); + void releaseSmushFrame(); + */ + +private: + TinyGL::ZBuffer *_zb; + byte *_screen; + byte *_smushBitmap; + int _smushWidth; + int _smushHeight; + byte *_storedDisplay; +}; + +} // End of namespace Stark + +#endif // STARK_GFX_TINYGL_H diff --git a/module.mk b/module.mk index 7978e642700..1c0a29f62f2 100644 --- a/module.mk +++ b/module.mk @@ -4,7 +4,9 @@ MODULE_OBJS := \ adpcm.o \ archive.o \ detection.o \ - gfx_opengl.o \ + gfx/driver.o \ + gfx/opengl.o \ + gfx/tinygl.o \ sound.o \ stark.o \ xmg.o \ diff --git a/stark.cpp b/stark.cpp index 79878058270..95fd596da49 100644 --- a/stark.cpp +++ b/stark.cpp @@ -24,7 +24,6 @@ */ #include "engines/stark/stark.h" -#include "engines/stark/gfx_opengl.h" #include "engines/stark/xmg.h" #include "common/config-manager.h" @@ -33,9 +32,7 @@ namespace Stark { -GfxBase *g_driver = NULL; - -StarkEngine::StarkEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { +StarkEngine::StarkEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc), _gfx(NULL) { _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, 127); _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); @@ -47,24 +44,10 @@ StarkEngine::~StarkEngine() { } Common::Error StarkEngine::run() { - bool fullscreen = false;//(tolower(g_registry->get("fullscreen", "FALSE")[0]) == 't'); - -//#ifdef USE_OPENGL - //else -//#else - //else -// error("gfx backend doesn't support hardware rendering"); -//#endif - - if (g_system->hasFeature(OSystem::kFeatureOpenGL)) - g_driver = new GfxOpenGL(); - else - error("Only OpenGL hardware rendering at the moment"); + _gfx = GfxDriver::create(); // Get the screen prepared - g_driver->setupScreen(640, 480, fullscreen); - - g_driver->clearScreen(); + _gfx->setupScreen(640, 480, ConfMan.getBool("fullscreen")); // Start running mainLoop(); @@ -97,13 +80,12 @@ void StarkEngine::mainLoop() { } updateDisplayScene(); - doFlip(); g_system->delayMillis(50); } } void StarkEngine::updateDisplayScene() { - g_driver->clearScreen(); + _gfx->clearScreen(); // Draw bg @@ -114,7 +96,7 @@ void StarkEngine::updateDisplayScene() { Common::SeekableReadStream *dat = _f.readStream(_f.size()); Graphics::Surface *surf; surf = xmg->decodeImage(dat); - g_driver->drawSurface(surf); + _gfx->drawSurface(surf); delete xmg; delete surf; delete dat; @@ -123,7 +105,7 @@ void StarkEngine::updateDisplayScene() { // setup cam - g_driver->set3DMode(); + //_gfx->set3DMode(); // setup lights @@ -131,10 +113,8 @@ void StarkEngine::updateDisplayScene() { // draw overlay -} - -void StarkEngine::doFlip() { - g_driver->flipBuffer(); + // Swap buffers + _gfx->flipBuffer(); } } // End of namespace Stark diff --git a/stark.h b/stark.h index 1a76909804b..7c136188e4a 100644 --- a/stark.h +++ b/stark.h @@ -30,6 +30,7 @@ #include "engines/engine.h" #include "engines/stark/archive.h" +#include "engines/stark/gfx/driver.h" namespace Stark { @@ -54,10 +55,10 @@ protected: virtual Common::Error run(); private: - void updateDisplayScene(); - void doFlip(); - void mainLoop(); + void updateDisplayScene(); + + GfxDriver *_gfx; const ADGameDescription *_gameDescription;