Browse Source

Layered Image Editor

Created an editor for the new Layered Image Asset.
Peter Robinson 3 years ago
parent
commit
1239ebf596

+ 8 - 1
editor/AssetAdmin/AssetInspector.cs

@@ -113,7 +113,10 @@ function AssetInspector::onAdd(%this)
 	%this.emitterGraphPage = %this.createTabPage("Emitter Graph", "AssetParticleGraphEmitterTool", "AssetParticleGraphTool");
 
 	//Image Frame Edit Tool
-	%this.imageFrameEditPage = %this.createTabPage("Frame Edit", "AssetImageFrameEditTool", "");
+	%this.imageFrameEditPage = %this.createTabPage("Explicit Frames", "AssetImageFrameEditTool", "");
+
+	//Image Layer Edit Tool
+	%this.imageLayersEditPage = %this.createTabPage("Image Layers", "AssetImageLayersEditTool", "");
 }
 
 function AssetInspector::createTabPage(%this, %name, %class, %superClass)
@@ -205,6 +208,8 @@ function AssetInspector::resetInspector(%this)
 	%this.tabBook.selectPage(0);
 	%this.tabBook.removeIfMember(%this.scaleGraphPage);
 	%this.tabBook.removeIfMember(%this.emitterGraphPage);
+	%this.tabBook.removeIfMember(%this.imageFrameEditPage);
+	%this.tabBook.removeIfMember(%this.imageLayersEditPage);
 
 	%this.emitterButtonBar.visible = false;
 	%this.deleteAssetButton.visible = true;
@@ -214,6 +219,7 @@ function AssetInspector::loadImageAsset(%this, %imageAsset, %assetID)
 {
 	%this.resetInspector();
 	%this.tabBook.add(%this.imageFrameEditPage);
+	%this.tabBook.add(%this.imageLayersEditPage);
 	%this.tabBook.selectPage(0);
 	%this.titlebar.setText("Image Asset:" SPC %imageAsset.AssetName);
 
@@ -227,6 +233,7 @@ function AssetInspector::loadImageAsset(%this, %imageAsset, %assetID)
 	%this.inspector.openGroupByIndex(0);
 
 	%this.imageFrameEditPage.inspect(%imageAsset);
+	%this.imageLayersEditPage.inspect(%imageAsset);
 }
 
 function AssetInspector::loadAnimationAsset(%this, %animationAsset, %assetID)

+ 254 - 0
editor/AssetAdmin/ImageEditor/AssetImageLayersEditRow.cs

