Skip to content

Commit

Permalink
Load modl from lvl_ chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
Lyuu17 committed Jul 4, 2024
1 parent 2f48120 commit 21dbca5
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 268 deletions.
1 change: 0 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ target_sources(${PROJECT_NAME}
"SWBF2/Native/Chunks/LightChunk.cpp"
"SWBF2/Native/Chunks/LoclChunk.cpp"
"SWBF2/Native/Chunks/ModelChunk.cpp"
"SWBF2/Native/Chunks/ModelSegmentChunk.cpp"
"SWBF2/Native/Chunks/ObjectDefinitionChunk.cpp"
"SWBF2/Native/Chunks/SkyChunk.cpp"
"SWBF2/Native/Chunks/StreamReader.cpp"
Expand Down
12 changes: 12 additions & 0 deletions src/SWBF2/Native/Chunks/LevelChunk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Native/Chunks/StreamReader.hpp"
#include "Native/Chunks/LevelChunk.hpp"
#include "Native/Chunks/WorldChunk.hpp"
#include "Native/Chunks/ModelChunk.hpp"

#include "Native/Hashes.hpp"
#include "Native/SWBF2.hpp"
Expand Down Expand Up @@ -33,6 +34,17 @@ namespace SWBF2::Native
lvl.m_worlds.insert_or_assign(world.m_worldName, world);
break;
}
case "modl"_m:
{
Model mdl{};

StreamReader r{ *readerChild };
ModelChunk::ProcessChunkOut(r, mdl);

lvl.m_models.insert_or_assign(mdl.m_name, mdl);

break;
}
default:
godot::UtilityFunctions::printerr(__FILE__, ":", __LINE__, ": ", readerChild->GetHeader().ToString().c_str(), " not implemented");
break;
Expand Down
252 changes: 245 additions & 7 deletions src/SWBF2/Native/Chunks/ModelChunk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "StreamReader.hpp"

#include "Native/Chunks/ModelChunk.hpp"
#include "Native/Chunks/ModelSegmentChunk.hpp"
#include "Native/Models/Model.hpp"
#include "Native/Models/ModelSegment.hpp"
#include "Native/SWBF2.hpp"
Expand All @@ -12,11 +11,18 @@ namespace SWBF2::Native
{
void ModelChunk::ProcessChunk(StreamReader &streamReader)
{
Model model;
Model model{};

ProcessChunkOut(streamReader, model);

SWBF2::m_models.insert_or_assign(model.m_name, model);
}

void ModelChunk::ProcessChunkOut(StreamReader &streamReader, Model &mdl)
{
auto modelNameReaderChild = streamReader.ReadChildWithHeader<"NAME"_m>();
{
*modelNameReaderChild >> model.m_name;
*modelNameReaderChild >> mdl.m_name;
}

auto vertexReaderChild = streamReader.ReadChildWithHeader<"VRTX"_m>();
Expand All @@ -29,12 +35,12 @@ namespace SWBF2::Native

auto nodeReaderChild = streamReader.ReadChildWithHeader<"NODE"_m>();
{
*nodeReaderChild >> model.m_node;
*nodeReaderChild >> mdl.m_node;
}

auto infoReaderChild = streamReader.ReadChildWithHeader<"INFO"_m>();
{
*infoReaderChild >> model.m_info;
*infoReaderChild >> mdl.m_info;
}

std::optional<StreamReader> readerChild;
Expand All @@ -44,7 +50,7 @@ namespace SWBF2::Native
{
case "segm"_m: {
StreamReader r{ *readerChild };
ModelSegmentChunk::ProcessChunk(r, model);
ProcessSegmentChunk(r, mdl);
break;
}

Expand All @@ -54,7 +60,239 @@ namespace SWBF2::Native
break;
}
}
}

