Fixed crash on initialization of KRResourceBinding encapsulated in KRNodeProperty by changing default value to an empty string rather than nullptr. Implemented KRNODE_PROPERTY_ARRAY. KRModel meshes are now using KRNODE_PROPERTY_ARRAY

This commit is contained in:
2025-11-24 21:14:24 -08:00
parent ae9469dd62
commit a4c8b77f3a
7 changed files with 55 additions and 40 deletions

View File

@@ -71,5 +71,5 @@ private:
KRNODE_PROPERTY(std::string, m_zone, "", "zone"); KRNODE_PROPERTY(std::string, m_zone, "", "zone");
KRNODE_PROPERTY(float, m_gradient_distance, 0.25f, "gradient"); KRNODE_PROPERTY(float, m_gradient_distance, 0.25f, "gradient");
KRNODE_PROPERTY(float, m_ambient_gain, 1.f, "gain"); KRNODE_PROPERTY(float, m_ambient_gain, 1.f, "gain");
KRNODE_PROPERTY(KRAudioSampleBinding, m_ambient, nullptr, "sample"); KRNODE_PROPERTY(KRAudioSampleBinding, m_ambient, "", "sample");
}; };

View File

@@ -133,7 +133,7 @@ private:
int m_currentBufferFrame; // Siren Audio Engine frame number within current buffer int m_currentBufferFrame; // Siren Audio Engine frame number within current buffer
void advanceBuffer(); void advanceBuffer();
KRNODE_PROPERTY(KRAudioSampleBinding, m_sample, nullptr, "sample"); KRNODE_PROPERTY(KRAudioSampleBinding, m_sample, "", "sample");
KRNODE_PROPERTY(float, m_gain, 1.f, "gain"); KRNODE_PROPERTY(float, m_gain, 1.f, "gain");
KRNODE_PROPERTY(float, m_pitch, 1.f, "pitch"); KRNODE_PROPERTY(float, m_pitch, 1.f, "pitch");
KRNODE_PROPERTY(bool, m_looping, false, "looping"); KRNODE_PROPERTY(bool, m_looping, false, "looping");

View File

@@ -74,7 +74,7 @@ public:
void render(RenderInfo& ri) override; void render(RenderInfo& ri) override;
private: private:
KRNODE_PROPERTY(KRMeshBinding, m_model, nullptr, "mesh"); KRNODE_PROPERTY(KRMeshBinding, m_model, "", "mesh");
KRNODE_PROPERTY(unsigned int, m_layer_mask, 0xffffffff, "layer_mask"); KRNODE_PROPERTY(unsigned int, m_layer_mask, 0xffffffff, "layer_mask");
KRNODE_PROPERTY(float, m_audio_occlusion, 1.f, "audio_occlusion"); KRNODE_PROPERTY(float, m_audio_occlusion, 1.f, "audio_occlusion");

View File

