Torque3D/Engine/source/gui/controls/guiBitmapCtrl.cpp

389 lines
12 KiB
C++
Raw Normal View History

2012-09-19 11:15:01 -04:00
//-----------------------------------------------------------------------------
// Copyright (c) 2012 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 "platform/platform.h"
#include "gui/controls/guiBitmapCtrl.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "console/engineAPI.h"
#include "gfx/gfxDevice.h"
#include "gfx/gfxDrawUtil.h"
#include "gfx/gfxAPI.h"
#include "gui/buttons/guiButtonBaseCtrl.h"
2012-09-19 11:15:01 -04:00
#include "materials/matTextureTarget.h"
2012-09-19 11:15:01 -04:00
IMPLEMENT_CONOBJECT(GuiBitmapCtrl);
2024-12-21 23:02:23 +00:00
ConsoleDocClass(GuiBitmapCtrl,
2012-09-19 11:15:01 -04:00
"@brief A gui control that is used to display an image.\n\n"
2024-12-21 23:02:23 +00:00
2012-09-19 11:15:01 -04:00
"The image is stretched to the constraints of the control by default. However, the control can also\n"
"tile the image as well.\n\n"
"The image itself is stored inside the GuiBitmapCtrl::bitmap field. The boolean value that decides\n"
"whether the image is stretched or tiled is stored inside the GuiBitmapCtrl::wrap field.\n"
2024-12-21 23:02:23 +00:00
2012-09-19 11:15:01 -04:00
"@tsexample\n"
"// Create a tiling GuiBitmapCtrl that displays \"myImage.png\"\n"
"%bitmapCtrl = new GuiBitmapCtrl()\n"
"{\n"
" bitmap = \"myImage.png\";\n"
" wrap = \"true\";\n"
"};\n"
"@endtsexample\n\n"
2024-12-21 23:02:23 +00:00
2012-09-19 11:15:01 -04:00
"@ingroup GuiControls"
);
ImplementEnumType(BitmapDrawMode,
"Draw Mode of the bitmap control.\n\n"
"@ingroup GuiControls")
{
GuiBitmapCtrl::BitmapMode_Stretch, "Stretch", "Stretches the bitmap to fill the control extents. Aspect ratio is not preserved."
},
{ GuiBitmapCtrl::BitmapMode_Tile, "Tile", "Repeats the bitmap to fill the control extents without scaling." },
{ GuiBitmapCtrl::BitmapMode_Fit, "Fit", "Scales the bitmap to fit entirely within the control while preserving aspect ratio. May result in letterboxing." },
{ GuiBitmapCtrl::BitmapMode_Fill, "Fill", "Scales the bitmap to completely fill the control while preserving aspect ratio. Portions of the bitmap may be cropped." },
{ GuiBitmapCtrl::BitmapMode_Center, "Center", "Draws the bitmap at its original size centered within the control. No scaling is applied." },
EndImplementEnumType;
2012-09-19 11:15:01 -04:00
GuiBitmapCtrl::GuiBitmapCtrl(void)
2024-12-21 23:02:23 +00:00
: mStartPoint(0, 0),
mColor(ColorI::WHITE),
mAngle(0),
2024-12-21 23:02:23 +00:00
mWrap(false),
mDrawMode(BitmapMode_Stretch),
mFilterType(GFXTextureFilterLinear),
2024-12-21 23:02:23 +00:00
mBitmap(NULL),
mBitmapName(StringTable->EmptyString())
2012-09-19 11:15:01 -04:00
{
}
void GuiBitmapCtrl::initPersistFields()
{
docsURL;
2024-12-21 23:02:23 +00:00
addGroup("Bitmap");
INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiBitmapCtrl, "The bitmap to render in this BitmapCtrl.")
2026-02-17 00:23:53 +00:00
addField("color", TypeColorI, Offset(mColor, GuiBitmapCtrl), "color mul");
addField("wrap", TypeBool, Offset(mWrap, GuiBitmapCtrl), "If true, the bitmap is tiled inside the control rather than stretched to fit.");
addField("drawMode", TYPEID<BitmapMode>(), Offset(mDrawMode, GuiBitmapCtrl), "Sets the mode to draw this bitmap in this control (wrap forces Tile mode).");
addField("filterType", TYPEID<GFXTextureFilterType>(), Offset(mFilterType, GuiBitmapCtrl), "Sets the bitmap texture filter mode.");
addFieldV("angle", TypeRangedF32, Offset(mAngle, GuiBitmapCtrl), &CommonValidators::DegreeRange, "rotation");
endGroup("Bitmap");
2012-09-19 11:15:01 -04:00
Parent::initPersistFields();
}
bool GuiBitmapCtrl::onWake()
{
2024-12-21 23:02:23 +00:00
if (!Parent::onWake())
2012-09-19 11:15:01 -04:00
return false;
setActive(true);
2012-09-19 11:15:01 -04:00
return true;
}
void GuiBitmapCtrl::onSleep()
{
mBitmap = NULL;
2012-09-19 11:15:01 -04:00
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 && (getExtent().x == 0) && (getExtent().y == 0) && getBitmap())
2012-09-19 11:15:01 -04:00
{
2024-12-21 23:02:23 +00:00
setExtent(mBitmap->getWidth(), mBitmap->getHeight());
2012-09-19 11:15:01 -04:00
}
}
2024-12-21 23:02:23 +00:00
void GuiBitmapCtrl::setBitmap(const char* name, bool resize)
2012-09-19 11:15:01 -04:00
{
2024-12-21 23:02:23 +00:00
// coming in here we are probably getting a filename.
if (AssetDatabase.isDeclaredAsset(name))
{
_setBitmap(StringTable->insert(name));
}
else
{
StringTableEntry assetId = ImageAsset::getAssetIdByFilename(StringTable->insert(name));
if (assetId != StringTable->EmptyString())
_setBitmap(assetId);
else
_setBitmap(StringTable->EmptyString());
2024-12-21 23:02:23 +00:00
}
2012-09-19 11:15:01 -04:00
if (mBitmapAsset.notNull())
{
mBitmap = mBitmapAsset->getTexture(&GFXDefaultGUIProfile);
if (getBitmap() && resize)
{
setExtent(mBitmap->getWidth(), mBitmap->getHeight());
updateSizing();
}
2012-09-19 11:15:01 -04:00
}
setUpdate();
}
void GuiBitmapCtrl::setBitmapHandle(GFXTexHandle handle, bool resize)
{
mBitmap = handle;
2012-09-19 11:15:01 -04:00
mBitmapName = StringTable->insert("texhandle");
2012-09-19 11:15:01 -04:00
// Resize the control to fit the bitmap
2024-12-21 23:02:23 +00:00
if (resize)
2012-09-19 11:15:01 -04:00
{
setExtent(mBitmap->getWidth(), mBitmap->getHeight());
2012-09-19 11:15:01 -04:00
updateSizing();
}
}
2024-12-21 23:02:23 +00:00
void GuiBitmapCtrl::updateSizing()
2012-09-19 11:15:01 -04:00
{
2024-12-21 23:02:23 +00:00
if (!getParent())
return;
// updates our bounds according to our horizSizing and verSizing rules
RectI fakeBounds(getPosition(), getParent()->getExtent());
parentResized(fakeBounds, fakeBounds);
}
void GuiBitmapCtrl::onRender(Point2I offset, const RectI& updateRect)
{
if (mBitmap.isNull() && mBitmapAsset.notNull())
mBitmap = getBitmap();
if (mBitmap)
2012-09-19 11:15:01 -04:00
{
GFX->getDrawUtil()->clearBitmapModulation();
GFX->getDrawUtil()->setBitmapModulation(mColor);
if (dynamic_cast<GuiButtonBaseCtrl*>(getParent()))
{
GuiButtonBaseCtrl* parent = static_cast<GuiButtonBaseCtrl*>(getParent());
GFX->getDrawUtil()->setBitmapModulation(mProfile->mFillColor);
if (parent->isHighlighted())
GFX->getDrawUtil()->setBitmapModulation(mProfile->mFillColorHL);
if (parent->isDepressed() || parent->getStateOn())
GFX->getDrawUtil()->setBitmapModulation(mProfile->mFillColorSEL);
if (!parent->isActive())
GFX->getDrawUtil()->setBitmapModulation(mProfile->mFillColorNA);
}
if (mWrap && mDrawMode != BitmapMode_Tile)
mDrawMode = BitmapMode_Tile;
RectI ctrlRect(offset, getExtent());
GFXTextureObject* texture = mBitmap;
F32 texW = (F32)texture->getWidth();
F32 texH = (F32)texture->getHeight();
F32 ctrlW = (F32)getExtent().x;
F32 ctrlH = (F32)getExtent().y;
switch (mDrawMode)
{
case BitmapMode_Tile:
2024-12-21 23:02:23 +00:00
{
// How many repetitions needed (+1 ensures full coverage)
const S32 xCount = (ctrlW / texW) + 1;
const S32 yCount = (ctrlH / texH) + 1;
// Scroll offset (wrap-safe)
const S32 xShift = mStartPoint.x % (S32)texW;
const S32 yShift = mStartPoint.y % (S32)texH;
RectI srcRegion(0, 0, (S32)texW, (S32)texH);
2024-12-21 23:02:23 +00:00
RectI dstRegion;
for (S32 y = 0; y < yCount; ++y)
{
for (S32 x = 0; x < xCount; ++x)
2024-12-21 23:02:23 +00:00
{
dstRegion.set(
offset.x + (x * texW) - xShift,
offset.y + (y * texH) - yShift,
texW,
texH
);
GFX->getDrawUtil()->drawBitmapStretchSR(texture, dstRegion, srcRegion, GFXBitmapFlip_None, mFilterType, true, mAngle);
2024-12-21 23:02:23 +00:00
}
}
2012-09-19 11:15:01 -04:00
break;
2024-12-21 23:02:23 +00:00
}
case GuiBitmapCtrl::BitmapMode_Fit:
{
F32 scale = getMin(ctrlW / texW, ctrlH / texH);
S32 drawW = (S32)(texW * scale);
S32 drawH = (S32)(texH * scale);
S32 x = offset.x + (ctrlW - drawW) * 0.5f;
S32 y = offset.y + (ctrlH - drawH) * 0.5f;
RectI dst(x, y, drawW, drawH);
GFX->getDrawUtil()->drawBitmapStretch(texture, dst, GFXBitmapFlip_None, mFilterType, false, mAngle);
break;
}
case GuiBitmapCtrl::BitmapMode_Fill:
{
F32 scale = getMax(ctrlW / texW, ctrlH / texH);
S32 drawW = (S32)(texW * scale);
S32 drawH = (S32)(texH * scale);
S32 x = offset.x + (ctrlW - drawW) * 0.5f;
S32 y = offset.y + (ctrlH - drawH) * 0.5f;
RectI dst(x, y, drawW, drawH);
GFX->getDrawUtil()->drawBitmapStretch(texture, dst, GFXBitmapFlip_None, mFilterType, false, mAngle);
break;
}
case GuiBitmapCtrl::BitmapMode_Center:
{
S32 x = offset.x + (ctrlW - texW) * 0.5f;
S32 y = offset.y + (ctrlH - texH) * 0.5f;
RectI dst(x, y, texW, texH);
GFX->getDrawUtil()->drawBitmapStretch(texture, dst, GFXBitmapFlip_None, mFilterType, false, mAngle);
break;
}
default:
2012-09-19 11:15:01 -04:00
{
GFX->getDrawUtil()->drawBitmapStretch(texture, ctrlRect, GFXBitmapFlip_None, mFilterType, false, mAngle);
break;
}
2012-09-19 11:15:01 -04:00
}
}
if (mProfile->mBorder || !mBitmap)
2012-09-19 11:15:01 -04:00
{
RectI rect(offset.x, offset.y, getExtent().x, getExtent().y);
GFX->getDrawUtil()->drawRect(rect, mProfile->mBorderColor);
}
renderChildControls(offset, updateRect);
}
void GuiBitmapCtrl::setValue(S32 x, S32 y)
{
if (getBitmap())
2012-09-19 11:15:01 -04:00
{
2024-12-21 23:02:23 +00:00
x += mBitmapAsset->getTextureBitmapWidth() / 2;
y += mBitmapAsset->getTextureBitmapHeight() / 2;
}
while (x < 0)
x += 256;
mStartPoint.x = x % 256;
while (y < 0)
y += 256;
mStartPoint.y = y % 256;
2012-09-19 11:15:01 -04:00
}
2024-12-21 23:02:23 +00:00
DefineEngineMethod(GuiBitmapCtrl, setValue, void, (S32 x, S32 y), ,
2012-09-19 11:15:01 -04:00
"Set the offset of the bitmap within the control.\n"
"@param x The x-axis offset of the image.\n"
"@param y The y-axis offset of the image.\n")
{
object->setValue(x, y);
}
//
static ConsoleDocFragment _sGuiBitmapCtrlSetBitmap1(
"@brief Assign an image to the control.\n\n"
"Child controls with resize according to their layout settings.\n"
"@param filename The filename of the image.\n"
"@param resize Optional parameter. If true, the GUI will resize to fit the image.",
"GuiBitmapCtrl", // The class to place the method in; use NULL for functions.
2024-12-21 23:02:23 +00:00
"void setBitmap( String filename, bool resize );"); // The definition string.
2012-09-19 11:15:01 -04:00
static ConsoleDocFragment _sGuiBitmapCtrlSetBitmap2(
"@brief Assign an image to the control.\n\n"
"Child controls will resize according to their layout settings.\n"
"@param filename The filename of the image.\n"
"@param resize A boolean value that decides whether the ctrl refreshes or not.",
"GuiBitmapCtrl", // The class to place the method in; use NULL for functions.
2024-12-21 23:02:23 +00:00
"void setBitmap( String filename );"); // The definition string.
2012-09-19 11:15:01 -04:00
//"Set the bitmap displayed in the control. Note that it is limited in size, to 256x256."
2024-12-21 23:02:23 +00:00
DefineEngineMethod(GuiBitmapCtrl, setBitmap, void, (const char* fileRoot, bool resize), (false),
2012-09-19 11:15:01 -04:00
"( String filename | String filename, bool resize ) Assign an image to the control.\n\n"
2024-12-21 23:02:23 +00:00
"@hide")
2012-09-19 11:15:01 -04:00
{
char filename[1024];
Con::expandScriptFilename(filename, sizeof(filename), fileRoot);
2024-12-21 23:02:23 +00:00
object->setBitmap(filename, resize);
2012-09-19 11:15:01 -04:00
}
2024-12-21 23:02:23 +00:00
DefineEngineMethod(GuiBitmapCtrl, getBitmap, const char*, (), ,
"Gets the current bitmap set for this control.\n\n"
"@hide")
{
2024-12-21 23:02:23 +00:00
return object->_getBitmap();
}
2024-12-21 23:02:23 +00:00
DefineEngineMethod(GuiBitmapCtrl, setNamedTexture, bool, (String namedtexture), ,
"@brief Set a texture as the image.\n\n"
"@param namedtexture The name of the texture (NamedTexTarget).\n"
2024-12-21 23:02:23 +00:00
"@return true if the texture exists.")
{
GFXTexHandle theTex;
2024-12-21 23:02:23 +00:00
NamedTexTarget* namedTarget = NULL;
namedTarget = NamedTexTarget::find(namedtexture.c_str());
2024-12-21 23:02:23 +00:00
if (namedTarget)
{
2024-12-21 23:02:23 +00:00
theTex = namedTarget->getTexture(0);
}
2024-12-21 23:02:23 +00:00
if (theTex.isValid())
{
2024-12-21 23:02:23 +00:00
object->setBitmapHandle(theTex, false);
return true; //a new texture was set correctly
}
return false; //we couldn't change the texture
}