SWBF2::m_models.insert_or_assign(model.m_name, model);
void ModelChunk::ProcessSegmentChunk(StreamReader &streamReader, Model &model)
{
ModelSegment segment;

auto infoReaderChild = streamReader.ReadChildWithHeader<"INFO"_m>();
{
*infoReaderChild >> segment.m_primitiveType;
*infoReaderChild >> segment.m_vertexCount;
*infoReaderChild >> segment.m_primitiveCount;
}

std::optional<StreamReader> readerChild;
while ((readerChild = streamReader.ReadChild()).has_value())
{
switch (readerChild->GetHeader().m_Magic)
{
case "MTRL"_m:
{
Material mat;
*readerChild >> mat.m_flags;

uint8_t r, g, b, a;
*readerChild >> r >> g >> b >> a;
mat.m_diffuseColor = godot::Color(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);

*readerChild >> r >> g >> b >> a;
mat.m_specularColor = godot::Color(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);

*readerChild >> mat.m_specularExponent;
*readerChild >> mat.m_parameters;
*readerChild >> mat.m_attachedLight;

segment.m_material = mat;

break;
}
case "RTYP"_m:
{
*readerChild >> segment.p_renderType;
break;
}
case "IBUF"_m:
{
*readerChild >> segment.m_indicesBuf.m_indicesCount;

segment.m_indicesBuf.m_indices.resize(segment.m_indicesBuf.m_indicesCount);

std::vector<uint16_t> indices;
indices.resize(segment.m_indicesBuf.m_indicesCount);

*readerChild >> indices;

std::copy(indices.begin(), indices.end(), segment.m_indicesBuf.m_indices.ptrw());
break;
}
case "VBUF"_m:
{
*readerChild >> segment.m_verticesBuf.m_verticesCount;
*readerChild >> segment.m_verticesBuf.m_stride;
*readerChild >> segment.m_verticesBuf.m_flags;

for (uint32_t i = 0; i < segment.m_verticesBuf.m_verticesCount; ++i)
{
ProcessSegmentVerticesBuffer(*readerChild, model, segment);
}

break;
}
case "TNAM"_m:
{
uint32_t index;
*readerChild >> index;

std::string texName;
*readerChild >> texName;

string_tolower(texName);
segment.m_textureNames[index] = texName;

break;
}
case "BNAM"_m:
case "SKIN"_m:
case "BMAP"_m:
case "MNAM"_m:
default:
godot::UtilityFunctions::printerr(__FILE__, ":", __LINE__, ": ", readerChild->GetHeader().ToString().c_str(), " not implemented");
break;
}
}

model.m_segments.push_back(segment);
}

