REDRIVER2/src_rebuild/Game/C/tile.c

481 lines
10 KiB
C

#include "driver2.h"
#include "models.h"
#include "system.h"
#include "mission.h"
#include "draw.h"
#include "texture.h"
#include "tile.h"
#include "ASM/rndrasm.h"
// [D] [T] [A]
void Tile1x1(MODEL *model)
{
int opz, Z;
int ofse;
PL_POLYFT4* polys;
int i;
u_char ptype;
POLY_FT4* prims;
SVECTOR* srcVerts;
srcVerts = (SVECTOR*)model->vertices;
polys = (PL_POLYFT4*)model->poly_block;
// grass should be under pavements and other things
if ((model->shape_flags & SHAPE_FLAG_WATER) || (model->flags2 & MODEL_FLAG_GRASS))
ofse = 229;
else
ofse = 133;
#ifdef USE_PGXP
PGXP_SetZOffsetScale(0.0f, ofse > 200 ? 1.005f : 0.995f);
#endif
i = model->num_polys;
while (i-- > 0)
{
// iterate through polygons
// with skipping
ptype = polys->id & 0x1f;
// perform transform
gte_ldv3(&srcVerts[polys->v0], &srcVerts[polys->v1], &srcVerts[polys->v3]);
gte_rtpt();
// get culling value
gte_nclip();
gte_stopz(&opz);
if (opz > 0)
{
prims = (POLY_FT4*)plotContext.primptr;
setPolyFT4(prims);
*(ulong*)&prims->r0 = plotContext.colour;
// retrieve first three verts
gte_stsxy3(&prims->x0, &prims->x1, &prims->x2);
// translate 4th vert and get OT Z value
gte_ldv0(&srcVerts[polys->v2]);
gte_rtps();
gte_avsz4();
gte_stotz(&Z);
gte_stsxy(&prims->x3);
prims->tpage = (*plotContext.ptexture_pages)[polys->texture_set];
prims->clut = (*plotContext.ptexture_cluts)[polys->texture_set][polys->texture_id];
*(ushort*)&prims->u0 = *(ushort*)&polys->uv0;
*(ushort*)&prims->u1 = *(ushort*)&polys->uv1;
*(ushort*)&prims->u2 = *(ushort*)&polys->uv3;
*(ushort*)&prims->u3 = *(ushort*)&polys->uv2;
addPrim(plotContext.ot + (Z >> 1) + ofse, prims);
plotContext.primptr += sizeof(POLY_FT4);
}
polys = (PL_POLYFT4*)((char*)polys + plotContext.polySizes[ptype]);
}
#ifdef USE_PGXP
PGXP_SetZOffsetScale(0.0f, 1.0f);
#endif
// done
plotContext.current->primptr = plotContext.primptr;
}
// [D] [T]
void DrawTILES(PACKED_CELL_OBJECT** tiles, int tile_amount)
{
MODEL* pModel;
PACKED_CELL_OBJECT *ppco;
PACKED_CELL_OBJECT** tilePointers;
int previous_matrix, yang, dofse, Z;
int model_number;
if (gTimeOfDay > -1)
{
if (gTimeOfDay < 3)
{
plotContext.colour = combointensity & 0xffffffU | 0x2C000000;
}
else if (gTimeOfDay == 3)
{
plotContext.colour = ((combointensity >> 16 & 255) / 3) << 16 | ((combointensity >> 8 & 255) / 3) << 8 | (combointensity & 255) / 3 | 0x2C000000U;
}
}
previous_matrix = -1;
if (gWeather - 1U < 2)
{
u_int col;
col = plotContext.colour >> 2 & 0x3f;
plotContext.colour = col * 0x30000 | col * 0x300 | col * 3 | 0x2C000000;
}
plotContext.ot = current->ot;
plotContext.current = current;
plotContext.primptr = current->primptr;
plotContext.ptexture_pages = (ushort(*)[128])texture_pages;
plotContext.ptexture_cluts = (ushort(*)[128][32])texture_cluts;
plotContext.lastTexInfo = 0x18273472;
plotContext.flags = 0;
plotContext.polySizes = PolySizes;
tilePointers = (PACKED_CELL_OBJECT **)tiles;
while (tile_amount--)
{
ppco = *tilePointers++;
plotContext.f4colourTable[6] = ppco->pos.vx;
plotContext.f4colourTable[7] = (ppco->pos.vy << 0x10) >> 0x11;
plotContext.f4colourTable[8] = ppco->pos.vz;
yang = ppco->value & 0x3f;
model_number = (ppco->value >> 6) | (ppco->pos.vy & 1) << 10;
if (previous_matrix == yang)
{
Z = Apply_InvCameraMatrixSetTrans((VECTOR_NOPAD *)(plotContext.f4colourTable + 6));
}
else
{
Z = Apply_InvCameraMatrixAndSetMatrix((VECTOR_NOPAD *)(plotContext.f4colourTable + 6), &CompoundMatrix[previous_matrix = yang]);
}
if (Z <= DRAW_LOD_DIST_HIGH)
{
if (Low2HighDetailTable[model_number] != 0xffff)
model_number = Low2HighDetailTable[model_number];
pModel = modelpointers[model_number];
if (Z < 2000)
TileNxN(pModel, 4, 75);
else
TileNxN(pModel, 2, 35);
}
else
{
pModel = Z > DRAW_LOD_DIST_LOW ? pLodModels[model_number] : modelpointers[model_number];
Tile1x1(pModel);
}
}
current->primptr = plotContext.primptr;
}
// [A] custom implemented function
void makeMesh(MVERTEX(*VSP)[5][5], int m, int n)
{
/* vertices by index in quad:
3---------2
| |
| |
| |
0---------1
*/
// 0 3 2 1
// do subdivision
MVERTEX v1, v2, v3, v4;
MVERTEX e1, e2, e3, e4, e5;
MVERTEX p1, p2, p3, p4, p5;
if (n < 2)
return;
#if 0
// no need to subdivide!
if (g_pgxpZBuffer)
return;
#endif
v1 = (*VSP)[0][0];
v2 = (*VSP)[0][1];
v3 = (*VSP)[0][3];
v4 = (*VSP)[0][2];
VecSubtract(&e1, &v2, &v1); // plane[1] - plane[0];
e1.uv.s.u0 = (v2.uv.s.u0 - v1.uv.s.u0) / 2;
e1.uv.s.v0 = (v2.uv.s.v0 - v1.uv.s.v0) / 2;
VecSubtract(&e2, &v3, &v4); // plane[2] - plane[3];
e2.uv.s.u0 = (v3.uv.s.u0 - v4.uv.s.u0) / 2;
e2.uv.s.v0 = (v3.uv.s.v0 - v4.uv.s.v0) / 2;
VecSubtract(&e3, &v4, &v1); // plane[3] - plane[0];
e3.uv.s.u0 = (v4.uv.s.u0 - v1.uv.s.u0) / 2;
e3.uv.s.v0 = (v4.uv.s.v0 - v1.uv.s.v0) / 2;
VecSubtract(&e4, &v3, &v2); // plane[2] - plane[1];
e4.uv.s.u0 = (v3.uv.s.u0 - v2.uv.s.u0) / 2;
e4.uv.s.v0 = (v3.uv.s.v0 - v2.uv.s.v0) / 2;
//-----------
// half them all
SetVec(&e1, e1.vx / 2, e1.vy / 2, e1.vz / 2);
SetVec(&e2, e2.vx / 2, e2.vy / 2, e2.vz / 2);
SetVec(&e3, e3.vx / 2, e3.vy / 2, e3.vz / 2);
SetVec(&e4, e4.vx / 2, e4.vy / 2, e4.vz / 2);
//-----------
VecAdd(&p1, &e1, &v1); // e1 * 0.5f + plane[0];
p1.uv.s.u0 = e1.uv.s.u0 + v1.uv.s.u0;
p1.uv.s.v0 = e1.uv.s.v0 + v1.uv.s.v0;
VecAdd(&p2, &e2, &v4); // e2 * 0.5f + plane[3];
p2.uv.s.u0 = e2.uv.s.u0 + v4.uv.s.u0;
p2.uv.s.v0 = e2.uv.s.v0 + v4.uv.s.v0;
VecAdd(&p3, &e3, &v1); // e3 * 0.5f + plane[0];
p3.uv.s.u0 = e3.uv.s.u0 + v1.uv.s.u0;
p3.uv.s.v0 = e3.uv.s.v0 + v1.uv.s.v0;
VecAdd(&p4, &e4, &v2); // e4 * 0.5f + plane[1];
p4.uv.s.u0 = e4.uv.s.u0 + v2.uv.s.u0;
p4.uv.s.v0 = e4.uv.s.v0 + v2.uv.s.v0;
//-----------
VecSubtract(&e5, &p2, &p1); // p2 - p1;
e5.uv.s.u0 = (p2.uv.s.u0 - p1.uv.s.u0) / 2;
e5.uv.s.v0 = (p2.uv.s.v0 - p1.uv.s.v0) / 2;
SetVec(&e5, e5.vx / 2, e5.vy / 2, e5.vz / 2);
VecAdd(&p5, &e5, &p1); // e5 * 0.5f + p1;
p5.uv.s.u0 = e5.uv.s.u0 + p1.uv.s.u0;
p5.uv.s.v0 = e5.uv.s.v0 + p1.uv.s.v0;
//-----------
(*VSP)[0][0] = v1; // { plane[0], p1, p5, p3 },
(*VSP)[0][1] = p1;
(*VSP)[0][2] = p3;
(*VSP)[0][3] = p5;
(*VSP)[1][0] = p1; // { p1, plane[1], p4, p5 },
(*VSP)[1][1] = v2;
(*VSP)[1][2] = p5;
(*VSP)[1][3] = p4;
(*VSP)[2][0] = p5; // { p5, p4, plane[2], p2 },
(*VSP)[2][1] = p4;
(*VSP)[2][2] = p2;
(*VSP)[2][3] = v3;
(*VSP)[3][0] = p3; // { p3, p5, p2, plane[3] }
(*VSP)[3][1] = p5;
(*VSP)[3][2] = v4;
(*VSP)[3][3] = p2;
}
// [A] custom implemented function
void drawMesh(MVERTEX(*VSP)[5][5], int m, int n, _pct *pc)
{
POLY_FT4* prim;
int z, opz;
prim = (POLY_FT4*)pc->primptr;
int numPolys = 4;
if (n < 2)
numPolys = 1;
#if 0
// no need to subdivide!
if (g_pgxpZBuffer)
numPolys = 1;
#endif
for (int index = 0; index < numPolys; index++)
{
setPolyFT4(prim);
*(ulong*)&prim->r0 = pc->colour; // FIXME: semiTransparency support
// test
gte_ldv3(&(*VSP)[index][0], &(*VSP)[index][1], &(*VSP)[index][2]);
gte_rtpt();
gte_nclip();
gte_stopz(&opz);
gte_avsz3();
gte_stotz(&z);
if (pc->flags & (PLOT_NO_CULL | PLOT_INV_CULL))
{
if (pc->flags & PLOT_NO_CULL)
opz = 1; // no culling
else // PLOT_FRONT_CULL
opz = -opz; // front face
}
if (opz > 0 && z > 5)
{
gte_stsxy3(&prim->x0, &prim->x1, &prim->x2);
gte_ldv0(&(*VSP)[index][3]);
gte_rtps();
gte_stsxy(&prim->x3);
*(ushort*)&prim->u0 = (*VSP)[index][0].uv.val;
*(ushort*)&prim->u1 = (*VSP)[index][1].uv.val;
*(ushort*)&prim->u2 = (*VSP)[index][2].uv.val;
*(ushort*)&prim->u3 = (*VSP)[index][3].uv.val;
prim->clut = pc->clut >> 0x10;
prim->tpage = pc->tpage >> 0x10;
addPrim(pc->ot + (z >> 1), prim);
prim++;
}
}
pc->primptr = (char*)prim;
}
// [A] custom implemented function
void SubdivNxM(char *polys, int n, int m, int ofse)
{
MVERTEX subdivVerts[5][5];
SVECTOR* verts = plotContext.verts;
POLYFT4* pft4 = (POLYFT4*)polys;
plotContext.clut = (u_int)(*plotContext.ptexture_cluts)[pft4->texture_set][pft4->texture_id] << 0x10;
plotContext.tpage = (u_int)(*plotContext.ptexture_pages)[pft4->texture_set] << 0x10;
copyVector(&subdivVerts[0][0], &verts[pft4->v0]);
subdivVerts[0][0].uv.val = *(ushort*)&pft4->uv0;
copyVector(&subdivVerts[0][1], &verts[pft4->v1]);
subdivVerts[0][1].uv.val = *(ushort*)&pft4->uv1;
copyVector(&subdivVerts[0][2], &verts[pft4->v3]);
subdivVerts[0][2].uv.val = *(ushort*)&pft4->uv3;
copyVector(&subdivVerts[0][3], &verts[pft4->v2]);
subdivVerts[0][3].uv.val = *(ushort*)&pft4->uv2;
plotContext.ot += ofse;
makeMesh((MVERTEX(*)[5][5])subdivVerts, m, n);
drawMesh((MVERTEX(*)[5][5])subdivVerts, m, n, &plotContext);
plotContext.ot -= ofse;
}
// [D] [T]
void TileNxN(MODEL *model, int levels, int Dofse)
{
u_int ttype, tileTypes;
u_char *polys;
int i;
int ofse;
polys = (u_char *)model->poly_block;
plotContext.verts = (SVECTOR *)model->vertices;
// WEIRD: tile types comes right after model header it seems
tileTypes = *(u_int *)(model + 1) >> 2;
// grass should be under pavements and other things
if((model->shape_flags & SHAPE_FLAG_WATER) || (model->flags2 & MODEL_FLAG_GRASS))
ofse = 229;
else
ofse = 133;
int _m[5] = {
levels, levels, 0, 1, levels
};
int _ofse[5] = {
ofse, ofse, 0, Dofse, 133
};
i = model->num_polys;
ttype = 0;
while (i--)
{
#ifdef USE_PGXP
switch (ttype)
{
case 0:
case 1:
PGXP_SetZOffsetScale(0.0f, ofse > 200 ? 1.008f : 0.995f);
break;
case 3:
PGXP_SetZOffsetScale(0.0f, ofse < 40 ? 1.0f : 0.991f);
break;
case 4:
PGXP_SetZOffsetScale(0.0f, 1.0f);
break;
}
#endif
SubdivNxM((char*)polys, levels, _m[ttype], _ofse[ttype]);
ttype = tileTypes & 7;
tileTypes >>= 3;
polys += plotContext.polySizes[*polys];
}
#ifdef USE_PGXP
PGXP_SetZOffsetScale(0.0f, 1.0f);
#endif
}
void ProcessSubDivisionLump(char *lump_ptr, int lump_size)
{
// Driver 1 leftover...
UNIMPLEMENTED();
/*
SubDivisionArrays = lump_ptr;
return;*/
}
// [D] [T]
void ProcessLowDetailTable(char *lump_ptr, int lump_size)
{
int i;
Low2HighDetailTable = (ushort *)lump_ptr;
Low2LowerDetailTable = Low2HighDetailTable + num_models_in_pack;
for (i = 0; i < num_models_in_pack; i++)
{
if (Low2LowerDetailTable[i] != 0xFFFF)
pLodModels[i] = modelpointers[Low2LowerDetailTable[i]];
else
pLodModels[i] = modelpointers[i];
}
}