@@ -0,0 +1,254 @@
+
+function AssetImageLayersEditRow::onAdd(%this)
+{
+	%this.errorColor = "255 0 0 255";
+	%this.indexBox = new GuiControl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="0 0";
+		Extent="20 40";
+		Align = center;
+		vAlign = middle;
+		Text = %this.LayerIndex;
+		FontSizeAdjust = 1.4;
+		FontColor = %this.errorColor;
+	};
+	ThemeManager.setProfile(%this.indexBox, "codeProfile");
+	%this.add(%this.indexBox);
+
+	%this.imageBox = new GuiTextEditCtrl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="20 3";
+		Extent="200 32";
+		Text = %this.LayerImage;
+		AltCommand = %this.getID() @ ".LayerImageChange();";
+		FontColor = %this.errorColor;
+		InputMode = "AllText";
+	};
+	ThemeManager.setProfile(%this.imageBox, "textEditProfile");
+	%this.add(%this.imageBox);
+
+	%this.offsetXBox = new GuiTextEditCtrl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="224 3";
+		Extent="80 32";
+		Align = right;
+		Text = getWord(%this.LayerPosition, 0);
+		AltCommand = %this.getID() @ ".LayerPositionXChange();";
+		FontColor = %this.errorColor;
+		InputMode = "Number";
+	};
+	ThemeManager.setProfile(%this.offsetXBox, "textEditProfile");
+	%this.add(%this.offsetXBox);
+
+	%this.offsetYBox = new GuiTextEditCtrl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="308 3";
+		Extent="80 32";
+		Align = right;
+		Text = getWord(%this.LayerPosition, 1);
+		AltCommand = %this.getID() @ ".LayerPositionYChange();";
+		FontColor = %this.errorColor;
+		InputMode = "Number";
+	};
+	ThemeManager.setProfile(%this.offsetYBox, "textEditProfile");
+	%this.add(%this.offsetYBox);
+
+	%this.LayerColor = %this.scrubColor(%this.LayerColor);
+	%this.colorBox = new GuiTextEditCtrl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="392 3";
+		Extent="164 32";
+		Align = right;
+		Text = %this.LayerColor;
+		AltCommand = %this.getID() @ ".LayerColorChange();";
+		FontColor = %this.errorColor;
+		InputMode = "AllText";
+	};
+	ThemeManager.setProfile(%this.colorBox, "textEditProfile");
+	%this.add(%this.colorBox);
+
+	%this.buttonBar = new GuiChainCtrl()
+	{
+		Class = "EditorButtonBar";
+		Position = "564 5";
+		Extent = "0 24";
+		ChildSpacing = 4;
+		IsVertical = false;
+		Tool = %this;
+	};
+	ThemeManager.setProfile(%this.buttonBar, "emptyProfile");
+	%this.add(%this.buttonBar);
+
+	if(%this.LayerIndex > 0)
+	{
+		%this.buttonBar.addButton("MoveLayerUp", 2, "Move Layer Up", "getMoveLayerUpEnabled");
+		%this.buttonBar.addButton("MoveLayerDown", 6, "Move Layer Down", "getMoveLayerDownEnabled");
+		%this.buttonBar.addButton("RemoveLayer", 23, "Remove Layer", "");
+	}
+	else
+	{
+		%this.imageBox.active = false;
+		%this.offsetXBox.active = false;
+		%this.offsetYBox.active = false;
+	}
+}
+
+function AssetImageLayersEditRow::LayerImageChange(%this)
+{
+	%name = %this.imageBox.getText();
+	%name = stripChars(%name, " ");
+	%this.imageBox.setText(%name);
+	if(%name !$= %this.LayerImage)
+	{
+		if(%name $= "")
+		{
+			%this.setNameError(true);
+		}
+		else
+		{
+			%this.setNameError(false);
+			%this.postEvent("LayerImageChange", %this SPC %name);
+		}
+	}
+}
+
+function AssetImageLayersEditRow::LayerPositionXChange(%this)
+{
+	%x = %this.offsetXBox.getText();
+	%x = stripChars(%x, " ");
+	if(%x $= "")
+	{
+		%x = 0;
+	}
+	%this.offsetXBox.setText(%x);
+
+	if(%x !$= getWord(%this.LayerPosition, 0))
+	{
+		%this.postEvent("LayerPositionChange", %this SPC %x SPC getWord(%this.LayerPosition, 1));
+	}
+}
+
+function AssetImageLayersEditRow::LayerPositionYChange(%this)
+{
+	%y = %this.offsetYBox.getText();
+	%y = stripChars(%y, " ");
+	if(%y $= "")
+	{
+		%y = 0;
+	}
+	%this.offsetYBox.setText(%y);
+
+	if(%y !$= getWord(%this.CellOffset, 1))
+	{
+		%this.postEvent("LayerPositionChange", %this SPC getWord(%this.LayerPosition, 0) SPC %y);
+	}
+}
+
+function AssetImageLayersEditRow::LayerColorChange(%this)
+{
+	%color = %this.scrubColor(%this.colorBox.getText());
+	%this.colorBox.setText(%color);
+
+	if(%color !$= %this.LayerColor)
+	{
+		%this.postEvent("LayerColorChange", %this SPC %color);
+	}
+}
+
+function AssetImageLayersEditRow::setNameError(%this, %hasError)
+{
+	%this.imageBox.overrideFontColor = %hasError;
+	%this.indexBox.overrideFontColor = %hasError;
+}
+
+function AssetImageLayersEditRow::getMoveLayerUpEnabled(%this)
+{
+	return %this.LayerIndex != 1;
+}
+
+function AssetImageLayersEditRow::getMoveLayerDownEnabled(%this)
+{
+	return %this.LayerIndex != %this.LayerCount;
+}
+
+function AssetImageLayersEditRow::getRemoveCellEnabled(%this)
+{
+	return true;
+}
+
+function AssetImageLayersEditRow::updateLayerCount(%this, %newCount)
+{
+	%this.LayerCount = %newCount;
+	%this.buttonBar.refreshEnabled();
+}
+
+function AssetImageLayersEditRow::MoveLayerUp(%this)
+{
+	%this.postEvent("swapLayers", (%this.LayerIndex - 1) SPC %this.LayerIndex);
+}
+
+function AssetImageLayersEditRow::MoveLayerDown(%this)
+{
+	%this.postEvent("swapLayers", %this.LayerIndex SPC (%this.LayerIndex + 1));
+}
+
+function AssetImageLayersEditRow::RemoveLayer(%this)
+{
+	%this.postEvent("removeLayer", %this.LayerIndex);
+}
+
+function AssetImageLayersEditRow::refresh(%this)
+{
+	%this.indexBox.setText(%this.LayerIndex);
+	%this.imageBox.setText(%this.LayerImage);
+	%this.offsetXBox.setText(getWord(%this.LayerPosition, 0));
+	%this.offsetYBox.setText(getWord(%this.LayerPosition, 1));
+	%this.colorBox.setText(%this.LayerColor);
+}
+
+function AssetImageLayersEditRow::onRemove(%this)
+{
+	%this.deleteObjects();
+}
+
+function AssetImageLayersEditRow::scrubColor(%this, %color)
+{
+	%red = %this.scrubChannel(getWord(%color, 0));
+	%green = %this.scrubChannel(getWord(%color, 1));
+	%blue = %this.scrubChannel(getWord(%color, 2));
+	%alpha = %this.scrubChannel(getWord(%color, 3));
+
+	return %red SPC %green SPC %blue SPC %alpha;
+}
+
+function AssetImageLayersEditRow::scrubChannel(%this, %val)
+{
+	%val = mFloatLength(mClamp(%val, 0, 1), 3);
+	if(getSubStr(%val, 4, 1) != "0")
+	{
+		return %val;
+	}
+	%val = getSubStr(%val, 0, 4);
+
+	if(getSubStr(%val, 3, 1) != "0")
+	{
+		return %val;
+	}
+	%val = getSubStr(%val, 0, 3);
+
+	if(getSubStr(%val, 2, 1) != "0")
+	{
+		return %val;
+	}
+	return getSubStr(%val, 0, 1);
+}

