Browse Source

Working on Material import

Josh Engebretson 10 years ago
parent
commit
d7ace33a91

+ 3 - 0
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/tsconfig.json

@@ -23,6 +23,9 @@
         "./ui/ResourceFrame.ts",
         "./ui/ResourceFrame.ts",
         "./ui/ScriptWidget.ts",
         "./ui/ScriptWidget.ts",
         "./ui/UIEvents.ts",
         "./ui/UIEvents.ts",
+        "./ui/inspector/DataBinding.ts",
+        "./ui/inspector/InspectorFrame.ts",
+        "./ui/inspector/MaterialInspector.ts",
         "./ui/modal/MessageModal.ts",
         "./ui/modal/MessageModal.ts",
         "./ui/modal/ModalOps.ts"
         "./ui/modal/ModalOps.ts"
     ]
     ]

+ 4 - 3
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/ui/MainFrame.ts

@@ -1,6 +1,8 @@
 import menubar = require("./MainFrameMenu");
 import menubar = require("./MainFrameMenu");
 import ProjectFrame = require("./ProjectFrame");
 import ProjectFrame = require("./ProjectFrame");
 import ResourceFrame = require("./ResourceFrame");
 import ResourceFrame = require("./ResourceFrame");
+import InspectorFrame = require("./inspector/InspectorFrame");
+
 import MessageModal = require("./modal/MessageModal");
 import MessageModal = require("./modal/MessageModal");
 import UIEvents = require("./UIEvents");
 import UIEvents = require("./UIEvents");
 
 
