Added enum support to entity file format, see "Team" component for an example. Use ComponentInfo::Enum to convert enum string keys to its corresponding integer representation at runtime.
This commit is contained in:
@@ -21,16 +21,24 @@ void EntityFile::Parse(const EntityFileHandler* handler) const
|
||||
using namespace xercesc;
|
||||
|
||||
EntityFileSAXHandler saxHandler(handler, nullptr);
|
||||
m_SAX2XMLReader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
|
||||
m_SAX2XMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
|
||||
m_SAX2XMLReader->setFeature(XMLUni::fgXercesSchema, true);
|
||||
m_SAX2XMLReader->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
|
||||
setReaderFeatures(m_SAX2XMLReader);
|
||||
m_SAX2XMLReader->setContentHandler(&saxHandler);
|
||||
m_SAX2XMLReader->setErrorHandler(&saxHandler);
|
||||
m_SAX2XMLReader->setDeclarationHandler(&saxHandler);
|
||||
m_SAX2XMLReader->parse(m_FilePath.string().c_str());
|
||||
}
|
||||
|
||||
void EntityFile::setReaderFeatures(xercesc::SAX2XMLReader* reader)
|
||||
{
|
||||
using namespace xercesc;
|
||||
reader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
|
||||
reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
|
||||
reader->setFeature(XMLUni::fgSAX2CoreValidation, true);
|
||||
reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
|
||||
reader->setFeature(XMLUni::fgXercesSchema, true);
|
||||
reader->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
|
||||
}
|
||||
|
||||
std::size_t EntityFile::GetTypeStride(std::string typeName)
|
||||
{
|
||||
std::map<std::string, size_t> typeStrides{
|
||||
@@ -39,6 +47,7 @@ std::size_t EntityFile::GetTypeStride(std::string typeName)
|
||||
{ "float", sizeof(float) },
|
||||
{ "double", sizeof(double) },
|
||||
{ "string", sizeof(std::string) },
|
||||
{ "enum", sizeof(int) },
|
||||
{ "Vector", sizeof(glm::vec3) },
|
||||
{ "Quaternion", sizeof(glm::quat) },
|
||||
{ "Color", sizeof(glm::vec4) }
|
||||
@@ -77,7 +86,7 @@ void EntityFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t&
|
||||
|
||||
void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData)
|
||||
{
|
||||
if (field.Type == "int") {
|
||||
if (field.Type == "int" || field.Type == "enum") {
|
||||
int value = boost::lexical_cast<int>(valueData);
|
||||
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
|
||||
} else if (field.Type == "float") {
|
||||
@@ -95,3 +104,171 @@ void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& fie
|
||||
LOG_WARNING("Unknown value data type: %s", field.Type.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
EntityFileSAXHandler::EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) : m_Handler(handler)
|
||||
, m_Reader(reader)
|
||||
{
|
||||
// 0 is imaginary base parent
|
||||
m_EntityStack.push(0);
|
||||
m_StateStack.push(State::Unknown);
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs)
|
||||
{
|
||||
std::string name = XS::ToString(_localName);
|
||||
|
||||
if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) {
|
||||
if (name == "Entity") {
|
||||
m_StateStack.push(State::Entity);
|
||||
onStartEntity(attrs);
|
||||
return;
|
||||
}
|
||||
if (name == "EntityRef") {
|
||||
onStartEntityRef(attrs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string uri = XS::ToString(_uri);
|
||||
if (m_StateStack.top() == State::Entity) {
|
||||
if (uri == "components") {
|
||||
m_StateStack.push(State::Component);
|
||||
onStartComponent(name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_StateStack.top() == State::Component) {
|
||||
m_StateStack.push(State::ComponentField);
|
||||
onStartComponentField(name, attrs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname)
|
||||
{
|
||||
std::string name = XS::ToString(_localName);
|
||||
if (m_StateStack.top() == State::Entity) {
|
||||
if (name == "Entity") {
|
||||
m_StateStack.pop();
|
||||
onEndEntity();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string uri = XS::ToString(_uri);
|
||||
if (m_StateStack.top() == State::Component) {
|
||||
//if (uri == "components") {
|
||||
m_StateStack.pop();
|
||||
onEndComponent(name);
|
||||
return;
|
||||
//}
|
||||
}
|
||||
|
||||
if (m_StateStack.top() == State::ComponentField) {
|
||||
m_StateStack.pop();
|
||||
onEndComponentField(name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::characters(const XMLCh* const chars, const XMLSize_t length)
|
||||
{
|
||||
if (m_StateStack.top() == State::ComponentField) {
|
||||
char* transcoded = xercesc::XMLString::transcode(chars);
|
||||
onFieldData(transcoded);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::fatalError(const xercesc::SAXParseException& e)
|
||||
{
|
||||
XS::ToString s(e.getMessage());
|
||||
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
|
||||
//throw e;
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::error(const xercesc::SAXParseException& e)
|
||||
{
|
||||
XS::ToString s(e.getMessage());
|
||||
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::warning(const xercesc::SAXParseException& e)
|
||||
{
|
||||
XS::ToString s(e.getMessage());
|
||||
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onStartEntity(const xercesc::Attributes& attrs)
|
||||
{
|
||||
EntityID parent = m_EntityStack.top();
|
||||
|
||||
if (m_Handler->m_OnStartEntityCallback) {
|
||||
std::string name;
|
||||
auto xName = attrs.getValue(XS::ToXMLCh("name"));
|
||||
if (xName != nullptr) {
|
||||
name = XS::ToString(xName);
|
||||
}
|
||||
m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name);
|
||||
}
|
||||
|
||||
m_EntityStack.push(m_NextEntityID);
|
||||
m_NextEntityID++;
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onEndEntity()
|
||||
{
|
||||
m_EntityStack.pop();
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onStartEntityRef(const xercesc::Attributes& attrs)
|
||||
{
|
||||
std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file")));
|
||||
|
||||
xercesc::SAX2XMLReader* reader = xercesc::XMLReaderFactory::createXMLReader();
|
||||
EntityFile::setReaderFeatures(reader);
|
||||
reader->setContentHandler(this);
|
||||
reader->setErrorHandler(this);
|
||||
reader->parse(path.c_str());
|
||||
delete reader;
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onStartComponentField(const std::string& field, const xercesc::Attributes& attrs)
|
||||
{
|
||||
//LOG_DEBUG(" Field: %s", field.c_str());
|
||||
m_CurrentField = field;
|
||||
m_CurrentAttributes.clear();
|
||||
for (int i = 0; i < attrs.getLength(); i++) {
|
||||
auto name = attrs.getQName(i);
|
||||
auto value = attrs.getValue(name);
|
||||
//LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value));
|
||||
m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string();
|
||||
}
|
||||
|
||||
if (m_Handler->m_OnStartFieldCallback) {
|
||||
m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onEndComponent(const std::string& name) { }
|
||||
|
||||
void EntityFileSAXHandler::onStartComponent(const std::string& name)
|
||||
{
|
||||
//LOG_DEBUG(" Component: %s", name.c_str());
|
||||
m_CurrentComponent = name;
|
||||
if (m_Handler->m_OnStartComponentCallback) {
|
||||
m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onEndComponentField(const std::string& field) { }
|
||||
|
||||
void EntityFileSAXHandler::onFieldData(char* data)
|
||||
{
|
||||
//LOG_DEBUG(" Data: %s", data);
|
||||
if (m_Handler->m_OnStartFieldDataCallback) {
|
||||
m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data);
|
||||
}
|
||||
|
||||
xercesc::XMLString::release(&data);
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile)
|
||||
|
||||
for (auto& kv : m_ComponentInfo) {
|
||||
auto& info = kv.second;
|
||||
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);
|
||||
LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta->Annotation.c_str());
|
||||
LOG_DEBUG("Stride: %i", info.Stride);
|
||||
LOG_DEBUG("Allocation: %i", info.Meta->Allocation);
|
||||
for (auto& kv : info.Fields) {
|
||||
auto& field = kv.second;
|
||||
LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type, kv.first.c_str());
|
||||
LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type.c_str(), kv.first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,46 +62,16 @@ void EntityFilePreprocessor::parseComponentInfo()
|
||||
}
|
||||
|
||||
ComponentInfo compInfo;
|
||||
compInfo.Meta = std::make_shared<ComponentInfo::Meta_t>();
|
||||
|
||||
// Name
|
||||
compInfo.Name = XS::ToString(element->getName());
|
||||
// Known allocation
|
||||
compInfo.Meta.Allocation = m_ComponentCounts[compInfo.Name];
|
||||
compInfo.Meta->Allocation = m_ComponentCounts[compInfo.Name];
|
||||
// Annotation
|
||||
auto componentAnnotation = element->getAnnotation();
|
||||
if (componentAnnotation != nullptr) {
|
||||
// Parse annotation XML
|
||||
char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString());
|
||||
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(annotationString), strlen(annotationString), "MemBuf: Annotation String");
|
||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, grammarPool);
|
||||
parser.setErrorHandler(&errorHandler);
|
||||
parser.parse(annotationInput);
|
||||
XMLString::release(&annotationString);
|
||||
auto doc = parser.getDocument();
|
||||
|
||||
// TODO: Add allocation estimations from external file on map-to-map basis
|
||||
// Add allocation estimation(s)
|
||||
//auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation"));
|
||||
//for (int i = 0; i < allocationTags->getLength(); ++i) {
|
||||
// auto allocation = dynamic_cast<DOMElement*>(allocationTags->item(i));
|
||||
// auto child = allocation->getFirstChild();
|
||||
// if (child == nullptr) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// XSValue::Status status;
|
||||
// XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status);
|
||||
// compInfo.Meta.Allocation += val->fData.fValue.f_int;
|
||||
//}
|
||||
|
||||
// Save documentation string
|
||||
auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation"));
|
||||
if (documentationTags->getLength() != 0) {
|
||||
auto child = documentationTags->item(0)->getFirstChild();
|
||||
if (child != nullptr) {
|
||||
compInfo.Meta.Annotation = XS::ToString(child->getNodeValue());
|
||||
}
|
||||
}
|
||||
compInfo.Meta->Annotation = parseAnnotationXML(componentAnnotation->getAnnotationString());
|
||||
} else {
|
||||
LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str());
|
||||
}
|
||||
@@ -140,24 +110,58 @@ void EntityFilePreprocessor::parseComponentInfo()
|
||||
|
||||
std::string name = XS::ToString(elementDeclaration->getName());
|
||||
std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->getName());
|
||||
std::string typeNamespace = XS::ToString(elementDeclaration->getTypeDefinition()->getNamespace());
|
||||
std::string baseType = XS::ToString(elementDeclaration->getTypeDefinition()->getBaseType()->getName());
|
||||
|
||||
std::string effectiveType = type;
|
||||
size_t stride = EntityFile::GetTypeStride(type);
|
||||
if (stride == 0) {
|
||||
LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str());
|
||||
continue;
|
||||
stride = EntityFile::GetTypeStride(baseType);
|
||||
if (stride == 0) {
|
||||
LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\" with base type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str(), baseType.c_str());
|
||||
continue;
|
||||
}
|
||||
effectiveType = baseType;
|
||||
}
|
||||
|
||||
// Annotation
|
||||
auto fieldAnnotation = elementDeclaration->getAnnotation();
|
||||
if (fieldAnnotation != nullptr) {
|
||||
compInfo.Meta->FieldAnnotations[name] = parseAnnotationXML(fieldAnnotation->getAnnotationString());
|
||||
} else {
|
||||
LOG_WARNING("Component field \"%s.%s\" is missing an annotation!", compInfo.Name.c_str(), name.c_str());
|
||||
}
|
||||
|
||||
if (effectiveType == "enum") {
|
||||
// Parse potential enum type definition for field type
|
||||
if (compInfo.Meta->FieldEnumDefinitions.count(name) == 0) {
|
||||
auto enumTypeDefinition = xsModel->getTypeDefinition(XS::ToXMLCh(type), XS::ToXMLCh("components"));
|
||||
auto xsComplexType = dynamic_cast<XSComplexTypeDefinition*>(enumTypeDefinition);
|
||||
auto xsComplexContent = xsComplexType->getParticle();
|
||||
auto xsExtension = xsComplexContent->getModelGroupTerm();
|
||||
auto xsExtensionParticles = xsExtension->getParticles();
|
||||
auto xsChoice = xsExtensionParticles->elementAt(0)->getModelGroupTerm();
|
||||
auto xsChoiceParticles = xsChoice->getParticles();
|
||||
for (int i = 0; i < xsChoiceParticles->size(); ++i) {
|
||||
auto enumElement = xsChoiceParticles->elementAt(i)->getElementTerm();
|
||||
std::string enumName = XS::ToString(enumElement->getName());
|
||||
std::string enumValue = XS::ToString(enumElement->getConstraintValue());
|
||||
compInfo.Meta->FieldEnumDefinitions[name][enumName] = boost::lexical_cast<int>(enumValue);
|
||||
LOG_DEBUG("ENUM %s = %s", enumName.c_str(), enumValue.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto& field = compInfo.Fields[name];
|
||||
field.Name = name;
|
||||
field.Type = type;
|
||||
field.Type = effectiveType;
|
||||
field.Offset = fieldOffset;
|
||||
field.Stride = stride;
|
||||
compInfo.FieldsInOrder.push_back(name);
|
||||
|
||||
fieldOffset += stride;
|
||||
}
|
||||
|
||||
compInfo.Meta.Stride = fieldOffset;
|
||||
compInfo.Stride = fieldOffset;
|
||||
m_ComponentInfo[compInfo.Name] = compInfo;
|
||||
}
|
||||
}
|
||||
@@ -170,8 +174,10 @@ void EntityFilePreprocessor::parseDefaults()
|
||||
|
||||
for (auto& ci : m_ComponentInfo) {
|
||||
// Allocate memory for default values
|
||||
ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Meta.Stride]);
|
||||
memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride);
|
||||
ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Stride]);
|
||||
memset(ci.second.Defaults.get(), 0, ci.second.Stride);
|
||||
|
||||
std::string componentName = ci.first;
|
||||
|
||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
|
||||
parser.setDoSchema(true);
|
||||
@@ -179,8 +185,11 @@ void EntityFilePreprocessor::parseDefaults()
|
||||
parser.setErrorHandler(&errorHandler);
|
||||
parser.setValidationScheme(XercesDOMParser::Val_Always);
|
||||
parser.setValidationSchemaFullChecking(true);
|
||||
//parser.setDoNamespaces(true);
|
||||
//boost::filesystem::path schemaLocation = "Schema/Components/" + componentName + ".xsd";
|
||||
//std::string namespaceSchema = schemaLocation.string();
|
||||
//parser.setExternalNoNamespaceSchemaLocation("Teamasdasdasdasd.xsd");
|
||||
|
||||
std::string componentName = ci.first;
|
||||
LOG_DEBUG("Parsing defaults for component %s", componentName.c_str());
|
||||
boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml";
|
||||
|
||||
@@ -192,7 +201,7 @@ void EntityFilePreprocessor::parseDefaults()
|
||||
}
|
||||
|
||||
// Find the node in the components namespace matching the component name
|
||||
std::string tagName = "c:" + componentName;
|
||||
std::string tagName = componentName;
|
||||
auto rootNodes = doc->getElementsByTagName(XS::ToXMLCh(tagName));
|
||||
if (rootNodes->getLength() == 0) {
|
||||
LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str());
|
||||
@@ -225,9 +234,19 @@ void EntityFilePreprocessor::parseDefaults()
|
||||
EntityFile::WriteAttributeData(data, field, attributes);
|
||||
}
|
||||
|
||||
// Handle potential field values
|
||||
auto childNode = fieldElement->getFirstChild();
|
||||
if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) {
|
||||
if (childNode == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// An enum will either have an element node with a text node inside,
|
||||
// or contain a text node directly.
|
||||
if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) {
|
||||
childNode = childNode->getFirstChild();
|
||||
}
|
||||
|
||||
// Handle potential field values
|
||||
if (childNode->getNodeType() == DOMNode::TEXT_NODE) {
|
||||
char* cstrValue = XMLString::transcode(childNode->getNodeValue());
|
||||
EntityFile::WriteValueData(data, field, cstrValue);
|
||||
XMLString::release(&cstrValue);
|
||||
@@ -236,3 +255,27 @@ void EntityFilePreprocessor::parseDefaults()
|
||||
}
|
||||
}
|
||||
|
||||
std::string EntityFilePreprocessor::parseAnnotationXML(const XMLCh* xml)
|
||||
{
|
||||
using namespace xercesc;
|
||||
|
||||
// Parse annotation XML
|
||||
char* annotationString = XMLString::transcode(xml);
|
||||
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(annotationString), strlen(annotationString), "MemBuf: Annotation String");
|
||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
|
||||
//parser.setErrorHandler(&errorHandler);
|
||||
parser.parse(annotationInput);
|
||||
XMLString::release(&annotationString);
|
||||
auto doc = parser.getDocument();
|
||||
|
||||
// Save documentation string
|
||||
auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation"));
|
||||
if (documentationTags->getLength() != 0) {
|
||||
auto child = documentationTags->item(0)->getFirstChild();
|
||||
if (child != nullptr) {
|
||||
return XS::ToString(child->getNodeValue());
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement
|
||||
fieldElement->setAttribute(X("Y"), X(boost::lexical_cast<std::string>(q.y)));
|
||||
fieldElement->setAttribute(X("Z"), X(boost::lexical_cast<std::string>(q.z)));
|
||||
fieldElement->setAttribute(X("W"), X(boost::lexical_cast<std::string>(q.w)));
|
||||
} else if (field.Type == "int") {
|
||||
} else if (field.Type == "int" || field.Type == "enum") {
|
||||
const int& value = c[fieldName];
|
||||
fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value))));
|
||||
} else if (field.Type == "float") {
|
||||
|
||||
@@ -75,7 +75,7 @@ ComponentWrapper World::AttachComponent(EntityID entity, const std::string& comp
|
||||
// Allocate space for the component
|
||||
ComponentWrapper c = pool->Allocate(entity);
|
||||
// Write default values
|
||||
memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride);
|
||||
memcpy(c.Data, ci.Defaults.get(), ci.Stride);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -484,8 +484,8 @@ void EditorSystem::drawUI(World* world, double dt)
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader(componentType.c_str())) {
|
||||
if (!ci.Meta.Annotation.empty()) {
|
||||
ImGui::Text(ci.Meta.Annotation.c_str());
|
||||
if (!ci.Meta->Annotation.empty()) {
|
||||
ImGui::Text(ci.Meta->Annotation.c_str());
|
||||
}
|
||||
|
||||
auto& component = world->GetComponent(m_Selection, componentType);
|
||||
@@ -529,6 +529,26 @@ void EditorSystem::drawUI(World* world, double dt)
|
||||
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
|
||||
component.SetProperty(fieldName, static_cast<double>(tempVal));
|
||||
}
|
||||
} else if (field.Type == "int") {
|
||||
int val = component.Property<int>(fieldName);
|
||||
ImGui::InputInt("", &val);
|
||||
} else if (field.Type == "enum") {
|
||||
int currentValue = component.Property<int>(fieldName);
|
||||
int item = -1;
|
||||
std::stringstream enumKeys;
|
||||
std::vector<int> enumValues;
|
||||
int i = 0;
|
||||
for (auto& kv : ci.Meta->FieldEnumDefinitions.at(fieldName)) {
|
||||
enumKeys << kv.first << " (" << kv.second << ")" << '\0';
|
||||
enumValues.push_back(kv.second);
|
||||
if (currentValue == kv.second) {
|
||||
item = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (ImGui::Combo("", &item, enumKeys.str().c_str())) {
|
||||
component.SetProperty(fieldName, enumValues.at(item));
|
||||
}
|
||||
} else if (field.Type == "bool") {
|
||||
auto& val = component.Property<bool>(fieldName);
|
||||
ImGui::Checkbox("", &val);
|
||||
|
||||
Reference in New Issue
Block a user