CCollision done and fixes

This commit is contained in:
aap 2020-07-27 15:38:34 +02:00
parent 5d266ace64
commit 6b7a8f96a6
7 changed files with 272 additions and 200 deletions

View file

@ -107,8 +107,11 @@ CCollision::LoadCollisionWhenINeedIt(bool forceChange)
void void
CCollision::SortOutCollisionAfterLoad(void) CCollision::SortOutCollisionAfterLoad(void)
{ {
CColStore::LoadCollision(TheCamera.GetPosition());
CStreaming::LoadAllRequestedModels(false);
} }
//--MIAMI: done
void void
CCollision::LoadCollisionScreen(eLevelName level) CCollision::LoadCollisionScreen(eLevelName level)
{ {
@ -251,7 +254,7 @@ CCollision::TestVerticalLineBox(const CColLine &line, const CBox &box)
} }
bool bool
CCollision::TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) CCollision::TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane)
{ {
float t; float t;
CVector normal; CVector normal;
@ -266,9 +269,9 @@ CCollision::TestLineTriangle(const CColLine &line, const CVector *verts, const C
// find point of intersection // find point of intersection
CVector p = line.p0 + (line.p1-line.p0)*t; CVector p = line.p0 + (line.p1-line.p0)*t;
const CVector &va = verts[tri.a]; const CVector &va = verts[tri.a].Get();
const CVector &vb = verts[tri.b]; const CVector &vb = verts[tri.b].Get();
const CVector &vc = verts[tri.c]; const CVector &vc = verts[tri.c].Get();
CVector2D vec1, vec2, vec3, vect; CVector2D vec1, vec2, vec3, vect;
// We do the test in 2D. With the plane direction we // We do the test in 2D. With the plane direction we
@ -361,15 +364,16 @@ CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph)
bool bool
CCollision::TestSphereTriangle(const CColSphere &sphere, CCollision::TestSphereTriangle(const CColSphere &sphere,
const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane)
{ {
// If sphere and plane don't intersect, no collision // If sphere and plane don't intersect, no collision
if(Abs(plane.CalcPoint(sphere.center)) > sphere.radius) float planedist = plane.CalcPoint(sphere.center);
if(Abs(planedist) > sphere.radius)
return false; return false;
const CVector &va = verts[tri.a]; const CVector &va = verts[tri.a].Get();
const CVector &vb = verts[tri.b]; const CVector &vb = verts[tri.b].Get();
const CVector &vc = verts[tri.c]; const CVector &vc = verts[tri.c].Get();
// calculate two orthogonal basis vectors for the triangle // calculate two orthogonal basis vectors for the triangle
CVector vec2 = vb - va; CVector vec2 = vb - va;
@ -393,28 +397,36 @@ CCollision::TestSphereTriangle(const CColSphere &sphere,
int testcase = insideAB + insideAC + insideBC; int testcase = insideAB + insideAC + insideBC;
float dist = 0.0f; float dist = 0.0f;
if(testcase == 1){ switch(testcase){
case 0:
return false; // shouldn't happen
case 1:
// closest to a vertex // closest to a vertex
if(insideAB) dist = (sphere.center - vc).Magnitude(); if(insideAB) dist = (sphere.center - vc).Magnitude();
else if(insideAC) dist = (sphere.center - vb).Magnitude(); else if(insideAC) dist = (sphere.center - vb).Magnitude();
else if(insideBC) dist = (sphere.center - va).Magnitude(); else if(insideBC) dist = (sphere.center - va).Magnitude();
else assert(0); else assert(0);
}else if(testcase == 2){ break;
case 2:
// closest to an edge // closest to an edge
// looks like original game as DistToLine manually inlined
if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center); if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center);
else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center); else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center);
else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center); else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center);
else assert(0); else assert(0);
}else if(testcase == 3){ break;
case 3:
// center is in triangle // center is in triangle
return true; dist = Abs(planedist);
}else break;
assert(0); // front fell off default:
assert(0);
}
return dist < sphere.radius; return dist < sphere.radius;
} }
//--MIAMI: TODO //--MIAMI: DONE
bool bool
CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough, bool ignoreShootThrough) CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough, bool ignoreShootThrough)
{ {
@ -429,25 +441,32 @@ CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColMod
if(!TestLineBox(newline, model.boundingBox)) if(!TestLineBox(newline, model.boundingBox))
return false; return false;
for(i = 0; i < model.numSpheres; i++) for(i = 0; i < model.numSpheres; i++){
if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_TRANSPARENT_CLOTH) if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue;
if(ignoreShootThrough && IsShootThrough(model.spheres[i].surface)) continue;
if(TestLineSphere(newline, model.spheres[i])) if(TestLineSphere(newline, model.spheres[i]))
return true; return true;
}
for(i = 0; i < model.numBoxes; i++) for(i = 0; i < model.numBoxes; i++){
if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_TRANSPARENT_CLOTH) if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue;
if(ignoreShootThrough && IsShootThrough(model.boxes[i].surface)) continue;
if(TestLineBox(newline, model.boxes[i])) if(TestLineBox(newline, model.boxes[i]))
return true; return true;
}
CalculateTrianglePlanes(&model); CalculateTrianglePlanes(&model);
for(i = 0; i < model.numTriangles; i++) for(i = 0; i < model.numTriangles; i++){
if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_TRANSPARENT_CLOTH) if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue;
if(ignoreShootThrough && IsShootThrough(model.triangles[i].surface)) continue;
if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i])) if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i]))
return true; return true;
}
return false; return false;
} }
// TODO: TestPillWithSpheresInColModel, but only called from overloaded CWeapon::FireMelee which isn't used
// //
// Process // Process
@ -716,18 +735,19 @@ CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CC
return true; return true;
} }
//--MIAMI: unused
bool bool
CCollision::ProcessVerticalLineTriangle(const CColLine &line, CCollision::ProcessVerticalLineTriangle(const CColLine &line,
const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane,
CColPoint &point, float &mindist, CStoredCollPoly *poly) CColPoint &point, float &mindist, CStoredCollPoly *poly)
{ {
float t; float t;
CVector normal; CVector normal;
const CVector &p0 = line.p0; const CVector &p0 = line.p0;
const CVector &va = verts[tri.a]; const CVector &va = verts[tri.a].Get();
const CVector &vb = verts[tri.b]; const CVector &vb = verts[tri.b].Get();
const CVector &vc = verts[tri.c]; const CVector &vc = verts[tri.c].Get();
// early out bound rect test // early out bound rect test
if(p0.x < va.x && p0.x < vb.x && p0.x < vc.x) return false; if(p0.x < va.x && p0.x < vb.x && p0.x < vc.x) return false;
@ -792,6 +812,7 @@ CCollision::ProcessVerticalLineTriangle(const CColLine &line,
if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false;
if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false;
if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false;
if(t >= mindist) return false;
point.point = p; point.point = p;
point.normal = normal; point.normal = normal;
point.surfaceA = 0; point.surfaceA = 0;
@ -817,16 +838,12 @@ CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CCol
return false; return false;
// maybe inlined? // maybe inlined?
CColTriangle tri;
tri.a = 0;
tri.b = 1;
tri.c = 2;
CColTrianglePlane plane; CColTrianglePlane plane;
plane.Set(poly->verts, tri); plane.Set(poly->verts[0], poly->verts[1], poly->verts[2]);
const CVector &va = poly->verts[tri.a]; const CVector &va = poly->verts[0];
const CVector &vb = poly->verts[tri.b]; const CVector &vb = poly->verts[1];
const CVector &vc = poly->verts[tri.c]; const CVector &vc = poly->verts[2];
CVector p0 = pos; CVector p0 = pos;
CVector p1(pos.x, pos.y, z); CVector p1(pos.x, pos.y, z);
@ -891,8 +908,8 @@ CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CCol
bool bool
CCollision::ProcessLineTriangle(const CColLine &line , CCollision::ProcessLineTriangle(const CColLine &line ,
const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane,
CColPoint &point, float &mindist) CColPoint &point, float &mindist, CStoredCollPoly *poly)
{ {
float t; float t;
CVector normal; CVector normal;
@ -910,9 +927,9 @@ CCollision::ProcessLineTriangle(const CColLine &line ,
// find point of intersection // find point of intersection
CVector p = line.p0 + (line.p1-line.p0)*t; CVector p = line.p0 + (line.p1-line.p0)*t;
const CVector &va = verts[tri.a]; const CVector &va = verts[tri.a].Get();
const CVector &vb = verts[tri.b]; const CVector &vb = verts[tri.b].Get();
const CVector &vc = verts[tri.c]; const CVector &vc = verts[tri.c].Get();
CVector2D vec1, vec2, vec3, vect; CVector2D vec1, vec2, vec3, vect;
switch(plane.dir){ switch(plane.dir){
@ -958,19 +975,26 @@ CCollision::ProcessLineTriangle(const CColLine &line ,
if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false;
if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false;
if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false;
if(t >= mindist) return false;
point.point = p; point.point = p;
point.normal = normal; point.normal = normal;
point.surfaceA = 0; point.surfaceA = 0;
point.pieceA = 0; point.pieceA = 0;
point.surfaceB = tri.surface; point.surfaceB = tri.surface;
point.pieceB = 0; point.pieceB = 0;
if(poly){
poly->verts[0] = va;
poly->verts[1] = vb;
poly->verts[2] = vc;
poly->valid = true;
}
mindist = t; mindist = t;
return true; return true;
} }
bool bool
CCollision::ProcessSphereTriangle(const CColSphere &sphere, CCollision::ProcessSphereTriangle(const CColSphere &sphere,
const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane,
CColPoint &point, float &mindistsq) CColPoint &point, float &mindistsq)
{ {
// If sphere and plane don't intersect, no collision // If sphere and plane don't intersect, no collision
@ -979,9 +1003,9 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere,
if(Abs(planedist) > sphere.radius || distsq > mindistsq) if(Abs(planedist) > sphere.radius || distsq > mindistsq)
return false; return false;
const CVector &va = verts[tri.a]; const CVector &va = verts[tri.a].Get();
const CVector &vb = verts[tri.b]; const CVector &vb = verts[tri.b].Get();
const CVector &vc = verts[tri.c]; const CVector &vc = verts[tri.c].Get();
// calculate two orthogonal basis vectors for the triangle // calculate two orthogonal basis vectors for the triangle
CVector normal; CVector normal;
@ -1008,25 +1032,33 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere,
int testcase = insideAB + insideAC + insideBC; int testcase = insideAB + insideAC + insideBC;
float dist = 0.0f; float dist = 0.0f;
CVector p; CVector p;
if(testcase == 1){ switch(testcase){
case 0:
return false; // shouldn't happen
case 1:
// closest to a vertex // closest to a vertex
if(insideAB) p = vc; if(insideAB) p = vc;
else if(insideAC) p = vb; else if(insideAC) p = vb;
else if(insideBC) p = va; else if(insideBC) p = va;
else assert(0); else assert(0);
dist = (sphere.center - p).Magnitude(); dist = (sphere.center - p).Magnitude();
}else if(testcase == 2){ break;
case 2:
// closest to an edge // closest to an edge
// looks like original game as DistToLine manually inlined
if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center, p); if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center, p);
else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center, p); else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center, p);
else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center, p); else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center, p);
else assert(0); else assert(0);
}else if(testcase == 3){ break;
case 3:
// center is in triangle // center is in triangle
dist = Abs(planedist); dist = Abs(planedist);
p = sphere.center - normal*planedist; p = sphere.center - normal*planedist;
}else break;
assert(0); // front fell off default:
assert(0);
}
if(dist >= sphere.radius || dist*dist >= mindistsq) if(dist >= sphere.radius || dist*dist >= mindistsq)
return false; return false;
@ -1061,18 +1093,24 @@ CCollision::ProcessLineOfSight(const CColLine &line,
return false; return false;
float coldist = mindist; float coldist = mindist;
for(i = 0; i < model.numSpheres; i++) for(i = 0; i < model.numSpheres; i++){
if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_TRANSPARENT_CLOTH) if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue;
if(ignoreShootThrough && IsShootThrough(model.spheres[i].surface)) continue;
ProcessLineSphere(newline, model.spheres[i], point, coldist); ProcessLineSphere(newline, model.spheres[i], point, coldist);
}
for(i = 0; i < model.numBoxes; i++) for(i = 0; i < model.numBoxes; i++){
if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_TRANSPARENT_CLOTH) if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue;
if(ignoreShootThrough && IsShootThrough(model.boxes[i].surface)) continue;
ProcessLineBox(newline, model.boxes[i], point, coldist); ProcessLineBox(newline, model.boxes[i], point, coldist);
}
CalculateTrianglePlanes(&model); CalculateTrianglePlanes(&model);
for(i = 0; i < model.numTriangles; i++) for(i = 0; i < model.numTriangles; i++){
if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_TRANSPARENT_CLOTH) if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue;
if(ignoreShootThrough && IsShootThrough(model.triangles[i].surface)) continue;
ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist); ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist);
}
if(coldist < mindist){ if(coldist < mindist){
point.point = matrix * point.point; point.point = matrix * point.point;
@ -1095,31 +1133,33 @@ CCollision::ProcessVerticalLine(const CColLine &line,
// transform line to model space // transform line to model space
// Why does the game seem to do this differently than above? // Why does the game seem to do this differently than above?
CColLine newline(MultiplyInverse(matrix, line.p0), MultiplyInverse(matrix, line.p1)); CColLine newline(MultiplyInverse(matrix, line.p0), MultiplyInverse(matrix, line.p1));
newline.p1.x = newline.p0.x;
newline.p1.y = newline.p0.y;
if(!TestVerticalLineBox(newline, model.boundingBox)) if(!TestLineBox(newline, model.boundingBox))
return false; return false;
// BUG? is IsSeeThroughVertical really the right thing? also not checking shoot through
float coldist = mindist; float coldist = mindist;
for(i = 0; i < model.numSpheres; i++) for(i = 0; i < model.numSpheres; i++){
if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_TRANSPARENT_CLOTH) if(ignoreSeeThrough && IsSeeThroughVertical(model.spheres[i].surface)) continue;
ProcessLineSphere(newline, model.spheres[i], point, coldist); ProcessLineSphere(newline, model.spheres[i], point, coldist);
}
for(i = 0; i < model.numBoxes; i++) for(i = 0; i < model.numBoxes; i++){
if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_TRANSPARENT_CLOTH) if(ignoreSeeThrough && IsSeeThroughVertical(model.boxes[i].surface)) continue;
ProcessLineBox(newline, model.boxes[i], point, coldist); ProcessLineBox(newline, model.boxes[i], point, coldist);
}
CalculateTrianglePlanes(&model); CalculateTrianglePlanes(&model);
TempStoredPoly.valid = false; TempStoredPoly.valid = false;
for(i = 0; i < model.numTriangles; i++) for(i = 0; i < model.numTriangles; i++){
if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_TRANSPARENT_CLOTH) if(ignoreSeeThrough && IsSeeThroughVertical(model.triangles[i].surface)) continue;
ProcessVerticalLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly); ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly);
}
if(coldist < mindist){ if(coldist < mindist){
point.point = matrix * point.point; point.point = matrix * point.point;
point.normal = Multiply3x3(matrix, point.normal); point.normal = Multiply3x3(matrix, point.normal);
if(poly && TempStoredPoly.valid){ if(TempStoredPoly.valid && poly){
*poly = TempStoredPoly; *poly = TempStoredPoly;
poly->verts[0] = matrix * poly->verts[0]; poly->verts[0] = matrix * poly->verts[0];
poly->verts[1] = matrix * poly->verts[1]; poly->verts[1] = matrix * poly->verts[1];
@ -1353,6 +1393,15 @@ CCollision::CalculateTrianglePlanes(CColModel *model)
} }
} }
void
CCollision::RemoveTrianglePlanes(CColModel *model)
{
if(model->trianglePlanes){
ms_colModelCache.Remove(model->GetLinkPtr());
model->RemoveTrianglePlanes();
}
}
void void
CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel)
{ {
@ -1575,15 +1624,75 @@ CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel)
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
} }
static void
GetSurfaceColor(uint8 surf, uint8 &r, uint8 &g, uint8 &b)
{
// game doesn't do this
r = 255;
g = 128;
b = 0;
switch(CSurfaceTable::GetAdhesionGroup(surf)){
case ADHESIVE_RUBBER:
r = 255;
g = 0;
b = 0;
break;
case ADHESIVE_HARD:
r = 255;
g = 255;
b = 128;
break;
case ADHESIVE_ROAD:
r = 128;
g = 128;
b = 128;
break;
case ADHESIVE_LOOSE:
r = 0;
g = 255;
b = 0;
break;
case ADHESIVE_SAND:
r = 255;
g = 128;
b = 128;
break;
case ADHESIVE_WET:
r = 0;
g = 0;
b = 255;
break;
}
if(surf == SURFACE_SAND || surf == SURFACE_SAND_BEACH){
r = 255;
g = 255;
b = 0;
}
float f = (surf & 0xF)/32.0f + 0.5f;
r *= f;
g *= f;
b *= f;
if(surf == SURFACE_TRANSPARENT_CLOTH || surf == SURFACE_METAL_CHAIN_FENCE ||
surf == SURFACE_TRANSPARENT_STONE || surf == SURFACE_SCAFFOLD_POLE)
if(CTimer::GetFrameCounter() & 1){
r = 0;
g = 0;
b = 0;
}
}
void void
CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id) CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id)
{ {
int i; int i;
int s; int s;
float f;
CVector verts[8]; CVector verts[8];
CVector min, max; CVector min, max;
int r, g, b; uint8 r, g, b;
RwImVertexIndex *iptr; RwImVertexIndex *iptr;
RwIm3DVertex *vptr; RwIm3DVertex *vptr;
@ -1602,53 +1711,8 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel,
verts[1] = mat * verts[1]; verts[1] = mat * verts[1];
verts[2] = mat * verts[2]; verts[2] = mat * verts[2];
// game doesn't do this
r = 255;
g = 128;
b = 0;
s = colModel.triangles[i].surface; s = colModel.triangles[i].surface;
f = (s & 0xF)/32.0f + 0.5f; GetSurfaceColor(s, r, g, b);
switch(CSurfaceTable::GetAdhesionGroup(s)){
case ADHESIVE_RUBBER:
r = f * 255.0f;
g = 0;
b = 0;
break;
case ADHESIVE_HARD:
r = f*255.0f;
g = f*255.0f;
b = f*128.0f;
break;
case ADHESIVE_ROAD:
r = f*128.0f;
g = f*128.0f;
b = f*128.0f;
break;
case ADHESIVE_LOOSE:
r = 0;
g = f * 255.0f;
b = 0;
break;
case ADHESIVE_WET:
r = 0;
g = 0;
b = f * 255.0f;
break;
default:
// this doesn't make much sense
r *= f;
g *= f;
b *= f;
}
if(s == SURFACE_TRANSPARENT_CLOTH || s == SURFACE_METAL_CHAIN_FENCE ||
s == SURFACE_TRANSPARENT_STONE || s == SURFACE_SCAFFOLD_POLE)
if(CTimer::GetFrameCounter() & 1){
r = 0;
g = 0;
b = 0;
}
if(s > SURFACE_METAL_GATE){ if(s > SURFACE_METAL_GATE){
r = CGeneral::GetRandomNumber(); r = CGeneral::GetRandomNumber();
@ -1689,47 +1753,7 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel,
verts[7] = mat * CVector(max.x, max.y, max.z); verts[7] = mat * CVector(max.x, max.y, max.z);
s = colModel.boxes[i].surface; s = colModel.boxes[i].surface;
f = (s & 0xF)/32.0f + 0.5f; GetSurfaceColor(s, r, g, b);
switch(CSurfaceTable::GetAdhesionGroup(s)){
case ADHESIVE_RUBBER:
r = f * 255.0f;
g = 0;
b = 0;
break;
case ADHESIVE_HARD:
r = f*255.0f;
g = f*255.0f;
b = f*128.0f;
break;
case ADHESIVE_ROAD:
r = f*128.0f;
g = f*128.0f;
b = f*128.0f;
break;
case ADHESIVE_LOOSE:
r = 0;
g = f * 255.0f;
b = 0;
break;
case ADHESIVE_WET:
r = 0;
g = 0;
b = f * 255.0f;
break;
default:
// this doesn't make much sense
r *= f;
g *= f;
b *= f;
}
if(s == SURFACE_TRANSPARENT_CLOTH || s == SURFACE_METAL_CHAIN_FENCE ||
s == SURFACE_TRANSPARENT_STONE || s == SURFACE_SCAFFOLD_POLE)
if(CTimer::GetFrameCounter() & 1){
r = 0;
g = 0;
b = 0;
}
RenderBuffer::StartStoring(36, 8, &iptr, &vptr); RenderBuffer::StartStoring(36, 8, &iptr, &vptr);
RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255);
@ -1833,7 +1857,7 @@ CColLine::Set(const CVector &p0, const CVector &p1)
} }
void void
CColTriangle::Set(const CVector *, int a, int b, int c, uint8 surf, uint8 piece) CColTriangle::Set(const CompressedVector *, int a, int b, int c, uint8 surf, uint8 piece)
{ {
this->a = a; this->a = a;
this->b = b; this->b = b;
@ -1842,12 +1866,8 @@ CColTriangle::Set(const CVector *, int a, int b, int c, uint8 surf, uint8 piece)
} }
void void
CColTrianglePlane::Set(const CVector *v, CColTriangle &tri) CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc)
{ {
const CVector &va = v[tri.a];
const CVector &vb = v[tri.b];
const CVector &vc = v[tri.c];
normal = CrossProduct(vc-va, vb-va); normal = CrossProduct(vc-va, vb-va);
normal.Normalise(); normal.Normalise();
dist = DotProduct(normal, va); dist = DotProduct(normal, va);
@ -1905,6 +1925,7 @@ CColModel::RemoveCollisionVolumes(void)
RwFree(boxes); RwFree(boxes);
RwFree(vertices); RwFree(vertices);
RwFree(triangles); RwFree(triangles);
CCollision::RemoveTrianglePlanes(this);
} }
numSpheres = 0; numSpheres = 0;
numLines = 0; numLines = 0;
@ -1950,7 +1971,7 @@ CColModel::GetLinkPtr(void)
void void
CColModel::GetTrianglePoint(CVector &v, int i) const CColModel::GetTrianglePoint(CVector &v, int i) const
{ {
v = vertices[i]; v = vertices[i].Get();
} }
CColModel& CColModel&
@ -2029,7 +2050,7 @@ CColModel::operator=(const CColModel &other)
if(vertices) if(vertices)
RwFree(vertices); RwFree(vertices);
if(numVerts){ if(numVerts){
vertices = (CVector*)RwMalloc(numVerts*sizeof(CVector)); vertices = (CompressedVector*)RwMalloc(numVerts*sizeof(CompressedVector));
for(i = 0; i < numVerts; i++) for(i = 0; i < numVerts; i++)
vertices[i] = other.vertices[i]; vertices[i] = other.vertices[i];
} }