@@ -12,7 +14,7 @@ class MainFrame extends ScriptWidget {
 
 
     projectframe: ProjectFrame;
     projectframe: ProjectFrame;
     resourceframe: ResourceFrame;
     resourceframe: ResourceFrame;
-    inspectorframe: Editor.InspectorFrame;
+    inspectorframe: InspectorFrame;
 
 
     inspectorlayout: Atomic.UILayout;
     inspectorlayout: Atomic.UILayout;
 
 
@@ -26,8 +28,7 @@ class MainFrame extends ScriptWidget {
 
 
         this.inspectorlayout = <Atomic.UILayout> this.getWidget("inspectorlayout");
         this.inspectorlayout = <Atomic.UILayout> this.getWidget("inspectorlayout");
 
 
-        this.inspectorframe = new Editor.InspectorFrame();
-        this.inspectorframe.load("AtomicEditor/editor/ui/inspectorframe.tb.txt");
+        this.inspectorframe = new InspectorFrame();
         this.inspectorlayout.addChild(this.inspectorframe);
         this.inspectorlayout.addChild(this.inspectorframe);
 
 
         this.projectframe = new ProjectFrame(this);
         this.projectframe = new ProjectFrame(this);

+ 1 - 0
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/ui/ProjectFrame.ts

@@ -193,6 +193,7 @@ class ProjectFrame extends ScriptWidget {
 
 
         var button = new Atomic.UIButton();
         var button = new Atomic.UIButton();
 
 
+        // setup the drag object
         button.dragObject = new Atomic.UIDragObject(asset, asset.name);
         button.dragObject = new Atomic.UIDragObject(asset, asset.name);
 
 
         var lp = new Atomic.UILayoutParams;
         var lp = new Atomic.UILayoutParams;

+ 9 - 0
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/ui/inspector/DataBinding.ts

@@ -0,0 +1,9 @@
+
+
+class DataBinding
+{
+
+}
+
+
+export = DataBinding;

+ 60 - 0
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/ui/inspector/InspectorFrame.ts

@@ -0,0 +1,60 @@
+
+import UIEvents = require("../UIEvents");
+import ScriptWidget = require("../ScriptWidget");
+import DataBinding = require("./DataBinding");
+
+// inspectors
+
+import MaterialInspector = require("./MaterialInspector");
+
+
+var UI = Atomic.UI;
+
+class InspectorFrame extends ScriptWidget {
+
+  constructor() {
+
+    super();
+
+    this.gravity = UI.GRAVITY_TOP_BOTTOM;
+
+    this.load("AtomicEditor/editor/ui/inspectorframe.tb.txt");
+
+    var container = this.getWidget("inspectorcontainer");
+
+    this.materialInspector = new MaterialInspector();
+    container.addChild(this.materialInspector);
+
+    this.subscribeToEvent(UIEvents.EditResource, (data) => this.handleEditResource(data));
+
+  }
+
+  handleEditResource(ev: UIEvents.EditorResourceEvent) {
+
+      var path = ev.path;
+
+      var db = ToolCore.getAssetDatabase();
+      var asset = db.getAssetByPath(path);
+      if (asset) {
+
+        this.inspect(asset);
+
+      }
+
+  }
+
+
+  inspect(asset:ToolCore.Asset) {
+
+    if (asset.importerName == "MaterialImporter") {
+
+      this.materialInspector.inspect(asset);
+
+    }
+  }
+
+  materialInspector:MaterialInspector;
+
+}
+
+export = InspectorFrame;

+ 36 - 0
Data/AtomicEditor/Resources/EditorData/AtomicEditor/typescript/ui/inspector/MaterialInspector.ts

@@ -0,0 +1,36 @@
+
+import ScriptWidget = require("../ScriptWidget");
+
+var UI = Atomic.UI;
+
+class MaterialInspector extends ScriptWidget {
+
+  constructor() {
+
+    super();
+
+    var text = this.nameTextField = new Atomic.UITextField();
+    text.gravity = UI.GRAVITY_ALL;
+
+    //this.gravity = UI.GRAVITY_ALL;
+
+    this.addChild(text)
+
+  }
+
+  inspect(asset:ToolCore.Asset) {
+
+    //this.material = mat;
+
+    this.nameTextField.text = asset.name;
+
+  }
+
+  material:Atomic.Material;
+
+  nameTextField:Atomic.UITextField;
+
+
+}
+
+export = MaterialInspector;

+ 6 - 0
Source/ToolCore/Assets/Asset.cpp

@@ -4,6 +4,7 @@
 #include "ModelImporter.h"
 #include "ModelImporter.h"
 #include "FolderImporter.h"
 #include "FolderImporter.h"
 #include "SceneImporter.h"
 #include "SceneImporter.h"
+#include "MaterialImporter.h"
 #include "Asset.h"
 #include "Asset.h"
 
 
 namespace ToolCore
 namespace ToolCore
@@ -60,6 +61,11 @@ bool Asset::SetPath(const String& path)
                 name_ = GetFileName(path);
                 name_ = GetFileName(path);
                 importer_ = new SceneImporter(context_);
                 importer_ = new SceneImporter(context_);
             }
             }
+            else if (ext == ".material")
+            {
+                name_ = GetFileName(path);
+                importer_ = new MaterialImporter(context_);
+            }
 
 
         }
         }
 
 

+ 2 - 0
Source/ToolCore/Assets/Asset.h

@@ -23,6 +23,8 @@ public:
 
 
     const String& GetGUID() const { return guid_; }
     const String& GetGUID() const { return guid_; }
 
 
+    const String& GetImporterName() { return importer_.Null() ? String::EMPTY : importer_->GetTypeName(); }
+
     const String& GetName() { return name_; }
     const String& GetName() { return name_; }
 
 
     const String& GetPath() const { return path_; }
     const String& GetPath() const { return path_; }

+ 17 - 0
Source/ToolCore/Assets/AssetDatabase.cpp

@@ -93,6 +93,23 @@ Asset* AssetDatabase::GetAssetByGUID(const String& guid)
 
 
 }
 }
 
 
