Browse Source

Continue work on material editor.
Added shaderParameterNames property to Material's AngelScript API.
Added error prints to possible resource loading error situations.

Lasse Öörni 12 years ago
parent
commit
0b657a893d

+ 28 - 12
Bin/Data/Scripts/Editor/AttributeEditor.as

@@ -949,19 +949,10 @@ void PickResourceDone(StringHash eventType, VariantMap& eventData)
 
 
     // Validate the resource. It must come from within a registered resource directory, and be loaded successfully
     // Validate the resource. It must come from within a registered resource directory, and be loaded successfully
     String resourceName = eventData["FileName"].GetString();
     String resourceName = eventData["FileName"].GetString();
-    Array<String>@ resourceDirs = cache.resourceDirs;
-    Resource@ res;
-
-    for (uint i = 0; i < resourceDirs.length; ++i)
+    Resource@ res = GetPickedResource(resourceName);
+    if (res is null)
     {
     {
-        if (!resourceName.ToLower().StartsWith(resourceDirs[i].ToLower()))
-            continue;
-        resourceName = resourceName.Substring(resourceDirs[i].length);
-        res = cache.GetResource(resourcePicker.typeName, resourceName);
-        break;
-    }
-    if (res is null) {
-        log.Warning("Cannot find resource type: " + resourcePicker.typeName + " Name:" + resourceName);
+        @resourcePicker = null;
         return;
         return;
     }
     }
 
 
@@ -1012,6 +1003,31 @@ void PickResourceDone(StringHash eventType, VariantMap& eventData)
     @resourcePicker = null;
     @resourcePicker = null;
 }
 }
 
 
