mirror of
https://github.com/tribes2/engine.git
synced 2026-01-20 19:54:46 +00:00
470 lines
14 KiB
C++
470 lines
14 KiB
C++
//-----------------------------------------------------------------------------
|
|
// V12 Engine
|
|
//
|
|
// Copyright (c) 2001 GarageGames.Com
|
|
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "game/projLinearFlare.h"
|
|
#include "core/bitStream.h"
|
|
#include "console/consoleTypes.h"
|
|
|
|
#include "dgl/dgl.h"
|
|
#include "platformWIN32/platformGL.h"
|
|
#include "scenegraph/sceneState.h"
|
|
|
|
IMPLEMENT_CO_DATABLOCK_V1(LinearFlareProjectileData);
|
|
IMPLEMENT_CO_NETOBJECT_V1(LinearFlareProjectile);
|
|
|
|
//--------------------------------------------------------------------------
|
|
//--------------------------------------
|
|
//
|
|
LinearFlareProjectileData::LinearFlareProjectileData()
|
|
{
|
|
numFlares = 25;
|
|
size[0] = .2;
|
|
size[1] = .25;
|
|
size[2] = 3.0;
|
|
flareColor = ColorF(0.25, 0.25, 1);
|
|
|
|
flareModTexture = "";
|
|
flareBaseTexture = "";
|
|
}
|
|
|
|
LinearFlareProjectileData::~LinearFlareProjectileData()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
void LinearFlareProjectileData::initPersistFields()
|
|
{
|
|
Parent::initPersistFields();
|
|
|
|
addField("numFlares", TypeS32, Offset(numFlares, LinearFlareProjectileData));
|
|
addField("size", TypeF32, Offset(size, LinearFlareProjectileData), NUM_SIZES);
|
|
addField("flareColor", TypeColorF, Offset(flareColor, LinearFlareProjectileData));
|
|
|
|
addField("flareModTexture", TypeString, Offset(flareModTexture, LinearFlareProjectileData));
|
|
addField("flareBaseTexture", TypeString, Offset(flareBaseTexture, LinearFlareProjectileData));
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
bool LinearFlareProjectileData::onAdd()
|
|
{
|
|
if(!Parent::onAdd())
|
|
return false;
|
|
|
|
if (numFlares < 0) {
|
|
Con::warnf(ConsoleLogEntry::General, "LinearFlareProjectile(%s)::onAdd: must have at least no flares", getName());
|
|
numFlares = 0;
|
|
}
|
|
flareColor.clamp();
|
|
|
|
if (!flareModTexture || !flareModTexture[0] || !flareBaseTexture || !flareBaseTexture[0]) {
|
|
Con::warnf(ConsoleLogEntry::General, "LinearFlareProjectile(%s)::onAdd: must have mod and base textures", getName());
|
|
return false;
|
|
}
|
|
if (dStrlen(flareModTexture) >= 255 || dStrlen(flareBaseTexture) >= 255) {
|
|
Con::warnf(ConsoleLogEntry::General, "LinearFlareProjectile(%s)::onAdd: must have mod and base textures with strlen < 255", getName());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool LinearFlareProjectileData::preload(bool server, char errorBuffer[256])
|
|
{
|
|
if (Parent::preload(server, errorBuffer) == false)
|
|
return false;
|
|
|
|
if(!server)
|
|
{
|
|
baseHandle = TextureHandle(flareBaseTexture, MeshTexture);
|
|
modHandle = TextureHandle(flareModTexture, MeshTexture);
|
|
if((TextureObject*)baseHandle == NULL)
|
|
{
|
|
dSprintf(errorBuffer, sizeof(errorBuffer), "Unable to load texture: %s", flareBaseTexture);
|
|
return false;
|
|
}
|
|
if((TextureObject*)modHandle == NULL)
|
|
{
|
|
dSprintf(errorBuffer, sizeof(errorBuffer), "Unable to load texture: %s", flareModTexture);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
void LinearFlareProjectileData::packData(BitStream* stream)
|
|
{
|
|
Parent::packData(stream);
|
|
|
|
stream->write(numFlares);
|
|
stream->write(flareColor);
|
|
stream->writeString(flareModTexture);
|
|
stream->writeString(flareBaseTexture);
|
|
|
|
for( U32 i=0; i<NUM_SIZES; i++ )
|
|
{
|
|
stream->write( size[i] );
|
|
}
|
|
}
|
|
|
|
void LinearFlareProjectileData::unpackData(BitStream* stream)
|
|
{
|
|
Parent::unpackData(stream);
|
|
|
|
stream->read(&numFlares);
|
|
stream->read(&flareColor);
|
|
flareModTexture = stream->readSTString();
|
|
flareBaseTexture = stream->readSTString();
|
|
|
|
for( U32 i=0; i<NUM_SIZES; i++ )
|
|
{
|
|
stream->read( &size[i] );
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//--------------------------------------
|
|
//
|
|
LinearFlareProjectile::LinearFlareProjectile()
|
|
{
|
|
// Todo: ScopeAlways?
|
|
mNetFlags.set(Ghostable);
|
|
|
|
mFlares = NULL;
|
|
}
|
|
|
|
LinearFlareProjectile::~LinearFlareProjectile()
|
|
{
|
|
delete [] mFlares;
|
|
mFlares = NULL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void LinearFlareProjectile::initPersistFields()
|
|
{
|
|
Parent::initPersistFields();
|
|
|
|
//
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
bool LinearFlareProjectile::onAdd()
|
|
{
|
|
if(!Parent::onAdd())
|
|
return false;
|
|
|
|
U32 numSizes = LinearFlareProjectileData::NUM_SIZES;
|
|
|
|
mObjBox.min.set(mDataBlock->size[numSizes], mDataBlock->size[numSizes], mDataBlock->size[numSizes]);
|
|
mObjBox.max.set(mDataBlock->size[numSizes], mDataBlock->size[numSizes], mDataBlock->size[numSizes]);
|
|
mObjBox.min.neg();
|
|
resetWorldBox();
|
|
|
|
if (isClientObject()) {
|
|
if (mDataBlock->numFlares > 0)
|
|
mFlares = new Flare[mDataBlock->numFlares];
|
|
else
|
|
mFlares = NULL;
|
|
|
|
for (U32 i = 0; i < mDataBlock->numFlares; i++)
|
|
mFlares[i].active = false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void LinearFlareProjectile::onRemove()
|
|
{
|
|
Parent::onRemove();
|
|
}
|
|
|
|
|
|
bool LinearFlareProjectile::onNewDataBlock(GameBaseData* dptr)
|
|
{
|
|
mDataBlock = dynamic_cast<LinearFlareProjectileData*>(dptr);
|
|
if (!mDataBlock || !Parent::onNewDataBlock(dptr))
|
|
return false;
|
|
|
|
scriptOnNewDataBlock();
|
|
return true;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
void LinearFlareProjectile::advanceTime(F32 dt)
|
|
{
|
|
Parent::advanceTime(dt);
|
|
|
|
if (mDataBlock->activateDelayMS != -1 &&
|
|
mCurrTick * TickMs < mDataBlock->activateDelayMS)
|
|
return;
|
|
|
|
static MRandomLCG sRand(50817);
|
|
for (U32 i = 0; i < mDataBlock->numFlares; i++) {
|
|
if (mFlares[i].active) {
|
|
mFlares[i].currT += dt;
|
|
if (mFlares[i].currT > mFlares[i].t2) {
|
|
mFlares[i].active = false;
|
|
}
|
|
}
|
|
|
|
if (mFlares[i].active == false) {
|
|
mFlares[i].minTheta = mDegToRad(87.0f);
|
|
mFlares[i].maxTheta = mDegToRad(65.0f + 20 * sRand.randF());
|
|
mFlares[i].h0 = mDataBlock->size[0];
|
|
mFlares[i].h1 = mDataBlock->size[1] + 0.25 * sRand.randF();
|
|
mFlares[i].h2 = mDataBlock->size[2] + sRand.randF();
|
|
|
|
mFlares[i].a0 = 0.0;
|
|
mFlares[i].a1 = 1.0;
|
|
mFlares[i].a2 = 0.0;
|
|
mFlares[i].currT = 0.0;
|
|
mFlares[i].active = true;
|
|
mFlares[i].normal = Point3F(1.0 - 2*sRand.randF(), 1.0 - 2*sRand.randF(), 1.0 - 2*sRand.randF());
|
|
mFlares[i].normal.normalize();
|
|
|
|
mFlares[i].t0 = 0.0;
|
|
mFlares[i].t1 = 0.15 + 0.225 * sRand.randF();
|
|
mFlares[i].t2 = 0.4 + 0.595 * sRand.randF();
|
|
}
|
|
|
|
mFlares[i].generatePoints();
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
void LinearFlareProjectile::renderObject(SceneState* state, SceneRenderImage *sri /*sceneImage*/)
|
|
{
|
|
if( mHitWater && mPlayedSplash ) return;
|
|
|
|
if( mProjectileShape )
|
|
{
|
|
Parent::renderObject( state, sri );
|
|
}
|
|
|
|
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
|
|
|
|
RectI viewport;
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
dglGetViewport(&viewport);
|
|
|
|
// Uncomment this if this is a "simple" (non-zone managing) object
|
|
state->setupObjectProjection(this);
|
|
|
|
Point3F cameraOffset;
|
|
getRenderTransform().getColumn(3,&cameraOffset);
|
|
cameraOffset -= state->getCameraPosition();
|
|
F32 fogAmount = state->getHazeAndFog(cameraOffset.len(),cameraOffset.z);
|
|
|
|
MatrixF mv;
|
|
dglGetModelview(&mv);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
dglMultMatrix(&getRenderTransform());
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, mDataBlock->modHandle.getGLName());
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
glEnable(GL_BLEND);
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
|
for (U32 i = 0; i < mDataBlock->numFlares; i++) {
|
|
if (mFlares[i].active)
|
|
mFlares[i].render(mDataBlock->flareColor, mFadeValue * (1.0 - fogAmount));
|
|
}
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
|
|
|
|
if( !mProjectileShape )
|
|
{
|
|
Point3F ax0;
|
|
Point3F ax1;
|
|
Point3F center;
|
|
mv.getRow(0, &ax0);
|
|
mv.getRow(2, &ax1);
|
|
getRenderTransform().getColumn(3, ¢er);
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
glBindTexture(GL_TEXTURE_2D, mDataBlock->baseHandle.getGLName());
|
|
glColor3f(mSqrt(mDataBlock->flareColor.red) * mFadeValue * (1.0 - fogAmount),
|
|
mSqrt(mDataBlock->flareColor.green) * mFadeValue * (1.0 - fogAmount),
|
|
mSqrt(mDataBlock->flareColor.blue) * mFadeValue * (1.0 - fogAmount));
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glTexCoord2f(0, 0);
|
|
glVertex3fv(center + ((ax0 * -0.6) + (ax1 * -0.6)) * mDataBlock->scale.x);
|
|
glTexCoord2f(0, 1);
|
|
glVertex3fv(center + ((ax0 * -0.6) + (ax1 * 0.6)) * mDataBlock->scale.x);
|
|
glTexCoord2f(1, 1);
|
|
glVertex3fv(center + ((ax0 * 0.6) + (ax1 * 0.6)) * mDataBlock->scale.x);
|
|
glTexCoord2f(1, 0);
|
|
glVertex3fv(center + ((ax0 * 0.6) + (ax1 * -0.6)) * mDataBlock->scale.x);
|
|
glEnd();
|
|
glColor3f(mFadeValue * (1.0 - fogAmount),
|
|
mFadeValue * (1.0 - fogAmount),
|
|
mFadeValue * (1.0 - fogAmount));
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glTexCoord2f(0, 0);
|
|
glVertex3fv(center + ((ax0 * -0.3) + (ax1 * -0.3)) * mDataBlock->scale.x);
|
|
glTexCoord2f(0, 1);
|
|
glVertex3fv(center + ((ax0 * -0.3) + (ax1 * 0.3)) * mDataBlock->scale.x);
|
|
glTexCoord2f(1, 1);
|
|
glVertex3fv(center + ((ax0 * 0.3) + (ax1 * 0.3)) * mDataBlock->scale.x);
|
|
glTexCoord2f(1, 0);
|
|
glVertex3fv(center + ((ax0 * 0.3) + (ax1 * -0.3)) * mDataBlock->scale.x);
|
|
glEnd();
|
|
}
|
|
|
|
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
dglSetViewport(viewport);
|
|
|
|
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
U32 LinearFlareProjectile::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
|
|
{
|
|
U32 retMask = Parent::packUpdate(con, mask, stream);
|
|
|
|
//
|
|
|
|
return retMask;
|
|
}
|
|
|
|
void LinearFlareProjectile::unpackUpdate(NetConnection* con, BitStream* stream)
|
|
{
|
|
Parent::unpackUpdate(con, stream);
|
|
|
|
//
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
void LinearFlareProjectile::Flare::generatePoints()
|
|
{
|
|
Point3F axisz = normal;
|
|
Point3F axisx;
|
|
Point3F axisy;
|
|
|
|
if (mFabs(axisz.x) < 0.9) {
|
|
mCross(axisz, Point3F(1, 0, 0), &axisy);
|
|
axisy.normalize();
|
|
mCross(axisz, axisy, &axisx);
|
|
axisx.normalize();
|
|
axisx.neg();
|
|
} else {
|
|
mCross(axisz, Point3F(0, 1, 0), &axisy);
|
|
axisy.normalize();
|
|
mCross(axisz, axisy, &axisx);
|
|
axisx.normalize();
|
|
axisx.neg();
|
|
}
|
|
|
|
F32 currTheta;
|
|
F32 currH1;
|
|
if (currT < t1) {
|
|
currTheta = minTheta;
|
|
currH1 = h1 + (h2 - h1) * (currT / t1);
|
|
} else {
|
|
currTheta = minTheta + ((maxTheta - minTheta) * ((currT - t1) / (t2 - t1)));
|
|
currH1 = h2;
|
|
}
|
|
F32 zmul = 1 - mSin(currTheta);
|
|
|
|
axisx *= mCos(currTheta);
|
|
axisy *= mCos(currTheta);
|
|
|
|
points[0] = (axisz - axisx - axisy) * h0;
|
|
points[1] = (axisz - axisy ) * h0;
|
|
points[2] = (axisz + axisx - axisy) * h0;
|
|
points[3] = (axisz + axisx ) * h0;
|
|
points[4] = (axisz + axisx + axisy) * h0;
|
|
points[5] = (axisz + axisy ) * h0;
|
|
points[6] = (axisz - axisx + axisy) * h0;
|
|
points[7] = (axisz - axisx ) * h0;
|
|
|
|
points[8] = ((axisz - axisx - axisy) * currH1) - axisz * zmul;
|
|
points[9] = ((axisz - axisy ) * currH1) - axisz * zmul;
|
|
points[10] = ((axisz + axisx - axisy) * currH1) - axisz * zmul;
|
|
points[11] = ((axisz + axisx ) * currH1) - axisz * zmul;
|
|
points[12] = ((axisz + axisx + axisy) * currH1) - axisz * zmul;
|
|
points[13] = ((axisz + axisy ) * currH1) - axisz * zmul;
|
|
points[14] = ((axisz - axisx + axisy) * currH1) - axisz * zmul;
|
|
points[15] = ((axisz - axisx ) * currH1) - axisz * zmul;
|
|
}
|
|
|
|
void LinearFlareProjectile::Flare::render(const ColorF& color, const F32 currFade)
|
|
{
|
|
F32 currA;
|
|
if (currT < t1) {
|
|
currA = a0 + (a1 - a0) * (currT / t1);
|
|
} else {
|
|
currA = a1 + (a2 - a1) * ((currT - t1) / (t2 - t1));
|
|
}
|
|
currA *= currFade;
|
|
|
|
ColorF base = color * currA * currFade;
|
|
ColorF bright = color * currA * 0.5;
|
|
ColorF dim = color * (0.25 * currA);
|
|
|
|
for (U32 i = 0; i <= 6; i+=2) {
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glTexCoord2f(0.5, 0.9);
|
|
glColor3f(base.red, base.green, base.blue);
|
|
glVertex3fv(points[i + 1]);
|
|
|
|
glTexCoord2f(0, 0.9);
|
|
glColor3f(base.red, base.green, base.blue);
|
|
glVertex3fv(points[i + 0]);
|
|
|
|
glTexCoord2f(0, 0.1);
|
|
glColor3f(bright.red, bright.green, bright.blue);
|
|
glVertex3fv(points[i + 8 + 0]);
|
|
|
|
glTexCoord2f(0.5, 0.1);
|
|
glColor3f(dim.red, dim.green, dim.blue);
|
|
glVertex3fv(points[i + 8 + 1]);
|
|
|
|
glTexCoord2f(1, 0.1);
|
|
glColor3f(bright.red, bright.green, bright.blue);
|
|
glVertex3fv(points[8 + ((i + 2) & 0x7)]);
|
|
|
|
glTexCoord2f(1, 0.9);
|
|
glColor3f(base.red, base.green, base.blue);
|
|
glVertex3fv(points[(i + 2) & 0x7]);
|
|
glEnd();
|
|
|
|
}
|
|
}
|