| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- // Urho3D editor import functions
- String importOptions = "-t";
- class ParentAssignment
- {
- uint childID;
- String parentName;
- }
- class AssetMapping
- {
- String assetName;
- String fullAssetName;
- }
- Array<AssetMapping> assetMappings;
- void ImportModel(const String&in fileName)
- {
- if (fileName.empty)
- return;
- ui.cursor.shape = CS_BUSY;
- String modelName = "Models/" + GetFileName(fileName) + ".mdl";
- String outFileName = sceneResourcePath + modelName;
- fileSystem.CreateDir(sceneResourcePath + "Models");
- Array<String> args;
- args.Push("model");
- args.Push("\"" + fileName + "\"");
- args.Push("\"" + outFileName + "\"");
- args.Push("-p \"" + sceneResourcePath + "\"");
- Array<String> options = importOptions.Trimmed().Split(' ');
- for (uint i = 0; i < options.length; ++i)
- args.Push(options[i]);
- // If material lists are to be applied, make sure the option to create them exists
- if (applyMaterialList)
- args.Push("-l");
- if (fileSystem.SystemRun(fileSystem.programDir + "AssetImporter", args) == 0)
- {
- Node@ newNode = editorScene.CreateChild(GetFileName(fileName));
- StaticModel@ newModel = newNode.CreateComponent("StaticModel");
- newNode.position = GetNewNodePosition();
- newModel.model = cache.GetResource("Model", modelName);
- newModel.ApplyMaterialList(); // Setup default materials if possible
- // Create an undo action for the create
- CreateNodeAction action;
- action.Define(newNode);
- SaveEditAction(action);
- SetSceneModified();
- FocusNode(newNode);
- }
- }
- void ImportScene(const String&in fileName)
- {
- if (fileName.empty)
- return;
- ui.cursor.shape = CS_BUSY;
- // Handle Tundra scene files here in code, otherwise via AssetImporter
- if (GetExtension(fileName) == ".txml")
- ImportTundraScene(fileName);
- else
- {
- // Export scene to a temp file, then load and delete it if successful
- String tempSceneName = sceneResourcePath + TEMP_SCENE_NAME;
- Array<String> args;
- args.Push("scene");
- args.Push("\"" + fileName + "\"");
- args.Push("\"" + tempSceneName + "\"");
- args.Push("-p \"" + sceneResourcePath + "\"");
- Array<String> options = importOptions.Trimmed().Split(' ');
- for (uint i = 0; i < options.length; ++i)
- args.Push(options[i]);
- if (applyMaterialList)
- args.Push("-l");
- if (fileSystem.SystemRun(fileSystem.programDir + "AssetImporter", args) == 0)
- {
- skipMruScene = true; // set to avoid adding tempscene to mru
- LoadScene(tempSceneName);
- fileSystem.Delete(tempSceneName);
- UpdateWindowTitle();
- }
- }
- }
- void ImportTundraScene(const String&in fileName)
- {
- fileSystem.CreateDir(sceneResourcePath + "Materials");
- fileSystem.CreateDir(sceneResourcePath + "Models");
- fileSystem.CreateDir(sceneResourcePath + "Textures");
- XMLFile source;
- source.Load(File(fileName, FILE_READ));
- String filePath = GetPath(fileName);
- XMLElement sceneElem = source.root;
- XMLElement entityElem = sceneElem.GetChild("entity");
- Array<String> convertedMaterials;
- Array<String> convertedMeshes;
- Array<ParentAssignment> parentAssignments;
- // Read the scene directory structure recursively to get assetname to full assetname mappings
- Array<String> fileNames = fileSystem.ScanDir(filePath, "*.*", SCAN_FILES, true);
- for (uint i = 0; i < fileNames.length; ++i)
- {
- AssetMapping mapping;
- mapping.assetName = GetFileNameAndExtension(fileNames[i]);
- mapping.fullAssetName = fileNames[i];
- assetMappings.Push(mapping);
- }
- // Clear old scene, then create a zone and a directional light first
- ResetScene();
- // Set standard gravity
- editorScene.CreateComponent("PhysicsWorld");
- editorScene.physicsWorld.gravity = Vector3(0, -9.81, 0);
- // Create zone & global light
- Node@ zoneNode = editorScene.CreateChild("Zone");
- Zone@ zone = zoneNode.CreateComponent("Zone");
- zone.boundingBox = BoundingBox(-1000, 1000);
- zone.ambientColor = Color(0.364, 0.364, 0.364);
- zone.fogColor = Color(0.707792, 0.770537, 0.831373);
- zone.fogStart = 100.0;
- zone.fogEnd = 500.0;
- Node@ lightNode = editorScene.CreateChild("GlobalLight");
- Light@ light = lightNode.CreateComponent("Light");
- lightNode.rotation = Quaternion(60, 30, 0);
- light.lightType = LIGHT_DIRECTIONAL;
- light.color = Color(0.639, 0.639, 0.639);
- light.castShadows = true;
- light.shadowCascade = CascadeParameters(5, 15.0, 50.0, 0.0, 0.9);
- // Loop through scene entities
- while (!entityElem.isNull)
- {
- String nodeName;
- String meshName;
- String parentName;
- Vector3 meshPos;
- Vector3 meshRot;
- Vector3 meshScale(1, 1, 1);
- Vector3 pos;
- Vector3 rot;
- Vector3 scale(1, 1, 1);
- bool castShadows = false;
- float drawDistance = 0;
- Array<String> materialNames;
- int shapeType = -1;
- float mass = 0.0f;
- Vector3 bodySize;
- bool trigger = false;
- bool kinematic = false;
- uint collisionLayer;
- uint collisionMask;
- String collisionMeshName;
- XMLElement compElem = entityElem.GetChild("component");
- while (!compElem.isNull)
- {
- String compType = compElem.GetAttribute("type");
- if (compType == "EC_Mesh" || compType == "Mesh")
- {
- Array<String> coords = GetComponentAttribute(compElem, "Transform").Split(',');
- meshPos = GetVector3FromStrings(coords, 0);
- meshPos.z = -meshPos.z; // Convert to lefthanded
- meshRot = GetVector3FromStrings(coords, 3);
- meshScale = GetVector3FromStrings(coords, 6);
- meshName = GetComponentAttribute(compElem, "Mesh ref");
- castShadows = GetComponentAttribute(compElem, "Cast shadows").ToBool();
- drawDistance = GetComponentAttribute(compElem, "Draw distance").ToFloat();
- materialNames = GetComponentAttribute(compElem, "Mesh materials").Split(';');
- ProcessRef(meshName);
- for (uint i = 0; i < materialNames.length; ++i)
- ProcessRef(materialNames[i]);
- }
- if (compType == "EC_Name" || compType == "Name")
- nodeName = GetComponentAttribute(compElem, "name");
- if (compType == "EC_Placeable" || compType == "Placeable")
- {
- Array<String> coords = GetComponentAttribute(compElem, "Transform").Split(',');
- pos = GetVector3FromStrings(coords, 0);
- pos.z = -pos.z; // Convert to lefthanded
- rot = GetVector3FromStrings(coords, 3);
- scale = GetVector3FromStrings(coords, 6);
- parentName = GetComponentAttribute(compElem, "Parent entity ref");
- }
- if (compType == "EC_RigidBody" || compType == "RigidBody")
- {
- shapeType = GetComponentAttribute(compElem, "Shape type").ToInt();
- mass = GetComponentAttribute(compElem, "Mass").ToFloat();
- bodySize = GetComponentAttribute(compElem, "Size").ToVector3();
- collisionMeshName = GetComponentAttribute(compElem, "Collision mesh ref");
- trigger = GetComponentAttribute(compElem, "Phantom").ToBool();
- kinematic = GetComponentAttribute(compElem, "Kinematic").ToBool();
- collisionLayer = GetComponentAttribute(compElem, "Collision Layer").ToInt();
- collisionMask = GetComponentAttribute(compElem, "Collision Mask").ToInt();
- ProcessRef(collisionMeshName);
- }
- compElem = compElem.GetNext("component");
- }
- // If collision mesh not specified for the rigid body, assume same as the visible mesh
- if ((shapeType == 4 || shapeType == 6) && collisionMeshName.Trimmed().empty)
- collisionMeshName = meshName;
- if (!meshName.empty || shapeType >= 0)
- {
- for (uint i = 0; i < materialNames.length; ++i)
- ConvertMaterial(materialNames[i], filePath, convertedMaterials);
- ConvertModel(meshName, filePath, convertedMeshes);
- ConvertModel(collisionMeshName, filePath, convertedMeshes);
- Node@ newNode = editorScene.CreateChild(nodeName);
- // Calculate final transform in an Ogre-like fashion
- Quaternion quat = GetTransformQuaternion(rot);
- Quaternion meshQuat = GetTransformQuaternion(meshRot);
- Quaternion finalQuat = quat * meshQuat;
- Vector3 finalScale = scale * meshScale;
- Vector3 finalPos = pos + quat * (scale * meshPos);
- newNode.SetTransform(finalPos, finalQuat, finalScale);
- // Create model
- if (!meshName.empty)
- {
- StaticModel@ model = newNode.CreateComponent("StaticModel");
- model.model = cache.GetResource("Model", GetOutModelName(meshName));
- model.drawDistance = drawDistance;
- model.castShadows = castShadows;
- // Set default grey material to match Tundra defaults
- model.material = cache.GetResource("Material", "Materials/DefaultGrey.xml");
- // Then try to assign the actual materials
- for (uint i = 0; i < materialNames.length; ++i)
- {
- Material@ mat = cache.GetResource("Material", GetOutMaterialName(materialNames[i]));
- if (mat !is null)
- model.materials[i] = mat;
- }
- }
- // Create rigidbody & collision shape
- if (shapeType >= 0)
- {
- RigidBody@ body = newNode.CreateComponent("RigidBody");
- // If mesh has scaling, undo it for the collision shape
- bodySize.x /= meshScale.x;
- bodySize.y /= meshScale.y;
- bodySize.z /= meshScale.z;
- CollisionShape@ shape = newNode.CreateComponent("CollisionShape");
- switch (shapeType)
- {
- case 0:
- shape.SetBox(bodySize);
- break;
- case 1:
- shape.SetSphere(bodySize.x);
- break;
- case 2:
- shape.SetCylinder(bodySize.x, bodySize.y);
- break;
- case 3:
- shape.SetCapsule(bodySize.x, bodySize.y);
- break;
- case 4:
- shape.SetTriangleMesh(cache.GetResource("Model", GetOutModelName(collisionMeshName)), 0, bodySize);
- break;
- case 6:
- shape.SetConvexHull(cache.GetResource("Model", GetOutModelName(collisionMeshName)), 0, bodySize);
- break;
- }
- body.collisionLayer = collisionLayer;
- body.collisionMask = collisionMask;
- body.trigger = trigger;
- body.mass = mass;
- }
- // Store pending parent assignment if necessary
- if (!parentName.empty)
- {
- ParentAssignment assignment;
- assignment.childID = newNode.id;
- assignment.parentName = parentName;
- parentAssignments.Push(assignment);
- }
- }
- entityElem = entityElem.GetNext("entity");
- }
- // Process any parent assignments now
- for (uint i = 0; i < parentAssignments.length; ++i)
- {
- Node@ childNode = editorScene.GetNode(parentAssignments[i].childID);
- Node@ parentNode = editorScene.GetChild(parentAssignments[i].parentName, true);
- if (childNode !is null && parentNode !is null)
- childNode.parent = parentNode;
- }
- UpdateHierarchyItem(editorScene, true);
- UpdateWindowTitle();
- assetMappings.Clear();
- }
- String GetFullAssetName(const String& assetName)
- {
- for (uint i = 0; i < assetMappings.length; ++i)
- {
- if (assetMappings[i].assetName == assetName)
- return assetMappings[i].fullAssetName;
- }
- return assetName;
- }
- Quaternion GetTransformQuaternion(Vector3 rotEuler)
- {
- // Convert rotation to lefthanded
- Quaternion rotateX(-rotEuler.x, Vector3(1, 0, 0));
- Quaternion rotateY(-rotEuler.y, Vector3(0, 1, 0));
- Quaternion rotateZ(-rotEuler.z, Vector3(0, 0, -1));
- return rotateZ * rotateY * rotateX;
- }
- String GetComponentAttribute(XMLElement compElem, const String&in name)
- {
- XMLElement attrElem = compElem.GetChild("attribute");
- while (!attrElem.isNull)
- {
- if (attrElem.GetAttribute("name") == name)
- return attrElem.GetAttribute("value");
- attrElem = attrElem.GetNext("attribute");
- }
- return "";
- }
- Vector3 GetVector3FromStrings(Array<String>@ coords, uint startIndex)
- {
- return Vector3(coords[startIndex].ToFloat(), coords[startIndex + 1].ToFloat(), coords[startIndex + 2].ToFloat());
- }
- void ProcessRef(String& ref)
- {
- if (ref.StartsWith("local://"))
- ref = ref.Substring(8);
- if (ref.StartsWith("file://"))
- ref = ref.Substring(7);
- }
- String GetOutModelName(const String&in ref)
- {
- return "Models/" + GetFullAssetName(ref).Replaced('/', '_').Replaced(".mesh", ".mdl");
- }
- String GetOutMaterialName(const String&in ref)
- {
- return "Materials/" + GetFullAssetName(ref).Replaced('/', '_').Replaced(".material", ".xml");
- }
- String GetOutTextureName(const String&in ref)
- {
- return "Textures/" + GetFullAssetName(ref).Replaced('/', '_');
- }
- void ConvertModel(const String&in modelName, const String&in filePath, Array<String>@ convertedModels)
- {
- if (modelName.Trimmed().empty)
- return;
- for (uint i = 0; i < convertedModels.length; ++i)
- {
- if (convertedModels[i] == modelName)
- return;
- }
- String meshFileName = filePath + GetFullAssetName(modelName);
- String xmlFileName = filePath + GetFullAssetName(modelName) + ".xml";
- String outFileName = sceneResourcePath + GetOutModelName(modelName);
- // Convert .mesh to .mesh.xml
- String cmdLine = "ogrexmlconverter \"" + meshFileName + "\" \"" + xmlFileName + "\"";
- if (!fileSystem.FileExists(xmlFileName))
- fileSystem.SystemCommand(cmdLine.Replaced('/', '\\'));
- if (!fileSystem.FileExists(outFileName))
- {
- // Convert .mesh.xml to .mdl
- Array<String> args;
- args.Push("\"" + xmlFileName + "\"");
- args.Push("\"" + outFileName + "\"");
- args.Push("-a");
- fileSystem.SystemRun(fileSystem.programDir + "OgreImporter", args);
- }
- convertedModels.Push(modelName);
- }
- void ConvertMaterial(const String&in materialName, const String&in filePath, Array<String>@ convertedMaterials)
- {
- if (materialName.Trimmed().empty)
- return;
- for (uint i = 0; i < convertedMaterials.length; ++i)
- {
- if (convertedMaterials[i] == materialName)
- return;
- }
- String fileName = filePath + GetFullAssetName(materialName);
- String outFileName = sceneResourcePath + GetOutMaterialName(materialName);
- if (!fileSystem.FileExists(fileName))
- return;
- bool mask = false;
- bool twoSided = false;
- bool uvScaleSet = false;
- String textureName;
- Vector2 uvScale(1, 1);
- Color diffuse(1, 1, 1, 1);
- File file(fileName, FILE_READ);
- while (!file.eof)
- {
- String line = file.ReadLine().Trimmed();
- if (line.StartsWith("alpha_rejection") || line.StartsWith("scene_blend alpha_blend"))
- mask = true;
- if (line.StartsWith("cull_hardware none"))
- twoSided = true;
- // Todo: handle multiple textures per material
- if (textureName.empty && line.StartsWith("texture "))
- {
- textureName = line.Substring(8);
- ProcessRef(textureName);
- }
- if (!uvScaleSet && line.StartsWith("scale "))
- {
- uvScale = line.Substring(6).ToVector2();
- uvScaleSet = true;
- }
- if (line.StartsWith("diffuse "))
- diffuse = line.Substring(8).ToColor();
- }
- XMLFile outMat;
- XMLElement rootElem = outMat.CreateRoot("material");
- XMLElement techniqueElem = rootElem.CreateChild("technique");
- if (twoSided)
- {
- XMLElement cullElem = rootElem.CreateChild("cull");
- cullElem.SetAttribute("value", "none");
- XMLElement shadowCullElem = rootElem.CreateChild("shadowcull");
- shadowCullElem.SetAttribute("value", "none");
- }
- if (!textureName.empty)
- {
- techniqueElem.SetAttribute("name", mask ? "Techniques/DiffAlphaMask.xml" : "Techniques/Diff.xml");
- String outTextureName = GetOutTextureName(textureName);
- XMLElement textureElem = rootElem.CreateChild("texture");
- textureElem.SetAttribute("unit", "diffuse");
- textureElem.SetAttribute("name", outTextureName);
- fileSystem.Copy(filePath + GetFullAssetName(textureName), sceneResourcePath + outTextureName);
- }
- else
- techniqueElem.SetAttribute("name", "NoTexture.xml");
- if (uvScale != Vector2(1, 1))
- {
- XMLElement uScaleElem = rootElem.CreateChild("parameter");
- uScaleElem.SetAttribute("name", "UOffset");
- uScaleElem.SetVector3("value", Vector3(1 / uvScale.x, 0, 0));
- XMLElement vScaleElem = rootElem.CreateChild("parameter");
- vScaleElem.SetAttribute("name", "VOffset");
- vScaleElem.SetVector3("value", Vector3(0, 1 / uvScale.y, 0));
- }
- if (diffuse != Color(1, 1, 1, 1))
- {
- XMLElement diffuseElem = rootElem.CreateChild("parameter");
- diffuseElem.SetAttribute("name", "MatDiffColor");
- diffuseElem.SetColor("value", diffuse);
- }
- File outFile(outFileName, FILE_WRITE);
- outMat.Save(outFile);
- outFile.Close();
- convertedMaterials.Push(materialName);
- }
|