View file

@ -10,6 +10,19 @@
#define MAX_COLLISION_POINTS 32 #define MAX_COLLISION_POINTS 32
#endif #endif
struct CompressedVector
{
#ifdef COMPRESSED_COL_VECTORS
int16 x, y, z;
CVector Get(void) const { return CVector(x, y, z)/128.0f; };
void Set(float x, float y, float z) { this->x = x*128.0f; this->y = y*128.0f; this->z = z*128.0f; };
#else
float x, y, z;
CVector Get(void) const { return CVector(x, y, z); };
void Set(float x, float y, float z) { this->x = x; this->y = y; this->z = z; };
#endif
};
struct CSphere struct CSphere
{ {
CVector center; CVector center;
@ -63,7 +76,7 @@ struct CColTriangle
uint16 c; uint16 c;
uint8 surface; uint8 surface;
void Set(const CVector *v, int a, int b, int c, uint8 surf, uint8 piece); void Set(const CompressedVector *v, int a, int b, int c, uint8 surf, uint8 piece);
}; };
struct CColTrianglePlane struct CColTrianglePlane
@ -72,7 +85,8 @@ struct CColTrianglePlane
float dist; float dist;
uint8 dir; uint8 dir;
void Set(const CVector *v, CColTriangle &tri); void Set(const CVector &va, const CVector &vb, const CVector &vc);
void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); }
void GetNormal(CVector &n) const { n = normal; } void GetNormal(CVector &n) const { n = normal; }
float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; }; float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; };
}; };
@ -113,7 +127,7 @@ struct CColModel
CColSphere *spheres; CColSphere *spheres;
CColLine *lines; CColLine *lines;
CColBox *boxes; CColBox *boxes;
CVector *vertices; CompressedVector *vertices;
CColTriangle *triangles; CColTriangle *triangles;
CColTrianglePlane *trianglePlanes; CColTrianglePlane *trianglePlanes;
@ -145,24 +159,25 @@ public:
static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id); static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id);
static void CalculateTrianglePlanes(CColModel *model); static void CalculateTrianglePlanes(CColModel *model);
static void RemoveTrianglePlanes(CColModel *model);
// all these return true if there's a collision // all these return true if there's a collision
static bool TestSphereSphere(const CSphere &s1, const CSphere &s2); static bool TestSphereSphere(const CSphere &s1, const CSphere &s2);
static bool TestSphereBox(const CSphere &sph, const CBox &box); static bool TestSphereBox(const CSphere &sph, const CBox &box);
static bool TestLineBox(const CColLine &line, const CBox &box); static bool TestLineBox(const CColLine &line, const CBox &box);
static bool TestVerticalLineBox(const CColLine &line, const CBox &box); static bool TestVerticalLineBox(const CColLine &line, const CBox &box);
static bool TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); static bool TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane);
static bool TestLineSphere(const CColLine &line, const CColSphere &sph); static bool TestLineSphere(const CColLine &line, const CColSphere &sph);
static bool TestSphereTriangle(const CColSphere &sphere, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); static bool TestSphereTriangle(const CColSphere &sphere, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane);
static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough, bool ignoreShootThrough); static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough, bool ignoreShootThrough);
static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq); static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq);
static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq); static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq);
static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist); static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist);
static bool ProcessVerticalLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly); static bool ProcessVerticalLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly);
static bool ProcessLineTriangle(const CColLine &line , const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist); static bool ProcessLineTriangle(const CColLine &line , const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly = nil);
static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist); static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist);
static bool ProcessSphereTriangle(const CColSphere &sph, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq); static bool ProcessSphereTriangle(const CColSphere &sph, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq);
static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough); static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough);
static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough, CStoredCollPoly *poly); static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough, CStoredCollPoly *poly);
static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists); static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists);