+ 203 - 0
editor/AssetAdmin/ImageEditor/AssetImageLayersEditTool.cs

@@ -0,0 +1,203 @@
+
+function AssetImageLayersEditTool::onAdd(%this)
+{
+	%this.toolScroll = new GuiScrollCtrl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="0 40";
+		Extent= getWord(%this.extent, 0) SPC (getWord(%this.extent, 1) - 40);
+		hScrollBar="dynamic";
+		vScrollBar="dynamic";
+		constantThumbHeight="0";
+		showArrowButtons="1";
+		scrollBarThickness="14";
+	};
+	ThemeManager.setProfile(%this.toolScroll, "scrollingPanelProfile");
+	ThemeManager.setProfile(%this.toolScroll, "scrollingPanelThumbProfile", "ThumbProfile");
+	ThemeManager.setProfile(%this.toolScroll, "scrollingPanelTrackProfile", "TrackProfile");
+	ThemeManager.setProfile(%this.toolScroll, "scrollingPanelArrowProfile", "ArrowProfile");
+	%this.add(%this.toolScroll);
+
+	%this.rowChain = new GuiChainCtrl()
+	{
+		HorizSizing="right";
+		VertSizing="bottom";
+		Position="0 0";
+		Extent= "662" SPC getWord(%this.toolScroll.extent, 1);
+		IsVertical="1";
+		ChildSpacing="2";
+	};
+	ThemeManager.setProfile(%this.rowChain, "emptyProfile");
+	%this.toolScroll.add(%this.rowChain);
+
+	%this.addNewLayerButton = new GuiButtonCtrl()
+	{
+		HorizSizing="left";
+		VertSizing="bottom";
+		Position="580 5";
+		Extent= "110 26";
+		Text = "Add Layer";
+		command = %this.getID() @ ".addNewLayer();";
+	};
+	ThemeManager.setProfile(%this.addNewLayerButton, "buttonProfile");
+	%this.add(%this.addNewLayerButton);
+}
+
+function AssetImageLayersEditTool::inspect(%this, %asset)
+{
+	%this.asset = %asset;
+
+	%this.rowChain.deleteObjects();
+	%this.addHeaderRow();
+	%this.createRows();
+}
+
+function AssetImageLayersEditTool::createRows(%this)
+{
+	%this.addImageLayerRow(%this.asset.getRelativeImageFile(), "0 0", %this.asset.getBlendColor(), 0);
+
+	%count = %this.asset.getLayerCount();
+	for(%i = 1; %i <= %count; %i++)
+	{
+		%image = %this.asset.getLayerImage(%i);
+		%position = %this.asset.getLayerPosition(%i);
+		%color = %this.asset.getLayerBlendColor(%i);
+
+		%this.addImageLayerRow(%image, %position, %color, %i);
+	}
+}
+
+function AssetImageLayersEditTool::addHeaderRow(%this)
+{
+	%row = new GuiControl()
+	{
+		Class = "AssetImageLayersHeaderRow";
+		HorizSizing="right";
+		VertSizing="bottom";
+		Position="0 0";
+		Extent="560 22";
+	};
+	ThemeManager.setProfile(%row, "emptyProfile");
+	%this.rowChain.add(%row);
+}
+
+function AssetImageLayersEditTool::addImageLayerRow(%this, %image, %position, %color, %index)
+{
+	%row = new GuiControl()
+	{
+		Class = "AssetImageLayersEditRow";
+		HorizSizing="right";
+		VertSizing="bottom";
+		Position="0 0";
+		Extent="662 40";
+		LayerImage = %image;
+		LayerPosition = %position;
+		LayerColor = %color;
+		LayerIndex = %index;
+		LayerCount = %this.asset.getLayerCount();
+	};
+	ThemeManager.setProfile(%row, "emptyProfile");
+	%this.rowChain.add(%row);
+	%this.startListening(%row);
+}
+
+function AssetImageLayersEditTool::addNewLayer(%this)
+{
+	%index = %this.asset.getLayerCount();
+	%image = %this.asset.getRelativeImageFile();
+
+	%this.rowChain.callOnChildrenNoRecurse("updateLayerCount", %index + 1);
+
+	%this.asset.addLayer(%image, "0 0", "1 1 1 1");
+	%this.addImageLayerRow(%image, "0 0", "1 1 1 1", %index + 1);
+}
+
+function AssetImageLayersEditTool::onLayerImageChange(%this, %data)
+{
+	%row = getWord(%data, 0);
+	%image = getWord(%data, 1);
+
+	%this.asset.setLayerImage(%row.LayerIndex, %image);
+	%row.LayerImage = %image;
+}
+
+function AssetImageLayersEditTool::onLayerPositionChange(%this, %data)
+{
+	%row = getWord(%data, 0);
+	%x = getWord(%data, 1);
+	%y = getWord(%data, 2);
+
+	%this.asset.setLayerPosition(%row.LayerIndex, %x SPC %y);
+	%row.LayerPosition = %x SPC %y;
+}
+
+function AssetImageLayersEditTool::onLayerColorChange(%this, %data)
+{
+	%row = getWord(%data, 0);
+	%color = getWord(%data, 1) SPC getWord(%data, 2) SPC getWord(%data, 3) SPC getWord(%data, 4);
+
+	if(%row.LayerIndex == 0)
+	{
+		%this.asset.setBlendColor(%color);
+	}
+	else
+	{
+		%this.asset.setLayerBlendColor(%row.LayerIndex, %color);
+	}
+	%row.LayerColor = %color;
+}
+
+function AssetImageLayersEditTool::onSwapLayers(%this, %data)
+{
+	%index1 = getWord(%data, 0);
+	%index2 = getWord(%data, 1);
+
+	%image1 = %this.asset.getLayerImage(%index1);
+	%offset1 = %this.asset.getLayerPosition(%index1);
+	%color1 = %this.asset.getLayerBlendColor(%index1);
+
+	%image2 = %this.asset.getLayerImage(%index2);
+	%offset2 = %this.asset.getLayerPosition(%index2);
+	%color2 = %this.asset.getLayerBlendColor(%index2);
+
+	%this.asset.moveLayerForward(%index1);
+
+	%row1 = %this.rowChain.getObject(%index1 + 1);
+	%row2 = %this.rowChain.getObject(%index2 + 1);
+
+	%row1.LayerPosition = %offset2;
+	%row1.LayerColor = %color2;
+	%row1.LayerImage = %image2;
+
+	%row2.LayerPosition = %offset1;
+	%row2.LayerColor = %color1;
+	%row2.LayerImage = %image1;
+
+	%row1.refresh();
+	%row2.refresh();
+}
+
+function AssetImageLayersEditTool::onRemoveLayer(%this, %index)
+{
+	%this.schedule(50, "onRemoveLayer2", %index);
+}
+
+function AssetImageLayersEditTool::onRemoveLayer2(%this, %index)
+{
+	%this.asset.removeLayer(%index);
+	%row = %this.rowChain.getObject(%index + 1);
+	%row.delete();
+
+	%count = %this.asset.getLayerCount();
+	for(%i = 0; %i < %this.rowChain.getCount(); %i++)
+	{
+		%row = %this.rowChain.getObject(%i);
+		if(%row.isMethod("refresh"))
+		{
+			%row.LayerIndex = (%i - 1);
+			%row.updateLayerCount(%count);
+			%row.refresh();
+		}
+	}
+}

