Merge branch 'development' of https://github.com/TorqueGameEngines/Torque3D into TreeWork

This commit is contained in:
AzaezelX 2026-02-10 20:45:42 -06:00
commit a0a22178c3
23 changed files with 447 additions and 135 deletions

View file

@ -180,6 +180,11 @@ bool AIController::getAIMove(Move* movePtr)
if (obj->getContainer()->castRay(start, end, StaticShapeObjectType, &info)) if (obj->getContainer()->castRay(start, end, StaticShapeObjectType, &info))
{ {
getNav()->repath(); getNav()->repath();
mMovement.mInAir = false;
}
else
{
mMovement.mInAir = true;
} }
obj->enableCollision(); obj->enableCollision();
getGoal()->mInRange = false; getGoal()->mInRange = false;
@ -307,6 +312,13 @@ void AIController::Movement::onStuck()
#endif #endif
} }
bool AIController::Movement::isInWater()
{
ShapeBase* sbo = dynamic_cast<ShapeBase*>(getCtrl()->getAIInfo()->mObj.getPointer());
if (!sbo) return false;
return sbo->getWaterCoverage() > 0.0f;
}
DefineEngineMethod(AIController, setMoveSpeed, void, (F32 speed), , DefineEngineMethod(AIController, setMoveSpeed, void, (F32 speed), ,
"@brief Sets the move speed for an AI object.\n\n" "@brief Sets the move speed for an AI object.\n\n"
@ -335,6 +347,23 @@ DefineEngineMethod(AIController, stop, void, (), ,
object->mMovement.stopMove(); object->mMovement.stopMove();
} }
DefineEngineMethod(AIController, isStopped, bool, (), ,
"@brief is the player moving?.\n\n")
{
return object->mMovement.isStopped();
}
DefineEngineMethod(AIController, isInAir, bool, (), ,
"@brief is the player moving?.\n\n")
{
return object->mMovement.isInAir();
}
DefineEngineMethod(AIController, isInWater, bool, (), ,
"@brief is the player in water?.\n\n")
{
return object->mMovement.isInWater();
}
/** /**
* Set the state of a movement trigger. * Set the state of a movement trigger.

View file

@ -85,10 +85,11 @@ public:
AIController* mControllerRef; AIController* mControllerRef;
AIController* getCtrl() { return mControllerRef; }; AIController* getCtrl() { return mControllerRef; };
MoveState mMoveState; MoveState mMoveState;
bool mInAir = false;
F32 mMoveSpeed = 1.0; F32 mMoveSpeed = 1.0;
void setMoveSpeed(F32 speed) { mMoveSpeed = speed; }; void setMoveSpeed(F32 speed) { mMoveSpeed = speed; };
F32 getMoveSpeed() { return mMoveSpeed; }; F32 getMoveSpeed() { return mMoveSpeed; };
bool mMoveSlowdown; // Slowdown as we near the destination bool mMoveSlowdown = false; // Slowdown as we near the destination
Point3F mLastLocation; // For stuck check Point3F mLastLocation; // For stuck check
S32 mMoveStuckTestCountdown; // The current countdown until at AI starts to check if it is stuck S32 mMoveStuckTestCountdown; // The current countdown until at AI starts to check if it is stuck
Point3F mAimLocation; Point3F mAimLocation;
@ -96,6 +97,9 @@ public:
bool mMoveTriggers[MaxTriggerKeys]; bool mMoveTriggers[MaxTriggerKeys];
void stopMove(); void stopMove();
void onStuck(); void onStuck();
bool isStopped() { return mMoveState == ModeStop; };
bool isInAir() { return mInAir; };
bool isInWater();
} mMovement; } mMovement;
struct TriggerState struct TriggerState

View file

@ -1436,15 +1436,13 @@ void ConvexShape::_updateGeometry( bool updateCollision )
const Vector< U32 > &facePntMap = face.points; const Vector< U32 > &facePntMap = face.points;
const Vector< ConvexShape::Triangle > &triangles = face.triangles; const Vector< ConvexShape::Triangle > &triangles = face.triangles;
const Point3F binormal = mCross(face.normal, face.tangent);
for (S32 j = 0; j < triangles.size(); j++) for (S32 j = 0; j < triangles.size(); j++)
{ {
for (S32 k = 0; k < 3; k++) for (S32 k = 0; k < 3; k++)
{ {
pVert->normal = face.normal; pVert->normal = face.normal;
pVert->T = face.tangent; pVert->T = face.tangent;
pVert->B = mCross(face.normal,face.tangent); pVert->B = mCross(face.normal, face.tangent);
pVert->point = pointList[facePntMap[triangles[j][k]]]; pVert->point = pointList[facePntMap[triangles[j][k]]];
pVert->texCoord = face.texcoords[triangles[j][k]]; pVert->texCoord = face.texcoords[triangles[j][k]];
pVert->texCoord2 = pVert->texCoord; pVert->texCoord2 = pVert->texCoord;
@ -1966,10 +1964,12 @@ void ConvexShape::Geometry::generate(const Vector< PlaneF > &planes, const Vecto
U32 *vertMap = new U32[pntCount]; U32 *vertMap = new U32[pntCount];
Point3F binormal = mCross(newFace.normal, newFace.tangent);
MatrixF quadMat( true ); MatrixF quadMat( true );
quadMat.setPosition( averagePnt ); quadMat.setPosition( averagePnt );
quadMat.setColumn( 0, newFace.tangent ); quadMat.setColumn( 0, newFace.tangent );
quadMat.setColumn( 1, mCross( newFace.normal, newFace.tangent ) ); quadMat.setColumn( 1, binormal);
quadMat.setColumn( 2, newFace.normal ); quadMat.setColumn( 2, newFace.normal );
quadMat.inverse(); quadMat.inverse();
@ -2055,8 +2055,8 @@ void ConvexShape::Geometry::generate(const Vector< PlaneF > &planes, const Vecto
// Calculate texture coordinates for each point in this face. // Calculate texture coordinates for each point in this face.
if (newFace.normal.z < -0.9f) binormal = -binormal;
const Point3F binormal = mCross( newFace.normal, newFace.tangent );
PlaneF planey( newFace.centroid - 0.5f * binormal, binormal ); PlaneF planey( newFace.centroid - 0.5f * binormal, binormal );
PlaneF planex( newFace.centroid - 0.5f * newFace.tangent, newFace.tangent ); PlaneF planex( newFace.centroid - 0.5f * newFace.tangent, newFace.tangent );
@ -2064,7 +2064,7 @@ void ConvexShape::Geometry::generate(const Vector< PlaneF > &planes, const Vecto
for ( S32 j = 0; j < newFace.points.size(); j++ ) for ( S32 j = 0; j < newFace.points.size(); j++ )
{ {
F32 x = planex.distToPlane( points[ newFace.points[ j ] ] ); F32 x = -planex.distToPlane( points[ newFace.points[ j ] ] );
F32 y = planey.distToPlane( points[ newFace.points[ j ] ] ); F32 y = planey.distToPlane( points[ newFace.points[ j ] ] );
if (!texOffset.empty()) if (!texOffset.empty())
@ -2086,7 +2086,7 @@ void ConvexShape::Geometry::generate(const Vector< PlaneF > &planes, const Vecto
if (vertFlip.size() > 0 && vertFlip[i]) if (vertFlip.size() > 0 && vertFlip[i])
y *= -1; y *= -1;
newFace.texcoords[j].set(-x, -y); newFace.texcoords[j].set(x, y);
} }
// Data verification tests. // Data verification tests.

View file

@ -535,7 +535,7 @@ bool ParticleData::onAdd()
{ {
Con::warnf(ConsoleLogEntry::General, Con::warnf(ConsoleLogEntry::General,
"ParticleData(%s) bad value(s) for animTexTiling [%d or %d <= 0], invalid datablock", "ParticleData(%s) bad value(s) for animTexTiling [%d or %d <= 0], invalid datablock",
animTexTiling.x, animTexTiling.y, getName()); getName(), animTexTiling.x, animTexTiling.y);
return false; return false;
} }

View file

@ -312,6 +312,7 @@ IMPLEMENT_CALLBACK( Item, onLeaveLiquid, void, ( const char* objID, const char*
Item::Item() Item::Item()
{ {
mTypeMask |= ItemObjectType | DynamicShapeObjectType; mTypeMask |= ItemObjectType | DynamicShapeObjectType;
mPathfindingIgnore = true;
mDataBlock = 0; mDataBlock = 0;
mStatic = false; mStatic = false;
mRotate = false; mRotate = false;

View file

@ -1552,7 +1552,7 @@ ConsoleDocClass( Player,
Player::Player() Player::Player()
{ {
mTypeMask |= PlayerObjectType | DynamicShapeObjectType; mTypeMask |= PlayerObjectType | DynamicShapeObjectType;
mPathfindingIgnore = true;
mDelta.pos = mAnchorPoint = Point3F(0,0,100); mDelta.pos = mAnchorPoint = Point3F(0,0,100);
mDelta.rot = mDelta.head = Point3F(0,0,0); mDelta.rot = mDelta.head = Point3F(0,0,0);
mDelta.rotOffset.set(0.0f,0.0f,0.0f); mDelta.rotOffset.set(0.0f,0.0f,0.0f);

View file

@ -376,7 +376,7 @@ Vehicle::Vehicle()
{ {
mDataBlock = 0; mDataBlock = 0;
mTypeMask |= VehicleObjectType | DynamicShapeObjectType; mTypeMask |= VehicleObjectType | DynamicShapeObjectType;
mPathfindingIgnore = true;
mDelta.pos = Point3F(0,0,0); mDelta.pos = Point3F(0,0,0);
mDelta.posVec = Point3F(0,0,0); mDelta.posVec = Point3F(0,0,0);
mDelta.warpTicks = mDelta.warpCount = 0; mDelta.warpTicks = mDelta.warpCount = 0;

View file

@ -1529,6 +1529,7 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
CodeBlock::smInFunction = false; CodeBlock::smInFunction = false;
setCurrentStringTable(&getGlobalStringTable());
// check for argument setup // check for argument setup
for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext()) for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext())
{ {
@ -1541,6 +1542,7 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
ip = walk->defaultValue->compile(codeStream, ip, walkType); ip = walk->defaultValue->compile(codeStream, ip, walkType);
} }
} }
setCurrentStringTable(&getFunctionStringTable());
codeStream.emit(OP_FUNC_DECL); codeStream.emit(OP_FUNC_DECL);
codeStream.emitSTE(fnName); codeStream.emitSTE(fnName);

View file

@ -288,6 +288,13 @@ enum ChannelSemantic : U8
CH_B CH_B
}; };
struct PackedChannelDesc
{
ChannelSemantic semantic;
U8 bits;
U8 shift;
};
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// Bitmap format descriptor // Bitmap format descriptor
struct GBitmapFormatDesc struct GBitmapFormatDesc
@ -299,7 +306,9 @@ struct GBitmapFormatDesc
bool premultiplied; bool premultiplied;
bool isFloat; bool isFloat;
U8 bytesPerChannel; U8 bytesPerChannel;
bool isPacked = false;
U8 bytesPerPixel = 0;
PackedChannelDesc packed[4] = {};
bool is8() const { return !isFloat && bytesPerChannel == 1; } bool is8() const { return !isFloat && bytesPerChannel == 1; }
bool is16() const { return !isFloat && bytesPerChannel == 2; } bool is16() const { return !isFloat && bytesPerChannel == 2; }
}; };
@ -316,17 +325,47 @@ GBitmapFormatDesc getFormatDesc(GFXFormat fmt)
case GFXFormatL8: case GFXFormatL8:
return { 1, {CH_L, CH_NONE, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 }; return { 1, {CH_L, CH_NONE, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 };
case GFXFormatA4L4: case GFXFormatA4L4:
return { 2, {CH_L, CH_A, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 }; return { 2, {CH_L, CH_A, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 0, true, 1,
{
{ CH_L, 4, 0 }, // CH_L must be declared before CH_A
{ CH_A, 4, 4 }
}
};
// 16-bit formats // 16-bit formats
case GFXFormatR5G6B5: case GFXFormatR5G6B5:
return { 3, {CH_R, CH_G, CH_B, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 }; return { 3, {CH_R, CH_G, CH_B, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 0, true, 2,
{
{ CH_R, 5, 11 },
{ CH_G, 6, 5 },
{ CH_B, 5, 0 }
}
};
case GFXFormatR5G5B5A1: case GFXFormatR5G5B5A1:
return { 4, {CH_R, CH_G, CH_B, CH_A}, STBIR_TYPE_UINT8, false, false, false, 1 }; return { 4, {CH_R, CH_G, CH_B, CH_A}, STBIR_TYPE_UINT8, false, false, false, 0, true, 2,
{
{ CH_R, 5, 11 },
{ CH_G, 5, 6 },
{ CH_B, 5, 1 },
{ CH_A, 1, 0 }
}
};
case GFXFormatR5G5B5X1: case GFXFormatR5G5B5X1:
return { 4, {CH_R, CH_G, CH_B, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 }; return { 4, {CH_R, CH_G, CH_B, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 0, true, 2,
{
{ CH_R, 5, 11 },
{ CH_G, 5, 6 },
{ CH_B, 5, 1 },
{ CH_A, 1, 0 }
}
};
case GFXFormatA8L8: case GFXFormatA8L8:
return { 2, {CH_L, CH_A, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 }; return { 2, {CH_L, CH_A, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 0, true, 2,
{
{ CH_L, 8, 0 }, // CH_L must be declared before CH_A
{ CH_A, 8, 8 }
}
};
case GFXFormatL16: case GFXFormatL16:
return { 1, {CH_L, CH_NONE, CH_NONE, CH_NONE}, STBIR_TYPE_UINT16, false, false, false, 2 }; return { 1, {CH_L, CH_NONE, CH_NONE, CH_NONE}, STBIR_TYPE_UINT16, false, false, false, 2 };
case GFXFormatR16F: case GFXFormatR16F:
@ -403,10 +442,73 @@ inline float linearToSrgb(float c)
return (c <= 0.0031308f) ? c * 12.92f : 1.055f * powf(c, 1.f / 2.4f) - 0.055f; return (c <= 0.0031308f) ? c * 12.92f : 1.055f * powf(c, 1.f / 2.4f) - 0.055f;
} }
static inline LinearPixel loadPackedPixel(
const void* src,
const GBitmapFormatDesc& fmt,
U32 index)
{
LinearPixel p;
p.r = p.g = p.b = 0.f;
p.a = 1.f;
const U8* base = (const U8*)src + index * fmt.bytesPerPixel;
U32 raw = 0;
dMemcpy(&raw, base, fmt.bytesPerPixel);
#ifdef TORQUE_BIG_ENDIAN
if (fmt.bytesPerPixel == 2)
raw = convertLEndianToHost((U16)raw);
else if (fmt.bytesPerPixel == 4)
raw = convertLEndianToHost((U32)raw);
#endif
for (U32 i = 0; i < fmt.channels; ++i)
{
const PackedChannelDesc& ch = fmt.packed[i];
U32 mask = (1u << ch.bits) - 1u;
U32 v = (raw >> ch.shift) & mask;
// Expand to 8-bit exactly like GBitmap getColor code
U8 expanded8;
if (ch.bits == 5)
expanded8 = (v << 3) | (v >> 2);
else if (ch.bits == 6)
expanded8 = (v << 2) | (v >> 4);
else if (ch.bits == 4)
expanded8 = v * 17;
else if (ch.bits == 1)
expanded8 = v ? 255 : 0;
else // 8-bit
expanded8 = (U8)v;
float f = expanded8 / 255.f;
switch (ch.semantic)
{
case CH_R: p.r = f; break;
case CH_G: p.g = f; break;
case CH_B: p.b = f; break;
case CH_A: p.a = f; break;
case CH_L:
p.r = p.g = p.b = f;
break;
default:
break;
}
}
return p;
}
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// Load a pixel from src format into LinearPixel // Load a pixel from src format into LinearPixel
static inline LinearPixel loadPixel(const void* src, const GBitmapFormatDesc& fmt, U32 index) static inline LinearPixel loadPixel(const void* src, const GBitmapFormatDesc& fmt, U32 index)
{ {
if (fmt.isPacked)
return loadPackedPixel(src, fmt, index);
LinearPixel p; LinearPixel p;
const U8* base = (const U8*)src + index * fmt.channels * fmt.bytesPerChannel; const U8* base = (const U8*)src + index * fmt.channels * fmt.bytesPerChannel;
@ -441,10 +543,72 @@ static inline LinearPixel loadPixel(const void* src, const GBitmapFormatDesc& fm
return p; return p;
} }
static inline void storePackedPixel(
void* dst,
const GBitmapFormatDesc& fmt,
U32 index,
const LinearPixel& p)
{
U32 raw = 0;
for (U32 i = 0; i < fmt.channels; ++i)
{
const PackedChannelDesc& ch = fmt.packed[i];
float v = 0.f;
switch (ch.semantic)
{
case CH_R: v = p.r; break;
case CH_G: v = p.g; break;
case CH_B: v = p.b; break;
case CH_A: v = p.a; break;
case CH_L: v = p.r; break; // legacy behavior
default: continue;
}
// Clamp
v = mClamp(v, 0.f, 1.f);
// Canonical float → U8
U32 expanded8 = U32(v * 255.f + 0.5f);
// Contract to bit depth EXACTLY like Gbitmap setColor code
U32 maxv = (1u << ch.bits) - 1u;
U32 iv;
if (ch.bits == 8)
iv = expanded8;
else
iv = expanded8 * maxv / 255;
raw |= (iv & maxv) << ch.shift;
}
#ifdef TORQUE_BIG_ENDIAN
if (fmt.bytesPerPixel == 2)
{
U16 v = convertLEndianToHost((U16)raw);
dMemcpy((U8*)dst + index * fmt.bytesPerPixel, &v, 2);
}
else if (fmt.bytesPerPixel == 4)
{
U32 v = convertLEndianToHost(raw);
dMemcpy((U8*)dst + index * fmt.bytesPerPixel, &v, 4);
}
#else
dMemcpy((U8*)dst + index * fmt.bytesPerPixel, &raw, fmt.bytesPerPixel);
#endif
}
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// Store a LinearPixel into dst format // Store a LinearPixel into dst format
static inline void storePixel(void* dst, const GBitmapFormatDesc& fmt, U32 index, const LinearPixel& p) static inline void storePixel(void* dst, const GBitmapFormatDesc& fmt, U32 index, const LinearPixel& p)
{ {
if (fmt.isPacked)
{
storePackedPixel(dst, fmt, index, p);
return;
}
U8* base = (U8*)dst + index * fmt.channels * fmt.bytesPerChannel; U8* base = (U8*)dst + index * fmt.channels * fmt.bytesPerChannel;
for (U32 c = 0; c < fmt.channels; ++c) for (U32 c = 0; c < fmt.channels; ++c)
{ {
@ -455,7 +619,7 @@ static inline void storePixel(void* dst, const GBitmapFormatDesc& fmt, U32 index
case CH_G: v = p.g; break; case CH_G: v = p.g; break;
case CH_B: v = p.b; break; case CH_B: v = p.b; break;
case CH_A: v = p.a; break; case CH_A: v = p.a; break;
case CH_L: v = (p.r + p.g + p.b) / 3.f; break; case CH_L: v = p.r; break;
default: break; default: break;
} }

View file

@ -61,45 +61,39 @@ inline F32 convertHalfToFloat(U16 h)
U32 exp = (h >> 10) & 0x0000001F; U32 exp = (h >> 10) & 0x0000001F;
U32 mant = h & 0x000003FF; U32 mant = h & 0x000003FF;
U32 outSign = sign << 31; U32 out;
U32 outExp, outMant;
if (exp == 0) if (exp == 0)
{ {
if (mant == 0) if (mant == 0)
{ {
// Zero // Zero
outExp = 0; out = sign;
outMant = 0;
} }
else else
{ {
// Subnormal number -> normalize // Subnormal number -> normalize
exp = 1; exp = 127 - 14;
while ((mant & 0x00000400) == 0) while ((mant & 0x0400) == 0)
{ {
mant <<= 1; mant <<= 1;
exp -= 1; exp--;
} }
mant &= 0x000003FF; mant &= 0x03FF;
outExp = (exp + (127 - 15)) << 23; out = sign | (exp << 23) | (mant << 13);
outMant = mant << 13;
} }
} }
else if (exp == 31) else if (exp == 31)
{ {
// Inf or NaN // Inf or NaN
outExp = 0xFF << 23; out = sign | 0x7F800000 | (mant << 13);
outMant = mant ? (mant << 13) : 0;
} }
else else
{ {
// Normalized // Normalized
outExp = (exp + (127 - 15)) << 23; out = sign | ((exp + (127 - 15)) << 23) | (mant << 13);
outMant = mant << 13;
} }
U32 out = outSign | outExp | outMant;
F32 result; F32 result;
dMemcpy(&result, &out, sizeof(F32)); dMemcpy(&result, &out, sizeof(F32));
return result; return result;
@ -110,40 +104,54 @@ inline U16 convertFloatToHalf(F32 f)
U32 bits; U32 bits;
dMemcpy(&bits, &f, sizeof(U32)); dMemcpy(&bits, &f, sizeof(U32));
U32 sign = (bits >> 16) & 0x00008000; U32 sign = (bits >> 16) & 0x8000;
U32 exp = ((bits >> 23) & 0x000000FF) - (127 - 15); U32 exp = (bits >> 23) & 0xFF;
U32 mant = bits & 0x007FFFFF; U32 mant = bits & 0x007FFFFF;
if (exp <= 0) if (exp == 255)
{
if (exp < -10)
return (U16)sign; // Too small => 0
mant = (mant | 0x00800000) >> (1 - exp);
return (U16)(sign | (mant >> 13));
}
else if (exp == 0xFF - (127 - 15))
{ {
// Inf or NaN
if (mant == 0) if (mant == 0)
{
// Inf
return (U16)(sign | 0x7C00); return (U16)(sign | 0x7C00);
} mant >>= 13;
else return (U16)(sign | 0x7C00 | mant | (mant == 0));
{
// NaN
mant >>= 13;
return (U16)(sign | 0x7C00 | mant | (mant == 0));
}
} }
else
S32 newExp = (S32)exp - 127 + 15;
if (newExp >= 31)
{ {
if (exp > 30) // Overflow → Inf
{ return (U16)(sign | 0x7C00);
// Overflow => Inf
return (U16)(sign | 0x7C00);
}
return (U16)(sign | (exp << 10) | (mant >> 13));
} }
else if (newExp <= 0)
{
// Subnormal or underflow
if (newExp < -10)
return (U16)sign;
mant |= 0x800000;
U32 shifted = mant >> (1 - newExp);
// Round to nearest-even
if (shifted & 0x00001000)
shifted += 0x00002000;
return (U16)(sign | (shifted >> 13));
}
// Normalized with rounding
mant += 0x00001000;
if (mant & 0x00800000)
{
mant = 0;
newExp++;
}
if (newExp >= 31)
return (U16)(sign | 0x7C00);
return (U16)(sign | (newExp << 10) | (mant >> 13));
} }
// Convert a single 16-bit value (0..65535) to 8-bit (0..255) // Convert a single 16-bit value (0..65535) to 8-bit (0..255)

View file

@ -202,11 +202,10 @@ bool GuiIconButtonCtrl::resize(const Point2I &newPosition, const Point2I &newExt
void GuiIconButtonCtrl::setBitmap(const char *name) void GuiIconButtonCtrl::setBitmap(const char *name)
{ {
_setBitmap(name);
if(!isAwake()) if(!isAwake())
return; return;
_setBitmap(name);
// So that extent is recalculated if autoSize is set. // So that extent is recalculated if autoSize is set.
resize( getPosition(), getExtent() ); resize( getPosition(), getExtent() );

View file

@ -3389,7 +3389,7 @@ void GuiTreeViewCtrl::onMouseDown(const GuiEvent & event)
mPossibleRenameItem = NULL; mPossibleRenameItem = NULL;
mRenamingItem = NULL; mRenamingItem = NULL;
mTempItem = NULL; mTempItem = NULL;
bool wasSelected = isSelected(item);
// //
if( event.modifier & SI_MULTISELECT ) if( event.modifier & SI_MULTISELECT )
{ {
@ -3474,7 +3474,6 @@ void GuiTreeViewCtrl::onMouseDown(const GuiEvent & event)
{ {
mTempItem = item; mTempItem = item;
bool wasSelected = isSelected( item );
bool multiSelect = getSelectedItemsCount() > 1; bool multiSelect = getSelectedItemsCount() > 1;
if( !wasSelected || !multiSelect ) if( !wasSelected || !multiSelect )
@ -3520,7 +3519,7 @@ void GuiTreeViewCtrl::onMouseDown(const GuiEvent & event)
return; return;
// //
if ( mFullRowSelect || hitFlags.test( OnImage ) ) if (hitFlags.test(OnImage) || ((mFullRowSelect || hitFlags.test(OnIcon)) && wasSelected))
{ {
item->setExpanded(!item->isExpanded()); item->setExpanded(!item->isExpanded());
if( !item->isInspectorData() && item->mState.test(Item::VirtualParent) ) if( !item->isInspectorData() && item->mState.test(Item::VirtualParent) )

View file

@ -454,8 +454,8 @@ S32 NavMesh::getLink(const Point3F &pos)
{ {
if(mDeleteLinks[i]) if(mDeleteLinks[i])
continue; continue;
SphereF start(getLinkStart(i), mLinkRads[i]); SphereF start(getLinkStart(i), mMax(mLinkRads[i],0.25f));
SphereF end(getLinkEnd(i), mLinkRads[i]); SphereF end(getLinkEnd(i), mMax(mLinkRads[i], 0.25f));
if(start.isContained(pos) || end.isContained(pos)) if(start.isContained(pos) || end.isContained(pos))
return i; return i;
} }
@ -653,7 +653,7 @@ DefineEngineMethod(NavMesh, deleteLinks, void, (),,
static void buildCallback(SceneObject* object, void* key) static void buildCallback(SceneObject* object, void* key)
{ {
SceneContainer::CallbackInfo* info = reinterpret_cast<SceneContainer::CallbackInfo*>(key); SceneContainer::CallbackInfo* info = reinterpret_cast<SceneContainer::CallbackInfo*>(key);
if (!object->mPathfindingIgnore) if (!object->mPathfindingIgnore && (object->getTypeMask() & MarkerObjectType) == 0)
object->buildPolyList(info->context, info->polyList, info->boundingBox, info->boundingSphere); object->buildPolyList(info->context, info->polyList, info->boundingBox, info->boundingSphere);
} }

View file

@ -75,6 +75,10 @@ MODULE_BEGIN( TSShapeInstance )
"@brief Enables mesh instancing on non-skin meshes that have less that this count of verts.\n" "@brief Enables mesh instancing on non-skin meshes that have less that this count of verts.\n"
"The default value is 2000. Higher values can degrade performance.\n" "The default value is 2000. Higher values can degrade performance.\n"
"@ingroup Rendering\n" ); "@ingroup Rendering\n" );
Con::addVariable("$MaxSkinBones", TypeS32, &TSShape::smMaxSkinBones,
"@brief Max number of bones allowed by a given shape for hardwar skinning. Default 70\n"
"@ingroup Rendering\n");
} }
MODULE_END; MODULE_END;

View file

@ -199,8 +199,13 @@ function GameConnectionListener::onSetSpawnPointComplete( %this, %client )
%client.player = spawnObject(%client.spawnClass, %client.spawnDataBlock, "", %client.spawnProperties, %client.spawnScript); %client.player = spawnObject(%client.spawnClass, %client.spawnDataBlock, "", %client.spawnProperties, %client.spawnScript);
if(!isObject(%client.player)) if(!isObject(%client.player))
{
error("Failed to spawn player object!"); error("Failed to spawn player object!");
}
else if (%client.player.isMemberOfClass("Camera"))
{
%client.camera = %client.player;
}
if (!%client.player.isMemberOfClass(%client.spawnClass)) if (!%client.player.isMemberOfClass(%client.spawnClass))
warn("Trying to spawn a class that does not derive from "@ %client.spawnClass); warn("Trying to spawn a class that does not derive from "@ %client.spawnClass);

View file

@ -82,10 +82,17 @@ function GameBaseData::onNewDataBlock(%this, %obj, %reload)
{ {
if (%reload) if (%reload)
{ {
%client = "";
if (isObject(%obj.client))
%client = %obj.client;
if(%this.isMethod("onRemove")) if(%this.isMethod("onRemove"))
%this.onRemove(%obj); %this.onRemove(%obj);
if(%this.isMethod("onAdd")) if(%this.isMethod("onAdd"))
%this.onAdd(%obj); %this.onAdd(%obj);
if (%client)
%client.setControlObject(%obj);
} }
} }

View file

@ -5,7 +5,6 @@
scriptFile="DamageModel.tscript" scriptFile="DamageModel.tscript"
CreateFunction="onCreate" CreateFunction="onCreate"
DestroyFunction="onDestroy" DestroyFunction="onDestroy"
Group="Game"
Dependencies="UI=1"> Dependencies="UI=1">
<DeclaredAssets <DeclaredAssets
Extension="asset.taml" Extension="asset.taml"

View file

@ -23,6 +23,7 @@ function DamageModel::onCreateGameServer(%this)
%this.queueExec("./scripts/server/shapeBase"); %this.queueExec("./scripts/server/shapeBase");
%this.queueExec("./scripts/server/vehicle"); %this.queueExec("./scripts/server/vehicle");
%this.queueExec("./scripts/server/player"); %this.queueExec("./scripts/server/player");
%this.queueExec("./scripts/server/commands");
} }
//This is called when the server is shut down due to the game/map being exited //This is called when the server is shut down due to the game/map being exited
@ -35,6 +36,7 @@ function DamageModel::initClient(%this)
{ {
%this.queueExec("./guis/damageGuiOverlay.gui"); %this.queueExec("./guis/damageGuiOverlay.gui");
%this.queueExec("./scripts/client/playGui"); %this.queueExec("./scripts/client/playGui");
%this.queueExec("./scripts/client/client");
} }
//This is called when a client connects to a server //This is called when a client connects to a server

View file

@ -0,0 +1,67 @@
// ----------------------------------------------------------------------------
// WeaponHUD
// ----------------------------------------------------------------------------
// Update the Ammo Counter with current ammo, if not any then hide the counter.
function clientCmdSetAmmoAmountHud(%amount, %amountInClips)
{
if (!%amount)
AmmoAmount.setVisible(false);
else
{
AmmoAmount.setVisible(true);
AmmoAmount.setText("Ammo: " @ %amount @ "/" @ %amountInClips);
}
}
// Here we update the Weapon Preview image & reticle for each weapon. We also
// update the Ammo Counter (just so we don't have to call it separately).
// Passing an empty parameter ("") hides the HUD component.
function clientCmdRefreshWeaponHUD(%amount, %preview, %ret, %zoomRet, %amountInClips)
{
if (!%amount)
AmmoAmount.setVisible(false);
else
{
AmmoAmount.setVisible(true);
AmmoAmount.setText("Ammo: " @ %amount @ "/" @ %amountInClips);
}
if (%preview $= "" || detag(%preview) $= "blank")
{
WeaponHUD.setVisible(false);
PreviewImage.setBitmap("");
}
else
{
WeaponHUD.setVisible(true);
PreviewImage.setbitmap(detag(%preview));
}
if (%ret $= "" || detag(%ret) $= "blank")
{
Reticle.setVisible(false);
Reticle.setBitmap("");
}
else
{
Reticle.setVisible(true);
Reticle.setbitmap(detag(%ret));
}
if (isObject(ZoomReticle) || detag(%zoomRet) $= "blank")
{
if (%zoomRet $= "" || detag(%zoomRet) $= "blank")
{
ZoomReticle.setVisible(false);
ZoomReticle.setBitmap("");
}
else
{
ZoomReticle.setVisible(true);
ZoomReticle.setBitmap(detag(%zoomRet));
}
}
}

View file

@ -0,0 +1,12 @@
// ----------------------------------------------------------------------------
// weapon HUD
// ----------------------------------------------------------------------------
function GameConnection::setAmmoAmountHud(%client, %amount, %amountInClips )
{
commandToClient(%client, 'SetAmmoAmountHud', %amount, %amountInClips);
}
function GameConnection::RefreshWeaponHud(%client, %amount, %preview, %ret, %zoomRet, %amountInClips)
{
commandToClient(%client, 'RefreshWeaponHud', %amount, %preview, %ret, %zoomRet, %amountInClips);
}

View file

@ -687,21 +687,6 @@ function AssetBrowser::buildAssetPreview( %this, %asset, %moduleName )
%textBottomPad = 20; %textBottomPad = 20;
%previewButton = new GuiIconButtonCtrl()
{
class = "AssetBrowserPreviewButton";
useMouseEvents = true;
iconLocation = "Center";
sizeIconToButton = true;
makeIconSquare = true;
textLocation = "Bottom";
extent = %previewSize.x SPC %previewSize.y + %textBottomPad;
buttonType = "RadioButton";
buttonMargin = "0 -10";
profile = ToolsGuiDefaultIconBtnProfile;
assetBrowser = %this;
};
%previewScaleSize = %this-->previewSlider.getValue(); %previewScaleSize = %this-->previewSlider.getValue();
if(%previewScaleSize $= "") if(%previewScaleSize $= "")
@ -710,29 +695,6 @@ function AssetBrowser::buildAssetPreview( %this, %asset, %moduleName )
%this-->previewSlider.setValue(1); %this-->previewSlider.setValue(1);
} }
if(%previewScaleSize == 0 || startsWith(%this.dirHandler.currentAddress, "Creator"))
{
%previewButton.iconLocation = "Left";
%previewButton.textLocation = "Right";
%previewButton.setextent(160,34);
%previewButton.buttonMargin = "8 8";
%previewButton.textMargin = "6";
%this.previewListMode = true;
}
else
{
%size = %previewSize.x * %previewScaleSize;
%previewButton.setextent(%size,%size + %textBottomPad);
%this.previewListMode = false;
}
//%previewButton.extent = %previewSize.x + %previewBounds SPC %previewSize.y + %previewBounds + 24;
%previewButton.assetName = %assetName;
%previewButton.moduleName = %moduleName;
%previewButton.assetType = %assetType;
if(%this.selectMode) if(%this.selectMode)
{ {
%doubleClickCommand = %this @ ".selectAsset( "@ %this @ ".selectedAsset );"; %doubleClickCommand = %this @ ".selectAsset( "@ %this @ ".selectedAsset );";
@ -755,20 +717,47 @@ function AssetBrowser::buildAssetPreview( %this, %asset, %moduleName )
if(%this.previewData.doubleClickCommand !$= "") if(%this.previewData.doubleClickCommand !$= "")
%doubleClickCommand = %this.previewData.doubleClickCommand; %doubleClickCommand = %this.previewData.doubleClickCommand;
%previewButton.assetName = %assetName; %previewButton = new GuiIconButtonCtrl()
%previewButton.moduleName = %moduleName; {
%previewButton.assetType = %assetType; class = "AssetBrowserPreviewButton";
%previewButton.assetBrowser = %this; useMouseEvents = true;
iconLocation = "Center";
sizeIconToButton = true;
makeIconSquare = true;
textLocation = "Bottom";
extent = %previewSize.x SPC %previewSize.y + %textBottomPad;
buttonType = "RadioButton";
buttonMargin = "0 -10";
profile = ToolsGuiDefaultIconBtnProfile;
tooltip = %this.previewData.tooltip;
assetBrowser = %this;
assetName = %assetName;
moduleName = %moduleName;
assetType = %assetType;
bitmapAsset = %this.previewData.previewImage;
Command = %this @ ".updateSelection( $ThisControl.assetName, $ThisControl.moduleName );";
altCommand = %doubleClickCommand;
text = %this.previewData.assetName;
originalAssetName = %this.previewData.assetName;
};
%previewButton.setBitmap(%this.previewData.previewImage); if(%previewScaleSize == 0 || startsWith(%this.dirHandler.currentAddress, "Creator"))
{
%previewButton.iconLocation = "Left";
%previewButton.textLocation = "Right";
%previewButton.setextent(160,34);
%previewButton.buttonMargin = "8 8";
%previewButton.textMargin = "6";
%previewButton.profile = "AssetBrowserPreview" @ %previewButton.assetType; %this.previewListMode = true;
%previewButton.tooltip = %this.previewData.tooltip; }
%previewButton.Command = %this @ ".updateSelection( $ThisControl.assetName, $ThisControl.moduleName );"; else
%previewButton.altCommand = %doubleClickCommand; {
%size = %previewSize.x * %previewScaleSize;
%previewButton.setextent(%size,%size + %textBottomPad);
%previewButton.text = %this.previewData.assetName; %this.previewListMode = false;
%previewButton.text.originalAssetName = %this.previewData.assetName; }
// add to the gui control array // add to the gui control array
%this-->assetList.add(%previewButton); %this-->assetList.add(%previewButton);

View file

@ -350,6 +350,13 @@ function DecalEditorGui::completeGizmoTransform( %this, %decalId, %nodeDetails )
function DecalEditorGui::onSleep( %this ) function DecalEditorGui::onSleep( %this )
{ {
DecalEditorTreeView.clearSelection();
DecalDataList.setSelected( DecalDataList.getSelectedItems(), false );
DecalEditorGui.currentDecalData = "";
DecalPreviewWindow-->decalPreview.setBitmap("");
DecalEditorGui.selDecalInstanceId = "";
DecalPreviewWindow-->instancePreview.setBitmap("");
} }
function DecalEditorGui::syncNodeDetails( %this ) function DecalEditorGui::syncNodeDetails( %this )
@ -629,14 +636,30 @@ function DecalEditorGui::updateInstancePreview( %this, %material )
if( isObject( %material ) ) if( isObject( %material ) )
{ {
%previewImage = %material.getDiffuseMap(0); %previewImage = %material.getDiffuseMapAsset(0);
} }
else else if(AssetDatabase.isDeclaredAsset(%material))
{ {
if(AssetDatabase.isDeclaredAsset(%material)) if(AssetDatabase.getAssetType(%material) $= "MaterialAsset")
{
%matAsset = AssetDatabase.acquireAsset(%material);
%previewImage = %matAsset.materialDefinitionName.getDiffuseMap(0);
}
else if(AssetDatabase.getAssetType(%material) $= "ImageAsset")
{ {
%previewImage = %material; %previewImage = %material;
} }
else
{
error("DecalEditorGui::updateDecalPreview() - Tried to set an invalid asset type for the editor preview!");
return;
}
}
else
{
error("DecalEditorGui::updateDecalPreview() - Tried to set a non material, non asset value for the editor preview!");
return;
} }
DecalPreviewWindow-->instancePreview.setBitmap( getAssetPreviewImage(%previewImage) ); DecalPreviewWindow-->instancePreview.setBitmap( getAssetPreviewImage(%previewImage) );

View file

@ -641,16 +641,14 @@ function MaterialEditorGui::setActiveMaterial( %this, %material )
MaterialEditorGui.currentMaterial = %material; MaterialEditorGui.currentMaterial = %material;
MaterialEditorGui.lastMaterial = %material; MaterialEditorGui.lastMaterial = %material;
// we create or recreate a material to hold in a pristine state if(!isObject(notDirtyMaterial))
// or, this crashes the ap. fix properly - BJR
//if(isObject(notDirtyMaterial))
// notDirtyMaterial.delete();
singleton Material(notDirtyMaterial)
{ {
mapTo = "matEd_mappedMat"; singleton Material(notDirtyMaterial)
diffuseMapAsset[0] = "ToolsModule:matEd_mappedMat_image"; {
}; mapTo = "matEd_mappedMat";
diffuseMapAsset[0] = "ToolsModule:matEd_mappedMat_image";
};
}
// Converts the texture files into absolute paths. // Converts the texture files into absolute paths.
MaterialEditorGui.convertTextureFields(); MaterialEditorGui.convertTextureFields();