View file

@ -326,13 +326,13 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname)
int32 numVertices = *(int16*)buf; int32 numVertices = *(int16*)buf;
buf += 4; buf += 4;
if(numVertices > 0){ if(numVertices > 0){
model.vertices = (CVector*)RwMalloc(numVertices*sizeof(CVector)); model.vertices = (CompressedVector*)RwMalloc(numVertices*sizeof(CompressedVector));
for(i = 0; i < numVertices; i++){ for(i = 0; i < numVertices; i++){
model.vertices[i] = *(CVector*)buf; model.vertices[i].Set(*(float*)buf, *(float*)(buf+4), *(float*)(buf+8));
#if 0 #if 0
if(Abs(model.vertices[i].x) >= 256.0f || if(Abs(*(float*)buf) >= 256.0f ||
Abs(model.vertices[i].y) >= 256.0f || Abs(*(float*)(buf+4)) >= 256.0f ||
Abs(model.vertices[i].z) >= 256.0f) Abs(*(float*)(buf+8)) >= 256.0f)
printf("%s:Collision volume too big\n", modelname); printf("%s:Collision volume too big\n", modelname);
#endif #endif
buf += 12; buf += 12;

View file

@ -53,6 +53,41 @@ enum
struct CColPoint; struct CColPoint;
inline bool
IsSeeThrough(uint8 surfType)
{
switch(surfType)
case SURFACE_GLASS:
case SURFACE_TRANSPARENT_CLOTH:
case SURFACE_METAL_CHAIN_FENCE:
case SURFACE_TRANSPARENT_STONE:
case SURFACE_SCAFFOLD_POLE:
return true;
return false;
}
// I think the necessity of this function is really a bug
inline bool
IsSeeThroughVertical(uint8 surfType)
{
switch(surfType)
case SURFACE_GLASS:
case SURFACE_TRANSPARENT_CLOTH:
return true;
return false;
}
inline bool
IsShootThrough(uint8 surfType)
{
switch(surfType)
case SURFACE_METAL_CHAIN_FENCE:
case SURFACE_TRANSPARENT_STONE:
case SURFACE_SCAFFOLD_POLE:
return true;
return false;
}
class CSurfaceTable class CSurfaceTable
{ {
static float ms_aAdhesiveLimitTable[NUMADHESIVEGROUPS][NUMADHESIVEGROUPS]; static float ms_aAdhesiveLimitTable[NUMADHESIVEGROUPS][NUMADHESIVEGROUPS];

View file

@ -54,7 +54,7 @@ enum Config {
NUMBOATALPHALIST = 20, NUMBOATALPHALIST = 20,
NUMALPHAENTITYLIST = 200, NUMALPHAENTITYLIST = 200,
NUMALPHAUNTERWATERENTITYLIST = 30, NUMALPHAUNTERWATERENTITYLIST = 30,
NUMCOLCACHELINKS = 200, NUMCOLCACHELINKS = 50,
NUMREFERENCES = 800, NUMREFERENCES = 800,
// Zones // Zones
@ -166,6 +166,7 @@ enum Config {
#if defined GTA_PS2 #if defined GTA_PS2
# define GTA_PS2_STUFF # define GTA_PS2_STUFF
# define RANDOMSPLASH # define RANDOMSPLASH
# define COMPRESSED_COL_VECTORS
#elif defined GTA_PC #elif defined GTA_PC
# define GTA3_1_1_PATCH # define GTA3_1_1_PATCH
//# define GTA3_STEAM_PATCH //# define GTA3_STEAM_PATCH

View file

@ -424,10 +424,10 @@ CGlass::RenderEntityInGlass(CEntity *entity)
ASSERT(col!=nil); ASSERT(col!=nil);
if ( col->numTriangles >= 2 ) if ( col->numTriangles >= 2 )
{ {
CVector a = object->GetMatrix() * col->vertices[0]; CVector a = object->GetMatrix() * col->vertices[0].Get();
CVector b = object->GetMatrix() * col->vertices[1]; CVector b = object->GetMatrix() * col->vertices[1].Get();
CVector c = object->GetMatrix() * col->vertices[2]; CVector c = object->GetMatrix() * col->vertices[2].Get();
CVector d = object->GetMatrix() * col->vertices[3]; CVector d = object->GetMatrix() * col->vertices[3].Get();
if ( object->bGlassCracked ) if ( object->bGlassCracked )
{ {
@ -613,10 +613,10 @@ CGlass::WindowRespondsToCollision(CEntity *entity, float amount, CVector speed,
CColModel *col = object->GetColModel(); CColModel *col = object->GetColModel();
ASSERT(col!=nil); ASSERT(col!=nil);
CVector a = object->GetMatrix() * col->vertices[0]; CVector a = object->GetMatrix() * col->vertices[0].Get();
CVector b = object->GetMatrix() * col->vertices[1]; CVector b = object->GetMatrix() * col->vertices[1].Get();
CVector c = object->GetMatrix() * col->vertices[2]; CVector c = object->GetMatrix() * col->vertices[2].Get();
CVector d = object->GetMatrix() * col->vertices[3]; CVector d = object->GetMatrix() * col->vertices[3].Get();
float minx = Min(Min(a.x, b.x), Min(c.x, d.x)); float minx = Min(Min(a.x, b.x), Min(c.x, d.x));
float maxx = Max(Max(a.x, b.x), Max(c.x, d.x)); float maxx = Max(Max(a.x, b.x), Max(c.x, d.x));

View file

@ -2239,7 +2239,7 @@ CVehicle::DoSunGlare(void)
int a2 = colmodel->triangles[i+1].a; int a2 = colmodel->triangles[i+1].a;
int b2 = colmodel->triangles[i+1].b; int b2 = colmodel->triangles[i+1].b;
int c2 = colmodel->triangles[i+1].c; int c2 = colmodel->triangles[i+1].c;
CVector vert1 = colmodel->vertices[a1]; CVector vert1 = colmodel->vertices[a1].Get();
CVector vert4; CVector vert4;
// Need an upward surface // Need an upward surface
if(vert1.z <= 0.0f) if(vert1.z <= 0.0f)
@ -2250,23 +2250,23 @@ CVehicle::DoSunGlare(void)
if(a2 != a1 && a2 != b1 && a2 != c1){ if(a2 != a1 && a2 != b1 && a2 != c1){
// a2 is not in tri1 // a2 is not in tri1
numTri2Verts++; numTri2Verts++;
vert4 = colmodel->vertices[a2]; vert4 = colmodel->vertices[a2].Get();
} }
if(b2 != a1 && b2 != b1 && b2 != c1){ if(b2 != a1 && b2 != b1 && b2 != c1){
// b2 is not in tri1 // b2 is not in tri1
numTri2Verts++; numTri2Verts++;
vert4 = colmodel->vertices[b2]; vert4 = colmodel->vertices[b2].Get();
} }
if(c2 != a1 && c2 != b1 && c2 != c1){ if(c2 != a1 && c2 != b1 && c2 != c1){
// c2 is not in tri1 // c2 is not in tri1
numTri2Verts++; numTri2Verts++;
vert4 = colmodel->vertices[c2]; vert4 = colmodel->vertices[c2].Get();
} }
// Need exactly one vertex from tri2 for a quad with tri1 // Need exactly one vertex from tri2 for a quad with tri1
if(numTri2Verts != 1) if(numTri2Verts != 1)
continue; continue;
CVector mid = (vert1 + colmodel->vertices[b1] + colmodel->vertices[c1] + vert4)/4.0f; CVector mid = (vert1 + colmodel->vertices[b1].Get() + colmodel->vertices[c1].Get() + vert4)/4.0f;
float dy = mid.y - vert1.y; float dy = mid.y - vert1.y;
float dx = mid.x - vert1.x; float dx = mid.x - vert1.x;
float dist = 1.4f * Min(Abs(dx), Abs(dy)); float dist = 1.4f * Min(Abs(dx), Abs(dy));