247 lines
7.0 KiB
C++
247 lines
7.0 KiB
C++
#include "model.hpp"
|
|
|
|
#include "cmdfile.hpp"
|
|
#include "cache.hpp"
|
|
|
|
#include <BulletCollision/CollisionShapes/btShapeHull.h>
|
|
|
|
std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::string& filename)
|
|
{
|
|
auto model = std::make_shared<Model>();
|
|
model->name_ = filename; // TODO: name not filename
|
|
std::vector<glm::vec3> vert_pos; // rember for collision trimesh
|
|
|
|
CLIENT_ONLY(MeshBuilder mb(gfx::MF_NONE);)
|
|
std::unique_ptr<btConvexHullShape> temp_hull;
|
|
std::unique_ptr<btCompoundShape> compound;
|
|
|
|
LoadCMDFile(filename, [&](const std::string& command, std::istringstream& iss) {
|
|
if (command == "v")
|
|
{
|
|
glm::vec3 pos;
|
|
iss >> pos.x >> pos.y >> pos.z;
|
|
|
|
CLIENT_ONLY(
|
|
MeshVertex v;
|
|
v.pos = pos;
|
|
iss >> v.normal.x >> v.normal.y >> v.normal.z;
|
|
iss >> v.uv.x >> v.uv.y;
|
|
|
|
v.uv.y = 1.0f - v.uv.y; // FLIP FOR GL
|
|
|
|
if (model->skeleton_)
|
|
{
|
|
size_t num_bones = 0;
|
|
iss >> num_bones;
|
|
for (size_t i = 0; i < num_bones; ++i)
|
|
{
|
|
iss >> v.bones[i].bone_index >> v.bones[i].weight;
|
|
}
|
|
}
|
|
|
|
mb.AddVertex(v);
|
|
)
|
|
|
|
if (model->cmesh_)
|
|
vert_pos.emplace_back(pos);
|
|
|
|
if (temp_hull)
|
|
{
|
|
auto offset_pos = pos - model->col_offset_;
|
|
|
|
temp_hull->addPoint(btVector3(offset_pos.x, offset_pos.y, offset_pos.z), false);
|
|
|
|
}
|
|
|
|
model->aabb_.AddPoint(pos);
|
|
}
|
|
else if (command == "f")
|
|
{
|
|
uint32_t indices[3];
|
|
iss >> indices[0] >> indices[1] >> indices[2];
|
|
|
|
CLIENT_ONLY(
|
|
MeshTriangle t;
|
|
t.vert[0] = indices[0];
|
|
t.vert[1] = indices[1];
|
|
t.vert[2] = indices[2];
|
|
|
|
mb.AddTriangle(t);
|
|
)
|
|
|
|
if (model->cmesh_)
|
|
{
|
|
glm::vec3 p[3];
|
|
for (size_t i = 0; i < 3; ++i)
|
|
{
|
|
size_t index = indices[i];
|
|
if (index >= vert_pos.size())
|
|
throw std::runtime_error("Vertex index out of bounds in model");
|
|
|
|
p[i] = vert_pos[index] - model->col_offset_;
|
|
}
|
|
|
|
model->cmesh_->AddTriangle(p[0], p[1], p[2]);
|
|
}
|
|
}
|
|
else if (command == "surface")
|
|
{
|
|
std::string surface_name, texture_name;
|
|
CLIENT_ONLY(gfx::SurfaceFlags sflags = gfx::SF_NONE;)
|
|
|
|
iss >> surface_name;
|
|
|
|
// Optional flags
|
|
std::string flag;
|
|
while (iss >> flag)
|
|
{
|
|
if (flag == "+texture")
|
|
{
|
|
iss >> texture_name;
|
|
}
|
|
else if (flag == "+2sided")
|
|
{
|
|
CLIENT_ONLY(sflags |= gfx::SF_2SIDED;)
|
|
}
|
|
else if (flag == "+ocolor")
|
|
{
|
|
CLIENT_ONLY(sflags |= gfx::SF_OBJECT_COLOR;)
|
|
}
|
|
else if (flag == "+blend")
|
|
{
|
|
std::string blend_str;
|
|
iss >> blend_str;
|
|
|
|
CLIENT_ONLY(
|
|
sflags |= gfx::SF_BLEND;
|
|
if (blend_str == "additive")
|
|
sflags |= gfx::SF_BLEND_ADDITIVE;
|
|
)
|
|
}
|
|
}
|
|
|
|
CLIENT_ONLY(
|
|
std::shared_ptr<const gfx::Texture> texture;
|
|
if (!texture_name.empty())
|
|
{
|
|
texture = CacheManager::GetTexture("data/" + texture_name + ".png");
|
|
}
|
|
|
|
mb.BeginSurface(sflags, surface_name, texture);
|
|
)
|
|
}
|
|
else if (command == "makecoltrimesh")
|
|
{
|
|
model->cmesh_ = std::make_unique<collision::TriangleMesh>();
|
|
}
|
|
else if (command == "makeconvexhull")
|
|
{
|
|
temp_hull = std::make_unique<btConvexHullShape>();
|
|
}
|
|
else if (command == "skeleton")
|
|
{
|
|
std::string skel_name;
|
|
iss >> skel_name;
|
|
model->skeleton_ = CacheManager::GetSkeleton("data/" + skel_name + ".sk");
|
|
CLIENT_ONLY(mb.SetMeshFlag(gfx::MF_SKELETAL));
|
|
}
|
|
else if (command == "col")
|
|
{
|
|
std::string shape_type;
|
|
Transform trans;
|
|
float sy, sz;
|
|
iss >> shape_type;
|
|
ParseTransform(iss, trans);
|
|
iss >> sy >> sz;
|
|
glm::vec3 scale(trans.scale, sy, sz);
|
|
trans.scale = 1.0f;
|
|
|
|
trans.position -= model->col_offset_; // apply offset
|
|
|
|
if (!compound)
|
|
{
|
|
compound = std::make_unique<btCompoundShape>();
|
|
}
|
|
|
|
if (shape_type == "box")
|
|
{
|
|
auto box_shape = std::make_unique<btBoxShape>(btVector3(scale.x, scale.y, scale.z));
|
|
compound->addChildShape(trans.ToBtTransform(), box_shape.get());
|
|
model->subshapes_.push_back(std::move(box_shape));
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("Unknown collision shape type: " + shape_type);
|
|
}
|
|
}
|
|
else if (command == "centerofmass")
|
|
{
|
|
glm::vec3 com;
|
|
iss >> com.x >> com.y >> com.z;
|
|
model->col_offset_ = com;
|
|
}
|
|
else if (command == "param")
|
|
{
|
|
std::string key, val;
|
|
iss >> key >> val;
|
|
model->params_[key] = val;
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("Unknown command in model file: " + command);
|
|
}
|
|
});
|
|
|
|
CLIENT_ONLY(
|
|
mb.Build();
|
|
model->mesh_ = mb.GetMesh();
|
|
)
|
|
|
|
// tri mesh
|
|
if (model->cmesh_)
|
|
model->cmesh_->Build();
|
|
|
|
// convex hull
|
|
if (temp_hull)
|
|
{
|
|
temp_hull->recalcLocalAabb();
|
|
|
|
auto shape_hull = std::make_unique<btShapeHull>(temp_hull.get());
|
|
shape_hull->buildHull(temp_hull->getMargin());
|
|
|
|
model->cshape_ = std::make_unique<btConvexHullShape>((btScalar*)shape_hull->getVertexPointer(), shape_hull->numVertices(), sizeof(btVector3));
|
|
}
|
|
else
|
|
{
|
|
model->cshape_ = std::move(compound);
|
|
}
|
|
|
|
return model;
|
|
}
|
|
|
|
const std::string* assets::Model::GetParam(const std::string& key) const
|
|
{
|
|
auto it = params_.find(key);
|
|
if (it == params_.end())
|
|
return nullptr;
|
|
|
|
return &it->second;
|
|
}
|
|
|
|
bool assets::Model::GetParamFloat(const std::string& key, float& out) const
|
|
{
|
|
auto str_val = GetParam(key);
|
|
if (!str_val)
|
|
return false;
|
|
|
|
std::string str = *str_val;
|
|
|
|
auto dashpos = str.find(',');
|
|
if (dashpos != std::string::npos)
|
|
str[dashpos] = '.';
|
|
|
|
out = std::strtof(str.c_str(), nullptr);
|
|
|
|
return true;
|
|
}
|