diff --git a/dists/msvc7/residual.vcproj b/dists/msvc7/residual.vcproj
index 17c2052b7ad..0e6e88a73f4 100644
--- a/dists/msvc7/residual.vcproj
+++ b/dists/msvc7/residual.vcproj
@@ -578,6 +578,9 @@
+
+
diff --git a/dists/msvc71/residual.vcproj b/dists/msvc71/residual.vcproj
index ea27cf49f6b..d2765349171 100644
--- a/dists/msvc71/residual.vcproj
+++ b/dists/msvc71/residual.vcproj
@@ -592,6 +592,9 @@
+
+
diff --git a/dists/msvc8/residual.vcproj b/dists/msvc8/residual.vcproj
index 8e4107d07da..949d650aff7 100644
--- a/dists/msvc8/residual.vcproj
+++ b/dists/msvc8/residual.vcproj
@@ -810,6 +810,10 @@
RelativePath="..\..\engine\tinygl\ztriangle.h"
>
+
+
+
+
::iterator i = _costumeStack.begin(); i != _costumeStack.end(); i++)
(*i)->setupTextures();
+ if (!g_driver->isHardwareAccelerated()/* && g_engine->getFlagRefreshShadowMask()*/) {
+ for (int l = 0; l < 5; l++) {
+ if (!_shadowArray[l].active)
+ continue;
+ g_driver->setShadow(&_shadowArray[l]);
+ g_driver->drawShadowPlanes();
+ g_driver->setShadow(NULL);
+ }
+ }
+
if (!_costumeStack.empty()) {
- setupDrawShadow();
+ Costume *costume = _costumeStack.back();
+ if (!g_driver->isHardwareAccelerated()) {
+ for (int l = 0; l < 5; l++) {
+ if (!_shadowArray[l].active)
+ continue;
+ g_driver->setShadow(&_shadowArray[l]);
+ g_driver->setShadowMode();
+ g_driver->startActorDraw(_pos, _yaw, _pitch, _roll);
+ costume->draw();
+ g_driver->finishActorDraw();
+ g_driver->setShadow(NULL);
+ g_driver->clearShadowMode();
+ }
+ }
+
+ // normal draw actor
g_driver->startActorDraw(_pos, _yaw, _pitch, _roll);
- _costumeStack.back()->draw();
+ costume->draw();
g_driver->finishActorDraw();
- finishDrawShadow();
}
}
@@ -640,6 +665,20 @@ void Actor::setActiveShadow(int shadowId) {
assert(shadowId >= 0 && shadowId <= 4);
_activeShadowSlot = shadowId;
+ _shadowArray[_activeShadowSlot].active = true;
+}
+
+void Actor::setShadowValid(int valid) {
+/* if (valid == -1)
+ _shadowArray[_activeShadowSlot].active = false;
+ else
+ _shadowArray[_activeShadowSlot].active = true;*/
+}
+
+void Actor::setActivateShadow(int shadowId, bool state) {
+ assert(shadowId >= 0 && shadowId <= 4);
+
+ _shadowArray[shadowId].active = state;
}
void Actor::setShadowPoint(Vector3d pos) {
@@ -654,16 +693,9 @@ void Actor::clearShadowPlanes() {
while (!shadow->planeList.empty()) {
shadow->planeList.pop_back();
}
+ delete[] shadow->shadowMask;
+ shadow->shadowMask = NULL;
+ shadow->active = false;
}
}
-void Actor::setupDrawShadow() {
- if (_activeShadowSlot == -1)
- return;
-
- g_driver->setupShadower(_shadowArray);
-}
-
-void Actor::finishDrawShadow() {
- g_driver->setupShadower(NULL);
-}
diff --git a/engine/actor.h b/engine/actor.h
index 5d2a3a48a1c..f5e6bb6f686 100644
--- a/engine/actor.h
+++ b/engine/actor.h
@@ -46,6 +46,7 @@ struct Shadow {
std::string name;
Vector3d pos;
SectorListType planeList;
+ byte *shadowMask;
bool active;
};
@@ -132,8 +133,8 @@ public:
void setShadowPlane(const char *name);
void addShadowPlane(const char *name);
void clearShadowPlanes();
- void setupDrawShadow();
- void finishDrawShadow();
+ void setShadowValid(int);
+ void setActivateShadow(int, bool);
void setConstrain(bool constrain) {
_constrain = constrain;
diff --git a/engine/backend/driver.h b/engine/backend/driver.h
index fe2ed8cb3e4..06af5b0df9e 100644
--- a/engine/backend/driver.h
+++ b/engine/backend/driver.h
@@ -78,7 +78,11 @@ public:
virtual void startActorDraw(Vector3d pos, float yaw, float pitch, float roll) = 0;
virtual void finishActorDraw() = 0;
- virtual void setupShadower(Shadow *shadow) = 0;
+ virtual void setShadow(Shadow *shadow) = 0;
+ virtual void drawShadowPlanes() = 0;
+ virtual void setShadowMode() = 0;
+ virtual void clearShadowMode() = 0;
+ virtual void setShadowColor(byte r, byte g, byte b) = 0;
virtual void set3DMode() = 0;
@@ -296,6 +300,9 @@ protected:
int _screenWidth, _screenHeight, _screenBPP;
bool _isFullscreen;
Shadow *_currentShadowArray;
+ unsigned char _shadowColorR;
+ unsigned char _shadowColorG;
+ unsigned char _shadowColorB;
};
extern Driver *g_driver;
diff --git a/engine/backend/sdl/driver_gl.cpp b/engine/backend/sdl/driver_gl.cpp
index d2f303ceb90..e5914ef3ed4 100644
--- a/engine/backend/sdl/driver_gl.cpp
+++ b/engine/backend/sdl/driver_gl.cpp
@@ -131,7 +131,19 @@ void DriverGL::finishActorDraw() {
glDisable(GL_TEXTURE_2D);
}
-void DriverGL::setupShadower(Shadow *shadow) {
+void DriverGL::setShadow(Shadow *shadow) {
+}
+
+void DriverGL::drawShadowPlanes() {
+}
+
+void DriverGL::setShadowMode() {
+}
+
+void DriverGL::clearShadowMode() {
+}
+
+void DriverGL::setShadowColor(byte r, byte g, byte b) {
}
void DriverGL::set3DMode() {
diff --git a/engine/backend/sdl/driver_gl.h b/engine/backend/sdl/driver_gl.h
index 6464bd095bd..1855d2f4f02 100644
--- a/engine/backend/sdl/driver_gl.h
+++ b/engine/backend/sdl/driver_gl.h
@@ -57,8 +57,12 @@ public:
void startActorDraw(Vector3d pos, float yaw, float pitch, float roll);
void finishActorDraw();
- void setupShadower(Shadow *shadow);
-
+ void setShadow(Shadow *shadow);
+ void drawShadowPlanes();
+ void setShadowMode();
+ void clearShadowMode();
+ void setShadowColor(byte r, byte g, byte b);
+
void set3DMode();
void translateViewpoint(Vector3d pos, float pitch, float yaw, float roll);
diff --git a/engine/backend/sdl/driver_tinygl.cpp b/engine/backend/sdl/driver_tinygl.cpp
index 2caf72256e5..1b17d942186 100644
--- a/engine/backend/sdl/driver_tinygl.cpp
+++ b/engine/backend/sdl/driver_tinygl.cpp
@@ -26,6 +26,7 @@
#include "common/sys.h"
#include "common/endian.h"
#include "common/debug.h"
+#include "common/vector3d.h"
#include "engine/colormap.h"
#include "engine/material.h"
@@ -184,10 +185,61 @@ bool DriverTinyGL::isHardwareAccelerated() {
return false;
}
+void tglShadowProjection(Vector3d *light, Vector3d *plane, Vector3d *normal) {
+ // 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;
+
+ nx = normal->x();
+ ny = normal->y();
+ nz = -normal->z(); // for some unknown for me reason it need negate
+ 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 DriverTinyGL::startActorDraw(Vector3d pos, float yaw, float pitch, float roll) {
tglEnable(TGL_TEXTURE_2D);
tglMatrixMode(TGL_MODELVIEW);
tglPushMatrix();
+ if (_currentShadowArray) {
+ assert(_currentShadowArray->shadowMask);
+ tglSetShadowColor(_shadowColorR, _shadowColorG, _shadowColorB);
+ tglSetShadowMaskBuf(_currentShadowArray->shadowMask);
+ SectorListType::iterator i = _currentShadowArray->planeList.begin();
+ Sector *shadowSector = *i;
+ tglShadowProjection(&_currentShadowArray->pos, &shadowSector->getVertices()[1], &shadowSector->getNormal());
+ }
tglTranslatef(pos.x(), pos.y(), pos.z());
tglRotatef(yaw, 0, 0, 1);
tglRotatef(pitch, 1, 0, 0);
@@ -199,24 +251,38 @@ void DriverTinyGL::finishActorDraw() {
tglPopMatrix();
tglDisable(TGL_TEXTURE_2D);
-/* // enable to draw shadow planes (Special Sectors)
- int k, r;
- if (!_currentShadowArray)
- return;
+ if (_currentShadowArray) {
+ tglSetShadowMaskBuf(NULL);
+ }
+}
- 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();
+void DriverTinyGL::drawShadowPlanes() {
+ tglEnable(TGL_SHADOW_MASK_MODE);
+ if (_currentShadowArray->shadowMask)
+ memset(_currentShadowArray->shadowMask, 0, _screenWidth * _screenHeight);
+ else
+ _currentShadowArray->shadowMask = new byte[_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 DriverTinyGL::setShadowMode() {
+ tglEnable(TGL_SHADOW_MODE);
+}
+
+void DriverTinyGL::clearShadowMode() {
+ tglDisable(TGL_SHADOW_MODE);
}
void DriverTinyGL::set3DMode() {
@@ -224,8 +290,18 @@ void DriverTinyGL::set3DMode() {
tglEnable(TGL_DEPTH_TEST);
}
-void DriverTinyGL::setupShadower(Shadow *shadow) {
+void DriverTinyGL::setShadow(Shadow *shadow) {
_currentShadowArray = shadow;
+ if (shadow)
+ tglDisable(TGL_LIGHTING);
+ else
+ tglEnable(TGL_LIGHTING);
+}
+
+void DriverTinyGL::setShadowColor(byte r, byte g, byte b) {
+ _shadowColorR = r;
+ _shadowColorG = g;
+ _shadowColorB = b;
}
void DriverTinyGL::drawModelFace(const Model::Face *face, float *vertices, float *vertNormals, float *textureVerts) {
diff --git a/engine/backend/sdl/driver_tinygl.h b/engine/backend/sdl/driver_tinygl.h
index c82c29c6499..da3f785c822 100644
--- a/engine/backend/sdl/driver_tinygl.h
+++ b/engine/backend/sdl/driver_tinygl.h
@@ -57,8 +57,12 @@ public:
void startActorDraw(Vector3d pos, float yaw, float pitch, float roll);
void finishActorDraw();
- void setupShadower(Shadow *shadow);
-
+ void setShadow(Shadow *shadow);
+ void drawShadowPlanes();
+ void setShadowMode();
+ void clearShadowMode();
+ void setShadowColor(byte r, byte g, byte b);
+
void set3DMode();
void translateViewpoint(Vector3d pos, float pitch, float yaw, float roll);
diff --git a/engine/engine.cpp b/engine/engine.cpp
index 54e34e10572..2a4e6b0b993 100644
--- a/engine/engine.cpp
+++ b/engine/engine.cpp
@@ -358,6 +358,7 @@ void Engine::updateDisplayScene() {
a->draw();
a->undraw(a->inSet(_currScene->name()) && a->visible());
}
+ flagRefreshShadowMask(false);
// Draw overlying scene components
// The overlay objects should be drawn on top of everything else,
@@ -413,6 +414,7 @@ void Engine::mainLoop() {
_savegameLoadRequest = false;
_savegameSaveRequest = false;
_savegameFileName = NULL;
+ _refreshShadowMask = false;
for (;;) {
if (_savegameLoadRequest) {
@@ -644,6 +646,7 @@ void Engine::setScene(const char *name) {
if (b == NULL)
warning("Could not find scene file %s\n", name);
_currScene = new Scene(name, b->data(), b->len());
+ flagRefreshShadowMask(true);
registerScene(_currScene);
_currScene->setSoundParameters(20, 127);
// should delete the old scene after creating the new one
@@ -673,7 +676,3 @@ void Engine::setTextSpeed(int speed) {
_textSpeed = 10;
_textSpeed = speed;
}
-
-void Engine::setShadowColor(Color c) {
- _shadowColor = c;
-}
diff --git a/engine/engine.h b/engine/engine.h
index ce938f120f2..2129c3a880a 100644
--- a/engine/engine.h
+++ b/engine/engine.h
@@ -69,7 +69,6 @@ public:
bool getFlipEnable() { return _flipEnable; }
void refreshDrawMode() { _refreshDrawNeeded = true; }
void drawPrimitives();
- void setShadowColor(Color c);
void mainLoop();
unsigned frameStart() const { return _frameStart; }
@@ -106,6 +105,13 @@ public:
_scenes.remove(a);
}
+ void flagRefreshShadowMask(bool flag) {
+ _refreshShadowMask = flag;
+ }
+ bool getFlagRefreshShadowMask() {
+ return _refreshShadowMask;
+ }
+
// Actor registration
typedef std::list ActorListType;
ActorListType::const_iterator actorsBegin() const {
@@ -187,7 +193,7 @@ private:
bool _refreshDrawNeeded;
char _fps[8];
bool _doFlip;
- Color _shadowColor;
+ bool _refreshShadowMask;
unsigned _frameStart, _frameTime, _movieTime;
unsigned int _frameTimeCollection;
diff --git a/engine/lua.cpp b/engine/lua.cpp
index 0201f7144f4..50372df47a5 100644
--- a/engine/lua.cpp
+++ b/engine/lua.cpp
@@ -1431,7 +1431,7 @@ static void SetShadowColor() {
int g = check_int(2);
int b = check_int(3);
- g_engine->setShadowColor(Color(r, g, b));
+ g_driver->setShadowColor(r, g, b);
}
static void KillActorShadows() {
@@ -1483,20 +1483,22 @@ static void AddShadowPlane() {
static void ActivateActorShadow() {
DEBUG_FUNCTION();
- /*Actor *act = */check_actor(1);
- /*int shadowId = */check_int(2);
- /*bool state = */getbool(3);
+ Actor *act = check_actor(1);
+ int shadowId = check_int(2);
+ bool state = getbool(3);
- //act->setActivateShadow(shadowId, state);
+ act->setActivateShadow(shadowId, state);
}
static void SetActorShadowValid() {
DEBUG_FUNCTION();
- /*Actor *act = */check_actor(1);
- /*int valid = */check_int(2);
+ Actor *act = check_actor(1);
+ int valid = check_int(2);
- //act->setShadowValid(valid);
+ warning("SetActorShadowValid(%d) unknown purpose", valid);
+
+ act->setShadowValid(valid);
}
// 0 - translate from '/msgId/'
diff --git a/engine/scene.cpp b/engine/scene.cpp
index 9eb333e3d58..f98f7a650e8 100644
--- a/engine/scene.cpp
+++ b/engine/scene.cpp
@@ -219,6 +219,7 @@ void Scene::setSetup(int num) {
return;
}
_currSetup = _setups + num;
+ g_engine->flagRefreshShadowMask(true);
}
void Scene::drawBitmaps(ObjectState::Position stage) {
diff --git a/engine/tinygl/README.residual b/engine/tinygl/README.residual
index 26e4afbad30..6bdcff89a4b 100644
--- a/engine/tinygl/README.residual
+++ b/engine/tinygl/README.residual
@@ -10,3 +10,4 @@ The changes made from the original version of TinyGL 0.4 are:
* Removed unneeded code.
* Introduced second 32-bit z-buffer for 3d objects only,
and kept 16-bit only for static z-buffer bitmaps.
+* Added support for drawing in shadow mode (generate mask and polygon shadow).
diff --git a/engine/tinygl/api.cpp b/engine/tinygl/api.cpp
index 27a79249af8..d73166c8155 100644
--- a/engine/tinygl/api.cpp
+++ b/engine/tinygl/api.cpp
@@ -604,3 +604,15 @@ void tglDebug(int mode) {
GLContext *c = gl_get_context();
c->print_flag = mode;
}
+
+void tglSetShadowMaskBuf(unsigned char *buf) {
+ GLContext *c = gl_get_context();
+ c->zb->shadow_mask_buf = buf;
+}
+
+void tglSetShadowColor(unsigned char r, unsigned char g, unsigned char b) {
+ GLContext *c = gl_get_context();
+ c->zb->shadow_color_r = r << 8;
+ c->zb->shadow_color_g = g << 8;
+ c->zb->shadow_color_b = b << 8;
+}
diff --git a/engine/tinygl/clip.cpp b/engine/tinygl/clip.cpp
index ecb591ef10e..6c9bbae8cc9 100644
--- a/engine/tinygl/clip.cpp
+++ b/engine/tinygl/clip.cpp
@@ -388,7 +388,13 @@ void gl_draw_triangle_fill(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p
}
#endif
- if (c->texture_2d_enabled) {
+ if (c->shadow_mode & 1) {
+ assert(c->zb->shadow_mask_buf);
+ ZB_fillTriangleFlatShadowMask(c->zb, &p0->zp, &p1->zp, &p2->zp);
+ } else if (c->shadow_mode & 2) {
+ assert(c->zb->shadow_mask_buf);
+ ZB_fillTriangleFlatShadow(c->zb, &p0->zp, &p1->zp, &p2->zp);
+ } else if (c->texture_2d_enabled) {
#ifdef PROFILE
count_triangles_textured++;
#endif
diff --git a/engine/tinygl/gl.h b/engine/tinygl/gl.h
index 5ae5fdb68ac..8dedddd79da 100644
--- a/engine/tinygl/gl.h
+++ b/engine/tinygl/gl.h
@@ -125,6 +125,8 @@ enum {
TGL_POLYGON_OFFSET_POINT = 0x2A01,
TGL_POLYGON_OFFSET_LINE = 0x2A02,
TGL_POLYGON_OFFSET_FILL = 0x8037,
+ TGL_SHADOW_MASK_MODE = 0x0C40,
+ TGL_SHADOW_MODE = 0x0C41,
// Display Lists
TGL_COMPILE = 0x1300,
@@ -783,6 +785,9 @@ void tglGetIntegerv(int pname, int *params);
void tglGetFloatv(int pname, float *v);
void tglFrontFace(int mode);
+void tglSetShadowMaskBuf(unsigned char *buf);
+void tglSetShadowColor(unsigned char r, unsigned char g, unsigned char b);
+
// opengl 1.2 arrays
void tglEnableClientState(TGLenum array);
void tglDisableClientState(TGLenum array);
diff --git a/engine/tinygl/init.cpp b/engine/tinygl/init.cpp
index f716795a203..50928f4a625 100644
--- a/engine/tinygl/init.cpp
+++ b/engine/tinygl/init.cpp
@@ -164,6 +164,9 @@ void tglInit(void *zbuffer1) {
// opengl 1.1 polygon offset
c->offset_states = 0;
+ // shadow mode
+ c->shadow_mode = 0;
+
// clear the resize callback function pointer
c->gl_resize_viewport = NULL;
diff --git a/engine/tinygl/misc.cpp b/engine/tinygl/misc.cpp
index ede3f214585..08a27554fca 100644
--- a/engine/tinygl/misc.cpp
+++ b/engine/tinygl/misc.cpp
@@ -82,6 +82,18 @@ void glopEnableDisable(GLContext *c, TGLParam *p) {
else
c->offset_states &= ~TGL_OFFSET_LINE;
break;
+ case TGL_SHADOW_MASK_MODE:
+ if (v)
+ c->shadow_mode |= 1;
+ else
+ c->shadow_mode &= ~1;
+ break;
+ case TGL_SHADOW_MODE:
+ if (v)
+ c->shadow_mode |= 2;
+ else
+ c->shadow_mode &= ~2;
+ break;
default:
if (code>=TGL_LIGHT0 && codexsize = xsize;
zb->ysize = ysize;
@@ -55,6 +55,7 @@ ZBuffer *ZB_open(int xsize, int ysize, int mode, void *frame_buffer) {
}
zb->current_texture = NULL;
+ zb->shadow_mask_buf = NULL;
return zb;
error:
@@ -182,7 +183,7 @@ void ZB_clear(ZBuffer *zb, int clear_z, int z,
memset_s(zb->zbuf, z, zb->xsize * zb->ysize);
}
if (clear_z) {
- memset_l(zb->zbuf, z, zb->xsize * zb->ysize);
+ memset_l(zb->zbuf2, z, zb->xsize * zb->ysize);
}
if (clear_color) {
pp = zb->pbuf;
diff --git a/engine/tinygl/zbuffer.h b/engine/tinygl/zbuffer.h
index 9ab984c8d77..0d0083236b2 100644
--- a/engine/tinygl/zbuffer.h
+++ b/engine/tinygl/zbuffer.h
@@ -29,12 +29,16 @@ typedef unsigned short PIXEL;
#define PSZSH 4
typedef struct {
- int xsize,ysize;
+ int xsize, ysize;
int linesize; // line size, in bytes
int mode;
unsigned short *zbuf;
unsigned long *zbuf2;
+ unsigned char *shadow_mask_buf;
+ int shadow_color_r;
+ int shadow_color_g;
+ int shadow_color_b;
PIXEL *pbuf;
int frame_buffer_allocated;
@@ -59,6 +63,7 @@ void ZB_resize(ZBuffer *zb, void *frame_buffer, int xsize, int ysize);
void ZB_clear(ZBuffer *zb, int clear_z, int z, int clear_color, int r, int g, int b);
// linesize is in BYTES
void ZB_copyFrameBuffer(ZBuffer *zb, void *buf, int linesize);
+//void ZB_setShadowMaskBuf(
// zline.c
@@ -71,6 +76,10 @@ void ZB_line_z(ZBuffer * zb, ZBufferPoint * p1, ZBufferPoint * p2);
void ZB_setTexture(ZBuffer *zb, PIXEL *texture);
void ZB_fillTriangleFlat(ZBuffer *zb, ZBufferPoint *p1,
ZBufferPoint *p2, ZBufferPoint *p3);
+void ZB_fillTriangleFlatShadowMask(ZBuffer *zb, ZBufferPoint *p1,
+ ZBufferPoint *p2, ZBufferPoint *p3);
+void ZB_fillTriangleFlatShadow(ZBuffer *zb, ZBufferPoint *p1,
+ ZBufferPoint *p2, ZBufferPoint *p3);
void ZB_fillTriangleSmooth(ZBuffer *zb, ZBufferPoint *p1,
ZBufferPoint *p2, ZBufferPoint *p3);
void ZB_fillTriangleMapping(ZBuffer *zb, ZBufferPoint *p1,
diff --git a/engine/tinygl/zgl.h b/engine/tinygl/zgl.h
index 7b61c75f216..bfdf4c99d08 100644
--- a/engine/tinygl/zgl.h
+++ b/engine/tinygl/zgl.h
@@ -260,7 +260,9 @@ typedef struct GLContext {
float offset_factor;
float offset_units;
int offset_states;
-
+
+ int shadow_mode;
+
/* specular buffer. could probably be shared between contexts,
but that wouldn't be 100% thread safe */
GLSpecBuf *specbuf_first;
diff --git a/engine/tinygl/ztriangle.cpp b/engine/tinygl/ztriangle.cpp
index 6829fb883ae..05165bac8b8 100644
--- a/engine/tinygl/ztriangle.cpp
+++ b/engine/tinygl/ztriangle.cpp
@@ -14,7 +14,7 @@ void ZB_fillTriangleFlat(ZBuffer *zb, ZBufferPoint *p0,
#define DRAW_INIT() { \
color = RGB_TO_PIXEL(p2->r, p2->g, p2->b); \
}
-
+
#define PUT_PIXEL(_a) { \
zz = z >> ZB_POINT_Z_FRAC_BITS; \
if ((ZCMP(zz, pz[_a])) && (ZCMP(z, pz_2[_a]))) { \
diff --git a/engine/tinygl/ztriangle_shadow.cpp b/engine/tinygl/ztriangle_shadow.cpp
new file mode 100644
index 00000000000..39522d7b30c
--- /dev/null
+++ b/engine/tinygl/ztriangle_shadow.cpp
@@ -0,0 +1,364 @@
+
+#include "engine/tinygl/zbuffer.h"
+
+#define ZCMP(z, zpix) ((z) >= (zpix))
+
+void ZB_fillTriangleFlatShadowMask(ZBuffer *zb, ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
+ ZBufferPoint *t, *pr1, *pr2, *l1, *l2;
+ float fdx1, fdx2, fdy1, fdy2, fz;
+ unsigned char *pm1;
+ int part, update_left, update_right;
+
+ int nb_lines, dx1, dy1, tmp, dx2, dy2;
+
+ int error, derror;
+ int x1, dxdy_min, dxdy_max;
+ // warning: x2 is multiplied by 2^16
+ int x2, dx2dy2;
+
+ // we sort the vertex with increasing y
+ if (p1->y < p0->y) {
+ t = p0;
+ p0 = p1;
+ p1 = t;
+ }
+ if (p2->y < p0->y) {
+ t = p2;
+ p2 = p1;
+ p1 = p0;
+ p0 = t;
+ } else if (p2->y < p1->y) {
+ t = p1;
+ p1 = p2;
+ p2 = t;
+ }
+
+ // we compute dXdx and dXdy for all interpolated values
+
+ fdx1 = (float)(p1->x - p0->x);
+ fdy1 = (float)(p1->y - p0->y);
+
+ fdx2 = (float)(p2->x - p0->x);
+ fdy2 = (float)(p2->y - p0->y);
+
+ fz = fdx1 * fdy2 - fdx2 * fdy1;
+ if (fz == 0)
+ return;
+ fz = (float)(1.0 / fz);
+
+ fdx1 *= fz;
+ fdy1 *= fz;
+ fdx2 *= fz;
+ fdy2 *= fz;
+
+ // screen coordinates
+
+ pm1 = zb->shadow_mask_buf + zb->xsize * p0->y;
+
+ for (part = 0; part < 2; part++) {
+ if (part == 0) {
+ if (fz > 0) {
+ update_left = 1;
+ update_right = 1;
+ l1 = p0;
+ l2 = p2;
+ pr1 = p0;
+ pr2 = p1;
+ } else {
+ update_left = 1;
+ update_right = 1;
+ l1 = p0;
+ l2 = p1;
+ pr1 = p0;
+ pr2 = p2;
+ }
+ nb_lines = p1->y - p0->y;
+ } else {
+ // second part
+ if (fz > 0) {
+ update_left = 0;
+ update_right = 1;
+ pr1 = p1;
+ pr2 = p2;
+ } else {
+ update_left = 1;
+ update_right = 0;
+ l1 = p1;
+ l2 = p2;
+ }
+ nb_lines = p2->y - p1->y + 1;
+ }
+
+ // compute the values for the left edge
+ if (update_left) {
+ dy1 = l2->y - l1->y;
+ dx1 = l2->x - l1->x;
+ if (dy1 > 0)
+ tmp = (dx1 << 16) / dy1;
+ else
+ tmp = 0;
+ x1 = l1->x;
+ error = 0;
+ derror = tmp & 0x0000ffff;
+ dxdy_min = tmp >> 16;
+ dxdy_max = dxdy_min + 1;
+ }
+
+ // compute values for the right edge
+
+ if (update_right) {
+ dx2 = (pr2->x - pr1->x);
+ dy2 = (pr2->y - pr1->y);
+ if (dy2 > 0)
+ dx2dy2 = ( dx2 << 16) / dy2;
+ else
+ dx2dy2 = 0;
+ x2 = pr1->x << 16;
+ }
+
+ // we draw all the scan line of the part
+ while (nb_lines > 0) {
+ nb_lines--;
+ // generic draw line
+ {
+ register unsigned char *pm;
+ register int n;
+
+ n = (x2 >> 16) - x1;
+ pm = pm1 + x1;
+ while (n >= 3) {
+ for (int a = 0; a <= 3; a++) {
+ pm[a] = 0xff;
+ }
+ pm += 4;
+ n -= 4;
+ }
+ while (n >= 0) {
+ pm[0] = 0xff;
+ pm += 1;
+ n -= 1;
+ }
+ }
+
+ // left edge
+ error += derror;
+ if (error > 0) {
+ error -= 0x10000;
+ x1 += dxdy_max;
+ } else {
+ x1 += dxdy_min;
+ }
+
+ // right edge
+ x2 += dx2dy2;
+
+ // screen coordinates
+ pm1 = pm1 + zb->xsize;
+ }
+ }
+}
+
+void ZB_fillTriangleFlatShadow(ZBuffer *zb, ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
+ int color;
+ ZBufferPoint *t, *pr1, *pr2, *l1, *l2;
+ float fdx1, fdx2, fdy1, fdy2, fz, d1, d2;
+ unsigned char *pm1;
+ unsigned short *pz1;
+ unsigned long *pz2;
+ PIXEL *pp1;
+ int part, update_left, update_right;
+
+ int nb_lines, dx1, dy1, tmp, dx2, dy2;
+
+ int error, derror;
+ int x1, dxdy_min, dxdy_max;
+ // warning: x2 is multiplied by 2^16
+ int x2, dx2dy2;
+
+ int z1, dzdx, dzdy, dzdl_min, dzdl_max;
+
+ // we sort the vertex with increasing y
+ if (p1->y < p0->y) {
+ t = p0;
+ p0 = p1;
+ p1 = t;
+ }
+ if (p2->y < p0->y) {
+ t = p2;
+ p2 = p1;
+ p1 = p0;
+ p0 = t;
+ } else if (p2->y < p1->y) {
+ t = p1;
+ p1 = p2;
+ p2 = t;
+ }
+
+ // we compute dXdx and dXdy for all interpolated values
+
+ fdx1 = (float)(p1->x - p0->x);
+ fdy1 = (float)(p1->y - p0->y);
+
+ fdx2 = (float)(p2->x - p0->x);
+ fdy2 = (float)(p2->y - p0->y);
+
+ fz = fdx1 * fdy2 - fdx2 * fdy1;
+ if (fz == 0)
+ return;
+ fz = (float)(1.0 / fz);
+
+ fdx1 *= fz;
+ fdy1 *= fz;
+ fdx2 *= fz;
+ fdy2 *= fz;
+
+ d1 = (float)(p1->z - p0->z);
+ d2 = (float)(p2->z - p0->z);
+ dzdx = (int)(fdy2 * d1 - fdy1 * d2);
+ dzdy = (int)(fdx1 * d2 - fdx2 * d1);
+
+ // screen coordinates
+
+ pp1 = (PIXEL *)((char *)zb->pbuf + zb->linesize * p0->y);
+ pm1 = zb->shadow_mask_buf + p0->y * zb->xsize;
+ pz1 = zb->zbuf + p0->y * zb->xsize;
+ pz2 = zb->zbuf2 + p0->y * zb->xsize;
+
+ color = RGB_TO_PIXEL(zb->shadow_color_r, zb->shadow_color_g, zb->shadow_color_b);
+
+ for (part = 0; part < 2; part++) {
+ if (part == 0) {
+ if (fz > 0) {
+ update_left = 1;
+ update_right = 1;
+ l1 = p0;
+ l2 = p2;
+ pr1 = p0;
+ pr2 = p1;
+ } else {
+ update_left = 1;
+ update_right = 1;
+ l1 = p0;
+ l2 = p1;
+ pr1 = p0;
+ pr2 = p2;
+ }
+ nb_lines = p1->y - p0->y;
+ } else {
+ // second part
+ if (fz > 0) {
+ update_left = 0;
+ update_right = 1;
+ pr1 = p1;
+ pr2 = p2;
+ } else {
+ update_left = 1;
+ update_right = 0;
+ l1 = p1;
+ l2 = p2;
+ }
+ nb_lines = p2->y - p1->y + 1;
+ }
+
+ // compute the values for the left edge
+
+ if (update_left) {
+ dy1 = l2->y - l1->y;
+ dx1 = l2->x - l1->x;
+ if (dy1 > 0)
+ tmp = (dx1 << 16) / dy1;
+ else
+ tmp = 0;
+ x1 = l1->x;
+ error = 0;
+ derror = tmp & 0x0000ffff;
+ dxdy_min = tmp >> 16;
+ dxdy_max = dxdy_min + 1;
+
+ z1 = l1->z;
+ dzdl_min = (dzdy + dzdx * dxdy_min);
+ dzdl_max = dzdl_min + dzdx;
+ }
+
+ // compute values for the right edge
+
+ if (update_right) {
+ dx2 = (pr2->x - pr1->x);
+ dy2 = (pr2->y - pr1->y);
+ if (dy2>0)
+ dx2dy2 = ( dx2 << 16) / dy2;
+ else
+ dx2dy2 = 0;
+ x2 = pr1->x << 16;
+ }
+
+ // we draw all the scan line of the part
+
+ while (nb_lines > 0) {
+ nb_lines--;
+ // generic draw line
+ {
+ register PIXEL *pp;
+ register unsigned char *pm;
+ register int n;
+ register unsigned short *pz;
+ register unsigned long *pz_2;
+ register unsigned int z, zz;
+
+ n = (x2 >> 16) - x1;
+ pp = (PIXEL *)((char *)pp1 + x1 * PSZB);
+ pm = pm1 + x1;
+ pz = pz1 + x1;
+ pz_2 = pz2 + x1;
+ z = z1;
+ while (n >= 3) {
+ for (int a = 0; a < 4; a++) {
+ zz = z >> ZB_POINT_Z_FRAC_BITS;
+ if ((ZCMP(zz, pz[a])) && (ZCMP(z, pz_2[a])) && pm[0]) {
+ pp[a] = color;
+ pz_2[a] = z;
+ }
+ z += dzdx;
+ }
+ pz += 4;
+ pz_2 += 4;
+ pm += 4;
+ pp = (PIXEL *)((char *)pp + 4 * PSZB);
+ n -= 4;
+ }
+ while (n >= 0) {
+ zz = z >> ZB_POINT_Z_FRAC_BITS;
+ if ((ZCMP(zz, pz[0])) && (ZCMP(z, pz_2[0])) && pm[0]) {
+ pp[0] = color;
+ pz_2[0] = z;
+ }
+ pz += 1;
+ pz_2 += 1;
+ pm += 1;
+ pp = (PIXEL *)((char *)pp + PSZB);
+ n -= 1;
+ }
+ }
+
+ // left edge
+ error += derror;
+ if (error > 0) {
+ error -= 0x10000;
+ x1 += dxdy_max;
+ z1 += dzdl_max;
+ } else {
+ x1 += dxdy_min;
+ z1 += dzdl_min;
+ }
+
+ // right edge
+ x2 += dx2dy2;
+
+ // screen coordinates
+ pp1 = (PIXEL *)((char *)pp1 + zb->linesize);
+ pz1 += zb->xsize;
+ pz2 += zb->xsize;
+ pm1 += zb->xsize;
+ }
+ }
+}