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; + } + } +}