Prechádzať zdrojové kódy

Merge pull request #65 from TorqueGameEngines/development

T2D 4.0.0 Early Access 2.1
Peter Robinson 2 rokov pred
rodič
commit
2c555d6dd0
93 zmenil súbory, kde vykonal 2500 pridanie a 253 odobranie
  1. 2 2
      .github/workflows/PR-builds.yml
  2. 8 1
      editor/AssetAdmin/AssetInspector.cs
  3. 254 0
      editor/AssetAdmin/ImageEditor/AssetImageLayersEditRow.cs
  4. 203 0
      editor/AssetAdmin/ImageEditor/AssetImageLayersEditTool.cs
  5. 54 0
      editor/AssetAdmin/ImageEditor/AssetImageLayersHeaderRow.cs
  6. 4 0
      editor/AssetAdmin/ImageEditor/exec.cs
  7. 1 1
      editor/EditorCore/gui/guiProfiles.cs
  8. 2 1
      engine/compilers/Make-32bit/Torque2D.mk
  9. 3 2
      engine/compilers/Make-64bit/Torque2D.mk
  10. 0 51
      engine/compilers/VisualStudio 2017/GuiBlank.gui
  11. 5 0
      engine/compilers/VisualStudio 2019/Torque 2D.vcxproj
  12. 15 0
      engine/compilers/VisualStudio 2019/Torque 2D.vcxproj.filters
  13. BIN
      engine/compilers/VisualStudio 2022/Torque 2D.aps
  14. 0 0
      engine/compilers/VisualStudio 2022/Torque 2D.ico
  15. 0 0
      engine/compilers/VisualStudio 2022/Torque 2D.rc
  16. 2 2
      engine/compilers/VisualStudio 2022/Torque 2D.sln
  17. 22 13
      engine/compilers/VisualStudio 2022/Torque 2D.vcxproj
  18. 16 1
      engine/compilers/VisualStudio 2022/Torque 2D.vcxproj.filters
  19. 9 13
      engine/compilers/VisualStudio 2022/libogg.vcxproj
  20. 7 7
      engine/compilers/VisualStudio 2022/libvorbis.vcxproj
  21. 7 7
      engine/compilers/VisualStudio 2022/ljpeg.vcxproj
  22. 0 0
      engine/compilers/VisualStudio 2022/ljpeg.vcxproj.filters
  23. 7 7
      engine/compilers/VisualStudio 2022/lpng.vcxproj
  24. 0 0
      engine/compilers/VisualStudio 2022/lpng.vcxproj.filters
  25. 0 0
      engine/compilers/VisualStudio 2022/main.cs
  26. 0 0
      engine/compilers/VisualStudio 2022/resource.h
  27. 7 7
      engine/compilers/VisualStudio 2022/zlib.vcxproj
  28. 0 0
      engine/compilers/VisualStudio 2022/zlib.vcxproj.filters
  29. 452 10
      engine/source/2d/assets/ImageAsset.cc
  30. 68 0
      engine/source/2d/assets/ImageAsset.h
  31. 434 1
      engine/source/2d/assets/ImageAsset_ScriptBinding.h
  32. 1 1
      engine/source/2d/assets/ParticleAssetFieldCollection.h
  33. 1 1
      engine/source/2d/core/BatchRender.h
  34. 1 3
      engine/source/2d/editorToy/EditorToySceneWindow.cc
  35. 38 26
      engine/source/2d/gui/guiSpriteCtrl.cc
  36. 3 0
      engine/source/2d/gui/guiSpriteCtrl.h
  37. 23 0
      engine/source/2d/gui/guiSpriteCtrl_ScriptBindings.h
  38. 2 2
      engine/source/2d/scene/Scene.cc
  39. 1 1
      engine/source/2d/scene/Scene.h
  40. 4 1
      engine/source/2d/sceneobject/Path.h
  41. 1 1
      engine/source/2d/sceneobject/SceneObject.cc
  42. 1 1
      engine/source/2d/sceneobject/Trigger.h
  43. 116 0
      engine/source/algorithm/pcg_basic.c
  44. 78 0
      engine/source/algorithm/pcg_basic.h
  45. 1 1
      engine/source/assets/assetTagsManifest.h
  46. 3 3
      engine/source/collection/hashTable.h
  47. 1 1
      engine/source/collection/nameTags.h
  48. 1 1
      engine/source/component/behaviors/behaviorInstance.h
  49. 1 1
      engine/source/console/console.cc
  50. 1 1
      engine/source/console/consoleDictionary.h
  51. 0 3
      engine/source/game/defaultGame.cc
  52. 2 2
      engine/source/game/version.h
  53. 1 1
      engine/source/graphics/PNGImage.h
  54. 59 0
      engine/source/graphics/gBitmap.cc
  55. 3 0
      engine/source/graphics/gBitmap.h
  56. 1 1
      engine/source/graphics/gColor.cc
  57. 4 7
      engine/source/gui/buttons/guiDropDownCtrl.cc
  58. 9 0
      engine/source/gui/containers/guiChainCtrl.cc
  59. 23 2
      engine/source/gui/containers/guiExpandCtrl.cc
  60. 1 0
      engine/source/gui/containers/guiExpandCtrl.h
  61. 9 0
      engine/source/gui/containers/guiGridCtrl.cc
  62. 21 2
      engine/source/gui/containers/guiScrollCtrl.cc
  63. 5 0
      engine/source/gui/containers/guiWindowCtrl.cc
  64. 49 34
      engine/source/gui/guiControl.cc
  65. 6 0
      engine/source/gui/guiControl.h
  66. 1 1
      engine/source/gui/guiTypes.h
  67. 23 0
      engine/source/math/mRandom.cc
  68. 32 0
      engine/source/math/mRandom.h
  69. 1 1
      engine/source/math/noise/NoiseGenerator_ScriptBinding.h
  70. 72 0
      engine/source/math/noise/RandomNumberGenerator.cc
  71. 65 0
      engine/source/math/noise/RandomNumberGenerator.h
  72. 60 0
      engine/source/math/noise/RandomNumberGenerator_ScriptBinding.h
  73. 1 1
      engine/source/module/moduleManager.cc
  74. 1 1
      engine/source/module/moduleManager.h
  75. 2 2
      engine/source/persistence/taml/binary/tamlBinaryReader.h
  76. 2 2
      engine/source/persistence/taml/json/tamlJSONReader.h
  77. 1 1
      engine/source/persistence/taml/taml.h
  78. 2 2
      engine/source/persistence/taml/xml/tamlXmlReader.h
  79. 1 1
      engine/source/platform/platformFileIO.cc
  80. 2 2
      engine/source/platform/platformString_ScriptBinding.h
  81. 1 1
      engine/source/platformWin32/winConsole_ScriptBinding.h
  82. 2 2
      engine/source/platformWin32/winDInputDevice.cc
  83. 6 5
      engine/source/platformWin32/winFileio.cc
  84. 4 4
      engine/source/platformWin32/winGLSpecial.cc
  85. 0 2
      engine/source/platformWin32/winGLSpecial_ScriptBinding.h
  86. 3 1
      library/AppCore/appCore.cs
  87. 1 1
      library/AppCore/gui/guiProfiles.cs
  88. 0 0
      library/BlankGame/gui/images/torqueBG.image.taml
  89. 3 0
      library/ScreenFade/gui/background.image.taml
  90. BIN
      library/ScreenFade/gui/background.png
  91. 15 0
      library/ScreenFade/module.taml
  92. 71 0
      library/ScreenFade/screenFade.cs
  93. 75 0
      library/ScreenFade/scripts/ScreenFadeBackground.cs

+ 2 - 2
.github/workflows/PR-builds.yml

@@ -3,7 +3,7 @@ on: [push, pull_request, workflow_dispatch]
 jobs:
   Build-Windows-32bit-VS2019:
     name: 32-bit Windows On VS2019
-    runs-on: windows-latest
+    runs-on: windows-2019
     steps:
       - uses: actions/checkout@v2
       - uses: microsoft/[email protected]
@@ -20,7 +20,7 @@ jobs:
             ! engine/
   Build-Windows-64bit-VS2019:
     name: 64-bit Windows On VS2019
-    runs-on: windows-latest
+    runs-on: windows-2019
     steps:
       - uses: actions/checkout@v2
       - uses: microsoft/[email protected]

+ 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");

+ 1 - 1
editor/EditorCore/gui/guiProfiles.cs

