Browse Source

Upgrades to GuiSpriteCtrl

The GuiSpriteControl has been upgraded to replace the GuiBitmap and GuiFadeInBitmap controls. It now has options to tile the image have a fixed aspect ratio. The image can be resized and offset and now has it's own image color instead of using the fill color. Finally it now has moveTo, GrowTo, and fadeTo functions that change offset, size, and color over time.
Peter Robinson 4 years ago
parent
commit
3ac14d10be

+ 0 - 3
engine/compilers/VisualStudio 2017/Torque 2D.vcxproj

@@ -619,7 +619,6 @@
     <ClCompile Include="..\..\source\gui\containers\guiGridCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiTabPageCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiArrayCtrl.cc" />
-    <ClCompile Include="..\..\source\gui\guiBitmapCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiBubbleTextCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiCanvas.cc" />
     <ClCompile Include="..\..\source\gui\guiColorPicker.cc" />
@@ -627,7 +626,6 @@
     <ClCompile Include="..\..\source\gui\guiConsoleEditCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiControl.cc" />
     <ClCompile Include="..\..\source\gui\guiDefaultControlRender.cc" />
-    <ClCompile Include="..\..\source\gui\guiFadeinBitmapCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiInputCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiListBoxCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiMessageVectorCtrl.cc" />
@@ -1165,7 +1163,6 @@
     <ClInclude Include="..\..\source\gui\containers\guiTabPageCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiWindowCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\guiArrayCtrl.h" />
-    <ClInclude Include="..\..\source\gui\guiBitmapCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiBubbleTextCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiCanvas.h" />
     <ClInclude Include="..\..\source\gui\guiCanvas_ScriptBinding.h" />

+ 0 - 9
engine/compilers/VisualStudio 2017/Torque 2D.vcxproj.filters

@@ -744,9 +744,6 @@
     <ClCompile Include="..\..\source\gui\guiArrayCtrl.cc">
       <Filter>gui</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\gui\guiBitmapCtrl.cc">
-      <Filter>gui</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\gui\guiBubbleTextCtrl.cc">
       <Filter>gui</Filter>
     </ClCompile>
@@ -768,9 +765,6 @@
     <ClCompile Include="..\..\source\gui\guiDefaultControlRender.cc">
       <Filter>gui</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\gui\guiFadeinBitmapCtrl.cc">
-      <Filter>gui</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\gui\guiInputCtrl.cc">
       <Filter>gui</Filter>
     </ClCompile>
@@ -2094,9 +2088,6 @@
     <ClInclude Include="..\..\source\gui\guiArrayCtrl.h">
       <Filter>gui</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\gui\guiBitmapCtrl.h">
-      <Filter>gui</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\gui\guiBubbleTextCtrl.h">
       <Filter>gui</Filter>
     </ClInclude>

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

@@ -90,6 +90,7 @@ public:
                 mPixelHeight = pixelFrameHeight;
                 mRegionName = StringTable->insert(regionName);
             };
+			inline RectI toRectI(void) const { return RectI(mPixelOffset, Point2I(mPixelWidth, mPixelHeight)); }
 
             Point2I mPixelOffset;
             U32 mPixelWidth;

+ 515 - 31
engine/source/2d/gui/guiSpriteCtrl.cc

@@ -36,6 +36,10 @@
 #include "graphics/dgl.h"
 #endif
 
+#ifndef _H_GUIDEFAULTCONTROLRENDER_
+#include "gui/guiDefaultControlRender.h"
+#endif
+
 #include "guiSpriteCtrl_ScriptBindings.h"
 
 //-----------------------------------------------------------------------------
@@ -46,15 +50,24 @@ IMPLEMENT_CONOBJECT(GuiSpriteCtrl);
 
 GuiSpriteCtrl::GuiSpriteCtrl( void ) :
     mImageAssetId(StringTable->EmptyString),
-    mImageFrameId(0),
+    mFrame(0),
     mNamedImageFrameId(StringTable-> EmptyString),
-    mAnimationAssetId(StringTable->EmptyString)
+    mAnimationAssetId(StringTable->EmptyString),
+	mBitmapName(StringTable->EmptyString)
 {
     // Set to self ticking.
     mSelfTick = true;
     
     // Default to static provider.
     mStaticProvider = true;
+
+	mTileImage = false;
+	mPositionOffset.set(0, 0);
+	mImageColor = FluidColorI(255, 255, 255, 255);
+	mImageSize.set(10, 10);
+	mFullSize = true;
+	mConstrainProportions = true;
+	mSingleFrameBitmap = true;
 }
 
 //-----------------------------------------------------------------------------
@@ -70,10 +83,20 @@ void GuiSpriteCtrl::initPersistFields()
     // Call parent.
     Parent::initPersistFields();
 
+	addGroup("GuiSpriteCtrl");
     addProtectedField("Image", TypeAssetId, Offset(mImageAssetId, GuiSpriteCtrl), &setImage, &defaultProtectedGetFn, &writeImage, "The image asset Id used for the image.");
-    addProtectedField("Frame", TypeS32, Offset(mImageFrameId, GuiSpriteCtrl), &setImageFrame, &defaultProtectedGetFn, &writeImageFrame, "The image frame used for the image.");
-    addProtectedField("NamedFrame", TypeString, Offset(mNamedImageFrameId, GuiSpriteCtrl), &setNamedImageFrame, &defaultProtectedGetFn, &writeNamedImageFrame, "The named image frame used for the image");
+    addProtectedField("Frame", TypeS32, Offset(mFrame, GuiSpriteCtrl), &setImageFrame, &defaultProtectedGetFn, &writeImageFrame, "The image frame used for the image or bitmap.");
+    addProtectedField("NamedFrame", TypeString, Offset(mNamedImageFrameId, GuiSpriteCtrl), &setNamedImageFrame, &defaultProtectedGetFn, &writeNamedImageFrame, "The named image frame used for the image.");
     addProtectedField("Animation", TypeAssetId, Offset(mAnimationAssetId, GuiSpriteCtrl), &setAnimation, &defaultProtectedGetFn, &writeAnimation, "The animation to use.");
+	addProtectedField("Bitmap", TypeFilename, Offset(mBitmapName, GuiSpriteCtrl), &setBitmapName, &getBitmapName, &writeBitmapName, "The bitmap to use in absence of an asset.");
+	addProtectedField("singleFrameBitmap", TypeBool, Offset(mSingleFrameBitmap, GuiSpriteCtrl), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeBitmapName, "If true, will assume there is a single frame when scanning the bitmap.");
+	addField("tileImage", TypeBool, Offset(mTileImage, GuiSpriteCtrl));
+	addField("positionOffset", TypePoint2I, Offset(mPositionOffset, GuiSpriteCtrl));
+	addField("imageColor", TypeFluidColorI, Offset(mImageColor, GuiSpriteCtrl));
+	addField("imageSize", TypePoint2I, Offset(mImageSize, GuiSpriteCtrl));
+	addField("fullSize", TypeBool, Offset(mFullSize, GuiSpriteCtrl));
+	addField("constrainProportions", TypeBool, Offset(mConstrainProportions, GuiSpriteCtrl));
+	endGroup("GuiSpriteCtrl");
 }
 
 //------------------------------------------------------------------------------
@@ -111,29 +134,34 @@ bool GuiSpriteCtrl::onWake()
     if (!Parent::onWake())
         return false;
 
-    // Are we in static mode?
+	mActive = true;
+
     if ( mImageAssetId != StringTable->EmptyString )
     {
         if ( mNamedImageFrameId != StringTable->EmptyString)
         {
             // Set the image asset and named frame
-            ImageFrameProvider::setImage( mImageAssetId, mNamedImageFrameId );
+            setImage( mImageAssetId, mNamedImageFrameId );
         }
         else
         {
             // Set image asset and numerical frame.
-            ImageFrameProvider::setImage( mImageAssetId, mImageFrameId );
+            setImage( mImageAssetId, mFrame );
         }
     }
     else if ( mAnimationAssetId != StringTable->EmptyString )
     {
         // Play animation asset.
-        ImageFrameProvider::setAnimation( mAnimationAssetId );
+        setAnimation( mAnimationAssetId );
     }
+	else if (mBitmapName != StringTable->EmptyString)
+	{
+		setBitmap(mBitmapName);
+	}
     else
     {
         // Not good, so warn.
-        Con::warnf("GuiSpriteCtrl::onWake() - No Image or Animation Asset defined.");
+        Con::warnf("GuiSpriteCtrl::onWake() - No Image, Animation, or bitmap defined.");
     }
 
     return true;
@@ -146,16 +174,184 @@ void GuiSpriteCtrl::onSleep()
     // Clear assets.
     ImageFrameProvider::clearAssets();
 
+	mBitmapTextureHandle = NULL;
+
     // Call parent.
     Parent::onSleep();
 }
 
