// Copyright (c) 2023 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "PrefabGen.hpp" using namespace Dawn; void PrefabGen::generate( std::vector *out, struct Prefab *info, std::string tabs ) { struct ClassGenInfo classInfo; classInfo.clazz = info->name; classInfo.extend = "SceneItemPrefab<" + info->name + ">"; classInfo.constructorArgs = "Scene *scene, sceneitemid_t id"; classInfo.extendArgs = "scene, id"; struct MethodGenInfo methodAssets; methodAssets.name = "prefabAssets"; methodAssets.isStatic = true; methodAssets.type = "std::vector"; methodAssets.args = "AssetManager *man"; line(&methodAssets.body, "std::vector assets;", ""); struct MethodGenInfo methodInit; methodInit.name = "prefabInit"; methodInit.isOverride = true; methodInit.args = "AssetManager *man"; classInfo.includes.push_back("prefab/SceneItemPrefab.hpp"); // Process assets int32_t assetNumber = 0; std::map assetMap; auto processAsset = [&](struct PrefabAsset a) { std::string assetType = ""; a.usageName = "asset" + std::to_string(assetNumber++); switch(a.type) { case PREFAB_ASSET_TYPE_TEXTURE: assetType = "TextureAsset"; assetMap[a.fileName] = "&" + a.usageName + "->texture"; break; case PREFAB_ASSET_TYPE_TRUETYPE_FONT: assetType = "TrueTypeAsset"; assetMap[a.fileName] = "&" + a.usageName + "->font"; break; default: assertUnreachable(); } line(&methodInit.body, "auto " + a.usageName + " = man->get<" + assetType + ">(\"" + a.fileName + "\");", ""); line(&methodAssets.body, "assets.push_back(man->get<" + assetType + ">(\"" + a.fileName + "\"));", ""); }; // Load self assets auto itAssets = info->root.assets.begin(); while(itAssets != info->root.assets.end()) { processAsset(*itAssets); ++itAssets; } // TODO: Load child assets? line(&methodInit.body, "", ""); // Process root and all of its children int32_t childNumber = 0; int32_t componentNumber = 0; auto processComponent = [&](struct PrefabComponent c, std::string item) { auto componentName = "cmp" + std::to_string(componentNumber++); bool_t componentInit = true; if(c.ref.size() > 0) { componentInit = false; componentName = c.ref; line(&classInfo.publicProperties, c.type + " *" + c.ref + " = nullptr;", ""); } // Initialize line(&methodInit.body, (componentInit ? "auto " : "") + componentName + " = " + item + "->addComponent<" + c.type + ">();", ""); // Now set each property auto itValues = c.values.begin(); while(itValues != c.values.end()) { auto value = itValues->second; if(assetMap.find(value) != assetMap.end()) { value = assetMap[value]; } line(&methodInit.body, componentName + "->" + itValues->first + " = " + value + ";", ""); ++itValues; } classInfo.includes.push_back(c.include); }; std::function processChild; processChild = [&](struct PrefabChild &child, std::string parent) { auto name = "itm" + std::to_string(childNumber++); bool_t init = true; if(child.ref.size() > 0) { init = false; name = child.ref; line(&classInfo.publicProperties, "SceneItemComponent *" + name + " = nullptr;", ""); } line(&methodInit.body, (init ? "auto " : "") + name + " = scene->createSceneItem();", ""); // Process extra properties if(child.position.size() > 0) { line(&methodInit.body, name + "->transform.setLocalPosition(" + child.position + ");", ""); } if(child.scale.size() > 0) { line(&methodInit.body, name + "->transform.setLocalScale(" + child.scale + ");", ""); } // Add components for children auto itComponents = child.components.begin(); while(itComponents != child.components.end()) { auto c = *itComponents; processComponent(c, name); ++itComponents; } // Process sub children auto itChildren = child.children.begin(); while(itChildren != child.children.end()) { processChild(*itChildren, name); ++itChildren; } // Set parent line(&methodInit.body, name + "->transform.setParent(&"+parent+"->transform);", ""); }; // Process each child auto itChildren = info->root.children.begin(); while(itChildren != info->root.children.end()) { processChild(*itChildren, "this"); line(&methodInit.body, "", ""); ++itChildren; } // Process self components auto itComponents = info->root.components.begin(); while(itComponents != info->root.components.end()) { auto c = *itComponents; processComponent(c, "this"); ++itComponents; } // Seal methods line(&methodAssets.body, "return assets;", ""); // Add in methods CodeGen::methodGen(&classInfo.publicCode, methodAssets); line(&classInfo.publicCode, "", ""); CodeGen::methodGen(&classInfo.publicCode, methodInit); CodeGen::classGen(out, classInfo); }