+ 54 - 0
editor/AssetAdmin/ImageEditor/AssetImageLayersHeaderRow.cs

@@ -0,0 +1,54 @@
+
+function AssetImageLayersHeaderRow::onAdd(%this)
+{
+	%this.imageBox = new GuiControl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="20 0";
+		Extent="200 25";
+		Text = "Layer Image";
+		vAlign = "Bottom";
+	};
+	ThemeManager.setProfile(%this.imageBox, "LabelProfile");
+	%this.add(%this.imageBox);
+
+	%this.offsetXBox = new GuiControl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="224 0";
+		Extent="80 25";
+		Text = "X";
+		Align = "Center";
+		vAlign = "Bottom";
+	};
+	ThemeManager.setProfile(%this.offsetXBox, "LabelProfile");
+	%this.add(%this.offsetXBox);
+
+	%this.offsetYBox = new GuiControl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="308 0";
+		Extent="80 25";
+		Text = "Y";
+		Align = "Center";
+		vAlign = "Bottom";
+	};
+	ThemeManager.setProfile(%this.offsetYBox, "LabelProfile");
+	%this.add(%this.offsetYBox);
+
+	%this.colorBox = new GuiControl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="392 0";
+		Extent="164 25";
+		Text = "Color";
+		Align = "Center";
+		vAlign = "Bottom";
+	};
+	ThemeManager.setProfile(%this.colorBox, "LabelProfile");
+	%this.add(%this.colorBox);
+}