-//-----------------------------------------------------------------------------
+void GuiSpriteCtrl::setBitmap(const char *name)
+{
+	mBitmapName = StringTable->insert(name);
+	if (*mBitmapName) {
+		mBitmapTextureHandle = TextureHandle(mBitmapName, TextureHandle::BitmapTexture, true);
+		mBitmapTextureHandle.setFilter(GL_LINEAR);
+	}
+	else
+		mBitmapTextureHandle = NULL;
+}
+
+U32 GuiSpriteCtrl::constructBitmapArray()
+{
+	if (mSingleFrameBitmap)
+		return 0;
+
+	if (mBitmapArrayRects.size())
+		return mBitmapArrayRects.size();
+
+	GBitmap *bmp = mBitmapTextureHandle.getBitmap();
+
+	// Make sure the texture exists.
+	if (!bmp)
+		return 0;
+
+	//get the separator color
+	ColorI sepColor;
+	if (!bmp || !bmp->getColor(0, 0, sepColor))
+	{
+		Con::errorf("GuiSpriteCtrl::constructBitmapArray: Failed to create bitmap array from %s - couldn't ascertain seperator color!", mBitmapName);
+		AssertFatal(false, avar("GuiSpriteCtrl::constructBitmapArray: Failed to create bitmap array from %s - couldn't ascertain seperator color!", mBitmapName));
+		return 0;
+	}
+
+	//now loop through all the scroll pieces, and find the bounding rectangle for each piece in each state
+	S32 curY = 0;
+
+	// ascertain the height of this row...
+	ColorI color;
+	mBitmapArrayRects.clear();
+	while (curY < (S32)bmp->getHeight())
+	{
+		// skip any sep colors
+		bmp->getColor(0, curY, color);
+		if (color == sepColor)
+		{
+			curY++;
+			continue;
+		}
+		// ok, process left to right, grabbing bitmaps as we go...
+		S32 curX = 0;
+		while (curX < (S32)bmp->getWidth())
+		{
+			bmp->getColor(curX, curY, color);
+			if (color == sepColor)
+			{
+				curX++;
+				continue;
+			}
+			S32 startX = curX;
+			while (curX < (S32)bmp->getWidth())
+			{
+				bmp->getColor(curX, curY, color);
+				if (color == sepColor)
+					break;
+				curX++;
+			}
+			S32 stepY = curY;
+			while (stepY < (S32)bmp->getHeight())
+			{
+				bmp->getColor(startX, stepY, color);
+				if (color == sepColor)
+					break;
+				stepY++;
+			}
+			mBitmapArrayRects.push_back(RectI(startX, curY, curX - startX, stepY - curY));
+		}
+		// ok, now skip to the next separation color on column 0
+		while (curY < (S32)bmp->getHeight())
+		{
+			bmp->getColor(0, curY, color);
+			if (color == sepColor)
+				break;
+			curY++;
+		}
+	}
+	return mBitmapArrayRects.size();
+}
+
+Point2I& GuiSpriteCtrl::constrain(Point2I &point, bool grow)
+{
+	if (!mConstrainProportions)
+	{
+		return point;
+	}
+
+	F32 targetRatio = getAspectRatio();
+	F32 currentRatio = (F32)(point.y / point.x);
+	if (targetRatio > currentRatio) //Too short
+	{
+		return grow ? Point2I(point.x, mRound(point.x * targetRatio)) : Point2I(mRound(point.y / targetRatio), point.y);
+	}
+	else if (targetRatio < currentRatio) //Too tall
+	{
+		return grow ? Point2I(mRound(point.y / targetRatio), point.y) : Point2I(point.x, mRound(point.x * targetRatio));
+	}
+	return point;
+}
+
+Point2I& GuiSpriteCtrl::constrainLockX(Point2I &point)
+{
+	if (!mConstrainProportions)
+	{
+		return point;
+	}
+
+	F32 targetRatio = getAspectRatio();
+	return Point2I(point.x, mRound(point.x * targetRatio));
+}
+
+Point2I& GuiSpriteCtrl::constrainLockY(Point2I &point)
+{
+	if (!mConstrainProportions)
+	{
+		return point;
+	}
+
+	F32 targetRatio = getAspectRatio();
+	return Point2I(point.y / targetRatio, point.y);
+}
+
+F32 GuiSpriteCtrl::getAspectRatio()
+{
+	RectI src = getSourceRect(usesAsset() ? getProviderTexture() : mBitmapTextureHandle);
+	if (src.isValidRect())
+	{
+		return ((F32)src.extent.y / (F32)src.extent.x);
+	}
+	return 1.0;
+}
 
-void GuiSpriteCtrl::processTick(void)
+Point2I& GuiSpriteCtrl::applyAlignment(RectI &bounds, Point2I &size)
 {
-	// Update using tick period.
-	update(Tickable::smTickSec);
+	Point2I offset = Point2I(0, 0);
+
+	if (mProfile->mAlignment == GuiControlProfile::AlignmentType::RightAlign)
+	{
+		offset.x = bounds.extent.x - size.x;
+	}
+	else if (mProfile->mAlignment == GuiControlProfile::AlignmentType::CenterAlign)
+	{
+		S32 halfW = mRound(size.x / 2);
+		offset.x = mRound(bounds.extent.x / 2) - halfW;
+	}
+
+	if (mProfile->mVAlignment == GuiControlProfile::VertAlignmentType::BottomVAlign)
+	{
+		offset.y = bounds.extent.y - size.y;
+	}
+	else if (mProfile->mVAlignment == GuiControlProfile::VertAlignmentType::MiddleVAlign)
+	{
+		S32 halfH = mRound(size.y / 2);
+		offset.y = mRound(bounds.extent.y / 2) - halfH;
+	}
+
+	//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);
+
+	return offset;
 }
 
 //-----------------------------------------------------------------------------
@@ -165,6 +361,9 @@ bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const U32 frame )
     // Sanity!
     AssertFatal( pImageAssetId != NULL, "Cannot use a NULL asset Id." );
 
+	//Capture the current tick state
+	bool isTicking = isProcessingTicks();
+
     // Reset animation.
     if ( mAnimationAssetId != StringTable->EmptyString )
         mAnimationAssetId = StringTable->EmptyString;
@@ -173,10 +372,6 @@ bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const U32 frame )
     if ( mImageAssetId != pImageAssetId )
         mImageAssetId = StringTable->insert(pImageAssetId);
 
-    // Set the image frame if the image asset was set.
-    if ( mImageAssetId != StringTable->EmptyString )
-        setImageFrame(frame);
-
     // Finish if not awake.
     if ( !isAwake() )
         return true;
@@ -185,6 +380,12 @@ bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const U32 frame )
     if ( !ImageFrameProvider::setImage(pImageAssetId, frame) )
         return false;
 
+	//Restore the tick state
+	if (isProcessingTicks() != isTicking)
+	{
+		setProcessTicks(true);
+	}
+
     // Update control.
     setUpdate();
 
@@ -198,6 +399,9 @@ bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const char* pNamedFrame
     // Sanity!
     AssertFatal( pImageAssetId != NULL, "Cannot use a NULL asset Id." );
 
+	//Capture the current tick state
+	bool isTicking = isProcessingTicks();
+
     // Reset animation.
     if ( mAnimationAssetId != StringTable->EmptyString )
         mAnimationAssetId = StringTable->EmptyString;
@@ -206,10 +410,6 @@ bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const char* pNamedFrame
     if ( mImageAssetId != pImageAssetId )
         mImageAssetId = StringTable->insert(pImageAssetId);
 
-    // Set the image frame if the image asset was set.
-    if ( mImageAssetId != StringTable->EmptyString )
-        setNamedImageFrame(pNamedFrame);
-
     // Finish if not awake.
     if ( !isAwake() )
         return true;
@@ -218,6 +418,12 @@ bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const char* pNamedFrame
     if ( !ImageFrameProvider::setImage(pImageAssetId, pNamedFrame) )
         return false;
 
+	//Restore the tick state
+	if (isProcessingTicks() != isTicking)
+	{
+		setProcessTicks(true);
+	}
+
     // Update control.
     setUpdate();
 
@@ -229,25 +435,28 @@ bool GuiSpriteCtrl::setImage( const char* pImageAssetId, const char* pNamedFrame
 bool GuiSpriteCtrl::setImageFrame( const U32 frame )
 {
     // Check Existing Image.
-    if ( mImageAssetId == StringTable->EmptyString )
+    if ( mImageAssetId == StringTable->EmptyString && mBitmapName == StringTable->EmptyString )
     {
         // Warn.
-        Con::warnf("GuiSpriteCtrl::setImageFrame() - Cannot set frame without existing asset Id.");
+        Con::warnf("GuiSpriteCtrl::setImageFrame() - Cannot set frame without existing image asset or bitmap.");
 
         // Return Here.
         return false;
     }
 
     // Set frame.
-    mImageFrameId = frame;
+    mFrame = frame;
 
     // Finish if not awake.
     if ( !isAwake() )
         return true;
 
-    // Call parent.
-    if ( !ImageFrameProvider::setImageFrame(frame) )
-        return false;
+	if(usesAsset())
+	{
+		// Call parent.
+		if ( !ImageFrameProvider::setImageFrame(frame) )
+			return false;
+	}
 
     // Update control.
     setUpdate();
@@ -312,12 +521,287 @@ bool GuiSpriteCtrl::setAnimation( const char* pAnimationAssetId )
     return true;
 }
 
-//-----------------------------------------------------------------------------
+void GuiSpriteCtrl::onRender(Point2I offset, const RectI &updateRect)
+{
+	RectI ctrlRect = applyMargins(offset, mBounds.extent, NormalState, mProfile);
+
+	if (!ctrlRect.isValidRect())
+	{
+		return;
+	}
+
+	renderUniversalRect(ctrlRect, mProfile, NormalState);
+
+	RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, NormalState, mProfile);
+	RectI contentRect = applyPadding(fillRect.point, fillRect.extent, NormalState, mProfile);
+
+	if (contentRect.isValidRect() && (usesAsset() || mBitmapName != StringTable->EmptyString))
+	{
+		RectI oldClip = dglGetClipRect();
+		RectI clipRect = contentRect;
+		if (clipRect.intersect(oldClip))
+		{
+			dglSetClipRect(clipRect);
+			dglSetBitmapModulation(ColorF(mImageColor));
+
+			Point2I offset = Point2I(0, 0);
+			Point2I size = constrain(mImageSize);
+
+			if (mTileImage) //Tile the image
+			{
+				offset = mPositionOffset;
+				offset.x = (mPositionOffset.x % size.x);
+				if (offset.x > 0)
+				{
+					offset.x -= size.x;
+				}
+				offset.y = (mPositionOffset.y % size.y);
+				if (offset.y > 0)
+				{
+					offset.y -= size.y;
+				}
+
+				RenderTiledImage(contentRect, offset, size);
+			}
+			else if (mFullSize) //Fill with the image
+			{
+				size = constrain(contentRect.extent, false);
+				if (mConstrainProportions)
+				{
+					offset = applyAlignment(contentRect, size);
+				}
+				RenderImage(contentRect, offset, size);
+			}
+			else //Position the image by profile alignment
+			{
+				size = constrain(mImageSize);
+				if (size.x > contentRect.extent.x)
+				{
+					size.x = contentRect.extent.x;
+					size = constrainLockX(size);
+				}
+				if (size.y > contentRect.extent.y)
+				{
+					size.y = contentRect.extent.y;
+					size = constrainLockY(size);
+				}
+				offset = applyAlignment(contentRect, size);
+
+				RenderImage(contentRect, offset, size);
+			}
+			dglClearBitmapModulation();
+			dglSetClipRect(oldClip);
+
+			//Render the childen
+			renderChildControls(offset, contentRect, updateRect);
+		}
+
+		//One more thing...
+		if (usesAsset() && !isStaticFrameProvider() && !isAnimationFinished() && !isAnimationPaused() && !isProcessingTicks())
+		{
+			setProcessTicks(true);
+		}
+	}
+}
 
