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(float, m_gradient_distance, 0.25f, "gradient");
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
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_pitch, 1.f, "pitch");
KRNODE_PROPERTY(bool, m_looping, false, "looping");

View File

@@ -74,7 +74,7 @@ public:
void render(RenderInfo& ri) override;
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(float, m_audio_occlusion, 1.f, "audio_occlusion");

View File

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

View File

@@ -80,8 +80,7 @@ public:
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(float, m_min_lod_coverage, 0.f, "min_lod_coverage");
KRNODE_PROPERTY(bool, m_receivesShadow, true, "receives_shadow");

View File

@@ -96,53 +96,63 @@ public:
}
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) {
element->SetAttribute(config::name, val ? "true" : "false");
element->SetAttribute(attributeName, val ? "true" : "false");
} 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) {
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) {
element->SetAttribute(config::name, val.c_str());
element->SetAttribute(attributeName, val.c_str());
} 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 {
element->SetAttribute(config::name, val);
element->SetAttribute(attributeName, val);
}
}
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 (element->QueryIntAttribute(config::name, &val) != tinyxml2::XML_SUCCESS) {
if (element->QueryIntAttribute(attributeName, &val) != tinyxml2::XML_SUCCESS) {
val = config::defaultVal;
}
} 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;
}
} 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;
}
} 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;
}
} 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) {
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) {
const char* name = element->Attribute(config::name);
const char* name = element->Attribute(attributeName);
if (name) {
val = name;
} else {
val = config::defaultVal;
}
} 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) {
val.set(name);
} else {
@@ -163,6 +173,13 @@ public:
}; \
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
: public KRContextObject
, public KRReflectedObject

View File

@@ -69,6 +69,6 @@ public:
private:
KRNODE_PROPERTY(std::string, m_zone, "", "zone");
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");
};