diff options
-rw-r--r-- | CHANGES | 11 | ||||
-rw-r--r-- | build.zig | 1 | ||||
-rw-r--r-- | src/Constants.h | 4 | ||||
-rw-r--r-- | src/Decals.cpp | 469 | ||||
-rw-r--r-- | src/Decals.h | 47 | ||||
-rw-r--r-- | src/Game.h | 2 | ||||
-rw-r--r-- | src/GameDraw.cpp | 5 | ||||
-rw-r--r-- | src/GameInitDispose.cpp | 37 | ||||
-rw-r--r-- | src/GameTick.cpp | 16 | ||||
-rw-r--r-- | src/Models.cpp | 13 | ||||
-rw-r--r-- | src/Models.h | 25 | ||||
-rw-r--r-- | src/Person.cpp | 2 | ||||
-rw-r--r-- | src/Quaternions.cpp | 74 | ||||
-rw-r--r-- | src/Quaternions.h | 9 | ||||
-rw-r--r-- | src/decal.zig | 118 | ||||
-rw-r--r-- | src/geom.zig | 59 | ||||
-rw-r--r-- | src/main.zig | 1 |
17 files changed, 381 insertions, 512 deletions
diff --git a/CHANGES b/CHANGES index af8462f..d171b83 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,14 @@ +Tag: 2.5.1 +Date: 2023-08-24 + + Zig 0.11 compatibility + + The codebase has been ported to Zig 0.11 + and the following bugs have been fixed: + + * Missing bullet/crater holes on certain walls (from 2.4.6) + * Disruptive disappearance of decals + Tag: 2.5.0 Date: 2023-02-15 diff --git a/build.zig b/build.zig index 989d620..56a86c6 100644 --- a/build.zig +++ b/build.zig @@ -43,7 +43,6 @@ pub fn build(b: *Build) void { "src/Globals.cpp", "src/Models.cpp", "src/Person.cpp", - "src/Quaternions.cpp", "src/Skeleton.cpp", "src/Sprites.cpp", }, &.{ "--std=c++17", "-Wall", "-Werror", "-fno-sanitize=undefined" }); diff --git a/src/Constants.h b/src/Constants.h index 654c904..ac3c1c8 100644 --- a/src/Constants.h +++ b/src/Constants.h @@ -6,10 +6,6 @@ #define max_muscles 29 #define gravity -25 -#define bullethole 0 -#define crater 1 -#define bloodpool 2 - #define idleanim 0 #define joganim 1 #define pistolaimanim 2 diff --git a/src/Decals.cpp b/src/Decals.cpp index eb2a90b..510a557 100644 --- a/src/Decals.cpp +++ b/src/Decals.cpp @@ -1,363 +1,146 @@ +#include <algorithm> #include <cmath> -#include "Camera.h" -#include "Constants.h" #include "Decals.h" -#include "misc.h" -extern float multiplier; -extern bool slomo; -extern bool blood; -extern float fogcolorr; -extern float fogcolorg; -extern float fogcolorb; -//Functions -extern float sinefluct; -extern int environment; -extern Model gunmodels[10]; -extern Camera camera; -extern float precipitationhorz; -extern float precipitationvert; -extern float precipitationdensity; -extern float snowdelay; +#define NORMAL_OFFSET 0.02f -int Decals::MakeDecal(int atype, XYZ location, float size, XYZ normal, int poly, Model *model, XYZ move, float rotation){ - int major=0; - float normalv[3]; - XYZ right; - XYZ up; - XYZ nothing; - XYZ axis[3]; - XYZ temp; - - nothing = {}; - - axis[0].x=1; - axis[1].y=1; - axis[2].z=1; - - normalv[0]=abs(normal.x); - normalv[1]=abs(normal.y); - normalv[2]=abs(normal.z); - - if(normalv[1]>normalv[major])major=1; - if(normalv[2]>normalv[major])major=2; +enum corner { SW, SE, NE, NW }; - if (normalv[0] == 1 || normalv[1] == 1 || normalv[2] == 1) { - if ((major == 0 && normal.x > 0) || major == 1) - right = {0.0f, 0.0f, -1.0f}; - else if (major == 0) - right = {0.0f, 0.0f, 1.0f}; - else if (major == 0) - right = {normal.z, 0.0f, 0.0f}; - } else { - right = crossProduct(axis[major], normal); +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; } - up = normalize(crossProduct(normal, right)); - right = normalize(right); + 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; - float count; - float count2; - float countinc=1/size; - if(countinc<.01)countinc=.01; - if(countinc>.2)countinc=.2; - float normaloffset=.02; - int good; - - numpoints[howmanydecals]=0; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right - up) * (size/3) /*+ normal/100*/; - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 0; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 0; - if((move.x==0&&move.z==0&&rotation==0)|| - LineFacetd(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-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) - )numpoints[howmanydecals]++; - else { - good=-1; - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 0; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right - up*count) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - if(good!=-1)numpoints[howmanydecals]++; - good=-1; - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 0; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right*count - up) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - if(good!=-1)numpoints[howmanydecals]++; - if(good==-1){ - good=-1; - count2=1-countinc; - while(good==-1&&count2>-1){ - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5-count2/2; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right*count2 - up*count) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - count2-=countinc; - } - if(good!=-1)numpoints[howmanydecals]++; - } - } - - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right - up) * (size/3) /*+ normal/100*/; - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 1; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 0; - if((move.x==0&&move.y==0&&move.z==0&&rotation==0)|| - LineFacetd(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-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) - )numpoints[howmanydecals]++; - else { - good=-1; - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 0; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right*count - up) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - if(good!=-1)numpoints[howmanydecals]++; - good=-1; - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 1; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right - up*count) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - if(good!=-1)numpoints[howmanydecals]++; - if(good==-1){ - good=-1; - count2=1-countinc; - while(good==-1&&count2>-1){ - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5+count2/2; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right*count2 - up*count) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - count2-=countinc; - } - if(good!=-1)numpoints[howmanydecals]++; - } - } - - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right + up) * (size/3) /*+ normal/100*/; - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 1; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 1; - if((move.x==0&&move.y==0&&move.z==0&&rotation==0)|| - LineFacetd(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-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) - )numpoints[howmanydecals]++; - else { - good=-1; - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 1; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right + up*count) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - if(good!=-1)numpoints[howmanydecals]++; - good=-1; - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 1; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right*count + up) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - if(good!=-1)numpoints[howmanydecals]++; - if(good==-1){ - good=-1; - count2=1-countinc; - while(good==-1&&count2>-1){ - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5+count2/2; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right*count2 + up*count) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - count2-=countinc; - } - if(good!=-1)numpoints[howmanydecals]++; - } - } - - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right + up) * (size/3) /*+ normal/100*/; - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 0; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 1; - if((move.x==0&&move.y==0&&move.z==0&&rotation==0)|| - LineFacetd(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-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) - )numpoints[howmanydecals]++; - else { - good=-1; - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 1; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right*count + up) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - if(good!=-1)numpoints[howmanydecals]++; - good=-1; - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 0; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right + up*count) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - if(good!=-1)numpoints[howmanydecals]++; - if(good==-1){ - good=-1; - count2=1-countinc; - while(good==-1&&count2>-1){ - count=1-countinc; - while(good==-1&&count>-1){ - texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5-count2/2; - texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; - points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right*count2 + up*count) * (size/3); - count-=countinc; - good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); - } - count2-=countinc; - } - if(good!=-1)numpoints[howmanydecals]++; - } - } - for(int i=0;i<numpoints[howmanydecals];i++){ - points[howmanydecals*8+i] += normal*normaloffset; - } - - type[howmanydecals]=atype; - alivetime[howmanydecals]=0; - if(howmanydecals<maxdecals){howmanydecals++;} - - return 0; -} - -int Decals::DeleteDecal(int which){ - if(which>=0){ - numpoints[which]=numpoints[howmanydecals-1]; - alivetime[which]=alivetime[howmanydecals-1]; - type[which]=type[howmanydecals-1]; - for(int i=0;i<numpoints[which];i++){ - points[which*8+i] = points[howmanydecals*8-8+i]; - texcoordsx[which*8+i] = texcoordsx[howmanydecals*8-8+i]; - texcoordsy[which*8+i] = texcoordsy[howmanydecals*8-8+i]; - } - if(howmanydecals>0){howmanydecals--;} + 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; } - return 0; -} - -void Decals::DoStuff() -{ - for(int i=0;i<howmanydecals;i++){ - alivetime[i]+=multiplier; - if(alivetime[i]>10&&(type[i]==bullethole||type[i]==crater))DeleteDecal(i); - if(alivetime[i]>20&&(type[i]==bloodpool))DeleteDecal(i); + 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++; } -} - -void Decals::draw() -{ - glAlphaFunc(GL_GREATER, 0.01); - - float bloodpoolspeed=1; - - glDepthFunc(GL_LEQUAL); - glEnable(GL_BLEND); - glEnable(GL_CULL_FACE); - glEnable(GL_TEXTURE_2D); - glEnable(GL_LIGHTING); - glDepthMask(0); - glAlphaFunc(GL_GREATER, 0.01); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_POLYGON_OFFSET_FILL); - for(int i=0;i<howmanydecals;i++){ - if(type[i]==bullethole)glBindTexture(GL_TEXTURE_2D, bulletholetextureptr); - if(type[i]==crater)glBindTexture(GL_TEXTURE_2D, cratertextureptr); - if(type[i]!=bloodpool)glColor4f(1,1,1,10-alivetime[i]); - - if(type[i]==bloodpool&&alivetime[i]<bloodpoolspeed*.2)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[0]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*.2&&alivetime[i]<bloodpoolspeed*.4)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[1]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*.4&&alivetime[i]<bloodpoolspeed*.6)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[2]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*.6&&alivetime[i]<bloodpoolspeed*.8)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[3]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*.8&&alivetime[i]<bloodpoolspeed*1)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[4]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*1&&alivetime[i]<bloodpoolspeed*1.2)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[5]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*1.2&&alivetime[i]<bloodpoolspeed*1.4)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[6]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*1.4&&alivetime[i]<bloodpoolspeed*1.6)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[7]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*1.6&&alivetime[i]<bloodpoolspeed*1.8)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[8]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*1.8&&alivetime[i]<bloodpoolspeed*2.0)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[9]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*2.0)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[10]); - if(type[i]==bloodpool&&alivetime[i]<bloodpoolspeed*2.0)glColor4f(1,1,1,1.5-(alivetime[i]*5/bloodpoolspeed-(int)(alivetime[i]*5/bloodpoolspeed))); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*2.0)glColor4f(1,1,1,20-alivetime[i]); - - glPushMatrix(); - glBegin(GL_TRIANGLE_FAN); - for(int j=0;j<numpoints[i];j++){ - glTexCoord2f(texcoordsx[i*8+j], texcoordsy[i*8+j]); glVertex3f(points[i*8+j].x,points[i*8+j].y,points[i*8+j].z); - } - glEnd(); - glPopMatrix(); - if(type[i]==bloodpool&&alivetime[i]<bloodpoolspeed*2.0){ - if(type[i]==bloodpool&&alivetime[i]<bloodpoolspeed*.2)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[1]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*.2&&alivetime[i]<bloodpoolspeed*.4)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[2]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*.4&&alivetime[i]<bloodpoolspeed*.6)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[3]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*.6&&alivetime[i]<bloodpoolspeed*.8)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[4]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*.8&&alivetime[i]<bloodpoolspeed*1)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[5]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*1&&alivetime[i]<bloodpoolspeed*1.2)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[6]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*1.2&&alivetime[i]<bloodpoolspeed*1.4)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[7]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*1.4&&alivetime[i]<bloodpoolspeed*1.6)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[8]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*1.6&&alivetime[i]<bloodpoolspeed*1.8)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[9]); - if(type[i]==bloodpool&&alivetime[i]>=bloodpoolspeed*1.8&&alivetime[i]<bloodpoolspeed*2.0)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[10]); - if(type[i]==bloodpool)glColor4f(1,1,1,alivetime[i]*5/bloodpoolspeed-(int)(alivetime[i]*5/bloodpoolspeed)); + 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; + } - glPushMatrix(); - glBegin(GL_TRIANGLE_FAN); - for(int j=0;j<numpoints[i];j++){ - glTexCoord2f(texcoordsx[i*8+j], texcoordsy[i*8+j]); glVertex3f(points[i*8+j].x,points[i*8+j].y,points[i*8+j].z); - } - glEnd(); - glPopMatrix(); + 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; } - glDepthMask(1); - glDisable(GL_TEXTURE_2D); - glColor4f(1,1,1,1); - glEnable(GL_CULL_FACE); - glDisable(GL_POLYGON_OFFSET_FILL); - glDepthFunc(GL_LEQUAL); + if (good > -1) + d->numpoints[d->len]++; } -Decals::~Decals() +void addDecal(struct Decals *d, enum decal kind, XYZ location, float size, + XYZ normal, int poly, Model *model, XYZ move, float rotation) { - const GLuint holes[] {bulletholetextureptr, cratertextureptr}; - glDeleteTextures(2, holes); - glDeleteTextures(11, bloodtextureptr); + 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 f37f523..cfe7a0e 100644 --- a/src/Decals.h +++ b/src/Decals.h @@ -2,7 +2,7 @@ // Copyright (C) 2002 David Rosen // Copyright (C) 2003 Steven Fuller // Copyright (C) 2003 Zachary Jack Slater -// Copyright (C) 2021 Nguyễn Gia Phong +// Copyright (C) 2021, 2023 Nguyễn Gia Phong // // This file is part of Black Shades. // @@ -25,30 +25,33 @@ #include "Models.h" #include "Quaternions.h" -#define maxdecals 120 +#define MAX_DECALS 120 -class Decals{ -public: - GLuint bulletholetextureptr; - GLuint cratertextureptr; - GLuint bloodtextureptr[11]; +enum decal { BULLET_HOLE, CRATER, BLOOD_POOL }; - int howmanydecals; +struct Decals { + GLuint hole_textures[2]; + GLuint blood_textures[11]; - int type[maxdecals]; - - XYZ points[8*maxdecals]; - int numpoints[maxdecals]; - float texcoordsx[8*maxdecals]; - float texcoordsy[8*maxdecals]; - float alivetime[maxdecals]; - - void draw(); + GLuint len; + enum decal kind[MAX_DECALS]; + XYZ points[MAX_DECALS * 8]; + GLuint numpoints[MAX_DECALS]; + GLfloat texcoordsx[MAX_DECALS * 8]; + GLfloat texcoordsy[MAX_DECALS * 8]; + GLfloat alive[MAX_DECALS]; +}; - int DeleteDecal(int which); - int MakeDecal(int atype, XYZ location, float size, XYZ normal, int poly, Model *model, XYZ move, float rotation); +#ifdef __cplusplus +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); +void updateDecals(struct Decals *d); +void drawDecals(struct Decals *d); +void destroyDecals(struct Decals *d); +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus - void DoStuff(); - ~Decals(); -}; #endif // BLACKSHADES_DECALS_H diff --git a/src/Game.h b/src/Game.h index 24c6792..0639532 100644 --- a/src/Game.h +++ b/src/Game.h @@ -27,6 +27,8 @@ #define max_people 90 #define max_people_block 20 +extern float multiplier; + #include <stdbool.h> #include <AL/al.h> diff --git a/src/GameDraw.cpp b/src/GameDraw.cpp index 911e9ea..b97f814 100644 --- a/src/GameDraw.cpp +++ b/src/GameDraw.cpp @@ -2,7 +2,7 @@ // Copyright (C) 2002 David Rosen // Copyright (C) 2003 Ryan C. Gordon // Copyright (C) 2003 Steven Fuller -// Copyright (C) 2021 Nguyễn Gia Phong +// Copyright (C) 2021, 2023 Nguyễn Gia Phong // // This file is part of Black Shades. // @@ -519,8 +519,7 @@ void Game::DrawGLScene(void) } } - // Decals - decals.draw(); + drawDecals(&decals); // Occluding blocks beginx=(camera.position.x+block_spacing/2)/block_spacing-2; diff --git a/src/GameInitDispose.cpp b/src/GameInitDispose.cpp index 0a21275..86bb2bb 100644 --- a/src/GameInitDispose.cpp +++ b/src/GameInitDispose.cpp @@ -998,15 +998,8 @@ void initGame(Game* game) glClearColor(fogcolorr,fogcolorg,fogcolorb,1); game->initialized = true; - /* - for(int i=0;i<sprites.howmanysprites;i++){ - sprites.DeleteSprite(0); - } - for(int i=0;i<decals.howmanydecals;i++){ - decals.DeleteDecal(0); - }*/ - decals.howmanydecals=0; + decals.len = 0; sprites.howmanysprites=0; game->losedelay = 1; } @@ -1032,19 +1025,20 @@ void initGl(Game* game) sprites.raintextureptr = loadTexture("sprites/white.qoi"); sprites.snowtextureptr = loadTexture("sprites/white.qoi"); - decals.bulletholetextureptr = loadTexture("black.qoi"); - decals.cratertextureptr = loadTexture("black.qoi"); - decals.bloodtextureptr[0u] = loadTexture("blood/00.qoi"); - decals.bloodtextureptr[1u] = loadTexture("blood/01.qoi"); - decals.bloodtextureptr[2u] = loadTexture("blood/02.qoi"); - decals.bloodtextureptr[3u] = loadTexture("blood/03.qoi"); - decals.bloodtextureptr[4u] = loadTexture("blood/04.qoi"); - decals.bloodtextureptr[5u] = loadTexture("blood/05.qoi"); - decals.bloodtextureptr[6u] = loadTexture("blood/06.qoi"); - decals.bloodtextureptr[7u] = loadTexture("blood/07.qoi"); - decals.bloodtextureptr[8u] = loadTexture("blood/08.qoi"); - decals.bloodtextureptr[9u] = loadTexture("blood/09.qoi"); - decals.bloodtextureptr[10] = loadTexture("blood/10.qoi"); + // TODO: use more detailed textuures for hole decals + decals.hole_textures[0] = loadTexture("black.qoi"); + decals.hole_textures[1] = loadTexture("black.qoi"); + decals.blood_textures[0u] = loadTexture("blood/00.qoi"); + decals.blood_textures[1u] = loadTexture("blood/01.qoi"); + decals.blood_textures[2u] = loadTexture("blood/02.qoi"); + decals.blood_textures[3u] = loadTexture("blood/03.qoi"); + decals.blood_textures[4u] = loadTexture("blood/04.qoi"); + decals.blood_textures[5u] = loadTexture("blood/05.qoi"); + decals.blood_textures[6u] = loadTexture("blood/06.qoi"); + decals.blood_textures[7u] = loadTexture("blood/07.qoi"); + decals.blood_textures[8u] = loadTexture("blood/08.qoi"); + decals.blood_textures[9u] = loadTexture("blood/09.qoi"); + decals.blood_textures[10] = loadTexture("blood/10.qoi"); } struct Scores getScores(Game* game) @@ -1067,4 +1061,5 @@ void closeGame(Game* game) glDeleteTextures(5, textures); alDeleteSources(33 + game->musictoggle * 4, gSourceID); alDeleteBuffers(33 + game->musictoggle * 4, gSampleSet); + destroyDecals(&decals); } diff --git a/src/GameTick.cpp b/src/GameTick.cpp index 634db76..7fa90fa 100644 --- a/src/GameTick.cpp +++ b/src/GameTick.cpp @@ -758,12 +758,12 @@ void bleed(Game* game, size_t i) XYZ normish {0.0f, 1.0f, 0.0f}; if (whichtri >= 0) { - decals.MakeDecal(bloodpool, temp, 12, normish, + addDecal(&decals, BLOOD_POOL, temp, 12, normish, whichtri, &game->sidewalkcollide, move, rot); } else { temp = person.skeleton.joints[abdomen].position; temp.y = -0.5f; - decals.MakeDecal(bloodpool, temp, 12, normish, + addDecal(&decals, BLOOD_POOL, temp, 12, normish, 0, &game->sidewalkcollide, {}, 0); } person.firstlongdead = true; @@ -1004,7 +1004,7 @@ void Game::Tick() spawnNpc(this); sprites.DoStuff(); - decals.DoStuff(); + updateDecals(&decals); // Facing XYZ facing {0, 0, -1}; @@ -2089,7 +2089,7 @@ void Game::Tick() // with wall if(oldend==finalwallhit){ - decals.MakeDecal(bullethole, finalwallhit,.7,hitnorm, hitpoly, model, hitmove, hitrotation); + addDecal(&decals, BULLET_HOLE, finalwallhit,.7,hitnorm, hitpoly, model, hitmove, hitrotation); XYZ velocity; @@ -2234,7 +2234,7 @@ void Game::Tick() impact = true; auto normalrotated = rotate(blocks[citytype[wherex][wherey]].normals[whichtri], 0, cityrotation[wherex][wherey] * 90, 0); if (sprites.size[i] > 1) - decals.MakeDecal(crater, wallhit, 9, normalrotated, whichtri, &blocks[citytype[wherex][wherey]], move, cityrotation[wherex][wherey] * 90); + addDecal(&decals, CRATER, wallhit, 9, 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; @@ -2267,7 +2267,7 @@ void Game::Tick() move = {}; sprites.location[i].y=-.5; XYZ normish = {0.0f, 1.0f, 0.0f}; - decals.MakeDecal(crater, sprites.location[i],9,normish, 0, &blocks[citytype[wherex][wherey]], move, 0); + addDecal(&decals, CRATER, sprites.location[i],9,normish, 0, &blocks[citytype[wherex][wherey]], move, 0); } auto soundpos = sprites.location[i] - camera.position; @@ -2390,14 +2390,14 @@ void Game::Tick() XYZ normish = {0.0f, 1.0f, 0.0f}; if(whichtri>=0){ - decals.MakeDecal(crater, sprites.location[i],9,normish, 0, &sidewalkcollide, move, cityrotation[wherex][wherey]*90); + 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 = {}; - decals.MakeDecal(crater, sprites.location[i],9,normish, 0, &sidewalkcollide, move, 0); + addDecal(&decals, CRATER, sprites.location[i],9,normish, 0, &sidewalkcollide, move, 0); } for(int k=0;k<numpeople;k++){ diff --git a/src/Models.cpp b/src/Models.cpp index acbbaa8..0e558e2 100644 --- a/src/Models.cpp +++ b/src/Models.cpp @@ -120,16 +120,15 @@ void Model::draw(float r, float g, float b) int Model::LineCheck(XYZ p1, XYZ p2, XYZ *p) { int result = -1; - if (segmentIntersectsSphere(p1, p2, boundingspherecenter, - boundingsphereradius)) { + if (segCrossSphere(p1, p2, boundingspherecenter, boundingsphereradius)) { float olddistance = 9999999.0; for (int j = 0; j < TriangleNum; ++j) { XYZ point; - if (!LineFacetd(p1, p2, - vertex[Triangles[j].vertex[0]], - vertex[Triangles[j].vertex[1]], - vertex[Triangles[j].vertex[2]], - normals[j], &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) { diff --git a/src/Models.h b/src/Models.h index 5c27d6f..7929887 100644 --- a/src/Models.h +++ b/src/Models.h @@ -1,36 +1,25 @@ #ifndef _MODELS_H_ #define _MODELS_H_ -/**> Model Loading <**/ -// -// Model Maximums -// #include <GL/gl.h> #include "Quaternions.h" #include "Constants.h" -#define max_textured_triangle 400 // maximum number of texture-filled triangles in a model -#define max_model_vertex max_textured_triangle*3 // maximum number of vertexs +#define MAX_TEXTURED_TRIANGLES 400 -// -// Model Structures -// - -class TexturedTriangle{ -public: +struct TexturedTriangle { short vertex[3]; float r,g,b; }; -class Model{ -public: +struct Model { short vertexNum, TriangleNum; - XYZ vertex[max_model_vertex]; - XYZ normals[max_textured_triangle]; - TexturedTriangle Triangles[max_textured_triangle]; - GLfloat vArray[max_textured_triangle*27]; + XYZ vertex[MAX_TEXTURED_TRIANGLES * 3]; + XYZ normals[MAX_TEXTURED_TRIANGLES]; + TexturedTriangle Triangles[MAX_TEXTURED_TRIANGLES]; + GLfloat vArray[MAX_TEXTURED_TRIANGLES * 27]; XYZ boundingspherecenter; float boundingsphereradius; diff --git a/src/Person.cpp b/src/Person.cpp index d4a298b..0115a89 100644 --- a/src/Person.cpp +++ b/src/Person.cpp @@ -72,7 +72,7 @@ HitStruct Person::BulletCollideWithPlayer(int who, XYZ start, XYZ end){ } tempbulletloc[0]=start; tempbulletloc[1]=end; - if (segmentIntersectsSphere(start, end, average, distancemax)) { + if (segCrossSphere(start, end, average, distancemax)) { for (auto& joint : skeleton.joints) { if (joint.hasparent && joint.visible) { tempbulletloc[0] = start; diff --git a/src/Quaternions.cpp b/src/Quaternions.cpp deleted file mode 100644 index 9b32dc0..0000000 --- a/src/Quaternions.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include <cmath> - -#include "Quaternions.h" - -bool PointInTriangle(XYZ *p, XYZ normal, XYZ *p1, XYZ *p2, XYZ *p3) -{ - bool bInter = false; - float pointv[3] { p->x, p->y, p->z }; - float p1v[3] { p1->x, p1->y, p1->z }; - float p2v[3] { p2->x, p2->y, p2->z }; - float p3v[3] { p3->x, p3->y, p3->z }; - float normalv[3] { normal.x, normal.y, normal.z }; - - int i = 0, j = 0; -#define ABS(X) (((X)<0.f)?-(X):(X) ) -#define MAX(A, B) (((A)<(B))?(B):(A)) - float max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2])); -#undef MAX - if (max == ABS(normalv[0])) {i = 1; j = 2;} // y, z - if (max == ABS(normalv[1])) {i = 0; j = 2;} // x, z - if (max == ABS(normalv[2])) {i = 0; j = 1;} // x, y -#undef ABS - - float u0 = pointv[i] - p1v[i]; - float v0 = pointv[j] - p1v[j]; - float u1 = p2v[i] - p1v[i]; - float v1 = p2v[j] - p1v[j]; - float u2 = p3v[i] - p1v[i]; - float v2 = p3v[j] - p1v[j]; - - if (u1 > -1.0e-05f && u1 < 1.0e-05f)// == 0.0f) - { - float b = u0 / u2; - if (0.0f <= b && b <= 1.0f) - { - float a = (v0 - b * v2) / v1; - if ((a >= 0.0f) && (( a + b ) <= 1.0f)) - bInter = 1; - } - } - else - { - float b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1); - if (0.0f <= b && b <= 1.0f) - { - float a = (u0 - b * u2) / u1; - if ((a >= 0.0f) && (( a + b ) <= 1.0f )) - bInter = 1; - } - } - - return bInter; -} - -float LineFacetd(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc, XYZ n, XYZ *p) -{ - - //Calculate the parameters for the plane - float d = - n.x * pa.x - n.y * pa.y - n.z * pa.z; - - //Calculate the position on the line that intersects the plane - float denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z); - if (abs(denom) < 0.0000001) // Line and plane don't intersect - return 0; - float mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom; - p->x = p1.x + mu * (p2.x - p1.x); - p->y = p1.y + mu * (p2.y - p1.y); - p->z = p1.z + mu * (p2.z - p1.z); - if (mu < 0 || mu > 1) // Intersection not along line segment - return 0; - - if(!PointInTriangle( p, n, &pa, &pb, &pc)){return 0;} - return 1; -} diff --git a/src/Quaternions.h b/src/Quaternions.h index 6ed778a..4c10cd6 100644 --- a/src/Quaternions.h +++ b/src/Quaternions.h @@ -46,13 +46,12 @@ extern "C" { struct XYZ crossProduct(struct XYZ, struct XYZ); struct XYZ normalize(struct XYZ); void reflect(struct XYZ*, struct XYZ); - bool segmentIntersectsSphere(struct XYZ, struct XYZ, struct XYZ, float); + bool segCrossSphere(struct XYZ, struct XYZ, struct XYZ, float); + bool segCrossTrigon(struct XYZ p1, struct XYZ p2, + struct XYZ *pa, struct XYZ *pb, struct XYZ *pc, + struct XYZ *n, struct XYZ *p); struct XYZ rotate(struct XYZ, float, float, float); - float LineFacetd(struct XYZ p1, struct XYZ p2, - struct XYZ pa, struct XYZ pb, struct XYZ pc, - struct XYZ n, struct XYZ *p); - void setFrustum(float (*)[4], float*, float*); int cubeInFrustum(float (*)[4], float, float, float, float); int sphereInFrustum(float (*)[4], float, float, float, float); diff --git a/src/decal.zig b/src/decal.zig new file mode 100644 index 0000000..de4d9e8 --- /dev/null +++ b/src/decal.zig @@ -0,0 +1,118 @@ +// Decal construction and drawing +// Copyright (C) 2002 David Rosen +// Copyright (C) 2003 Steven Fuller +// 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 f32Eps = std.math.floatEps(f32); +const XYZ = @import("geom.zig").XYZ; +const c = @import("cimport.zig"); + +const size = 120; + +const Kind = enum(c_int) { bullet_hole, crater, blood_pool }; + +const Decals = extern struct { + // GLuint is always 32-bit. + 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, +}; + +export fn drawDecals(d: *const Decals) void { + c.glAlphaFunc(c.GL_GREATER, 0.01); + c.glDepthFunc(c.GL_LEQUAL); + c.glEnable(c.GL_BLEND); + c.glEnable(c.GL_CULL_FACE); + c.glEnable(c.GL_TEXTURE_2D); + c.glEnable(c.GL_LIGHTING); + c.glDepthMask(0); + c.glAlphaFunc(c.GL_GREATER, 0.01); + c.glTexParameterf(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_S, c.GL_CLAMP); + c.glTexParameterf(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_T, c.GL_CLAMP); + c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA); + c.glEnable(c.GL_POLYGON_OFFSET_FILL); + for (0..d.len) |i| { + switch (d.kind[i]) { + .bullet_hole, .crater => |k| { + c.glColor4f(1.0, 1.0, 1.0, 1.0 - d.alive[i] / 10.0); + c.glBindTexture(c.GL_TEXTURE_2D, d.hole_textures[switch (k) { + .bullet_hole => 0, + .crater => 1, + // https://github.com/ziglang/zig/issues/12863 + else => unreachable, // TODO: remove + }]); + }, + .blood_pool => { + const alpha = if (d.alive[i] < 2.0) + @mod(d.alive[i], 0.2) + 0.8 + else + (20.0 - d.alive[i]) / 18.0; + c.glColor4f(1.0, 1.0, 1.0, alpha); + const j: usize = @intFromFloat(d.alive[i] * 5.0); + c.glBindTexture(c.GL_TEXTURE_2D, d.blood_textures[@min(j, 10)]); + }, + } + + c.glPushMatrix(); + c.glBegin(c.GL_TRIANGLE_FAN); + for (0..d.numpoints[i]) |j| { + c.glTexCoord2f(d.texcoordsx[i * 8 + j], d.texcoordsy[i * 8 + j]); + c.glVertex3f(d.points[i * 8 + j].x, + d.points[i * 8 + j].y, d.points[i * 8 + j].z); + } + c.glEnd(); + c.glPopMatrix(); + } + c.glDepthMask(1); + c.glDisable(c.GL_TEXTURE_2D); + c.glEnable(c.GL_CULL_FACE); + c.glDisable(c.GL_POLYGON_OFFSET_FILL); + c.glDepthFunc(c.GL_LEQUAL); +} + +export fn updateDecals(d: *Decals) void { + for (0..d.len) |i| { + d.alive[i] += c.multiplier; + if (d.alive[i] < @as(f32, switch (d.kind[i]) { + .bullet_hole, .crater => 10.0, + .blood_pool => 20.0, + })) continue; + + d.len -= 1; + const last = d.len; + d.numpoints[i] = d.numpoints[last]; + d.alive[i] = d.alive[last]; + d.kind[i] = d.kind[last]; + for (0..d.numpoints[i]) |j| { + d.points[i * 8 + j] = d.points[last * 8 + j]; + d.texcoordsx[i * 8 + j] = d.texcoordsx[last * 8 + j]; + d.texcoordsy[i * 8 + j] = d.texcoordsy[last * 8 + j]; + } + } +} + +export fn destroyDecals(d: *const Decals) void { + c.glDeleteTextures(2, &d.hole_textures); + c.glDeleteTextures(11, &d.blood_textures); +} diff --git a/src/geom.zig b/src/geom.zig index 80cf1db..d6dc036 100644 --- a/src/geom.zig +++ b/src/geom.zig @@ -19,6 +19,7 @@ const Child = std.meta.Child; const degreesToRadians = std.math.degreesToRadians; +const f32Eps = std.math.floatEps(f32); const std = @import("std"); fn sqr(x: anytype) @TypeOf(x) { @@ -29,6 +30,8 @@ fn dot(u: anytype, v: @TypeOf(u)) Child(@TypeOf(u)) { return @reduce(.Add, u * v); } +pub const XYZ = extern struct { x: f32, y: f32, z: f32 }; + export fn sqrlen(v: XYZ) f32 { const u: @Vector(3, f32) = @bitCast(v); return dot(u, u); @@ -43,8 +46,6 @@ export fn len(v: XYZ) f32 { return norm(u); } -const XYZ = extern struct { x: f32, y: f32, z: f32 }; - export fn crossProduct(u: XYZ, v: XYZ) XYZ { return .{ .x = u.y * v.z - u.z * v.y, @@ -86,12 +87,10 @@ export fn rotate(v: XYZ, deg_x: f32, deg_y: f32, deg_z: f32) XYZ { return u; } -export fn segmentIntersectsSphere(a: XYZ, b: XYZ, i: XYZ, r: f32) bool { - // FIXME: call directly with vectors +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); - if (@reduce(.Or, @max(p, q) < c - splat(3, r))) return false; if (@reduce(.Or, @min(p, q) > c + splat(3, r))) return false; // https://en.wikipedia.org/wiki/Line–sphere_intersection @@ -100,6 +99,56 @@ export fn segmentIntersectsSphere(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 { + 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) + return false; // parallel segment and triangle + + const a: @Vector(3, f32) = @bitCast(p_a.*); + const mu = (dot(a, n) - dot(p, n)) / denom; + const i = p + (q - p) * splat(3, mu); + if (mu < 0 or mu > 1) + return false; // intersection not within segment + + const n_abs = @fabs(n); + const n_max = @reduce(.Max, n_abs); + const k: struct { usize, usize } = if (n_max == n_abs[0]) + .{ 1, 2 } + else if (n_max == n_abs[1]) + .{ 0, 2 } + else if (n_max == n_abs[2]) + .{ 0, 1 } + else unreachable; + + const b: @Vector(3, f32) = @bitCast(p_b.*); + const c: @Vector(3, f32) = @bitCast(p_c.*); + const u = @Vector(3, f32){ i[k[0]], b[k[0]], c[k[0]] } - splat(3, a[k[0]]); + 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) { + const s = u[0] / u[2]; + if (s >= 0 and s <= 1) { + const t = (v[0] - s * v[2]) / v[1]; + if (t >= 0 and s + t <= 1) + return true; + } + } else { + const s = (v[0] * u[1] - u[0] * v[1]) / (v[2] * u[1] - u[2] * v[1]); + if (s >= 0 and s <= 1) { + const t = (u[0] - s * u[2]) / u[1]; + if (t >= 0 and s + t <= 1) + return true; + } + } + return false; +} + fn transpose(comptime n: comptime_int, m: [n]@Vector(n, f32)) @TypeOf(m) { const flat: @Vector(sqr(n), f32) = @bitCast(m); return @bitCast(@shuffle(f32, flat, undefined, blk: { diff --git a/src/main.zig b/src/main.zig index b44b592..afffafd 100644 --- a/src/main.zig +++ b/src/main.zig @@ -37,6 +37,7 @@ var game: *c.Game = undefined; var prng: DefaultPrng = undefined; comptime { + _ = @import("decal.zig"); _ = @import("geom.zig"); } // export functions in C ABI |