@@ -81,7 +81,7 @@ function EditorCore::SafeCreateNamedObject(%this, %name, %object)
 	if(isObject(%name))
 	{
 		%originalObject = nameToID(%name);
-		if(%orginalObject.getClassName() !$= %object.getClassName())
+		if(%originalObject.getClassName() !$= %object.getClassName())
 		{
 			warn("Attempted to change the class of the named object " @ %name @ "!");
 			warn("Original Class: " @ %originalObject.getClassName());

+ 2 - 1
engine/compilers/Make-32bit/Torque2D.mk

@@ -2,7 +2,8 @@ APPNAME := ../../../Torque2D
 
 2D_SOURCES :=            $(shell find ../../source/2d/ -name "*.cc") + \
 						 $(shell find ../../source/2d/ -name "*.cpp")
-ALGORITHM_SOURCES :=     $(shell find ../../source/algorithm/ -name "*.cc")
+ALGORITHM_SOURCES :=     $(shell find ../../source/algorithm/ -name "*.cc") + \
+                         $(shell find ../../source/algorithm/ -name "*.c")
 ASSETS_SOURCES :=        $(shell find ../../source/assets/ -name "*.cc")
 AUDIO_SOURCES :=         $(shell find ../../source/audio/ -name "*.cc")
 BITMAPFONT_SOURCES :=    $(shell find ../../source/bitmapFont/ -name "*.cc")

+ 3 - 2
engine/compilers/Make-64bit/Torque2D.mk

@@ -2,7 +2,8 @@ APPNAME := ../../../Torque2D
 
 2D_SOURCES :=            $(shell find ../../source/2d/ -name "*.cc") + \
 						 $(shell find ../../source/2d/ -name "*.cpp")
-ALGORITHM_SOURCES :=     $(shell find ../../source/algorithm/ -name "*.cc")
+ALGORITHM_SOURCES :=     $(shell find ../../source/algorithm/ -name "*.cc") + \
+                         $(shell find ../../source/algorithm/ -name "*.c")
 ASSETS_SOURCES :=        $(shell find ../../source/assets/ -name "*.cc")
 AUDIO_SOURCES :=         $(shell find ../../source/audio/ -name "*.cc")
 BITMAPFONT_SOURCES :=    $(shell find ../../source/bitmapFont/ -name "*.cc")
@@ -63,7 +64,7 @@ SOURCES := $(2D_SOURCES) + \
 LDFLAGS := -g -m64
 LDLIBS := -lstdc++ -lm -ldl -lpthread -lrt -lX11 -lXft -lSDL -lopenal
 
-CFLAGS := -std=c++14 -MMD -I. -Wfatal-errors -Wunused -m64 -msse -march=x86-64 -pipe
+CFLAGS := -std=c++17 -MMD -I. -Wfatal-errors -Wunused -m64 -msse -march=x86-64 -pipe
 
 CFLAGS += -I/usr/include
 CFLAGS += -I/usr/include/freetype2

+ 0 - 51
engine/compilers/VisualStudio 2017/GuiBlank.gui

@@ -1,51 +0,0 @@
-//--- Created With GUIEDITORTOY ---//
-%guiContent = new GuiControl(GuiBlank) {
-   Name = "GuiBlank";
-   canSaveDynamicFields = "0";
-   hidden = "0";
-   locked = "0";
-   isContainer = "1";
-   Profile = "GuiDefaultProfile";
-   HorizSizing = "width";
-   VertSizing = "height";
-   Position = "0 0";
-   Extent = "1920 1017";
-   MinExtent = "8 2";
-   canSave = "1";
-   Visible = "1";
-   Active = "0";
-   tooltipWidth = "250";
-   hovertime = "1000";
-
-   new GuiWindowCtrl() {
-      canSaveDynamicFields = "0";
-      hidden = "0";
-      locked = "0";
-      isContainer = "1";
-      Profile = "GuiWindowProfile";
-      HorizSizing = "right";
-      VertSizing = "bottom";
-      Position = "256 456";
-      Extent = "300 240";
-      MinExtent = "8 2";
-      canSave = "1";
-      Visible = "1";
-      Active = "1";
-      tooltipWidth = "250";
-      hovertime = "1000";
-      resizeWidth = "1";
-      resizeHeight = "1";
-      canMove = "1";
-      canClose = "1";
-      canMinimize = "1";
-      canMaximize = "1";
-      titleHeight = "20";
-      resizeRightWidth = "10";
-      resizeBottomHeight = "10";
-      contentProfile = "GuiWindowContentProfile";
-      closeButtonProfile = "GuiWindowCloseButtonProfile";
-      minButtonProfile = "GuiWindowMinButtonProfile";
-      maxButtonProfile = "GuiWindowMaxButtonProfile";
-   };
-};
-//--- GUIEDITORTOY END ---//

+ 5 - 0
engine/compilers/VisualStudio 2019/Torque 2D.vcxproj

@@ -516,6 +516,7 @@
     <ClCompile Include="..\..\source\2d\scene\WorldQuery.cc" />
     <ClCompile Include="..\..\source\algorithm\crc.cc" />
     <ClCompile Include="..\..\source\algorithm\hashFunction.cc" />
+    <ClCompile Include="..\..\source\algorithm\pcg_basic.c" />
     <ClCompile Include="..\..\source\algorithm\Perlin.cc" />
     <ClCompile Include="..\..\source\assets\assetBase.cc" />
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
@@ -677,6 +678,7 @@
     <ClCompile Include="..\..\source\math\mFluid.cpp" />
     <ClCompile Include="..\..\source\math\mPoint.cpp" />
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc" />
+    <ClCompile Include="..\..\source\math\noise\RandomNumberGenerator.cc" />
     <ClCompile Include="..\..\source\math\rectClipper.cpp" />
     <ClCompile Include="..\..\source\memory\dataChunker.cc" />
     <ClCompile Include="..\..\source\memory\frameAllocator_ScriptBinding.cc" />
@@ -940,6 +942,7 @@
     <ClInclude Include="..\..\source\algorithm\crctab.h" />
     <ClInclude Include="..\..\source\algorithm\hashFunction.h" />
     <ClInclude Include="..\..\source\algorithm\md5.h" />
+    <ClInclude Include="..\..\source\algorithm\pcg_basic.h" />
     <ClInclude Include="..\..\source\algorithm\Perlin.h" />
     <ClInclude Include="..\..\source\assets\assetBase.h" />
     <ClInclude Include="..\..\source\assets\assetBase_ScriptBinding.h" />
@@ -1182,6 +1185,8 @@
     <ClInclude Include="..\..\source\math\mNormalDistribution.h" />
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator.h" />
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\math\noise\RandomNumberGenerator.h" />
+    <ClInclude Include="..\..\source\math\noise\RandomNumberGenerator_ScriptBinding.h" />
     <ClInclude Include="..\..\source\math\random_ScriptBinding.h" />
     <ClInclude Include="..\..\source\math\rectClipper.h" />
     <ClInclude Include="..\..\source\math\vector_ScriptBinding.h" />

+ 15 - 0
engine/compilers/VisualStudio 2019/Torque 2D.vcxproj.filters

@@ -1336,6 +1336,12 @@
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc">
       <Filter>math\noise</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\source\algorithm\pcg_basic.c">
+      <Filter>algorithm</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\math\noise\RandomNumberGenerator.cc">
+      <Filter>math\noise</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -3058,6 +3064,15 @@
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator_ScriptBinding.h">
       <Filter>math\noise</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\source\algorithm\pcg_basic.h">
+      <Filter>algorithm</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\math\noise\RandomNumberGenerator.h">
+      <Filter>math\noise</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\math\noise\RandomNumberGenerator_ScriptBinding.h">
+      <Filter>math\noise</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Torque 2D.rc" />

BIN
engine/compilers/VisualStudio 2017/Torque 2D.aps → engine/compilers/VisualStudio 2022/Torque 2D.aps


+ 0 - 0
engine/compilers/VisualStudio 2017/Torque 2D.ico → engine/compilers/VisualStudio 2022/Torque 2D.ico


+ 0 - 0
engine/compilers/VisualStudio 2017/Torque 2D.rc → engine/compilers/VisualStudio 2022/Torque 2D.rc


+ 2 - 2
engine/compilers/VisualStudio 2017/Torque 2D.sln → engine/compilers/VisualStudio 2022/Torque 2D.sln

@@ -1,6 +1,6 @@
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.28307.1300
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31729.503
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Torque2D", "Torque 2D.vcxproj", "{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}"
 	ProjectSection(ProjectDependencies) = postProject

+ 22 - 13
engine/compilers/VisualStudio 2017/Torque 2D.vcxproj → engine/compilers/VisualStudio 2022/Torque 2D.vcxproj

@@ -30,38 +30,38 @@
     <ProjectGuid>{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}</ProjectGuid>
     <RootNamespace>TorqueGame</RootNamespace>
     <ProjectName>Torque2D</ProjectName>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
@@ -117,6 +117,10 @@
     <OutDir>../../../</OutDir>
     <IntDir>../../Link/VC2012.$(Configuration).$(PlatformName)/$(ProjectName)/</IntDir>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>../../../</OutDir>
+    <IntDir>../../Link/VC2012.$(Configuration).$(PlatformName)/$(ProjectName)/</IntDir>
+  </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <Midl>
       <TypeLibraryName>$(OutDir)Torque2D.tlb</TypeLibraryName>
@@ -143,7 +147,7 @@
       <WarningLevel>Level3</WarningLevel>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
       <ShowIncludes>false</ShowIncludes>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -193,7 +197,7 @@
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
       <ShowIncludes>false</ShowIncludes>
       <FunctionLevelLinking>true</FunctionLevelLinking>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -243,7 +247,7 @@
       <CompileAs>CompileAsCpp</CompileAs>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -304,7 +308,7 @@
       <CompileAs>CompileAsCpp</CompileAs>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -364,7 +368,7 @@
       <CompileAs>CompileAsCpp</CompileAs>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -425,7 +429,7 @@
       <CompileAs>CompileAsCpp</CompileAs>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -512,6 +516,7 @@
     <ClCompile Include="..\..\source\2d\scene\WorldQuery.cc" />
     <ClCompile Include="..\..\source\algorithm\crc.cc" />
     <ClCompile Include="..\..\source\algorithm\hashFunction.cc" />
+    <ClCompile Include="..\..\source\algorithm\pcg_basic.c" />
     <ClCompile Include="..\..\source\algorithm\Perlin.cc" />
     <ClCompile Include="..\..\source\assets\assetBase.cc" />
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
@@ -673,6 +678,7 @@
     <ClCompile Include="..\..\source\math\mFluid.cpp" />
     <ClCompile Include="..\..\source\math\mPoint.cpp" />
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc" />
+    <ClCompile Include="..\..\source\math\noise\RandomNumberGenerator.cc" />
     <ClCompile Include="..\..\source\math\rectClipper.cpp" />
     <ClCompile Include="..\..\source\memory\dataChunker.cc" />
     <ClCompile Include="..\..\source\memory\frameAllocator_ScriptBinding.cc" />
@@ -936,6 +942,7 @@
     <ClInclude Include="..\..\source\algorithm\crctab.h" />
     <ClInclude Include="..\..\source\algorithm\hashFunction.h" />
     <ClInclude Include="..\..\source\algorithm\md5.h" />
+    <ClInclude Include="..\..\source\algorithm\pcg_basic.h" />
     <ClInclude Include="..\..\source\algorithm\Perlin.h" />
     <ClInclude Include="..\..\source\assets\assetBase.h" />
     <ClInclude Include="..\..\source\assets\assetBase_ScriptBinding.h" />
@@ -1178,6 +1185,8 @@
     <ClInclude Include="..\..\source\math\mNormalDistribution.h" />
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator.h" />
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\math\noise\RandomNumberGenerator.h" />
+    <ClInclude Include="..\..\source\math\noise\RandomNumberGenerator_ScriptBinding.h" />
     <ClInclude Include="..\..\source\math\random_ScriptBinding.h" />
     <ClInclude Include="..\..\source\math\rectClipper.h" />
     <ClInclude Include="..\..\source\math\vector_ScriptBinding.h" />

+ 16 - 1
engine/compilers/VisualStudio 2017/Torque 2D.vcxproj.filters → engine/compilers/VisualStudio 2022/Torque 2D.vcxproj.filters

@@ -203,7 +203,7 @@
       <UniqueIdentifier>{598766e4-7dc1-45b8-8acf-f133f4fced82}</UniqueIdentifier>
     </Filter>
     <Filter Include="math\noise">
-      <UniqueIdentifier>{1ca99a8e-9e94-4ab8-996e-b4835a603512}</UniqueIdentifier>
+      <UniqueIdentifier>{1a2a7ebc-eda6-4a67-b9ab-bc9f437b5d5c}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
   <ItemGroup>
@@ -1336,6 +1336,12 @@
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc">
       <Filter>math\noise</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\source\algorithm\pcg_basic.c">
+      <Filter>algorithm</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\math\noise\RandomNumberGenerator.cc">
+      <Filter>math\noise</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -3058,6 +3064,15 @@
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator_ScriptBinding.h">
       <Filter>math\noise</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\source\algorithm\pcg_basic.h">
+      <Filter>algorithm</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\math\noise\RandomNumberGenerator.h">
+      <Filter>math\noise</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\math\noise\RandomNumberGenerator_ScriptBinding.h">
+      <Filter>math\noise</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Torque 2D.rc" />

+ 9 - 13
engine/compilers/VisualStudio 2017/libogg.vcxproj → engine/compilers/VisualStudio 2022/libogg.vcxproj

@@ -30,30 +30,30 @@
     <ProjectGuid>{15CBFEFF-7965-41F5-B4E2-21E8795C9159}</ProjectGuid>
     <RootNamespace>libogg</RootNamespace>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <WholeProgramOptimization>false</WholeProgramOptimization>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
-    <WholeProgramOptimization>false</WholeProgramOptimization>
-    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
@@ -79,8 +79,8 @@
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\../../Link/Debug/libogg\</IntDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\../../Link/Release\</OutDir>
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\../../Link/Release/libogg\</IntDir>
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\../../Link/Release\</OutDir>
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\../../Link/Release/libogg\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <TargetName>$(ProjectName)_DEBUG</TargetName>
@@ -171,16 +171,12 @@
       <BufferSecurityCheck>false</BufferSecurityCheck>
       <PrecompiledHeader>
       </PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
+      <WarningLevel>Level4</WarningLevel>
       <DebugInformationFormat>
       </DebugInformationFormat>
       <CompileAs>CompileAsC</CompileAs>
       <DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <CallingConvention>Cdecl</CallingConvention>
-      <AssemblerListingLocation>.\../../Link/Release/libogg/</AssemblerListingLocation>
-      <ObjectFileName>.\../../Link/Release/libogg/</ObjectFileName>
-      <ProgramDataBaseFileName>.\../../Link/Release/libogg/</ProgramDataBaseFileName>
-      <OmitFramePointers>false</OmitFramePointers>
     </ClCompile>
   </ItemDefinitionGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 7 - 7
engine/compilers/VisualStudio 2017/libvorbis.vcxproj → engine/compilers/VisualStudio 2022/libvorbis.vcxproj

@@ -22,30 +22,30 @@
     <ProjectGuid>{3A214E06-B95E-4D61-A291-1F8DF2EC10FD}</ProjectGuid>
     <RootNamespace>libvorbis</RootNamespace>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <WholeProgramOptimization>false</WholeProgramOptimization>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
@@ -75,8 +75,8 @@
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\../../Link/Debug/libvorbis\</IntDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\../../Link/Release\</OutDir>
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\../../Link/Release/libvorbis\</IntDir>
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\../../Link/Release/</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\../../Link/Release/libvorbis</IntDir>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <TargetName>$(ProjectName)_DEBUG</TargetName>

+ 7 - 7
engine/compilers/VisualStudio 2017/ljpeg.vcxproj → engine/compilers/VisualStudio 2022/ljpeg.vcxproj

@@ -28,38 +28,38 @@
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{0B07BA94-AA53-4FD4-ADB4-79EC2DA53B36}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">

+ 0 - 0
engine/compilers/VisualStudio 2017/ljpeg.vcxproj.filters → engine/compilers/VisualStudio 2022/ljpeg.vcxproj.filters


+ 7 - 7
engine/compilers/VisualStudio 2017/lpng.vcxproj → engine/compilers/VisualStudio 2022/lpng.vcxproj

@@ -28,38 +28,38 @@
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{AF1179E3-A838-46A3-A427-1E62AA4C52F4}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">

+ 0 - 0
engine/compilers/VisualStudio 2017/lpng.vcxproj.filters → engine/compilers/VisualStudio 2022/lpng.vcxproj.filters


+ 0 - 0
engine/compilers/VisualStudio 2017/main.cs → engine/compilers/VisualStudio 2022/main.cs


+ 0 - 0
engine/compilers/VisualStudio 2017/resource.h → engine/compilers/VisualStudio 2022/resource.h


+ 7 - 7
engine/compilers/VisualStudio 2017/zlib.vcxproj → engine/compilers/VisualStudio 2022/zlib.vcxproj

@@ -58,38 +58,38 @@
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{86CB2525-0CF3-40D3-BF42-A0A95035EE8C}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">

+ 0 - 0
engine/compilers/VisualStudio 2017/zlib.vcxproj.filters → engine/compilers/VisualStudio 2022/zlib.vcxproj.filters


+ 452 - 10
engine/source/2d/assets/ImageAsset.cc

@@ -117,6 +117,12 @@ static StringTableEntry cellWidthName               = StringTable->insert( "Widt
 static StringTableEntry cellHeightName              = StringTable->insert( "Height" );
 static StringTableEntry cellNameEntryName           = StringTable->insert( "Name" );
 
+static StringTableEntry imageLayerCustomNodeName    = StringTable->insert("ImageLayers");
+static StringTableEntry layerNodeName               = StringTable->insert("ImageLayer");
+static StringTableEntry layerImageFile              = StringTable->insert("ImageFile");
+static StringTableEntry layerPositionName           = StringTable->insert("Position");
+static StringTableEntry layerBlendColorName         = StringTable->insert("BlendColor");
+
 //------------------------------------------------------------------------------
 
 static EnumTable::Enums textureFilterLookup[] =
@@ -174,11 +180,14 @@ ImageAsset::ImageAsset() :  mImageFile(StringTable->EmptyString),
                             mCellWidth(0),
                             mCellHeight(0),
 
+                            mBlendColor(1.0f, 1.0f, 1.0f),
+
                             mImageTextureHandle(NULL)
 {
     // Set Vector Associations.
     VECTOR_SET_ASSOCIATION( mFrames );
     VECTOR_SET_ASSOCIATION( mExplicitFrames );
+    VECTOR_SET_ASSOCIATION(mImageLayers);
 }
 
 //------------------------------------------------------------------------------
@@ -201,6 +210,7 @@ void ImageAsset::initPersistFields()
     addProtectedField("FilterMode", TypeEnum, Offset(mLocalFilterMode, ImageAsset), &setFilterMode, &defaultProtectedGetFn, &writeFilterMode, 1, &textureFilterTable);   
     addProtectedField("ExplicitMode", TypeBool, Offset(mExplicitMode, ImageAsset), &setExplicitMode, &defaultProtectedGetFn, &writeExplicitMode, "");
     addProtectedField("CellRowOrder", TypeBool, Offset(mCellRowOrder, ImageAsset), &setCellRowOrder, &defaultProtectedGetFn, &writeCellRowOrder, "If true, cell number are applied left-to-right, top-to-bottom.");
+    addProtectedField("BlendColor", TypeColorF, Offset(mBlendColor, ImageAsset), &setBlendColor, &defaultProtectedGetFn, &writeBlendColor, "Changes the base color of the texture. You should only use this if you are using layers.");
     endGroup("Image Fields");
 
     addGroup("X Values");
@@ -1069,8 +1079,18 @@ void ImageAsset::initializeAsset( void )
     // Ensure the image-file is expanded.
     mImageFile = expandAssetFilePath( mImageFile );
 
+    // Time to load the layer files too.
+    for (auto& layer : mImageLayers)
+    {
+        const char* path = expandAssetFilePath(layer.mImageFile);
+        layer.LoadImage(path);
+    }
+
     // Calculate the image.
     calculateImage();
+
+    // Redraw the image.
+    redrawImage();
 }
 
 //------------------------------------------------------------------------------
@@ -1086,6 +1106,9 @@ void ImageAsset::onAssetRefresh( void )
     
     // Compile image.
     calculateImage();
+
+    // Redraw the image.
+    redrawImage();
 }
 
 //-----------------------------------------------------------------------------
@@ -1126,7 +1149,7 @@ void ImageAsset::calculateImage( void )
         TextureManager::refresh( mImageFile );
 
     // Get image texture.
-    mImageTextureHandle.set( mImageFile, TextureHandle::BitmapTexture, true, getForce16Bit() );
+    mImageTextureHandle.set( mImageFile, mImageLayers.size() > 0 ? TextureHandle::BitmapKeepTexture : TextureHandle::BitmapTexture, true, getForce16Bit() );
 
     // Is the texture valid?
     if ( mImageTextureHandle.IsNull() )
@@ -1377,6 +1400,47 @@ void ImageAsset::calculateExplicitMode( void )
     }
 }
 
+void ImageAsset::completeLayerChange(const bool doRedraw)
+{
+    if (doRedraw)
+    {
+        redrawImage();
+
+        if (getOwned())
+        {
+            refreshAsset();
+        }
+    }
+}
+
+void ImageAsset::redrawImage()
+{
+    if (mImageLayers.size() > 0)
+    {
+        GBitmap* map = mImageTextureHandle.getBitmap();
+        if (map == nullptr)
+        {
+            // This should reload the texture and keep it in memory
+            mImageTextureHandle.set(mImageFile, TextureHandle::BitmapKeepTexture, true, getForce16Bit());
+            map = mImageTextureHandle.getBitmap();
+            if (map == nullptr)
+            {
+                // 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;
+            }
+            mImageLayers[0].LoadImage(mImageLayers[0].mImageFile);
+        }
+        map->clearImage(mBlendColor);
+        for (auto &layer : mImageLayers)
+        {
+            map->mergeLayer(layer.mPosition, layer.mBitmap, layer.mBlendColor);
+        }
+
+        mImageTextureHandle.refresh();
+    }
+}
+
 //------------------------------------------------------------------------------
 
 bool ImageAsset::setFilterMode( void* obj, const char* data )
@@ -1385,6 +1449,233 @@ bool ImageAsset::setFilterMode( void* obj, const char* data )
     return false;
 }
 
