763 lines
24 KiB
C++
763 lines
24 KiB
C++
/******************************************************************************
|
|
Plush Version 1.2
|
|
cam.c
|
|
Camera and Rendering
|
|
Copyright (c) 1996-2000, Justin Frankel
|
|
******************************************************************************/
|
|
|
|
#include "plush.h"
|
|
|
|
|
|
#include "../lice/lice_extended.h"
|
|
|
|
#include "../mergesort.h"
|
|
|
|
#define MACRO_plMatrixApply(m,x,y,z,outx,outy,outz) \
|
|
( outx ) = ( x )*( m )[0] + ( y )*( m )[1] + ( z )*( m )[2] + ( m )[3];\
|
|
( outy ) = ( x )*( m )[4] + ( y )*( m )[5] + ( z )*( m )[6] + ( m )[7];\
|
|
( outz ) = ( x )*( m )[8] + ( y )*( m )[9] + ( z )*( m )[10] + ( m )[11]
|
|
|
|
#define MACRO_plDotProduct(x1,y1,z1,x2,y2,z2) \
|
|
((( x1 )*( x2 ))+(( y1 )*( y2 ))+(( z1 )*( z2 )))
|
|
|
|
#define MACRO_plNormalizeVector(x,y,z) { \
|
|
double length; \
|
|
length = ( x )*( x )+( y )*( y )+( z )*( z ); \
|
|
if (length > 0.0000000001) { \
|
|
double __l = 1.0/sqrt(length); \
|
|
( x ) *= __l; \
|
|
( y ) *= __l; \
|
|
( z ) *= __l; \
|
|
} \
|
|
}
|
|
|
|
|
|
static void _FindNormal(double x2, double x3,double y2, double y3,
|
|
double zv, double *res) {
|
|
res[0] = zv*(y2-y3);
|
|
res[1] = zv*(x3-x2);
|
|
res[2] = x2*y3 - y2*x3;
|
|
}
|
|
|
|
|
|
void pl_Cam::SetTarget(pl_Float x, pl_Float y, pl_Float z) {
|
|
double dx, dy, dz;
|
|
dx = x - X;
|
|
dy = y - Y;
|
|
dz = z - Z;
|
|
Roll = 0;
|
|
if (dz > 0.0001f) {
|
|
Pan = (pl_Float) (-atan(dx/dz)*(180.0/PL_PI));
|
|
dz /= cos(Pan*(PL_PI/180.0));
|
|
Pitch = (pl_Float) (atan(dy/dz)*(180.0/PL_PI));
|
|
} else if (dz < -0.0001f) {
|
|
Pan = (pl_Float) (180.0-atan(dx/dz)*(180.0/PL_PI));
|
|
dz /= cos((Pan-180.0f)*(PL_PI/180.0));
|
|
Pitch = (pl_Float) (-atan(dy/dz)*(180.0/PL_PI));
|
|
} else {
|
|
Pan = 90.0f;
|
|
Pitch = (pl_Float) (atan2(dy,-dx) * (180.0 / PL_PI));
|
|
Roll = -90.0f;
|
|
}
|
|
GenMatrix = true;
|
|
}
|
|
|
|
void pl_Cam::RecalcFrustum(int fbw, int fbh)
|
|
{
|
|
const int cx = (CenterX*m_lastFBScaling)/256 + fbw/2;
|
|
const int cy = (CenterY*m_lastFBScaling)/256 + fbh/2;
|
|
m_lastCX = cx;
|
|
m_lastCY = cy;
|
|
|
|
m_adj_asp = 1.0 / AspectRatio;
|
|
m_fovfactor = CalcFOVFactor(fbw);
|
|
memset(m_clipPlanes,0,sizeof(m_clipPlanes));
|
|
|
|
/* Back */
|
|
m_clipPlanes[0][2] = -1.0;
|
|
m_clipPlanes[0][3] = -ClipBack;
|
|
|
|
/* Left */
|
|
m_clipPlanes[1][3] = 0.00000001;
|
|
if (cx == 0) m_clipPlanes[1][0] = 1.0;
|
|
else
|
|
{
|
|
_FindNormal(-100,-100,
|
|
100, -100,
|
|
m_fovfactor*100.0/cx,
|
|
m_clipPlanes[1]);
|
|
if (cx < 0)
|
|
{
|
|
m_clipPlanes[1][0] = -m_clipPlanes[1][0];
|
|
m_clipPlanes[1][1] = -m_clipPlanes[1][1];
|
|
m_clipPlanes[1][2] = -m_clipPlanes[1][2];
|
|
}
|
|
}
|
|
|
|
/* Right */
|
|
m_clipPlanes[2][3] = 0.00000001;
|
|
if (fbw == cx) m_clipPlanes[2][0] = -1.0;
|
|
else
|
|
{
|
|
_FindNormal(100,100,
|
|
-100, 100,
|
|
m_fovfactor*100.0/(fbw-cx),
|
|
m_clipPlanes[2]);
|
|
if (cx > fbw)
|
|
{
|
|
m_clipPlanes[2][0] = -m_clipPlanes[2][0];
|
|
m_clipPlanes[2][1] = -m_clipPlanes[2][1];
|
|
m_clipPlanes[2][2] = -m_clipPlanes[2][2];
|
|
}
|
|
}
|
|
|
|
/* Top */
|
|
m_clipPlanes[3][3] = 0.00000001;
|
|
if (cy == 0) m_clipPlanes[3][1] = 1.0;
|
|
else
|
|
{
|
|
_FindNormal(100, -100,
|
|
100, 100,
|
|
m_fovfactor*m_adj_asp*-100.0/(cy),
|
|
m_clipPlanes[3]);
|
|
if (cy < 0)
|
|
{
|
|
m_clipPlanes[3][0] = -m_clipPlanes[3][0];
|
|
m_clipPlanes[3][1] = -m_clipPlanes[3][1];
|
|
m_clipPlanes[3][2] = -m_clipPlanes[3][2];
|
|
}
|
|
}
|
|
|
|
/* Bottom */
|
|
m_clipPlanes[4][3] = 0.00000001;
|
|
if (cy == fbh) m_clipPlanes[4][1] = -1.0;
|
|
else
|
|
{
|
|
_FindNormal(-100, 100,
|
|
-100, -100,
|
|
m_fovfactor*m_adj_asp*100.0/(cy-fbh),
|
|
m_clipPlanes[4]);
|
|
if (cy > fbh)
|
|
{
|
|
m_clipPlanes[4][0] = -m_clipPlanes[4][0];
|
|
m_clipPlanes[4][1] = -m_clipPlanes[4][1];
|
|
m_clipPlanes[4][2] = -m_clipPlanes[4][2];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* Returns: 0 if nothing gets in, 1 or 2 if pout1 & pout2 get in */
|
|
pl_uInt pl_Cam::_ClipToPlane(pl_uInt numVerts, pl_Float *plane)
|
|
{
|
|
pl_uInt i, nextvert, curin, nextin;
|
|
double curdot, nextdot, scale;
|
|
pl_uInt invert, outvert;
|
|
invert = 0;
|
|
outvert = 0;
|
|
curdot = m_cl[0].newVertices[0].xformedx*plane[0] +
|
|
m_cl[0].newVertices[0].xformedy*plane[1] +
|
|
m_cl[0].newVertices[0].xformedz*plane[2];
|
|
curin = (curdot >= plane[3]);
|
|
|
|
for (i=0 ; i < numVerts; i++) {
|
|
nextvert = (i + 1) % numVerts;
|
|
if (curin) {
|
|
memcpy(&m_cl[1].ShadeInfos[outvert][0],&m_cl[0].ShadeInfos[invert][0],3*sizeof(pl_Float));
|
|
int a;
|
|
for(a=0;a<PLUSH_MAX_MAPCOORDS;a++)
|
|
{
|
|
m_cl[1].MappingU[a][outvert] = m_cl[0].MappingU[a][invert];
|
|
m_cl[1].MappingV[a][outvert] = m_cl[0].MappingV[a][invert];
|
|
}
|
|
m_cl[1].newVertices[outvert++] = m_cl[0].newVertices[invert];
|
|
}
|
|
nextdot = m_cl[0].newVertices[nextvert].xformedx*plane[0] +
|
|
m_cl[0].newVertices[nextvert].xformedy*plane[1] +
|
|
m_cl[0].newVertices[nextvert].xformedz*plane[2];
|
|
nextin = (nextdot >= plane[3]);
|
|
if (curin != nextin) {
|
|
scale = (plane[3] - curdot) / (nextdot - curdot);
|
|
m_cl[1].newVertices[outvert].xformedx = (pl_Float) (m_cl[0].newVertices[invert].xformedx +
|
|
(m_cl[0].newVertices[nextvert].xformedx - m_cl[0].newVertices[invert].xformedx)
|
|
* scale);
|
|
m_cl[1].newVertices[outvert].xformedy = (pl_Float) (m_cl[0].newVertices[invert].xformedy +
|
|
(m_cl[0].newVertices[nextvert].xformedy - m_cl[0].newVertices[invert].xformedy)
|
|
* scale);
|
|
m_cl[1].newVertices[outvert].xformedz = (pl_Float) (m_cl[0].newVertices[invert].xformedz +
|
|
(m_cl[0].newVertices[nextvert].xformedz - m_cl[0].newVertices[invert].xformedz)
|
|
* scale);
|
|
|
|
m_cl[1].ShadeInfos[outvert][0] = m_cl[0].ShadeInfos[invert][0] + (m_cl[0].ShadeInfos[nextvert][0] - m_cl[0].ShadeInfos[invert][0]) * scale;
|
|
m_cl[1].ShadeInfos[outvert][1] = m_cl[0].ShadeInfos[invert][1] + (m_cl[0].ShadeInfos[nextvert][1] - m_cl[0].ShadeInfos[invert][1]) * scale;
|
|
m_cl[1].ShadeInfos[outvert][2] = m_cl[0].ShadeInfos[invert][2] + (m_cl[0].ShadeInfos[nextvert][2] - m_cl[0].ShadeInfos[invert][2]) * scale;
|
|
|
|
int a;
|
|
for(a=0;a<PLUSH_MAX_MAPCOORDS;a++)
|
|
{
|
|
m_cl[1].MappingU[a][outvert] = m_cl[0].MappingU[a][invert] +
|
|
(m_cl[0].MappingU[a][nextvert] - m_cl[0].MappingU[a][invert]) * scale;
|
|
m_cl[1].MappingV[a][outvert] = m_cl[0].MappingV[a][invert] +
|
|
(m_cl[0].MappingV[a][nextvert] - m_cl[0].MappingV[a][invert]) * scale;
|
|
}
|
|
outvert++;
|
|
}
|
|
curdot = nextdot;
|
|
curin = nextin;
|
|
invert++;
|
|
}
|
|
return outvert;
|
|
}
|
|
|
|
bool pl_Cam::ProjectCoordinate(pl_Float x, pl_Float y, pl_Float z, pl_Float *screen_x, pl_Float *screen_y, pl_Float *dist)
|
|
{
|
|
x -= X;
|
|
y -= Y;
|
|
z -= Z;
|
|
plMatrixApply(CamMatrix,x,y,z,&x,&y,&z);
|
|
|
|
if (dist) *dist = sqrt(x*x + y*y + z*z);
|
|
|
|
if (!m_lastFBWidth || !m_lastFBHeight || z < 0.0000000001) return false;
|
|
|
|
const double iz = 1.0/z;
|
|
double ytmp = CalcFOVFactor(m_lastFBWidth) * iz;
|
|
double xtmp = ytmp*x;
|
|
ytmp *= y*m_adj_asp;
|
|
|
|
xtmp += CenterX + m_lastFBWidth/2;
|
|
ytmp += CenterY + m_lastFBHeight/2;
|
|
|
|
if (screen_x) *screen_x = xtmp;
|
|
if (screen_y) *screen_y = ytmp;
|
|
|
|
return xtmp >= 0 && xtmp < m_lastFBWidth && ytmp >= 0 && ytmp < m_lastFBHeight;
|
|
}
|
|
|
|
|
|
void pl_Cam::ClipRenderFace(pl_Face *face, pl_Obj *obj) {
|
|
const int cx = m_lastCX, cy = m_lastCY;
|
|
|
|
{
|
|
pl_Vertex *vlist=obj->Vertices.Get();
|
|
int a;
|
|
for (a = 0; a < 3; a ++) {
|
|
m_cl[0].newVertices[a] = vlist[face->VertexIndices[a]];
|
|
|
|
memcpy(&m_cl[0].ShadeInfos[a][0],&face->Shades[a][0],3*sizeof(pl_Float));
|
|
int b;
|
|
for(b=0;b<PLUSH_MAX_MAPCOORDS;b++)
|
|
{
|
|
m_cl[0].MappingU[b][a] = face->MappingU[b][a];
|
|
m_cl[0].MappingV[b][a] = face->MappingV[b][a];
|
|
}
|
|
}
|
|
}
|
|
|
|
pl_uInt numVerts = 3;
|
|
{
|
|
int a = (m_clipPlanes[0][3] < 0.0 ? 0 : 1);
|
|
while (a < PL_NUM_CLIP_PLANES && numVerts > 2)
|
|
{
|
|
numVerts = _ClipToPlane(numVerts, m_clipPlanes[a]);
|
|
memcpy(&m_cl[0],&m_cl[1],sizeof(m_cl[0]));
|
|
a++;
|
|
}
|
|
}
|
|
if (numVerts > 2) {
|
|
pl_Face newface;
|
|
memcpy(&newface,face,sizeof(pl_Face));
|
|
int k;
|
|
for (k = 2; k < (int)numVerts; k ++) {
|
|
int a;
|
|
for (a = 0; a < 3; a ++) {
|
|
int w;
|
|
if (a == 0) w = 0;
|
|
else w = a+(k-2); ;
|
|
pl_Vertex *thisv=m_cl[0].newVertices+w;
|
|
newface.Shades[a][0] = m_cl[0].ShadeInfos[w][0];
|
|
newface.Shades[a][1] = m_cl[0].ShadeInfos[w][1];
|
|
newface.Shades[a][2] = m_cl[0].ShadeInfos[w][2];
|
|
int b;
|
|
for(b=0;b<PLUSH_MAX_MAPCOORDS;b++)
|
|
{
|
|
newface.MappingU[b][a] = m_cl[0].MappingU[b][w];
|
|
newface.MappingV[b][a] = m_cl[0].MappingV[b][w];
|
|
}
|
|
newface.Scrz[a] = 1.0f/thisv->xformedz;
|
|
double ytmp = m_fovfactor * newface.Scrz[a];
|
|
double xtmp = ytmp*thisv->xformedx;
|
|
ytmp *= thisv->xformedy*m_adj_asp;
|
|
newface.Scrx[a] = xtmp+cx;
|
|
newface.Scry[a] = ytmp+cy;
|
|
}
|
|
RenderTrisOut++;
|
|
|
|
// quick approx of triangle area
|
|
RenderPixelsOut += 0.5*fabs(
|
|
(newface.Scrx[1] - newface.Scrx[0]) *
|
|
(newface.Scry[2] - newface.Scry[0]) -
|
|
(newface.Scrx[2] - newface.Scrx[0]) *
|
|
(newface.Scry[1] - newface.Scry[0]) );
|
|
|
|
PutFace(&newface);
|
|
}
|
|
}
|
|
}
|
|
|
|
pl_sInt pl_Cam::ClipNeeded(pl_Face *face, pl_Obj *obj) {
|
|
const int fbw=m_fBuffer.m_w, fbh=m_fBuffer.m_h;
|
|
const int cx = m_lastCX, cy = m_lastCY;
|
|
double dr,dl,db,dt;
|
|
double f;
|
|
dr = (fbw-cx);
|
|
dl = (-cx);
|
|
db = (fbh-cy);
|
|
dt = (-cy);
|
|
f = m_fovfactor*m_adj_asp;
|
|
pl_Vertex *vlist=obj->Vertices.Get();
|
|
pl_Vertex *v0=vlist+face->VertexIndices[0];
|
|
pl_Vertex *v1=vlist+face->VertexIndices[1];
|
|
pl_Vertex *v2=vlist+face->VertexIndices[2];
|
|
|
|
return ((ClipBack <= 0.0 ||
|
|
v0->xformedz <= ClipBack ||
|
|
v1->xformedz <= ClipBack ||
|
|
v2->xformedz <= ClipBack) &&
|
|
(v0->xformedz >= 0 ||
|
|
v1->xformedz >= 0 ||
|
|
v2->xformedz >= 0) &&
|
|
(v0->xformedx*m_fovfactor<=dr*v0->xformedz ||
|
|
v1->xformedx*m_fovfactor<=dr*v1->xformedz ||
|
|
v2->xformedx*m_fovfactor<=dr*v2->xformedz) &&
|
|
(v0->xformedx*m_fovfactor>=dl*v0->xformedz ||
|
|
v1->xformedx*m_fovfactor>=dl*v1->xformedz ||
|
|
v2->xformedx*m_fovfactor>=dl*v2->xformedz) &&
|
|
(v0->xformedy*f<=db*v0->xformedz ||
|
|
v1->xformedy*f<=db*v1->xformedz ||
|
|
v2->xformedy*f<=db*v2->xformedz) &&
|
|
(v0->xformedy*f>=dt*v0->xformedz ||
|
|
v1->xformedy*f>=dt*v1->xformedz ||
|
|
v2->xformedy*f>=dt*v2->xformedz));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void pl_Cam::Begin(LICE_IBitmap *fb, bool want_zbclear, pl_ZBuffer zbclear) {
|
|
if (WDL_NOT_NORMALLY(m_fBuffer.m_buf) || WDL_NOT_NORMALLY(!fb)) return;
|
|
|
|
m_lastFBWidth=fb->getWidth();
|
|
m_lastFBHeight=fb->getHeight();
|
|
m_lastFBScaling = (int)fb->Extended(LICE_EXT_GET_SCALING,NULL);
|
|
if (m_lastFBScaling==0 || WDL_NOT_NORMALLY(m_lastFBScaling > 1024)) m_lastFBScaling=256;
|
|
|
|
m_fBuffer.m_buf = fb->getBits();
|
|
m_fBuffer.m_span = fb->getRowSpan();
|
|
m_fBuffer.m_w = fb->getWidth() * m_lastFBScaling / 256;
|
|
m_fBuffer.m_h = fb->getHeight() * m_lastFBScaling / 256;
|
|
m_fBuffer.m_flipped = fb->isFlipped();
|
|
|
|
if (WantZBuffer)
|
|
{
|
|
int zbsz=m_fBuffer.m_w*m_fBuffer.m_h;
|
|
pl_ZBuffer *zb=zBuffer.ResizeOK(zbsz);
|
|
if (!zb) zBuffer.Resize(0);
|
|
else if (want_zbclear)
|
|
{
|
|
if (!zbclear) memset(zb,0,zbsz*sizeof(pl_ZBuffer));
|
|
else
|
|
{
|
|
int i=zbsz;
|
|
while(i--) *zb++=zbclear;
|
|
}
|
|
}
|
|
}
|
|
else zBuffer.Resize(0);
|
|
pl_Float tempMatrix[16];
|
|
_numlights = 0;
|
|
_numfaces = _numfaces_sorted = 0;
|
|
if (GenMatrix)
|
|
{
|
|
plMatrixRotate(CamMatrix,2,-Pan);
|
|
plMatrixRotate(tempMatrix,1,-Pitch);
|
|
plMatrixMultiply(CamMatrix,tempMatrix);
|
|
plMatrixRotate(tempMatrix,3,-Roll);
|
|
plMatrixMultiply(CamMatrix,tempMatrix);
|
|
}
|
|
|
|
RecalcFrustum(m_fBuffer.m_w, m_fBuffer.m_h);
|
|
|
|
RenderTrisIn=RenderTrisCulled=RenderTrisOut=0;
|
|
RenderPixelsOut=0.0;
|
|
|
|
}
|
|
|
|
void pl_Cam::RenderLight(pl_Light *light) {
|
|
if (!light||WDL_NOT_NORMALLY(!m_fBuffer.m_buf)) return;
|
|
|
|
pl_Float *pl, xp, yp, zp;
|
|
if (light->Type == PL_LIGHT_NONE) return;
|
|
if (_lights.GetSize()<=_numlights) _lights.Resize(_numlights+1);
|
|
pl = _lights.Get()[_numlights].l;
|
|
if (light->Type == PL_LIGHT_VECTOR) {
|
|
xp = light->Xp;
|
|
yp = light->Yp;
|
|
zp = light->Zp;
|
|
MACRO_plMatrixApply(CamMatrix,xp,yp,zp,pl[0],pl[1],pl[2]);
|
|
} else if (light->Type & PL_LIGHT_POINT) {
|
|
xp = light->Xp-X;
|
|
yp = light->Yp-Y;
|
|
zp = light->Zp-Z;
|
|
MACRO_plMatrixApply(CamMatrix,xp,yp,zp,pl[0],pl[1],pl[2]);
|
|
}
|
|
_lights.Get()[_numlights++].light = light;
|
|
}
|
|
|
|
void pl_Cam::RenderObject(pl_Obj *obj, const pl_Float *bmatrix, const pl_Float *bnmatrix) {
|
|
if (!obj||WDL_NOT_NORMALLY(!m_fBuffer.m_buf)) return;
|
|
|
|
pl_Float oMatrix[16], nMatrix[16], tempMatrix[16];
|
|
|
|
if (obj->GenMatrix) {
|
|
plMatrixRotate(nMatrix,1,obj->Xa);
|
|
plMatrixRotate(tempMatrix,2,obj->Ya);
|
|
plMatrixMultiply(nMatrix,tempMatrix);
|
|
plMatrixRotate(tempMatrix,3,obj->Za);
|
|
plMatrixMultiply(nMatrix,tempMatrix);
|
|
memcpy(obj->RotMatrix,nMatrix,sizeof(pl_Float)*16);
|
|
|
|
memcpy(oMatrix,nMatrix,sizeof(pl_Float)*16);
|
|
plMatrixTranslate(tempMatrix, obj->Xp, obj->Yp, obj->Zp);
|
|
plMatrixMultiply(oMatrix,tempMatrix);
|
|
memcpy(obj->Matrix,oMatrix,sizeof(pl_Float)*16);
|
|
} else {
|
|
memcpy(oMatrix,obj->Matrix,sizeof(pl_Float)*16);
|
|
memcpy(nMatrix,obj->RotMatrix,sizeof(pl_Float)*16);
|
|
}
|
|
|
|
if (bnmatrix) plMatrixMultiply(nMatrix,bnmatrix);
|
|
if (bmatrix) plMatrixMultiply(oMatrix,bmatrix);
|
|
|
|
{
|
|
int i;
|
|
for (i = 0; i < obj->Children.GetSize(); i ++)
|
|
if (obj->Children.Get(i)) RenderObject(obj->Children.Get(i),oMatrix,nMatrix);
|
|
}
|
|
if (!obj->Faces.GetSize() || !obj->Vertices.GetSize()) return;
|
|
|
|
plMatrixTranslate(tempMatrix, -X, -Y, -Z);
|
|
plMatrixMultiply(oMatrix,tempMatrix);
|
|
plMatrixMultiply(oMatrix,CamMatrix);
|
|
plMatrixMultiply(nMatrix,CamMatrix);
|
|
|
|
{
|
|
pl_Vertex *vertex = obj->Vertices.Get();
|
|
int i = obj->Vertices.GetSize();
|
|
|
|
while (i--)
|
|
{
|
|
MACRO_plMatrixApply(oMatrix,vertex->x,vertex->y,vertex->z,
|
|
vertex->xformedx, vertex->xformedy, vertex->xformedz);
|
|
MACRO_plMatrixApply(nMatrix,vertex->nx,vertex->ny,vertex->nz,
|
|
vertex->xformednx,vertex->xformedny,vertex->xformednz);
|
|
vertex++;
|
|
}
|
|
}
|
|
|
|
if (_faces.GetSize() < _numfaces + obj->Faces.GetSize()) _faces.Resize(_numfaces + obj->Faces.GetSize());
|
|
|
|
|
|
_faceInfo *facelistout = _faces.Get() + _numfaces;
|
|
|
|
pl_Face *face = obj->Faces.Get();
|
|
int facecnt = obj->Faces.GetSize();
|
|
|
|
RenderTrisIn += facecnt;
|
|
_numfaces += facecnt;
|
|
pl_Vertex *vlist = obj->Vertices.Get();
|
|
|
|
while (facecnt--)
|
|
{
|
|
double nx,ny,nz;
|
|
pl_Mat *mat=face->Material;
|
|
if (mat->BackfaceCull || (mat->Lightable && !mat->Smoothing))
|
|
{
|
|
MACRO_plMatrixApply(nMatrix,face->nx,face->ny,face->nz,nx,ny,nz);
|
|
}
|
|
pl_Vertex *v0=vlist+face->VertexIndices[0];
|
|
pl_Vertex *v1=vlist+face->VertexIndices[1];
|
|
pl_Vertex *v2=vlist+face->VertexIndices[2];
|
|
|
|
if (!mat->BackfaceCull || (MACRO_plDotProduct(nx,ny,nz, v0->xformedx, v0->xformedy, v0->xformedz) < 0.0000001)) {
|
|
if (ClipNeeded(face,obj)) {
|
|
if (!mat->Smoothing && (mat->Lightable||mat->FadeDist)) {
|
|
pl_Float val[3];
|
|
memcpy(val,face->sLighting,3*sizeof(pl_Float));
|
|
if (mat->Lightable) {
|
|
_lightInfo *inf = _lights.Get();
|
|
int i=_numlights;
|
|
while (i--)
|
|
{
|
|
pl_Light *light = inf->light;
|
|
double lightsc=0.0;
|
|
if (light->Type & PL_LIGHT_POINT_ANGLE) {
|
|
double nx2 = inf->l[0] - v0->xformedx;
|
|
double ny2 = inf->l[1] - v0->xformedy;
|
|
double nz2 = inf->l[2] - v0->xformedz;
|
|
MACRO_plNormalizeVector(nx2,ny2,nz2);
|
|
lightsc = MACRO_plDotProduct(nx,ny,nz,nx2,ny2,nz2);
|
|
}
|
|
if (light->Type & PL_LIGHT_POINT_DISTANCE) {
|
|
double nx2 = inf->l[0] - v0->xformedx;
|
|
double ny2 = inf->l[1] - v0->xformedy;
|
|
double nz2 = inf->l[2] - v0->xformedz;
|
|
if (light->Type & PL_LIGHT_POINT_ANGLE) {
|
|
nx2 = (1.0 - 0.5*((nx2*nx2+ny2*ny2+nz2*nz2)/
|
|
light->HalfDistSquared));
|
|
lightsc *= plMax(0,plMin(1.0,nx2));
|
|
} else {
|
|
lightsc = (1.0 - 0.5*((nx2*nx2+ny2*ny2+nz2*nz2)/
|
|
light->HalfDistSquared));
|
|
lightsc = plMax(0,plMin(1.0,lightsc));
|
|
}
|
|
}
|
|
if (light->Type == PL_LIGHT_VECTOR)
|
|
lightsc = MACRO_plDotProduct(nx,ny,nz,inf->l[0],inf->l[1],inf->l[2]);
|
|
|
|
if (lightsc>0.0)
|
|
{
|
|
val[0] += light->Intensity[0]*lightsc;
|
|
val[1] += light->Intensity[1]*lightsc;
|
|
val[2] += light->Intensity[2]*lightsc;
|
|
}
|
|
else if (mat->BackfaceIllumination)
|
|
{
|
|
val[0] -= light->Intensity[0]*lightsc*mat->BackfaceIllumination;
|
|
val[1] -= light->Intensity[1]*lightsc*mat->BackfaceIllumination;
|
|
val[2] -= light->Intensity[2]*lightsc*mat->BackfaceIllumination;
|
|
}
|
|
inf++;
|
|
} /* End of light loop */
|
|
} /* End of flat shading if */
|
|
|
|
if (mat->FadeDist)
|
|
{
|
|
double lightsc = 1.0 - (v0->xformedz+v1->xformedz+v2->xformedz) / (mat->FadeDist*3.0);
|
|
if (lightsc<0.0) lightsc=0.0;
|
|
else if (lightsc>1.0)lightsc=1.0;
|
|
if (mat->Lightable)
|
|
{
|
|
val[0] *= lightsc;
|
|
val[1] *= lightsc;
|
|
val[2] *= lightsc;
|
|
}
|
|
else
|
|
{
|
|
val[0]+=lightsc;
|
|
val[1]+=lightsc;
|
|
val[2]+=lightsc;
|
|
}
|
|
}
|
|
face->Shades[0][0]=mat->Ambient[0] + mat->Diffuse[0]*val[0];
|
|
face->Shades[0][1]=mat->Ambient[1] + mat->Diffuse[1]*val[1];
|
|
face->Shades[0][2]=mat->Ambient[2] + mat->Diffuse[2]*val[2];
|
|
}
|
|
else memcpy(face->Shades,mat->Ambient,sizeof(mat->Ambient)); // flat shading
|
|
|
|
if ((mat->Texture && mat->TexMapIdx<0)||(mat->Texture2 && mat->Tex2MapIdx<0)) {
|
|
face->MappingU[PLUSH_MAX_MAPCOORDS-1][0] = 0.5 + (v0->xformednx);
|
|
face->MappingV[PLUSH_MAX_MAPCOORDS-1][0] = 0.5 - (v0->xformedny);
|
|
face->MappingU[PLUSH_MAX_MAPCOORDS-1][1] = 0.5 + (v1->xformednx);
|
|
face->MappingV[PLUSH_MAX_MAPCOORDS-1][1] = 0.5 - (v1->xformedny);
|
|
face->MappingU[PLUSH_MAX_MAPCOORDS-1][2] = 0.5 + (v2->xformednx);
|
|
face->MappingV[PLUSH_MAX_MAPCOORDS-1][2] = 0.5 - (v2->xformedny);
|
|
}
|
|
|
|
if (mat->Smoothing && (mat->Lightable || mat->FadeDist))
|
|
{
|
|
int a;
|
|
for (a = 0; a < 3; a ++) {
|
|
pl_Float val[3];
|
|
memcpy(val,face->vsLighting[a],sizeof(val));
|
|
pl_Vertex *thisvert = obj->Vertices.Get()+face->VertexIndices[a];
|
|
|
|
if (mat->Lightable)
|
|
{
|
|
int i=_numlights;
|
|
_lightInfo *inf = _lights.Get();
|
|
while (i--)
|
|
{
|
|
double lightsc = 0.0;
|
|
pl_Light *light = inf->light;
|
|
if (light->Type & PL_LIGHT_POINT_ANGLE) {
|
|
double nx2 = inf->l[0] - thisvert->xformedx;
|
|
double ny2 = inf->l[1] - thisvert->xformedy;
|
|
double nz2 = inf->l[2] - thisvert->xformedz;
|
|
MACRO_plNormalizeVector(nx2,ny2,nz2);
|
|
lightsc = MACRO_plDotProduct(thisvert->xformednx,
|
|
thisvert->xformedny,
|
|
thisvert->xformednz,
|
|
nx2,ny2,nz2);
|
|
}
|
|
if (light->Type & PL_LIGHT_POINT_DISTANCE) {
|
|
double nx2 = inf->l[0] - thisvert->xformedx;
|
|
double ny2 = inf->l[1] - thisvert->xformedy;
|
|
double nz2 = inf->l[2] - thisvert->xformedz;
|
|
if (light->Type & PL_LIGHT_POINT_ANGLE) {
|
|
double t= (1.0 - 0.5*((nx2*nx2+ny2*ny2+nz2*nz2)/light->HalfDistSquared));
|
|
lightsc *= plMax(0,plMin(1.0,t));
|
|
} else {
|
|
lightsc = (1.0 - 0.5*((nx2*nx2+ny2*ny2+nz2*nz2)/light->HalfDistSquared));
|
|
lightsc = plMax(0,plMin(1.0,lightsc));
|
|
}
|
|
}
|
|
|
|
if (light->Type == PL_LIGHT_VECTOR)
|
|
lightsc = MACRO_plDotProduct(thisvert->xformednx,
|
|
thisvert->xformedny,
|
|
thisvert->xformednz,
|
|
inf->l[0],inf->l[1],inf->l[2]);
|
|
if (lightsc > 0.0)
|
|
{
|
|
val[0] += lightsc * light->Intensity[0];
|
|
val[1] += lightsc * light->Intensity[1];
|
|
val[2] += lightsc * light->Intensity[2];
|
|
}
|
|
else if (mat->BackfaceIllumination)
|
|
{
|
|
val[0] -= lightsc * light->Intensity[0]*mat->BackfaceIllumination;
|
|
val[1] -= lightsc * light->Intensity[1]*mat->BackfaceIllumination;
|
|
val[2] -= lightsc * light->Intensity[2]*mat->BackfaceIllumination;
|
|
}
|
|
inf++;
|
|
} /* End of light loop */
|
|
} /* End of gouraud shading if */
|
|
if (mat->FadeDist)
|
|
{
|
|
double lightsc = 1.0-thisvert->xformedz/mat->FadeDist;
|
|
if (lightsc<0.0) lightsc=0.0;
|
|
else if (lightsc>1.0)lightsc=1.0;
|
|
if (mat->Lightable)
|
|
{
|
|
val[0] *= lightsc;
|
|
val[1] *= lightsc;
|
|
val[2] *= lightsc;
|
|
}
|
|
else
|
|
{
|
|
val[0] += lightsc;
|
|
val[1] += lightsc;
|
|
val[2] += lightsc;
|
|
}
|
|
}
|
|
face->Shades[a][0] = mat->Ambient[0] + mat->Diffuse[0]*val[0];
|
|
face->Shades[a][1] = mat->Ambient[1] + mat->Diffuse[1]*val[1];
|
|
face->Shades[a][2] = mat->Ambient[2] + mat->Diffuse[2]*val[2];
|
|
} /* End of vertex loop for */
|
|
} /* End of gouraud shading mask if */
|
|
else // flat modes, shade all vertices
|
|
{
|
|
memcpy(&face->Shades[1][0],&face->Shades[0][0],sizeof(pl_Float)*3);
|
|
memcpy(&face->Shades[2][0],&face->Shades[0][0],sizeof(pl_Float)*3);
|
|
}
|
|
|
|
facelistout->zd = v0->xformedz+v1->xformedz+v2->xformedz;
|
|
facelistout->obj=obj;
|
|
facelistout->face = face;
|
|
facelistout++;
|
|
|
|
|
|
RenderTrisCulled++;
|
|
|
|
} /* Is it in our area Check */
|
|
} /* Backface Check */
|
|
face++;
|
|
}
|
|
_numfaces = facelistout-_faces.Get();
|
|
}
|
|
void pl_Cam::SortToCurrent()
|
|
{
|
|
if (Sort && _numfaces > _numfaces_sorted+1)
|
|
{
|
|
WDL_mergesort(_faces.Get()+_numfaces_sorted,
|
|
_numfaces-_numfaces_sorted,sizeof(_faceInfo),
|
|
Sort > 0 ? sortFwdFunc : sortRevFunc,
|
|
(char*)_sort_tmpspace.Resize((_numfaces-_numfaces_sorted)*sizeof(_faceInfo),false));
|
|
}
|
|
_numfaces_sorted=_numfaces;
|
|
}
|
|
|
|
int pl_Cam::sortRevFunc(const void *a, const void *b)
|
|
{
|
|
_faceInfo *aa = (_faceInfo*)a;
|
|
_faceInfo *bb = (_faceInfo*)b;
|
|
|
|
if (aa->zd < bb->zd) return -1;
|
|
if (aa->zd > bb->zd) return 1;
|
|
return 0;
|
|
}
|
|
|
|
int pl_Cam::sortFwdFunc(const void *a, const void *b)
|
|
{
|
|
_faceInfo *aa = (_faceInfo*)a;
|
|
_faceInfo *bb = (_faceInfo*)b;
|
|
|
|
if (aa->zd < bb->zd) return 1;
|
|
if (aa->zd > bb->zd) return -1;
|
|
return 0;
|
|
}
|
|
|
|
void pl_Cam::End() {
|
|
if (WDL_NOT_NORMALLY(!m_fBuffer.m_buf)) return;
|
|
|
|
SortToCurrent();
|
|
|
|
_faceInfo *f = _faces.Get();
|
|
int n=_numfaces;
|
|
while (n-->0)
|
|
{
|
|
if (f->face->Material)
|
|
{
|
|
ClipRenderFace(f->face,f->obj);
|
|
}
|
|
f++;
|
|
}
|
|
|
|
m_fBuffer.m_buf = NULL;
|
|
_numfaces=0;
|
|
_numlights = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
void pl_Light::Set(pl_uChar mode, pl_Float x, pl_Float y, pl_Float z, pl_Float intensity_r, pl_Float intensity_g, pl_Float intensity_b, pl_Float halfDist) {
|
|
pl_Float m[16], m2[16];
|
|
Type = mode;
|
|
Intensity[0] = intensity_r;
|
|
Intensity[1] = intensity_g;
|
|
Intensity[2] = intensity_b;
|
|
HalfDistSquared = halfDist*halfDist;
|
|
switch (mode) {
|
|
case PL_LIGHT_VECTOR:
|
|
plMatrixRotate(m,1,x);
|
|
plMatrixRotate(m2,2,y);
|
|
plMatrixMultiply(m,m2);
|
|
plMatrixRotate(m2,3,z);
|
|
plMatrixMultiply(m,m2);
|
|
plMatrixApply(m,0.0,0.0,-1.0,&Xp, &Yp, &Zp);
|
|
break;
|
|
case PL_LIGHT_POINT_ANGLE:
|
|
case PL_LIGHT_POINT_DISTANCE:
|
|
case PL_LIGHT_POINT:
|
|
Xp = x;
|
|
Yp = y;
|
|
Zp = z;
|
|
break;
|
|
}
|
|
}
|