+ 4 - 0
editor/AssetAdmin/ImageEditor/exec.cs

@@ -1,3 +1,7 @@
 exec("./AssetImageFrameEditTool.cs");
 exec("./AssetImageFrameEditRow.cs");
 exec("./AssetImageFrameHeaderRow.cs");
+
+exec("./AssetImageLayersEditTool.cs");
+exec("./AssetImageLayersEditRow.cs");
+exec("./AssetImageLayersHeaderRow.cs");

+ 3 - 5
engine/source/2d/assets/ImageAsset.cc

@@ -1427,6 +1427,7 @@ void ImageAsset::redrawImage()
             {
                 // We still can't come up with a bitmap, so warn and return
                 Con::warnf("ImageAsset::redrawImage() - Unable to load bitmap for image '%s'.", mImageFile);
+                return;
             }
         }
         map->clearImage();
@@ -1591,7 +1592,7 @@ void ImageAsset::setLayerImage(const U32 index, const char* imagePath, const boo
     if (getOwned())
     {
         const char* path = expandAssetFilePath(imagePath);
-        mImageLayers[index].mImageFile = StringTable->insert(path);
+        mImageLayers[index].mImageFile = StringTable->insert(imagePath);
         mImageLayers[index].LoadImage(path);
     }
     else
@@ -1666,10 +1667,7 @@ void ImageAsset::setBlendColor(const ColorF color, const bool doRedraw)
     
     mImageLayers[0].mBlendColor.set(color.red, color.green, color.blue, color.alpha);
 
-    if (doRedraw)
-    {
-        redrawImage();
-    }
+    completeLayerChange(doRedraw);
 }
 
 const ColorF ImageAsset::getBlendColor()