+Asset* AssetDatabase::GetAssetByPath(const String& path)
+{
+    List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
+
+    while (itr != assets_.End())
+    {
+        if (path == (*itr)->GetPath())
+            return *itr;
+
+        itr++;
+    }
+
+    return 0;
+
+}
+
+
 void AssetDatabase::Scan()
 void AssetDatabase::Scan()
 {
 {
     FileSystem* fs = GetSubsystem<FileSystem>();
     FileSystem* fs = GetSubsystem<FileSystem>();

+ 1 - 0
Source/ToolCore/Assets/AssetDatabase.h

@@ -22,6 +22,7 @@ public:
     virtual ~AssetDatabase();
     virtual ~AssetDatabase();
 
 
     Asset* GetAssetByGUID(const String& guid);
     Asset* GetAssetByGUID(const String& guid);
+    Asset* GetAssetByPath(const String& guid);
 
 
     String GetCachePath();
     String GetCachePath();
 
 

+ 60 - 0
Source/ToolCore/Assets/MaterialImporter.cpp

@@ -0,0 +1,60 @@
+
+#include "Asset.h"
+#include "AssetDatabase.h"
+#include "MaterialImporter.h"
+
+namespace ToolCore
+{
+
+MaterialImporter::MaterialImporter(Context* context) : AssetImporter(context)
+{
+
+}
+
+MaterialImporter::~MaterialImporter()
+{
+
+}
+
+void MaterialImporter::SetDefaults()
+{
+    AssetImporter::SetDefaults();
+}
+
+bool MaterialImporter::Import(const String& guid)
+{
+    AssetDatabase* db = GetSubsystem<AssetDatabase>();
+    Asset* asset = db->GetAssetByGUID(guid);
+
+    if (!asset)
+        return false;
+
+    return true;
+}
+
+bool MaterialImporter::LoadInternal()
+{
+    if (!AssetImporter::LoadInternal())
+        return false;
+
+    JSONValue root = json_->GetRoot();
+
+    JSONValue import = root.GetChild("MaterialImporter", JSON_OBJECT);
+
+    return true;
+}
+
+bool MaterialImporter::SaveInternal()
+{
+    if (!AssetImporter::SaveInternal())
+        return false;
+
+    JSONValue root = json_->GetRoot();
+
+    JSONValue import = root.CreateChild("MaterialImporter");
+
+    return true;
+}
+
+
+}

+ 29 - 0
Source/ToolCore/Assets/MaterialImporter.h

@@ -0,0 +1,29 @@
+
+#pragma once
+
+#include "AssetImporter.h"
+
+namespace ToolCore
+{
+
+class MaterialImporter : public AssetImporter
+{
+    OBJECT(MaterialImporter);
+
+public:
+    /// Construct.
+    MaterialImporter(Context* context);
+    virtual ~MaterialImporter();
+
+    virtual void SetDefaults();
+
+    bool Import(const String& guid);
+
+protected:
+
+    virtual bool LoadInternal();
+    virtual bool SaveInternal();
+
+};
+
+}

+ 179 - 4
Source/ToolCore/Import/OpenAssetImporter.cpp

@@ -25,9 +25,11 @@
 // https://github.com/AtomicGameEngine/AtomicGameEngine
 // https://github.com/AtomicGameEngine/AtomicGameEngine
 
 
 #include <Atomic/Core/ProcessUtils.h>
 #include <Atomic/Core/ProcessUtils.h>
+#include <Atomic/Core/Context.h>
 #include <Atomic/IO/Log.h>
 #include <Atomic/IO/Log.h>
 #include <Atomic/IO/File.h>
 #include <Atomic/IO/File.h>
 #include <Atomic/IO/FileSystem.h>
 #include <Atomic/IO/FileSystem.h>
+#include <Atomic/Resource/XMLFile.h>
 
 
 #include <Atomic/Atomic3D/AnimatedModel.h>
 #include <Atomic/Atomic3D/AnimatedModel.h>
 #include <Atomic/Atomic3D/Animation.h>
 #include <Atomic/Atomic3D/Animation.h>
@@ -58,9 +60,9 @@ OpenAssetImporter::OpenAssetImporter(Context* context) : Object(context) ,
     includeNonSkinningBones_(false),
     includeNonSkinningBones_(false),
     verboseLog_(false),
     verboseLog_(false),
     emissiveAO_(false),
     emissiveAO_(false),
-    noOverwriteMaterial_(false),
-    noOverwriteTexture_(false),
-    noOverwriteNewerTexture_(false),
+    noOverwriteMaterial_(true),
+    noOverwriteTexture_(true),
+    noOverwriteNewerTexture_(true),
     checkUniqueModel_(true),
     checkUniqueModel_(true),
     maxBones_(64),
     maxBones_(64),
     defaultTicksPerSecond_(4800.0f)
     defaultTicksPerSecond_(4800.0f)
@@ -97,6 +99,8 @@ bool OpenAssetImporter::Load(const String &assetPath)
 
 
     //PrintLine("Reading file " + assetPath);
     //PrintLine("Reading file " + assetPath);
 
 
+    sourceAssetPath_ = GetPath(assetPath);
+
     scene_ = aiImportFile(GetNativePath(assetPath).CString(), aiCurrentFlags_);
     scene_ = aiImportFile(GetNativePath(assetPath).CString(), aiCurrentFlags_);
 
 
     if (!scene_)
     if (!scene_)
@@ -135,6 +139,12 @@ void OpenAssetImporter::ExportModel(const String& outName, bool animationOnly)
         CollectAnimations();
         CollectAnimations();
         BuildAndSaveAnimations();
         BuildAndSaveAnimations();
     }
     }