+void ImageAsset::addLayer(const char* imagePath, const Point2I position, const ColorF blendColor, const bool doRedraw)
+{
+    insertLayer(mImageLayers.size(), imagePath, position, blendColor, doRedraw);
+}
+
+void ImageAsset::insertLayer(const U32 index, const char* imagePath, const Point2I position, const ColorF blendColor, const bool doRedraw)
+{
+    if (mImageLayers.size() == 0)
+    {
+        Point2I p(0, 0);
+        ImageLayer baseLayer(mImageFile, p, mBlendColor);
+        mImageLayers.push_back(baseLayer);
+
+        if (getOwned())
+        {
+            baseLayer.LoadImage(mImageFile);
+        }
+    }
+    ImageLayer layer(imagePath, position, blendColor);
+
+    if (getOwned())
+    {
+        const char* path = expandAssetFilePath(layer.mImageFile);
+        layer.LoadImage(path);
+    }
+
+    if (index == 0 || index >= mImageLayers.size())
+    {
+        mImageLayers.push_back(layer);
+    }
+    else
+    {
+        typeImageLayerVector::iterator iter = mImageLayers.begin() + index;
+        mImageLayers.insert(iter, layer);
+    }
+
+    completeLayerChange(doRedraw);
+}
+
+void ImageAsset::removeLayer(const U32 index, const bool doRedraw)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::removeLayer() - Invalid Index of %d.", index);
+        return;
+    }
+
+    mImageLayers.erase(index);
+
+    if (mImageLayers.size() == 1)
+    {
+        mImageLayers.clear();
+    }
+
+    completeLayerChange(doRedraw);
+}
+
+void ImageAsset::moveLayerForward(const U32 index, const bool doRedraw)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::moveLayerForward() - Invalid Index of %d.", index);
+        return;
+    }
+
+    if (index == mImageLayers.size() - 1)
+    {
+        return;
+    }
+
+    ImageLayer layer = mImageLayers[index];
+    mImageLayers.erase(index);
+    mImageLayers.insert(mImageLayers.begin() + index + 1, layer);
+
+    completeLayerChange(doRedraw);
+}
+
+void ImageAsset::moveLayerBackward(const U32 index, const bool doRedraw)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::moveLayerBackward() - Invalid Index of %d.", index);
+        return;
+    }
+
+    if (index == 1)
+    {
+        return;
+    }
+
+    moveLayerForward(index - 1, doRedraw);
+}
+
+void ImageAsset::moveLayerToFront(const U32 index, const bool doRedraw)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::moveLayerToFront() - Invalid Index of %d.", index);
+        return;
+    }
+
+    if (index == mImageLayers.size() - 1)
+    {
+        return;
+    }
+
+    ImageLayer layer = mImageLayers[index];
+    mImageLayers.erase(index);
+    mImageLayers.push_back(layer);//The back of the array is the front of the image
+
+    completeLayerChange(doRedraw);
+}
+
+void ImageAsset::moveLayerToBack(const U32 index, const bool doRedraw)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::moveLayerToBack() - Invalid Index of %d.", index);
+        return;
+    }
+
+    if (index == 1)
+    {
+        return;
+    }
+
+    ImageLayer layer = mImageLayers[index];
+    mImageLayers.erase(index);
+    mImageLayers.insert(mImageLayers.begin() + 1, layer);//The front of the array is the back of the image
+
+    completeLayerChange(doRedraw);
+}
+
+void ImageAsset::setLayerImage(const U32 index, const char* imagePath, const bool doRedraw)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::setLayerImage() - Invalid Index of %d.", index);
+        return;
+    }
+
+    if (getOwned())
+    {
+        const char* path = expandAssetFilePath(imagePath);
+        mImageLayers[index].mImageFile = StringTable->insert(imagePath);
+        mImageLayers[index].LoadImage(path);
+    }
+    else
+    {
+        mImageLayers[index].mImageFile = StringTable->insert(imagePath);
+    }
+
+    completeLayerChange(doRedraw);
+}
+
+void ImageAsset::setLayerPosition(const U32 index, const Point2I position, const bool doRedraw)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::setLayerPosition() - Invalid Index of %d.", index);
+        return;
+    }
+    mImageLayers[index].mPosition.set(position.x, position.y);
+    completeLayerChange(doRedraw);
+}
+
+void ImageAsset::setLayerBlendColor(const U32 index, const ColorF blendColor, const bool doRedraw)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::setLayerBlendColor() - Invalid Index of %d.", index);
+        return;
+    }
+    mImageLayers[index].mBlendColor.set(blendColor.red, blendColor.green, blendColor.blue, blendColor.alpha);
+    completeLayerChange(doRedraw);
+}
+
+const char* ImageAsset::getLayerImage(const U32 index)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::getLayerImage() - Invalid Index of %d.", index);
+        return StringTable->EmptyString;
+    }
+    return mImageLayers[index].mImageFile;
+}
+
+const Point2I ImageAsset::getLayerPosition(const U32 index)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::getLayerPosition() - Invalid Index of %d.", index);
+        return Point2I();
+    }
+    return mImageLayers[index].mPosition;
+}
+
+const ColorF ImageAsset::getLayerBlendColor(const U32 index)
+{
+    if (index < 1 || index >= mImageLayers.size())
+    {
+        Con::warnf("ImageAsset::getLayerBlendColor() - Invalid Index of %d.", index);
+        return ColorF();
+    }
+    return mImageLayers[index].mBlendColor;
+}
+
+void ImageAsset::setBlendColor(const ColorF color, const bool doRedraw)
+{
+    mBlendColor.set(color.red, color.green, color.blue, color.alpha);
+
+    if (mImageLayers.size() == 0)
+    {
+        Con::warnf("ImageAsset::setBlendColor() - The ImageAsset blend color will not be applied if layers are not being used.");
+        return;
+    }
+    
+    mImageLayers[0].mBlendColor.set(color.red, color.green, color.blue, color.alpha);
+
+    completeLayerChange(doRedraw);
+}
+
+const ColorF ImageAsset::getBlendColor()
+{
+    return mBlendColor;
+}
+
 //------------------------------------------------------------------------------
 
 void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
@@ -1395,11 +1686,7 @@ void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
     // Call parent.
     Parent::onTamlCustomWrite( customNodes );
 
-    // Finish if not in explicit mode.
-    if ( !mExplicitMode )
-        return;
-
-    if (mExplicitFrames.size() > 0)
+    if (mExplicitMode && mExplicitFrames.size() > 0)
     {
         // Add cell custom node.
         TamlCustomNode* pCustomCellNodes = customNodes.addNode( cellCustomNodeCellsName );
@@ -1420,18 +1707,42 @@ void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
             pCellNode->addField( cellHeightName, pixelArea.mPixelHeight );
         }
     }
+
+    if (mImageLayers.size() > 0)
+    {
+        TamlCustomNode* pCustomLayerNodes = customNodes.addNode(imageLayerCustomNodeName);
+
+        for (typeImageLayerVector::iterator frameItr = mImageLayers.begin() + 1; frameItr != mImageLayers.end(); ++frameItr)
+        {
+            const ImageLayer& layer = *frameItr;
+            TamlCustomNode* pLayerNode = pCustomLayerNodes->addNode(layerNodeName);
+
+            pLayerNode->addField(layerImageFile, layer.mImageFile);
+            pLayerNode->addField(layerPositionName, layer.mPosition);
+            pLayerNode->addField(layerBlendColorName, layer.mBlendColor);
+        }
+    }
 }
 
 //-----------------------------------------------------------------------------
 
-void ImageAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
+void ImageAsset::onTamlCustomRead(const TamlCustomNodes& customNodes)
 {
     // Debug Profiling.
     PROFILE_SCOPE(ImageAsset_OnTamlCustomRead);
-    
+
     // Call parent.
-    Parent::onTamlCustomRead( customNodes );
-    
+    Parent::onTamlCustomRead(customNodes);
+
+    // Load the explicit cells
+    loadTamlExplicitCells(customNodes);
+
+    // Load image layers
+    loadTamlImageLayers(customNodes);
+}
+
+void ImageAsset::loadTamlExplicitCells(const TamlCustomNodes& customNodes)
+{
     // Find cell custom node.
     const TamlCustomNode* pCustomCellNodes = customNodes.findNode( cellCustomNodeCellsName );
     
@@ -1554,6 +1865,84 @@ void ImageAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
     }
 }
 
+void ImageAsset::loadTamlImageLayers(const TamlCustomNodes& customNodes)
+{
+    // Find layer custom node.
+    const TamlCustomNode* pCustomLayerNodes = customNodes.findNode(imageLayerCustomNodeName);
+
+    // Continue if we have explicit layers.
+    if (pCustomLayerNodes != NULL)
+    {
+        // Fetch children layer nodes.
+        const TamlCustomNodeVector& layerNodes = pCustomLayerNodes->getChildren();
+
+        // Iterate layers.
+        for (TamlCustomNodeVector::const_iterator layerNodeItr = layerNodes.begin(); layerNodeItr != layerNodes.end(); ++layerNodeItr)
+        {
+            // Fetch layer node.
+            TamlCustomNode* pLayerNode = *layerNodeItr;
+
+            // Fetch node name.
+            StringTableEntry nodeName = pLayerNode->getNodeName();
+
+            // Is this a valid alias?
+            if (nodeName != layerNodeName)
+            {
+                // No, so warn.
+                Con::warnf("ImageAsset::onTamlCustomRead() - Encountered an unknown custom name of '%s'.  Only '%s' is valid.", nodeName, layerNodeName);
+                continue;
+            }
+
+            Point2I layerPosition(0, 0);
+            const char* imagePath = StringTable->EmptyString;
+            ColorF blendColor = ColorF(1, 1, 1, 1);
+
+            // Fetch fields.
+            const TamlCustomFieldVector& fields = pLayerNode->getFields();
+
+            // Iterate property fields.
+            for (TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr)
+            {
+                // Fetch field.
+                const TamlCustomField* pField = *fieldItr;
+
+                // Fetch field name.
+                StringTableEntry fieldName = pField->getFieldName();
+
+                // Check common fields.
+                if (fieldName == layerImageFile)
+                {
+                    imagePath = pField->getFieldValue();
+                }
+                else if (fieldName == layerPositionName)
+                {
+                    pField->getFieldValue(layerPosition);
+                }
+                else if (fieldName == layerBlendColorName)
+                {
+                    pField->getFieldValue(blendColor);
+                }
+                else
+                {
+                    // Unknown name so warn.
+                    Con::warnf("ImageAsset::onTamlCustomRead() - Encountered an unknown custom field name of '%s'.", fieldName);
+                    continue;
+                }
+            }
+
+            // Is the image name valid?
+            if (imagePath == StringTable->EmptyString)
+            {
+                // No, so warn
+                Con::warnf("ImageAsset::onTamlCustomRead() - Image File of '%s' is invalid or was not set.", imagePath);
+            }
+
+            // Add image layer.
+            addLayer(imagePath, layerPosition, blendColor, false);
+        }
+    }
+}
+
 //-----------------------------------------------------------------------------
 
 static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
@@ -1564,6 +1953,8 @@ static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlEleme
 
     char buffer[1024];
 
+    //---Cells---
+
     // Create ImageAsset node element.
     TiXmlElement* pImageAssetNodeElement = new TiXmlElement( "xs:element" );
     dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), cellCustomNodeCellsName );
@@ -1616,6 +2007,57 @@ static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlEleme
     pImageAssetHeight->SetAttribute( "name", cellHeightName );
     pImageAssetHeight->SetAttribute( "type", "xs:unsignedInt" );
     pImageAssetComplexTypeElement->LinkEndChild( pImageAssetHeight );
+
+    //---Layers---
+
+    char buffer2[1024];
+
+    // Create ImageAsset node element.
+    TiXmlElement* pImageAssetNodeElementL = new TiXmlElement("xs:element");
+    dSprintf(buffer, sizeof(buffer2), "%s.%s", pClassRep->getClassName(), imageLayerCustomNodeName);
+    pImageAssetNodeElementL->SetAttribute("name", buffer2);
+    pImageAssetNodeElementL->SetAttribute("minOccurs", 0);
+    pImageAssetNodeElementL->SetAttribute("maxOccurs", 1);
+    pParentElement->LinkEndChild(pImageAssetNodeElementL);
+
+    // Create complex type.
+    TiXmlElement* pImageAssetNodeComplexTypeElementL = new TiXmlElement("xs:complexType");
+    pImageAssetNodeElementL->LinkEndChild(pImageAssetNodeComplexTypeElementL);
+
+    // Create choice element.
+    TiXmlElement* pImageAssetNodeChoiceElementL = new TiXmlElement("xs:choice");
+    pImageAssetNodeChoiceElementL->SetAttribute("minOccurs", 0);
+    pImageAssetNodeChoiceElementL->SetAttribute("maxOccurs", "unbounded");
+    pImageAssetNodeComplexTypeElementL->LinkEndChild(pImageAssetNodeChoiceElementL);
+
+    // Create ImageAsset element.
+    TiXmlElement* pImageAssetElementL = new TiXmlElement("xs:element");
+    pImageAssetElementL->SetAttribute("name", layerNodeName);
+    pImageAssetElementL->SetAttribute("minOccurs", 0);
+    pImageAssetElementL->SetAttribute("maxOccurs", 1);
+    pImageAssetNodeChoiceElementL->LinkEndChild(pImageAssetElementL);
+
+    // Create complex type Element.
+    TiXmlElement* pImageAssetComplexTypeElementL = new TiXmlElement("xs:complexType");
+    pImageAssetElementL->LinkEndChild(pImageAssetComplexTypeElementL);
+
+    // Create "ImageFile" attribute.
+    TiXmlElement* pLayerImageFile = new TiXmlElement("xs:attribute");
+    pLayerImageFile->SetAttribute("name", layerImageFile);
+    pLayerImageFile->SetAttribute("type", "xs:string");
+    pImageAssetComplexTypeElementL->LinkEndChild(pLayerImageFile);
+
+    // Create "Position" attribute.
+    TiXmlElement* pLayerPosition = new TiXmlElement("xs:attribute");
+    pLayerPosition->SetAttribute("name", layerPositionName);
+    pLayerPosition->SetAttribute("type", "Point2I_ConsoleType");
+    pImageAssetComplexTypeElementL->LinkEndChild(pLayerPosition);
+
+    // Create "BlendColor" attribute.
+    TiXmlElement* pLayerBlendColor = new TiXmlElement("xs:attribute");
+    pLayerBlendColor->SetAttribute("name", layerBlendColorName);
+    pLayerBlendColor->SetAttribute("type", "ColorF_ConsoleType");
+    pImageAssetComplexTypeElementL->LinkEndChild(pLayerBlendColor);
 }
 
 //------------------------------------------------------------------------------

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

@@ -158,9 +158,32 @@ public:
         TexelArea mTexelArea;
     };
 
+    class ImageLayer
+    {
+    public:
+        ImageLayer() {}
+
+        ImageLayer(const char* imageFile, const Point2I position, const ColorF blendColor) :
+            mPosition(position), mBlendColor(blendColor), mBitmap(nullptr) 
+        {
+            mImageFile = StringTable->insert(imageFile);
+        }
+
+        void LoadImage(const char* path)
+        {
+            mBitmap = GBitmap::load(path);
+        }
+
+        StringTableEntry mImageFile;
+        Point2I mPosition;
+        ColorF mBlendColor;
+        GBitmap* mBitmap;
+    };
+
 private:
     typedef Vector<FrameArea> typeFrameAreaVector;
     typedef Vector<FrameArea::PixelArea> typeExplicitFrameAreaVector;