-void GuiSpriteCtrl::onRender( Point2I offset, const RectI &updateRect)
+void GuiSpriteCtrl::RenderImage(RectI &bounds, Point2I &offset, Point2I &size)
 {
-    // Call parent.
-    ImageFrameProvider::renderGui( *this, offset, updateRect );
+	TextureObject* texture = usesAsset() ? getProviderTexture() : (TextureObject *)mBitmapTextureHandle;
+
+	RectI srcRegion = getSourceRect(texture);
+	if (!srcRegion.isValidRect())
+	{
+		return;
+	}
+
+	RectI dstRegion = RectI(bounds.point + offset, size);
+	dglDrawBitmapStretchSR(texture, dstRegion, srcRegion, false);
+}
+
+void GuiSpriteCtrl::RenderTiledImage(RectI &bounds, Point2I &start, Point2I &size)
+{
+	TextureObject* texture = usesAsset() ? getProviderTexture() : (TextureObject *)mBitmapTextureHandle;
+
+	RectI srcRegion = getSourceRect(texture);
+	if (!srcRegion.isValidRect())
+	{
+		return;
+	}
+
+	RectI dstRegion;
+	float xdone = ((float)(bounds.extent.x - start.x) / (float)size.x) + 1;
+	float ydone = ((float)(bounds.extent.y - start.y) / (float)size.y) + 1;
+
+	// We manually draw each repeat because non power of two textures will 
+	// not tile correctly when rendered with dglDrawBitmapTile().
+	for (int y = 0; y < ydone; ++y)
+	{
+		for (int x = 0; x < xdone; ++x)
+		{
+			dstRegion.set((size.x * x) + start.x, (size.y * y) + start.y, size.x, size.y);
+			dglDrawBitmapStretchSR(texture, dstRegion, srcRegion, false);
+		}
+	}
+}
+
+RectI GuiSpriteCtrl::getSourceRect(TextureObject* texture)
+{
+	RectI srcRegion = RectI(0, 0, 0, 0);
+	bool hasAsset = usesAsset();
+	if (hasAsset)
+	{
+		const ImageAsset::FrameArea& frameArea = getProviderImageFrameArea();
+		srcRegion = RectI(frameArea.mPixelArea.mPixelOffset, Point2I(frameArea.mPixelArea.mPixelWidth, frameArea.mPixelArea.mPixelHeight));
+	}
+	else if (!hasAsset && mSingleFrameBitmap)
+	{
+		srcRegion = RectI(0, 0, texture->getBitmapWidth(), texture->getBitmapHeight());
+	}
+	else if (!hasAsset && constructBitmapArray() > mFrame)
+	{
+		RectI* frameRect = mBitmapArrayRects.address();
+		srcRegion = frameRect[mFrame];
+	}
+	return srcRegion;
+}
+
+void GuiSpriteCtrl::moveTo(S32 x, S32 y, S32 time, EasingFunction ease)
+{
+	mStartOffset.set(mPositionOffset.x, mPositionOffset.y);
+	mTargetOffset.set(x, y);
+	mFluidMoveTo.setAnimationLength(getMax(time, 0));
+	mFluidMoveTo.setEasingFunction(ease);
+
+	mFluidMoveTo.startFluidAnimation();
+	setProcessTicks(true);
+}
+
+void GuiSpriteCtrl::growTo(S32 x, S32 y, S32 time, EasingFunction ease)
+{
+	mStartSize.set(mImageSize.x, mImageSize.y);
+	mTargetSize.set(x, y);
+	mFluidGrowTo.setAnimationLength(getMax(time, 0));
+	mFluidGrowTo.setEasingFunction(ease);
+
+	mFluidGrowTo.startFluidAnimation();
+	setProcessTicks(true);
+}
+
+void GuiSpriteCtrl::fadeTo(const ColorI &color, S32 time, EasingFunction ease)
+{
+	mImageColor.setAnimationLength(getMax(time, 0));
+	mImageColor.setEasingFunction(ease);
+
+	mImageColor.startFluidAnimation(color);
+	setProcessTicks(true);
+}
+
+void GuiSpriteCtrl::processTick()
+{
+	bool shouldWeContinue = false;
+
+	//Animating
+	shouldWeContinue |= update(Tickable::smTickSec);
+	shouldWeContinue |= animateMoveTo();
+	shouldWeContinue |= animateGrowTo();
+	shouldWeContinue |= animateFadeTo();
+
+	if (!shouldWeContinue)
+	{
+		setProcessTicks(false);
+	}
+}
+
+bool GuiSpriteCtrl::update(const F32 elapsedTime)
+{
+	//Note: although this overrides ImageFrameProviderCore::update, the return value has a different meaning.
+	//True means the control should continue ticking. False means the animation now longer needs tickets.
+
+	// Static provider or bitmap?
+	if (!usesAsset() || isStaticFrameProvider())
+	{
+		return false;
+	}
+
+	// Finish if the animation has finished or paused.
+	if (isAnimationFinished() || isAnimationPaused())
+		return false;
+
+	// Update the animation.
+	if (updateAnimation(elapsedTime))
+	{
+		setUpdate();
+	}
+
+	// Finish if the animation has NOT finished.
+	if (!isAnimationFinished())
+		return true;
+
+	// Perform callback.
+	onAnimationEnd();
+
+	//We no longer need ticks.
+	return false;
+}
+
+bool GuiSpriteCtrl::animateMoveTo()
+{
+	if (!mFluidMoveTo.isAnimating())
+	{
+		return false;
+	}
+
+	setUpdate();
+	F32 progress = mFluidMoveTo.getProgress(32.0f);
+	mPositionOffset.set(
+		mFluidMoveTo.processValue(progress, mStartOffset.x, mTargetOffset.x),
+		mFluidMoveTo.processValue(progress, mStartOffset.y, mTargetOffset.y));
+
+	if (!mFluidMoveTo.isAnimating() && isMethod("onMoveToComplete"))
+	{
+		Con::executef(this, 1, "onMoveToComplete");
+	}
+
+	return mFluidMoveTo.isAnimating();
+}
+
+bool GuiSpriteCtrl::animateGrowTo()
+{
+	if (!mFluidGrowTo.isAnimating())
+	{
+		return false;
+	}
+
+	setUpdate();
+	F32 progress = mFluidGrowTo.getProgress(32.0f);
+	mImageSize.set(
+		mFluidGrowTo.processValue(progress, mStartSize.x, mTargetSize.x),
+		mFluidGrowTo.processValue(progress, mStartSize.y, mTargetSize.y));
+
+	if (!mFluidGrowTo.isAnimating() && isMethod("onGrowToComplete"))
+	{
+		Con::executef(this, 1, "onGrowToComplete");
+	}
+
+	return mFluidGrowTo.isAnimating();
+}
+
+bool GuiSpriteCtrl::animateFadeTo()
+{
+	if (!mImageColor.isAnimating())
+	{
+		return false;
+	}
+
+	setUpdate();
+	mImageColor.processTick();
+
+	if (!mImageColor.isAnimating() && isMethod("onFadeToComplete"))
+	{
+		Con::executef(this, 1, "onFadeToComplete");
+	}
+
+	return mImageColor.isAnimating();
 }
 
 //------------------------------------------------------------------------------

+ 75 - 9
engine/source/2d/gui/guiSpriteCtrl.h

@@ -36,50 +36,116 @@ private:
 
 protected:
     StringTableEntry                mImageAssetId;
-    U32                             mImageFrameId;
+    U32                             mFrame;
     StringTableEntry                mNamedImageFrameId;
     StringTableEntry                mAnimationAssetId;
+	StringTableEntry				mBitmapName;
+	TextureHandle					mBitmapTextureHandle;
+	Vector<RectI>					mBitmapArrayRects;
+
+	bool mTileImage; //If true, the image will tile over the content area
+	Point2I mPositionOffset; //Offset from the set location of the image
+	FluidColorI mImageColor; //The blend color used on the image
+	Point2I mImageSize; //The size of the image, reduced, if needed, to fit the content area
+	bool mFullSize; //If true, the image will take all available space
+	bool mConstrainProportions; //If true, the image will maintain its aspect ratio 
+	bool mSingleFrameBitmap; //If true and bitmaps are used, this will assume there's only one frame when scanning the bitmap
+
+	Fluid mFluidMoveTo;
+	Point2I mStartOffset;
+	Point2I mTargetOffset;
+
+	Fluid mFluidGrowTo;
+	Point2I mStartSize;
+	Point2I mTargetSize;
 
 public:
     GuiSpriteCtrl();
     virtual ~GuiSpriteCtrl();
+	static void initPersistFields();
     bool onWake();
     void onSleep();
-    void onRender(Point2I offset, const RectI &updateRect);
-    static void initPersistFields();
-
     virtual void copyTo(SimObject* object);
 
+	//Rendering
+	void onRender(Point2I offset, const RectI &updateRect);
+	void RenderImage(RectI &bounds, Point2I &offset, Point2I &size);
+	void RenderTiledImage(RectI &bounds, Point2I &start, Point2I &size);
+
+	//positioning and sizing
+	Point2I& constrain(Point2I &point, bool grow = true);
+	Point2I& constrainLockX(Point2I &point);
+	Point2I& constrainLockY(Point2I &point);
+	F32 getAspectRatio();
+	Point2I& applyAlignment(RectI &bounds, Point2I &size);
+
+	//Animation Functions
+	void moveTo(S32 x, S32 y, S32 time, EasingFunction ease = Linear);
+	void growTo(S32 x, S32 y, S32 time, EasingFunction ease = Linear);
+	void fadeTo(const ColorI &color, S32 time, EasingFunction ease = Linear);
+	bool animateMoveTo();
+	bool animateGrowTo();
+	bool animateFadeTo();
+
     // Static and Animated Assets.
     inline bool setImage( const char* pImageAssetId ) { return setImage( pImageAssetId, mImageFrame ); }
     virtual bool setImage( const char* pImageAssetId, const U32 frame );
     virtual bool setImage( const char* pImageAssetId, const char* pNamedFrame );
     inline StringTableEntry getImage( void ) const{ return mImageAssetId; }
     virtual bool setImageFrame( const U32 frame );