+ 1 - 0
engine/source/2d/assets/ImageAsset.h

@@ -219,6 +219,7 @@ public:
 
     void                    setImageFile( const char* pImageFile );
     inline StringTableEntry getImageFile( void ) const                      { return mImageFile; };
+    inline StringTableEntry getRelativeImageFile(void) const { return collapseAssetFilePath(mImageFile); };
 
     void                    setForce16Bit( const bool force16Bit );
     inline bool             getForce16Bit( void ) const                     { return mForce16Bit; }

+ 11 - 1
engine/source/2d/assets/ImageAsset_ScriptBinding.h

@@ -33,13 +33,23 @@ ConsoleMethodWithDocs(ImageAsset, setImageFile, ConsoleVoid, 3, 3, (ImageFile))
 //-----------------------------------------------------------------------------
 
 /*! Gets the image file.
-    @return Returns the bitmap image file.
+    @return Returns the bitmap image file, typically as an absolute path.
 */
 ConsoleMethodWithDocs(ImageAsset, getImageFile, ConsoleString, 2, 2, ())
 {
     return object->getImageFile();
 }
 
+//-----------------------------------------------------------------------------
+
+/*! Gets the image file.
+    @return Returns the bitmap image file as a path relative to the asset file.
+*/
+ConsoleMethodWithDocs(ImageAsset, getRelativeImageFile, ConsoleString, 2, 2, ())
+{
+    return object->getRelativeImageFile();
+}
+
 //------------------------------------------------------------------------------
 
 /*! Sets the filter mode.

+ 7 - 0
test/BlankGame/particles/baseRed_PT.particle.taml

@@ -0,0 +1,7 @@
+<ParticleAsset
+    AssetName="baseRed_PT">
+    <ParticleAssetEmitter
+        EmitterName="DefaultEmitter"
+        Image="@asset=BlankGame:baseRed"
+        Frame="0" />
+</ParticleAsset>

BIN
test/BlankGame/sprites/folder/baseRed.png


BIN
test/BlankGame/sprites/folder/test.png


BIN
test/BlankGame/sprites/folder/test2.png