diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/GameInitDispose.cpp | 318 | ||||
-rw-r--r-- | src/Models.cpp | 79 | ||||
-rw-r--r-- | src/Models.h | 65 | ||||
-rw-r--r-- | src/misc.h | 15 | ||||
-rw-r--r-- | src/misc.zig | 91 |
5 files changed, 237 insertions, 331 deletions
diff --git a/src/GameInitDispose.cpp b/src/GameInitDispose.cpp index 0022a07..8c9ea72 100644 --- a/src/GameInitDispose.cpp +++ b/src/GameInitDispose.cpp @@ -114,6 +114,8 @@ void LoadSounds(bool musictoggle) gSampleSet[footstepsound + 2] = loadSound("footstep/2.ogg"); gSampleSet[footstepsound + 3] = loadSound("footstep/3.ogg"); gSampleSet[footstepsound + 4] = loadSound("footstep/4.ogg"); + gSampleSet[pinpullsound] = loadSound("grenade/pin-pull.flac"); + gSampleSet[pinreplacesound] = loadSound("grenade/pin-replace.flac"); gSampleSet[clicksound] = loadSound("gun/empty-clip.wav"); gSampleSet[shotgunsound] = loadSound("gun/fire/20-gauge-shotgun.wav"); gSampleSet[pistol2sound] = loadSound("gun/fire/22-magnum-pistol.wav"); @@ -122,8 +124,6 @@ void LoadSounds(bool musictoggle) gSampleSet[riflesound] = loadSound("gun/fire/ar-15-rifle.wav"); gSampleSet[nearbulletsound] = loadSound("gun/near-bullet.wav"); gSampleSet[reloadsound] = loadSound("gun/reload.wav"); - gSampleSet[pinpullsound] = loadSound("grenade/pin-pull.flac"); - gSampleSet[pinreplacesound] = loadSound("grenade/pin-replace.flac"); gSampleSet[bodylandsound] = loadSound("impact/body-fall.wav"); gSampleSet[bodyhitsound] = loadSound("impact/body-hit.wav"); gSampleSet[knifeslashsound] = loadSound("impact/knife-stab.wav"); @@ -250,7 +250,7 @@ void initGame(Game* game) game->timeremaining = 50; game->difficulty= 0.8f; - ifstream ipstream {"Data/customlevels.txt"}; + ifstream ipstream {"data/customlevels.txt"}; if (ipstream) { ipstream.ignore(256,'\n');//ignore descriptive text ipstream >> game->nummissions; @@ -511,96 +511,32 @@ void initGame(Game* game) // Setup block models if (!game->initialized) { - game->blocks[0].load((char*) ":Data:Models:Block1.solid"); - game->blocks[1].load((char*) ":Data:Models:Block2.solid"); - game->blocks[2].load((char*) ":Data:Models:Block3.solid"); - game->blocks[3].load((char*) ":Data:Models:Block4.solid"); - for (auto&& block : game->blocks) { - block.Rotate(90, 0, 0); - block.Scale(0.8f, 0.8f, 0.8f); - block.CalculateNormals(); - - // Fix block radius - auto& center = block.boundingspherecenter; - center.x = center.y = center.z = 0; - - float radiusqr = 0.0; - for (int x = 0; x < block.vertexNum; x++) { - auto distance = findDistancefast(center, - block.vertex[x]); - if (distance > radiusqr) - radiusqr = distance; - } - block.boundingsphereradius = sqrt(radiusqr); - } - - game->sidewalkcollide.load((char*) ":Data:Models:Lowheightcollide.solid"); - game->sidewalkcollide.Rotate(90, 0, 0); - game->sidewalkcollide.Scale(0.8f, 0.8f, 0.8f); - game->sidewalkcollide.CalculateNormals(); - - game->blockwalls[0].load((char*) ":Data:Models:Block1collide.solid"); - game->blockwalls[1].load((char*) ":Data:Models:Block2collide.solid"); - game->blockwalls[2].load((char*) ":Data:Models:Block3collide.solid"); - game->blockwalls[3].load((char*) ":Data:Models:Block4collide.solid"); - for (auto&& blockwall : game->blockwalls) { - blockwall.Rotate(90, 0, 0); - blockwall.Scale(0.8f, 0.75f, 0.8f); - blockwall.CalculateNormals(); - } - - game->blockroofs[0].load((char*) ":Data:Models:Highblock1collide.solid"); - game->blockroofs[1].load((char*) ":Data:Models:Highblock2collide.solid"); - game->blockroofs[2].load((char*) ":Data:Models:Highblock3collide.solid"); - game->blockroofs[3].load((char*) ":Data:Models:Highblock4collide.solid"); - for (auto&& blockroof : game->blockroofs) { - blockroof.Rotate(90, 0, 0); - blockroof.Scale(0.8f, 0.8f, 0.8f); - blockroof.CalculateNormals(); - } - - game->blockcollide[0].load((char*) ":Data:Models:block1complete.solid"); - game->blockcollide[1].load((char*) ":Data:Models:block2complete.solid"); - game->blockcollide[2].load((char*) ":Data:Models:block3complete.solid"); - game->blockcollide[3].load((char*) ":Data:Models:block4complete.solid"); - for (auto&& blockcollide : game->blockcollide) { - blockcollide.Rotate(90, 0, 0); - blockcollide.Scale(0.8f, 0.8f, 0.8f); - blockcollide.CalculateNormals(); - } - - game->blocksimplecollide[0].load((char*) ":Data:Models:lowsimplecollide1.solid"); - game->blocksimplecollide[1].load((char*) ":Data:Models:lowsimplecollide2.solid"); - game->blocksimplecollide[2].load((char*) ":Data:Models:lowsimplecollide3.solid"); - game->blocksimplecollide[3].load((char*) ":Data:Models:lowsimplecollide4.solid"); - for (auto&& blocksimplecollide : game->blocksimplecollide) { - blocksimplecollide.Rotate(90, 0, 0); - blocksimplecollide.Scale(0.8f, 0.8f, 0.8f); - blocksimplecollide.CalculateNormals(); - } - - game->blockocclude.load((char*) ":Data:Models:blockocclude.solid"); - game->blockocclude.Rotate(90, 0, 0); - game->blockocclude.Scale(0.8f, 0.8f, 0.8f); - game->blockocclude.CalculateNormals(); - - game->blocksimple.load((char*) ":Data:Models:blocksimple.solid"); - game->blocksimple.Rotate(90, 0, 0); - game->blocksimple.Scale(0.8f, 2.0f, 0.8f); - game->blocksimple.CalculateNormals(); - - game->street.load((char*) ":Data:Models:streetsubdivided2.solid"); - game->street.Rotate(90,0,0); - game->street.Scale(0.01f, 0.01f, 0.01f); - game->street.CalculateNormals(); - - game->Bigstreet = game->street; - game->Bigstreet.Scale(10000.0f, 10000.0f, 10000.0f); - - game->path.load((char*) ":Data:Models:path.solid"); - game->path.Rotate(90,0,0); - game->path.Scale(0.8f, 0.8f, 0.8f); - game->path.CalculateNormals(); + game->blocks[0].load("blocks/0.off"); + game->blocks[1].load("blocks/1.off"); + game->blocks[2].load("blocks/2.off"); + game->blocks[3].load("blocks/3.off"); + game->sidewalkcollide.load("collide/sidewalk.off"); + game->blockwalls[0].load("collide/blocks/walls/0.off"); + game->blockwalls[1].load("collide/blocks/walls/1.off"); + game->blockwalls[2].load("collide/blocks/walls/2.off"); + game->blockwalls[3].load("collide/blocks/walls/3.off"); + game->blockroofs[0].load("collide/blocks/roofs/0.off"); + game->blockroofs[1].load("collide/blocks/roofs/1.off"); + game->blockroofs[2].load("collide/blocks/roofs/2.off"); + game->blockroofs[3].load("collide/blocks/roofs/3.off"); + game->blockcollide[0].load("collide/blocks/0.off"); + game->blockcollide[1].load("collide/blocks/1.off"); + game->blockcollide[2].load("collide/blocks/2.off"); + game->blockcollide[3].load("collide/blocks/3.off"); + game->blocksimplecollide[0].load("collide/blocks/simple/0.off"); + game->blocksimplecollide[1].load("collide/blocks/simple/1.off"); + game->blocksimplecollide[2].load("collide/blocks/simple/2.off"); + game->blocksimplecollide[3].load("collide/blocks/simple/3.off"); + game->blockocclude.load("blocks/occlude.off"); + game->blocksimple.load("blocks/simple.off"); + game->street.load("streets/small.off"); + game->Bigstreet.load("streets/big.off"); + game->path.load("streets/path.off"); } auto& vip = game->person[game->numpeople = 1]; @@ -662,163 +598,30 @@ void initGame(Game* game) } if (!game->initialized) { - //Load player model - skeletonmodels[0].load((char*) ":Data:Models:Head.solid"); - skeletonmodels[0].Rotate(90,0,0); - skeletonmodels[0].Scale(.02,.02,.02); - skeletonmodels[0].CalculateNormals(); - skeletonmodels[1].load((char*) ":Data:Models:Chest.solid"); - skeletonmodels[1].Rotate(90,0,0); - skeletonmodels[1].Scale(.02,.02,.02); - skeletonmodels[1].CalculateNormals(); - skeletonmodels[2].load((char*) ":Data:Models:Abdomen.solid"); - skeletonmodels[2].Rotate(90,0,0); - skeletonmodels[2].Scale(.02,.02,.02); - skeletonmodels[2].CalculateNormals(); - skeletonmodels[3].load((char*) ":Data:Models:Upper arm.solid"); - skeletonmodels[3].Rotate(90,0,0); - skeletonmodels[3].Scale(.02,.02,.02); - skeletonmodels[3].CalculateNormals(); - skeletonmodels[4].load((char*) ":Data:Models:Lower arm.solid"); - skeletonmodels[4].Rotate(90,0,0); - skeletonmodels[4].Scale(.02,.02,.02); - skeletonmodels[4].CalculateNormals(); - skeletonmodels[5].load((char*) ":Data:Models:Hand.solid"); - skeletonmodels[5].Rotate(90,0,0); - skeletonmodels[5].Scale(.02,.02,.02); - skeletonmodels[5].CalculateNormals(); - skeletonmodels[6].load((char*) ":Data:Models:Upper leg.solid"); - skeletonmodels[6].Rotate(90,0,0); - skeletonmodels[6].Scale(.02,.02,.02); - skeletonmodels[6].CalculateNormals(); - skeletonmodels[7].load((char*) ":Data:Models:Lower leg.solid"); - skeletonmodels[7].Rotate(90,0,0); - skeletonmodels[7].Scale(.02,.02,.02); - skeletonmodels[7].CalculateNormals(); - skeletonmodels[8].load((char*) ":Data:Models:Foot.solid"); - skeletonmodels[8].Rotate(90,0,0); - skeletonmodels[8].Scale(.02,.02,.02); - skeletonmodels[8].CalculateNormals(); - skeletonmodels[9].load((char*) ":Data:Models:Shades.solid"); - skeletonmodels[9].Rotate(90,0,0); - skeletonmodels[9].Scale(.02,.02,.02); - skeletonmodels[9].CalculateNormals(); - - //Load gun models - gunmodels[sniperriflemodel].load((char*) ":Data:Models:sniperrifle.solid"); - - gunmodels[sniperriflemodel].Rotate(0,0,90); - - gunmodels[sniperriflemodel].Scale(.001,.001,.001); - - gunmodels[sniperriflemodel].CalculateNormals(); - - gunmodels[assaultriflemodel].load((char*) ":Data:Models:assaultrifle.solid"); - - gunmodels[assaultriflemodel].Rotate(0,0,90); - - gunmodels[assaultriflemodel].Scale(.01,.01,.01); - - gunmodels[assaultriflemodel].CalculateNormals(); - - gunmodels[handgunbasemodel].load((char*) ":Data:Models:Handgunbase.solid"); - - gunmodels[handgunbasemodel].Rotate(0,0,90); - - gunmodels[handgunbasemodel].Rotate(180,0,0); - - gunmodels[handgunbasemodel].Scale(.014,.014,.014); - - gunmodels[handgunbasemodel].CalculateNormals(); - - gunmodels[handgunbasemodel].MultColor(.6); - - gunmodels[handgunslidemodel].load((char*) ":Data:Models:Handgunslide.solid"); - - gunmodels[handgunslidemodel].Rotate(0,0,90); - - gunmodels[handgunslidemodel].Rotate(180,0,0); - - gunmodels[handgunslidemodel].Scale(.014,.014,.014); - - gunmodels[handgunslidemodel].CalculateNormals(); - - gunmodels[handgunslidemodel].MultColor(.6); - - gunmodels[handgun2basemodel].load((char*) ":Data:Models:glockbase.solid"); - - gunmodels[handgun2basemodel].Rotate(0,0,90); - - gunmodels[handgun2basemodel].Rotate(180,0,0); - - gunmodels[handgun2basemodel].Scale(.014,.014,.014); - - gunmodels[handgun2basemodel].CalculateNormals(); - - gunmodels[handgun2basemodel].MultColor(.6); - - gunmodels[handgun2slidemodel].load((char*) ":Data:Models:glockslide.solid"); - - gunmodels[handgun2slidemodel].Rotate(0,0,90); - - gunmodels[handgun2slidemodel].Rotate(180,0,0); - - gunmodels[handgun2slidemodel].Scale(.014,.014,.014); - - gunmodels[handgun2slidemodel].CalculateNormals(); - - gunmodels[handgun2slidemodel].MultColor(.6); - - gunmodels[grenadebasemodel].load((char*) ":Data:Models:grenadebase.solid"); - - gunmodels[grenadebasemodel].Rotate(0,0,90); - - gunmodels[grenadebasemodel].Rotate(180,0,0); - - gunmodels[grenadebasemodel].Scale(.014,.014,.014); - - gunmodels[grenadebasemodel].CalculateNormals(); - - gunmodels[grenadepinmodel].load((char*) ":Data:Models:grenadepin.solid"); - - gunmodels[grenadepinmodel].Rotate(0,0,90); - - gunmodels[grenadepinmodel].Rotate(180,0,0); - - gunmodels[grenadepinmodel].Scale(.014,.014,.014); - - gunmodels[grenadepinmodel].CalculateNormals(); - - gunmodels[grenadespoonmodel].load((char*) ":Data:Models:grenadespoon.solid"); - - gunmodels[grenadespoonmodel].Rotate(0,0,90); - - gunmodels[grenadespoonmodel].Rotate(180,0,0); - - gunmodels[grenadespoonmodel].Scale(.014,.014,.014); - - gunmodels[grenadespoonmodel].CalculateNormals(); - - gunmodels[knifemodel].load((char*) ":Data:Models:Knife.solid"); - - gunmodels[knifemodel].Rotate(0,0,90); - - gunmodels[knifemodel].Rotate(180,0,0); - - gunmodels[knifemodel].Scale(.014,.014,.014); - - gunmodels[knifemodel].CalculateNormals(); - - gunmodels[shotgunmodel].load((char*) ":Data:Models:shotgun.solid"); - - gunmodels[shotgunmodel].Rotate(0,0,90); - - gunmodels[shotgunmodel].Scale(.001,.001,.001); - - gunmodels[shotgunmodel].CalculateNormals(); - - gunmodels[shotgunmodel].MultColor(.6); - + // Load person model + skeletonmodels[0].load("skeleton/head.off"); + skeletonmodels[1].load("skeleton/chest.off"); + skeletonmodels[2].load("skeleton/abdomen.off"); + skeletonmodels[3].load("skeleton/arm.off"); + skeletonmodels[4].load("skeleton/forearm.off"); + skeletonmodels[5].load("skeleton/hand.off"); + skeletonmodels[6].load("skeleton/thigh.off"); + skeletonmodels[7].load("skeleton/leg.off"); + skeletonmodels[8].load("skeleton/foot.off"); + skeletonmodels[9].load("skeleton/shades.off"); + + // Load weapon models + gunmodels[sniperriflemodel].load("guns/sniper-rifle.off"); + gunmodels[assaultriflemodel].load("guns/assault-rifle.off"); + gunmodels[handgunbasemodel].load("guns/handgun-big-base.off"); + gunmodels[handgunslidemodel].load("guns/handgun-big-slide.off"); + gunmodels[handgun2basemodel].load("guns/handgun-small-base.off"); + gunmodels[handgun2slidemodel].load("guns/handgun-small-slide.off"); + gunmodels[grenadebasemodel].load("grenade/base.off"); + gunmodels[grenadepinmodel].load("grenade/pin.off"); + gunmodels[grenadespoonmodel].load("grenade/spoon.off"); + gunmodels[knifemodel].load("knife.off"); + gunmodels[shotgunmodel].load("guns/shotgun.off"); } //Setup costumes @@ -829,35 +632,20 @@ void initGame(Game* game) float bottomcolor[3]; //Police - headcolor[0]=(float)240/255; - headcolor[1]=(float)183/255; - headcolor[2]=(float)132/255; - footcolor[0]=(float)119/255; - footcolor[1]=(float)68/255; - footcolor[2]=(float)18/255; - handcolor[0]=(float)240/255; - handcolor[1]=(float)183/255; - handcolor[2]=(float)132/255; - topcolor[0]=(float)14/255; - topcolor[1]=(float)18/255; - topcolor[2]=(float)195/255; - bottomcolor[0]=(float)14/255; - bottomcolor[1]=(float)18/255; - bottomcolor[2]=(float)195/255; // Greenish skin if zombies diff --git a/src/Models.cpp b/src/Models.cpp index cc69c44..6d8eecf 100644 --- a/src/Models.cpp +++ b/src/Models.cpp @@ -1,6 +1,5 @@ #include "Models.h" - -#include "Serialize.h" +#include "misc.h" //Functions void Model::UpdateVertexArray(){ @@ -62,43 +61,55 @@ void Model::UpdateVertexArray(){ boundingsphereradius=sqrt(boundingsphereradius); } -bool Model::load(Str255 Name) +void Model::load(const char* path) { - short tfile; - Files file; - - tfile=file.OpenFile(Name); - SetFPos(tfile,fsFromStart,0); - - // read model settings - ReadShort(tfile,1,&vertexNum); - ReadShort(tfile,1,&TriangleNum); - - // read the model data - ReadXYZ(tfile,vertexNum,vertex); - ReadTexturedTriangle(tfile,TriangleNum,Triangles); + auto model = loadModel(path); + vertexNum = model.vertices.len; + for (short i = 0; i < vertexNum; ++i) { + vertex[i].x = model.vertices.ptr[i].x; + vertex[i].y = model.vertices.ptr[i].y; + vertex[i].z = model.vertices.ptr[i].z; + } + free(model.vertices.ptr); - FSClose(tfile); + TriangleNum = model.faces.len; + for (short i = 0; i < TriangleNum; ++i) { + Triangles[i].vertex[0] = model.faces.ptr[i].v[0]; + Triangles[i].vertex[1] = model.faces.ptr[i].v[1]; + Triangles[i].vertex[2] = model.faces.ptr[i].v[2]; + Triangles[i].r = model.faces.ptr[i].r; + Triangles[i].g = model.faces.ptr[i].g; + Triangles[i].b = model.faces.ptr[i].b; + } + free(model.faces.ptr); - UpdateVertexArray(); + XYZ average {}; + for (auto&& v : vertex) + boundingspherecenter += v; + boundingspherecenter /= vertexNum; - XYZ average; - int howmany; - average=0; - howmany=0; - for(int i=0;i<vertexNum;i++){ - howmany++; - average=average+vertex[i]; - } - average=average/howmany; - boundingspherecenter=average; - boundingsphereradius=0; - for(int i=0;i<vertexNum;i++){ - if(findDistancefast(average,vertex[i])>boundingsphereradius)boundingsphereradius=findDistancefast(average,vertex[i]); - } - boundingsphereradius=sqrt(boundingsphereradius); + boundingsphereradius = 0; + for (auto&& v : vertex) + boundingsphereradius = max(boundingsphereradius, + findDistancefast(average, v)); + boundingsphereradius = sqrt(boundingsphereradius); + CalculateNormals(); +} - return 1; +void Model::save(const char* path) +{ + auto f = fopen(path, "w"); + fprintf(f, "%d %d 0\n", vertexNum, TriangleNum); + for (int i = 0; i < vertexNum; ++i) + fprintf(f, "%.3f %.3f %.3f\n", + vertex[i].x, vertex[i].y, vertex[i].z); + for (int i = 0; i < TriangleNum; ++i) + fprintf(f, "3 %d %d %d %.3f %.3f %.3f\n", + Triangles[i].vertex[0], + Triangles[i].vertex[1], + Triangles[i].vertex[2], + Triangles[i].r, Triangles[i].g, Triangles[i].b); + fclose(f); } void Model::Scale(float xscale,float yscale,float zscale) diff --git a/src/Models.h b/src/Models.h index 9c48841..2e37a9b 100644 --- a/src/Models.h +++ b/src/Models.h @@ -20,41 +20,42 @@ // class TexturedTriangle{ - public: - short vertex[3]; - float r,g,b; +public: + short vertex[3]; + float r,g,b; }; class Model{ - public: - 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 boundingspherecenter; - float boundingsphereradius; - int LineCheck(XYZ p1,XYZ p2, XYZ *p); - int LineCheck2(XYZ p1,XYZ p2, XYZ *p,XYZ move,float rotate); - int LineCheck2(XYZ *p1,XYZ *p2, XYZ *p,XYZ *move,float *rotate); - int LineCheck3(XYZ p1,XYZ p2, XYZ *p,XYZ move,float rotate,float *d); - - void UpdateVertexArray(); - bool load(Str255 Name); - void Scale(float xscale,float yscale,float zscale); - void ScaleNormals(float xscale,float yscale,float zscale); - void Translate(float xtrans,float ytrans,float ztrans); - void CalculateNormals(); - void draw(); - void draw(float r,float g,float b); - void draw(float r,float g,float b, float o); - void draw(float r,float g,float b, float x, float y, float z); - void Rotate(float xang,float yang,float zang); - void MultColor(float howmuch); - - XYZ boundingboxmin,boundingboxmax; +public: + 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 boundingspherecenter; + float boundingsphereradius; + int LineCheck(XYZ p1,XYZ p2, XYZ *p); + int LineCheck2(XYZ p1,XYZ p2, XYZ *p,XYZ move,float rotate); + int LineCheck2(XYZ *p1,XYZ *p2, XYZ *p,XYZ *move,float *rotate); + int LineCheck3(XYZ p1,XYZ p2, XYZ *p,XYZ move,float rotate,float *d); + + void UpdateVertexArray(); + void load(const char*); + void save(const char*); + void Scale(float xscale,float yscale,float zscale); + void ScaleNormals(float xscale,float yscale,float zscale); + void Translate(float xtrans,float ytrans,float ztrans); + void CalculateNormals(); + void draw(); + void draw(float r,float g,float b); + void draw(float r,float g,float b, float o); + void draw(float r,float g,float b, float x, float y, float z); + void Rotate(float xang,float yang,float zang); + void MultColor(float howmuch); + + XYZ boundingboxmin, boundingboxmax; }; #endif diff --git a/src/misc.h b/src/misc.h index 96b2307..fbd70cd 100644 --- a/src/misc.h +++ b/src/misc.h @@ -25,6 +25,20 @@ struct JointData { signed char parent; }; +struct ModelData { + struct { + struct { float x, y, z; } *ptr; + size_t len; + } vertices; + struct { + struct { + short v[3]; + float r, g, b; + } *ptr; + size_t len; + } faces; +}; + struct MuscleData { float length, initlen, minlen, maxlen; bool flag; @@ -38,6 +52,7 @@ extern "C" { #endif // __cplusplus AnimationData loadAnimation(const char*); void loadJoints(JointData*); + ModelData loadModel(const char*); void loadMuscles(MuscleData*); ALuint loadSound(const char*); GLuint loadTexture(const char*); diff --git a/src/misc.zig b/src/misc.zig index 2bbb9f0..7ff4680 100644 --- a/src/misc.zig +++ b/src/misc.zig @@ -24,12 +24,15 @@ usingnamespace @cImport({ }); const Dir = std.fs.Dir; +const TokenIterator = std.mem.TokenIterator; const al = @import("zeal"); const allocPrint = std.fmt.allocPrint; const allocator = std.heap.c_allocator; +const assert = std.debug.assert; const count = std.mem.count; const cwd = std.fs.cwd; const data_dir = @import("build_options").data_dir ++ [_]u8{ sep }; +const endsWith = std.mem.endsWith; const eql = std.mem.eql; const free = std.c.free; const join = std.fs.path.joinZ; @@ -38,6 +41,7 @@ const parseFloat = std.fmt.parseFloat; const parseInt = std.fmt.parseInt; const sep = std.fs.path.sep; const span = std.mem.span; +const startsWith = std.mem.startsWith; const std = @import("std"); const tokenize = std.mem.tokenize; @@ -146,6 +150,93 @@ export fn loadJoints(joints: [*]Joint) void { } } +const Vertex = extern struct { + x: f32, y: f32, z: f32, +}; + +const Face = extern struct { + // Only support triangles + v: [3]u16, + r: f32, g: f32, b: f32, +}; + +const OffIterator = struct { + token_iterator: TokenIterator, + + pub fn init(buffer: []const u8) OffIterator { + var self = .{ .token_iterator = tokenize(buffer, "\n") }; + if (!endsWith(u8, self.token_iterator.next().?, "OFF")) + self.token_iterator.reset(); + return self; + } + + pub fn next(self: *OffIterator) ?TokenIterator { + while (self.token_iterator.next()) |line| { + var words = tokenize(line, " "); + if (words.next()) |word| { // not empty + if (!startsWith(u8, word, "#")) { // not comment + words.reset(); + return words; + } + } + } + return null; + } +}; + +/// Load model from given OFF file. +export fn loadModel(path: [*:0]const u8) extern struct { + vertices: extern struct { + ptr: [*]Vertex, + len: usize, + }, + faces: extern struct { + ptr: [*]Face, + len: usize, + }, +} { + var dir = cwd().openDir(data_dir ++ "models", .{}) catch unreachable; + defer dir.close(); + const file = dir.readFileAlloc(allocator, span(path), max_size) + catch unreachable; + defer allocator.free(file); + var lines = OffIterator.init(file); + var counts = lines.next().?; + const vertex_count = parseInt(usize, counts.next().?, 10) catch unreachable; + const face_count = parseInt(usize, counts.next().?, 10) catch unreachable; + + const vertices = allocator.alloc(Vertex, vertex_count) catch unreachable; + for (vertices) |*vertex| { + var numbers = lines.next().?; + vertex.* = .{ + .x = parseFloat(f32, numbers.next().?) catch unreachable, + .y = parseFloat(f32, numbers.next().?) catch unreachable, + .z = parseFloat(f32, numbers.next().?) catch unreachable, + }; + } + + const faces = allocator.alloc(Face, face_count) catch unreachable; + for (faces) |*face| { + var numbers = lines.next().?; + assert(eql(u8, numbers.next().?, "3")); + face.* = .{ + .v = .{ + parseInt(u16, numbers.next().?, 10) catch unreachable, + parseInt(u16, numbers.next().?, 10) catch unreachable, + parseInt(u16, numbers.next().?, 10) catch unreachable, + }, + .r = parseFloat(f32, numbers.next().?) catch unreachable, + .g = parseFloat(f32, numbers.next().?) catch unreachable, + .b = parseFloat(f32, numbers.next().?) catch unreachable, + }; + } + + return .{ + .vertices = .{ .ptr = vertices.ptr , .len = vertices.len }, + .faces = .{ .ptr = faces.ptr , .len = faces.len }, + }; +} + const Muscle = extern struct { length: f32, initlen: f32, |