-    inline U32 getImageFrame( void ) const { return mImageFrameId; }
+    inline U32 getImageFrame( void ) const { return mFrame; }
     virtual bool setNamedImageFrame ( const char* namedFrame );
     inline StringTableEntry getNamedImageFrame( void ) const { return mNamedImageFrameId; }
     virtual bool setAnimation( const char* pAnimationAssetId );
     inline StringTableEntry getAnimation( void ) const { return mAnimationAssetId; }
 
+	//Accessors
+	inline bool getTileImage() { return mTileImage; }
+	inline void setTileImage(bool setting) { mTileImage = setting; }
+	inline Point2I getPositionOffset() { return mPositionOffset; }
+	inline void setPositionOffset(S32 x, S32 y) { mPositionOffset = Point2I(x, y); }
+	inline ColorI getImageColor() { return ColorI(mImageColor); }
+	inline void setImageColor(ColorI color) { mImageColor = FluidColorI(color); }
+	inline Point2I getImageSize() { return mImageSize; }
+	inline void setImageSize(Point2I size) { mImageSize = size; }
+	inline bool getFullSize() { return mFullSize; }
+	inline void setFullSize(bool isFull) { mFullSize = isFull; }
+	inline bool getConstrainProportions() { return mConstrainProportions; }
+	inline void setConstrainProportions(bool setting) { mConstrainProportions = setting; }
+	inline bool getSingleFrameBitmap() { return mSingleFrameBitmap; }
+	inline void setSingleFrameBitmap(bool isSingleFrame) { mSingleFrameBitmap = isSingleFrame; }
+
+	//Bitmap members
+	void setBitmap(const char *name);
+	inline void setBitmap(const TextureHandle &handle) { mBitmapTextureHandle = handle; }
+	inline StringTableEntry getBitmapName(void) const { return mBitmapName; }
+	U32 constructBitmapArray();
+	inline U32 getBitmapFrame() { return mSingleFrameBitmap ? 1 : constructBitmapArray(); }
+	inline bool usesAsset() { return (mImageAssetId != StringTable->EmptyString) || (mAnimationAssetId != StringTable->EmptyString); }
+
     // Declare type.
     DECLARE_CONOBJECT(GuiSpriteCtrl);
 
 protected:
+	virtual bool update(const F32 elapsedTime);
     virtual void onAnimationEnd( void );
 	virtual void processTick();
 	virtual void interpolateTick(F32 delta) {};
 	virtual void advanceTime(F32 timeDelta) {};
+	RectI getSourceRect(TextureObject* texture);
 
 protected:
     static bool setImage(void* obj, const char* data) { static_cast<GuiSpriteCtrl*>(obj)->setImage( data ); return false; }
-    static bool writeImage(void* obj, StringTableEntry pFieldName) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if ( !pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mImageAssetId != StringTable->EmptyString; }
+    static bool writeImage(void* obj, StringTableEntry pFieldName) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if( !pCastObject->usesAsset() || !pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mImageAssetId != StringTable->EmptyString; }
     static bool setImageFrame(void* obj, const char* data) { static_cast<GuiSpriteCtrl*>(obj)->setImageFrame( dAtoi(data) ); return false; }
-    static bool writeImageFrame(void* obj, StringTableEntry pFieldName) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if ( !pCastObject->isStaticFrameProvider() || pCastObject->isUsingNamedImageFrame() ) return false; return pCastObject->getImageFrame() > 0; }
+    static bool writeImageFrame(void* obj, StringTableEntry pFieldName) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if( !pCastObject->usesAsset() ) { return pCastObject->getBitmapFrame(); } if ( !pCastObject->isStaticFrameProvider() || pCastObject->isUsingNamedImageFrame() ) return false; return pCastObject->getImageFrame() > 0; }
     static bool setNamedImageFrame(void* obj, const char* data) { static_cast<GuiSpriteCtrl*>(obj)->setNamedImageFrame(data); return false; }
-    static bool writeNamedImageFrame(void* obj, StringTableEntry pFieldName) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if ( !pCastObject->isStaticFrameProvider() || !pCastObject->isUsingNamedImageFrame() ) return false; return pCastObject->mNamedImageFrameId != StringTable->EmptyString; }
+    static bool writeNamedImageFrame(void* obj, StringTableEntry pFieldName) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if( !pCastObject->usesAsset() || !pCastObject->isStaticFrameProvider() || !pCastObject->isUsingNamedImageFrame() ) return false; return pCastObject->mNamedImageFrameId != StringTable->EmptyString; }
     static bool setAnimation(void* obj, const char* data) { static_cast<GuiSpriteCtrl*>(obj)->setAnimation(data); return false; };
-    static bool writeAnimation(void* obj, StringTableEntry pFieldName) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if ( pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mAnimationAssetId != StringTable->EmptyString; }
+    static bool writeAnimation(void* obj, StringTableEntry pFieldName) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if( !pCastObject->usesAsset() || pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mAnimationAssetId != StringTable->EmptyString; }
+	static bool setBitmapName(void *obj, const char *data) { static_cast<GuiSpriteCtrl *>(obj)->setBitmap(data); return false; }
+	static const char *getBitmapName(void *obj, const char *data) { return static_cast<GuiSpriteCtrl*>(obj)->getBitmapName(); }
+	static bool writeBitmapName(void* obj, StringTableEntry pFieldName) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if( pCastObject->usesAsset() ) return false; return pCastObject->mBitmapName != StringTable->EmptyString; }
 };
 
 #endif //_GUISPRITECTRL_H_

+ 443 - 12
engine/source/2d/gui/guiSpriteCtrl_ScriptBindings.h

@@ -101,7 +101,7 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getImage, ConsoleString, 2, 2, ())
 ConsoleMethodWithDocs(GuiSpriteCtrl, setImageFrame, ConsoleBool, 3, 3, (int imageFrame))
 {
     // Are we in static mode?
-    if ( !object->isStaticFrameProvider() )
+    if ( object->usesAsset() && !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf("GuiSpriteCtrl::setImageFrame() - Method invalid, not in static mode.");
@@ -119,7 +119,7 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, setImageFrame, ConsoleBool, 3, 3, (int imag
 ConsoleMethodWithDocs(GuiSpriteCtrl, getImageFrame, ConsoleInt, 2, 2, ())
 {
     // Are we in static mode?
-    if ( !object->isStaticFrameProvider() )
+    if (object->usesAsset() && !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf("GuiSpriteCtrl::getImageFrame() - Method invalid, not in static mode.");
@@ -127,7 +127,7 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getImageFrame, ConsoleInt, 2, 2, ())
     }
 
     // Are we using a named image frame?
-    if ( object->isUsingNamedImageFrame() )
+    if (object->usesAsset() && object->isUsingNamedImageFrame() )
     {
         // Yes, so warn.
         Con::warnf("GuiSpriteCtrl::getImageFrame() - Method invalid, using a named image frame.");
@@ -147,13 +147,21 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getImageFrame, ConsoleInt, 2, 2, ())
 ConsoleMethodWithDocs(GuiSpriteCtrl, setNamedImageFrame, ConsoleBool, 3, 3, (frame))
 {
     // Are we in static mode?
-    if ( !object->isStaticFrameProvider() )
+    if ( object->usesAsset() && !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf("GuiSpriteCtrl::setNamedImageFrame() - Method invalid, not in static mode.");
         return false;
     }
 
+	// Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// No, so warn.
+		Con::warnf("GuiSpriteCtrl::setNamedImageFrame() - Method invalid, using bitmaps.");
+		return false;
+	}
+
     // Set the numerical frame
     return object->setNamedImageFrame( argv[2] );
 }
@@ -166,7 +174,7 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, setNamedImageFrame, ConsoleBool, 3, 3, (fra
 ConsoleMethodWithDocs(GuiSpriteCtrl, getNamedImageFrame, ConsoleString, 2, 2, ())
 {
     // Are we in static mode?
-    if ( !object->isStaticFrameProvider() )
+    if ( object->usesAsset() &&  !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf("GuiSpriteCtrl::getNamedImageFrame() - Method invalid, not in static mode.");
@@ -174,13 +182,21 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getNamedImageFrame, ConsoleString, 2, 2, ()
     }
 
     // Are we using a named image frame?
-    if ( !object->isUsingNamedImageFrame() )
+    if (object->usesAsset() && !object->isUsingNamedImageFrame() )
     {
         // No, so warn.
         Con::warnf("GuiSpriteCtrl::getNamedImageFrame() - Method invalid, not using a named image frame.");
         return NULL;
     }
 
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::getNamedImageFrame() - Method invalid, using a bitmap.");
+		return NULL;
+	}
+
     return object->getNamedImageFrame();
 }
 
@@ -204,13 +220,21 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, setAnimation, ConsoleVoid, 3, 3, (string an
 ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimation, ConsoleString, 2, 2, ())
 {
     // Are we in static mode?
-    if ( object->isStaticFrameProvider() )
+    if ( object->usesAsset() && object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf("GuiSpriteCtrl::getAnimation() - Method invalid, in static mode.");
         return StringTable->EmptyString;
     }
 
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::getAnimation() - Method invalid, using a bitmap.");
+		return StringTable->EmptyString;
+	}
+
     // Get animation.
     return object->getAnimation();
 }
@@ -223,13 +247,21 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimation, ConsoleString, 2, 2, ())
 ConsoleMethodWithDocs(GuiSpriteCtrl, pauseAnimation, ConsoleVoid, 3, 3, (bool enable))
 {
     // Are we in static mode?
-    if ( object->isStaticFrameProvider() )
+    if ( object->usesAsset() && object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf("GuiSpriteCtrl::pauseAnimation() - Method invalid, not in dynamic (animated) mode.");
         return;
     }
 
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::pauseAnimation() - Method invalid, using a bitmap.");
+		return;
+	}
+
     return static_cast<ImageFrameProvider*>(object)->pauseAnimation(dAtob(argv[2]));
 }
 