+    typedef Vector<ImageLayer> typeImageLayerVector;
 
     /// Configuration.
     StringTableEntry            mImageFile;
@@ -181,6 +204,8 @@ private:
     typeFrameAreaVector         mFrames;
     typeExplicitFrameAreaVector mExplicitFrames;
     TextureHandle               mImageTextureHandle;
+    typeImageLayerVector        mImageLayers;
+    ColorF                      mBlendColor;
 
 public:
     ImageAsset();
@@ -194,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; }
@@ -267,6 +293,26 @@ public:
     
     inline void forceCalculation( void ) { calculateImage(); }
 
+    /// Layers
+    void addLayer(const char* imagePath, const Point2I position, const ColorF blendColor, const bool doRedraw = true);
+    void insertLayer(const U32 index, const char* imagePath, const Point2I position, const ColorF blendColor, const bool doRedraw = true);
+    void removeLayer(const U32 index, const bool doRedraw = true);
+    void moveLayerForward(const U32 index, const bool doRedraw = true);
+    void moveLayerBackward(const U32 index, const bool doRedraw = true);
+    void moveLayerToFront(const U32 index, const bool doRedraw = true);
+    void moveLayerToBack(const U32 index, const bool doRedraw = true);
+    void setLayerImage(const U32 index, const char* imagePath, const bool doRedraw = true);
+    void setLayerPosition(const U32 index, const Point2I position, const bool doRedraw = true);
+    void setLayerBlendColor(const U32 index, const ColorF color, const bool doRedraw = true);
+    const U32 getLayerCount() { return getMax(mImageLayers.size() - 1, 0); } //We pretend layer 0 doesn't exist as it is internally created
+    const char* getLayerImage(const U32 index);
+    const Point2I getLayerPosition(const U32 index);
+    const ColorF getLayerBlendColor(const U32 index);
+    void forceRedrawImage() { redrawImage(); }
+    void setBlendColor(const ColorF color, const bool doRedraw = true);
+    const ColorF getBlendColor();
+
+
     /// Declare Console Object.
     DECLARE_CONOBJECT(ImageAsset);
 
@@ -277,6 +323,9 @@ private:
     void calculateExplicitMode( void );
     void setTextureFilter( const TextureFilterMode filterMode );
 
+    void completeLayerChange(const bool doRedraw);
+    void redrawImage();
+
 protected:
     virtual void initializeAsset( void );
     virtual void onAssetRefresh( void );
@@ -287,6 +336,9 @@ protected:
     virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
     virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
+    virtual void loadTamlExplicitCells(const TamlCustomNodes& customNodes);
+    virtual void loadTamlImageLayers(const TamlCustomNodes& customNodes);
+
 
 protected:
     static void textureEventCallback( const U32 eventCode, void *userData );
@@ -330,6 +382,22 @@ protected:
 
     static bool setCellHeight( void* obj, const char* data )                { static_cast<ImageAsset*>(obj)->setCellHeight(dAtoi(data)); return false; }
     static bool writeCellHeight( void* obj, StringTableEntry pFieldName )   { ImageAsset* pImageAsset = static_cast<ImageAsset*>(obj); return !pImageAsset->getExplicitMode() && pImageAsset->getCellHeight() != 0; }
+
+    static bool setBlendColor(void* obj, const char* data) 
+    { 
+        if (Utility::mGetStringElementCount(data) < 4)
+        {
+            Con::warnf("ImageAsset::BlendColor - Blend colors require four values (red/green/blue/alpha).");
+            return false;
+        }
+        static_cast<ImageAsset*>(obj)->setBlendColor(
+            ColorF(dAtof(Utility::mGetStringElement(data, 0)),
+            dAtof(Utility::mGetStringElement(data, 1)),
+            dAtof(Utility::mGetStringElement(data, 2)),
+            dAtof(Utility::mGetStringElement(data, 3))), true); 
+        return false; 
+    }
+    static bool writeBlendColor(void* obj, StringTableEntry pFieldName) { return static_cast<ImageAsset*>(obj)->getBlendColor() != ColorF(1.0f, 1.0f, 1.0f, 1.0f); }
 };
 
 //-----------------------------------------------------------------------------

+ 434 - 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.
@@ -602,4 +612,427 @@ ConsoleMethodWithDocs(ImageAsset, setExplicitMode, ConsoleVoid, 3, 3, (explicitM
     object->setExplicitMode(dAtob(argv[2]));
 }
 
+/*! Adds a layer to the ImageAsset
+@param imageFile The file for the image to layer over the texture.
+@param position The position for the layer to be at with (0, 0) in the top left corner.
+@param blendColor The blending color to be applied to this new layer.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, addLayer, ConsoleVoid, 5, 6, (imageFile, position, blendColor, [doRedraw]))
+{
+    if (argc < 5)
+    {
+        Con::warnf("ImageAsset::addLayer() - Invalid number of parameters!");
+        return;
+    }
+
+    F32 x, y;
+    x = 0.0f;
+    y = 0.0f;
+    if (Utility::mGetStringElementCount(argv[3]) >= 2)
+    {
+        x = dAtof(Utility::mGetStringElement(argv[3], 0));
+        y = dAtof(Utility::mGetStringElement(argv[3], 1));
+    }
+    Point2I pos(x, y);
+
+    const U32 colorCount = Utility::mGetStringElementCount(argv[4]);
+    if (colorCount != 4)
+    {
+        Con::warnf("Scene::addLayer() - Invalid color! Colors require four values (red / green / blue / alpha)!");
+        return;
+    }
+    ColorF blendColor = ColorF(dAtof(Utility::mGetStringElement(argv[4], 0)),
+        dAtof(Utility::mGetStringElement(argv[4], 1)),
+        dAtof(Utility::mGetStringElement(argv[4], 2)),
+        dAtof(Utility::mGetStringElement(argv[4], 3)));
+
+    bool redraw = true;
+    if (argc == 6)
+    {
+        redraw = dAtob(argv[5]);
+    }
+
+    object->addLayer(argv[2], pos, blendColor, redraw);
+}
+
+/*! Inserts a layer into the stack of layers on a texture at a given index.
+@param index The one-based index to insert the new layer at. Must be less or equal to the number of layers.
+@param imageFile The file for the image to layer over the texture.
+@param position The position for the layer to be at with (0, 0) in the top left corner.
+@param blendColor The blending color to be applied to this new layer.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, insertLayer, ConsoleVoid, 6, 7, (index, imageFile, position, blendColor, [doRedraw]))
+{
+    if (argc < 6)
+    {
+        Con::warnf("ImageAsset::insertLayer() - Invalid number of parameters!");
+        return;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    F32 x, y;
+    x = 0.0f;
+    y = 0.0f;
+    if (Utility::mGetStringElementCount(argv[4]) >= 2)
+    {
+        x = dAtof(Utility::mGetStringElement(argv[4], 0));
+        y = dAtof(Utility::mGetStringElement(argv[4], 1));
+    }
+    Point2I pos(x, y);
+
+    const U32 colorCount = Utility::mGetStringElementCount(argv[5]);
+    if (colorCount != 4)
+    {
+        Con::warnf("Scene::insertLayer() - Invalid color! Colors require four values (red / green / blue / alpha)!");
+        return;
+    }
+    ColorF blendColor = ColorF(dAtof(Utility::mGetStringElement(argv[5], 0)),
+        dAtof(Utility::mGetStringElement(argv[5], 1)),
+        dAtof(Utility::mGetStringElement(argv[5], 2)),
+        dAtof(Utility::mGetStringElement(argv[5], 3)));
+
+    bool redraw = true;
+    if (argc == 7)
+    {
+        redraw = dAtob(argv[6]);
+    }
+
+    object->insertLayer(index, argv[3], pos, blendColor, redraw);
+}
+
+/*! Removes a layer from a texture at a given index.
+@param index The one-based index to remove the new layer from. Must be less or equal to the number of layers.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, removeLayer, ConsoleVoid, 3, 4, (index, [doRedraw]))
+{
+    if (argc < 3)
+    {
+        Con::warnf("ImageAsset::removeLayer() - Invalid number of parameters!");
+        return;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    bool redraw = true;
+    if (argc == 4)
+    {
+        redraw = dAtob(argv[3]);
+    }
+
+    object->removeLayer(index, redraw);
+}
+
+/*! Moves the layer at the index forward.
+@param index The one-based index to move forward. Must be less or equal to the number of layers.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, moveLayerForward, ConsoleVoid, 3, 4, (index, [doRedraw]))
+{
+    if (argc < 3)
+    {
+        Con::warnf("ImageAsset::moveLayerForward() - Invalid number of parameters!");
+        return;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    bool redraw = true;
+    if (argc == 4)
+    {
+        redraw = dAtob(argv[3]);
+    }
+
+    object->moveLayerForward(index, redraw);
+}
+
+/*! Moves the layer at the index backward.
+@param index The one-based index to move backward. Must be less or equal to the number of layers.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, moveLayerBackward, ConsoleVoid, 3, 4, (index, [doRedraw]))
+{
+    if (argc < 3)
+    {
+        Con::warnf("ImageAsset::moveLayerBackward() - Invalid number of parameters!");
+        return;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    bool redraw = true;
+    if (argc == 4)
+    {
+        redraw = dAtob(argv[3]);
+    }
+
+    object->moveLayerBackward(index, redraw);
+}
+
+/*! Moves the layer at the index to the front.
+@param index The one-based index to move to the front. Must be less or equal to the number of layers.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, moveLayerToFront, ConsoleVoid, 3, 4, (index, [doRedraw]))
+{
+    if (argc < 3)
+    {
+        Con::warnf("ImageAsset::moveLayerToFront() - Invalid number of parameters!");
+        return;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    bool redraw = true;
+    if (argc == 4)
+    {
+        redraw = dAtob(argv[3]);
+    }
+
+    object->moveLayerToFront(index, redraw);
+}
+
+/*! Moves the layer at the index to the back.
+@param index The one-based index to move to the back. Must be less or equal to the number of layers.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, moveLayerToBack, ConsoleVoid, 3, 4, (index, [doRedraw]))
+{
+    if (argc < 3)
+    {
+        Con::warnf("ImageAsset::moveLayerToBack() - Invalid number of parameters!");
+        return;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    bool redraw = true;
+    if (argc == 4)
+    {
+        redraw = dAtob(argv[3]);
+    }
+
+    object->moveLayerToBack(index, redraw);
+}
+
+/*! Sets the image for a layer at the given index.
+@param index The one-based index to move to the back. Must be less or equal to the number of layers.
+@param image The path to an image to be used by the layer.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, setLayerImage, ConsoleVoid, 4, 5, (index, image, [doRedraw]))
+{
+    if (argc < 4)
+    {
+        Con::warnf("ImageAsset::setLayerImage() - Invalid number of parameters!");
+        return;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    bool redraw = true;
+    if (argc == 5)
+    {
+        redraw = dAtob(argv[4]);
+    }
+
+    object->setLayerImage(index, argv[3], redraw);
+}
+
+/*! Sets the position for a layer at the given index.
+@param index The one-based index to move to the back. Must be less or equal to the number of layers.
+@param position The space-deliminated (x, y) position to place the image with the top left corner as (0, 0). The layer can safely overflow the bounds of the original image.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, setLayerPosition, ConsoleVoid, 4, 5, (index, position, [doRedraw]))
+{
+    if (argc < 4)
+    {
+        Con::warnf("ImageAsset::setLayerPosition() - Invalid number of parameters!");
+        return;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    F32 x, y;
+    x = 0.0f;
+    y = 0.0f;
+    if (Utility::mGetStringElementCount(argv[3]) >= 2)
+    {
+        x = dAtof(Utility::mGetStringElement(argv[3], 0));
+        y = dAtof(Utility::mGetStringElement(argv[3], 1));
+    }
+    Point2I pos(x, y);
+
+    bool redraw = true;
+    if (argc == 5)
+    {
+        redraw = dAtob(argv[4]);
+    }
+
+    object->setLayerPosition(index, pos, redraw);
+}
+
+/*! Sets the blend color for a layer at the given index.
+@param index The one-based index to move to the back. Must be less or equal to the number of layers.
+@param blendColor The space-deliminated color used to blend the layer. Requires four decimal values between 0 and 1 that represent red, green, blue, and alpha.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, setLayerBlendColor, ConsoleVoid, 4, 5, (index, blendColor, [doRedraw]))
+{
+    if (argc < 4)
+    {
+        Con::warnf("ImageAsset::setLayerBlendColor() - Invalid number of parameters!");
+        return;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    const U32 colorCount = Utility::mGetStringElementCount(argv[3]);
+    if (colorCount != 4)
+    {
+        Con::warnf("Scene::setLayerBlendColor() - Invalid color! Colors require four values (red / green / blue / alpha)!");
+        return;
+    }
+    ColorF blendColor = ColorF(dAtof(Utility::mGetStringElement(argv[3], 0)),
+        dAtof(Utility::mGetStringElement(argv[3], 1)),
+        dAtof(Utility::mGetStringElement(argv[3], 2)),
+        dAtof(Utility::mGetStringElement(argv[3], 3)));
+
+    bool redraw = true;
+    if (argc == 5)
+    {
+        redraw = dAtob(argv[4]);
+    }
+
+    object->setLayerBlendColor(index, blendColor, redraw);
+}
+
+/*! Returns the number of layers.
+@return The number of layers used by the texture. Zero if only the base texture is used.
+*/
+ConsoleMethodWithDocs(ImageAsset, getLayerCount, ConsoleInt, 2, 2, ())
+{
+    return object->getLayerCount();
+}
+
+/*! Returns image used for a given layer.
+@param index The one-based index to move to the back. Must be less or equal to the number of layers.
+@return The path to the image file.
+*/
+ConsoleMethodWithDocs(ImageAsset, getLayerImage, ConsoleString, 3, 3, (index))
+{
+    if (argc < 3)
+    {
+        Con::warnf("ImageAsset::getLayerImage() - Invalid number of parameters!");
+        return StringTable->EmptyString;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    return object->getLayerImage(index);
+}
+
+/*! Returns position for a given layer.
+@param index The one-based index to move to the back. Must be less or equal to the number of layers.
+@return (int y, int x) The layer position.
+*/
+ConsoleMethodWithDocs(ImageAsset, getLayerPosition, ConsoleString, 3, 3, (index))
+{
+    if (argc < 3)
+    {
+        Con::warnf("ImageAsset::getLayerPosition() - Invalid number of parameters!");
+        return StringTable->EmptyString;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    char* retBuffer = Con::getReturnBuffer(64);
+    const Point2I& pos = object->getLayerPosition(index);
+    dSprintf(retBuffer, 64, "%d %d", pos.x, pos.y);
+    return retBuffer;
+}
+
+/*! Returns the blend color for a given layer.
+@param index The one-based index to move to the back. Must be less or equal to the number of layers.
+@return (float red / float green / float blue / float alpha) The layer blend color.
+*/
+ConsoleMethodWithDocs(ImageAsset, getLayerBlendColor, ConsoleString, 3, 3, (index))
+{
+    if (argc < 3)
+    {
+        Con::warnf("ImageAsset::getLayerBlendColor() - Invalid number of parameters!");
+        return StringTable->EmptyString;
+    }
+
+    U32 index = dAtoi(argv[2]);
+
+    return object->getLayerBlendColor(index).scriptThis();
+}
+
+/*! Forces the texture to redraw its layers. Redrawing can be expensive and is automatically done on every change to a layer unless prevented.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, forceRedraw, ConsoleVoid, 2, 2, ())
+{
+    if (object->getLayerCount() > 0)
+    {
+        object->forceRedrawImage();
+    }
+}
+
+/*! Sets the blend color for the base image when using layers.
+@param blendColor The space-deliminated color used to blend the layer. Requires four decimal values between 0 and 1 that represent red, green, blue, and alpha.
+@param doRedraw Optional value that prevents a redraw of the texture when false. Defaults to true.
+@return No return value.
+*/
+ConsoleMethodWithDocs(ImageAsset, setBlendColor, ConsoleVoid, 3, 4, (blendColor, [doRedraw]))
+{
+    if (argc < 3)
+    {
+        Con::warnf("ImageAsset::setBlendColor() - Invalid number of parameters!");
+        return;
+    }
+
+    const U32 colorCount = Utility::mGetStringElementCount(argv[2]);
+    if (colorCount != 4)
+    {
+        Con::warnf("Scene::setBlendColor() - Invalid color! Colors require four values (red / green / blue / alpha)!");
+        return;
+    }
+    ColorF blendColor = ColorF(dAtof(Utility::mGetStringElement(argv[2], 0)),
+        dAtof(Utility::mGetStringElement(argv[2], 1)),
+        dAtof(Utility::mGetStringElement(argv[2], 2)),
+        dAtof(Utility::mGetStringElement(argv[2], 3)));
+
+    bool redraw = true;
+    if (argc == 4)
+    {
+        redraw = dAtob(argv[3]);
+    }
+
+    object->setBlendColor(blendColor, redraw);
+}
+
+/*! Returns the blend color for the base texture when using layers.
+@return (float red / float green / float blue / float alpha) The base blend color.
+*/
+ConsoleMethodWithDocs(ImageAsset, getBlendColor, ConsoleString, 2, 2, ())
+{
+    return object->getBlendColor().scriptThis();
+}
+
 ConsoleMethodGroupEndWithDocs(ImageAsset)

+ 1 - 1
engine/source/2d/assets/ParticleAssetFieldCollection.h

@@ -27,7 +27,7 @@
 #include "2d/assets/ParticleAssetField.h"
 #endif
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 1 - 1
engine/source/2d/core/BatchRender.h

@@ -39,7 +39,7 @@
 #include "graphics/TextureManager.h"
 #endif
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 1 - 3
engine/source/2d/editorToy/EditorToySceneWindow.cc

@@ -382,10 +382,8 @@ bool EditorToySceneWindow::initCursors()
       mLeftRightCursor = dynamic_cast<GuiCursor*>(obj);
       obj = Sim::findObject("DefaultCursor");
       mDefaultCursor = dynamic_cast<GuiCursor*>(obj);
-      obj = Sim::findObject("MoveCursor");
-      mMoveCursor = dynamic_cast<GuiCursor*>(obj);
 
-      return(mMoveCursor != NULL && mUpDownCursor != NULL && mLeftRightCursor != NULL && mDefaultCursor != NULL && mMoveCursor != NULL);
+      return(mMoveCursor != NULL && mUpDownCursor != NULL && mLeftRightCursor != NULL && mDefaultCursor != NULL);
    }
    else
       return(true);

+ 38 - 26
engine/source/2d/gui/guiSpriteCtrl.cc

@@ -67,6 +67,7 @@ GuiSpriteCtrl::GuiSpriteCtrl( void ) :
 	mImageSize.set(10, 10);
 	mFullSize = true;
 	mConstrainProportions = true;
+	mClampImage = true;
 	mSingleFrameBitmap = true;
 }
 
@@ -95,6 +96,7 @@ void GuiSpriteCtrl::initPersistFields()
 	addField("imageColor", TypeFluidColorI, Offset(mImageColor, GuiSpriteCtrl));
 	addField("imageSize", TypePoint2I, Offset(mImageSize, GuiSpriteCtrl));
 	addField("fullSize", TypeBool, Offset(mFullSize, GuiSpriteCtrl));
+	addField("clampImage", TypeBool, Offset(mClampImage, GuiSpriteCtrl));
 	addField("constrainProportions", TypeBool, Offset(mConstrainProportions, GuiSpriteCtrl));
 	endGroup("GuiSpriteCtrl");
 }
