Browse Source

Merge pull request #65 from TorqueGameEngines/development

T2D 4.0.0 Early Access 2.1
Peter Robinson 2 years ago
parent
commit
2c555d6dd0
93 changed files with 2500 additions and 253 deletions
  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:
 jobs:
   Build-Windows-32bit-VS2019:
   Build-Windows-32bit-VS2019:
     name: 32-bit Windows On VS2019
     name: 32-bit Windows On VS2019
-    runs-on: windows-latest
+    runs-on: windows-2019
     steps:
     steps:
       - uses: actions/checkout@v2
       - uses: actions/checkout@v2
       - uses: microsoft/[email protected]
       - uses: microsoft/[email protected]
@@ -20,7 +20,7 @@ jobs:
             ! engine/
             ! engine/
   Build-Windows-64bit-VS2019:
   Build-Windows-64bit-VS2019:
     name: 64-bit Windows On VS2019
     name: 64-bit Windows On VS2019
-    runs-on: windows-latest
+    runs-on: windows-2019
     steps:
     steps:
       - uses: actions/checkout@v2
       - uses: actions/checkout@v2
       - uses: microsoft/[email protected]
       - 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");
 	%this.emitterGraphPage = %this.createTabPage("Emitter Graph", "AssetParticleGraphEmitterTool", "AssetParticleGraphTool");
 
 
 	//Image Frame Edit Tool
 	//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)
 function AssetInspector::createTabPage(%this, %name, %class, %superClass)
@@ -205,6 +208,8 @@ function AssetInspector::resetInspector(%this)
 	%this.tabBook.selectPage(0);
 	%this.tabBook.selectPage(0);
 	%this.tabBook.removeIfMember(%this.scaleGraphPage);
 	%this.tabBook.removeIfMember(%this.scaleGraphPage);
 	%this.tabBook.removeIfMember(%this.emitterGraphPage);
 	%this.tabBook.removeIfMember(%this.emitterGraphPage);
+	%this.tabBook.removeIfMember(%this.imageFrameEditPage);
+	%this.tabBook.removeIfMember(%this.imageLayersEditPage);
 
 
 	%this.emitterButtonBar.visible = false;
 	%this.emitterButtonBar.visible = false;
 	%this.deleteAssetButton.visible = true;
 	%this.deleteAssetButton.visible = true;