@@ -241,13 +273,21 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, pauseAnimation, ConsoleVoid, 3, 3, (bool en
 ConsoleMethodWithDocs(GuiSpriteCtrl, stopAnimation, ConsoleVoid, 2, 2, ())
 {
     // Are we in static mode?
-    if ( object->isStaticFrameProvider() )
+    if ( object->usesAsset() && object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf("GuiSpriteCtrl::stopAnimation() - Method invalid, not in dynamic (animated) mode.");
         return;
     }
 
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::stopAnimation() - Method invalid, using a bitmap.");
+		return;
+	}
+
     object->stopAnimation();
 }
 
@@ -260,13 +300,21 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, stopAnimation, ConsoleVoid, 2, 2, ())
 ConsoleMethodWithDocs(GuiSpriteCtrl, setAnimationFrame, ConsoleVoid, 3, 3, (int frame))
 {
     // Are we in static mode?
-    if ( object->isStaticFrameProvider() )
+    if ( object->usesAsset() && object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf("GuiSpriteCtrl::setAnimationFrame() - Method invalid, not in dynamic (animated) mode.");
         return;
     }
 
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::setAnimationFrame() - Method invalid, using a bitmap.");
+		return;
+	}
+
     // Set Animation Frame
     object->setAnimationFrame( dAtoi(argv[2]) );
 }
@@ -279,13 +327,21 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, setAnimationFrame, ConsoleVoid, 3, 3, (int
 ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimationFrame, ConsoleInt, 2, 2, ())
 {
     // Are we in static mode?
-    if ( object->isStaticFrameProvider() )
+    if ( object->usesAsset() && object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf("GuiSpriteCtrl::getAnimationFrame() - Method invalid, not in dynamic (animated) mode.");
         return -1;
     }
 
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::getAnimationFrame() - Method invalid, using a bitmap.");
+		return NULL;
+	}
+
     // Get Animation Frame.
     return object->getAnimationFrame();
 }
@@ -298,13 +354,21 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimationFrame, ConsoleInt, 2, 2, ())
 ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimationImageFrame, ConsoleInt, 2, 2, ())
 {
     // Are we in static mode?
-    if ( object->isStaticFrameProvider() )
+    if ( object->usesAsset() && object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf("GuiSpriteCtrl::getAnimationImageFrame() - Method invalid, not in dynamic (animated) mode.");
         return -1;
     }
 
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::getAnimationImageFrame() - Method invalid, using a bitmap.");
+		return -1;
+	}
+
     // Get the current animation asset
     const AnimationAsset* asset = object->getCurrentAnimation();
     