void ModelChunk::ProcessSegmentVerticesBuffer(StreamReader &streamReader, Model &model, ModelSegment &segment)
{
if ((segment.m_verticesBuf.m_flags & VBUFFlags::Position) != 0)
{
if ((segment.m_verticesBuf.m_flags & VBUFFlags::PositionCompressed) != 0)
{
godot::Vector3 low = model.m_info.m_vertexBox[0];
godot::Vector3 mul = model.m_info.m_vertexBox[1] - model.m_info.m_vertexBox[0];

int16_t data[4];
streamReader >> data;
godot::Vector3 c(data[0], data[1], data[2]);

constexpr float i16min = std::numeric_limits<int16_t>::min();
constexpr float i16max = std::numeric_limits<int16_t>::max();

segment.m_verticesBuf.m_positions.push_back((low + (c - godot::Vector3{ i16min, i16min, i16min }) * mul / (i16max - i16min)));
}
else
{
godot::Vector3 vec3;
streamReader >> vec3;

segment.m_verticesBuf.m_positions.push_back(vec3);
}
}

if ((segment.m_verticesBuf.m_flags & VBUFFlags::BlendWeight) != 0)
{
if ((segment.m_verticesBuf.m_flags & VBUFFlags::BlendWeightCompressed) != 0)
{
int8_t data[4];
streamReader >> data;

float_t one = (float)data[1], two = (float)data[2];
segment.m_verticesBuf.m_weights.push_back({ two, one, 1.0f - two - one });
}
else
{
godot::Vector2 vec2;
streamReader >> vec2;

segment.m_verticesBuf.m_weights.push_back({ vec2.x, vec2.y, 1.0f - vec2.x - vec2.y });
}
}

if ((segment.m_verticesBuf.m_flags & VBUFFlags::Unknown1) != 0)
{
uint32_t inds;
streamReader >> inds;

uint8_t x = (uint8_t)(inds & 0xffu);
uint8_t y = (uint8_t)((inds >> 8u) & 0xffu);
uint8_t z = (uint8_t)((inds >> 16u) & 0xffu);

segment.m_verticesBuf.m_boneIndices.push_back(godot::Vector3i{ x, y, z });
}

if ((segment.m_verticesBuf.m_flags & VBUFFlags::Normal) != 0)
{
if ((segment.m_verticesBuf.m_flags & VBUFFlags::NormalCompressed) != 0)
{
int8_t data[4];
streamReader >> data;
godot::Vector3 normal((float_t)data[0], (float_t)data[1], (float_t)data[2]);
normal = (normal * 2.0f) - godot::Vector3{ 1.0f, 1.0f, 1.0f };
segment.m_verticesBuf.m_normals.push_back(normal);
}
else
{
godot::Vector3 vec3;
streamReader >> vec3;

segment.m_verticesBuf.m_normals.push_back(vec3);
}
}

if ((segment.m_verticesBuf.m_flags & VBUFFlags::Tangents) != 0)
{
if ((segment.m_verticesBuf.m_flags & VBUFFlags::NormalCompressed) != 0)
{
int8_t data[4];
streamReader >> data;
godot::Vector3 tangent((float_t)data[0], (float_t)data[1], (float_t)data[2]);
tangent = (tangent * 2.0f) - godot::Vector3{ 1.0f, 1.0f, 1.0f };
segment.m_verticesBuf.m_tangents.push_back(tangent);

streamReader >> data;
godot::Vector3 biTangent((float_t)data[0], (float_t)data[1], (float_t)data[2]);
biTangent = (biTangent * 2.0f) - godot::Vector3{ 1.0f, 1.0f, 1.0f };
segment.m_verticesBuf.m_biTangents.push_back(biTangent);
}
else
{
godot::Vector3 vec3Tangent, vec3BiTangent;
streamReader >> vec3Tangent >> vec3BiTangent;

segment.m_verticesBuf.m_tangents.push_back(vec3Tangent);
segment.m_verticesBuf.m_biTangents.push_back(vec3BiTangent);
}
}

if ((segment.m_verticesBuf.m_flags & VBUFFlags::Color) != 0)
{
uint8_t colors[4];
streamReader >> colors;

godot::Color color{ (float)colors[0] / 255.0f, (float)colors[1] / 255.0f, (float)colors[2] / 255.0f, (float)colors[3] / 255.0f };
segment.m_verticesBuf.m_colors.push_back(color);
}

if ((segment.m_verticesBuf.m_flags & VBUFFlags::StaticLighting) != 0)
{
uint8_t colors[4];
streamReader >> colors;

godot::Color color{ (float)colors[0] / 255.0f, (float)colors[1] / 255.0f, (float)colors[2] / 255.0f, (float)colors[3] / 255.0f };
segment.m_verticesBuf.m_colors.push_back(color);
}

if ((segment.m_verticesBuf.m_flags & VBUFFlags::TexCoord) != 0)
{
if ((segment.m_verticesBuf.m_flags & VBUFFlags::TexCoordCompressed) != 0)
{
uint16_t data[2];
streamReader >> data;
godot::Vector2 uv(data[0], data[1]);
uv = uv / 2048.0f;
segment.m_verticesBuf.m_texCoords.push_back(uv);
}
else
{
godot::Vector2 vec2;
streamReader >> vec2;

segment.m_verticesBuf.m_texCoords.push_back(vec2);
}
}
}
}
5 changes: 5 additions & 0 deletions src/SWBF2/Native/Chunks/ModelChunk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

#include "StreamReader.hpp"

#include "Native/Models/Model.hpp"

namespace SWBF2::Native
{
class ModelChunk {
public:
static void ProcessChunk(StreamReader &streamReader);
static void ProcessChunkOut(StreamReader &streamReader, Model &mdl);
static void ProcessSegmentChunk(StreamReader &streamReader, Model &model);
static void ProcessSegmentVerticesBuffer(StreamReader &streamReader, Model &model, ModelSegment &segment);
};

}
Loading

0 comments on commit 21dbca5

Please sign in to comment.