+
+    if (!noMaterials_)
+    {
+        HashSet<String> usedTextures;
+        ExportMaterials(usedTextures);
+    }
 }
 }
 void OpenAssetImporter::BuildAndSaveModel(OutModel& model)
 void OpenAssetImporter::BuildAndSaveModel(OutModel& model)
 {
 {
@@ -396,7 +406,7 @@ String OpenAssetImporter::GetMeshMaterialName(aiMesh* mesh)
     if (matName.Trimmed().Empty())
     if (matName.Trimmed().Empty())
         matName = GenerateMaterialName(material);
         matName = GenerateMaterialName(material);
 
 
-    return (useSubdirs_ ? "Materials/" : "") + matName + ".xml";
+    return (useSubdirs_ ? "Materials/" : "") + matName + ".material";
 }
 }
 
 
 String OpenAssetImporter::GenerateMaterialName(aiMaterial* material)
 String OpenAssetImporter::GenerateMaterialName(aiMaterial* material)
@@ -880,6 +890,171 @@ void OpenAssetImporter::BuildAndSaveAnimations(OutModel* model)
     }
     }
 }
 }
 
 
+// Materials
+void OpenAssetImporter::ExportMaterials(HashSet<String>& usedTextures)
+{
+    if (useSubdirs_)
+    {
+        context_->GetSubsystem<FileSystem>()->CreateDir(sourceAssetPath_ + "Materials");
+    }
+
+    for (unsigned i = 0; i < scene_->mNumMaterials; ++i)
+        BuildAndSaveMaterial(scene_->mMaterials[i], usedTextures);
+}
+
+void OpenAssetImporter::BuildAndSaveMaterial(aiMaterial* material, HashSet<String>& usedTextures)
+{
+    aiString matNameStr;
+    material->Get(AI_MATKEY_NAME, matNameStr);
+    String matName = SanitateAssetName(FromAIString(matNameStr));
+    if (matName.Trimmed().Empty())
+        matName = GenerateMaterialName(material);
+
+    // Do not actually create a material instance, but instead craft an xml file manually
+    XMLFile outMaterial(context_);
+    XMLElement materialElem = outMaterial.CreateRoot("material");
+
+    String diffuseTexName;
+    String normalTexName;
+    String specularTexName;
+    String lightmapTexName;
+    String emissiveTexName;
+    Color diffuseColor = Color::WHITE;
+    Color specularColor;
+    Color emissiveColor = Color::BLACK;
+    bool hasAlpha = false;
+    bool twoSided = false;
+    float specPower = 1.0f;
+
+    aiString stringVal;
+    float floatVal;
+    int intVal;
+    aiColor3D colorVal;
+
+    if (material->Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), stringVal) == AI_SUCCESS)
+        diffuseTexName = GetFileNameAndExtension(FromAIString(stringVal));
+    if (material->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0), stringVal) == AI_SUCCESS)
+        normalTexName = GetFileNameAndExtension(FromAIString(stringVal));
+    if (material->Get(AI_MATKEY_TEXTURE(aiTextureType_SPECULAR, 0), stringVal) == AI_SUCCESS)
+        specularTexName = GetFileNameAndExtension(FromAIString(stringVal));
+    if (material->Get(AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP, 0), stringVal) == AI_SUCCESS)
+        specularTexName = GetFileNameAndExtension(FromAIString(stringVal));
+    if (material->Get(AI_MATKEY_TEXTURE(aiTextureType_EMISSIVE, 0), stringVal) == AI_SUCCESS)
+        emissiveTexName = GetFileNameAndExtension(FromAIString(stringVal));
+    if (!noMaterialDiffuseColor_)
+    {
+        if (material->Get(AI_MATKEY_COLOR_DIFFUSE, colorVal) == AI_SUCCESS)
+            diffuseColor = Color(colorVal.r, colorVal.g, colorVal.b);
+    }
+    if (material->Get(AI_MATKEY_COLOR_SPECULAR, colorVal) == AI_SUCCESS)
+        specularColor = Color(colorVal.r, colorVal.g, colorVal.b);
+    if (!emissiveAO_)
+    {
+        if (material->Get(AI_MATKEY_COLOR_EMISSIVE, colorVal) == AI_SUCCESS)
+            emissiveColor = Color(colorVal.r, colorVal.g, colorVal.b);
+    }
+    if (material->Get(AI_MATKEY_OPACITY, floatVal) == AI_SUCCESS)
+    {
+        if (floatVal < 1.0f)
+            hasAlpha = true;
+        diffuseColor.a_ = floatVal;
+    }
+    if (material->Get(AI_MATKEY_SHININESS, floatVal) == AI_SUCCESS)
+        specPower = floatVal;
+    if (material->Get(AI_MATKEY_TWOSIDED, intVal) == AI_SUCCESS)
+        twoSided = (intVal != 0);
+
+    String techniqueName = "Techniques/NoTexture";
+    if (!diffuseTexName.Empty())
+    {
+        techniqueName = "Techniques/Diff";
+        if (!normalTexName.Empty())
+            techniqueName += "Normal";
+        if (!specularTexName.Empty())
+            techniqueName += "Spec";
+        // For now lightmap does not coexist with normal & specular
+        if (normalTexName.Empty() && specularTexName.Empty() && !lightmapTexName.Empty())
+            techniqueName += "LightMap";
+        if (lightmapTexName.Empty() && !emissiveTexName.Empty())
+            techniqueName += emissiveAO_ ? "AO" : "Emissive";
+    }
+    if (hasAlpha)
+        techniqueName += "Alpha";
+
+    XMLElement techniqueElem = materialElem.CreateChild("technique");
+    techniqueElem.SetString("name", techniqueName + ".xml");
+
+    if (!diffuseTexName.Empty())
+    {
+        XMLElement diffuseElem = materialElem.CreateChild("texture");
+        diffuseElem.SetString("unit", "diffuse");
+        diffuseElem.SetString("name", GetMaterialTextureName(diffuseTexName));
+        usedTextures.Insert(diffuseTexName);
+    }
+    if (!normalTexName.Empty())
+    {
+        XMLElement normalElem = materialElem.CreateChild("texture");
+        normalElem.SetString("unit", "normal");
+        normalElem.SetString("name", GetMaterialTextureName(normalTexName));
+        usedTextures.Insert(normalTexName);
+    }
+    if (!specularTexName.Empty())
+    {
+        XMLElement specularElem = materialElem.CreateChild("texture");
+        specularElem.SetString("unit", "specular");
+        specularElem.SetString("name", GetMaterialTextureName(specularTexName));
+        usedTextures.Insert(specularTexName);
+    }
+    if (!lightmapTexName.Empty())
+    {
+        XMLElement lightmapElem = materialElem.CreateChild("texture");
+        lightmapElem.SetString("unit", "emissive");
+        lightmapElem.SetString("name", GetMaterialTextureName(lightmapTexName));
+        usedTextures.Insert(lightmapTexName);
+    }
+    if (!emissiveTexName.Empty())
+    {
+        XMLElement emissiveElem = materialElem.CreateChild("texture");
+        emissiveElem.SetString("unit", "emissive");
+        emissiveElem.SetString("name", GetMaterialTextureName(emissiveTexName));
+        usedTextures.Insert(emissiveTexName);
+    }
+
+    XMLElement diffuseColorElem = materialElem.CreateChild("parameter");
+    diffuseColorElem.SetString("name", "MatDiffColor");
+    diffuseColorElem.SetColor("value", diffuseColor);
+    XMLElement specularElem = materialElem.CreateChild("parameter");
+    specularElem.SetString("name", "MatSpecColor");
+    specularElem.SetVector4("value", Vector4(specularColor.r_, specularColor.g_, specularColor.b_, specPower));
+    XMLElement emissiveColorElem = materialElem.CreateChild("parameter");
+    emissiveColorElem.SetString("name", "MatEmissiveColor");
+    emissiveColorElem.SetColor("value", emissiveColor);
+
+    if (twoSided)
+    {
+        XMLElement cullElem = materialElem.CreateChild("cull");
+        XMLElement shadowCullElem = materialElem.CreateChild("shadowcull");
+        cullElem.SetString("value", "none");
+        shadowCullElem.SetString("value", "none");
+    }
+
+    FileSystem* fileSystem = context_->GetSubsystem<FileSystem>();
+
+    String outFileName = sourceAssetPath_ + (useSubdirs_ ? "Materials/" : "" ) + matName + ".material";
+    if (noOverwriteMaterial_ && fileSystem->FileExists(outFileName))
+    {
+        PrintLine("Skipping save of existing material " + matName);
+        return;
+    }
+
+    PrintLine("Writing material " + matName);
+
+    File outFile(context_);
+    if (!outFile.Open(outFileName, FILE_WRITE))
+        ErrorExit("Could not open output file " + outFileName);
+    outMaterial.Save(outFile);
+}
+
 void OpenAssetImporter::DumpNodes(aiNode* rootNode, unsigned level)
 void OpenAssetImporter::DumpNodes(aiNode* rootNode, unsigned level)
 {
 {
     if (!rootNode)
     if (!rootNode)

+ 4 - 0
Source/ToolCore/Import/OpenAssetImporter.h

@@ -55,6 +55,9 @@ private:
     void BuildAndSaveModel(OutModel& model);
     void BuildAndSaveModel(OutModel& model);
     void BuildAndSaveAnimations(OutModel* model = 0);
     void BuildAndSaveAnimations(OutModel* model = 0);
 
 
+    void ExportMaterials(HashSet<String>& usedTextures);
+    void BuildAndSaveMaterial(aiMaterial* material, HashSet<String>& usedTextures);
+
     void CollectSceneModels(OutScene& scene, aiNode* node);
     void CollectSceneModels(OutScene& scene, aiNode* node);
     void CollectBones(OutModel& model, bool animationOnly = false);
     void CollectBones(OutModel& model, bool animationOnly = false);
     void CollectBonesFinal(PODVector<aiNode*>& dest, const HashSet<aiNode*>& necessary, aiNode* node);
     void CollectBonesFinal(PODVector<aiNode*>& dest, const HashSet<aiNode*>& necessary, aiNode* node);
@@ -75,6 +78,7 @@ private:
     aiNode* rootNode_;
     aiNode* rootNode_;
 
 
     String inputName_;
     String inputName_;
+    String sourceAssetPath_;
     String resourcePath_;
     String resourcePath_;
     String outPath_;
     String outPath_;
     bool useSubdirs_;
     bool useSubdirs_;