Initial commit
This commit is contained in:
365
engines/icb/shadow_pc.cpp
Normal file
365
engines/icb/shadow_pc.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* Additional copyright for this file:
|
||||
* Copyright (C) 1999-2000 Revolution Software Ltd.
|
||||
* This code is based on source code created by Revolution Software,
|
||||
* used with permission.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/icb/common/px_common.h"
|
||||
#include "engines/icb/debug.h"
|
||||
#include "engines/icb/shadow_pc.h"
|
||||
#include "engines/icb/softskin_pc.h"
|
||||
#include "engines/icb/drawpoly_pc.h"
|
||||
#include "engines/icb/global_objects_psx.h"
|
||||
#include "engines/icb/actor_pc.h"
|
||||
#include "engines/icb/common/px_capri_maths.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
namespace ICB {
|
||||
|
||||
// 128 so then it fits into scratch pad !
|
||||
#define MAX_VECTORS 512
|
||||
#define MAX_SCRATCHPAD_VECTORS 128
|
||||
|
||||
int32 sverttpc;
|
||||
int32 st1pc;
|
||||
int32 st2pc;
|
||||
int32 st3pc;
|
||||
|
||||
void MakeShadowPC(RapAPI *srap, SVECTORPC *local, int32 nVertices, SVECTORPC *p_n, int32 p_d, SVECTORPC *ldir, CVECTOR *lcolour, MATRIXPC *world2screen, MATRIXPC *local2world,
|
||||
int32 debug, SVECTOR *bbox, SVECTOR *minbbox, SVECTOR *maxbbox, int16 xminLocal, int16 xmaxLocal, int16 yminLocal, int16 ymaxLocal, int16 zminLocal,
|
||||
int16 zmaxLocal);
|
||||
|
||||
void DrawShadow1PC(RapAPI *srap, int32 poseBone, MATRIXPC *lw, MATRIXPC *world2screen, MATRIXPC *local2world, int32 nShadows, SVECTORPC *ldirs, CVECTOR *lcolours, SVECTORPC *p_n,
|
||||
int32 *p_d, int32 debug, SVECTOR **shadowBox, SVECTOR *shadowBoxMin, SVECTOR *shadowBoxMax) {
|
||||
if (nShadows == 0)
|
||||
return;
|
||||
|
||||
SVECTORPC local[MAX_VECTORS];
|
||||
// compute the current animation positions of the
|
||||
// shadow mesh (rap) vertices
|
||||
|
||||
int16 xminLocal = +32767;
|
||||
int16 xmaxLocal = -32767;
|
||||
int16 yminLocal = +32767;
|
||||
int16 ymaxLocal = -32767;
|
||||
int16 zminLocal = +32767;
|
||||
int16 zmaxLocal = -32767;
|
||||
|
||||
sverttpc = g_system->getMillis();
|
||||
int32 screenScale = 0;
|
||||
int32 nVertices = softskinPC(srap, poseBone, lw, local, &xminLocal, &xmaxLocal, &yminLocal, &ymaxLocal, &zminLocal, &zmaxLocal, screenScale);
|
||||
|
||||
gte_SetScreenScaleShift_pc(screenScale);
|
||||
|
||||
// So all the local positions have been made
|
||||
sverttpc = g_system->getMillis() - sverttpc;
|
||||
|
||||
int32 s;
|
||||
SVECTORPC *pp_n = p_n;
|
||||
int32 *pp_d = p_d;
|
||||
SVECTORPC *pldirs = ldirs;
|
||||
CVECTOR *plcolours = lcolours;
|
||||
for (s = 0; s < nShadows; s++) {
|
||||
MakeShadowPC(srap, local, nVertices, pp_n, *pp_d, pldirs, plcolours, world2screen, local2world, debug, shadowBox[s], shadowBoxMin + s, shadowBoxMax + s, xminLocal,
|
||||
xmaxLocal, yminLocal, ymaxLocal, zminLocal, zmaxLocal);
|
||||
pldirs++;
|
||||
plcolours++;
|
||||
}
|
||||
}
|
||||
|
||||
void MakeShadowPC(RapAPI *srap, SVECTORPC *local, int32 nVertices, SVECTORPC *p_n, int32 p_d, SVECTORPC *ldir, CVECTOR *lcolour, MATRIXPC *world2screen, MATRIXPC *local2world,
|
||||
int32 debug, SVECTOR *bbox, SVECTOR *minbbox, SVECTOR *maxbbox, int16 xminLocal, int16 xmaxLocal, int16 yminLocal, int16 ymaxLocal, int16 zminLocal,
|
||||
int16 zmaxLocal) {
|
||||
|
||||
SVECTORPC workVerts[MAX_VECTORS];
|
||||
SVECTORPC *vertices = nullptr;
|
||||
|
||||
vertices = workVerts;
|
||||
|
||||
/*
|
||||
Make the shadow projection matrix
|
||||
|
||||
projection equation is:
|
||||
P = V + ( D - V.N ) L
|
||||
- - - - -
|
||||
|
||||
Where:
|
||||
P = is the projection point of vertex V
|
||||
V = vertex to be projected
|
||||
N = normal vector of the plane to project onto
|
||||
(doesn't have to be normalised)
|
||||
D = 'd' in the plane equation of the plane to project onto
|
||||
i.e. D = N.(point_plane)
|
||||
L = normalised light direction
|
||||
= L_direction / (L_direction . N )
|
||||
|
||||
|
||||
This expands into the following "rotation" matrix:
|
||||
|
||||
/ \
|
||||
| (1 - Nx*Lx) -Ny*Lx -Nz*Lx |
|
||||
| |
|
||||
| -Nx*Ly (1 - Ny*Ly) -Nz*Ly |
|
||||
| |
|
||||
| -Nx*Lz -Ny*Lz (1 - Nz*Lz) |
|
||||
\ /
|
||||
|
||||
and "transformation" matrix
|
||||
|
||||
/ \
|
||||
| +Lx*D |
|
||||
| |
|
||||
| +Ly*D |
|
||||
| |
|
||||
| +Lz*D |
|
||||
\ /
|
||||
*/
|
||||
|
||||
st1pc = g_system->getMillis();
|
||||
// First-up let us make normalised_light_direction
|
||||
int32 ld = p_n->vx * ldir->vx + p_n->vy * ldir->vy + p_n->vz * ldir->vz;
|
||||
|
||||
// Can't do a shadow if ld == 0 : light perpendicular to the plane
|
||||
if (ld == 0)
|
||||
return;
|
||||
|
||||
// To match names in the comments
|
||||
int32 D;
|
||||
SVECTORPC *N;
|
||||
SVECTORPC L;
|
||||
int32 work;
|
||||
|
||||
D = p_d;
|
||||
N = p_n;
|
||||
// * 4096 to get some fixed point accuracy in there!
|
||||
work = (ldir->vx << 12) / ld;
|
||||
if (work > 32767)
|
||||
work = 32767;
|
||||
if (work < -32767)
|
||||
work = -32767;
|
||||
L.vx = (int32)work;
|
||||
work = (ldir->vy << 12) / ld;
|
||||
if (work > 32767)
|
||||
work = 32767;
|
||||
if (work < -32767)
|
||||
work = -32767;
|
||||
L.vy = (int32)work;
|
||||
work = (ldir->vz << 12) / ld;
|
||||
if (work > 32767)
|
||||
work = 32767;
|
||||
if (work < -32767)
|
||||
work = -32767;
|
||||
L.vz = (int32)work;
|
||||
|
||||
MATRIXPC sproj;
|
||||
|
||||
// | (1 - Nx*Lx) -Ny*Lx -Nz*Lx |
|
||||
sproj.m[0][0] = (int32)(4096 - N->vx * L.vx);
|
||||
sproj.m[0][1] = (int32)(-N->vy * L.vx);
|
||||
sproj.m[0][2] = (int32)(-N->vz * L.vx);
|
||||
|
||||
// | -Nx*Ly (1 - Ny*Ly) -Nz*Ly |
|
||||
sproj.m[1][0] = (int32)(-N->vx * L.vy);
|
||||
sproj.m[1][1] = (int32)(4096 - N->vy * L.vy);
|
||||
sproj.m[1][2] = (int32)(-N->vz * L.vy);
|
||||
|
||||
// | -Nx*Lz -Ny*Lz (1 - Nz*Lz) |
|
||||
sproj.m[2][0] = (int32)(-N->vx * L.vz);
|
||||
sproj.m[2][1] = (int32)(-N->vy * L.vz);
|
||||
sproj.m[2][2] = (int32)(4096 - N->vz * L.vz);
|
||||
|
||||
// | +Lx*D |
|
||||
sproj.t[0] = (L.vx * D) >> 12; // go back to integer maths not fixed point
|
||||
|
||||
// | +Ly*D |
|
||||
sproj.t[1] = (L.vy * D) >> 12; // go back to integer maths not fixed point
|
||||
|
||||
// | +Lz*D |
|
||||
sproj.t[2] = (L.vz * D) >> 12; // go back to integer maths not fixed point
|
||||
|
||||
st1pc = g_system->getMillis() - st1pc;
|
||||
st2pc = g_system->getMillis();
|
||||
|
||||
SVECTORPC *world = vertices;
|
||||
SVECTORPC *pvert = vertices;
|
||||
|
||||
int32 flag;
|
||||
SVECTORPC *pworld;
|
||||
SVECTORPC *plocal;
|
||||
SVECTOR *pbbox;
|
||||
|
||||
plocal = local;
|
||||
pworld = world;
|
||||
VECTOR lpvert;
|
||||
int32 i;
|
||||
|
||||
// Transform the local vertices into world vertices
|
||||
gte_SetRotMatrix_pc(local2world);
|
||||
gte_SetTransMatrix_pc(local2world);
|
||||
for (i = 0; i < nVertices; i++) {
|
||||
gte_RotTrans_pc(plocal, &lpvert, &flag);
|
||||
pworld->vx = (int32)lpvert.vx;
|
||||
pworld->vy = (int32)lpvert.vy;
|
||||
pworld->vz = (int32)lpvert.vz;
|
||||
plocal++;
|
||||
pworld++;
|
||||
}
|
||||
|
||||
// Convert the bounding box from local co-ordinates into world co-ordinates
|
||||
bbox[0].vx = xminLocal;
|
||||
bbox[0].vy = yminLocal;
|
||||
bbox[0].vz = zminLocal;
|
||||
|
||||
bbox[1].vx = xminLocal;
|
||||
bbox[1].vy = yminLocal;
|
||||
bbox[1].vz = zmaxLocal;
|
||||
|
||||
bbox[2].vx = xmaxLocal;
|
||||
bbox[2].vy = yminLocal;
|
||||
bbox[2].vz = zminLocal;
|
||||
|
||||
bbox[3].vx = xmaxLocal;
|
||||
bbox[3].vy = yminLocal;
|
||||
bbox[3].vz = zmaxLocal;
|
||||
|
||||
bbox[4].vx = xmaxLocal;
|
||||
bbox[4].vy = ymaxLocal;
|
||||
bbox[4].vz = zminLocal;
|
||||
|
||||
bbox[5].vx = xmaxLocal;
|
||||
bbox[5].vy = ymaxLocal;
|
||||
bbox[5].vz = zmaxLocal;
|
||||
|
||||
bbox[6].vx = xminLocal;
|
||||
bbox[6].vy = ymaxLocal;
|
||||
bbox[6].vz = zminLocal;
|
||||
|
||||
bbox[7].vx = xminLocal;
|
||||
bbox[7].vy = ymaxLocal;
|
||||
bbox[7].vz = zmaxLocal;
|
||||
|
||||
pbbox = bbox;
|
||||
for (i = 0; i < 8; i++) {
|
||||
gte_RotTrans_pc(pbbox, &lpvert, &flag);
|
||||
pbbox->vx = (int16)lpvert.vx;
|
||||
pbbox->vy = (int16)lpvert.vy;
|
||||
pbbox->vz = (int16)lpvert.vz;
|
||||
pbbox++;
|
||||
}
|
||||
|
||||
// So basically do a load of RotTrans to project the world vertices
|
||||
// into a new set of world vertices
|
||||
gte_SetRotMatrix_pc(&sproj);
|
||||
gte_SetTransMatrix_pc(&sproj);
|
||||
SVECTORPC *ppvert;
|
||||
plocal = world;
|
||||
ppvert = pvert;
|
||||
|
||||
for (i = 0; i < nVertices; i++) {
|
||||
gte_RotTrans_pc(plocal, &lpvert, &flag);
|
||||
ppvert->vx = lpvert.vx;
|
||||
ppvert->vy = lpvert.vy;
|
||||
ppvert->vz = lpvert.vz;
|
||||
|
||||
plocal++;
|
||||
ppvert++;
|
||||
}
|
||||
|
||||
// Do the same for the bounding box
|
||||
pbbox = bbox;
|
||||
for (i = 0; i < 8; i++) {
|
||||
gte_RotTrans_pc(pbbox, &lpvert, &flag);
|
||||
pbbox->vx = (int16)lpvert.vx;
|
||||
pbbox->vy = (int16)lpvert.vy;
|
||||
pbbox->vz = (int16)lpvert.vz;
|
||||
pbbox++;
|
||||
}
|
||||
|
||||
// Put the correct rot and trans matrix in place
|
||||
// transform vertices from world space to screen space
|
||||
gte_SetRotMatrix_pc(world2screen);
|
||||
gte_SetTransMatrix_pc(world2screen);
|
||||
|
||||
// Loop over the vector pool converting them all to screen co-ordinates
|
||||
int32 p;
|
||||
if (debug == 0)
|
||||
ConvertToScreenCoords(pvert, pvert, nVertices);
|
||||
|
||||
// Do the same for the bounding box
|
||||
pbbox = bbox;
|
||||
SVECTORPC sxy0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
gte_RotTransPers_pc(pbbox, &sxy0, &p, &flag, (int32 *)&(pbbox->vz));
|
||||
pbbox->vx = (int16)sxy0.vx;
|
||||
pbbox->vy = (int16)sxy0.vy;
|
||||
pbbox++;
|
||||
}
|
||||
|
||||
// Find the minimum and maximum screen positions (plus z)
|
||||
pbbox = bbox;
|
||||
copyVector(minbbox, pbbox);
|
||||
copyVector(maxbbox, pbbox);
|
||||
pbbox++;
|
||||
for (i = 1; i < 8; i++, pbbox++) {
|
||||
if (pbbox->vx < minbbox->vx)
|
||||
minbbox->vx = pbbox->vx;
|
||||
if (pbbox->vy < minbbox->vy)
|
||||
minbbox->vy = pbbox->vy;
|
||||
if (pbbox->vz < minbbox->vz)
|
||||
minbbox->vz = pbbox->vz;
|
||||
if (pbbox->vx > maxbbox->vx)
|
||||
maxbbox->vx = pbbox->vx;
|
||||
if (pbbox->vy > maxbbox->vy)
|
||||
maxbbox->vy = pbbox->vy;
|
||||
if (pbbox->vz > maxbbox->vz)
|
||||
maxbbox->vz = pbbox->vz;
|
||||
}
|
||||
|
||||
st2pc = g_system->getMillis() - st2pc;
|
||||
st3pc = g_system->getMillis();
|
||||
|
||||
// Now draw the little blighters
|
||||
unlitPoly.r = lcolour->r;
|
||||
unlitPoly.g = lcolour->g;
|
||||
unlitPoly.b = lcolour->b;
|
||||
unlitPoly.cd = 0x80; // Switch to 0x80 for subtractive once the dutch are fixed.
|
||||
|
||||
// Now go and find the actual polygon data for this primitive
|
||||
uint32 *polyStart;
|
||||
uint32 nPolys;
|
||||
|
||||
nPolys = srap->nTRI3;
|
||||
if (nPolys != 0) {
|
||||
polyStart = RapAPIObject::GetTRI3Ptr(srap);
|
||||
// Do the drawing using internal C based debugging drawing code
|
||||
if (debug) {
|
||||
drawTRI3PC(polyStart, nPolys, pvert);
|
||||
} else {
|
||||
fastDrawTRI3PC(polyStart, nPolys, pvert);
|
||||
}
|
||||
}
|
||||
st3pc = g_system->getMillis() - st3pc;
|
||||
}
|
||||
|
||||
} // End of namespace ICB
|
||||
Reference in New Issue
Block a user