@@ -348,10 +350,18 @@ Point2I GuiSpriteCtrl::applyAlignment(RectI &bounds, Point2I &size)
 	}
 
 	//Apply the image offset
-	S32 maxX = bounds.extent.x - size.x;
-	S32 maxY = bounds.extent.y - size.y;
-	offset.x = mClamp(offset.x + mPositionOffset.x, 0, maxX);
-	offset.y = mClamp(offset.y + mPositionOffset.y, 0, maxY);
+	if (mClampImage)
+	{
+		S32 maxX = bounds.extent.x - size.x;
+		S32 maxY = bounds.extent.y - size.y;
+		offset.x = mClamp(offset.x + mPositionOffset.x, 0, maxX);
+		offset.y = mClamp(offset.y + mPositionOffset.y, 0, maxY);
+	}
+	else
+	{
+		offset.x = offset.x + mPositionOffset.x;
+		offset.y = offset.y + mPositionOffset.y;
+	}
 
 	return offset;
 }
@@ -546,50 +556,52 @@ void GuiSpriteCtrl::onRender(Point2I offset, const RectI &updateRect)
 			dglSetClipRect(clipRect);
 			dglSetBitmapModulation(ColorF(mImageColor));
 
-			Point2I offset = Point2I(0, 0);
+			Point2I imageOffset = Point2I(0, 0);
 			Point2I size = constrain(mImageSize);
 
 			if (mTileImage) //Tile the image
 			{
-				offset = mPositionOffset;
-				offset.x = (mPositionOffset.x % size.x);
-				if (offset.x > 0)
+				imageOffset = mPositionOffset;
+				imageOffset.x = (mPositionOffset.x % size.x);
+				if (imageOffset.x > 0)
 				{
-					offset.x -= size.x;
+					imageOffset.x -= size.x;
 				}
-				offset.y = (mPositionOffset.y % size.y);
-				if (offset.y > 0)
+				imageOffset.y = (mPositionOffset.y % size.y);
+				if (imageOffset.y > 0)
 				{
-					offset.y -= size.y;
+					imageOffset.y -= size.y;
 				}
 
-				RenderTiledImage(contentRect, offset, size);
+				RenderTiledImage(contentRect, imageOffset, size);
 			}
 			else if (mFullSize) //Fill with the image
 			{
 				size = constrain(contentRect.extent, false);
 				if (mConstrainProportions)
 				{
-					offset = applyAlignment(contentRect, size);
+					imageOffset = applyAlignment(contentRect, size);
 				}
-				RenderImage(contentRect, offset, size);
+				RenderImage(contentRect, imageOffset, size);
 			}
 			else //Position the image by profile alignment
 			{
-				size = constrain(mImageSize);
-				if (size.x > contentRect.extent.x)
-				{
-					size.x = contentRect.extent.x;
-					size = constrainLockX(size);
-				}
-				if (size.y > contentRect.extent.y)
+				if (mClampImage)
 				{
-					size.y = contentRect.extent.y;
-					size = constrainLockY(size);
+					if (size.x > contentRect.extent.x)
+					{
+						size.x = contentRect.extent.x;
+						size = constrainLockX(size);
+					}
+					if (size.y > contentRect.extent.y)
+					{
+						size.y = contentRect.extent.y;
+						size = constrainLockY(size);
+					}
 				}
-				offset = applyAlignment(contentRect, size);
+				imageOffset = applyAlignment(contentRect, size);
 
-				RenderImage(contentRect, offset, size);
+				RenderImage(contentRect, imageOffset, size);
 			}
 			dglClearBitmapModulation();
 			dglSetClipRect(oldClip);

+ 3 - 0
engine/source/2d/gui/guiSpriteCtrl.h

@@ -49,6 +49,7 @@ protected:
 	Point2I mImageSize; //The size of the image, reduced, if needed, to fit the content area
 	bool mFullSize; //If true, the image will take all available space
 	bool mConstrainProportions; //If true, the image will maintain its aspect ratio 
+	bool mClampImage; //If true, the image will be forced into the control's content area.
 	bool mSingleFrameBitmap; //If true and bitmaps are used, this will assume there's only one frame when scanning the bitmap
 
 	Fluid mFluidMoveTo;
@@ -110,6 +111,8 @@ public:
 	inline void setImageSize(Point2I size) { mImageSize = size; }
 	inline bool getFullSize() { return mFullSize; }
 	inline void setFullSize(bool isFull) { mFullSize = isFull; }
+	inline bool getClampImage() { return mClampImage; }
+	inline void setClampImage(bool clamp) { mClampImage = clamp; }
 	inline bool getConstrainProportions() { return mConstrainProportions; }
 	inline void setConstrainProportions(bool setting) { mConstrainProportions = setting; }
 	inline bool getSingleFrameBitmap() { return mSingleFrameBitmap; }

+ 23 - 0
engine/source/2d/gui/guiSpriteCtrl_ScriptBindings.h

@@ -761,6 +761,29 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getConstrainProportions, ConsoleBool, 2, 2,
 	return object->getConstrainProportions();
 }
 
+/*! Sets if the image should be able to overflow the content area.
+	@param clamp If true, the image will be forced into the content area. False will allow the image to overflow the content area, although it will still be cut off.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, setClampImage, ConsoleVoid, 3, 3, "(bool clamp)")
+{
+	if (argc != 3)
+	{
+		Con::warnf("GuiSpriteCtrl::setClampImage() - Invalid number of parameters!");
+		return;
+	}
+
+	object->setClampImage(dAtob(argv[2]));
+}
+
+/*! Gets if the image is able to overflow the content area.
+	@return True if overflow is possible and false otherwise.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, getClampImage, ConsoleBool, 2, 2, "()")
+{
+	return object->getClampImage();
+}
+
 /*! Animates the position offset from its current value to a target value over time.
 	@param x/y The space-delimited x and y values to change the image offset to.
 	@param time The time in miliseconds it should take to complete the transformation.

+ 2 - 2
engine/source/2d/scene/Scene.cc

@@ -3578,7 +3578,7 @@ void Scene::setDebugSceneObject( SceneObject* pSceneObject )
 void Scene::setLayerSortMode( const U32 layer, const SceneRenderQueue::RenderSort sortMode )
 {
     // Is the layer valid?
-    if ( layer > MAX_LAYERS_SUPPORTED )
+    if ( layer >= MAX_LAYERS_SUPPORTED )
     {
         // No, so warn.
         Con::warnf( "Scene::setLayerSortMode() - Layer '%d' is out of range.", layer );
@@ -3603,7 +3603,7 @@ void Scene::setLayerSortMode( const U32 layer, const SceneRenderQueue::RenderSor
 SceneRenderQueue::RenderSort Scene::getLayerSortMode( const U32 layer )
 {
     // Is the layer valid?
-    if ( layer > MAX_LAYERS_SUPPORTED )
+    if ( layer >= MAX_LAYERS_SUPPORTED )
     {
         // No, so warn.
         Con::warnf( "Scene::getLayerSortMode() - Layer '%d' is out of range.", layer );

+ 1 - 1
engine/source/2d/scene/Scene.h

@@ -51,7 +51,7 @@
 #include "2d/scene/DebugDraw.h"
 #endif
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 4 - 1
engine/source/2d/sceneobject/Path.h

@@ -77,6 +77,7 @@ public:
    {
       if (mNodes.empty()) return false;
       if((index >= 0) && (index < mNodes.size())) return true;
+      return false;
    }
 
    void attachObject(SceneObject* object, F32 speed, F32 force, bool orientToPath, F32 angleOff, bool snapToNode, S32 startNode, bool loop, S32 maxLoop);
@@ -95,6 +96,8 @@ public:
       Vector<PathObject*>::iterator i;
       for (i = mObjs.begin(); i != mObjs.end(); i++)
          if ((*i)->mObj == obj) return *i;
+      
+      return NULL;
    }
 
    DECLARE_CONOBJECT(Path);
@@ -110,4 +113,4 @@ private:
 
 };
 
-#endif
+#endif

+ 1 - 1
engine/source/2d/sceneobject/SceneObject.cc

@@ -4029,7 +4029,7 @@ void SceneObject::onTamlCustomRead( const TamlCustomNodes& customNodes )
             }
 
             // Is point count valid?
-            if ( pointCount == 0 || pointCount != 2 )
+            if ( pointCount != 2 )
             {
                 // No, so warn.
                 Con::warnf( "SceneObject::onTamlCustomRead() - No points (or not two points) on edge collision shape." );

+ 1 - 1
engine/source/2d/sceneobject/Trigger.h

@@ -27,7 +27,7 @@
 #include "2d/sceneobject/SceneObject.h"
 #endif
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 116 - 0
engine/source/algorithm/pcg_basic.c

@@ -0,0 +1,116 @@
+/*
+ * PCG Random Number Generation for C.
+ *
+ * Copyright 2014 Melissa O'Neill <[email protected]>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * For additional information about the PCG random number generation scheme,
+ * including its license and other licensing options, visit
+ *
+ *       http://www.pcg-random.org
+ */
+
+/*
+ * This code is derived from the full C implementation, which is in turn
+ * derived from the canonical C++ PCG implementation. The C++ version
+ * has many additional features and is preferable if you can use C++ in
+ * your project.
+ */
+
+#include "pcg_basic.h"
+
+// state for global RNGs
+
+static pcg32_random_t pcg32_global = PCG32_INITIALIZER;
+
+// pcg32_srandom(initstate, initseq)
+// pcg32_srandom_r(rng, initstate, initseq):
+//     Seed the rng.  Specified in two parts, state initializer and a
+//     sequence selection constant (a.k.a. stream id)
+
+void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
+{
+    rng->state = 0U;
+    rng->inc = (initseq << 1u) | 1u;
+    pcg32_random_r(rng);
+    rng->state += initstate;
+    pcg32_random_r(rng);
+}
+
+void pcg32_srandom(uint64_t seed, uint64_t seq)
+{
+    pcg32_srandom_r(&pcg32_global, seed, seq);
+}
+
+// pcg32_random()
+// pcg32_random_r(rng)
+//     Generate a uniformly distributed 32-bit random number
+
+uint32_t pcg32_random_r(pcg32_random_t* rng)
+{
+    uint64_t oldstate = rng->state;
+    rng->state = oldstate * 6364136223846793005ULL + rng->inc;
+    uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
+    uint32_t rot = oldstate >> 59u;
+    return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
+}
+
+uint32_t pcg32_random()
+{
+    return pcg32_random_r(&pcg32_global);
+}
+
+
+// pcg32_boundedrand(bound):
+// pcg32_boundedrand_r(rng, bound):
+//     Generate a uniformly distributed number, r, where 0 <= r < bound
+
+uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound)
+{
+    // To avoid bias, we need to make the range of the RNG a multiple of
+    // bound, which we do by dropping output less than a threshold.
+    // A naive scheme to calculate the threshold would be to do
+    //
+    //     uint32_t threshold = 0x100000000ull % bound;
+    //
+    // but 64-bit div/mod is slower than 32-bit div/mod (especially on
+    // 32-bit platforms).  In essence, we do
+    //
+    //     uint32_t threshold = (0x100000000ull-bound) % bound;
+    //
+    // because this version will calculate the same modulus, but the LHS
+    // value is less than 2^32.
+
+    uint32_t threshold = -bound % bound;
+
+    // Uniformity guarantees that this loop will terminate.  In practice, it
+    // should usually terminate quickly; on average (assuming all bounds are
+    // equally likely), 82.25% of the time, we can expect it to require just
+    // one iteration.  In the worst case, someone passes a bound of 2^31 + 1
+    // (i.e., 2147483649), which invalidates almost 50% of the range.  In 
+    // practice, bounds are typically small and only a tiny amount of the range
+    // is eliminated.
+    for (;;) {
+        uint32_t r = pcg32_random_r(rng);
+        if (r >= threshold)
+            return r % bound;
+    }
+}
+
+
+uint32_t pcg32_boundedrand(uint32_t bound)
+{
+    return pcg32_boundedrand_r(&pcg32_global, bound);
+}
+

