added initial support for shadows in software renderer but still a bit broken

This commit is contained in:
Pawel Kolodziejski 2008-07-05 08:48:39 +00:00
parent 6cc8a3db80
commit 5ea5ffb030
27 changed files with 634 additions and 60 deletions

View File

@ -578,6 +578,9 @@
<File
RelativePath="..\..\engine\tinygl\ztriangle.h">
</File>
<File
RelativePath="..\..\engine\tinygl\ztriangle_shadow.cpp">
</File>
</Filter>
<Filter
Name="imuse">

View File

@ -592,6 +592,9 @@
<File
RelativePath="..\..\engine\tinygl\ztriangle.h">
</File>
<File
RelativePath="..\..\engine\tinygl\ztriangle_shadow.cpp">
</File>
</Filter>
<Filter
Name="imuse">

View File

@ -810,6 +810,10 @@
RelativePath="..\..\engine\tinygl\ztriangle.h"
>
</File>
<File
RelativePath="..\..\engine\tinygl\ztriangle_shadow.cpp"
>
</File>
</Filter>
<Filter
Name="imuse"

View File

@ -815,6 +815,10 @@
RelativePath="..\..\engine\tinygl\ztriangle.h"
>
</File>
<File
RelativePath="..\..\engine\tinygl\ztriangle_shadow.cpp"
>
</File>
</Filter>
<Filter
Name="imuse"

View File

@ -62,7 +62,8 @@ Actor::Actor(const char *name) :
_shadowArray = new Shadow[5];
for (int i = 0; i < 5; i++) {
_shadowArray[i].active = true;
_shadowArray[i].active = false;
_shadowArray[i].shadowMask = NULL;
}
for (int i = 0; i < 10; i++) {
@ -599,12 +600,36 @@ void Actor::draw() {
for (std::list<Costume *>::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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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() {

View File

@ -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);

View File

@ -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 <phaetos@gaffga.de>
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) {

View File

@ -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);

View File

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

View File

@ -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<Actor *> 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;

View File

@ -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/'

View File

@ -219,6 +219,7 @@ void Scene::setSetup(int num) {
return;
}
_currSetup = _setups + num;
g_engine->flagRefreshShadowMask(true);
}
void Scene::drawBitmaps(ObjectState::Position stage) {

View File

@ -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).

View File

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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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 && code<TGL_LIGHT0+MAX_LIGHTS) {
gl_enable_disable_light(c,code - TGL_LIGHT0, v);

View File

@ -22,7 +22,8 @@ MODULE_OBJS := \
zbuffer.o \
zline.o \
zmath.o \
ztriangle.o
ztriangle.o \
ztriangle_shadow.o
# Include common rules
include $(srcdir)/rules.mk

View File

@ -14,7 +14,7 @@ ZBuffer *ZB_open(int xsize, int ysize, int mode, void *frame_buffer) {
zb = (ZBuffer *)gl_malloc(sizeof(ZBuffer));
if (zb == NULL)
return NULL;
return NULL;
zb->xsize = 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;

View File

@ -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,

View File

@ -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;

View File

@ -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]))) { \

View File

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