mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-20 15:13:45 +00:00
388 lines
12 KiB
C++
388 lines
12 KiB
C++
//-----------------------------------------------------------------------------
|
|
// 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"
|
|
|
|
#include "materials/matTextureTarget.h"
|
|
|
|
|
|
IMPLEMENT_CONOBJECT(GuiBitmapCtrl);
|
|
|
|
ConsoleDocClass(GuiBitmapCtrl,
|
|
"@brief A gui control that is used to display an image.\n\n"
|
|
|
|
"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"
|
|
|
|
"@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"
|
|
|
|
"@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;
|
|
|
|
GuiBitmapCtrl::GuiBitmapCtrl(void)
|
|
: mStartPoint(0, 0),
|
|
mColor(ColorI::WHITE),
|
|
mAngle(0),
|
|
mWrap(false),
|
|
mDrawMode(BitmapMode_Stretch),
|
|
mFilterType(GFXTextureFilterLinear),
|
|
mBitmap(NULL),
|
|
mBitmapName(StringTable->EmptyString())
|
|
{
|
|
}
|
|
|
|
void GuiBitmapCtrl::initPersistFields()
|
|
{
|
|
docsURL;
|
|
addGroup("Bitmap");
|
|
|
|
INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiBitmapCtrl, "The bitmap to render in this BitmapCtrl.")
|
|
|
|
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");
|
|
|
|
Parent::initPersistFields();
|
|
}
|
|
|
|
bool GuiBitmapCtrl::onWake()
|
|
{
|
|
if (!Parent::onWake())
|
|
return false;
|
|
setActive(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
void GuiBitmapCtrl::onSleep()
|
|
{
|
|
mBitmap = 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 && (getExtent().x == 0) && (getExtent().y == 0) && getBitmap())
|
|
{
|
|
setExtent(mBitmap->getWidth(), mBitmap->getHeight());
|
|
}
|
|
}
|
|
|
|
void GuiBitmapCtrl::setBitmap(const char* name, bool resize)
|
|
{
|
|
// 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());
|
|
}
|
|
|
|
if (mBitmapAsset.notNull())
|
|
{
|
|
mBitmap = mBitmapAsset->getTexture(&GFXDefaultGUIProfile);
|
|
|
|
if (getBitmap() && resize)
|
|
{
|
|
|
|
setExtent(mBitmap->getWidth(), mBitmap->getHeight());
|
|
updateSizing();
|
|
}
|
|
}
|
|
|
|
setUpdate();
|
|
}
|
|
|
|
void GuiBitmapCtrl::setBitmapHandle(GFXTexHandle handle, bool resize)
|
|
{
|
|
mBitmap = handle;
|
|
|
|
mBitmapName = StringTable->insert("texhandle");
|
|
|
|
// Resize the control to fit the bitmap
|
|
if (resize)
|
|
{
|
|
setExtent(mBitmap->getWidth(), mBitmap->getHeight());
|
|
updateSizing();
|
|
}
|
|
}
|
|
|
|
void GuiBitmapCtrl::updateSizing()
|
|
{
|
|
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)
|
|
{
|
|
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:
|
|
{
|
|
// 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);
|
|
RectI dstRegion;
|
|
|
|
for (S32 y = 0; y < yCount; ++y)
|
|
{
|
|
for (S32 x = 0; x < xCount; ++x)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
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:
|
|
{
|
|
GFX->getDrawUtil()->drawBitmapStretch(texture, ctrlRect, GFXBitmapFlip_None, mFilterType, false, mAngle);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mProfile->mBorder || !mBitmap)
|
|
{
|
|
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())
|
|
{
|
|
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;
|
|
}
|
|
|
|
DefineEngineMethod(GuiBitmapCtrl, setValue, void, (S32 x, S32 y), ,
|
|
"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.
|
|
"void setBitmap( String filename, bool resize );"); // The definition string.
|
|
|
|
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.
|
|
"void setBitmap( String filename );"); // The definition string.
|
|
|
|
|
|
//"Set the bitmap displayed in the control. Note that it is limited in size, to 256x256."
|
|
DefineEngineMethod(GuiBitmapCtrl, setBitmap, void, (const char* fileRoot, bool resize), (false),
|
|
"( String filename | String filename, bool resize ) Assign an image to the control.\n\n"
|
|
"@hide")
|
|
{
|
|
char filename[1024];
|
|
Con::expandScriptFilename(filename, sizeof(filename), fileRoot);
|
|
object->setBitmap(filename, resize);
|
|
}
|
|
|
|
DefineEngineMethod(GuiBitmapCtrl, getBitmap, const char*, (), ,
|
|
"Gets the current bitmap set for this control.\n\n"
|
|
"@hide")
|
|
{
|
|
return object->_getBitmap();
|
|
}
|
|
|
|
DefineEngineMethod(GuiBitmapCtrl, setNamedTexture, bool, (String namedtexture), ,
|
|
"@brief Set a texture as the image.\n\n"
|
|
"@param namedtexture The name of the texture (NamedTexTarget).\n"
|
|
"@return true if the texture exists.")
|
|
{
|
|
GFXTexHandle theTex;
|
|
NamedTexTarget* namedTarget = NULL;
|
|
namedTarget = NamedTexTarget::find(namedtexture.c_str());
|
|
if (namedTarget)
|
|
{
|
|
theTex = namedTarget->getTexture(0);
|
|
}
|
|
|
|
if (theTex.isValid())
|
|
{
|
|
object->setBitmapHandle(theTex, false);
|
|
return true; //a new texture was set correctly
|
|
}
|
|
return false; //we couldn't change the texture
|
|
}
|