Torque3D/Engine/source/afx/ce/afxBillboard.cpp
marauder2k7 73ad92b757 review notes from Az
Should render fallback for namedTarget if namedTarget fails
Add safety around namedtarget getTexture to stop assert
Missing assets should revert to fallback image and print a warning to console
Remove REFACTOR tag from all macros.
2025-03-30 11:22:42 +01:00

272 lines
8.9 KiB
C++

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
// Copyright (C) 2015 Faust Logic, Inc.
//
// 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 "afx/arcaneFX.h"
#include "gfx/gfxAPI.h"
#include "math/mathIO.h"
#include "afx/afxChoreographer.h"
#include "afx/ce/afxBillboard.h"
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxBillboardData
IMPLEMENT_CO_DATABLOCK_V1(afxBillboardData);
ConsoleDocClass( afxBillboardData,
"@brief A datablock that specifies a Billboard effect.\n\n"
"A Billboard effect is a textured quadrangle which is always aligned to face towards the camera. It is much like a single "
"static particle and is rendered in a similar fashion."
"\n\n"
"@ingroup afxEffects\n"
"@ingroup AFX\n"
"@ingroup Datablocks\n"
);
afxBillboardData::afxBillboardData()
{
color.set(1.0f, 1.0f, 1.0f, 1.0f);
dimensions.set(1.0f, 1.0f);
texCoords[0].set(0.0f, 0.0f);
texCoords[1].set(0.0f, 1.0f);
texCoords[2].set(1.0f, 1.0f);
texCoords[3].set(1.0f, 0.0f);
blendStyle = BlendUndefined;
srcBlendFactor = BLEND_UNDEFINED;
dstBlendFactor = BLEND_UNDEFINED;
}
afxBillboardData::afxBillboardData(const afxBillboardData& other, bool temp_clone)
: GameBaseData(other, temp_clone)
{
color = other.color;
CLONE_ASSET_REFACTOR(Texture);
dimensions = other.dimensions;
texCoords[0] = other.texCoords[0];
texCoords[1] = other.texCoords[1];
texCoords[2] = other.texCoords[2];
texCoords[3] = other.texCoords[3];
blendStyle = other.blendStyle;
srcBlendFactor = other.srcBlendFactor;
dstBlendFactor = other.dstBlendFactor;
}
#define myOffset(field) Offset(field, afxBillboardData)
extern EnumTable srcBlendFactorTable;
extern EnumTable dstBlendFactorTable;
ImplementEnumType( afxBillboard_BlendStyle, "Possible blending types.\n" "@ingroup afxBillboard\n\n" )
{ afxBillboardData::BlendNormal, "NORMAL", "..." },
{ afxBillboardData::BlendAdditive, "ADDITIVE", "..." },
{ afxBillboardData::BlendSubtractive, "SUBTRACTIVE", "..." },
{ afxBillboardData::BlendPremultAlpha, "PREMULTALPHA", "..." },
EndImplementEnumType;
void afxBillboardData::initPersistFields()
{
docsURL;
addField("color", TypeColorF, myOffset(color),
"The color assigned to the quadrangle geometry. The way it combines with the given "
"texture varies according to the setting of the textureFunction field.");
INITPERSISTFIELD_IMAGEASSET(Texture, afxBillboardData, "An image to use as the billboard's texture.");
addField("dimensions", TypePoint2F, myOffset(dimensions),
"A value-pair that specifies the horizontal and vertical dimensions of the billboard "
"in scene units.");
addField("textureCoords", TypePoint2F, myOffset(texCoords), 4,
"An array of four value-pairs that specify the UV texture coordinates for the four "
"corners of the billboard's quadrangle.");
addField("blendStyle", TYPEID<afxBillboardData::BlendStyle>(), myOffset(blendStyle),
"Selects a common blend factor preset. When set to 'user', srcBlendFactor and "
"dstBlendFactor can be used to set additional blend factor combinations.\n"
"Possible values: normal, additive, subtractive, premultalpha, or user.");
addField("srcBlendFactor", TYPEID<GFXBlend>(), myOffset(srcBlendFactor),
"Specifies source blend factor when blendStyle is set to 'user'.\n"
"Possible values: GFXBlendZero, GFXBlendOne, GFXBlendDestColor, GFXBlendInvDestColor, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha, GFXBlendDestAlpha, GFXBlendInvDestAlpha, or GFXBlendSrcAlphaSat");
addField("dstBlendFactor", TYPEID<GFXBlend>(), myOffset(dstBlendFactor),
"Specifies destination blend factor when blendStyle is set to 'user'.\n"
"Possible values: GFXBlendZero, GFXBlendOne, GFXBlendSrcColor, GFXBlendInvSrcColor, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha, GFXBlendDestAlpha, or GFXBlendInvDestAlpha");
Parent::initPersistFields();
}
void afxBillboardData::packData(BitStream* stream)
{
Parent::packData(stream);
stream->write(color);
PACKDATA_ASSET_REFACTOR(Texture);
mathWrite(*stream, dimensions);
mathWrite(*stream, texCoords[0]);
mathWrite(*stream, texCoords[1]);
mathWrite(*stream, texCoords[2]);
mathWrite(*stream, texCoords[3]);
stream->writeInt(srcBlendFactor, 4);
stream->writeInt(dstBlendFactor, 4);
}
void afxBillboardData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
stream->read(&color);
UNPACKDATA_ASSET_REFACTOR(Texture);
mathRead(*stream, &dimensions);
mathRead(*stream, &texCoords[0]);
mathRead(*stream, &texCoords[1]);
mathRead(*stream, &texCoords[2]);
mathRead(*stream, &texCoords[3]);
srcBlendFactor = (GFXBlend) stream->readInt(4);
dstBlendFactor = (GFXBlend) stream->readInt(4);
}
bool afxBillboardData::preload(bool server, String &errorStr)
{
if (!Parent::preload(server, errorStr))
return false;
// if blend-style is set to User, check for defined blend-factors
if (blendStyle == BlendUser && (srcBlendFactor == BLEND_UNDEFINED || dstBlendFactor == BLEND_UNDEFINED))
{
blendStyle = BlendUndefined;
Con::warnf(ConsoleLogEntry::General, "afxBillboardData(%s) incomplete blend factor specification.", getName());
}
// silently switch Undefined blend-style to User if blend factors are both defined
if (blendStyle == BlendUndefined && srcBlendFactor != BLEND_UNDEFINED && dstBlendFactor != BLEND_UNDEFINED)
{
blendStyle = BlendUser;
}
// set pre-defined blend-factors
switch (blendStyle)
{
case BlendNormal:
srcBlendFactor = GFXBlendSrcAlpha;
dstBlendFactor = GFXBlendInvSrcAlpha;
break;
case BlendSubtractive:
srcBlendFactor = GFXBlendZero;
dstBlendFactor = GFXBlendInvSrcColor;
break;
case BlendPremultAlpha:
srcBlendFactor = GFXBlendOne;
dstBlendFactor = GFXBlendInvSrcAlpha;
break;
case BlendUser:
break;
case BlendAdditive:
srcBlendFactor = GFXBlendSrcAlpha;
dstBlendFactor = GFXBlendOne;
break;
case BlendUndefined:
default:
blendStyle = BlendNormal;
srcBlendFactor = GFXBlendSrcAlpha;
dstBlendFactor = GFXBlendInvSrcAlpha;
break;
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxBillboard
IMPLEMENT_CO_NETOBJECT_V1(afxBillboard);
ConsoleDocClass( afxBillboard,
"@brief A Billboard effect as defined by an afxBillboardData datablock.\n\n"
"A Billboard effect is a textured quadrangle which is always aligned to "
"face towards the camera. It is much like a single static particle and is rendered "
"in a similar fashion.\n"
"@ingroup afxEffects\n"
"@ingroup AFX\n"
);
afxBillboard::afxBillboard()
{
mNetFlags.clear();
mNetFlags.set(IsGhost);
mDataBlock = 0;
fade_amt = 1.0f;
is_visible = true;
sort_priority = 0;
live_color.set(1.0f, 1.0f, 1.0f, 1.0f);
}
afxBillboard::~afxBillboard()
{
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
bool afxBillboard::onNewDataBlock(GameBaseData* dptr, bool reload)
{
mDataBlock = dynamic_cast<afxBillboardData*>(dptr);
if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
return false;
live_color = mDataBlock->color;
return true;
}
bool afxBillboard::onAdd()
{
if(!Parent::onAdd())
return false;
F32 width = mDataBlock->dimensions.x * 0.5f;
F32 height = mDataBlock->dimensions.y * 0.5f;
mObjBox = Box3F(Point3F(-width, -0.01f, -height), Point3F(width, 0.01f, height));
addToScene();
return true;
}
void afxBillboard::onRemove()
{
removeFromScene();
Parent::onRemove();
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//