diff --git a/include/Engine/Core/ComponentInfo.h b/include/Engine/Core/ComponentInfo.h index ee5f1a11..909224e2 100644 --- a/include/Engine/Core/ComponentInfo.h +++ b/include/Engine/Core/ComponentInfo.h @@ -12,9 +12,15 @@ struct ComponentInfo unsigned int Stride = 0; }; + struct Field_t + { + std::string Type; + unsigned int Offset; + unsigned int Stride; + }; + std::string Name; - std::unordered_map FieldTypes; - std::unordered_map FieldOffsets; + std::unordered_map Fields; Meta_t Meta; std::shared_ptr Defaults = nullptr; }; diff --git a/include/Engine/Core/ComponentWrapper.h b/include/Engine/Core/ComponentWrapper.h index 56ae943f..922b3d79 100644 --- a/include/Engine/Core/ComponentWrapper.h +++ b/include/Engine/Core/ComponentWrapper.h @@ -21,7 +21,7 @@ struct ComponentWrapper template T& Property(std::string name) { - unsigned int offset = Info.FieldOffsets.at(name); + unsigned int offset = Info.Fields.at(name).Offset; return *reinterpret_cast(&Data[offset]); } @@ -78,8 +78,9 @@ public: void AddProperty(std::string fieldName, T defaultValue) { m_DefaultValues.push_back(defaultValue); - m_ComponentInfo.FieldTypes[fieldName] = typeid(T).name(); - m_ComponentInfo.FieldOffsets[fieldName] = m_ComponentInfo.Meta.Stride; + m_ComponentInfo.Fields[fieldName].Name = typeid(T).name(); + m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Meta.Stride; + m_ComponentInfo.Fields[fieldName].Stride = sizeof(T); m_ComponentInfo.Meta.Stride += sizeof(T); } diff --git a/include/Engine/Core/EntityFile.h b/include/Engine/Core/EntityFile.h index 3bee9a5b..b6f0c434 100644 --- a/include/Engine/Core/EntityFile.h +++ b/include/Engine/Core/EntityFile.h @@ -275,8 +275,8 @@ private: public: static std::size_t GetTypeStride(std::string typeName); - static void WriteAttributeData(char* outData, const std::string fieldType, const std::map& attributes); - static void WriteValueData(char* outData, const std::string fieldType, const char* valueData); + static void WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map& attributes); + static void WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData); xercesc::XMLGrammarPool* GrammarPool() const { return m_GrammarPool; } diff --git a/src/Engine/Core/EntityFile.cpp b/src/Engine/Core/EntityFile.cpp index b05c9e48..1e381df5 100644 --- a/src/Engine/Core/EntityFile.cpp +++ b/src/Engine/Core/EntityFile.cpp @@ -46,50 +46,50 @@ std::size_t EntityFile::GetTypeStride(std::string typeName) return (it != typeStrides.end()) ? it->second : 0; } -void EntityFile::WriteAttributeData(char* outData, const std::string fieldType, const std::map& attributes) +void EntityFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map& attributes) { - if (fieldType == "Vector") { + if (field.Type == "Vector") { glm::vec3 vec; vec.x = boost::lexical_cast(attributes.at("X")); vec.y = boost::lexical_cast(attributes.at("Y")); vec.z = boost::lexical_cast(attributes.at("Z")); - memcpy(outData, reinterpret_cast(&vec), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "Color") { + memcpy(outData, reinterpret_cast(&vec), field.Stride); + } else if (field.Type == "Color") { glm::vec4 vec; vec.r = boost::lexical_cast(attributes.at("R")); vec.g = boost::lexical_cast(attributes.at("G")); vec.b = boost::lexical_cast(attributes.at("B")); vec.a = boost::lexical_cast(attributes.at("A")); - memcpy(outData, reinterpret_cast(&vec), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "Quaternion") { + memcpy(outData, reinterpret_cast(&vec), field.Stride); + } else if (field.Type == "Quaternion") { glm::quat q; q.x = boost::lexical_cast(attributes.at("X")); q.y = boost::lexical_cast(attributes.at("Y")); q.z = boost::lexical_cast(attributes.at("Z")); q.w = boost::lexical_cast(attributes.at("W")); - memcpy(outData, reinterpret_cast(&q), EntityFile::GetTypeStride(fieldType)); + memcpy(outData, reinterpret_cast(&q), field.Stride); } else if (!attributes.empty()) { LOG_WARNING("%i attributes not handled by any type conversion!", attributes.size()); } } -void EntityFile::WriteValueData(char* outData, const std::string fieldType, const char* valueData) +void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData) { - if (fieldType == "int") { + if (field.Type == "int") { int value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "float") { + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "float") { float value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "double") { + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "double") { double value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "bool") { + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "bool") { bool value = (valueData[0] == 't'); // Lazy bool evaluation - memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "string") { + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "string") { new (outData) std::string(valueData); } else { - LOG_WARNING("Unknown value data type: %s", fieldType.c_str()); + LOG_WARNING("Unknown value data type: %s", field.Type.c_str()); } } diff --git a/src/Engine/Core/EntityFileParser.cpp b/src/Engine/Core/EntityFileParser.cpp index e14e5508..5e685abe 100644 --- a/src/Engine/Core/EntityFileParser.cpp +++ b/src/Engine/Core/EntityFileParser.cpp @@ -35,24 +35,24 @@ void EntityFileParser::onStartComponentField(EntityID entity, std::string compon { EntityID realEntity = m_EntityIDMapper.at(entity); ComponentWrapper component = m_World->GetComponent(realEntity, componentType); - std::string fieldType = component.Info.FieldTypes.at(fieldName); + auto& field = component.Info.Fields.at(fieldName); - LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), fieldType.c_str()); + LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str()); LOG_DEBUG("Attributes:"); for (auto& kv : attributes) { LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str()); } - char* data = component.Data + component.Info.FieldOffsets.at(fieldName); - EntityFile::WriteAttributeData(data, fieldType, attributes); + char* data = component.Data + field.Offset; + EntityFile::WriteAttributeData(data, field, attributes); } void EntityFileParser::onFieldData(EntityID entity, std::string componentType, std::string fieldName, const char* fieldData) { EntityID realEntity = m_EntityIDMapper.at(entity); ComponentWrapper component = m_World->GetComponent(realEntity, componentType); - std::string fieldType = component.Info.FieldTypes.at(fieldName); + auto& field = component.Info.Fields.at(fieldName); - char* data = component.Data + component.Info.FieldOffsets.at(fieldName); - EntityFile::WriteValueData(data, fieldType, fieldData); + char* data = component.Data + field.Offset; + EntityFile::WriteValueData(data, field, fieldData); } diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityFilePreprocessor.cpp index 1f6b36f1..4fd768a1 100644 --- a/src/Engine/Core/EntityFilePreprocessor.cpp +++ b/src/Engine/Core/EntityFilePreprocessor.cpp @@ -19,8 +19,9 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile) LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta.Annotation.c_str()); LOG_DEBUG("Stride: %i", info.Meta.Stride); LOG_DEBUG("Allocation: %i", info.Meta.Allocation); - for (auto& kv : info.FieldTypes) { - LOG_DEBUG("\t%i\t%s %s", info.FieldOffsets[kv.first], kv.second.c_str(), kv.first.c_str()); + for (auto& kv : info.Fields) { + auto& field = kv.second; + LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type, kv.first.c_str()); } } @@ -142,8 +143,10 @@ void EntityFilePreprocessor::parseComponentInfo() continue; } - compInfo.FieldTypes[name] = type; - compInfo.FieldOffsets[name] = fieldOffset; + compInfo.Fields[name].Type = type; + compInfo.Fields[name].Offset = fieldOffset; + compInfo.Fields[name].Stride = stride; + fieldOffset += stride; } @@ -187,8 +190,9 @@ void EntityFilePreprocessor::parseDefaults() auto componentElement = dynamic_cast(rootNodes->item(0)); // Fill the default value buffer with values - for (auto& field : ci.second.FieldOffsets) { - std::string fieldName = field.first; + for (auto& kv : ci.second.Fields) { + std::string fieldName = kv.first; + auto& field = kv.second; auto fieldNodes = componentElement->getElementsByTagName(XS::ToXMLCh(fieldName)); auto fieldNode = fieldNodes->item(0); if (fieldNode == nullptr) { @@ -197,9 +201,7 @@ void EntityFilePreprocessor::parseDefaults() } auto fieldElement = dynamic_cast(fieldNode); - std::string fieldType = ci.second.FieldTypes.at(fieldName); - unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName); - char* data = ci.second.Defaults.get() + fieldOffset; + char* data = ci.second.Defaults.get() + field.Offset; // Handle potential field attributes if (fieldElement->hasAttributes()) { @@ -209,14 +211,14 @@ void EntityFilePreprocessor::parseDefaults() auto attribItem = attributeMap->item(i); attributes[XS::ToString(attribItem->getNodeName())] = XS::ToString(attribItem->getNodeValue()); } - EntityFile::WriteAttributeData(data, fieldType, attributes); + EntityFile::WriteAttributeData(data, field, attributes); } // Handle potential field values auto childNode = fieldElement->getFirstChild(); if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) { char* cstrValue = XMLString::transcode(childNode->getNodeValue()); - EntityFile::WriteValueData(data, fieldType, cstrValue); + EntityFile::WriteValueData(data, field, cstrValue); XMLString::release(&cstrValue); } } diff --git a/src/Engine/Core/EntityFileWriter.cpp b/src/Engine/Core/EntityFileWriter.cpp index 8207fbe3..f0c3684f 100644 --- a/src/Engine/Core/EntityFileWriter.cpp +++ b/src/Engine/Core/EntityFileWriter.cpp @@ -64,54 +64,53 @@ void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement DOMElement* componentElement = doc->createElement(X(qualifiedComponentName)); parentElement->appendChild(componentElement); ComponentWrapper c = kv.second->GetByEntity(entity); - for (auto& kv : c.Info.FieldTypes) { + for (auto& kv : c.Info.Fields) { std::string fieldName = kv.first; - std::string fieldType = kv.second; - std::size_t fieldOffset = c.Info.FieldOffsets.at(fieldName); + auto& field = kv.second; // Ignore fields that are equal to the default // HACK: This is probably sloooooow, but it's okay. - if (memcmp(c.Data + fieldOffset, c.Info.Defaults.get() + fieldOffset, EntityFile::GetTypeStride(fieldType)) == 0) { + if (memcmp(c.Data + field.Offset, c.Info.Defaults.get() + field.Offset, field.Stride) == 0) { continue; } DOMElement* fieldElement = doc->createElement(X(fieldName)); componentElement->appendChild(fieldElement); - if (fieldType == "Vector") { + if (field.Type == "Vector") { const glm::vec3& vec = c[fieldName]; fieldElement->setAttribute(X("X"), X(boost::lexical_cast(vec.x))); fieldElement->setAttribute(X("Y"), X(boost::lexical_cast(vec.y))); fieldElement->setAttribute(X("Z"), X(boost::lexical_cast(vec.z))); - } else if (fieldType == "Color") { + } else if (field.Type == "Color") { const glm::vec4& vec = c[fieldName]; fieldElement->setAttribute(X("R"), X(boost::lexical_cast(vec.r))); fieldElement->setAttribute(X("G"), X(boost::lexical_cast(vec.g))); fieldElement->setAttribute(X("B"), X(boost::lexical_cast(vec.b))); fieldElement->setAttribute(X("A"), X(boost::lexical_cast(vec.a))); - } else if (fieldType == "Quaternion") { + } else if (field.Type == "Quaternion") { const glm::quat& q = c[fieldName]; fieldElement->setAttribute(X("X"), X(boost::lexical_cast(q.x))); fieldElement->setAttribute(X("Y"), X(boost::lexical_cast(q.y))); fieldElement->setAttribute(X("Z"), X(boost::lexical_cast(q.z))); fieldElement->setAttribute(X("W"), X(boost::lexical_cast(q.w))); - } else if (fieldType == "int") { + } else if (field.Type == "int") { const int& value = c[fieldName]; fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast(value)))); - } else if (fieldType == "float") { + } else if (field.Type == "float") { const float& value = c[fieldName]; fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast(value)))); - } else if (fieldType == "double") { + } else if (field.Type == "double") { const double& value = c[fieldName]; fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast(value)))); - } else if (fieldType == "bool") { + } else if (field.Type == "bool") { const bool& value = c[fieldName]; if (value) { fieldElement->appendChild(doc->createTextNode(X("true"))); } else { fieldElement->appendChild(doc->createTextNode(X("false"))); } - } else if (fieldType == "string") { + } else if (field.Type == "string") { const std::string& value = c[fieldName]; fieldElement->appendChild(doc->createTextNode(X(value))); } diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index a43ca900..07a9e4e8 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -432,16 +432,16 @@ void EditorSystem::drawUI(World* world, double dt) } auto& component = world->GetComponent(m_Selection, componentType); - for (auto& pair : ci.FieldTypes) { - const std::string& field = pair.first; - const std::string& type = pair.second; + for (auto& kv : ci.Fields) { + const std::string& fieldName = kv.first; + auto& field = kv.second; - ImGui::PushID(field.c_str()); - if (type == "Vector") { - auto& val = component.Property(field); - if (field == "Scale") { + ImGui::PushID(fieldName.c_str()); + if (field.Type == "Vector") { + auto& val = component.Property(fieldName); + if (fieldName == "Scale") { ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits::max()); - } else if (field == "Orientation") { + } else if (fieldName == "Orientation") { glm::vec3 tempVal = glm::fmod(val, glm::vec3(glm::two_pi())); if (ImGui::SliderFloat3("", glm::value_ptr(tempVal), 0.f, glm::two_pi())) { val = tempVal; @@ -449,16 +449,16 @@ void EditorSystem::drawUI(World* world, double dt) } else { ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits::lowest(), std::numeric_limits::max()); } - } else if (type == "Color") { - auto& val = component.Property(field); + } else if (field.Type == "Color") { + auto& val = component.Property(fieldName); ImGui::ColorEdit4("", glm::value_ptr(val), true); - } else if (type == "string") { - std::string& val = component.Property(field); + } else if (field.Type == "string") { + std::string& val = component.Property(fieldName); char tempString[1024]; memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString))); if (ImGui::InputText("", tempString, sizeof(tempString))) { val = std::string(tempString); - LOG_DEBUG("%s::%s changed!", componentType.c_str(), field.c_str()); + LOG_DEBUG("%s::%s changed!", componentType.c_str(), fieldName.c_str()); } // DROP STUFF if (ImGui::IsItemHovered() && !m_LastDroppedFile.empty()) { @@ -466,21 +466,21 @@ void EditorSystem::drawUI(World* world, double dt) m_LastDroppedFile = ""; } - } else if (type == "double") { - float tempVal = static_cast(component.Property(field)); + } else if (field.Type == "double") { + float tempVal = static_cast(component.Property(fieldName)); if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) { - component.SetProperty(field, static_cast(tempVal)); + component.SetProperty(fieldName, static_cast(tempVal)); } - } else if (type == "bool") { - auto& val = component.Property(field); + } else if (field.Type == "bool") { + auto& val = component.Property(fieldName); ImGui::Checkbox("", &val); } else { - ImGui::TextDisabled(type.c_str()); + ImGui::TextDisabled(field.Type.c_str()); } ImGui::PopID(); ImGui::SameLine(); - ImGui::Text(field.c_str()); + ImGui::Text(fieldName.c_str()); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("field annotation goes here"); }