+ 78 - 0
engine/source/algorithm/pcg_basic.h

@@ -0,0 +1,78 @@
+/*
+ * PCG Random Number Generation for C.
+ *
+ * Copyright 2014 Melissa O'Neill <[email protected]>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * For additional information about the PCG random number generation scheme,
+ * including its license and other licensing options, visit
+ *
+ *     http://www.pcg-random.org
+ */
+
+/*
+ * This code is derived from the full C implementation, which is in turn
+ * derived from the canonical C++ PCG implementation. The C++ version
+ * has many additional features and is preferable if you can use C++ in
+ * your project.
+ */
+
+#ifndef PCG_BASIC_H_INCLUDED
+#define PCG_BASIC_H_INCLUDED 1
+
+#include <inttypes.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+struct pcg_state_setseq_64 {    // Internals are *Private*.
+    uint64_t state;             // RNG state.  All values are possible.
+    uint64_t inc;               // Controls which RNG sequence (stream) is
+                                // selected. Must *always* be odd.
+};
+typedef struct pcg_state_setseq_64 pcg32_random_t;
+
+// If you *must* statically initialize it, here's one.
+
+#define PCG32_INITIALIZER   { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }
+
+// pcg32_srandom(initstate, initseq)
+// pcg32_srandom_r(rng, initstate, initseq):
+//     Seed the rng.  Specified in two parts, state initializer and a
+//     sequence selection constant (a.k.a. stream id)
+
+void pcg32_srandom(uint64_t initstate, uint64_t initseq);
+void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate,
+                     uint64_t initseq);
+
+// pcg32_random()
+// pcg32_random_r(rng)
+//     Generate a uniformly distributed 32-bit random number
+
+uint32_t pcg32_random(void);
+uint32_t pcg32_random_r(pcg32_random_t* rng);
+
+// pcg32_boundedrand(bound):
+// pcg32_boundedrand_r(rng, bound):
+//     Generate a uniformly distributed number, r, where 0 <= r < bound
+
+uint32_t pcg32_boundedrand(uint32_t bound);
+uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound);
+
+#if __cplusplus
+}
+#endif
+
+#endif // PCG_BASIC_H_INCLUDED

+ 1 - 1
engine/source/assets/assetTagsManifest.h

@@ -27,7 +27,7 @@
 #include "sim/simBase.h"
 #endif
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 3 - 3
engine/source/collection/hashTable.h

@@ -20,8 +20,8 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
-#ifndef _HASHTABLE_H
-#define _HASHTABLE_H
+#ifndef _HASHTABLE_H_
+#define _HASHTABLE_H_
 
 #include "vector.h"
 #include "platform/platform.h"
@@ -697,4 +697,4 @@ inline Value& HashMap<Key,Value,Sequence>::operator[](const Key& key)
 
 
 
-#endif// _HASHTABLE_H
+#endif// _HASHTABLE_H_

+ 1 - 1
engine/source/collection/nameTags.h

@@ -27,7 +27,7 @@
 #include "sim/simBase.h"
 #endif
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 1 - 1
engine/source/component/behaviors/behaviorInstance.h

@@ -26,7 +26,7 @@
 #include "sim/simBase.h"
 #endif
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 1 - 1
engine/source/console/console.cc

@@ -42,7 +42,7 @@
 #include "output_ScriptBinding.h"
 #include "expando_ScriptBinding.h"
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 1 - 1
engine/source/console/consoleDictionary.h

@@ -116,7 +116,7 @@ public:
             if(type <= TypeInternalString)
             {
                 fval = val;
-                ival = static_cast<U32>(val);
+                ival = static_cast<U32>(static_cast<S32>(val));
                 if(sval != typeValueEmpty)
                 {
                     dFree(sval);

+ 0 - 3
engine/source/game/defaultGame.cc

@@ -592,9 +592,6 @@ void DefaultGame::processTimeEvent(TimeEvent *event)
    {
       elapsedTime = (U32) (elapsedTime * gTimeScale);
    }
-   {
-       elapsedTime = elapsedTime;
-   }
 
    Platform::advanceTime(elapsedTime);
    bool tickPass;

+ 2 - 2
engine/source/game/version.h

@@ -24,8 +24,8 @@
 #define _ENGINE_VERSION_H_
 
 // Engine Version.
-#define T2D_ENGINE_VERSION            "v4.0.0 ea2"    ///< Engine Version String.
-#define T2D_IPHONETOOLS_VERSION       "v4.0.0 ea2"    ///< Engine Version String for iPhone tools. Changing this will allow a fresh AppData folder to avoid conflicts with other builds existing on the system.
+#define T2D_ENGINE_VERSION            "v4.0.0 ea2.1"    ///< Engine Version String.
+#define T2D_IPHONETOOLS_VERSION       "v4.0.0 ea2.1"    ///< Engine Version String for iPhone tools. Changing this will allow a fresh AppData folder to avoid conflicts with other builds existing on the system.
 
 /// Gets the specified version number.  The version number is specified as a global in version.cc
 U32 getVersionNumber();

+ 1 - 1
engine/source/graphics/PNGImage.h

@@ -71,7 +71,7 @@ public:
     // Will "merge" the incoming image onto the current image on to an x, y position.
     bool MergeOn(U32 x, U32 y, const PNGImage* inc);
 
-    // Will clean up any allocated memory from the PNGImage. This must be called or their may be a memory leak.
+    // Will clean up any allocated memory from the PNGImage. This must be called or there may be a memory leak.
     bool CleanMemoryUsage();
 
     bool ClearImageData();

+ 59 - 0
engine/source/graphics/gBitmap.cc

@@ -121,6 +121,65 @@ void GBitmap::deleteImage()
    SAFE_DELETE(pPalette);
 }
 
+void GBitmap::clearImage(const ColorF blendColor)
+{
+    ColorI clearColor(blendColor.red, blendColor.green, blendColor.blue, 0);
+    for (U32 h = 0; h < getHeight(); h++)
+    {
+        for (U32 w = 0; w < getWidth(); w++)
+        {
+            setColor(w, h, clearColor);
+        }
+    }
+}
+
+bool GBitmap::mergeLayer(const Point2I pos, const GBitmap* layer, const ColorF blendColor)
+{
+    if (layer != nullptr && (getFormat() == BitmapFormat::RGBA || getFormat() == BitmapFormat::RGB) && (layer->getFormat() == BitmapFormat::RGBA || layer->getFormat() == BitmapFormat::RGB))
+    {
+        for (U32 h = getMax(0, pos.y); h < getHeight() && (h - pos.y) < layer->getHeight(); h++)
+        {
+            for (U32 w = getMax(0, pos.x); w < getWidth() && (w - pos.x) < layer->getWidth(); w++)
+            {
+                const U8* layerByte = layer->getAddress(w - pos.x, h - pos.y);
+                U8* baseByte = getAddress(w, h);
+
+                float layerAlpha = blendColor.alpha;
+                if (layer->getFormat() == BitmapFormat::RGBA)
+                {
+                    layerAlpha = (layerByte[3] / 255.0f) * blendColor.alpha;
+                }
+                if (layerAlpha <= 0.005f)
+                {
+                    continue;
+                }
+
+                float baseAlpha = 1.0f;
+                if (getFormat() == BitmapFormat::RGBA)
+                {
+                    baseAlpha = (baseByte[3] / 255.0f);
+                }
+                float alpha = layerAlpha + baseAlpha * (1 - layerAlpha);
+
+                float red = ((float)layerByte[0]/255.0f * layerAlpha * blendColor.red) + ((float)baseByte[0]/255.0f * baseAlpha * (1 - layerAlpha)) / alpha;
+                float green = ((float)layerByte[1]/255.0f * layerAlpha * blendColor.green) + ((float)baseByte[1]/255.0f * baseAlpha * (1 - layerAlpha)) / alpha;
+                float blue = ((float)layerByte[2]/255.0f * layerAlpha * blendColor.blue) + ((float)baseByte[2]/255.0f * baseAlpha * (1 - layerAlpha)) / alpha;
+
+                baseByte[0] = (U8)mClamp(red * 255.0f, 0.0f, 255.0f);
+                baseByte[1] = (U8)mClamp(green * 255.0f, 0.0f, 255.0f);
+                baseByte[2] = (U8)mClamp(blue * 255.0f, 0.0f, 255.0f);
+
+                if (getFormat() == BitmapFormat::RGBA)
+                {
+                    baseByte[3] = (U8)mClamp(alpha * 255.0f, 0.0f, 255.0f);
+                }
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
 
 //--------------------------------------------------------------------------
 void GBitmap::setPalette(GPalette* in_pPalette)

+ 3 - 0
engine/source/graphics/gBitmap.h

@@ -130,6 +130,7 @@ class GBitmap: public ResourceInstance
    static U32 sBitmapIdSource;
 
    void deleteImage();
+   void clearImage(const ColorF blendColor);
 
    BitmapFormat internalFormat;
   public:
@@ -149,6 +150,8 @@ class GBitmap: public ResourceInstance
                             ///  deleted on exit, or written out on a
                             ///  write.
 
+   bool mergeLayer(const Point2I pos, const GBitmap* layer, const ColorF blendColor);
+
    //-------------------------------------- Input/Output interface
   public:
    bool readJPEG(Stream& io_rStream);              // located in bitmapJpeg.cc

+ 1 - 1
engine/source/graphics/gColor.cc

@@ -30,7 +30,7 @@
 #include "string/stringUnit.h"
 #endif
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 4 - 7
engine/source/gui/buttons/guiDropDownCtrl.cc

@@ -180,13 +180,10 @@ void GuiDropDownCtrl::onRender(Point2I offset, const RectI& updateRect)
 	RectI contentRect = applyPadding(fillRect.point, fillRect.extent, currentState, mProfile);
 
 	//Render the triangle
-	if(mProfile->usesDefaultRendering(currentState))
-	{
-		RectI drawArea = RectI(contentRect.point.x + contentRect.extent.x - contentRect.extent.y, contentRect.point.y, contentRect.extent.y, contentRect.extent.y);
-		ColorI color = ColorI(getFontColor(mProfile, currentState));
-		renderTriangleIcon(drawArea, color, GuiDirection::Down, 8);
-		contentRect.extent.x -= contentRect.extent.y;
-	}
+	RectI drawArea = RectI(contentRect.point.x + contentRect.extent.x - contentRect.extent.y, contentRect.point.y, contentRect.extent.y, contentRect.extent.y);
+	ColorI color = ColorI(getFontColor(mProfile, currentState));
+	renderTriangleIcon(drawArea, color, GuiDirection::Down, 8);
+	contentRect.extent.x -= contentRect.extent.y;
 
 	//Render the text
 	S32 index = mListBox->getSelectedItem();

+ 9 - 0
engine/source/gui/containers/guiChainCtrl.cc

@@ -81,6 +81,15 @@ void GuiChainCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
 
 void GuiChainCtrl::onChildAdded(GuiControl *child)
 {
+	//Ensure the child isn't positioned to the center
+	if (child->getHorizSizing() == horizResizeCenter && !mIsVertical)
+	{
+		child->setHorizSizing(horizResizeLeft);
+	}
+	if (child->getVertSizing() == vertResizeCenter && mIsVertical)
+	{
+		child->setVertSizing(vertResizeTop);
+	}
 	Parent::onChildAdded(child);
 	calculateExtent();
 }

+ 23 - 2
engine/source/gui/containers/guiExpandCtrl.cc

@@ -116,6 +116,12 @@ void GuiExpandCtrl::parentResized(const Point2I &oldParentExtent, const Point2I
 	setUpdate();
 }
 
+void GuiExpandCtrl::childResized(GuiControl* child)
+{
+	calcExpandedExtent();
+	Parent::childResized(child);
+}
+
 void GuiExpandCtrl::setCollapsedExtent(const Point2I &extent)
 {
 	mCollapsedExtent = extent;
@@ -170,12 +176,27 @@ bool GuiExpandCtrl::processExpansion()
 		mBounds.extent.x = processValue(progress, mExpandedExtent.x, mCollapsedExtent.x);
 		mBounds.extent.y = processValue(progress, mExpandedExtent.y, mCollapsedExtent.y);
 	}
-	setUpdate();
 
-	GuiControl *parent = getParent();
+	GuiControl* parent = getParent();
 	if (parent)
+	{
+		if (mHorizSizing == horizResizeCenter)
+		{
+			mBounds.point.x = (parent->mBounds.extent.x - mBounds.extent.x) / 2;
+		}
+		if (mVertSizing == vertResizeCenter)
+		{
+			mBounds.point.y = (parent->mBounds.extent.y - mBounds.extent.y) / 2;
+		}
+
 		parent->childResized(this);
+	}
+	setUpdate();
 
+	if (isMethod("onResize"))
+	{
+		Con::executef(this, 2, "onResize");
+	}
 
 	if (mAnimationProgress >= 1.0f)
 	{

+ 1 - 0
engine/source/gui/containers/guiExpandCtrl.h

@@ -60,6 +60,7 @@ public:
 	GuiExpandCtrl();
 
    virtual void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
+   virtual void childResized(GuiControl* child);
 
    inline bool getExpanded() { return mExpanded; };
    void setExpanded(bool isExpanded);

+ 9 - 0
engine/source/gui/containers/guiGridCtrl.cc

@@ -321,6 +321,15 @@ Point2F GuiGridCtrl::GetGridItemHeight(const S32 totalArea, const S32 maxChainLe
 
 void GuiGridCtrl::onChildAdded(GuiControl *child)
 {
+	//Ensure the child isn't positioned to the center
+	if (child->getHorizSizing() == horizResizeCenter)
+	{
+		child->setHorizSizing(horizResizeLeft);
+	}
+	if (child->getVertSizing() == vertResizeCenter)
+	{
+		child->setVertSizing(vertResizeTop);
+	}
 	resize(getPosition(), getExtent());
 }
 

+ 21 - 2
engine/source/gui/containers/guiScrollCtrl.cc

@@ -95,8 +95,27 @@ void GuiScrollCtrl::initPersistFields()
 
 void GuiScrollCtrl::resize(const Point2I &newPos, const Point2I &newExt)
 {
-   Parent::resize(newPos, newExt);
-   computeSizes();
+	bool hasH = mHasHScrollBar;
+	bool hasV = mHasVScrollBar;
+	Parent::resize(newPos, newExt);
+	computeSizes();
+
+	if (hasH != mHasHScrollBar || hasV != mHasVScrollBar)
+	{
+		S32 deltaY = hasH != mHasHScrollBar ? (mHasHScrollBar ? mScrollBarThickness : -mScrollBarThickness) : 0;
+		S32 deltaX = hasV != mHasVScrollBar ? (mHasVScrollBar ? mScrollBarThickness : -mScrollBarThickness) : 0;
+
+		iterator i;
+		for (i = begin(); i != end(); i++)
+		{
+			GuiControl* ctrl = static_cast<GuiControl*>(*i);
+			ctrl->mRenderInsetRB = Point2I(ctrl->mRenderInsetRB.x + deltaX, ctrl->mRenderInsetRB.y + deltaY);
+			ctrl->parentResized(mBounds.extent - (ctrl->mRenderInsetLT + ctrl->mRenderInsetRB), mBounds.extent - (ctrl->mRenderInsetLT + ctrl->mRenderInsetRB));
+		}
+
+		Parent::resize(newPos, newExt);
+		computeSizes();
+	}
 }
 
 void GuiScrollCtrl::childResized(GuiControl *child)

+ 5 - 0
engine/source/gui/containers/guiWindowCtrl.cc

@@ -865,6 +865,11 @@ void GuiWindowCtrl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEve
 {
 	Point2I mousePos  = lastGuiEvent.mousePoint;
 	RectI winRect   = mBounds;
+	GuiControl* parent = getParent();
+	if (!parent)
+	{
+		return;
+	}
 	Point2I offset = getParent()->localToGlobalCoord(Point2I(0,0));
 	RectI rightRect = RectI( ( ( winRect.extent.x + winRect.point.x ) - mResizeRightWidth + offset.x), winRect.point.y + mTitleHeight + offset.y, mResizeRightWidth, winRect.extent.y );
 	RectI bottomRect = RectI( winRect.point.x + offset.x, ( ( winRect.point.y + winRect.extent.y ) - mResizeBottomHeight) + offset.y, winRect.extent.x , mResizeBottomHeight );

+ 49 - 34
engine/source/gui/guiControl.cc

@@ -305,10 +305,7 @@ void GuiControl::addObject(SimObject *object)
    if(mAwake)
       ctrl->awaken();
 
-  // If we are a child, notify our parent that we've been added
-  GuiControl *parent = ctrl->getParent();
-  if( parent )
-     parent->onChildAdded( ctrl );
+    onChildAdded( ctrl );
 }
 
 void GuiControl::removeObject(SimObject *object)
@@ -319,16 +316,14 @@ void GuiControl::removeObject(SimObject *object)
 		AssertWarn(0, "GuiControl::removeObject: attempted to remove NON GuiControl from set");
 		return;
 	}
-	GuiControl *parent = ctrl->getParent();
 
-   AssertFatal(mAwake == static_cast<GuiControl*>(object)->isAwake(), "GuiControl::removeObject: child control wake state is bad");
+   AssertFatal(mAwake == ctrl->isAwake(), "GuiControl::removeObject: child control wake state is bad");
    if (mAwake)
-      static_cast<GuiControl*>(object)->sleep();
+      ctrl->sleep();
     Parent::removeObject(object);
 
 	// If we are a child, notify our parent that we've been removed
-	if (parent)
-		parent->onChildRemoved(ctrl);
+	onChildRemoved(ctrl);
 }
 
 GuiControl *GuiControl::getParent()
@@ -416,13 +411,28 @@ void GuiControl::resize(const Point2I &newPosition, const Point2I &newExtent)
 
 	Point2I oldExtent = mBounds.extent;
 
+    //force center if using center positioning
+    Point2I actualNewPosition = Point2I(newPosition);
+    GuiControl* parent = getParent();
+    if (parent)
+    {
+        if (mHorizSizing == horizResizeCenter)
+        {
+            actualNewPosition.x = (parent->mBounds.extent.x - actualNewExtent.x) / 2;
+        }
+        if (mVertSizing == vertResizeCenter)
+        {
+            actualNewPosition.y = (parent->mBounds.extent.y - actualNewExtent.y) / 2;
+        }
+    }
+
    // only do the child control resizing stuff if you really need to.
    bool extentChanged = (actualNewExtent != oldExtent);
 
    if (extentChanged) {
       //call set update both before and after
       setUpdate();
-      mBounds.set(newPosition, actualNewExtent);
+      mBounds.set(actualNewPosition, actualNewExtent);
       iterator i;
       for(i = begin(); i != end(); i++)
       {
@@ -430,7 +440,6 @@ void GuiControl::resize(const Point2I &newPosition, const Point2I &newExtent)
          ctrl->parentResized(oldExtent - (ctrl->mRenderInsetLT + ctrl->mRenderInsetRB), actualNewExtent - (ctrl->mRenderInsetLT + ctrl->mRenderInsetRB));
       }
 
-      GuiControl *parent = getParent();
       if (parent)
          parent->childResized(this);
       setUpdate();
@@ -441,7 +450,7 @@ void GuiControl::resize(const Point2I &newPosition, const Point2I &newExtent)
 	  }
    }
    else {
-      mBounds.point = newPosition;
+      mBounds.point = actualNewPosition;
    }
 }
 void GuiControl::setPosition( const Point2I &newPosition )
@@ -552,29 +561,35 @@ Point2I GuiControl::extentBattery(Point2I &newExtent)
 	}
 
 	Point2I result = Point2I(newExtent);
-	if (newExtent.x < mBounds.extent.x && newExtent.x < mMinExtent.x)
-	{
-		mStoredExtent.x += mBounds.extent.x > mMinExtent.x ? (mMinExtent.x - newExtent.x) : (mBounds.extent.x - newExtent.x);
-		result.x = mMinExtent.x;
-	}
-	else if (newExtent.x > mBounds.extent.x && mStoredExtent.x > 0)
-	{
-		S32 charge = getMin(newExtent.x - mBounds.extent.x, mStoredExtent.x);
-		mStoredExtent.x -= charge;
-		result.x = newExtent.x - charge;
-	}
+    if (mHorizSizing != horizResizeRelative)
+    {
+        if (newExtent.x < mBounds.extent.x && newExtent.x < mMinExtent.x)
+        {
+            mStoredExtent.x += mBounds.extent.x > mMinExtent.x ? (mMinExtent.x - newExtent.x) : (mBounds.extent.x - newExtent.x);
+            result.x = mMinExtent.x;
+        }
+        else if (newExtent.x > mBounds.extent.x && mStoredExtent.x > 0)
+        {
+            S32 charge = getMin(newExtent.x - mBounds.extent.x, mStoredExtent.x);
+            mStoredExtent.x -= charge;
+            result.x = newExtent.x - charge;
+        }
+    }
 
-	if (newExtent.y < mBounds.extent.y && newExtent.y < mMinExtent.y)
-	{
-		mStoredExtent.y += mBounds.extent.y > mMinExtent.y ? (mMinExtent.y - newExtent.y) : (mBounds.extent.y - newExtent.y);
-		result.y = mMinExtent.y;
-	}
-	else if (newExtent.y > mBounds.extent.y && mStoredExtent.y > 0)
-	{
-		S32 charge = getMin(newExtent.y - mBounds.extent.y, mStoredExtent.y);
-		mStoredExtent.y -= charge;
-		result.y = newExtent.y - charge;
-	}
+    if (mVertSizing != vertResizeRelative)
+    {
+        if (newExtent.y < mBounds.extent.y && newExtent.y < mMinExtent.y)
+        {
+            mStoredExtent.y += mBounds.extent.y > mMinExtent.y ? (mMinExtent.y - newExtent.y) : (mBounds.extent.y - newExtent.y);
+            result.y = mMinExtent.y;
+        }
+        else if (newExtent.y > mBounds.extent.y && mStoredExtent.y > 0)
+        {
+            S32 charge = getMin(newExtent.y - mBounds.extent.y, mStoredExtent.y);
+            mStoredExtent.y -= charge;
+            result.y = newExtent.y - charge;
+        }
+    }
 	return result;
 }
 

+ 6 - 0
engine/source/gui/guiControl.h

@@ -327,6 +327,12 @@ public:
     inline void				 setTextExtend(const bool extend) { mTextExtend = extend; }
     inline bool				 getTextExtend() { return mTextExtend; }
 
+    const horizSizingOptions getHorizSizing() { return static_cast<horizSizingOptions>(mHorizSizing); }
+    const vertSizingOptions  getVertSizing() { return static_cast<vertSizingOptions>(mVertSizing); }
+
+    void                     setHorizSizing(const horizSizingOptions sizing) { mHorizSizing = sizing; }
+    void                     setVertSizing(const vertSizingOptions sizing) { mVertSizing = sizing; }
+
 	// Text Property Accessors
 	static bool setTextProperty(void* obj, const char* data) { static_cast<GuiControl*>(obj)->setText(data); return false; }
 	static const char* getTextProperty(void* obj, const char* data) { return static_cast<GuiControl*>(obj)->getText(); }

+ 1 - 1
engine/source/gui/guiTypes.h

@@ -61,7 +61,7 @@
 
 #include "graphics/gFont.h"
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 23 - 0
engine/source/math/mRandom.cc

@@ -181,4 +181,27 @@ U32 RandomR250::randI( void )
     return new_rand >> 1;
 }
 