@@ -109,7 +109,7 @@ KrResult KRModel::update(const KrNodeInfo* nodeInfo)
return res; return res;
} }
} }
m_meshes[lod].set(mesh); m_meshes[lod].val.set(mesh);
} }
return KR_SUCCESS; return KR_SUCCESS;
@@ -128,13 +128,12 @@ void KRModel::loadXML(tinyxml2::XMLElement* e)
m_receivesShadow.load(e); m_receivesShadow.load(e);
m_rim_power.load(e); m_rim_power.load(e);
m_rim_color.load(e); m_rim_color.load(e);
std::string meshNames[KRModel::kMeshLODCount];
m_meshes[0].set(e->Attribute("mesh")); m_meshes[0].load(e);
for (int lod = 1; lod < KRModel::kMeshLODCount; lod++) { for (int lod = 1; lod < KRModel::kMeshLODCount; lod++) {
char attribName[8]; char attribName[8];
snprintf(attribName, 8, "mesh%i", lod); snprintf(attribName, 8, "mesh%i", lod);
m_meshes[lod].set(e->Attribute(attribName)); m_meshes[lod].load(e, attribName);
} }
m_lightMap.load(e); m_lightMap.load(e);
@@ -143,11 +142,11 @@ void KRModel::loadXML(tinyxml2::XMLElement* e)
tinyxml2::XMLElement* KRModel::saveXML(tinyxml2::XMLNode* parent) tinyxml2::XMLElement* KRModel::saveXML(tinyxml2::XMLNode* parent)
{ {
tinyxml2::XMLElement* e = KRNode::saveXML(parent); tinyxml2::XMLElement* e = KRNode::saveXML(parent);
e->SetAttribute("mesh", m_meshes[0].getName().c_str()); m_meshes[0].load(e);
for (int lod = 1; lod < kMeshLODCount; lod++) { for (int lod = 1; lod < kMeshLODCount; lod++) {
char attribName[8]; char attribName[8];
snprintf(attribName, 8, "mesh%i", lod); snprintf(attribName, 8, "mesh%i", lod);
e->SetAttribute(attribName, m_meshes[lod].getName().c_str()); m_meshes[lod].load(e, attribName);
} }
m_lightMap.save(e); m_lightMap.save(e);
m_min_lod_coverage.save(e); m_min_lod_coverage.save(e);
@@ -193,13 +192,13 @@ void KRModel::loadModel()
bool meshChanged = false; bool meshChanged = false;
for (int lod = 0; lod < kMeshLODCount; lod++) { for (int lod = 0; lod < kMeshLODCount; lod++) {
KRMesh* prevMesh = nullptr; KRMesh* prevMesh = nullptr;
prevMesh = m_meshes[lod].get(); prevMesh = m_meshes[lod].val.get();
m_meshes[lod].bind(&getContext()); m_meshes[lod].val.bind(&getContext());
if (m_meshes[lod].get() != prevMesh) { if (m_meshes[lod].val.get() != prevMesh) {
meshChanged = true; meshChanged = true;
} }
if (m_meshes[lod].isBound()) { if (m_meshes[lod].val.isBound()) {
KRMesh* model = m_meshes[lod].get(); KRMesh* model = m_meshes[lod].val.get();
std::vector<KRBone*> model_bones; std::vector<KRBone*> model_bones;
int bone_count = model->getBoneCount(); int bone_count = model->getBoneCount();
bool all_bones_found = true; bool all_bones_found = true;
@@ -262,8 +261,8 @@ void KRModel::render(KRNode::RenderInfo& ri)
int bestLOD = -1; int bestLOD = -1;
KRMesh* pModel = nullptr; KRMesh* pModel = nullptr;
for (int lod = 0; lod < kMeshLODCount; lod++) { for (int lod = 0; lod < kMeshLODCount; lod++) {
if (m_meshes[lod].isBound()) { if (m_meshes[lod].val.isBound()) {
KRMesh* pLODModel = m_meshes[lod].get(); KRMesh* pLODModel = m_meshes[lod].val.get();
if ((float)pLODModel->getLODCoverage() / 100.0f > lod_coverage) { if ((float)pLODModel->getLODCoverage() / 100.0f > lod_coverage) {
if(bestLOD == -1 || pLODModel->getLODCoverage() < pModel->getLODCoverage()) { if(bestLOD == -1 || pLODModel->getLODCoverage() < pModel->getLODCoverage()) {
@@ -294,7 +293,7 @@ void KRModel::getResourceBindings(std::list<KRResourceBinding*>& bindings)
KRNode::getResourceBindings(bindings); KRNode::getResourceBindings(bindings);
for (int i = 0; i < kMeshLODCount; i++) { for (int i = 0; i < kMeshLODCount; i++) {
bindings.push_back(&m_meshes[i]); bindings.push_back(&m_meshes[i].val);
} }
bindings.push_back(&m_lightMap.val); bindings.push_back(&m_lightMap.val);
} }
@@ -306,8 +305,8 @@ void KRModel::preStream(const KRViewport& viewport, std::list<KRResourceRequest>
loadModel(); loadModel();
for (int i = 0; i < kMeshLODCount; i++) { for (int i = 0; i < kMeshLODCount; i++) {
if (m_meshes[i].isBound()) { if (m_meshes[i].val.isBound()) {
m_meshes[i].get()->preStream(); m_meshes[i].val.get()->preStream();
} }
} }
} }
@@ -319,8 +318,8 @@ kraken_stream_level KRModel::getStreamLevel(const KRViewport& viewport)
loadModel(); loadModel();
for (int lod = 0; lod < kMeshLODCount; lod++) { for (int lod = 0; lod < kMeshLODCount; lod++) {
if (m_meshes[lod].isBound()) { if (m_meshes[lod].val.isBound()) {
stream_level = KRMIN(stream_level, m_meshes[lod].get()->getStreamLevel()); stream_level = KRMIN(stream_level, m_meshes[lod].val.get()->getStreamLevel());
} }
} }
@@ -333,10 +332,10 @@ AABB KRModel::getBounds()
// Get the bounds of the lowest lod mesh // Get the bounds of the lowest lod mesh
for(int lod=0; lod<kMeshLODCount; lod++) { for(int lod=0; lod<kMeshLODCount; lod++) {
if (!m_meshes[lod].isBound()) { if (!m_meshes[lod].val.isBound()) {
continue; continue;
} }
KRMesh* mesh = m_meshes[lod].get(); KRMesh* mesh = m_meshes[lod].val.get();
if (m_faces_camera) { if (m_faces_camera) {
AABB normal_bounds = AABB::Create(mesh->getMinPoint(), mesh->getMaxPoint(), getModelMatrix()); AABB normal_bounds = AABB::Create(mesh->getMinPoint(), mesh->getMaxPoint(), getModelMatrix());
float max_dimension = normal_bounds.longest_radius(); float max_dimension = normal_bounds.longest_radius();

View File

@@ -80,8 +80,7 @@ public:
private: private:
std::array<KRMeshBinding, kMeshLODCount> m_meshes; KRNODE_PROPERTY_ARRAY(KRMeshBinding, m_meshes, "", "mesh", kMeshLODCount);
KRNODE_PROPERTY(KRTextureBinding, m_lightMap, KRTexture::TEXTURE_USAGE_LIGHT_MAP, "light_map"); KRNODE_PROPERTY(KRTextureBinding, m_lightMap, KRTexture::TEXTURE_USAGE_LIGHT_MAP, "light_map");
KRNODE_PROPERTY(float, m_min_lod_coverage, 0.f, "min_lod_coverage"); KRNODE_PROPERTY(float, m_min_lod_coverage, 0.f, "min_lod_coverage");
KRNODE_PROPERTY(bool, m_receivesShadow, true, "receives_shadow"); KRNODE_PROPERTY(bool, m_receivesShadow, true, "receives_shadow");

View File

@@ -96,53 +96,63 @@ public:
} }
void save(tinyxml2::XMLElement* element) const void save(tinyxml2::XMLElement* element) const
{
save(element, config::name);
}
void save(tinyxml2::XMLElement* element, const char* attributeName) const
{ {
if constexpr (std::is_same<T, bool>::value) { if constexpr (std::is_same<T, bool>::value) {
element->SetAttribute(config::name, val ? "true" : "false"); element->SetAttribute(attributeName, val ? "true" : "false");
} else if constexpr (std::is_same<T, hydra::Vector3>::value) { } else if constexpr (std::is_same<T, hydra::Vector3>::value) {
kraken::setXMLAttribute(config::name, element, val, config::defaultVal); kraken::setXMLAttribute(attributeName, element, val, config::defaultVal);
} else if constexpr (std::is_same<T, hydra::AABB>::value) { } else if constexpr (std::is_same<T, hydra::AABB>::value) {
kraken::setXMLAttribute(config::name, element, val, config::defaultVal); kraken::setXMLAttribute(attributeName, element, val, config::defaultVal);
} else if constexpr (std::is_same<T, std::string>::value) { } else if constexpr (std::is_same<T, std::string>::value) {
element->SetAttribute(config::name, val.c_str()); element->SetAttribute(attributeName, val.c_str());
} else if constexpr (std::is_base_of<KRResourceBinding, T>::value) { } else if constexpr (std::is_base_of<KRResourceBinding, T>::value) {
element->SetAttribute(config::name, val.getName().c_str()); element->SetAttribute(attributeName, val.getName().c_str());
} else { } else {
element->SetAttribute(config::name, val); element->SetAttribute(attributeName, val);
} }
} }
void load(tinyxml2::XMLElement* element) void load(tinyxml2::XMLElement* element)
{
load(element, config::name);
}
void load(tinyxml2::XMLElement* element, const char* attributeName)
{ {
if constexpr (std::is_same<T, int>::value) { if constexpr (std::is_same<T, int>::value) {
if (element->QueryIntAttribute(config::name, &val) != tinyxml2::XML_SUCCESS) { if (element->QueryIntAttribute(attributeName, &val) != tinyxml2::XML_SUCCESS) {
val = config::defaultVal; val = config::defaultVal;
} }
} else if constexpr (std::is_same<T, unsigned int>::value) { } else if constexpr (std::is_same<T, unsigned int>::value) {
if (element->QueryUnsignedAttribute(config::name, &val) != tinyxml2::XML_SUCCESS) { if (element->QueryUnsignedAttribute(attributeName, &val) != tinyxml2::XML_SUCCESS) {
val = config::defaultVal; val = config::defaultVal;
} }
} else if constexpr (std::is_same<T, float>::value) { } else if constexpr (std::is_same<T, float>::value) {
if (element->QueryFloatAttribute(config::name, &val) != tinyxml2::XML_SUCCESS) { if (element->QueryFloatAttribute(attributeName, &val) != tinyxml2::XML_SUCCESS) {
val = config::defaultVal; val = config::defaultVal;
} }
} else if constexpr (std::is_same<T, bool>::value) { } else if constexpr (std::is_same<T, bool>::value) {
if (element->QueryBoolAttribute(config::name, &val) != tinyxml2::XML_SUCCESS) { if (element->QueryBoolAttribute(attributeName, &val) != tinyxml2::XML_SUCCESS) {
val = config::defaultVal; val = config::defaultVal;
} }
} else if constexpr (std::is_same<T, hydra::Vector3>::value) { } else if constexpr (std::is_same<T, hydra::Vector3>::value) {
val = kraken::getXMLAttribute(config::name, element, config::defaultVal); val = kraken::getXMLAttribute(attributeName, element, config::defaultVal);
} else if constexpr (std::is_same<T, hydra::AABB>::value) { } else if constexpr (std::is_same<T, hydra::AABB>::value) {
val = kraken::getXMLAttribute(config::name, element, config::defaultVal); val = kraken::getXMLAttribute(attributeName, element, config::defaultVal);
} else if constexpr (std::is_same<T, std::string>::value) { } else if constexpr (std::is_same<T, std::string>::value) {
const char* name = element->Attribute(config::name); const char* name = element->Attribute(attributeName);
if (name) { if (name) {
val = name; val = name;
} else { } else {
val = config::defaultVal; val = config::defaultVal;
} }
} else if constexpr (std::is_base_of<KRResourceBinding, T>::value) { } else if constexpr (std::is_base_of<KRResourceBinding, T>::value) {
const char* name = element->Attribute(config::name); const char* name = element->Attribute(attributeName);
if (name) { if (name) {
val.set(name); val.set(name);
} else { } else {
@@ -163,6 +173,13 @@ public:
}; \ }; \
KRNodeProperty<PROP_TYPE, VAR ## _config> VAR; KRNodeProperty<PROP_TYPE, VAR ## _config> VAR;
#define KRNODE_PROPERTY_ARRAY(PROP_TYPE, VAR, PROP_DEFAULT, PROP_NAME, ARRAY_SIZE) \
struct VAR ## _config { \
static constexpr decltype(PROP_DEFAULT) defaultVal = PROP_DEFAULT; \
static constexpr const char* name = PROP_NAME; \
}; \
std::array<KRNodeProperty<PROP_TYPE, VAR ## _config>, ARRAY_SIZE> VAR;
class KRNode class KRNode
: public KRContextObject : public KRContextObject
, public KRReflectedObject , public KRReflectedObject

View File

@@ -69,6 +69,6 @@ public:
private: private:
KRNODE_PROPERTY(std::string, m_zone, "", "zone"); KRNODE_PROPERTY(std::string, m_zone, "", "zone");
KRNODE_PROPERTY(float, m_gradient_distance, 0.25f, "gradient"); KRNODE_PROPERTY(float, m_gradient_distance, 0.25f, "gradient");
KRNODE_PROPERTY(KRAudioSampleBinding, m_reverb, nullptr, "sample"); KRNODE_PROPERTY(KRAudioSampleBinding, m_reverb, "", "sample");
KRNODE_PROPERTY(float, m_reverb_gain, 1.f, "gain"); KRNODE_PROPERTY(float, m_reverb_gain, 1.f, "gain");
}; };