+Resource@ GetPickedResource(String resourceName)
+{
+    resourceName = GetResourceNameFromFullName(resourceName);
+    Resource@ res = cache.GetResource(resourcePicker.typeName, resourceName);
+
+    if (res is null)
+        log.Warning("Cannot find resource type: " + resourcePicker.typeName + " Name:" + resourceName);
+
+    return res;
+}
+
+String GetResourceNameFromFullName(const String&in resourceName)
+{
+    Array<String>@ resourceDirs = cache.resourceDirs;
+
+    for (uint i = 0; i < resourceDirs.length; ++i)
+    {
+        if (!resourceName.ToLower().StartsWith(resourceDirs[i].ToLower()))
+            continue;
+        return resourceName.Substring(resourceDirs[i].length);
+    }
+    
+    return ""; // Not found
+}
+
 void OpenResource(StringHash eventType, VariantMap& eventData)
 void OpenResource(StringHash eventType, VariantMap& eventData)
 {
 {
     UIElement@ button = eventData["Element"].GetUIElement();
     UIElement@ button = eventData["Element"].GetUIElement();

+ 3 - 0
Bin/Data/Scripts/Editor/EditorInspectorWindow.as

@@ -405,6 +405,9 @@ void PostEditAttribute(Serializable@ serializable, uint index)
 
 
 void SetAttributeEditorID(UIElement@ attrEdit, Array<Serializable@>@ serializables)
 void SetAttributeEditorID(UIElement@ attrEdit, Array<Serializable@>@ serializables)
 {
 {
+    if (serializables is null || serializables.length == 0)
+        return;
+
     // All target serializables must be either nodes, ui-elements, or components
     // All target serializables must be either nodes, ui-elements, or components
     Array<Variant> ids;
     Array<Variant> ids;
     switch (GetType(serializables[0]))
     switch (GetType(serializables[0]))

+ 270 - 3
Bin/Data/Scripts/Editor/EditorMaterial.as

@@ -1,19 +1,286 @@
 // Urho3D material editor
 // Urho3D material editor
 
 
 Window@ materialWindow;
 Window@ materialWindow;
+Material@ editMaterial;
 
 
 void CreateMaterialEditor()
 void CreateMaterialEditor()
 {
 {
     if (materialWindow !is null)
     if (materialWindow !is null)
         return;
         return;
-    
+
     materialWindow = ui.LoadLayout(cache.GetResource("XMLFile", "UI/EditorMaterialWindow.xml"));
     materialWindow = ui.LoadLayout(cache.GetResource("XMLFile", "UI/EditorMaterialWindow.xml"));
     ui.root.AddChild(materialWindow);
     ui.root.AddChild(materialWindow);
     materialWindow.opacity = uiMaxOpacity;
     materialWindow.opacity = uiMaxOpacity;
+
+    RefreshMaterialEditor();
+    
+    int height = Min(ui.root.height - 60, 500);
+    materialWindow.SetSize(300, height);
     CenterDialog(materialWindow);
     CenterDialog(materialWindow);
+
+    HideMaterialEditor();
+
+    SubscribeToEvent(materialWindow.GetChild("NewButton", true), "Released", "NewMaterial");
+    SubscribeToEvent(materialWindow.GetChild("RevertButton", true), "Released", "RevertMaterial");
+    SubscribeToEvent(materialWindow.GetChild("SaveButton", true), "Released", "SaveMaterial");
+    SubscribeToEvent(materialWindow.GetChild("SaveAsButton", true), "Released", "SaveMaterialAs");
+    SubscribeToEvent(materialWindow.GetChild("CloseButton", true), "Released", "HideMaterialEditor");
+    SubscribeToEvent(materialWindow.GetChild("NewParameterDropDown", true), "ItemSelected", "CreateShaderParameter");
+    SubscribeToEvent(materialWindow.GetChild("DeleteParameterButton", true), "Released", "DeleteShaderParameter");
+}
+
+bool ShowMaterialEditor()
+{
+    materialWindow.visible = true;
+    return true;
+}
+
+void HideMaterialEditor()
+{
+    materialWindow.visible = false;
 }
 }
 
 
 void EditMaterial(Material@ mat)
 void EditMaterial(Material@ mat)
 {
 {
-    CreateMaterialEditor();
-}
+    editMaterial = mat;
+    RefreshMaterialEditor();
+    ShowMaterialEditor();
+}
+
+void RefreshMaterialEditor()
+{
+    RefreshMaterialName();
+    RefreshMaterialTechniques();
+    RefreshMaterialTextures();
+    RefreshMaterialShaderParameters();
+}
+
+void RefreshMaterialName()
+{
+    UIElement@ container = materialWindow.GetChild("NameContainer");
+    container.RemoveAllChildren();
+
+    LineEdit@ nameEdit = CreateAttributeLineEdit(container, null, 0, 0);
+    if (editMaterial !is null)
+        nameEdit.text = editMaterial.name;
+
+    Button@ pickButton = CreateResourcePickerButton(container, null, 0, 0, "Pick");
+    SubscribeToEvent(pickButton, "Released", "PickEditMaterial");
+}
+
+void RefreshMaterialTechniques()
+{
+    ListView@ list = materialWindow.GetChild("TechniqueList");
+    list.RemoveAllItems();
+}
+
+void RefreshMaterialTextures()
+{
+    ListView@ list = materialWindow.GetChild("TextureList");
+    list.RemoveAllItems();
+}
+
+void RefreshMaterialShaderParameters()
+{
+    ListView@ list = materialWindow.GetChild("ShaderParameterList");
+    list.RemoveAllItems();
+    if (editMaterial is null)
+        return;
+
+    Array<String>@ parameterNames = editMaterial.shaderParameterNames;
+
+    for (uint i = 0; i < parameterNames.length; ++i)
+    {
+        VariantType type = editMaterial.shaderParameters[parameterNames[i]].type;
+        Variant value = editMaterial.shaderParameters[parameterNames[i]];
+        UIElement@ parent = CreateAttributeEditorParent(list, parameterNames[i], 0, 0);
+        uint numCoords = type - VAR_FLOAT + 1;
+
+        Array<String> coordValues = value.ToString().Split(' ');
+
+        for (uint j = 0; j < numCoords; ++j)
+        {
+            LineEdit@ attrEdit = CreateAttributeLineEdit(parent, null, 0, 0);
+            attrEdit.vars["Coordinate"] = j;
+            attrEdit.vars["Name"] = parameterNames[i];
+            attrEdit.text = coordValues[j];
+            SubscribeToEvent(attrEdit, "TextChanged", "EditShaderParameter");
+            SubscribeToEvent(attrEdit, "TextChanged", "EditShaderParameter");
+        }
+    }
+}
+
+void PickEditMaterial()
+{
+    @resourcePicker = GetResourcePicker(ShortStringHash("Material"));
+    if (resourcePicker is null)
+        return;
+
+    String lastPath = resourcePicker.lastPath;
+    if (lastPath.empty)
+        lastPath = sceneResourcePath;
+    CreateFileSelector("Pick " + resourcePicker.typeName, "OK", "Cancel", lastPath, resourcePicker.filters, resourcePicker.lastFilter);
+    SubscribeToEvent(uiFileSelector, "FileSelected", "PickEditMaterialDone");
+}
+
+void PickEditMaterialDone(StringHash eventType, VariantMap& eventData)
+{
+    CloseFileSelector();
+
+    if (!eventData["OK"].GetBool())
+    {
+        @resourcePicker = null;
+        return;
+    }
+
+    String resourceName = eventData["FileName"].GetString();
+    Resource@ res = GetPickedResource(resourceName);
+
+    if (res !is null)
+        EditMaterial(cast<Material>(res));
+
+    @resourcePicker = null;
+}
+
+void NewMaterial()
+{
+    EditMaterial(Material());
+}
+
+void RevertMaterial()
+{
+    if (editMaterial is null)
+        return;
+
+    cache.ReloadResource(editMaterial);
+    RefreshMaterialEditor();
+}
+
+void SaveMaterial()
+{
+    if (editMaterial is null || editMaterial.name.empty)
+        return;
+
+    String fullName = cache.GetResourceFileName(editMaterial.name);
+    if (fullName.empty)
+        return;
+
+    File saveFile(fullName, FILE_WRITE);
+    editMaterial.Save(saveFile);
+}
+
+void SaveMaterialAs()
+{
+    if (editMaterial is null)
+        return;
+
+    ResourcePicker@ picker = GetResourcePicker(ShortStringHash("Material"));
+    if (picker is null)
+        return;
+
+    String lastPath = picker.lastPath;
+    if (lastPath.empty)
+        lastPath = sceneResourcePath;
+    CreateFileSelector("Save material as", "Save", "Cancel", lastPath, picker.filters, picker.lastFilter);
+    SubscribeToEvent(uiFileSelector, "FileSelected", "SaveMaterialAsDone");
+}
+
+void SaveMaterialAsDone(StringHash eventType, VariantMap& eventData)
+{
+    CloseFileSelector();
+
+    if (editMaterial is null)
+        return;
+
+    if (!eventData["OK"].GetBool())
+    {
+        @resourcePicker = null;
+        return;
+    }
+
+    String fullName = eventData["FileName"].GetString();
+    File saveFile(fullName, FILE_WRITE);
+    if (editMaterial.Save(saveFile))
+    {
+        saveFile.Close();
+
+        // Load the new resource to update the name in the editor
+        Material@ newMat = cache.GetResource("Material", GetResourceNameFromFullName(fullName));
+        if (newMat !is null)
+            EditMaterial(newMat);
+    }
+}
+
+void EditShaderParameter(StringHash eventType, VariantMap& eventData)
+{
+    if (editMaterial is null)
+        return;
+
+    LineEdit@ attrEdit = eventData["Element"].GetUIElement();
+    uint coordinate = attrEdit.vars["Coordinate"].GetUInt();
+    
+    String name = attrEdit.vars["Name"].GetString();
+
+    Variant oldValue = editMaterial.shaderParameters[name];
+    Array<String> coordValues = oldValue.ToString().Split(' ');
+    coordValues[coordinate] = attrEdit.text;
+
+    String valueString;
+    for (uint i = 0; i < coordValues.length; ++i)
+    {
+        valueString += coordValues[i];
+        valueString += " ";
+    }
+
+    Variant newValue;
+    newValue.FromString(oldValue.type, valueString);
+    
+    editMaterial.shaderParameters[name] = newValue;
+}
+
+void CreateShaderParameter(StringHash eventType, VariantMap& eventData)
+{
+    if (editMaterial is null)
+        return;
+
+    LineEdit@ nameEdit = materialWindow.GetChild("ParameterNameEdit", true);
+    String newName = nameEdit.text.Trimmed();
+    if (newName.empty)
+        return;
+
+    DropDownList@ dropDown = eventData["Element"].GetUIElement();
+    Variant newValue;
+
+    switch (dropDown.selection)
+    {
+    case 0:
+        newValue = float(0);
+        break;
+    case 1:
+        newValue = Vector2(0, 0);
+        break;
+    case 2:
+        newValue = Vector3(0, 0, 0);
+        break;
+    case 3:
+        newValue = Vector4(0, 0, 0, 0);
+        break;
+    }
+
+    editMaterial.shaderParameters[newName] = newValue;
+    RefreshMaterialShaderParameters();
+}
+
+void DeleteShaderParameter()
+{
+    if (editMaterial is null)
+        return;
+
+    LineEdit@ nameEdit = materialWindow.GetChild("ParameterNameEdit", true);
+    String name = nameEdit.text.Trimmed();
+    if (name.empty)
+        return;
+
+    editMaterial.RemoveShaderParameter(name);
+    RefreshMaterialShaderParameters();
+}

+ 2 - 0
Bin/Data/Scripts/Editor/EditorUI.as

@@ -51,6 +51,7 @@ void CreateUI()
     CreateAttributeInspectorWindow();
     CreateAttributeInspectorWindow();
     CreateEditorSettingsDialog();
     CreateEditorSettingsDialog();
     CreateEditorPreferencesDialog();
     CreateEditorPreferencesDialog();
+    CreateMaterialEditor();
     CreateStatsBar();
     CreateStatsBar();
     CreateConsole();
     CreateConsole();
     CreateDebugHud();
     CreateDebugHud();
@@ -258,6 +259,7 @@ void CreateMenuBar()
         Window@ popup = menu.popup;
         Window@ popup = menu.popup;
         popup.AddChild(CreateMenuItem("Hierarchy", @ShowHierarchyWindow, 'H', QUAL_CTRL));
         popup.AddChild(CreateMenuItem("Hierarchy", @ShowHierarchyWindow, 'H', QUAL_CTRL));
         popup.AddChild(CreateMenuItem("Attribute inspector", @ShowAttributeInspectorWindow, 'I', QUAL_CTRL));
         popup.AddChild(CreateMenuItem("Attribute inspector", @ShowAttributeInspectorWindow, 'I', QUAL_CTRL));
+        popup.AddChild(CreateMenuItem("Material editor", @ShowMaterialEditor));
         popup.AddChild(CreateMenuItem("Editor settings", @ShowEditorSettingsDialog));
         popup.AddChild(CreateMenuItem("Editor settings", @ShowEditorSettingsDialog));
         popup.AddChild(CreateMenuItem("Editor preferences", @ShowEditorPreferencesDialog));
         popup.AddChild(CreateMenuItem("Editor preferences", @ShowEditorPreferencesDialog));
         CreateChildDivider(popup);
         CreateChildDivider(popup);

+ 104 - 1
Bin/Data/UI/EditorMaterialWindow.xml

@@ -1,5 +1,5 @@
 <element type="Window">
 <element type="Window">
-    <attribute name="Name" value="MaterialSWindow" />
+    <attribute name="Name" value="MaterialWindow" />
     <attribute name="Is Movable" value="true" />
     <attribute name="Is Movable" value="true" />
     <attribute name="Is Resizable" value="true" />
     <attribute name="Is Resizable" value="true" />
     <attribute name="Resize Border" value="6 6 6 6" />
     <attribute name="Resize Border" value="6 6 6 6" />
@@ -18,6 +18,13 @@
         </element>
         </element>
     </element>
     </element>
     <element type="BorderImage" style="EditorDivider" />
     <element type="BorderImage" style="EditorDivider" />
+    <element>
+        <attribute name="Min Size" value="0 16" />
+        <attribute name="Max Size" value="2147483647 16" />
+        <attribute name="Layout Mode" value="Horizontal" />
+        <attribute name="Name" value="NameContainer" />
+    </element>
+    <element type="BorderImage" style="EditorDivider" />
     <element type="Text">
     <element type="Text">
         <attribute name="Text" value="Techniques" />
         <attribute name="Text" value="Techniques" />
     </element>
     </element>
@@ -38,4 +45,100 @@
     <element type="ListView">
     <element type="ListView">
         <attribute name="Name" value="ShaderParameterList" />
         <attribute name="Name" value="ShaderParameterList" />
     </element>
     </element>
+    <element>
+        <attribute name="Min Size" value="0 17" />
+        <attribute name="Max Size" value="2147483647 17" />
+        <attribute name="Layout Mode" value="Horizontal" />
+        <element type="LineEdit">
+            <attribute name="Name" value="ParameterNameEdit" />
+        </element>
+        <element type="DropDownList">
+            <attribute name="Name" value="NewParameterDropDown" />
+            <attribute name="Min Size" value="50 17" />
+            <attribute name="Max Size" value="50 17" />
+            <attribute name="Resize Popup" value="true" />
+            <element internal="true">
+                <attribute name="Is Visible" value="false" />
+            </element>
+            <element type="Text">
+                <attribute name="Text" value="New" />
+                <attribute name="Text Alignment" value="Center" />
+            </element>
+            <!-- Skip style processing as the purpose of below tags is to populate the content element -->
+            <element type="Window" internal="true" popup="true" style="none">
+                <element type="ListView" internal="true" style="none">
+                    <element type="BorderImage" internal="true" style="none">
+                        <element internal="true" style="none">
+                            <element type="Text" style="EditorEnumAttributeText">
+                                <attribute name="Text" value="Float" />
+                            </element>
+                            <element type="Text" style="EditorEnumAttributeText">
+                                <attribute name="Text" value="Vector2" />
+                            </element>
+                            <element type="Text" style="EditorEnumAttributeText">
+                                <attribute name="Text" value="Vector3" />
+                            </element>
+                            <element type="Text" style="EditorEnumAttributeText">
+                                <attribute name="Text" value="Vector4" />
+                            </element>
+                        </element>
+                    </element>
+                </element>
+            </element>
+        </element>
+        <element type="Button">
+            <attribute name="Name" value="DeleteParameterButton" />
+            <attribute name="Min Size" value="50 17" />
+            <attribute name="Max Size" value="50 17" />
+            <attribute name="Layout Mode" value="Vertical" />
+            <attribute name="Layout Border" value="1 1 1 1" />
+            <element type="Text">
+                <attribute name="Text" value="Del" />
+                <attribute name="Text Alignment" value="Center" />
+            </element>
+        </element>
+    </element>
+    <element type="BorderImage" style="EditorDivider" />
+    <element>
+        <attribute name="Name" value="ButtonContainer" />
+        <attribute name="Min Size" value="0 16" />
+        <attribute name="Max Size" value="2147483647 16" />
+        <attribute name="Layout Mode" value="Horizontal" />
+        <element type="Button">
+            <attribute name="Name" value="NewButton" />
+            <attribute name="Layout Mode" value="Horizontal" />
+            <attribute name="Layout Border" value="1 1 1 1" />
+            <element type="Text">
+                <attribute name="Text" value="New" />
+                <attribute name="Text Alignment" value="Center" />
+            </element>
+        </element>
+        <element type="Button">
+            <attribute name="Name" value="RevertButton" />
+            <attribute name="Layout Mode" value="Horizontal" />
+            <attribute name="Layout Border" value="1 1 1 1" />
+            <element type="Text">
+                <attribute name="Text" value="Revert" />
+                <attribute name="Text Alignment" value="Center" />
+            </element>
+        </element>
+        <element type="Button">
+            <attribute name="Name" value="SaveButton" />
+            <attribute name="Layout Mode" value="Horizontal" />
+            <attribute name="Layout Border" value="1 1 1 1" />
+            <element type="Text">
+                <attribute name="Text" value="Save" />
+                <attribute name="Text Alignment" value="Center" />
+            </element>
+        </element>
+        <element type="Button">
+            <attribute name="Name" value="SaveAsButton" />
+            <attribute name="Layout Mode" value="Horizontal" />
+            <attribute name="Layout Border" value="1 1 1 1" />
+            <element type="Text">
+                <attribute name="Text" value="Save as" />
+                <attribute name="Text Alignment" value="Center" />
+            </element>
+        </element>
+    </element>
 </element>
 </element>

+ 1 - 0
Docs/ScriptAPI.dox

@@ -2062,6 +2062,7 @@ Properties:<br>
 - uint numTechniques
 - uint numTechniques
 - Technique@[] techniques (readonly)
 - Technique@[] techniques (readonly)
 - Variant[] shaderParameters
 - Variant[] shaderParameters
+- String[]@ shaderParameterNames (readonly)
 - Texture@[] textures
 - Texture@[] textures
 - bool occlusion (readonly)
 - bool occlusion (readonly)
 - CullMode cullMode
 - CullMode cullMode

+ 4 - 1
Engine/Resource/ResourceCache.cpp

@@ -427,8 +427,11 @@ Resource* ResourceCache::GetResource(ShortStringHash type, StringHash nameHash)
     // Attempt to load the resource
     // Attempt to load the resource
     SharedPtr<File> file = GetFile(name);
     SharedPtr<File> file = GetFile(name);
     if (!file)
     if (!file)
+    {
+        LOGERROR("Could not open the file for resource " + name);
         return 0;
         return 0;
-    
+    }
+
     LOGDEBUG("Loading resource " + name);
     LOGDEBUG("Loading resource " + name);
     resource->SetName(file->GetName());
     resource->SetName(file->GetName());
     if (!resource->Load(*(file.Get())))
     if (!resource->Load(*(file.Get())))

+ 4 - 1
Engine/Resource/XMLFile.cpp

@@ -83,8 +83,11 @@ bool XMLFile::Load(Deserializer& source)
     
     
     unsigned dataSize = source.GetSize();
     unsigned dataSize = source.GetSize();
     if (!dataSize)
     if (!dataSize)
+    {
+        LOGERROR("Zero sized XML data in " + source.GetName());
         return false;
         return false;
-    
+    }
+
     SharedArrayPtr<char> buffer(new char[dataSize]);
     SharedArrayPtr<char> buffer(new char[dataSize]);
     if (source.Read(buffer.Get(), dataSize) != dataSize)
     if (source.Read(buffer.Get(), dataSize) != dataSize)
         return false;
         return false;

+ 13 - 0
Engine/Script/GraphicsAPI.cpp

@@ -485,6 +485,18 @@ static void ConstructBiasParametersInit(float constantBias, float slopeScaledBia
     new(ptr) BiasParameters(constantBias, slopeScaledBias);
     new(ptr) BiasParameters(constantBias, slopeScaledBias);
 }
 }
 
 
+static CScriptArray* MaterialGetShaderParameterNames(Material* material)
+{
+    Vector<String> result;
+
+    const HashMap<StringHash, MaterialShaderParameter>& parameters = material->GetShaderParameters();
+    for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
+        result.Push(i->second_.name_);
+
+    Sort(result.Begin(), result.End());
+    return VectorToArray<String>(result, "Array<String>");
+}
+
 static void RegisterMaterial(asIScriptEngine* engine)
 static void RegisterMaterial(asIScriptEngine* engine)
 {
 {
     engine->RegisterObjectType("BiasParameters", sizeof(BiasParameters), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C);
     engine->RegisterObjectType("BiasParameters", sizeof(BiasParameters), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C);
@@ -557,6 +569,7 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Material", "Technique@+ get_techniques(uint)", asMETHOD(Material, GetTechnique), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "Technique@+ get_techniques(uint)", asMETHOD(Material, GetTechnique), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_shaderParameters(const String&in, const Variant&in)", asMETHOD(Material, SetShaderParameter), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_shaderParameters(const String&in, const Variant&in)", asMETHOD(Material, SetShaderParameter), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "const Variant& get_shaderParameters(const String&in) const", asMETHOD(Material, GetShaderParameter), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "const Variant& get_shaderParameters(const String&in) const", asMETHOD(Material, GetShaderParameter), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Material", "Array<String>@ get_shaderParameterNames() const", asFUNCTION(MaterialGetShaderParameterNames), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Material", "void set_textures(uint, Texture@+)", asMETHOD(Material, SetTexture), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_textures(uint, Texture@+)", asMETHOD(Material, SetTexture), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "Texture@+ get_textures(uint) const", asMETHOD(Material, GetTexture), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "Texture@+ get_textures(uint) const", asMETHOD(Material, GetTexture), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "bool get_occlusion()", asMETHOD(Material, GetOcclusion), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "bool get_occlusion()", asMETHOD(Material, GetOcclusion), asCALL_THISCALL);