+RandomPCG::RandomPCG()
+{
+    pcg32_srandom_r(&rng, generateSeed(), generateSeed());
+}
+
+RandomPCG::RandomPCG(const S32 seed)
+{
+    pcg32_srandom_r(&rng, seed, generateSeed());
+}
+
+RandomPCG::RandomPCG(const S32 seed, const S32 stream)
+{
+    pcg32_srandom_r(&rng, seed, stream);
+}
+
+void RandomPCG::setSeed(const S32 seed)
+{
+    pcg32_srandom_r(&rng, seed, generateSeed());
+}
 
+void RandomPCG::setSeed(const S32 seed, const S32 stream)
+{
+    pcg32_srandom_r(&rng, seed, stream);
+}

+ 32 - 0
engine/source/math/mRandom.h

@@ -27,6 +27,8 @@
 #include "platform/platform.h"
 #endif
 
+#include "algorithm/pcg_basic.h"
+
 //-----------------------------------------------------------------------------
 
 class RandomGeneratorBase
@@ -99,6 +101,36 @@ public:
 
 //-----------------------------------------------------------------------------
 
+
+//-----------------------------------------------------------------------------
+/// PCG Random Number Generator
+/// 
+/// Fast and statistically excellent random numbers
+///
+/// Period = 2^64
+///
+/// Copyright 2014 Melissa O'Neill <[email protected]>
+///
+/// Licensed under the Apache License, Version 2.0
+//-----------------------------------------------------------------------------
+class RandomPCG : public RandomGeneratorBase
+{
+private:
+    pcg32_random_t rng;
+
+public:
+    RandomPCG();
+    RandomPCG(const S32 seed);
+    RandomPCG(const S32 seed, const S32 stream);
+
+    void setSeed(const S32 seed);
+    void setSeed(const S32 seed, const S32 stream);
+    U32 randI(void) { return static_cast<U32>(pcg32_random_r(&rng)); }
+    U32 randI(U32 bound) { return static_cast<U32>(pcg32_boundedrand_r(&rng, static_cast<uint32_t>(bound))); }
+};
+
+//-----------------------------------------------------------------------------
+
 extern RandomLCG gRandGen;
 
 #endif //_MRANDOM_H_

+ 1 - 1
engine/source/math/noise/NoiseGenerator_ScriptBinding.h

@@ -23,7 +23,7 @@
 ConsoleMethodGroupBeginWithDocs(NoiseGenerator, ScriptObject)
 
 /*! Sets the seed for the noise generater.
-@param seed An interger seed value.
+@param seed An integer seed value.
 @return No return value.
 */
 ConsoleMethodWithDocs(NoiseGenerator, setSeed, ConsoleVoid, 3, 3, (int seed))

+ 72 - 0
engine/source/math/noise/RandomNumberGenerator.cc

@@ -0,0 +1,72 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _RANDOM_NUMBER_GENERATOR_H_
+#include "RandomNumberGenerator.h"
+#endif
+
+// Script bindings.
+#include "RandomNumberGenerator_ScriptBinding.h"
+
+//------------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(RandomNumberGenerator);
+
+//------------------------------------------------------------------------------
+
+RandomNumberGenerator::RandomNumberGenerator()
+{
+    mRNG = RandomPCG();
+}
+
+//------------------------------------------------------------------------------
+
+RandomNumberGenerator::~RandomNumberGenerator()
+{
+}
+
+//------------------------------------------------------------------------------
+
+void RandomNumberGenerator::setSeed(const U32 seed)
+{
+    mRNG.setSeed(seed);
+}
+
+void RandomNumberGenerator::setSeed(const U32 seed, const U32 stream)
+{
+    mRNG.setSeed(seed, stream);
+}
+
+U32 RandomNumberGenerator::getSeed()
+{
+    return mRNG.getSeed();
+}
+
+U32 RandomNumberGenerator::getRandom()
+{
+    return mRNG.randI();
+}
+
+U32 RandomNumberGenerator::getRandom(const U32 bound)
+{
+    return mRNG.randI(bound);
+}

+ 65 - 0
engine/source/math/noise/RandomNumberGenerator.h

@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _RANDOM_NUMBER_GENERATOR_H_
+#define _RANDOM_NUMBER_GENERATOR_H_
+
+#ifndef _MRANDOM_H_
+#include "math/mRandom.h"
+#endif
+
+#ifndef _SCRIPT_OBJECT_H_
+#include "sim/scriptObject.h"
+#endif
+
+#ifndef _UTILITY_H_
+#include "2d/core/Utility.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class RandomNumberGenerator : public ScriptObject
+{
+	typedef ScriptObject			Parent;
+
+private:
+	RandomPCG					mRNG;
+
+public:
+	RandomNumberGenerator();
+	virtual ~RandomNumberGenerator();
+
+	void setSeed(const U32 seed);
+	void setSeed(const U32 seed, const U32 stream);
+	U32 getSeed();
+	U32 getRandom();
+	U32 getRandom(const U32 bound);
+
+	/// Declare Console Object.
+	DECLARE_CONOBJECT(RandomNumberGenerator);
+
+private:
+
+protected:
+};
+
+#endif // _NOISE_GENERATOR_H_

+ 60 - 0
engine/source/math/noise/RandomNumberGenerator_ScriptBinding.h

@@ -0,0 +1,60 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+ConsoleMethodGroupBeginWithDocs(RandomNumberGenerator, ScriptObject)
+
+/*! Sets the seed and stream for the random number generater. Random values will always be the same for a seed/stream combination.
+@param seed An integer seed value.
+@param stream An optional integer value for the stream. If no stream is set a random stream value will be picked.
+@return No return value.
+*/
+ConsoleMethodWithDocs(RandomNumberGenerator, setSeed, ConsoleVoid, 3, 4, (int seed, [int stream]))
+{
+	if (argc == 3)
+	{
+		object->setSeed(dAtoi(argv[2]));
+	}
+	else if (argc == 4)
+	{
+		object->setSeed(dAtoi(argv[2]), dAtoi(argv[3]));
+	}
+}
+
+//------------------------------------------------------------------------------
+
+/*! Returns a random number integer value between 0 and an optional upper bound.
+* @param bound The optional value that the random number will be less than.
+@return A 32 bit number or a value where 0 <= number < bound.
+*/
+ConsoleMethodWithDocs(RandomNumberGenerator, getRandom, ConsoleFloat, 2, 3, ([int bound]))
+{
+	if (argc == 3)
+	{
+		return object->getRandom(dAtoi(argv[2]));
+	}
+	else
+	{
+		return object->getRandom();
+	}
+}
+
+ConsoleMethodGroupEndWithDocs(RandomNumberGenerator)

+ 1 - 1
engine/source/module/moduleManager.cc

