Enable fake geometry and box rendering for m2 particle emitters without mesh as they currently don't render
Make m2 header temporary to save memory, only save useful data
This commit is contained in:
@@ -27,7 +27,7 @@ Model::Model(const std::string& filename, Noggit::NoggitRenderContext context)
|
||||
, _context(context)
|
||||
, _renderer(this)
|
||||
{
|
||||
memset(&header, 0, sizeof(ModelHeader));
|
||||
// memset(&header, 0, sizeof(ModelHeader));
|
||||
}
|
||||
|
||||
void Model::finishLoading()
|
||||
@@ -41,6 +41,8 @@ void Model::finishLoading()
|
||||
throw std::runtime_error("Error loading file \"" + _file_key.stringRepr() + "\". Aborting to load model.");
|
||||
}
|
||||
|
||||
ModelHeader header;
|
||||
|
||||
memcpy(&header, f.getBuffer(), sizeof(ModelHeader));
|
||||
|
||||
|
||||
@@ -84,12 +86,21 @@ void Model::finishLoading()
|
||||
blend_override = M2Array<uint16_t>(f, ofs_blend_override, n_blend_override);
|
||||
}
|
||||
|
||||
animated = isAnimated(f); // isAnimated will set animGeometry and animTextures
|
||||
animated = isAnimated(f, header); // isAnimated will set animGeometry and animTextures
|
||||
|
||||
trans = 1.0f;
|
||||
_current_anim_seq = 0;
|
||||
|
||||
rad = header.bounding_box_radius;
|
||||
bounding_box_min = header.bounding_box_min;
|
||||
bounding_box_max = header.bounding_box_max;
|
||||
bounding_box_radius = header.bounding_box_radius;
|
||||
|
||||
collision_box_min = header.collision_box_min;
|
||||
collision_box_max = header.collision_box_max;
|
||||
collision_box_radius = header.collision_box_radius;
|
||||
|
||||
Flags = header.Flags;
|
||||
|
||||
|
||||
if (header.nGlobalSequences)
|
||||
{
|
||||
@@ -97,15 +108,21 @@ void Model::finishLoading()
|
||||
}
|
||||
|
||||
//! \todo This takes a biiiiiit long. Have a look at this.
|
||||
initCommon(f);
|
||||
initCommon(f, header);
|
||||
|
||||
if (animated)
|
||||
{
|
||||
initAnimated(f);
|
||||
initAnimated(f, header);
|
||||
}
|
||||
|
||||
f.close();
|
||||
|
||||
// add fake geometry for selection
|
||||
if (_renderer.renderPasses().empty() || particles_only() /* || this->file_key().filepath() == "world/generic/passivedoodads/particleemitters/ashenvalewisps.m2"*/)
|
||||
{
|
||||
_fake_geometry.emplace(this);
|
||||
}
|
||||
|
||||
finished = true;
|
||||
_state_changed.notify_all();
|
||||
}
|
||||
@@ -124,7 +141,7 @@ void Model::waitForChildrenLoaded()
|
||||
}
|
||||
|
||||
|
||||
bool Model::isAnimated(const BlizzardArchive::ClientFile& f)
|
||||
bool Model::isAnimated(const BlizzardArchive::ClientFile& f, ModelHeader& header)
|
||||
{
|
||||
// see if we have any animated bones
|
||||
ModelBoneDef const* bo = reinterpret_cast<ModelBoneDef const*>(f.getBuffer() + header.ofsBones);
|
||||
@@ -226,7 +243,7 @@ namespace
|
||||
}
|
||||
|
||||
|
||||
void Model::initCommon(const BlizzardArchive::ClientFile& f)
|
||||
void Model::initCommon(const BlizzardArchive::ClientFile& f, ModelHeader& header)
|
||||
{
|
||||
// vertices, normals, texcoords
|
||||
_vertices = M2Array<ModelVertex>(f, header.ofsVertices, header.nVertices);
|
||||
@@ -237,6 +254,12 @@ void Model::initCommon(const BlizzardArchive::ClientFile& f)
|
||||
v.normal = fixCoordSystem(v.normal);
|
||||
}
|
||||
|
||||
nBoundingTriangles = header.nBoundingTriangles;
|
||||
// Optional, load collision
|
||||
// collision_indices = M2Array<glm::uint16_t>(f, header.ofsBoundingTriangles, header.nBoundingTriangles);
|
||||
// collision_vertices = M2Array<glm::vec3>(f, header.ofsBoundingVertices, header.nBoundingVertices);
|
||||
// collision_normals = M2Array<glm::vec3>(f, header.ofsBoundingNormals, header.nBoundingNormals);
|
||||
|
||||
// textures
|
||||
ModelTextureDef const* texdef = reinterpret_cast<ModelTextureDef const*>(f.getBuffer() + header.ofsTextures);
|
||||
_textureFilenames.resize(header.nTextures);
|
||||
@@ -346,19 +369,13 @@ void Model::initCommon(const BlizzardArchive::ClientFile& f)
|
||||
_renderer.initRenderPasses(view, texture_unit, model_geosets);
|
||||
|
||||
g.close();
|
||||
|
||||
// add fake geometry for selection
|
||||
if (_renderer.renderPasses().empty())
|
||||
{
|
||||
_fake_geometry.emplace(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FakeGeometry::FakeGeometry(Model* m)
|
||||
{
|
||||
glm::vec3 min = m->header.bounding_box_min, max = m->header.bounding_box_max;
|
||||
glm::vec3 min = m->bounding_box_min, max = m->bounding_box_max;
|
||||
|
||||
vertices.emplace_back(min.x, max.y, min.z);
|
||||
vertices.emplace_back(min.x, max.y, max.z);
|
||||
@@ -382,7 +399,7 @@ FakeGeometry::FakeGeometry(Model* m)
|
||||
}
|
||||
|
||||
|
||||
void Model::initAnimated(const BlizzardArchive::ClientFile& f)
|
||||
void Model::initAnimated(const BlizzardArchive::ClientFile& f, ModelHeader& header)
|
||||
{
|
||||
std::vector<std::unique_ptr<BlizzardArchive::ClientFile>> animation_files;
|
||||
|
||||
@@ -480,12 +497,12 @@ void Model::calcBones(glm::mat4x4 const& model_view
|
||||
, int animation_time
|
||||
)
|
||||
{
|
||||
for (size_t i = 0; i<header.nBones; ++i)
|
||||
for (size_t i = 0; i< bones.size(); ++i)
|
||||
{
|
||||
bones[i].calc = false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i<header.nBones; ++i)
|
||||
for (size_t i = 0; i< bones.size(); ++i)
|
||||
{
|
||||
bones[i].calcMatrix(model_view, bones.data(), _anim, time, animation_time);
|
||||
}
|
||||
@@ -568,7 +585,7 @@ void Model::animate(glm::mat4x4 const& model_view, int anim_id, int anim_time)
|
||||
*/
|
||||
}
|
||||
|
||||
for (size_t i=0; i<header.nLights; ++i)
|
||||
for (size_t i=0; i< _lights.size(); ++i)
|
||||
{
|
||||
if (_lights[i].parent >= 0)
|
||||
{
|
||||
@@ -842,12 +859,12 @@ std::vector<std::pair<float, std::tuple<int, int, int>>> Model::intersect (glm::
|
||||
void Model::lightsOn(OpenGL::light lbase)
|
||||
{
|
||||
// setup lights
|
||||
for (unsigned int i=0, l=lbase; i<header.nLights; ++i) _lights[i].setup(_anim_time, l++, _global_animtime);
|
||||
for (unsigned int i=0, l=lbase; i< _lights.size(); ++i) _lights[i].setup(_anim_time, l++, _global_animtime);
|
||||
}
|
||||
|
||||
void Model::lightsOff(OpenGL::light lbase)
|
||||
{
|
||||
for (unsigned int i = 0, l = lbase; i<header.nLights; ++i) gl.disable(l++);
|
||||
for (unsigned int i = 0, l = lbase; i< _lights.size(); ++i) gl.disable(l++);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -179,6 +179,13 @@ public:
|
||||
[[nodiscard]]
|
||||
bool animated_mesh() const { return (animGeometry || animBones); }
|
||||
|
||||
[[nodiscard]]
|
||||
bool particles_only() const
|
||||
{ // some particle emitters like wisps in ashenvale have a few vertices but no collision, using that to detect
|
||||
return !_particles.empty()
|
||||
&& (_renderer.renderPasses().empty() || _vertices.empty() || !nBoundingTriangles);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool is_required_when_saving() const override
|
||||
{
|
||||
@@ -210,10 +217,19 @@ public:
|
||||
// ===============================
|
||||
std::vector<Bone> bones;
|
||||
std::vector<glm::mat4x4> bone_matrices;
|
||||
ModelHeader header;
|
||||
// ModelHeader header; // we really don't need to store the offsets.
|
||||
std::vector<uint16_t> blend_override;
|
||||
|
||||
float rad;
|
||||
glm::vec3 bounding_box_min;
|
||||
glm::vec3 bounding_box_max;
|
||||
float bounding_box_radius;
|
||||
|
||||
glm::vec3 collision_box_min;
|
||||
glm::vec3 collision_box_max;
|
||||
float collision_box_radius;
|
||||
|
||||
uint32_t Flags;
|
||||
|
||||
float trans;
|
||||
bool animcalc;
|
||||
|
||||
@@ -228,6 +244,11 @@ public:
|
||||
|
||||
std::optional<FakeGeometry> _fake_geometry;
|
||||
|
||||
uint32_t nBoundingTriangles;
|
||||
// std::vector<uint16_t> collision_indices;
|
||||
// std::vector<glm::vec3> collision_vertices;
|
||||
// std::vector<glm::vec3> collision_normals;
|
||||
|
||||
private:
|
||||
bool _per_instance_animation;
|
||||
int _current_anim_seq;
|
||||
@@ -236,9 +257,9 @@ private:
|
||||
|
||||
Noggit::NoggitRenderContext _context;
|
||||
|
||||
void initCommon(const BlizzardArchive::ClientFile& f);
|
||||
bool isAnimated(const BlizzardArchive::ClientFile& f);
|
||||
void initAnimated(const BlizzardArchive::ClientFile& f);
|
||||
void initCommon(const BlizzardArchive::ClientFile& f, ModelHeader& header);
|
||||
bool isAnimated(const BlizzardArchive::ClientFile& f, ModelHeader& header);
|
||||
void initAnimated(const BlizzardArchive::ClientFile& f, ModelHeader& header);
|
||||
|
||||
void animate(glm::mat4x4 const& model_view, int anim_id, int anim_time);
|
||||
void calcBones(glm::mat4x4 const& model_view, int anim, int time, int animation_time);
|
||||
|
||||
@@ -75,11 +75,11 @@ struct ModelHeader {
|
||||
glm::vec3 collision_box_max;
|
||||
float collision_box_radius;
|
||||
|
||||
uint32_t nBoundingTriangles;
|
||||
uint32_t nBoundingTriangles; // aka collisionIndices or collision_triangles
|
||||
uint32_t ofsBoundingTriangles;
|
||||
uint32_t nBoundingVertices;
|
||||
uint32_t ofsBoundingVertices;
|
||||
uint32_t nBoundingNormals;
|
||||
uint32_t nBoundingNormals; // collisionFaceNormals
|
||||
uint32_t ofsBoundingNormals;
|
||||
|
||||
uint32_t nAttachments; // O
|
||||
|
||||
@@ -55,8 +55,8 @@ void ModelInstance::draw_box (glm::mat4x4 const& model_view
|
||||
, projection
|
||||
, transformMatrix()
|
||||
, { 1.0f, 1.0f, 0.0f, 1.0f }
|
||||
, misc::transform_model_box_coords(model->header.collision_box_min)
|
||||
, misc::transform_model_box_coords(model->header.collision_box_max)
|
||||
, misc::transform_model_box_coords(model->collision_box_min)
|
||||
, misc::transform_model_box_coords(model->collision_box_max)
|
||||
);
|
||||
|
||||
// draw bounding box
|
||||
@@ -64,8 +64,8 @@ void ModelInstance::draw_box (glm::mat4x4 const& model_view
|
||||
, projection
|
||||
, transformMatrix()
|
||||
, {1.0f, 1.0f, 1.0f, 1.0f}
|
||||
, misc::transform_model_box_coords(model->header.bounding_box_min)
|
||||
, misc::transform_model_box_coords(model->header.bounding_box_max)
|
||||
, misc::transform_model_box_coords(model->bounding_box_min)
|
||||
, misc::transform_model_box_coords(model->bounding_box_max)
|
||||
);
|
||||
|
||||
// draw extents
|
||||
@@ -84,8 +84,8 @@ void ModelInstance::draw_box (glm::mat4x4 const& model_view
|
||||
, projection
|
||||
, transformMatrix()
|
||||
, color
|
||||
, misc::transform_model_box_coords(model->header.bounding_box_min)
|
||||
, misc::transform_model_box_coords(model->header.bounding_box_max)
|
||||
, misc::transform_model_box_coords(model->bounding_box_min)
|
||||
, misc::transform_model_box_coords(model->bounding_box_max)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -104,8 +104,8 @@ void ModelInstance::intersect (glm::mat4x4 const& model_view
|
||||
std::vector<std::tuple<int, int, int>> triangle_indices;
|
||||
math::ray subray (_transform_mat_inverted, ray);
|
||||
|
||||
if ( !subray.intersect_bounds ( fixCoordSystem (model->header.bounding_box_min)
|
||||
, fixCoordSystem (model->header.bounding_box_max)
|
||||
if ( !subray.intersect_bounds ( fixCoordSystem (model->bounding_box_min)
|
||||
, fixCoordSystem (model->bounding_box_max)
|
||||
)
|
||||
)
|
||||
{
|
||||
@@ -142,11 +142,11 @@ bool ModelInstance::isInRenderDist(const float& cull_distance, const glm::vec3&
|
||||
|
||||
if (display == display_mode::in_3D)
|
||||
{
|
||||
dist = glm::distance(camera, pos) - model->rad * scale;
|
||||
dist = glm::distance(camera, pos) - model->bounding_box_radius * scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
dist = std::abs(pos.y - camera.y) - model->rad * scale;
|
||||
dist = std::abs(pos.y - camera.y) - model->bounding_box_radius * scale;
|
||||
}
|
||||
|
||||
if (dist >= cull_distance)
|
||||
@@ -188,8 +188,8 @@ void ModelInstance::recalcExtents()
|
||||
updateTransformMatrix();
|
||||
|
||||
math::aabb const relative_to_model
|
||||
( glm::min ( model->header.collision_box_min, model->header.bounding_box_min)
|
||||
, glm::max ( model->header.collision_box_max, model->header.bounding_box_max)
|
||||
( glm::min ( model->collision_box_min, model->bounding_box_min)
|
||||
, glm::max ( model->collision_box_max, model->bounding_box_max)
|
||||
);
|
||||
|
||||
//! \todo If both boxes are {inf, -inf}, or well, if any min.c > max.c,
|
||||
@@ -259,10 +259,10 @@ void ModelInstance::updateDetails(Noggit::Ui::detail_infos* detail_widget)
|
||||
<< "<br><b>server position X/Y/Z: </b>{" << (ZEROPOINT - pos.z) << ", " << (ZEROPOINT - pos.x) << ", " << pos.y << "}"
|
||||
<< "<br><b>server orientation: </b>" << fabs(2 * glm::pi<float>() - glm::pi<float>() / 180.0 * (float(dir.y) < 0 ? fabs(float(dir.y)) + 180.0 : fabs(float(dir.y) - 180.0)))
|
||||
|
||||
<< "<br><b>textures Used:</b> " << model->header.nTextures
|
||||
<< "<br><b>textures Used:</b> " << model->_textures.size()
|
||||
<< "<br><b>size category:</b><span> " << size_cat;
|
||||
|
||||
for (unsigned j = 0; j < model->header.nTextures; j++)
|
||||
for (unsigned j = 0; j < model->_textures.size(); j++)
|
||||
{
|
||||
bool stuck = !model->_textures[j]->finishedLoading();
|
||||
bool error = model->_textures[j]->finishedLoading() && !model->_textures[j]->is_uploaded();
|
||||
|
||||
@@ -19,8 +19,8 @@ ModelRender::ModelRender(Model* model)
|
||||
void ModelRender::upload()
|
||||
{
|
||||
_vertex_box_points = math::box_points(
|
||||
misc::transform_model_box_coords(_model->header.bounding_box_min)
|
||||
, misc::transform_model_box_coords(_model->header.bounding_box_max));
|
||||
misc::transform_model_box_coords(_model->bounding_box_min)
|
||||
, misc::transform_model_box_coords(_model->bounding_box_max));
|
||||
|
||||
for (std::string const& texture : _model->_textureFilenames)
|
||||
_model->_textures.emplace_back(texture, _model->_context);
|
||||
@@ -197,10 +197,14 @@ void ModelRender::draw(glm::mat4x4 const& model_view
|
||||
}
|
||||
|
||||
// store the model count to draw the bounding boxes later
|
||||
if (all_boxes || _model->_hidden)
|
||||
if (all_boxes || _model->_hidden )
|
||||
{
|
||||
model_boxes_to_draw.emplace(_model, instances.size());
|
||||
}
|
||||
else if (_model->use_fake_geometry() /*|| _model->particles_only()*/)
|
||||
{ // hackfix for rendering particle only objects bounds as they currently don't render
|
||||
model_boxes_to_draw.emplace(_model, instances.size());
|
||||
}
|
||||
|
||||
/*
|
||||
if (draw_particles && (!_particles.empty() || !_ribbons.empty()))
|
||||
@@ -317,7 +321,7 @@ void ModelRender::fixShaderIdBlendOverride()
|
||||
}
|
||||
|
||||
int shader = 0;
|
||||
bool blend_mode_override = (_model->header.Flags & m2_flag_use_texture_combiner_combos);
|
||||
bool blend_mode_override = (_model->Flags & m2_flag_use_texture_combiner_combos);
|
||||
|
||||
// fuckporting check
|
||||
if (pass.texture_coord_combo_index + pass.texture_count - 1 >= _model->_texture_unit_lookup.size())
|
||||
|
||||
@@ -858,7 +858,8 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
models_to_draw.clear();
|
||||
wmos_to_draw.clear();
|
||||
|
||||
if(draw_models_with_box || (draw_hidden_models && !model_boxes_to_draw.empty()))
|
||||
// if(draw_models_with_box || (draw_hidden_models && !model_boxes_to_draw.empty()))
|
||||
if (!model_boxes_to_draw.empty())
|
||||
{
|
||||
OpenGL::Scoped::use_program m2_box_shader{ *_m2_box_program.get() };
|
||||
|
||||
@@ -896,17 +897,8 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
|
||||
if (model->_rendered_last_frame)
|
||||
{
|
||||
bool is_selected = false;
|
||||
/*
|
||||
auto id = model->uid;
|
||||
bool const is_selected = _world->current_selection().size() > 0 &&
|
||||
std::find_if(_world->current_selection().begin(), _world->current_selection().end(),
|
||||
[id](selection_type type)
|
||||
{
|
||||
return var_type(type) == typeid(selected_object_type)
|
||||
&& std::get<selected_object_type>(type)->which() == SceneObjectTypes::eMODEL
|
||||
&& static_cast<ModelInstance*>(std::get<selected_object_type>(type))->uid == id;
|
||||
}) != _world->current_selection().end();*/
|
||||
// bool is_selected = false;
|
||||
bool is_selected = _world->is_selected(model->uid);
|
||||
|
||||
model->draw_box(model_view, projection, is_selected); // make optional!
|
||||
}
|
||||
@@ -1101,7 +1093,7 @@ void WorldRender::draw (glm::mat4x4 const& model_view
|
||||
}
|
||||
}
|
||||
|
||||
if (terrainMode == editing_mode::light)
|
||||
if (terrainMode == editing_mode::light && alpha_light_sphere > 0.0f)
|
||||
{
|
||||
// Sky* CurrentSky = skies()->findClosestSkyByDistance(camera_pos);
|
||||
Sky* CurrentSky = skies()->findClosestSkyByWeight();
|
||||
|
||||
Reference in New Issue
Block a user