@@ -327,6 +391,14 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimationImageFrame, ConsoleInt, 2, 2, (
 */
 ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimationNamedImageFrame, ConsoleString, 2, 2, ())
 {
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::getAnimationNamedImageFrame() - Method invalid, using a bitmap.");
+		return NULL;
+	}
+
     // Are we in static mode?
     if ( object->isStaticFrameProvider() )
     {
@@ -357,6 +429,14 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimationNamedImageFrame, ConsoleString,
 */
 ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimationTime, ConsoleFloat, 2, 2, ())
 {
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::getAnimationTime() - Method invalid, using a bitmap.");
+		return 0.0f;
+	}
+
     // Are we in static mode?
     if ( object->isStaticFrameProvider() )
     {
@@ -377,6 +457,14 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimationTime, ConsoleFloat, 2, 2, ())
 */
 ConsoleMethodWithDocs(GuiSpriteCtrl, getIsAnimationFinished, ConsoleBool, 2, 2, ())
 {
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::getAnimationFinished() - Method invalid, using a bitmap.");
+		return true;
+	}
+
     // Are we in static mode?
     if ( object->isStaticFrameProvider() )
     {
@@ -396,6 +484,14 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getIsAnimationFinished, ConsoleBool, 2, 2,
 */
 ConsoleMethodWithDocs(GuiSpriteCtrl, setAnimationTimeScale, ConsoleVoid, 3, 3, (float timeScale))
 {
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::setAnimationTimeScale() - Method invalid, using a bitmap.");
+		return;
+	}
+
     // Are we in static mode?
     if ( object->isStaticFrameProvider() )
     {
@@ -414,6 +510,14 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, setAnimationTimeScale, ConsoleVoid, 3, 3, (
 */
 ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimationTimeScale, ConsoleFloat, 2, 2, ())
 {
+	//Are we using a bitmap?
+	if (!object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::getAnimationTimeScale() - Method invalid, using a bitmap.");
+		return -1;
+	}
+
     // Are we in static mode?
     if ( object->isStaticFrameProvider() )
     {
@@ -425,4 +529,331 @@ ConsoleMethodWithDocs(GuiSpriteCtrl, getAnimationTimeScale, ConsoleFloat, 2, 2,
     return object->getAnimationTimeScale();
 }
 
+/*! Sets the amount to offset the image from its actual position. The image will not exceed the bounds of the content area.
+	@param x/y The space-delimited x and y values to offset the image by.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, setPositionOffset, ConsoleVoid, 3, 3, "(Vector2 x y)")
+{
+	if (argc != 3)
+	{
+		Con::warnf("GuiSpriteCtrl::setPositionOffset() - Invalid number of parameters!");
+		return;
+	}
+
+	const U32 posCount = Utility::mGetStringElementCount(argv[2]);
+	if (posCount != 2)
+	{
+		Con::warnf("GuiSpriteCtrl::setPositionOffset() - Position requires x and y");
+		return;
+	}
+
+	object->setPositionOffset(dAtoi(Utility::mGetStringElement(argv[2], 0)),
+		dAtoi(Utility::mGetStringElement(argv[2], 0)));
+}
+
+/*! Gets the amount to offset the image from its actual position. The offset may be greater than the movement of the image becuase of the bounds of the content area.
+	@return The space-delimited x and y values to offset the image by.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, getPositionOffset, ConsoleString, 2, 2, "()")
+{
+	char *retBuffer = Con::getReturnBuffer(64);
+	const Point2I &off = object->getPositionOffset();
+	dSprintf(retBuffer, 64, "%d %d", off.x, off.y);
+	return retBuffer;
+}
+
+/*! Sets the size of the image. The image will not exceed the bounds of the content area.
+	@param x/y The space-delimited x and y values of the image size.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, setImageSize, ConsoleVoid, 3, 3, "(Vector2 x y)")
+{
+	if (argc != 3)
+	{
+		Con::warnf("GuiSpriteCtrl::setImageSize() - Invalid number of parameters!");
+		return;
+	}
+
+	const U32 posCount = Utility::mGetStringElementCount(argv[2]);
+	if (posCount != 2)
+	{
+		Con::warnf("GuiSpriteCtrl::setImageSize() - Size requires x and y");
+		return;
+	}
+
+	object->setImageSize(Point2I(dAtoi(Utility::mGetStringElement(argv[2], 0)),
+		dAtoi(Utility::mGetStringElement(argv[2], 0))));
+}
+
+/*! Gets the size of the image.
+	@return The space-delimited x and y values of the image size.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, getImageSize, ConsoleString, 2, 2, "()")
+{
+	char *retBuffer = Con::getReturnBuffer(64);
+	const Point2I &size = object->getImageSize();
+	dSprintf(retBuffer, 64, "%d %d", size.x, size.y);
+	return retBuffer;
+}
+
+/*! Sets the color that should be used to display the image.
+	@param r/g/b/a The space-delimited red, green, blue, and alpha values between 0 and 255.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, setImageColor, ConsoleVoid, 3, 3, "(color red/green/blue/[alpha])")
+{
+	if (argc != 3)
+	{
+		Con::warnf("GuiSpriteCtrl::setImageColor() - Invalid number of parameters!");
+		return;
+	}
+
+
+	const U32 colorCount = Utility::mGetStringElementCount(argv[2]);
+	if (colorCount != 3 && colorCount != 4)
+	{
+		Con::warnf("GuiSpriteCtrl::setImageColor() - Colors require 4 values between 0 and 255 (red, green, blue, alpha)!");
+		return;
+	}
+
+	U8 red, green, blue, alpha;
+	red = dAtoi(Utility::mGetStringElement(argv[2], 0));
+	green = dAtoi(Utility::mGetStringElement(argv[2], 1));
+	blue = dAtoi(Utility::mGetStringElement(argv[2], 2));
+	alpha = colorCount == 4 ? dAtoi(Utility::mGetStringElement(argv[2], 3)) : 255;
+	
+
+	object->setImageColor(ColorI(red, green, blue, alpha));
+}
+
+/*! Gets the current image color.
+	@return The space-delimited red, green, blue, and alpha values of the color.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, getImageColor, ConsoleString, 2, 2, "()")
+{
+	char *retBuffer = Con::getReturnBuffer(64);
+	const ColorI &color = object->getImageColor();
+	dSprintf(retBuffer, 64, "%d %d %d %d", color.red, color.green, color.blue, color.alpha);
+	return retBuffer;
+}
+
+/*! Sets if the bitmap should be broken into multiple frames based on the color of the first pixel.
+	@param isSingle If true, the bitmap has one and only one frame. If false, the top left pixel color will be used to divide the bitmap into frames.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, setSingleFrameBitmap, ConsoleVoid, 3, 3, "(bool isSingle)")
+{
+	//Are we using an asset?
+	if (object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::setSingleFrameBitmap() - Method invalid, using an asset.");
+		return;
+	}
+
+	if (argc != 3)
+	{
+		Con::warnf("GuiSpriteCtrl::setSingleFrameBitmap() - Invalid number of parameters!");
+		return;
+	}
+
+	object->setSingleFrameBitmap(dAtob(argv[2]));
+}
+
+/*! Gets if the bitmap should be broken into multiple frames based on the color of the first pixel.
+	@return Returns true if there's only one frame for the bitmap and false otherwise.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, getSingleFrameBitmap, ConsoleBool, 2, 2, "()")
+{
+	//Are we using a asset?
+	if (object->usesAsset())
+	{
+		// Yes, so warn.
+		Con::warnf("GuiSpriteCtrl::getSingleFrameBitmap() - Method invalid, using an asset.");
+		return true;
+	}
+
+	return object->getSingleFrameBitmap();
+}
+
+/*! Sets if the image should tile across the content area of the control.
+	@param tileImage If true, the image will tile. If false, it will display a single copy of the image.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, setTileImage, ConsoleVoid, 3, 3, "(bool tileImage)")
+{
+	if (argc != 3)
+	{
+		Con::warnf("GuiSpriteCtrl::setTileImage() - Invalid number of parameters!");
+		return;
+	}
+
+	object->setTileImage(dAtob(argv[2]));
+}
+
+/*! Gets if the image will tile across the content area of the control.
+	@return True if tiling is on and false otherwise.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, getTileImage, ConsoleBool, 2, 2, "()")
+{
+	return object->getTileImage();
+}
+
+/*! Sets if the image should take the entire content area.
+	@param fullSize If true, the image will take the entire content area. False will cause the image to use the image size.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, setFullSize, ConsoleVoid, 3, 3, "(bool fullSize)")
+{
+	if (argc != 3)
+	{
+		Con::warnf("GuiSpriteCtrl::setFullSize() - Invalid number of parameters!");
+		return;
+	}
+
+	object->setFullSize(dAtob(argv[2]));
+}
+
+/*! Gets if the image will take the entire content area.
+	@return True if using the entire content area and false otherwise.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, getFullSize, ConsoleBool, 2, 2, "()")
+{
+	return object->getFullSize();
+}
+
+/*! Sets if the image should keep its aspect ratio.
+	@param constrain If true, maintain its aspect ratio. False otherwise.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, setConstrainProportions, ConsoleVoid, 3, 3, "(bool constrain)")
+{
+	if (argc != 3)
+	{
+		Con::warnf("GuiSpriteCtrl::setConstrainProportions() - Invalid number of parameters!");
+		return;
+	}
+
+	object->setConstrainProportions(dAtob(argv[2]));
+}
+
+/*! Gets if the image will maintain its aspect ratio.
+	@return True it will constrain proportions and false otherwise.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, getConstrainProportions, ConsoleBool, 2, 2, "()")
+{
+	return object->getConstrainProportions();
+}
+
+/*! Animates the position offset from its current value to a target value over time.
+	@param x/y The space-delimited x and y values to change the image offset to.
+	@param time The time in miliseconds it should take to complete the transformation.
+	@param ease The optional easing function that should be applied to the the animation. Defaults to linear.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, moveTo, ConsoleVoid, 4, 5, "(Vector2 x y, int time, [EasingFunction ease])")
+{
+	if (argc != 4 && argc != 5)
+	{
+		Con::warnf("GuiSpriteCtrl::moveTo() - Invalid number of parameters!");
+		return;
+	}
+
+	const U32 posCount = Utility::mGetStringElementCount(argv[2]);
+	if (posCount != 2)
+	{
+		Con::warnf("GuiSpriteCtrl::moveTo() - Position requires x and y");
+		return;
+	}
+
+	EasingFunction ease = Linear;
+	if (argc == 5)
+	{
+		for (U32 i = 0; i < (sizeof(easingEnums) / sizeof(EnumTable::Enums)); i++)
+		{
+			if (dStricmp(easingEnums[i].label, argv[4]) == 0)
+				ease = (EasingFunction)easingEnums[i].index;
+		}
+	}
+
+	object->moveTo(dAtoi(Utility::mGetStringElement(argv[2], 0)),
+		dAtoi(Utility::mGetStringElement(argv[2], 0)),
+		dAtoi(argv[3]), ease);
+}
+
+/*! Animates the image size from its current value to a target value over time.
+	@param x/y The space-delimited x and y values to change the image size to. Note that the image will not exceed the content area of the control.
+	@param time The time in miliseconds it should take to complete the transformation.
+	@param ease The optional easing function that should be applied to the the animation. Defaults to linear.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, growTo, ConsoleVoid, 4, 5, "(Vector2 x y, int time, [EasingFunction ease])")
+{
+	if (argc != 4 && argc != 5)
+	{
+		Con::warnf("GuiSpriteCtrl::growTo() - Invalid number of parameters!");
+		return;
+	}
+
+	const U32 posCount = Utility::mGetStringElementCount(argv[2]);
+	if (posCount != 2)
+	{
+		Con::warnf("GuiSpriteCtrl::growTo() - Position requires x and y");
+		return;
+	}
+
+	EasingFunction ease = Linear;
+	if (argc == 5)
+	{
+		for (U32 i = 0; i < (sizeof(easingEnums) / sizeof(EnumTable::Enums)); i++)
+		{
+			if (dStricmp(easingEnums[i].label, argv[4]) == 0)
+				ease = (EasingFunction)easingEnums[i].index;
+		}
+	}
+
+	object->growTo(dAtoi(Utility::mGetStringElement(argv[2], 0)),
+		dAtoi(Utility::mGetStringElement(argv[2], 0)),
+		dAtoi(argv[3]), ease);
+}
+
+/*! Animates the image color from its current value to a target value over time.
+	@param red/green/blue/alpha The space-delimited color values to change the image color to. Color values should be between 0 and 255.
+	@param time The time in miliseconds it should take to complete the transformation.
+	@param ease The optional easing function that should be applied to the the animation. Defaults to linear.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiSpriteCtrl, fadeTo, ConsoleVoid, 4, 5, "(Vector2 x y, int time, [EasingFunction ease])")
+{
+	if (argc != 4 && argc != 5)
+	{
+		Con::warnf("GuiSpriteCtrl::fadeTo() - Invalid number of parameters!");
+		return;
+	}
+
+	const U32 colorCount = Utility::mGetStringElementCount(argv[2]);
+	if (colorCount != 4)
+	{
+		Con::warnf("GuiSpriteCtrl::fadeTo() - Color requires 4 values between 0 and 255 (red, green, blue, alpha)");
+		return;
+	}
+
+	EasingFunction ease = Linear;
+	if (argc == 5)
+	{
+		for (U32 i = 0; i < (sizeof(easingEnums) / sizeof(EnumTable::Enums)); i++)
+		{
+			if (dStricmp(easingEnums[i].label, argv[4]) == 0)
+				ease = (EasingFunction)easingEnums[i].index;
+		}
+	}
+
+	object->fadeTo(ColorI(dAtof(Utility::mGetStringElement(argv[2], 0)),
+		dAtof(Utility::mGetStringElement(argv[2], 1)),
+		dAtof(Utility::mGetStringElement(argv[2], 2)),
+		dAtof(Utility::mGetStringElement(argv[2], 3))),
+		dAtoi(argv[3]), ease);
+}
+
 ConsoleMethodGroupEndWithDocs(GuiSpriteCtrl)

+ 0 - 262
engine/source/gui/guiBitmapCtrl.cc

@@ -1,262 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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.
-//-----------------------------------------------------------------------------
-
-#include "console/console.h"
-#include "console/consoleTypes.h"
-#include "graphics/dgl.h"
-
-#include "gui/guiBitmapCtrl.h"
-
-IMPLEMENT_CONOBJECT(GuiBitmapCtrl);
-
-GuiBitmapCtrl::GuiBitmapCtrl(void)
-{
-    mBitmapName = StringTable->EmptyString;
-    startPoint.set(0, 0);
-    mWrap = false;
-
-    //Luma:	Ability to specify source rect for image UVs
-    mUseSourceRect = false;
-    mSourceRect.set(0, 0, 0, 0);
-}
-
-bool GuiBitmapCtrl::setBitmapName( void *obj, const char *data )
-{
-   // Prior to this, you couldn't do bitmap.bitmap = "foo.jpg" and have it work.
-   // With protected console types you can now call the setBitmap function and
-   // make it load the image.
-   static_cast<GuiBitmapCtrl *>( obj )->setBitmap( data );
-
-   // Return false because the setBitmap method will assign 'mBitmapName' to the
-   // argument we are specifying in the call.
-   return false;
-}
-
-void GuiBitmapCtrl::initPersistFields()
-{
-   Parent::initPersistFields();
-   addGroup("GuiBitmapCtrl");		
-   addProtectedField( "bitmap", TypeFilename, Offset( mBitmapName, GuiBitmapCtrl ), &setBitmapName, &defaultProtectedGetFn, "" );
-   //addField("bitmap", TypeFilename, Offset(mBitmapName, GuiBitmapCtrl));
-   addField("wrap",   TypeBool,     Offset(mWrap,       GuiBitmapCtrl));
-   endGroup("GuiBitmapCtrl");		
-
-   //Luma:	ability to specify source rect for image UVs
-   addGroup("Misc");
-   //ability to specify source rect for image UVs
-   addField( "useSourceRect", TypeBool, Offset( mUseSourceRect, GuiBitmapCtrl ));
-   addField( "sourceRect", TypeRectI, Offset( mSourceRect, GuiBitmapCtrl ));
-   endGroup("Misc");	
-}
-
-ConsoleMethod( GuiBitmapCtrl, setValue, void, 4, 4, "(int xAxis, int yAxis)"
-              "Set the offset of the bitmap.\n"
-              "@return No return value."
-              )
-{
-   object->setValue(dAtoi(argv[2]), dAtoi(argv[3]));
-}
-
-ConsoleMethod( GuiBitmapCtrl, setBitmap, void, 3, 3, "( pathName ) Use the setBitmap method to change the bitmap this control uses.\n"
-                                                                "@param pathName A path to a new texture for this control. Limited to 256x256.\n"
-                                                                "@return No return value")
-{
-   object->setBitmap(argv[2]);
-}
-
-ConsoleMethod(GuiBitmapCtrl, getTextureWidth, S32, 2, 2, "Gets the Width of the Texture.\n"
-              "@return Texture Width"
-              )
-{
-   return object->getWidth();
-}
-
-ConsoleMethod(GuiBitmapCtrl, getTextureHeight, S32, 2, 2, "Gets the Height of the Texture.\n"
-              "@return Texture Height"
-              )
-{
-   return object->getHeight();
-}
-
-bool GuiBitmapCtrl::onWake()
-{
-   if (! Parent::onWake())
-      return false;
-   setActive(true);
-   setBitmap(mBitmapName);
-   return true;
-}
-
-void GuiBitmapCtrl::onSleep()
-{
-   mTextureHandle = NULL;
-   Parent::onSleep();
-}
-
-//-------------------------------------
-void GuiBitmapCtrl::inspectPostApply()
-{
-   // if the extent is set to (0,0) in the gui editor and appy hit, this control will
-   // set it's extent to be exactly the size of the bitmap (if present)
-   Parent::inspectPostApply();
-
-   if (!mWrap && (mBounds.extent.x == 0) && (mBounds.extent.y == 0) && mTextureHandle)
-   {
-      TextureObject *texture = (TextureObject *) mTextureHandle;
-      mBounds.extent.x = texture->getBitmapWidth();
-      mBounds.extent.y = texture->getBitmapHeight();
-   }
-}
-
-void GuiBitmapCtrl::setBitmap(const char *name, bool resize)
-{
-   mBitmapName = StringTable->insert(name);
-   if (*mBitmapName) {
-	   mTextureHandle = TextureHandle(mBitmapName, TextureHandle::BitmapTexture, true);
-	   mTextureHandle.setFilter(GL_LINEAR);
-
-      // Resize the control to fit the bitmap
-      if (resize) {
-         TextureObject* texture = (TextureObject *) mTextureHandle;
-         mBounds.extent.x = texture->getBitmapWidth();
-         mBounds.extent.y = texture->getBitmapHeight();
-         GuiControl *parent = getParent();
-         if( !parent ) {
-             Con::errorf( "GuiBitmapCtrl::setBitmap( %s ), trying to resize but object has no parent.", name ) ;
-         } else {
-             Point2I extent = parent->getExtent();
-         parentResized(extent,extent);
-      }
-   }
-   }
-   else
-      mTextureHandle = NULL;
-   setUpdate();
-}
-
-
-void GuiBitmapCtrl::setBitmap(const TextureHandle &handle, bool resize)
-{
-   mTextureHandle = handle;
-
-   // Resize the control to fit the bitmap
-   if (resize) {
-      TextureObject* texture = (TextureObject *) mTextureHandle;
-      mBounds.extent.x = texture->getBitmapWidth();
-      mBounds.extent.y = texture->getBitmapHeight();
-      Point2I extent = getParent()->getExtent();
-      parentResized(extent,extent);
-   }
-}
-
-
-void GuiBitmapCtrl::onRender(Point2I offset, const RectI &updateRect)
-{
-   if (mTextureHandle)
-   {
-      dglClearBitmapModulation();
-        if(mWrap)
-        {
-         // We manually draw each repeat because non power of two textures will 
-         // not tile correctly when rendered with dglDrawBitmapTile(). The non POT
-         // bitmap will be padded by the hardware, and we'll see lots of slack
-         // in the texture. So... lets do what we must: draw each repeat by itself:
-         TextureObject* texture = (TextureObject *) mTextureHandle;
-            RectI srcRegion;
-            RectI dstRegion;
-            float xdone = ((float)mBounds.extent.x/(float)texture->getBitmapWidth())+1;
-            float ydone = ((float)mBounds.extent.y/(float)texture->getBitmapHeight())+1;
-
-            int xshift = startPoint.x%texture->getBitmapWidth();
-            int yshift = startPoint.y%texture->getBitmapHeight();
-            for(int y = 0; y < ydone; ++y)
-                for(int x = 0; x < xdone; ++x)
-                {
-                    //Luma:	ability to specify source rect for image UVs
-                    if(mUseSourceRect && mSourceRect.isValidRect())
-                    {
-                        srcRegion = mSourceRect;
-                    }
-                    else
-                    {
-                        srcRegion.set(0,0,texture->getBitmapWidth(),texture->getBitmapHeight());
-                    }
-                    dstRegion.set( ((texture->getBitmapWidth()*x)+offset.x)-xshift,
-                                      ((texture->getBitmapHeight()*y)+offset.y)-yshift,
-                                      texture->getBitmapWidth(),	
-                                      texture->getBitmapHeight());
-                dglDrawBitmapStretchSR(texture,dstRegion, srcRegion, false);
-                }
-        }
-        else
-      {
-         RectI rect(offset, mBounds.extent);
-        
-         //Luma:	ability to specify source rect for image UVs
-         if(mUseSourceRect && mSourceRect.isValidRect() )
-         {
-            RectI srcRegion;
-            srcRegion = mSourceRect;
-            dglDrawBitmapStretchSR(mTextureHandle,rect, srcRegion, false);
-        }
-        else
-        {
-            dglDrawBitmapStretch(mTextureHandle, rect);
-        }
-      }
-   }
-
-   if (mProfile->mBorderDefault && *mProfile->mBorderDefault->mBorder > 0 && !mTextureHandle)
-   {
-      RectI rect(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
-      dglDrawRect(rect, mProfile->mBorderDefault->mBorderColor[0]);
-   }
-
-   renderChildControls(offset, mBounds, updateRect);
-}
-
-void GuiBitmapCtrl::setValue(S32 x, S32 y)
-{
-   if (mTextureHandle)
-   {
-        TextureObject* texture = (TextureObject *) mTextureHandle;
-        x+=texture->getBitmapWidth()/2;
-        y+=texture->getBitmapHeight()/2;
-    }
-    while (x < 0)
-        x += 256;
-    startPoint.x = x % 256;
-                
-    while (y < 0)
-        y += 256;
-    startPoint.y = y % 256;
-}
-
-//Luma:	ability to specify source rect for image UVs
-void GuiBitmapCtrl::setSourceRect(U32 x, U32 y, U32 width, U32 height) 
-{ 
-    mSourceRect.set(x, y, width, height); 
-} 
-void GuiBitmapCtrl::setUseSourceRect(bool bUse)
-{
-    mUseSourceRect = bUse;
-}

+ 0 - 78
engine/source/gui/guiBitmapCtrl.h

@@ -1,78 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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 _GUIBITMAPCTRL_H_
-#define _GUIBITMAPCTRL_H_
-
-#ifndef _GUICONTROL_H_
-#include "gui/guiControl.h"
-#endif
-#ifndef _TEXTURE_MANAGER_H_
-#include "graphics/TextureManager.h"
-#endif
-
-
-/// Renders a bitmap.
-class GuiBitmapCtrl : public GuiControl
-{
-private:
-   typedef GuiControl Parent;
-
-protected:
-   static bool setBitmapName( void *obj, const char *data );
-   static const char *getBitmapName( void *obj, const char *data );
-
-   StringTableEntry mBitmapName;
-   TextureHandle mTextureHandle;
-   Point2I startPoint;
-   bool mWrap;
-
-   //Luma:	ability to specify source rect for image UVs
-   bool		mUseSourceRect;
-   RectI	mSourceRect;
-
-public:
-   //creation methods
-   DECLARE_CONOBJECT(GuiBitmapCtrl);
-   GuiBitmapCtrl();
-   static void initPersistFields();
-
-   //Parental methods
-   bool onWake();
-   void onSleep();
-   void inspectPostApply();
-
-   void setBitmap(const char *name,bool resize = false);
-   void setBitmap(const TextureHandle &handle,bool resize = false);
-
-   S32 getWidth() const       { return(mTextureHandle.getWidth()); }
-   S32 getHeight() const      { return(mTextureHandle.getHeight()); }
-
-   //Luma:	ability to specify source rect for image UVs
-   void setSourceRect(U32 x, U32 y, U32 width, U32 height);
-   void setUseSourceRect(bool bUse);
-
-   void onRender(Point2I offset, const RectI &updateRect);
-   void setValue(S32 x, S32 y);
-};
-
-#endif

+ 1 - 1
engine/source/gui/guiDefaultControlRender.cc

@@ -207,7 +207,7 @@ void renderSizableBorderedImageAsset(RectI &bounds, U8 frame, ImageAsset *imageA
 		const ImageAsset::FrameArea::PixelArea& pixelArea9 = imageAsset->getImageFrameArea((U32)i+8).mPixelArea;
 
 		renderSizableBorderedTexture(bounds, imageAsset->getImageTexture(), 
-			RectI(pixelArea1.mPixelOffset, Point2I(pixelArea1.mPixelWidth, pixelArea1.mPixelHeight)),
+			pixelArea1.toRectI(),
 			RectI(pixelArea2.mPixelOffset, Point2I(pixelArea2.mPixelWidth, pixelArea2.mPixelHeight)),
 			RectI(pixelArea3.mPixelOffset, Point2I(pixelArea3.mPixelWidth, pixelArea3.mPixelHeight)), 
 			RectI(pixelArea4.mPixelOffset, Point2I(pixelArea4.mPixelWidth, pixelArea4.mPixelHeight)), 

+ 0 - 136
engine/source/gui/guiFadeinBitmapCtrl.cc

@@ -1,136 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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.
-//-----------------------------------------------------------------------------
-
-#include "console/console.h"
-#include "console/consoleTypes.h"
-#include "graphics/dgl.h"
-
-#include "gui/guiBitmapCtrl.h"
-
-class GuiFadeinBitmapCtrl : public GuiBitmapCtrl
-{
-   typedef GuiBitmapCtrl Parent;
-public:
-   U32 wakeTime;
-   bool done;
-   U32 fadeinTime;
-   U32 waitTime;
-   U32 fadeoutTime;
-
-   GuiFadeinBitmapCtrl()
-   {
-      wakeTime    = 0;
-      fadeinTime  = 1000;
-      waitTime    = 2000;
-      fadeoutTime = 1000;
-      done        = false;
-   }
-   void onPreRender()
-   {
-      Parent::onPreRender();
-      setUpdate();
-   }
-   void onMouseDown(const GuiEvent &)
-   {
-      Con::executef(this, 1, "click");
-   }
-   bool onKeyDown(const GuiEvent &)
-   {
-      Con::executef(this, 1, "click");
-      return true;
-   }
-   DECLARE_CONOBJECT(GuiFadeinBitmapCtrl);
-   bool onWake()
-   {
-      if(!Parent::onWake())
-         return false;
-      wakeTime = Platform::getRealMilliseconds();
-      done = false;
-      return true;
-   }
-   void onRender(Point2I offset, const RectI &updateRect)
-   {
-      Parent::onRender(offset, updateRect);
-      U32 elapsed = Platform::getRealMilliseconds() - wakeTime;
-
-      U32 alpha;
-      if (elapsed < fadeinTime)
-      {
-         // fade-in
-         alpha = (U32)(255 - (255 * (F32(elapsed) / F32(fadeinTime))));
-      }
-      else if (elapsed < (fadeinTime+waitTime))
-      {
-         // wait
-         alpha = 0;
-      }
-      else if (elapsed < (fadeinTime+waitTime+fadeoutTime))
-      {
-         // fade out
-         elapsed -= (fadeinTime+waitTime);
-         alpha = (U32)(255 * F32(elapsed) / F32(fadeoutTime));
-      }
-      else
-      {
-         // done state
-         alpha = fadeoutTime ? 255 : 0;
-         done = true;
-      }
-      ColorI color(0,0,0,alpha);
-      dglDrawRectFill(offset, mBounds.extent + offset, color);
-   }
-   static void initPersistFields()
-   {
-      Parent::initPersistFields();
-      addField("fadeinTime", TypeS32, Offset(fadeinTime, GuiFadeinBitmapCtrl));
-      addField("waitTime", TypeS32, Offset(waitTime, GuiFadeinBitmapCtrl));
-      addField("fadeoutTime", TypeS32, Offset(fadeoutTime, GuiFadeinBitmapCtrl));
-      addField("done", TypeBool, Offset(done, GuiFadeinBitmapCtrl));
-   }
-};
-
-IMPLEMENT_CONOBJECT(GuiFadeinBitmapCtrl);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-

+ 102 - 0
engine/source/math/mFluid.cpp

@@ -21,8 +21,20 @@
 //-----------------------------------------------------------------------------
 
 #include "platform/platform.h"
+#include "platform/types.h"
+#include "console/consoleTypes.h"
+#include "console/console.h"
+#include "console/consoleInternal.h"
 #include "math/mFluid.h"
 
+#ifndef _TICKABLE_H_
+#include "platform/Tickable.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
+
 Fluid::Fluid()
 {
 	mAnimationLength = 1000;
@@ -74,6 +86,14 @@ const char* Fluid::getEasingFunctionDescription(const EasingFunction ease)
 
 //------------------------------------------------------------------------
 
+FluidColorI::FluidColorI(ColorI &color)
+{
+	red = color.red;
+	green = color.green;
+	blue = color.blue;
+	alpha = color.alpha;
+}
+
 void FluidColorI::startFluidAnimation(const ColorI &color)
 {
 	mAnimationProgress = 0.0f;
@@ -115,4 +135,86 @@ void FluidColorI::set(const ColorI& in_rCopy)
 	green = in_rCopy.green;
 	blue = in_rCopy.blue;
 	alpha = in_rCopy.alpha;
+}
+
+void FluidColorI::set(U8 red, U8 green, U8 blue, U8 alpha)
+{
+	red = red;
+	green = green;
+	blue = blue;
+	alpha = alpha;
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleType(FluidColorI, TypeFluidColorI, sizeof(FluidColorI), "")
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeFluidColorI)
+{
+	// Fetch color.
+	FluidColorI* color = (FluidColorI*)dptr;
+
+	// Fetch stock color name.
+	StringTableEntry colorName = StockColor::name(*color);
+
+	// Write as color name if was found.
+	if (colorName != StringTable->EmptyString)
+		return colorName;
+
+	// Format as color components.
+	char* returnBuffer = Con::getReturnBuffer(256);
+	dSprintf(returnBuffer, 256, "%d %d %d %d", color->red, color->green, color->blue, color->alpha);
+	return returnBuffer;
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeFluidColorI)
+{
+	FluidColorI* color = (FluidColorI*)dptr;
+	if (argc == 1)
+	{
+		// Is only a single argument passed?
+		if (StringUnit::getUnitCount(argv[0], " ") == 1)
+		{
+			// Is this a stock color name?
+			if (!StockColor::isColor(argv[0]))
+			{
+				// No, so warn.
+				Con::warnf("FluidColorI() - Invalid single argument of '%s' could not be interpreted as a stock color name.  Using default.", argv[0]);
+			}
+
+			// Set stock color (if it's invalid we'll get the default.
+			color->set(argv[0]);
+
+			return;
+		}
+
+		color->set(0, 0, 0, 255);
+		S32 r, g, b, a;
+		const S32 args = dSscanf(argv[0], "%d %d %d %d", &r, &g, &b, &a);
+		color->red = r;
+		color->green = g;
+		color->blue = b;
+		if (args == 4)
+			color->alpha = a;
+	}
+	else if (argc == 3)
+	{
+		color->red = dAtoi(argv[0]);
+		color->green = dAtoi(argv[1]);
+		color->blue = dAtoi(argv[2]);
+		color->alpha = 255;
+	}
+	else if (argc == 4)
+	{
+		color->red = dAtoi(argv[0]);
+		color->green = dAtoi(argv[1]);
+		color->blue = dAtoi(argv[2]);
+		color->alpha = dAtoi(argv[3]);
+	}
+	else
+		Con::printf("Color must be set as { r, g, b [,a] }, { r g b [b] }  or { stockColorName }");
 }

+ 10 - 0
engine/source/math/mFluid.h

@@ -35,6 +35,8 @@
 #include "graphics/gColor.h"
 #endif
 
+DefineConsoleType(TypeFluidColorI)
+
 class Fluid
 {
 protected:
@@ -78,9 +80,17 @@ protected:
 	U8 alphaTarget;
 
 public:
+	FluidColorI() { }
+	FluidColorI(ColorI &color);
+	FluidColorI(const U8 in_r,
+		const U8 in_g,
+		const U8 in_b,
+		const U8 in_a = U8(255)) : ColorI(in_r, in_g, in_b, in_a) { };
+
 	virtual void startFluidAnimation(const ColorI &color);
 	virtual bool processTick(); //Returns true if we should continue to processTicks
 	void set(const ColorI& in_rCopy);
+	void set(U8 red, U8 green, U8 blue, U8 alpha = 255);
 };
 
 #endif // _MFLUID_H_

+ 13 - 6
toybox/GuiEditorToy/1/assets/gui/guiEditorCtrl.gui

@@ -14,8 +14,9 @@
    isContainer = "1";
    canSave = "1";
    canSaveDynamicFields = "1";
-   
-    new GuiBitmapCtrl() {
+
+    new GuiSpriteCtrl() {
+		Profile = "GuiDefaultProfile";
 		HorizSizing = "width";
         VertSizing = "height";
         Position = "0 0";
@@ -24,10 +25,16 @@
         canSave = "1";
         Visible = "1";
         hovertime = "1000";
+		imageColor = "255 255 255 255";
         bitmap = "./images/gridTiny2";
-        wrap = "1";
+		singleFrameBitmap = "1";
+		tileImage = "1";
+		positionOffset = "0 0";
+		imageSize = "128 128";
+		fullSize = "0";
+		constrainProportions = "1";
 	};
-   
+
     new GuiControl(GuiEditorContent) {
         canSaveDynamicFields = "0";
         isContainer = "1";
@@ -40,7 +47,7 @@
         canSave = "1";
         Visible = "1";
         hovertime = "1000";
-				  
+
 		new GuiControl(GuiBlank) {
             canSaveDynamicFields = "0";
             isContainer = "1";
@@ -55,7 +62,7 @@
             hovertime = "1000";
 		};
 	};
-		
+
 	new GuiEditCtrl(GuiEditor) {
 		canSaveDynamicFields = "0";
 		isContainer = "0";

+ 4 - 2
toybox/Sandbox/1/gui/ToolboxDialog.gui.taml

@@ -1,13 +1,15 @@
 <GuiSpriteCtrl
     Name="ToolboxDialog"
-    Profile="GuiToolboxProfile"
+    Profile="GuiDefaultProfile"
     HorizSizing="relative"
     VertSizing="relative"
     Position="0 0"
     Extent="1024 768"
     MinExtent="320 320"
     Visible="1"
-	Image="@asset=Sandbox:blueGradient">
+	Image="@asset=Sandbox:blueGradient"
+	imageColor="255 255 255 220"
+	constrainProportions="0">
 
 	<!-- Close Toolbox -->
 	<GuiButtonCtrl

+ 1 - 11
toybox/Sandbox/1/gui/guiProfiles.cs

@@ -334,10 +334,7 @@ if(!isObject(GuiTabPageProfile)) new GuiControlProfile (GuiTabPageProfile : GuiD
 };
 
 
-if(!isObject(GuiSpriteProfile)) new GuiControlProfile (GuiSpriteProfile : GuiDefaultProfile)
-{
-	FillColor = "255 255 255 255";
-};
+if(!isObject(GuiSpriteProfile)) new GuiControlProfile (GuiSpriteProfile : GuiDefaultProfile);
 
 // ----------------------------------------------------------------------------
 if (!isObject(GuiTreeViewProfile)) new GuiControlProfile (GuiTreeViewProfile : GuiDefaultProfile)
@@ -566,13 +563,6 @@ if(!isObject(GuiTransparentScrollProfile)) new GuiControlProfile (GuiTransparent
 
 //-----------------------------------------------------------------------------
 
-if(!isObject(GuiToolboxProfile)) new GuiControlProfile( GuiToolboxProfile : GuiScrollProfile )
-{
-    fillColor = "255 255 255 220";
-};
-
-//-----------------------------------------------------------------------------
-
 if(!isObject(SandboxWindowProfile)) new GuiControlProfile (SandboxWindowProfile : GuiDefaultProfile)
 {
     // fill color