@@ -565,7 +565,7 @@ bool ModuleManager::unloadModuleGroup( const char* pModuleGroup )
             if ( mEchoInfo )
             {
                 Con::printf( "Module Manager: Unloading group '%s' but could not unload module Id '%s' at version Id '%d'.",
-                    moduleGroup, pLoadedEntry->mpModuleDefinition->getModuleId(), pLoadedEntry->mpModuleDefinition->getVersionId() );
+                    moduleGroup, pLoadReadyModuleDefinition->getModuleId(), pLoadReadyModuleDefinition->getVersionId() );
             }
             // Skip.
             continue;

+ 1 - 1
engine/source/module/moduleManager.h

@@ -31,7 +31,7 @@
 #include "collection/vector.h"
 #endif
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 2 - 2
engine/source/persistence/taml/binary/tamlBinaryReader.h

@@ -23,7 +23,7 @@
 #ifndef _TAML_BINARYREADER_H_
 #define _TAML_BINARYREADER_H_
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 
@@ -33,7 +33,7 @@
 
 //-----------------------------------------------------------------------------
 
-/// @ingroup tamlGroup
+/// @ingroup tamlGroup
 /// @see tamlGroup
 class TamlBinaryReader
 {

+ 2 - 2
engine/source/persistence/taml/json/tamlJSONReader.h

@@ -23,7 +23,7 @@
 #ifndef _TAML_JSONREADER_H_
 #define _TAML_JSONREADER_H_
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 
@@ -37,7 +37,7 @@
 
 //-----------------------------------------------------------------------------
 
-/// @ingroup tamlGroup
+/// @ingroup tamlGroup
 /// @see tamlGroup
 class TamlJSONReader
 {

+ 1 - 1
engine/source/persistence/taml/taml.h

@@ -47,7 +47,7 @@
 #include "sim/simBase.h"
 #endif
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 

+ 2 - 2
engine/source/persistence/taml/xml/tamlXmlReader.h

@@ -23,7 +23,7 @@
 #ifndef _TAML_XMLREADER_H_
 #define _TAML_XMLREADER_H_
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #endif
 
@@ -37,7 +37,7 @@
 
 //-----------------------------------------------------------------------------
 
-/// @ingroup tamlGroup
+/// @ingroup tamlGroup
 /// @see tamlGroup
 class TamlXmlReader
 {

+ 1 - 1
engine/source/platform/platformFileIO.cc

@@ -345,7 +345,7 @@ StringTableEntry Platform::makeRelativePathName(const char *path, const char *to
       return StringTable->insert(buffer);
    }
 
-   if((*pathPtr == 0 && *toPtr == '/') || (*toPtr == '/' && *pathPtr == 0))
+   if(*toPtr == '/' && *pathPtr == 0)
       branch = pathPtr;
 
    // Figure out parent dirs

+ 2 - 2
engine/source/platform/platformString_ScriptBinding.h

@@ -347,7 +347,7 @@ ConsoleFunctionWithDocs( stripTrailingSpaces, ConsoleString, 2, 2, ( string ))
    S32 temp = S32(dStrlen( argv[1] ));
    if ( temp )
    {
-      while ( ( argv[1][temp - 1] == ' ' || argv[1][temp - 1] == '_' ) && temp >= 1 )
+      while ( temp >= 1 && ( argv[1][temp - 1] == ' ' || argv[1][temp - 1] == '_' ) )
          temp--;
 
       if ( temp )
@@ -362,4 +362,4 @@ ConsoleFunctionWithDocs( stripTrailingSpaces, ConsoleString, 2, 2, ( string ))
    return( "" );	
 }
 
-/*! @} */ // group StringFunctions
+/*! @} */ // group StringFunctions

+ 1 - 1
engine/source/platformWin32/winConsole_ScriptBinding.h

@@ -42,7 +42,7 @@ ConsoleFunctionWithDocs(enableWinConsole, ConsoleVoid, 2, 2, ( enable ))
 ConsoleFunctionWithDocs(getWinNTVersion, ConsoleVoid, 1, 1, ())
 {
 	std::string ver = getWinNTVersion();
-	Con::printf("%s", ver);
+	Con::printf("%s", ver.c_str());
 }
 
 /*! @} */ // end group WindowsPlatform

+ 2 - 2
engine/source/platformWin32/winDInputDevice.cc

@@ -991,7 +991,7 @@ bool DInputDevice::buildEvent( DWORD offset, S32 newData, S32 oldData )
                }
                if( clearkeys & POV_down)
                {
-                  newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV;
+                  newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV2;
                   
                   Game->postEvent(newEvent);
                }
@@ -1022,7 +1022,7 @@ bool DInputDevice::buildEvent( DWORD offset, S32 newData, S32 oldData )
                }
                if( setkeys & POV_down)
                {
-                  newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV;
+                  newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV2;
                   
                   Game->postEvent(newEvent);
                }

+ 6 - 5
engine/source/platformWin32/winFileio.cc

@@ -981,7 +981,8 @@ bool Platform::hasSubDirectory(const char *pPath)
             continue;
 
          Platform::clearExcludedDirectories();
-
+         FindClose(handle);
+         
          return true;
       }      
    }
@@ -1003,10 +1004,10 @@ static bool recurseDumpDirectories(const char *basePath, const char *subPath, Ve
    // Compose our search string - Format : ([path]/[subpath]/*)
    //-----------------------------------------------------------------------------
 
-   dsize_t trLen = basePath ? dStrlen(basePath) : 0;
-   dsize_t subtrLen = subPath ? dStrlen(subPath) : 0;
-   char trail = trLen > 0 ? basePath[trLen - 1] : '\0';
-   char subTrail = subtrLen > 0 ? subPath[subtrLen - 1] : '\0';
+   dsize_t trLen = basePath ? dStrlen(basePath) : 0;
+   dsize_t subtrLen = subPath ? dStrlen(subPath) : 0;
+   char trail = trLen > 0 ? basePath[trLen - 1] : '\0';
+   char subTrail = subtrLen > 0 ? subPath[subtrLen - 1] : '\0';
    char subLead = subtrLen > 0 ? subPath[0] : '\0';
 
    if (trail == '/')

+ 4 - 4
engine/source/platformWin32/winGLSpecial.cc

@@ -190,28 +190,28 @@ static const char * TypeToString( GLenum t )
 // GLU Log Functions
 static void APIENTRY loggluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top)
 {
-   fprintf(winState.log_fp, "gluOrtho2D( %d, %d, %d, %d )\n", left, right, bottom, top);
+   fprintf(winState.log_fp, "gluOrtho2D( %f, %f, %f, %f )\n", left, right, bottom, top);
    fflush(winState.log_fp);
    dllgluOrtho2D(left, right, bottom, top);
 }
 
 static void APIENTRY loggluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
 {
-   fprintf(winState.log_fp, "gluPerspective( %d, %d, %d, %d )\n", fovy, aspect, zNear, zFar);
+   fprintf(winState.log_fp, "gluPerspective( %f, %f, %f, %f )\n", fovy, aspect, zNear, zFar);
    fflush(winState.log_fp);
    dllgluPerspective(fovy, aspect, zNear, zFar);
 }
 
 static void APIENTRY loggluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height, GLint viewport[4])
 {
-   fprintf(winState.log_fp, "gluPickMatrix(%d, %d, %d, %d, VIEW)\n", x, y, width, height);
+   fprintf(winState.log_fp, "gluPickMatrix(%f, %f, %f, %f, VIEW)\n", x, y, width, height);
    fflush(winState.log_fp);
    dllgluPickMatrix(x, y, width, height, viewport);
 }
 
 static void APIENTRY loggluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz)
 {
-   fprintf(winState.log_fp, "gluLookAt(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n",eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz);
+   fprintf(winState.log_fp, "gluLookAt(%f, %f, %f, %f, %f, %f, %f, %f, %f)\n",eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz);
    fflush(winState.log_fp);
    dllgluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz);
 }

+ 0 - 2
engine/source/platformWin32/winGLSpecial_ScriptBinding.h

@@ -56,8 +56,6 @@ ConsoleFunctionWithDocs(GLEnableLogging, ConsoleVoid, 2, 2, ( enable ))
          time( &aclock );
          newtime = localtime( &aclock );
 
-         asctime( newtime );
-
          winState.log_fp = fopen( "gl_log.txt", "wt" );
 
          fprintf( winState.log_fp, "%s\n", asctime( newtime ) );

+ 3 - 1
library/AppCore/appCore.cs

@@ -26,10 +26,12 @@ function AppCore::create( %this )
     exec("./scripts/constants.cs");
     exec("./scripts/defaultPreferences.cs");
 	exec("./gui/guiProfiles.cs");
+	%this.createGuiProfiles();
     exec("./scripts/canvas.cs");
 
     // Initialize the canvas
-    %this.initializeCanvas(%this.Project);
+	%module = ModuleDatabase.findModule("AppCore", 1);
+    %this.initializeCanvas(%module.Project);
 
 	// Load other modules
     ModuleDatabase.loadGroup("launch");

+ 1 - 1
library/AppCore/gui/guiProfiles.cs

@@ -81,7 +81,7 @@ function AppCore::SafeCreateNamedObject(%this, %name, %object)
 	if(isObject(%name))
 	{
 		%originalObject = nameToID(%name);
-		if(%orginalObject.getClassName() !$= %object.getClassName())
+		if(%originalObject.getClassName() !$= %object.getClassName())
 		{
 			warn("Attempted to change the class of the named object " @ %name @ "!");
 			warn("Original Class: " @ %originalObject.getClassName());

+ 0 - 0
library/BlankGame/gui/images/torqueBG.asset.taml → library/BlankGame/gui/images/torqueBG.image.taml


+ 3 - 0
library/ScreenFade/gui/background.image.taml

@@ -0,0 +1,3 @@
+<ImageAsset
+    AssetName="background"
+    ImageFile="background.png" />

BIN
library/ScreenFade/gui/background.png


+ 15 - 0
library/ScreenFade/module.taml

@@ -0,0 +1,15 @@
+<ModuleDefinition
+	ModuleId="ScreenFade"
+	VersionId="1"
+	BuildID="5"
+	Synchronized="1"
+	Description="Switches the Canvas with a quick screen fade. Can be used for a temporary background for dialogs or windows."
+	Author="Torque2D"
+	ScriptFile="screenFade.cs"
+	CreateFunction="create"
+	DestroyFunction="destroy">
+		<DeclaredAssets
+			Path="gui"
+			Extension="image.taml"
+			Recurse="false"/>
+</ModuleDefinition>

+ 71 - 0
library/ScreenFade/screenFade.cs

@@ -0,0 +1,71 @@
+function ScreenFade::create(%this)
+{
+	exec("./scripts/ScreenFadeBackground.cs");
+
+	%this.background = new GuiSpriteCtrl() {
+		class = "ScreenFadeBackground";
+		profile = "GuiDefaultProfile";
+		HorizSizing = "relative";
+		VertSizing = "relative";
+		Position = "0 0";
+		Image = "ScreenFade:background";
+		FullSize = 1;
+		ConstrainProportions = 0;
+		ImageColor = "255 255 255 0";
+		Owner = %this;
+	};
+}
+
+function ScreenFade::destroy(%this)
+{
+	if(isObject(%this.background))
+	{
+		%this.background.delete();
+	}
+}
+
+//Switches the canvas by fading in to color and back out to the new content. The process takes the given time in milliseconds.
+//Color and time are optional.
+//ScreenFade will post event: onSwapComplete().
+function ScreenFade::swapCanvas(%this, %content, %color, %time)
+{
+	if(%color $= "")
+	{
+		%color = "0 0 0 0";
+	}
+
+	if(%time $= "")
+	{
+		%time = 1400;
+	}
+
+	%base = getWord(%color, 0) SPC getWord(%color, 1) SPC getWord(%color, 2);
+	%this.background.solidColor = %base SPC "255";
+	%this.background.transparentColor = %base SPC "0";
+	%this.background.swapContent = %content;
+	%this.background.swapTime = mRound((%time / 5) * 2);
+	%this.background.startSwap();
+}
+
+//Fades the screen to color and then puts the dialog on top of it.
+//Color and time are optional.
+//When your dialog closes, call %this.post("dialogClose"); to inform ScreenFade where %this is the same object passed to openDialog().
+//ScreenFade will post events: onOpenComplete() and onCloseComplete().
+function ScreenFade::openDialog(%this, %dialog, %color, %time)
+{
+	if(%color $= "")
+	{
+		%color = "0 0 0 230";
+	}
+
+	if(%time $= "")
+	{
+		%time = 300;
+	}
+
+	%this.background.solidColor = %color;
+	%this.background.transparentColor = getWord(%color, 0) SPC getWord(%color, 1) SPC getWord(%color, 2) SPC "0";
+	%this.background.dialog = %dialog;
+	%this.background.dialogTime = %time;
+	%this.background.openDialog();
+}

+ 75 - 0
library/ScreenFade/scripts/ScreenFadeBackground.cs

@@ -0,0 +1,75 @@
+function ScreenFadeBackground::resetColor(%this)
+{
+	if(getWord(%this.getImageColor(), 3) == 0)
+	{
+		%this.setImageColor(%this.transparentColor);
+		%extent = Canvas.getExtent();
+		%this.setExtent(getWord(%extent, 0), getWord(%extent, 1));
+	}
+}
+
+function ScreenFadeBackground::startSwap(%this)
+{
+	%this.resetColor();
+	Canvas.pushDialog(%this);
+	%this.fadeTo(%this.solidColor, %this.swapTime, "EaseInOut");
+	%this.schedule(%this.swapTime, "doSwap");
+}
+
+function ScreenFadeBackground::doSwap(%this)
+{
+	Canvas.setContent(%this.swapContent);
+	Canvas.pushDialog(%this);
+	%this.schedule(%this.swapTime/2, "fadeSwap");
+}
+
+function ScreenFadeBackground::fadeSwap(%this)
+{
+	%this.fadeTo(%this.transparentColor, %this.swapTime, "EaseInOut");
+	%this.schedule(%this.swapTime, "finishSwap");
+}
+
+function ScreenFadeBackground::finishSwap(%this)
+{
+	Canvas.popDialog(%this);
+	%this.Owner.postEvent("SwapComplete");
+}
+
+function ScreenFadeBackground::openDialog(%this)
+{
+	%this.resetColor();
+	%this.add(%this.dialog);
+	Canvas.pushDialog(%this);
+	%this.fadeTo(%this.solidColor, %this.dialogTime, "EaseInOut");
+	%this.schedule(%this.dialogTime, "openDialogComplete");
+}
+
+function ScreenFadeBackground::openDialogComplete(%this)
+{
+	%this.Owner.postEvent("OpenComplete");
+	%this.startListening(%this.dialog);
+}
+
+function ScreenFadeBackground::onDialogClose(%this)
+{
+	if(%this.isAwake())
+	{
+		if(isEventPending(%this.hideSchedule))
+		{
+			cancel(%this.hideSchedule);
+		}
+		%this.fadeTo(%this.transparentColor, %this.dialogTime, "EaseIn");
+		%this.hideSchedule = %this.schedule(%this.dialogTime, "onCloseComplete");
+	}
+}
+
+function ScreenFadeBackground::onCloseComplete(%this)
+{
+	if(isObject(%this.dialog))
+	{
+		%this.stopListening(%this.dialog);
+		%this.removeIfMember(%this.dialog);
+	}
+	Canvas.popDialog(%this);
+	%this.Owner.postEvent("CloseComplete");
+}