@@ -214,6 +219,7 @@ function AssetInspector::loadImageAsset(%this, %imageAsset, %assetID)
 {
 {
 	%this.resetInspector();
 	%this.resetInspector();
 	%this.tabBook.add(%this.imageFrameEditPage);
 	%this.tabBook.add(%this.imageFrameEditPage);
+	%this.tabBook.add(%this.imageLayersEditPage);
 	%this.tabBook.selectPage(0);
 	%this.tabBook.selectPage(0);
 	%this.titlebar.setText("Image Asset:" SPC %imageAsset.AssetName);
 	%this.titlebar.setText("Image Asset:" SPC %imageAsset.AssetName);
 
 
@@ -227,6 +233,7 @@ function AssetInspector::loadImageAsset(%this, %imageAsset, %assetID)
 	%this.inspector.openGroupByIndex(0);
 	%this.inspector.openGroupByIndex(0);
 
 
 	%this.imageFrameEditPage.inspect(%imageAsset);
 	%this.imageFrameEditPage.inspect(%imageAsset);
+	%this.imageLayersEditPage.inspect(%imageAsset);
 }
 }
 
 
 function AssetInspector::loadAnimationAsset(%this, %animationAsset, %assetID)
 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("./AssetImageFrameEditTool.cs");
 exec("./AssetImageFrameEditRow.cs");
 exec("./AssetImageFrameEditRow.cs");
 exec("./AssetImageFrameHeaderRow.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))
 	if(isObject(%name))
 	{
 	{
 		%originalObject = nameToID(%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("Attempted to change the class of the named object " @ %name @ "!");
 			warn("Original Class: " @ %originalObject.getClassName());
 			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") + \
 2D_SOURCES :=            $(shell find ../../source/2d/ -name "*.cc") + \
 						 $(shell find ../../source/2d/ -name "*.cpp")
 						 $(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")
 ASSETS_SOURCES :=        $(shell find ../../source/assets/ -name "*.cc")
 AUDIO_SOURCES :=         $(shell find ../../source/audio/ -name "*.cc")
 AUDIO_SOURCES :=         $(shell find ../../source/audio/ -name "*.cc")
 BITMAPFONT_SOURCES :=    $(shell find ../../source/bitmapFont/ -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") + \
 2D_SOURCES :=            $(shell find ../../source/2d/ -name "*.cc") + \
 						 $(shell find ../../source/2d/ -name "*.cpp")
 						 $(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")
 ASSETS_SOURCES :=        $(shell find ../../source/assets/ -name "*.cc")
 AUDIO_SOURCES :=         $(shell find ../../source/audio/ -name "*.cc")
 AUDIO_SOURCES :=         $(shell find ../../source/audio/ -name "*.cc")
 BITMAPFONT_SOURCES :=    $(shell find ../../source/bitmapFont/ -name "*.cc")
 BITMAPFONT_SOURCES :=    $(shell find ../../source/bitmapFont/ -name "*.cc")
@@ -63,7 +64,7 @@ SOURCES := $(2D_SOURCES) + \
 LDFLAGS := -g -m64
 LDFLAGS := -g -m64
 LDLIBS := -lstdc++ -lm -ldl -lpthread -lrt -lX11 -lXft -lSDL -lopenal
 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
 CFLAGS += -I/usr/include/freetype2
 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\2d\scene\WorldQuery.cc" />
     <ClCompile Include="..\..\source\algorithm\crc.cc" />
     <ClCompile Include="..\..\source\algorithm\crc.cc" />
     <ClCompile Include="..\..\source\algorithm\hashFunction.cc" />
     <ClCompile Include="..\..\source\algorithm\hashFunction.cc" />
+    <ClCompile Include="..\..\source\algorithm\pcg_basic.c" />
     <ClCompile Include="..\..\source\algorithm\Perlin.cc" />
     <ClCompile Include="..\..\source\algorithm\Perlin.cc" />
     <ClCompile Include="..\..\source\assets\assetBase.cc" />
     <ClCompile Include="..\..\source\assets\assetBase.cc" />
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
@@ -677,6 +678,7 @@
     <ClCompile Include="..\..\source\math\mFluid.cpp" />
     <ClCompile Include="..\..\source\math\mFluid.cpp" />
     <ClCompile Include="..\..\source\math\mPoint.cpp" />
     <ClCompile Include="..\..\source\math\mPoint.cpp" />
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc" />
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc" />
+    <ClCompile Include="..\..\source\math\noise\RandomNumberGenerator.cc" />
     <ClCompile Include="..\..\source\math\rectClipper.cpp" />
     <ClCompile Include="..\..\source\math\rectClipper.cpp" />
     <ClCompile Include="..\..\source\memory\dataChunker.cc" />
     <ClCompile Include="..\..\source\memory\dataChunker.cc" />
     <ClCompile Include="..\..\source\memory\frameAllocator_ScriptBinding.cc" />
     <ClCompile Include="..\..\source\memory\frameAllocator_ScriptBinding.cc" />
@@ -940,6 +942,7 @@
     <ClInclude Include="..\..\source\algorithm\crctab.h" />
     <ClInclude Include="..\..\source\algorithm\crctab.h" />
     <ClInclude Include="..\..\source\algorithm\hashFunction.h" />
     <ClInclude Include="..\..\source\algorithm\hashFunction.h" />
     <ClInclude Include="..\..\source\algorithm\md5.h" />
     <ClInclude Include="..\..\source\algorithm\md5.h" />
+    <ClInclude Include="..\..\source\algorithm\pcg_basic.h" />
     <ClInclude Include="..\..\source\algorithm\Perlin.h" />
     <ClInclude Include="..\..\source\algorithm\Perlin.h" />
     <ClInclude Include="..\..\source\assets\assetBase.h" />
     <ClInclude Include="..\..\source\assets\assetBase.h" />
     <ClInclude Include="..\..\source\assets\assetBase_ScriptBinding.h" />
     <ClInclude Include="..\..\source\assets\assetBase_ScriptBinding.h" />
@@ -1182,6 +1185,8 @@
     <ClInclude Include="..\..\source\math\mNormalDistribution.h" />
     <ClInclude Include="..\..\source\math\mNormalDistribution.h" />
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator.h" />
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator.h" />
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator_ScriptBinding.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\random_ScriptBinding.h" />
     <ClInclude Include="..\..\source\math\rectClipper.h" />
     <ClInclude Include="..\..\source\math\rectClipper.h" />
     <ClInclude Include="..\..\source\math\vector_ScriptBinding.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">
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc">
       <Filter>math\noise</Filter>
       <Filter>math\noise</Filter>
     </ClCompile>
     </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>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -3058,6 +3064,15 @@
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator_ScriptBinding.h">
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator_ScriptBinding.h">
       <Filter>math\noise</Filter>
       <Filter>math\noise</Filter>
     </ClInclude>
     </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>
   <ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Torque 2D.rc" />
     <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
 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
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Torque2D", "Torque 2D.vcxproj", "{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}"
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Torque2D", "Torque 2D.vcxproj", "{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}"
 	ProjectSection(ProjectDependencies) = postProject
 	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>
     <ProjectGuid>{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}</ProjectGuid>
     <RootNamespace>TorqueGame</RootNamespace>
     <RootNamespace>TorqueGame</RootNamespace>
     <ProjectName>Torque2D</ProjectName>
     <ProjectName>Torque2D</ProjectName>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <ConfigurationType>Application</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   <ImportGroup Label="ExtensionSettings">
@@ -117,6 +117,10 @@
     <OutDir>../../../</OutDir>
     <OutDir>../../../</OutDir>
     <IntDir>../../Link/VC2012.$(Configuration).$(PlatformName)/$(ProjectName)/</IntDir>
     <IntDir>../../Link/VC2012.$(Configuration).$(PlatformName)/$(ProjectName)/</IntDir>
   </PropertyGroup>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>../../../</OutDir>
+    <IntDir>../../Link/VC2012.$(Configuration).$(PlatformName)/$(ProjectName)/</IntDir>
+  </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <Midl>
     <Midl>
       <TypeLibraryName>$(OutDir)Torque2D.tlb</TypeLibraryName>
       <TypeLibraryName>$(OutDir)Torque2D.tlb</TypeLibraryName>
@@ -143,7 +147,7 @@
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
       <ShowIncludes>false</ShowIncludes>
       <ShowIncludes>false</ShowIncludes>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     </ClCompile>
     <ResourceCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -193,7 +197,7 @@
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
       <ShowIncludes>false</ShowIncludes>
       <ShowIncludes>false</ShowIncludes>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     </ClCompile>
     <ResourceCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -243,7 +247,7 @@
       <CompileAs>CompileAsCpp</CompileAs>
       <CompileAs>CompileAsCpp</CompileAs>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     </ClCompile>
     <ResourceCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -304,7 +308,7 @@
       <CompileAs>CompileAsCpp</CompileAs>
       <CompileAs>CompileAsCpp</CompileAs>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     </ClCompile>
     <ResourceCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -364,7 +368,7 @@
       <CompileAs>CompileAsCpp</CompileAs>
       <CompileAs>CompileAsCpp</CompileAs>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     </ClCompile>
     <ResourceCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -425,7 +429,7 @@
       <CompileAs>CompileAsCpp</CompileAs>
       <CompileAs>CompileAsCpp</CompileAs>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
       <DisableSpecificWarnings>4800;4100;4127;4512</DisableSpecificWarnings>
-      <LanguageStandard>stdcpp14</LanguageStandard>
+      <ConformanceMode>true</ConformanceMode>
     </ClCompile>
     </ClCompile>
     <ResourceCompile>
     <ResourceCompile>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -512,6 +516,7 @@
     <ClCompile Include="..\..\source\2d\scene\WorldQuery.cc" />
     <ClCompile Include="..\..\source\2d\scene\WorldQuery.cc" />
     <ClCompile Include="..\..\source\algorithm\crc.cc" />
     <ClCompile Include="..\..\source\algorithm\crc.cc" />
     <ClCompile Include="..\..\source\algorithm\hashFunction.cc" />
     <ClCompile Include="..\..\source\algorithm\hashFunction.cc" />
+    <ClCompile Include="..\..\source\algorithm\pcg_basic.c" />
     <ClCompile Include="..\..\source\algorithm\Perlin.cc" />
     <ClCompile Include="..\..\source\algorithm\Perlin.cc" />
     <ClCompile Include="..\..\source\assets\assetBase.cc" />
     <ClCompile Include="..\..\source\assets\assetBase.cc" />
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
@@ -673,6 +678,7 @@
     <ClCompile Include="..\..\source\math\mFluid.cpp" />
     <ClCompile Include="..\..\source\math\mFluid.cpp" />
     <ClCompile Include="..\..\source\math\mPoint.cpp" />
     <ClCompile Include="..\..\source\math\mPoint.cpp" />
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc" />
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc" />
+    <ClCompile Include="..\..\source\math\noise\RandomNumberGenerator.cc" />
     <ClCompile Include="..\..\source\math\rectClipper.cpp" />
     <ClCompile Include="..\..\source\math\rectClipper.cpp" />
     <ClCompile Include="..\..\source\memory\dataChunker.cc" />
     <ClCompile Include="..\..\source\memory\dataChunker.cc" />
     <ClCompile Include="..\..\source\memory\frameAllocator_ScriptBinding.cc" />
     <ClCompile Include="..\..\source\memory\frameAllocator_ScriptBinding.cc" />
@@ -936,6 +942,7 @@
     <ClInclude Include="..\..\source\algorithm\crctab.h" />
     <ClInclude Include="..\..\source\algorithm\crctab.h" />
     <ClInclude Include="..\..\source\algorithm\hashFunction.h" />
     <ClInclude Include="..\..\source\algorithm\hashFunction.h" />
     <ClInclude Include="..\..\source\algorithm\md5.h" />
     <ClInclude Include="..\..\source\algorithm\md5.h" />
+    <ClInclude Include="..\..\source\algorithm\pcg_basic.h" />
     <ClInclude Include="..\..\source\algorithm\Perlin.h" />
     <ClInclude Include="..\..\source\algorithm\Perlin.h" />
     <ClInclude Include="..\..\source\assets\assetBase.h" />
     <ClInclude Include="..\..\source\assets\assetBase.h" />
     <ClInclude Include="..\..\source\assets\assetBase_ScriptBinding.h" />
     <ClInclude Include="..\..\source\assets\assetBase_ScriptBinding.h" />
@@ -1178,6 +1185,8 @@
     <ClInclude Include="..\..\source\math\mNormalDistribution.h" />
     <ClInclude Include="..\..\source\math\mNormalDistribution.h" />
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator.h" />
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator.h" />
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator_ScriptBinding.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\random_ScriptBinding.h" />
     <ClInclude Include="..\..\source\math\rectClipper.h" />
     <ClInclude Include="..\..\source\math\rectClipper.h" />
     <ClInclude Include="..\..\source\math\vector_ScriptBinding.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>
       <UniqueIdentifier>{598766e4-7dc1-45b8-8acf-f133f4fced82}</UniqueIdentifier>
     </Filter>
     </Filter>
     <Filter Include="math\noise">
     <Filter Include="math\noise">
-      <UniqueIdentifier>{1ca99a8e-9e94-4ab8-996e-b4835a603512}</UniqueIdentifier>
+      <UniqueIdentifier>{1a2a7ebc-eda6-4a67-b9ab-bc9f437b5d5c}</UniqueIdentifier>
     </Filter>
     </Filter>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
@@ -1336,6 +1336,12 @@
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc">
     <ClCompile Include="..\..\source\math\noise\NoiseGenerator.cc">
       <Filter>math\noise</Filter>
       <Filter>math\noise</Filter>
     </ClCompile>
     </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>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -3058,6 +3064,15 @@
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator_ScriptBinding.h">
     <ClInclude Include="..\..\source\math\noise\NoiseGenerator_ScriptBinding.h">
       <Filter>math\noise</Filter>
       <Filter>math\noise</Filter>
     </ClInclude>
     </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>
   <ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Torque 2D.rc" />
     <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>
     <ProjectGuid>{15CBFEFF-7965-41F5-B4E2-21E8795C9159}</ProjectGuid>
     <RootNamespace>libogg</RootNamespace>
     <RootNamespace>libogg</RootNamespace>
     <Keyword>Win32Proj</Keyword>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <CharacterSet>Unicode</CharacterSet>
     <WholeProgramOptimization>false</WholeProgramOptimization>
     <WholeProgramOptimization>false</WholeProgramOptimization>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <CharacterSet>Unicode</CharacterSet>
-    <WholeProgramOptimization>false</WholeProgramOptimization>
-    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   <ImportGroup Label="ExtensionSettings">
@@ -79,8 +79,8 @@
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\../../Link/Debug/libogg\</IntDir>
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\../../Link/Debug/libogg\</IntDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\../../Link/Release\</OutDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\../../Link/Release\</OutDir>
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\../../Link/Release/libogg\</IntDir>
     <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>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <TargetName>$(ProjectName)_DEBUG</TargetName>
     <TargetName>$(ProjectName)_DEBUG</TargetName>
@@ -171,16 +171,12 @@
       <BufferSecurityCheck>false</BufferSecurityCheck>
       <BufferSecurityCheck>false</BufferSecurityCheck>
       <PrecompiledHeader>
       <PrecompiledHeader>
       </PrecompiledHeader>
       </PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
+      <WarningLevel>Level4</WarningLevel>
       <DebugInformationFormat>
       <DebugInformationFormat>
       </DebugInformationFormat>
       </DebugInformationFormat>
       <CompileAs>CompileAsC</CompileAs>
       <CompileAs>CompileAsC</CompileAs>
       <DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <CallingConvention>Cdecl</CallingConvention>
       <CallingConvention>Cdecl</CallingConvention>
-      <AssemblerListingLocation>.\../../Link/Release/libogg/</AssemblerListingLocation>
-      <ObjectFileName>.\../../Link/Release/libogg/</ObjectFileName>
-      <ProgramDataBaseFileName>.\../../Link/Release/libogg/</ProgramDataBaseFileName>
-      <OmitFramePointers>false</OmitFramePointers>
     </ClCompile>
     </ClCompile>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <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>
     <ProjectGuid>{3A214E06-B95E-4D61-A291-1F8DF2EC10FD}</ProjectGuid>
     <RootNamespace>libvorbis</RootNamespace>
     <RootNamespace>libvorbis</RootNamespace>
     <Keyword>Win32Proj</Keyword>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <CharacterSet>Unicode</CharacterSet>
     <WholeProgramOptimization>false</WholeProgramOptimization>
     <WholeProgramOptimization>false</WholeProgramOptimization>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <CharacterSet>Unicode</CharacterSet>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
     <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   <ImportGroup Label="ExtensionSettings">
@@ -75,8 +75,8 @@
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\../../Link/Debug/libvorbis\</IntDir>
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\../../Link/Debug/libvorbis\</IntDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\../../Link/Release\</OutDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\../../Link/Release\</OutDir>
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\../../Link/Release/libvorbis\</IntDir>
     <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>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <TargetName>$(ProjectName)_DEBUG</TargetName>
     <TargetName>$(ProjectName)_DEBUG</TargetName>

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

@@ -28,38 +28,38 @@
   </ItemGroup>
   </ItemGroup>
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{0B07BA94-AA53-4FD4-ADB4-79EC2DA53B36}</ProjectGuid>
     <ProjectGuid>{0B07BA94-AA53-4FD4-ADB4-79EC2DA53B36}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   <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>
   </ItemGroup>
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{AF1179E3-A838-46A3-A427-1E62AA4C52F4}</ProjectGuid>
     <ProjectGuid>{AF1179E3-A838-46A3-A427-1E62AA4C52F4}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   <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>
   </ItemGroup>
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{86CB2525-0CF3-40D3-BF42-A0A95035EE8C}</ProjectGuid>
     <ProjectGuid>{86CB2525-0CF3-40D3-BF42-A0A95035EE8C}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Shipping|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseOfMfc>false</UseOfMfc>
     <UseOfMfc>false</UseOfMfc>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   <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 cellHeightName              = StringTable->insert( "Height" );
 static StringTableEntry cellNameEntryName           = StringTable->insert( "Name" );
 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[] =
 static EnumTable::Enums textureFilterLookup[] =
@@ -174,11 +180,14 @@ ImageAsset::ImageAsset() :  mImageFile(StringTable->EmptyString),
                             mCellWidth(0),
                             mCellWidth(0),
                             mCellHeight(0),
                             mCellHeight(0),
 
 
+                            mBlendColor(1.0f, 1.0f, 1.0f),
+
                             mImageTextureHandle(NULL)
                             mImageTextureHandle(NULL)
 {
 {
     // Set Vector Associations.
     // Set Vector Associations.
     VECTOR_SET_ASSOCIATION( mFrames );
     VECTOR_SET_ASSOCIATION( mFrames );
     VECTOR_SET_ASSOCIATION( mExplicitFrames );
     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("FilterMode", TypeEnum, Offset(mLocalFilterMode, ImageAsset), &setFilterMode, &defaultProtectedGetFn, &writeFilterMode, 1, &textureFilterTable);   
     addProtectedField("ExplicitMode", TypeBool, Offset(mExplicitMode, ImageAsset), &setExplicitMode, &defaultProtectedGetFn, &writeExplicitMode, "");
     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("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");
     endGroup("Image Fields");
 
 
     addGroup("X Values");
     addGroup("X Values");
@@ -1069,8 +1079,18 @@ void ImageAsset::initializeAsset( void )
     // Ensure the image-file is expanded.
     // Ensure the image-file is expanded.
     mImageFile = expandAssetFilePath( mImageFile );
     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.
     // Calculate the image.
     calculateImage();
     calculateImage();
+
+    // Redraw the image.
+    redrawImage();
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -1086,6 +1106,9 @@ void ImageAsset::onAssetRefresh( void )
     
     
     // Compile image.
     // Compile image.
     calculateImage();
     calculateImage();
+
+    // Redraw the image.
+    redrawImage();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -1126,7 +1149,7 @@ void ImageAsset::calculateImage( void )
         TextureManager::refresh( mImageFile );
         TextureManager::refresh( mImageFile );
 
 
     // Get image texture.
     // 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?
     // Is the texture valid?
     if ( mImageTextureHandle.IsNull() )
     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 )
 bool ImageAsset::setFilterMode( void* obj, const char* data )
@@ -1385,6 +1449,233 @@ bool ImageAsset::setFilterMode( void* obj, const char* data )
     return false;
     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 )
 void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
@@ -1395,11 +1686,7 @@ void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
     // Call parent.
     // Call parent.
     Parent::onTamlCustomWrite( customNodes );
     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.
         // Add cell custom node.
         TamlCustomNode* pCustomCellNodes = customNodes.addNode( cellCustomNodeCellsName );
         TamlCustomNode* pCustomCellNodes = customNodes.addNode( cellCustomNodeCellsName );
@@ -1420,18 +1707,42 @@ void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
             pCellNode->addField( cellHeightName, pixelArea.mPixelHeight );
             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.
     // Debug Profiling.
     PROFILE_SCOPE(ImageAsset_OnTamlCustomRead);
     PROFILE_SCOPE(ImageAsset_OnTamlCustomRead);
-    
+
     // Call parent.
     // 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.
     // Find cell custom node.
     const TamlCustomNode* pCustomCellNodes = customNodes.findNode( cellCustomNodeCellsName );
     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 )
 static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
@@ -1564,6 +1953,8 @@ static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlEleme
 
 
     char buffer[1024];
     char buffer[1024];
 
 
+    //---Cells---
+
     // Create ImageAsset node element.
     // Create ImageAsset node element.
     TiXmlElement* pImageAssetNodeElement = new TiXmlElement( "xs:element" );
     TiXmlElement* pImageAssetNodeElement = new TiXmlElement( "xs:element" );
     dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), cellCustomNodeCellsName );
     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( "name", cellHeightName );
     pImageAssetHeight->SetAttribute( "type", "xs:unsignedInt" );
     pImageAssetHeight->SetAttribute( "type", "xs:unsignedInt" );
     pImageAssetComplexTypeElement->LinkEndChild( pImageAssetHeight );
     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;
         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:
 private:
     typedef Vector<FrameArea> typeFrameAreaVector;
     typedef Vector<FrameArea> typeFrameAreaVector;
     typedef Vector<FrameArea::PixelArea> typeExplicitFrameAreaVector;
     typedef Vector<FrameArea::PixelArea> typeExplicitFrameAreaVector;
+    typedef Vector<ImageLayer> typeImageLayerVector;
 
 
     /// Configuration.
     /// Configuration.
     StringTableEntry            mImageFile;
     StringTableEntry            mImageFile;
@@ -181,6 +204,8 @@ private:
     typeFrameAreaVector         mFrames;
     typeFrameAreaVector         mFrames;
     typeExplicitFrameAreaVector mExplicitFrames;
     typeExplicitFrameAreaVector mExplicitFrames;
     TextureHandle               mImageTextureHandle;
     TextureHandle               mImageTextureHandle;
+    typeImageLayerVector        mImageLayers;
+    ColorF                      mBlendColor;
 
 
 public:
 public:
     ImageAsset();
     ImageAsset();
@@ -194,6 +219,7 @@ public:
 
 
     void                    setImageFile( const char* pImageFile );
     void                    setImageFile( const char* pImageFile );
     inline StringTableEntry getImageFile( void ) const                      { return mImageFile; };
     inline StringTableEntry getImageFile( void ) const                      { return mImageFile; };
+    inline StringTableEntry getRelativeImageFile(void) const { return collapseAssetFilePath(mImageFile); };
 
 
     void                    setForce16Bit( const bool force16Bit );
     void                    setForce16Bit( const bool force16Bit );
     inline bool             getForce16Bit( void ) const                     { return mForce16Bit; }
     inline bool             getForce16Bit( void ) const                     { return mForce16Bit; }
@@ -267,6 +293,26 @@ public:
     
     
     inline void forceCalculation( void ) { calculateImage(); }
     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 Console Object.
     DECLARE_CONOBJECT(ImageAsset);
     DECLARE_CONOBJECT(ImageAsset);
 
 
@@ -277,6 +323,9 @@ private:
     void calculateExplicitMode( void );
     void calculateExplicitMode( void );
     void setTextureFilter( const TextureFilterMode filterMode );
     void setTextureFilter( const TextureFilterMode filterMode );
 
 
+    void completeLayerChange(const bool doRedraw);
+    void redrawImage();
+
 protected:
 protected:
     virtual void initializeAsset( void );
     virtual void initializeAsset( void );
     virtual void onAssetRefresh( void );
     virtual void onAssetRefresh( void );
@@ -287,6 +336,9 @@ protected:
     virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
     virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
     virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
     virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 
+    virtual void loadTamlExplicitCells(const TamlCustomNodes& customNodes);
+    virtual void loadTamlImageLayers(const TamlCustomNodes& customNodes);
+
 
 
 protected:
 protected:
     static void textureEventCallback( const U32 eventCode, void *userData );
     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 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 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.
 /*! 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, ())
 ConsoleMethodWithDocs(ImageAsset, getImageFile, ConsoleString, 2, 2, ())
 {
 {
     return object->getImageFile();
     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.
 /*! Sets the filter mode.
@@ -602,4 +612,427 @@ ConsoleMethodWithDocs(ImageAsset, setExplicitMode, ConsoleVoid, 3, 3, (explicitM
     object->setExplicitMode(dAtob(argv[2]));
     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)
 ConsoleMethodGroupEndWithDocs(ImageAsset)

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

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

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

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

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

@@ -382,10 +382,8 @@ bool EditorToySceneWindow::initCursors()
       mLeftRightCursor = dynamic_cast<GuiCursor*>(obj);
       mLeftRightCursor = dynamic_cast<GuiCursor*>(obj);
       obj = Sim::findObject("DefaultCursor");
       obj = Sim::findObject("DefaultCursor");
       mDefaultCursor = dynamic_cast<GuiCursor*>(obj);
       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
    else
       return(true);
       return(true);

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

@@ -67,6 +67,7 @@ GuiSpriteCtrl::GuiSpriteCtrl( void ) :
 	mImageSize.set(10, 10);
 	mImageSize.set(10, 10);
 	mFullSize = true;
 	mFullSize = true;
 	mConstrainProportions = true;
 	mConstrainProportions = true;
+	mClampImage = true;
 	mSingleFrameBitmap = true;
 	mSingleFrameBitmap = true;
 }
 }
 
 
@@ -95,6 +96,7 @@ void GuiSpriteCtrl::initPersistFields()
 	addField("imageColor", TypeFluidColorI, Offset(mImageColor, GuiSpriteCtrl));
 	addField("imageColor", TypeFluidColorI, Offset(mImageColor, GuiSpriteCtrl));
 	addField("imageSize", TypePoint2I, Offset(mImageSize, GuiSpriteCtrl));
 	addField("imageSize", TypePoint2I, Offset(mImageSize, GuiSpriteCtrl));
 	addField("fullSize", TypeBool, Offset(mFullSize, GuiSpriteCtrl));
 	addField("fullSize", TypeBool, Offset(mFullSize, GuiSpriteCtrl));
+	addField("clampImage", TypeBool, Offset(mClampImage, GuiSpriteCtrl));
 	addField("constrainProportions", TypeBool, Offset(mConstrainProportions, GuiSpriteCtrl));
 	addField("constrainProportions", TypeBool, Offset(mConstrainProportions, GuiSpriteCtrl));
 	endGroup("GuiSpriteCtrl");
 	endGroup("GuiSpriteCtrl");
 }
 }
@@ -348,10 +350,18 @@ Point2I GuiSpriteCtrl::applyAlignment(RectI &bounds, Point2I &size)
 	}
 	}
 
 
 	//Apply the image offset
 	//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;
 	return offset;
 }
 }
@@ -546,50 +556,52 @@ void GuiSpriteCtrl::onRender(Point2I offset, const RectI &updateRect)
 			dglSetClipRect(clipRect);
 			dglSetClipRect(clipRect);
 			dglSetBitmapModulation(ColorF(mImageColor));
 			dglSetBitmapModulation(ColorF(mImageColor));
 
 
-			Point2I offset = Point2I(0, 0);
+			Point2I imageOffset = Point2I(0, 0);
 			Point2I size = constrain(mImageSize);
 			Point2I size = constrain(mImageSize);
 
 
 			if (mTileImage) //Tile the image
 			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
 			else if (mFullSize) //Fill with the image
 			{
 			{
 				size = constrain(contentRect.extent, false);
 				size = constrain(contentRect.extent, false);
 				if (mConstrainProportions)
 				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
 			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();
 			dglClearBitmapModulation();
 			dglSetClipRect(oldClip);
 			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
 	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 mFullSize; //If true, the image will take all available space
 	bool mConstrainProportions; //If true, the image will maintain its aspect ratio 
 	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
 	bool mSingleFrameBitmap; //If true and bitmaps are used, this will assume there's only one frame when scanning the bitmap
 
 
 	Fluid mFluidMoveTo;
 	Fluid mFluidMoveTo;
@@ -110,6 +111,8 @@ public:
 	inline void setImageSize(Point2I size) { mImageSize = size; }
 	inline void setImageSize(Point2I size) { mImageSize = size; }
 	inline bool getFullSize() { return mFullSize; }
 	inline bool getFullSize() { return mFullSize; }
 	inline void setFullSize(bool isFull) { mFullSize = isFull; }
 	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 bool getConstrainProportions() { return mConstrainProportions; }
 	inline void setConstrainProportions(bool setting) { mConstrainProportions = setting; }
 	inline void setConstrainProportions(bool setting) { mConstrainProportions = setting; }
 	inline bool getSingleFrameBitmap() { return mSingleFrameBitmap; }
 	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();
 	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.
 /*! 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 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.
 	@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 )
 void Scene::setLayerSortMode( const U32 layer, const SceneRenderQueue::RenderSort sortMode )
 {
 {
     // Is the layer valid?
     // Is the layer valid?
-    if ( layer > MAX_LAYERS_SUPPORTED )
+    if ( layer >= MAX_LAYERS_SUPPORTED )
     {
     {
         // No, so warn.
         // No, so warn.
         Con::warnf( "Scene::setLayerSortMode() - Layer '%d' is out of range.", layer );
         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 )
 SceneRenderQueue::RenderSort Scene::getLayerSortMode( const U32 layer )
 {
 {
     // Is the layer valid?
     // Is the layer valid?
-    if ( layer > MAX_LAYERS_SUPPORTED )
+    if ( layer >= MAX_LAYERS_SUPPORTED )
     {
     {
         // No, so warn.
         // No, so warn.
         Con::warnf( "Scene::getLayerSortMode() - Layer '%d' is out of range.", layer );
         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"
 #include "2d/scene/DebugDraw.h"
 #endif
 #endif
 
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #include "collection/hashTable.h"
 #endif
 #endif
 
 

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

@@ -77,6 +77,7 @@ public:
    {
    {
       if (mNodes.empty()) return false;
       if (mNodes.empty()) return false;
       if((index >= 0) && (index < mNodes.size())) return true;
       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);
    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;
       Vector<PathObject*>::iterator i;
       for (i = mObjs.begin(); i != mObjs.end(); i++)
       for (i = mObjs.begin(); i != mObjs.end(); i++)
          if ((*i)->mObj == obj) return *i;
          if ((*i)->mObj == obj) return *i;
+      
+      return NULL;
    }
    }
 
 
    DECLARE_CONOBJECT(Path);
    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?
             // Is point count valid?
-            if ( pointCount == 0 || pointCount != 2 )
+            if ( pointCount != 2 )
             {
             {
                 // No, so warn.
                 // No, so warn.
                 Con::warnf( "SceneObject::onTamlCustomRead() - No points (or not two points) on edge collision shape." );
                 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"
 #include "2d/sceneobject/SceneObject.h"
 #endif
 #endif
 
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #include "collection/hashTable.h"
 #endif
 #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"
 #include "sim/simBase.h"
 #endif
 #endif
 
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #include "collection/hashTable.h"
 #endif
 #endif
 
 

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

@@ -20,8 +20,8 @@
 // IN THE SOFTWARE.
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-#ifndef _HASHTABLE_H
-#define _HASHTABLE_H
+#ifndef _HASHTABLE_H_
+#define _HASHTABLE_H_
 
 
 #include "vector.h"
 #include "vector.h"
 #include "platform/platform.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"
 #include "sim/simBase.h"
 #endif
 #endif
 
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #include "collection/hashTable.h"
 #endif
 #endif
 
 

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

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

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

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

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

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

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

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

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

@@ -24,8 +24,8 @@
 #define _ENGINE_VERSION_H_
 #define _ENGINE_VERSION_H_
 
 
 // Engine Version.
 // 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
 /// Gets the specified version number.  The version number is specified as a global in version.cc
 U32 getVersionNumber();
 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.
     // Will "merge" the incoming image onto the current image on to an x, y position.
     bool MergeOn(U32 x, U32 y, const PNGImage* inc);
     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 CleanMemoryUsage();
 
 
     bool ClearImageData();
     bool ClearImageData();

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

@@ -121,6 +121,65 @@ void GBitmap::deleteImage()
    SAFE_DELETE(pPalette);
    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)
 void GBitmap::setPalette(GPalette* in_pPalette)

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

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

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

@@ -30,7 +30,7 @@
 #include "string/stringUnit.h"
 #include "string/stringUnit.h"
 #endif
 #endif
 
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #include "collection/hashTable.h"
 #endif
 #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);
 	RectI contentRect = applyPadding(fillRect.point, fillRect.extent, currentState, mProfile);
 
 
 	//Render the triangle
 	//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
 	//Render the text
 	S32 index = mListBox->getSelectedItem();
 	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)
 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);
 	Parent::onChildAdded(child);
 	calculateExtent();
 	calculateExtent();
 }
 }

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

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

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

@@ -60,6 +60,7 @@ public:
 	GuiExpandCtrl();
 	GuiExpandCtrl();
 
 
    virtual void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
    virtual void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
+   virtual void childResized(GuiControl* child);
 
 
    inline bool getExpanded() { return mExpanded; };
    inline bool getExpanded() { return mExpanded; };
    void setExpanded(bool isExpanded);
    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)
 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());
 	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)
 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)
 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;
 	Point2I mousePos  = lastGuiEvent.mousePoint;
 	RectI winRect   = mBounds;
 	RectI winRect   = mBounds;
+	GuiControl* parent = getParent();
+	if (!parent)
+	{
+		return;
+	}
 	Point2I offset = getParent()->localToGlobalCoord(Point2I(0,0));
 	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 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 );
 	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)
    if(mAwake)
       ctrl->awaken();
       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)
 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");
 		AssertWarn(0, "GuiControl::removeObject: attempted to remove NON GuiControl from set");
 		return;
 		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)
    if (mAwake)
-      static_cast<GuiControl*>(object)->sleep();
+      ctrl->sleep();
     Parent::removeObject(object);
     Parent::removeObject(object);
 
 
 	// If we are a child, notify our parent that we've been removed
 	// If we are a child, notify our parent that we've been removed
-	if (parent)
-		parent->onChildRemoved(ctrl);
+	onChildRemoved(ctrl);
 }
 }
 
 
 GuiControl *GuiControl::getParent()
 GuiControl *GuiControl::getParent()
@@ -416,13 +411,28 @@ void GuiControl::resize(const Point2I &newPosition, const Point2I &newExtent)
 
 
 	Point2I oldExtent = mBounds.extent;
 	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.
    // only do the child control resizing stuff if you really need to.
    bool extentChanged = (actualNewExtent != oldExtent);
    bool extentChanged = (actualNewExtent != oldExtent);
 
 
    if (extentChanged) {
    if (extentChanged) {
       //call set update both before and after
       //call set update both before and after
       setUpdate();
       setUpdate();
-      mBounds.set(newPosition, actualNewExtent);
+      mBounds.set(actualNewPosition, actualNewExtent);
       iterator i;
       iterator i;
       for(i = begin(); i != end(); 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));
          ctrl->parentResized(oldExtent - (ctrl->mRenderInsetLT + ctrl->mRenderInsetRB), actualNewExtent - (ctrl->mRenderInsetLT + ctrl->mRenderInsetRB));
       }
       }
 
 
-      GuiControl *parent = getParent();
       if (parent)
       if (parent)
          parent->childResized(this);
          parent->childResized(this);
       setUpdate();
       setUpdate();
@@ -441,7 +450,7 @@ void GuiControl::resize(const Point2I &newPosition, const Point2I &newExtent)
 	  }
 	  }
    }
    }
    else {
    else {
-      mBounds.point = newPosition;
+      mBounds.point = actualNewPosition;
    }
    }
 }
 }
 void GuiControl::setPosition( const Point2I &newPosition )
 void GuiControl::setPosition( const Point2I &newPosition )
@@ -552,29 +561,35 @@ Point2I GuiControl::extentBattery(Point2I &newExtent)
 	}
 	}
 
 
 	Point2I result = 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;
 	return result;
 }
 }
 
 

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

@@ -327,6 +327,12 @@ public:
     inline void				 setTextExtend(const bool extend) { mTextExtend = extend; }
     inline void				 setTextExtend(const bool extend) { mTextExtend = extend; }
     inline bool				 getTextExtend() { return mTextExtend; }
     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
 	// Text Property Accessors
 	static bool setTextProperty(void* obj, const char* data) { static_cast<GuiControl*>(obj)->setText(data); return false; }
 	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(); }
 	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"
 #include "graphics/gFont.h"
 
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #include "collection/hashTable.h"
 #endif
 #endif
 
 

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

@@ -181,4 +181,27 @@ U32 RandomR250::randI( void )
     return new_rand >> 1;
     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"
 #include "platform/platform.h"
 #endif
 #endif
 
 
+#include "algorithm/pcg_basic.h"
+
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 class RandomGeneratorBase
 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;
 extern RandomLCG gRandGen;
 
 
 #endif //_MRANDOM_H_
 #endif //_MRANDOM_H_

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

@@ -23,7 +23,7 @@
 ConsoleMethodGroupBeginWithDocs(NoiseGenerator, ScriptObject)
 ConsoleMethodGroupBeginWithDocs(NoiseGenerator, ScriptObject)
 
 
 /*! Sets the seed for the noise generater.
 /*! Sets the seed for the noise generater.
-@param seed An interger seed value.
+@param seed An integer seed value.
 @return No return value.
 @return No return value.
 */
 */
 ConsoleMethodWithDocs(NoiseGenerator, setSeed, ConsoleVoid, 3, 3, (int seed))
 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 )
             if ( mEchoInfo )
             {
             {
                 Con::printf( "Module Manager: Unloading group '%s' but could not unload module Id '%s' at version Id '%d'.",
                 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.
             // Skip.
             continue;
             continue;

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

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

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

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

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

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

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

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

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

@@ -23,7 +23,7 @@
 #ifndef _TAML_XMLREADER_H_
 #ifndef _TAML_XMLREADER_H_
 #define _TAML_XMLREADER_H_
 #define _TAML_XMLREADER_H_
 
 
-#ifndef _HASHTABLE_H
+#ifndef _HASHTABLE_H_
 #include "collection/hashTable.h"
 #include "collection/hashTable.h"
 #endif
 #endif
 
 
@@ -37,7 +37,7 @@
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-/// @ingroup tamlGroup
+/// @ingroup tamlGroup
 /// @see tamlGroup
 /// @see tamlGroup
 class TamlXmlReader
 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);
       return StringTable->insert(buffer);
    }
    }
 
 
-   if((*pathPtr == 0 && *toPtr == '/') || (*toPtr == '/' && *pathPtr == 0))
+   if(*toPtr == '/' && *pathPtr == 0)
       branch = pathPtr;
       branch = pathPtr;
 
 
    // Figure out parent dirs
    // 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] ));
    S32 temp = S32(dStrlen( argv[1] ));
    if ( temp )
    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--;
          temp--;
 
 
       if ( temp )
       if ( temp )
@@ -362,4 +362,4 @@ ConsoleFunctionWithDocs( stripTrailingSpaces, ConsoleString, 2, 2, ( string ))
    return( "" );	
    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, ())
 ConsoleFunctionWithDocs(getWinNTVersion, ConsoleVoid, 1, 1, ())
 {
 {
 	std::string ver = getWinNTVersion();
 	std::string ver = getWinNTVersion();
-	Con::printf("%s", ver);
+	Con::printf("%s", ver.c_str());
 }
 }
 
 
 /*! @} */ // end group WindowsPlatform
 /*! @} */ // 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)
                if( clearkeys & POV_down)
                {
                {
-                  newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV;
+                  newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV2;
                   
                   
                   Game->postEvent(newEvent);
                   Game->postEvent(newEvent);
                }
                }
@@ -1022,7 +1022,7 @@ bool DInputDevice::buildEvent( DWORD offset, S32 newData, S32 oldData )
                }
                }
                if( setkeys & POV_down)
                if( setkeys & POV_down)
                {
                {
-                  newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV;
+                  newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV2;
                   
                   
                   Game->postEvent(newEvent);
                   Game->postEvent(newEvent);
                }
                }

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

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

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

