diff options
| author | Nguyễn Gia Phong <cnx@loang.net> | 2023-11-18 21:40:15 +0900 |
|---|---|---|
| committer | Nguyễn Gia Phong <cnx@loang.net> | 2023-11-18 21:40:15 +0900 |
| commit | ae0810b2d4cdd31cd05f5746c6411da9d458eead (patch) | |
| tree | a827fbe10c12a4a4665b98144f32e767ba5a3553 /src | |
| parent | 371906f5fb958691a8bfce85c28eb4dfaf63559c (diff) | |
| download | blackshades-ae0810b2d4cdd31cd05f5746c6411da9d458eead.tar.gz | |
Convert model geometry to Zig
Diffstat (limited to 'src')
| -rw-r--r-- | src/Decals.cpp | 146 | ||||
| -rw-r--r-- | src/Decals.h | 3 | ||||
| -rw-r--r-- | src/GameDraw.cpp | 117 | ||||
| -rw-r--r-- | src/GameTick.cpp | 296 | ||||
| -rw-r--r-- | src/Models.cpp | 46 | ||||
| -rw-r--r-- | src/Models.h | 25 | ||||
| -rw-r--r-- | src/Person.cpp | 13 | ||||
| -rw-r--r-- | src/Skeleton.cpp | 9 | ||||
| -rw-r--r-- | src/decal.zig | 146 | ||||
| -rw-r--r-- | src/geom.zig | 22 | ||||
| -rw-r--r-- | src/main.zig | 1 | ||||
| -rw-r--r-- | src/model.zig | 90 |
12 files changed, 459 insertions, 455 deletions
diff --git a/src/Decals.cpp b/src/Decals.cpp deleted file mode 100644 index 510a557..0000000 --- a/src/Decals.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include <algorithm> -#include <cmath> - -#include "Decals.h" - -#define NORMAL_OFFSET 0.02f - -enum corner { SW, SE, NE, NW }; - -void bind(struct Decals *d, XYZ location, float size, XYZ normal, - int poly, Model *model, XYZ move, float rotation, - XYZ right, XYZ up, enum corner direction) -{ - float x, y; - switch (direction) { - case SW: - x = -1.0f; - y = -1.0f; - break; - case NW: - x = 1.0f; - y = -1.0f; - break; - case NE: - x = 1.0f; - y = 1.0f; - break; - case SE: - x = -1.0f; - y = 1.0f; - break; - } - - size_t i = d->len * 8 + d->numpoints[d->len]; - d->points[i] = location + right * x + up * y; - d->texcoordsx[i] = x * 0.5f + 0.5f; - d->texcoordsy[i] = y * 0.5f + 0.5f; - - XYZ temp; - if ((move.x == 0 && move.y == 0 && move.z == 0 && rotation == 0) - || segCrossTrigon(d->points[i] + normal / 25, - d->points[i] - normal / 25, - model->vertex + model->Triangles[poly].vertex[0], - model->vertex + model->Triangles[poly].vertex[1], - model->vertex + model->Triangles[poly].vertex[2], - &normal, &temp)) { - d->numpoints[d->len]++; - return; - } - - const auto n = normal / 25.0f; - const float countinc = std::max(0.01f, std::min(1.0f / size, 0.2f)); - int good = -1; - float count = 1.0f - countinc; - while (good == -1 && count > -1.0f) { - d->texcoordsx[i] = x * 0.5f + 0.5f; - d->texcoordsy[i] = y * count * 0.5f + 0.5f; - d->points[i] = location + right * x + up * (y * count); - count -= countinc; - good = model->LineCheck2(d->points[i] + n, - d->points[i] - n, - &temp, move, rotation); - } - if (good > -1) { - d->numpoints[d->len]++; - i++; - } - - good = -1; - count = 1.0f - countinc; - while (good == -1 && count > -1.0f) { - d->texcoordsx[i] = x * count * 0.5f + 0.5f; - d->texcoordsy[i] = y * 0.5f + 0.5f; - d->points[i] = location + right * (x * count) + up * y; - count -= countinc; - good = model->LineCheck2(d->points[i] + n, - d->points[i] - n, - &temp, move, rotation); - } - if (good > -1) { - d->numpoints[d->len]++; - return; - } - - float count2 = 1.0f - countinc; - while (good == -1 && count2 > -1.0f){ - count = 1.0f - countinc; - while (good == -1 && count > -1.0f) { - d->texcoordsx[i] = x * count2 * 0.5f + 0.5f; - d->texcoordsy[i] = y * count * 0.5f + 0.5f; - d->points[i] = location + right * (x * count2) + up * (y * count); - count -= countinc; - good = model->LineCheck2(d->points[i] + n, - d->points[i] - n, - &temp, move, rotation); - } - count2 -= countinc; - } - if (good > -1) - d->numpoints[d->len]++; -} - -void addDecal(struct Decals *d, enum decal kind, XYZ location, float size, - XYZ normal, int poly, Model *model, XYZ move, float rotation) -{ - if (d->len >= MAX_DECALS) - return; - d->kind[d->len] = kind; - d->alive[d->len] = 0; - - float normalv[] = {abs(normal.x), abs(normal.y), abs(normal.z)}; - unsigned char major = 0; - if (normalv[1] > normalv[major]) - major = 1; - if (normalv[2] > normalv[major]) - major = 2; - - XYZ right = {0.0f}; - if (normalv[0] == 1.0f || normalv[1] == 1.0f || normalv[2] == 1.0f) { - if ((major == 0 && normal.x > 0) || major == 1) - right.z = -1.0f; - else if (major == 0) - right.z = 1.0f; - else - right.x = normal.z; - } else { - XYZ axis = {0.0f}; - ((float *) &axis)[major] = 1.0f; - right = crossProduct(axis, normal); - } - - d->numpoints[d->len] = 0; - XYZ up = normalize(crossProduct(normal, right)) * (size / 3); - right = normalize(right) * (size / 3); - bind(d, location, size, normal, poly, model, - move, rotation, right, up, SW); - bind(d, location, size, normal, poly, model, - move, rotation, right, up, NW); - bind(d, location, size, normal, poly, model, - move, rotation, right, up, NE); - bind(d, location, size, normal, poly, model, - move, rotation, right, up, SE); - for (int i = 0; i < d->numpoints[d->len]; ++i) - d->points[d->len * 8 + i] += normal * NORMAL_OFFSET; - d->len++; -} diff --git a/src/Decals.h b/src/Decals.h index cfe7a0e..4eb6cf7 100644 --- a/src/Decals.h +++ b/src/Decals.h @@ -46,7 +46,8 @@ struct Decals { extern "C" { #endif // __cplusplus void addDecal(struct Decals *d, enum decal kind, XYZ location, float size, - XYZ normal, int poly, Model *model, XYZ move, float rotation); + XYZ normal, int poly, const struct Model *model, + XYZ move, float rotation); void updateDecals(struct Decals *d); void drawDecals(struct Decals *d); void destroyDecals(struct Decals *d); diff --git a/src/GameDraw.cpp b/src/GameDraw.cpp index 846a7fa..42382cc 100644 --- a/src/GameDraw.cpp +++ b/src/GameDraw.cpp @@ -485,7 +485,6 @@ void Game::DrawGLScene(void) if(endz>num_blocks-1)endz=num_blocks-1; bool draw; - int whichtri; XYZ collpoint; for(int i=beginx;i<=endx;i++){ for(int j=beginz;j<=endz;j++){ @@ -502,8 +501,13 @@ void Game::DrawGLScene(void) if(distsquared>(viewdistance*viewdistance+block_spacing*block_spacing ))draw=0; if(draw&&citytype[i][j]!=3&&!cubeInFrustum(frustum, (i)*block_spacing,0,(j)*block_spacing,block_spacing))draw=0; - if(draw&&citytype[i][j]!=3&&!sphereInFrustum(frustum, blocks[citytype[i][j]].boundingspherecenter.x+(i)*block_spacing,blocks[citytype[i][j]].boundingspherecenter.y,blocks[citytype[i][j]].boundingspherecenter.z+(j)*block_spacing,blocks[citytype[i][j]].boundingsphereradius))draw=0; - + if (draw && citytype[i][j] != 3 + && !sphereInFrustum(frustum, + blocks[citytype[i][j]].center.x + i * block_spacing, + blocks[citytype[i][j]].center.y, + blocks[citytype[i][j]].center.z + j * block_spacing, + blocks[citytype[i][j]].radius)) + draw = false; if(draw){ glPushMatrix(); glTranslatef(i*block_spacing,0,j*block_spacing); @@ -552,72 +556,47 @@ void Game::DrawGLScene(void) glEnable(GL_COLOR_MATERIAL); glEnable(GL_BLEND); for(int i=0;i<numpeople;i++){ - draw=1; - if(person[i].skeleton.free<1){ - if(person[i].whichblockx>=0&&person[i].whichblockx<num_blocks&&person[i].whichblocky>=0&&person[i].whichblocky<num_blocks){ - if(!drawn[person[i].whichblockx][person[i].whichblocky])draw=0; - }else draw=0; - if(draw) - if(!cubeInFrustum(frustum, person[i].playercoords.x,person[i].playercoords.y,person[i].playercoords.z,5))draw=0; - if (draw && sqrlen(person[i].playercoords - camera.position) > 1000000) - draw = 0; - if(draw) - for(int j=beginx;j<=endx;j++){ - for(int k=beginz;k<=endz;k++){ - if(draw){ - move.y=0; - move.x=j*block_spacing; - move.z=k*block_spacing; - if (sqrlen(move - camera.position) < 100000) { - whichtri=blockocclude.LineCheck2(camera.position,person[i].playercoords,&collpoint,move,0); - if(whichtri!=-1)draw=0; - } - } - } - } - - if(draw){ - move.y=0; - move.x=person[i].whichblockx*block_spacing; - move.z=person[i].whichblocky*block_spacing; - whichtri=blockocclude.LineCheck2(camera.position,person[i].playercoords,&collpoint,move,0); - if(whichtri!=-1)draw=0; - } - if(i==0)draw=1; - } - - if(person[i].skeleton.free==1){ - if(draw) - if(!person[i].skeleton.broken&&!cubeInFrustum(frustum, person[i].averageloc.x,person[i].averageloc.y,person[i].averageloc.z,5))draw=0; - if (draw && sqrlen(person[i].averageloc - camera.position) > 1000000) - draw = 0; - if(draw) - if(person[i].skeleton.joints[0].position.y<-2)draw=0; - - for(int j=beginx;j<=endx;j++){ - for(int k=beginz;k<=endz;k++){ - if(draw){ - move.y=0; - move.x=j*block_spacing; - move.z=k*block_spacing; - if (sqrlen(move - camera.position) < 100000) { - whichtri=blockocclude.LineCheck2(camera.position,person[i].averageloc,&collpoint,move,0); - if(whichtri!=-1)draw=0; - } - } - } - } - if(draw){ - move.y=0; - move.x=person[i].whichblockx*block_spacing; - move.z=person[i].whichblocky*block_spacing; - whichtri=blockocclude.LineCheck2(camera.position,person[i].averageloc,&collpoint,move,0); - if(whichtri!=-1)draw=0; - } - if(i==0)draw=1; - } - - if(draw&&person[i].existing==1){ + draw = true; + if (((!person[i].skeleton.free + || !person[i].skeleton.broken) + && !cubeInFrustum(frustum, + person[i].playercoords.x, + person[i].playercoords.y, + person[i].playercoords.z, 5)) + || (person[i].skeleton.free + && (person[i].whichblockx < 0 + || person[i].whichblockx >= num_blocks + || person[i].whichblocky < 0 + || person[i].whichblocky >= num_blocks + || !drawn[person[i].whichblockx][person[i].whichblocky])) + || (person[i].skeleton.free + && person[i].skeleton.joints[0].position.y < -2) + || (sqrlen(person[i].playercoords - camera.position) + > 1000000)) + draw = false; + for (auto j = beginx; j <= endx; ++j) + for(auto k = beginz; k <= endz; ++k) + if (draw && sqrlen(move - camera.position) < 100000 + && (segCrossModelTrans(camera.position, person[i].playercoords, &blockocclude, + {(float) j * block_spacing, + 0.0f, + (float) k * block_spacing}, + 0.0f, + &collpoint) + > -1)) + draw = false; + if (draw && (segCrossModelTrans(camera.position, person[i].playercoords, &blockocclude, + {(float) person[i].whichblockx * block_spacing, + 0.0f, + (float) person[i].whichblocky * block_spacing}, + 0.0f, + &collpoint) + > -1)) + draw = false; + if (i == 0) + draw = true; + + if (draw && person[i].existing) { if ((sqrlen(person[i].playercoords - camera.position) < 100000 + this->zoom * 3000000 && !person[i].skeleton.free) || (sqrlen(person[i].averageloc - camera.position) < 100000 + this->zoom * 3000000 diff --git a/src/GameTick.cpp b/src/GameTick.cpp index b628637..2bfdda6 100644 --- a/src/GameTick.cpp +++ b/src/GameTick.cpp @@ -5,7 +5,7 @@ // Copyright (C) 2003 Steven Fuller // Copyright (C) 2003 Zachary Jack Slater // Copyright (C) 2003 Toby Haynes -// Copyright (C) 2021-2022 Nguyễn Gia Phong +// Copyright (C) 2021-2023 Nguyễn Gia Phong // // This file is part of Black Shades. // @@ -497,8 +497,10 @@ void checkPersonCollisions(Game* game, int k) const XYZ move = {(float) i * block_spacing, 0.0f, (float) j * block_spacing}; XYZ collpoint; - if (game->sidewalkcollide.LineCheck2(overpoint, - underpoint, &collpoint, move, city_rot) == -1) + if (segCrossModelTrans(overpoint, underpoint, + &game->sidewalkcollide, move, city_rot, + &collpoint) + == -1) continue; if (person.playercoords.y <= collpoint.y @@ -516,19 +518,13 @@ void checkPersonCollisions(Game* game, int k) // Wall collision const auto city_type = game->citytype[i][j]; for (auto& bound : game->boundingpoints) { - const auto whichtri = game->blockwalls[city_type].LineCheck2(person.playercoords + bound, - person.playercoords + bound, - &collpoint, move, city_rot); - if (whichtri == -1) - continue; - } - for (auto& bound : game->boundingpoints) { auto pointnum = k + 1; if (pointnum > 3) pointnum = 0; - const auto whichtri = game->blockwalls[city_type].LineCheck2(person.playercoords + bound, + const auto whichtri = segCrossModelTrans(person.playercoords + bound, person.playercoords + game->boundingpoints[pointnum], - &collpoint, move, city_rot); + game->blockwalls + city_type, + move, city_rot, &collpoint); if (whichtri == -1) continue; person.playercoords += rotate(game->blockwalls[city_type].normals[whichtri], 0, city_rot, 0); @@ -752,20 +748,21 @@ void bleed(Game* game, size_t i) overpoint.y += 3000; auto underpoint = person.skeleton.joints[abdomen].position; underpoint.y -= 3000; - XYZ temp; + XYZ loc; XYZ move {(float) x * block_spacing, 0.0f, (float) y * block_spacing, }; - auto whichtri = game->sidewalkcollide.LineCheck2(overpoint, - underpoint, &temp, move, rot); + auto whichtri = segCrossModelTrans(overpoint, underpoint, + &game->sidewalkcollide, move, rot, &loc); XYZ normish {0.0f, 1.0f, 0.0f}; if (whichtri >= 0) { - addDecal(&decals, BLOOD_POOL, temp, 12, normish, + addDecal(&decals, BLOOD_POOL, loc, 12, normish, whichtri, &game->sidewalkcollide, move, rot); } else { - temp = person.skeleton.joints[abdomen].position; - temp.y = -0.5f; - addDecal(&decals, BLOOD_POOL, temp, 12, normish, - 0, &game->sidewalkcollide, {}, 0); + loc = person.skeleton.joints[abdomen].position; + loc.y = -0.5f; + move = {0.0f}; + addDecal(&decals, BLOOD_POOL, loc, 12, normish, + 0, &game->sidewalkcollide, move, 0); } person.firstlongdead = true; return; @@ -953,14 +950,15 @@ void renderLaser(Game* game) }; XYZ tmp {}; auto& block = game->blocks[game->citytype[i][j]]; - auto whichtri = block.LineCheck2(start, end, - &tmp, move, game->cityrotation[i][j]*90); - if (whichtri != -1) + if (segCrossModelTrans(start, end, &block, + move, game->cityrotation[i][j]*90, &tmp) + > -1) end = tmp; } - XYZ tmp {camera.position.x, 0.0f, camera.position.z}; - auto whichtri = game->Bigstreet.LineCheck2(start, end, &tmp, tmp, 0); - if (whichtri != -1) + XYZ tmp; + if (segCrossModelTrans(start, end, &game->Bigstreet, + {camera.position.x, 0.0f, camera.position.z}, 0, &tmp) + > -1) end = tmp; // People @@ -1151,10 +1149,17 @@ void Game::Tick() person[i].pathtarget.x+=l*block_spacing; person[i].pathtarget.z+=m*block_spacing; - if (sqrlen(person[i].playercoords - person[i].pathtarget) < leastdistance - && sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) > sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords) - && j != 1 && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[person[i].whichblockx][person[i].whichblocky]) == -1 - && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[l][m]) == -1) { + if (j != 1 + && (sqrlen(person[i].playercoords - person[i].pathtarget) + < leastdistance) + && (sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) + < sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords)) + && (segCrossModelTrans(person[i].playercoords, person[i].pathtarget, &blocksimple, + move, cityrotation[person[i].whichblockx][person[i].whichblocky], &blah) + == -1) + && (segCrossModelTrans(person[i].playercoords, person[i].pathtarget, &blocksimple, + move, cityrotation[l][m], &blah) + == -1)) { person[i].lastdistancevictim = sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords); leastdistance = sqrlen(person[i].playercoords - person[i].pathtarget); closesttarget=j; @@ -1226,28 +1231,14 @@ void Game::Tick() person[i].pathtarget.x+=person[i].whichblockx*block_spacing; person[i].pathtarget.z+=person[i].whichblocky*block_spacing; - if (sqrlen(person[i].playercoords - person[i].pathtarget) < leastdistance - && sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) < person[i].lastdistancevictim - && j != 1 && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[person[i].whichblockx][person[i].whichblocky]) == -1) { - leastdistance = sqrlen(person[i].playercoords - person[i].pathtarget); - person[i].lastdistancevictim = sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords); - closesttarget=j; - finaltarget=person[i].pathtarget; - } - } - - leastdistance=2000000; - for(int j=0;j<path.vertexNum;j++){ - person[i].pathtarget.x=path.vertex[j].x; - person[i].pathtarget.z=path.vertex[j].z; - person[i].pathtarget.y=path.vertex[j].y; - person[i].pathtarget*=person[i].pathsize; - person[i].pathtarget.x+=person[i].whichblockx*block_spacing; - person[i].pathtarget.z+=person[i].whichblocky*block_spacing; - - if (sqrlen(person[i].playercoords - person[i].pathtarget) < leastdistance - && sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) < person[i].lastdistancevictim - && j != 1 && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[person[i].whichblockx][person[i].whichblocky]) == -1) { + if (j != 1 + && (sqrlen(person[i].playercoords - person[i].pathtarget) + < leastdistance) + && (sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) + < person[i].lastdistancevictim) + && (segCrossModelTrans(person[i].playercoords, person[i].pathtarget, &blocksimple, + move, cityrotation[person[i].whichblockx][person[i].whichblocky], &blah) + == -1)) { leastdistance = sqrlen(person[i].playercoords - person[i].pathtarget); person[i].lastdistancevictim = sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords); closesttarget=j; @@ -1279,10 +1270,17 @@ void Game::Tick() person[i].pathtarget.x+=l*block_spacing; person[i].pathtarget.z+=m*block_spacing; - if (sqrlen(person[i].playercoords - person[i].pathtarget) < leastdistance - && sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) < sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords) - && j != 1 && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[l][m]) == -1 - && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[person[i].whichblockx][person[i].whichblocky]) == -1) { + if (j != 1 + && (sqrlen(person[i].playercoords - person[i].pathtarget) + < leastdistance) + && (sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) + < sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords)) + && (segCrossModelTrans(person[i].playercoords, person[i].pathtarget, &blocksimple, + move, cityrotation[person[i].whichblockx][person[i].whichblocky], &blah) + == -1) + && (segCrossModelTrans(person[i].playercoords, person[i].pathtarget, &blocksimple, + move, cityrotation[l][m], &blah) + == -1)) { leastdistance = sqrlen(person[i].playercoords - person[i].pathtarget); closesttarget=j; finaltarget=person[i].pathtarget; @@ -1315,29 +1313,27 @@ void Game::Tick() person[i].killtargetvisible = 0; if(person[i].killtargetvisible){ - beginx=person[i].whichblockx-2; - if(beginx<0)beginx=0; - beginz=person[i].whichblocky-2; - if(beginz<0)beginz=0; - endx=person[i].whichblockx+2; - if(endx>num_blocks-1)endx=num_blocks-1; - endz=person[i].whichblocky+2; - if(endz>num_blocks-1)endz=num_blocks-1; - - for(int l=beginx;l<=endx;l++){ - for(int m=beginx;m<=endx;m++){ - move.x=l*block_spacing; - move.z=m*block_spacing; - move.y=-3; - if(person[i].killtargetvisible){ - if(blocksimple.LineCheck2(person[i].playercoords,person[person[i].killtarget].playercoords,&blah,move,cityrotation[l][m])!=-1) - { - person[i].killtargetvisible=0; - } - } - } - } - } + beginx = std::max(0, + person[i].whichblockx - 2); + beginz = std::max(0, + person[i].whichblocky - 2); + endx = std::min(num_blocks - 1, + person[i].whichblockx + 2); + endz = std::min(num_blocks - 1, + person[i].whichblocky + 2); + + for (auto l = beginx; l <= endx; ++l) + for (auto m = beginx; m <= endx; ++m) + if (person[i].killtargetvisible + && (segCrossModelTrans(person[i].playercoords, + person[person[i].killtarget].playercoords, + &blocksimple, + {(float) l * block_spacing, + -3.0f, + (float) m * block_spacing}, + cityrotation[l][m], &blah) + > -1)) + person[i].killtargetvisible = 0; if(person[i].type==eviltype){ if(!person[i].killtargetvisible&&person[i].targetanimation==idleanim){ @@ -1458,6 +1454,7 @@ void Game::Tick() finaltarget=person[person[i].killtarget].playercoords; } } + } if(person[i].killtargetvisible||realcheck)person[i].pathtarget=finaltarget; if (realcheck) @@ -1783,34 +1780,28 @@ void Game::Tick() for(int i=beginx;i<=endx;i++) for(int j=beginz;j<=endz;j++){ move = {(float) i * block_spacing, 0.0f, (float) j * block_spacing}; - whichtri=blocks[citytype[i][j]].LineCheck2(start,end,&wallhit,move,cityrotation[i][j]*90); - - if(whichtri!=-1){ - - whichhit=-1; - - end=wallhit; - - finalwallhit=wallhit; - - hitnorm=rotate(blocks[citytype[i][j]].normals[whichtri],0,cityrotation[i][j]*90,0); - - hitmove=move; - - hitrotation=cityrotation[i][j]*90; - - hitpoly=whichtri; - - model=&blocks[citytype[i][j]]; - - if(j==0&&blocks[citytype[i][j]].normals[whichtri].y>.9)bulletstrength=2; + whichtri = segCrossModelTrans(start, end, + blocks + citytype[i][j], + move, cityrotation[i][j] * 90, + &wallhit); + if (whichtri > -1) { + whichhit = -1; + end = finalwallhit = wallhit; + hitnorm = rotate(blocks[citytype[i][j]].normals[whichtri], + 0, cityrotation[i][j]*90, 0); + hitmove = move; + hitrotation = cityrotation[i][j]*90; + hitpoly = whichtri; + model = &blocks[citytype[i][j]]; + if (j == 0 + && blocks[citytype[i][j]].normals[whichtri].y > 0.9) + bulletstrength = 2; } } - wallhit = {camera.position.x, 0.0f, camera.position.z}; - - whichtri=Bigstreet.LineCheck2(start,end,&wallhit,wallhit,0); - - if(whichtri!=-1){ + whichtri = segCrossModelTrans(start, end, &Bigstreet, + {camera.position.x, 0.0f, camera.position.z}, 0, + &wallhit); + if (whichtri > -1) { end.y-=.5; end=wallhit; finalwallhit=wallhit; @@ -2095,54 +2086,27 @@ void Game::Tick() } // with wall - if(oldend==finalwallhit){ - - addDecal(&decals, BULLET_HOLE, finalwallhit,.7,hitnorm, hitpoly, model, hitmove, hitrotation); - - XYZ velocity; - - velocity=aim*-4; - - velocity=hitnorm*3; - - if(person[j].whichgun==sniperrifle){ - + if (oldend == finalwallhit) { + addDecal(&decals, BULLET_HOLE, finalwallhit, 0.7f, + hitnorm, hitpoly, model, hitmove, hitrotation); + // FIXME: WTF? + XYZ velocity = aim * -4.0f; + velocity = hitnorm * 3; + switch (person[j].whichgun) { + case sniperrifle: sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 10); - sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 2); - - } - - if(person[j].whichgun==shotgun){ - + break; + case shotgun: sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 5); - sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, .8); - - } - - if(person[j].whichgun==assaultrifle){ - - sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 6); - - sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 1); - - } - - if(person[j].whichgun==handgun1){ - - sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 6); - - sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 1); - - } - - if(person[j].whichgun==handgun2){ - + break; + case assaultrifle: + case handgun1: + case handgun2: sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 6); - sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 1); - + break; } auto soundpos = finalwallhit - camera.position; @@ -2237,13 +2201,20 @@ void Game::Tick() int wherex = sprites.location[i].x / block_spacing + 0.5f; int wherey = sprites.location[i].z / block_spacing + 0.5f; move = {(float) wherex * block_spacing, 0.0f, (float) wherey * block_spacing}; - whichtri=blocks[citytype[wherex][wherey]].LineCheck2(sprites.oldlocation[i],sprites.location[i],&wallhit,move,cityrotation[wherex][wherey]*90); + whichtri = segCrossModelTrans(sprites.oldlocation[i], + sprites.location[i], + blocks + citytype[wherex][wherey], + move, cityrotation[wherex][wherey] * 90, + &wallhit); if (whichtri != -1) { impact = true; auto normalrotated = rotate(blocks[citytype[wherex][wherey]].normals[whichtri], 0, cityrotation[wherex][wherey] * 90, 0); if (sprites.size[i] > 1) - addDecal(&decals, CRATER, wallhit, 9, normalrotated, whichtri, &blocks[citytype[wherex][wherey]], move, cityrotation[wherex][wherey] * 90); + addDecal(&decals, CRATER, wallhit, 9.0f, + normalrotated, whichtri, + &blocks[citytype[wherex][wherey]], + move, cityrotation[wherex][wherey] * 90); sprites.location[i] = wallhit + normalrotated * 0.02f; reflect(&sprites.velocity[i], normalrotated); sprites.velocity[i] *= 0.3f; @@ -2276,7 +2247,8 @@ void Game::Tick() move = {}; sprites.location[i].y=-.5; XYZ normish = {0.0f, 1.0f, 0.0f}; - addDecal(&decals, CRATER, sprites.location[i],9,normish, 0, &blocks[citytype[wherex][wherey]], move, 0); + addDecal(&decals, CRATER, sprites.location[i], 9.0f, + normish, 0, blocks + citytype[wherex][wherey], move, 0); } auto soundpos = sprites.location[i] - camera.position; @@ -2395,18 +2367,20 @@ void Game::Tick() move = {(float) wherex * block_spacing, 0.0f, (float) wherey * block_spacing}; XYZ temp; - whichtri=sidewalkcollide.LineCheck2(overpoint,underpoint,&temp,move,cityrotation[wherex][wherey]*90); - + whichtri = segCrossModelTrans(overpoint, underpoint, + &sidewalkcollide, + move, cityrotation[wherex][wherey] * 90, &temp); XYZ normish = {0.0f, 1.0f, 0.0f}; - if(whichtri>=0){ - addDecal(&decals, CRATER, sprites.location[i],9,normish, 0, &sidewalkcollide, move, cityrotation[wherex][wherey]*90); - } - - if(whichtri==-1){ - temp=sprites.location[i]; - temp.y=-.5; - move = {}; - addDecal(&decals, CRATER, sprites.location[i],9,normish, 0, &sidewalkcollide, move, 0); + if (whichtri > -1) { + addDecal(&decals, CRATER, sprites.location[i], 9.0f, + normish, 0, &sidewalkcollide, move, + cityrotation[wherex][wherey]*90); + } else { + temp = sprites.location[i]; + temp.y = -0.5f; + move = {0.0f}; + addDecal(&decals, CRATER, sprites.location[i], 9.0f, + normish, 0, &sidewalkcollide, move, 0); } for(int k=0;k<numpeople;k++){ diff --git a/src/Models.cpp b/src/Models.cpp index 63cf26a..bc0b4d2 100644 --- a/src/Models.cpp +++ b/src/Models.cpp @@ -46,16 +46,16 @@ void Model::CalculateNormals() vArray[i*27+26]=Triangles[i].b; } - boundingspherecenter = {}; + this->center = {}; for (int i = 0; i < vertexNum; ++i) - boundingspherecenter += vertex[i]; - boundingspherecenter /= vertexNum; + this->center += vertex[i]; + this->center /= vertexNum; - boundingsphereradius = 0; + this->radius = 0; for (int i = 0; i < vertexNum; ++i) - boundingsphereradius = std::max(boundingsphereradius, - sqrlen(boundingspherecenter - vertex[i])); - boundingsphereradius = sqrt(boundingsphereradius); + this->radius = std::max(this->radius, + sqrlen(this->center - vertex[i])); + this->radius = sqrt(this->radius); } void Model::load(const char* path) @@ -106,35 +106,3 @@ void Model::draw(float r, float g, float b) glColor4f(r, g, b, 1.0f); glDrawArrays(GL_TRIANGLES, 0, TriangleNum*3); } - -int Model::LineCheck(XYZ p1, XYZ p2, XYZ *p) -{ - int result = -1; - if (segCrossSphere(p1, p2, boundingspherecenter, boundingsphereradius)) { - float olddistance = 9999999.0; - for (int j = 0; j < TriangleNum; ++j) { - XYZ point; - if (!segCrossTrigon(p1, p2, - vertex + Triangles[j].vertex[0], - vertex + Triangles[j].vertex[1], - vertex + Triangles[j].vertex[2], - normals + j, &point)) - continue; - float distance = sqrlen(point - p1); - if (distance < olddistance || result == -1) { - olddistance = distance; - result = j; - *p = point; - } - } - } - return result; -} - -int Model::LineCheck2(XYZ p1, XYZ p2, XYZ *p, XYZ move, float deg_y) -{ - int result = this->LineCheck(rotate(p1 - move, 0, -deg_y, 0), - rotate(p2 - move, 0, -deg_y, 0), p); - *p = rotate(*p, 0, deg_y, 0) + move; - return result; -} diff --git a/src/Models.h b/src/Models.h index 7929887..8ab4f90 100644 --- a/src/Models.h +++ b/src/Models.h @@ -9,24 +9,22 @@ #define MAX_TEXTURED_TRIANGLES 400 struct TexturedTriangle { - short vertex[3]; + GLuint vertex[3]; float r,g,b; }; struct Model { - short vertexNum, TriangleNum; - XYZ vertex[MAX_TEXTURED_TRIANGLES * 3]; + GLuint vertexNum; XYZ normals[MAX_TEXTURED_TRIANGLES]; + TexturedTriangle Triangles[MAX_TEXTURED_TRIANGLES]; - GLfloat vArray[MAX_TEXTURED_TRIANGLES * 27]; + GLuint TriangleNum; - XYZ boundingspherecenter; - float boundingsphereradius; - int LineCheck(XYZ, XYZ, XYZ*); - int LineCheck2(XYZ, XYZ, XYZ*, XYZ, float); + XYZ center; + float radius; + GLfloat vArray[MAX_TEXTURED_TRIANGLES * 27]; - void UpdateVertexArray(); void load(const char*); void save(const char*); void CalculateNormals(); @@ -34,4 +32,13 @@ struct Model { void draw(float r,float g,float b); }; +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus +int segCrossModel(struct XYZ, struct XYZ, struct Model *, struct XYZ *); +int segCrossModelTrans(struct XYZ, struct XYZ, struct Model *, + struct XYZ, float, struct XYZ *); +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus #endif diff --git a/src/Person.cpp b/src/Person.cpp index 65eb002..0b0a97c 100644 --- a/src/Person.cpp +++ b/src/Person.cpp @@ -105,9 +105,9 @@ HitStruct Person::BulletCollideWithPlayer(int who, XYZ start, XYZ end){ tempbulletloc[1].y=M[13]; tempbulletloc[1].z=M[14]; glPopMatrix(); - collide=skeletonmodels[joint.modelnum].LineCheck(tempbulletloc[0],tempbulletloc[1],&collisionpoint); - if(collide!=-1) - { + collide = segCrossModel(tempbulletloc[0], tempbulletloc[1], + skeletonmodels + joint.modelnum, &collisionpoint); + if (collide > -1) { glPushMatrix(); glLoadIdentity(); glTranslatef((joint.position.x + joint.parent->position.x) / 2, @@ -165,9 +165,10 @@ HitStruct Person::BulletCollideWithPlayer(int who, XYZ start, XYZ end){ tempbulletloc[1].y=M[13]; tempbulletloc[1].z=M[14]; glPopMatrix(); - collide=skeletonmodels[skeleton.muscles[j].parent1->modelnum].LineCheck(tempbulletloc[0],tempbulletloc[1],&collisionpoint); - if(collide!=-1) - { + collide = segCrossModel(tempbulletloc[0], tempbulletloc[1], + skeletonmodels + skeleton.muscles[j].parent1->modelnum, + &collisionpoint); + if (collide > -1) { glPushMatrix(); glLoadIdentity(); glTranslatef( (skeleton.muscles[j].parent1->position.x+skeleton.muscles[j].parent2->position.x)/2, diff --git a/src/Skeleton.cpp b/src/Skeleton.cpp index b01e27d..b29ec53 100644 --- a/src/Skeleton.cpp +++ b/src/Skeleton.cpp @@ -83,13 +83,12 @@ void Skeleton::DoConstraints(Model *collide, XYZ *move, float rotation) overpoint.y += 10; XYZ underpoint = pos; XYZ impact; - int whichtri = collide->LineCheck2(overpoint, underpoint, - &impact, *move, rotation); + int whichtri = segCrossModelTrans(overpoint, underpoint, + collide, *move, rotation, &impact); if (whichtri == -1 || collide->normals[whichtri].y <= 0.8) - whichtri = collide->LineCheck2( - joints[i].realoldposition, pos, - &impact, *move, rotation); + whichtri = segCrossModelTrans(joints[i].realoldposition, pos, + collide, *move, rotation, &impact); if (pos.y <= 0 || whichtri != -1) { if (whichtri == -1 diff --git a/src/decal.zig b/src/decal.zig index a89fc22..3292534 100644 --- a/src/decal.zig +++ b/src/decal.zig @@ -18,10 +18,19 @@ // You should have received a copy of the GNU General Public License // along with Black Shades. If not, see <https://www.gnu.org/licenses/>. -const XYZ = @import("geom.zig").XYZ; +const Child = @import("std").meta.Child; +const Model = model.Model; +const XYZ = geom.XYZ; const c = @import("cimport.zig"); +const geom = @import("geom.zig"); +const model = @import("model.zig"); +const norm = geom.norm; +const segCrossModelTrans = model.segCrossModelTrans; +const segCrossTrigon = geom.segCrossTrigon; +const splat = geom.splat; -const size = 120; +const ones: @Vector(3, f32) = @splat(1.0); +const max_len = 120; const Kind = enum(c_int) { bullet_hole, crater, blood_pool }; @@ -30,14 +39,135 @@ const Decals = extern struct { hole_textures: [2]u32, blood_textures: [11]u32, len: u32, - kind: [size]Kind, - points: [size * 8]XYZ, - numpoints: [size]u32, - texcoordsx: [size * 8]f32, - texcoordsy: [size * 8]f32, - alive: [size]f32, + kind: [max_len]Kind, + points: [max_len * 8]XYZ, + numpoints: [max_len]u32, + texcoordsx: [max_len * 8]f32, + texcoordsy: [max_len * 8]f32, + alive: [max_len]f32, }; +fn cross(u: @Vector(3, f32), v: @Vector(3, f32)) @Vector(3, f32) { + return .{ + u[1] * v[2] - u[2] * v[1], + u[2] * v[0] - u[0] * v[2], + u[0] * v[1] - u[1] * v[0], + }; +} + +fn normalize(vector: anytype, unit: Child(@TypeOf(vector))) @TypeOf(vector) { + const d = norm(vector) / unit; + if (d == 0) return vector; + return vector / @as(@TypeOf(vector), @splat(d)); +} + +fn pointTouchModel(p: @Vector(3, f32), n: @Vector(3, f32), + m: *const Model, move: XYZ, rot: f32) bool { + var temp: XYZ = undefined; + return segCrossModelTrans(@bitCast(p + n), @bitCast(p - n), + m, move, rot, &temp) > -1; +} + +export fn addDecal(d: *Decals, kind: Kind, location: XYZ, + size: f32, normal: XYZ, poly: c_int, + m: *const Model, move: XYZ, rot: f32) void { + if (d.len >= max_len) return; + const n: @Vector(3, f32) = @bitCast(normal); + const abs_n = @fabs(n); + var major: u2 = 0; + if (abs_n[1] > abs_n[major]) + major = 1; + if (abs_n[2] > abs_n[major]) + major = 2; + + const r: @Vector(3, f32) = if (@reduce(.And, abs_n != ones)) + cross(switch (major) { + 0 => .{ 1.0, 0.0, 0.0 }, + 1 => .{ 0.0, 1.0, 0.0 }, + 2 => .{ 0.0, 0.0, 1.0 }, + else => unreachable, + }, n) + else if (major == 0 and normal.x > 0 or major == 1) + .{ 0.0, 0.0, -1.0 } + else if (major == 0) + .{ 0.0, 0.0, 1.0 } + else + .{ normal.z, 0.0, 0.0 }; + const up = normalize(cross(n, r), size / 3.0); + const right = normalize(r, size / 3.0); + const loc: @Vector(3, f32) = @bitCast(location); + const trigon = &m.trigons[@intCast(poly)].vertices; + const n_eps = n * splat(3, @as(f32, 0.02)); + const n_eps2 = n * splat(3, @as(f32, 0.04)); + + d.kind[d.len] = kind; + d.numpoints[d.len] = 0; + d.alive[d.len] = 0; + for ([_]f32{ -1, 1, 1, -1 }, [_]f32{ -1, -1, 1, 1 }) |x, y| { + var p = loc + right * splat(3, x) + up * splat(3, y); + var i = d.len * 8 + d.numpoints[d.len]; + var temp: XYZ = undefined; + if (move.x == 0 and move.y == 0 and move.z == 0 and rot == 0 + or segCrossTrigon(@bitCast(p + n_eps2), @bitCast(p - n_eps2), + &m.vertices[trigon.*[0]], + &m.vertices[trigon.*[1]], + &m.vertices[trigon.*[2]], + &normal, &temp)) { + d.texcoordsx[i] = x * 0.5 + 0.5; + d.texcoordsy[i] = y * 0.5 + 0.5; + d.points[i] = @bitCast(p + n_eps); + d.numpoints[d.len] += 1; + continue; + } + + const count_inc = @max(0.01, @min(1.0 / size, 0.2)); + var good: bool = false; + var count = 1.0 - count_inc; + while (!good and count > -1.0) : (count -= count_inc) { + d.texcoordsx[i] = x * 0.5 + 0.5; + d.texcoordsy[i] = y * count * 0.5 + 0.5; + p = loc + right * splat(3, x) + up * splat(3, y * count); + good = pointTouchModel(p, n_eps2, m, move, rot); + } + if (good) { + d.points[i] = @bitCast(p + n_eps); + d.numpoints[d.len] += 1; + i += 1; + } + + good = false; + count = 1.0 - count_inc; + while (!good and count > -1.0) : (count -= count_inc) { + d.texcoordsx[i] = x * count * 0.5 + 0.5; + d.texcoordsy[i] = y * 0.5 + 0.5; + p = loc + right * splat(3, x * count) + up * splat(3, y); + good = pointTouchModel(p, n_eps2, m, move, rot); + } + if (good) { + d.points[i] = @bitCast(p + n_eps); + d.numpoints[d.len] += 1; + continue; + } + + var count2 = 1.0 - count_inc; + while (!good and count2 > -1.0) : (count2 -= count_inc) { + count = 1.0 - count_inc; + while (!good and count > -1.0) : (count -= count_inc) { + d.texcoordsx[i] = x * count2 * 0.5 + 0.5; + d.texcoordsy[i] = y * count * 0.5 + 0.5; + p = loc + right * splat(3, x * count2) + + up * splat(3, y * count); + good = pointTouchModel(p, n_eps2, m, move, rot); + } + } + if (good) { + d.points[i] = @bitCast(p + n_eps); + d.numpoints[d.len] += 1; + } + } + d.len += 1; +} + export fn drawDecals(d: *const Decals) void { c.glAlphaFunc(c.GL_GREATER, 0.01); c.glDepthFunc(c.GL_LEQUAL); diff --git a/src/geom.zig b/src/geom.zig index 5727a39..42002ee 100644 --- a/src/geom.zig +++ b/src/geom.zig @@ -19,10 +19,10 @@ const Child = std.meta.Child; const degreesToRadians = std.math.degreesToRadians; -const f32Eps = std.math.floatEps(f32); +const floatEps = std.math.floatEps; const std = @import("std"); -fn sqr(x: anytype) @TypeOf(x) { +pub fn sqr(x: anytype) @TypeOf(x) { return x * x; } @@ -37,7 +37,7 @@ export fn sqrlen(v: XYZ) f32 { return dot(u, u); } -fn norm(v: anytype) Child(@TypeOf(v)) { +pub fn norm(v: anytype) Child(@TypeOf(v)) { return @sqrt(dot(v, v)); } @@ -54,7 +54,7 @@ export fn crossProduct(u: XYZ, v: XYZ) XYZ { }; } -inline fn splat(comptime n: comptime_int, x: anytype) @Vector(n, @TypeOf(x)) { +pub fn splat(comptime n: comptime_int, x: anytype) @Vector(n, @TypeOf(x)) { return @splat(x); } @@ -70,7 +70,7 @@ export fn reflect(v: XYZ, n: XYZ) XYZ { return @bitCast(u - m * splat(3, dot(u, m) * 2)); } -fn rotate2d(i: *f32, j: *f32, a: f32) void { +pub fn rotate2d(i: *f32, j: *f32, a: f32) void { if (a == 0) return; const x = i.*; const y = j.*; @@ -87,7 +87,7 @@ export fn rotate(v: XYZ, deg_x: f32, deg_y: f32, deg_z: f32) XYZ { return u; } -export fn segCrossSphere(a: XYZ, b: XYZ, i: XYZ, r: f32) bool { +pub export fn segCrossSphere(a: XYZ, b: XYZ, i: XYZ, r: f32) bool { const p: @Vector(3, f32) = @bitCast(a); const q: @Vector(3, f32) = @bitCast(b); const c: @Vector(3, f32) = @bitCast(i); @@ -99,14 +99,14 @@ export fn segCrossSphere(a: XYZ, b: XYZ, i: XYZ, r: f32) bool { return sqr(dot(u, (p - c))) >= @reduce(.Add, sqr(p - c)) - sqr(r); } -export fn segCrossTrigon(start: XYZ, end: XYZ, - p_a: *const XYZ, p_b: *const XYZ, p_c: *const XYZ, - normal: *const XYZ, intersection: *XYZ) bool { +pub export fn segCrossTrigon(start: XYZ, end: XYZ, + p_a: *const XYZ, p_b: *const XYZ, p_c: *const XYZ, + normal: *const XYZ, intersection: *XYZ) bool { const p: @Vector(3, f32) = @bitCast(start); const q: @Vector(3, f32) = @bitCast(end); const n: @Vector(3, f32) = @bitCast(normal.*); const denom = dot(q - p, n); - if (@fabs(denom) < f32Eps) + if (@fabs(denom) < floatEps(f32)) return false; // parallel segment and triangle const a: @Vector(3, f32) = @bitCast(p_a.*); @@ -132,7 +132,7 @@ export fn segCrossTrigon(start: XYZ, end: XYZ, const v = @Vector(3, f32){ i[k[1]], b[k[1]], c[k[1]] } - splat(3, a[k[1]]); intersection.* = @bitCast(i); - if (@fabs(u[1]) < f32Eps) { + if (@fabs(u[1]) < floatEps(f32)) { const s = u[0] / u[2]; if (s >= 0 and s <= 1) { const t = (v[0] - s * v[2]) / v[1]; diff --git a/src/main.zig b/src/main.zig index afffafd..dae76e9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -39,6 +39,7 @@ var prng: DefaultPrng = undefined; comptime { _ = @import("decal.zig"); _ = @import("geom.zig"); + _ = @import("model.zig"); } // export functions in C ABI fn resizeWindow(window: gf.Window, width: c_int, height: c_int) void { diff --git a/src/model.zig b/src/model.zig new file mode 100644 index 0000000..274176d --- /dev/null +++ b/src/model.zig @@ -0,0 +1,90 @@ +// 3D model +// Copyright (C) 2002 David Rosen +// Copyright (C) 2023 Nguyễn Gia Phong +// +// This file is part of Black Shades. +// +// Black Shades 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. +// +// Black Shades 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 Black Shades. If not, see <https://www.gnu.org/licenses/>. + +const XYZ = geom.XYZ; +const degToRad = std.math.degreesToRadians; +const floatMax = std.math.floatMax; +const geom = @import("geom.zig"); +const rotate2d = geom.rotate2d; +const segCrossSphere = geom.segCrossSphere; +const segCrossTrigon = geom.segCrossTrigon; +const sqr = geom.sqr; +const std = @import("std"); + +const max_trigons = 400; + +const Trigon = extern struct { + vertices: [3]u32, + r: f32, + g: f32, + b: f32, +}; + +pub const Model = extern struct { + vertices: [max_trigons * 3]XYZ, + vertices_len: u32, + normals: [max_trigons]XYZ, + trigons: [max_trigons]Trigon, + trigons_len: u32, + center: XYZ, + radius: f32, + vert_array: [max_trigons * 27]f32, +}; + +pub export fn segCrossModel(start: XYZ, end: XYZ, m: *const Model, + intersection: *XYZ) c_int { + if (!segCrossSphere(start, end, m.center, m.radius)) + return -1; + const p: @Vector(3, f32) = @bitCast(start); + var result: c_int = -1; + var shortest = floatMax(f32); + for (0..m.trigons_len) |j| { + var v: @Vector(3, f32) = undefined; + if (!segCrossTrigon(start, end, + &m.vertices[m.trigons[j].vertices[0]], + &m.vertices[m.trigons[j].vertices[1]], + &m.vertices[m.trigons[j].vertices[2]], + &m.normals[j], @ptrCast(&v))) + continue; + const distance = @reduce(.Add, sqr(v - p)); + if (distance < shortest or result == -1) { + shortest = distance; + result = @intCast(j); + intersection.* = @bitCast(v); + } + } + return result; +} + +pub export fn segCrossModelTrans(start: XYZ, end: XYZ, m: *const Model, + move: XYZ, rot: f32, + intersection: *XYZ) c_int { + const t: @Vector(3, f32) = @bitCast(move); + var p = @as(@Vector(3, f32), @bitCast(start)) - t; + rotate2d(&p[2], &p[0], degToRad(f32, -rot)); + var q = @as(@Vector(3, f32), @bitCast(end)) - t; + rotate2d(&q[2], &q[0], degToRad(f32, -rot)); + + defer { + rotate2d(&intersection.z, &intersection.x, degToRad(f32, rot)); + intersection.* = @bitCast(@as(@Vector(3, f32), + @bitCast(intersection.*)) + t); + } + return segCrossModel(@bitCast(p), @bitCast(q), m, intersection); +} |