@@ -190,28 +190,28 @@ static const char * TypeToString( GLenum t )
 // GLU Log Functions
 // GLU Log Functions
 static void APIENTRY loggluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top)
 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);
    fflush(winState.log_fp);
    dllgluOrtho2D(left, right, bottom, top);
    dllgluOrtho2D(left, right, bottom, top);
 }
 }
 
 
 static void APIENTRY loggluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
 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);
    fflush(winState.log_fp);
    dllgluPerspective(fovy, aspect, zNear, zFar);
    dllgluPerspective(fovy, aspect, zNear, zFar);
 }
 }
 
 
 static void APIENTRY loggluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height, GLint viewport[4])
 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);
    fflush(winState.log_fp);
    dllgluPickMatrix(x, y, width, height, viewport);
    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)
 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);
    fflush(winState.log_fp);
    dllgluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz);
    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 );
          time( &aclock );
          newtime = localtime( &aclock );
          newtime = localtime( &aclock );
 
 
-         asctime( newtime );
-
          winState.log_fp = fopen( "gl_log.txt", "wt" );
          winState.log_fp = fopen( "gl_log.txt", "wt" );
 
 
          fprintf( winState.log_fp, "%s\n", asctime( newtime ) );
          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/constants.cs");
     exec("./scripts/defaultPreferences.cs");
     exec("./scripts/defaultPreferences.cs");
 	exec("./gui/guiProfiles.cs");
 	exec("./gui/guiProfiles.cs");
+	%this.createGuiProfiles();
     exec("./scripts/canvas.cs");
     exec("./scripts/canvas.cs");
 
 
     // Initialize the canvas
     // Initialize the canvas
-    %this.initializeCanvas(%this.Project);
+	%module = ModuleDatabase.findModule("AppCore", 1);
+    %this.initializeCanvas(%module.Project);
 
 
 	// Load other modules
 	// Load other modules
     ModuleDatabase.loadGroup("launch");
     ModuleDatabase.loadGroup("launch");

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

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