You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
763 lines
21 KiB
763 lines
21 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
|
|
#include "hsTypes.h" |
|
#include "hsStream.h" |
|
#include "hsOscillator.h" |
|
#include "../plMath/hsFastMath.h" |
|
#include "hsGTriMesh.h" |
|
#include "hsTriangle3.h" |
|
#include "../plPipeline/plPipeline.h" |
|
|
|
#if defined(__MWERKS__) && !defined(HS_DEBUGGING) |
|
#pragma optimization_level 0 |
|
#endif |
|
|
|
static hsScalar rnd0_1() |
|
{ |
|
return hsScalar(rand()) / hsScalar(RAND_MAX); |
|
} |
|
|
|
void hsWave::Save(hsStream* s, hsScalar secs) |
|
{ |
|
fWorldCenter.Write(s); |
|
|
|
s->WriteSwapScalar(fWorldFrequency); |
|
|
|
s->WriteSwapScalar(fWorldAmplitude); |
|
|
|
s->WriteSwapScalar(fPhase); |
|
s->WriteSwapScalar(fRate); |
|
|
|
s->WriteSwapScalar(secs - fStartSecs); |
|
|
|
s->WriteSwapScalar(fSecsToLive); |
|
} |
|
|
|
void hsWave::Load(hsStream* s, hsScalar secs) |
|
{ |
|
fWorldCenter.Read(s); |
|
|
|
fWorldFrequency = s->ReadSwapScalar(); |
|
|
|
fWorldAmplitude = s->ReadSwapScalar(); |
|
|
|
fPhase = s->ReadSwapScalar(); |
|
fRate = s->ReadSwapScalar(); |
|
|
|
fStartSecs = s->ReadSwapScalar(); |
|
fStartSecs = secs - fStartSecs; |
|
|
|
fSecsToLive = s->ReadSwapScalar(); |
|
} |
|
|
|
void hsWave::Init(hsScalar secs, hsPoint3& center, hsScalar per, hsScalar amp, hsScalar rate, hsScalar life, hsBool32 attenOut) |
|
{ |
|
fStartSecs = secs; |
|
fWorldCenter = center; |
|
fWorldFrequency = hsScalarInvert(per); |
|
fWorldAmplitude = amp; |
|
fRate = rate; |
|
fSecsToLive = life; |
|
AttenuateOut(attenOut); |
|
} |
|
|
|
hsBool32 hsWave::IsSpent(hsScalar secs) const |
|
{ |
|
return secs - fStartSecs > fSecsToLive; |
|
} |
|
|
|
void hsWave::Accumulate(const hsPoint3& pos, const hsVector3& localZ, hsVector3& accum, hsVector3& accumNorm) const |
|
{ |
|
hsVector3 del(&pos, &fLocalCenter); |
|
hsScalar dot = del.InnerProduct(localZ); |
|
dot *= -2.f; |
|
del += localZ * dot; |
|
|
|
hsScalar dist = del.MagnitudeSquared(); |
|
dist = hsFastMath::InvSqrtAppr(dist); |
|
del *= dist; |
|
dist = hsScalarInvert(dist); |
|
|
|
hsScalar ampl = fLocalAmplitude; |
|
if( fAttenuateOutScale > 0 ) |
|
{ |
|
if( dist > fInnerRadius ) |
|
{ |
|
if( dist > fOuterRadius ) |
|
return; |
|
ampl *= fOuterRadius - dist; |
|
ampl *= fAttenuateOutScale; |
|
} |
|
} |
|
|
|
dist *= fLocalFrequency; |
|
dist += fPhase; |
|
|
|
hsScalar s, c; |
|
hsFastMath::SinCosAppr(dist, s, c); |
|
|
|
s *= ampl; |
|
s += ampl; |
|
c *= ampl * fLocalFrequency; |
|
|
|
// accum += s * localZ; |
|
accum.fZ += s / localZ.fZ; |
|
|
|
hsVector3 norm; |
|
norm = localZ; |
|
norm += del * -c; |
|
accumNorm += norm; |
|
|
|
return; |
|
} |
|
|
|
void hsWave::Update(hsScalar secs, const hsMatrix44& l2w, const hsMatrix44& w2l) |
|
{ |
|
if( l2w.fFlags & hsMatrix44::kIsIdent ) |
|
{ |
|
fLocalCenter = fWorldCenter; |
|
fLocalFrequency = fWorldFrequency; |
|
fLocalAmplitude = fWorldAmplitude; |
|
} |
|
else |
|
{ |
|
hsVector3 ax; |
|
ax.Set(w2l.fMap[0][2], w2l.fMap[1][2], w2l.fMap[2][2]); |
|
hsScalar ooScale = ax.MagnitudeSquared(); |
|
ooScale = hsFastMath::InvSqrtAppr(ooScale); |
|
|
|
fLocalCenter = w2l * fWorldCenter; |
|
fLocalFrequency = fWorldFrequency * ooScale; |
|
|
|
hsScalar scale = 1.f / ooScale; |
|
fLocalAmplitude = fWorldAmplitude * scale; |
|
} |
|
fLocalAmplitude *= AgeScale(secs); |
|
|
|
if( fAttenuateOutScale > 0 ) |
|
{ |
|
fInnerRadius = fRate * (secs - fStartSecs) * hsScalarPI * 2.f; |
|
fOuterRadius = fInnerRadius * (5.f/4.f); |
|
fAttenuateOutScale = hsScalarInvert(fOuterRadius - fInnerRadius); |
|
} |
|
|
|
fPhase = -(secs - fStartSecs) * fRate * hsScalarPI * 2.f; |
|
} |
|
|
|
hsScalar hsWave::ScaledAmplitude(hsScalar secs) const |
|
{ |
|
return fWorldAmplitude * AgeScale(secs); |
|
} |
|
|
|
hsScalar hsWave::AgeScale(hsScalar secs) const |
|
{ |
|
hsScalar age = secs - fStartSecs; |
|
extern int dbgCurrentTest; |
|
if( dbgCurrentTest ) |
|
{ |
|
age *= 4.f; |
|
age -= 2.f * fSecsToLive; |
|
if( age < 0 ) |
|
age = -age; |
|
age -= fSecsToLive; |
|
} |
|
else |
|
{ |
|
age *= 2.f; |
|
age -= fSecsToLive; |
|
if( age < 0 ) |
|
age = -age; |
|
} |
|
hsScalar ageScale = 1.f - age / fSecsToLive; |
|
if( ageScale < 0 ) |
|
ageScale = 0; |
|
else if( ageScale > 1.f ) |
|
ageScale = 1.f; |
|
return ageScale; |
|
} |
|
|
|
hsOscillator::hsOscillator() |
|
{ |
|
} |
|
|
|
hsOscillator::~hsOscillator() |
|
{ |
|
} |
|
|
|
hsWave& hsOscillator::GetWeakestWave(hsScalar secs) |
|
{ |
|
hsAssert(!GetDisabled(), "Shouldn't be messing with disabled oscillator system"); |
|
int weakest = 0; |
|
hsScalar amp = fWaves[0].ScaledAmplitude(secs); |
|
int i; |
|
for( i = 0; i < fWaves.GetCount(); i++ ) |
|
{ |
|
hsScalar tAmp = fWaves[i].ScaledAmplitude(secs); |
|
if( tAmp < amp ) |
|
{ |
|
weakest = i; |
|
amp = tAmp; |
|
} |
|
} |
|
return fWaves[weakest]; |
|
} |
|
|
|
hsWave& hsOscillator::GetTempWave(hsScalar secs) |
|
{ |
|
int i; |
|
for( i = 0; i < fTempWaves.GetCount(); i++ ) |
|
{ |
|
if( fTempWaves[i].IsSpent(secs) ) |
|
return fTempWaves[i]; |
|
} |
|
fTempWaves.Push(); |
|
return fTempWaves[fTempWaves.GetCount()-1]; |
|
} |
|
|
|
void hsOscillator::ISpawnWave(hsScalar secs, int i) |
|
{ |
|
hsPoint3 corner; |
|
fWorldCenterBounds.GetCorner(&corner); |
|
hsVector3 ax[3]; |
|
fWorldCenterBounds.GetAxes(ax+0, ax+1, ax+2); |
|
hsScalar r; |
|
r = rnd0_1(); |
|
ax[0] *= r; |
|
corner += ax[0]; |
|
r = rnd0_1(); |
|
ax[1] *= r; |
|
corner += ax[1]; |
|
r = rnd0_1(); |
|
ax[2] *= r; |
|
corner += ax[2]; |
|
|
|
hsScalar per = fMinPeriod; |
|
r = rnd0_1(); |
|
hsScalar rr = r; |
|
r *= fMaxPeriod - fMinPeriod; |
|
per += r; |
|
|
|
hsScalar amp = fMinAmplitude; |
|
r = rr * rnd0_1(); |
|
r *= fMaxAmplitude - fMinAmplitude; |
|
amp += r; |
|
|
|
hsScalar life = fMinLife; |
|
r = rnd0_1(); |
|
r *= fMaxLife - fMinLife; |
|
life += r; |
|
|
|
hsScalar rate = fMinRate; |
|
r = rnd0_1(); |
|
r *= fMaxRate - fMinRate; |
|
rate += r; |
|
|
|
fWaves[i].Init(secs, corner, per, amp, rate, life); |
|
|
|
} |
|
|
|
void hsOscillator::IUpdate(hsScalar secs, plPipeline* pipe, const hsMatrix44& l2w, const hsMatrix44& w2l) |
|
{ |
|
if( GetDisabled() ) |
|
return; |
|
|
|
fWorldCenter = pipe->GetViewPositionWorld(); |
|
fWorldCenter.fZ = (fWorldCenterBounds.GetMins().fZ + fWorldCenterBounds.GetMaxs().fZ) * 0.5f; |
|
fLocalCenter = w2l * fWorldCenter; |
|
|
|
fLocalToWorld = l2w; |
|
fWorldToLocal = w2l; |
|
|
|
fLocalX.Set(w2l.fMap[0][0],w2l.fMap[1][0],w2l.fMap[2][0]); |
|
fLocalX.Normalize(); |
|
fLocalY.Set(w2l.fMap[0][1],w2l.fMap[1][1],w2l.fMap[2][1]); |
|
fLocalY.Normalize(); |
|
fLocalZ.Set(w2l.fMap[0][2],w2l.fMap[1][2],w2l.fMap[2][2]); |
|
fLocalZ.Normalize(); |
|
|
|
hsVector3 ax; |
|
hsScalar ooScale; |
|
ax.Set(w2l.fMap[0][0], w2l.fMap[1][0], w2l.fMap[2][0]); |
|
ooScale = ax.MagnitudeSquared(); |
|
ooScale = hsFastMath::InvSqrtAppr(ooScale); |
|
fLocalAttenScale.fX = fWorldAttenScale.fX * ooScale; |
|
|
|
ax.Set(w2l.fMap[0][1], w2l.fMap[1][1], w2l.fMap[2][1]); |
|
ooScale = ax.MagnitudeSquared(); |
|
ooScale = hsFastMath::InvSqrtAppr(ooScale); |
|
fLocalAttenScale.fY = fWorldAttenScale.fY * ooScale; |
|
|
|
fLocalAttenScale.fZ = 0; |
|
|
|
int i; |
|
for( i = 0; i < fWaves.GetCount(); i++ ) |
|
{ |
|
if( fWaves[i].IsSpent(secs) ) |
|
ISpawnWave(secs, i); |
|
fWaves[i].Update(secs, l2w, w2l); |
|
} |
|
for( i = 0; i < fTempWaves.GetCount(); i++ ) |
|
{ |
|
while( (i < fTempWaves.GetCount()) && fTempWaves[i].IsSpent(secs) ) |
|
fTempWaves.Remove(i, 1); |
|
if( i < fTempWaves.GetCount() ) |
|
fTempWaves[i].Update(secs, l2w, w2l); |
|
} |
|
} |
|
|
|
hsScalar hsOscillator::IAttenuate(const hsPoint3& in) const |
|
{ |
|
const hsPoint3& cen = fLocalCenter; |
|
hsVector3 del(&in, &cen); |
|
|
|
hsScalar atX = del.InnerProduct(fLocalX); |
|
atX *= fLocalAttenScale.fX; |
|
if( atX > 0 ) |
|
atX = -atX; |
|
atX += 1.f; |
|
if( atX < 0 ) |
|
atX = 0; |
|
|
|
hsScalar atY = del.InnerProduct(fLocalY); |
|
atY *= fLocalAttenScale.fY; |
|
if( atY > 0 ) |
|
atY = -atY; |
|
atY += 1.f; |
|
if( atY < 0 ) |
|
atY = 0; |
|
|
|
hsScalar at = atX * atY; |
|
return at; |
|
} |
|
|
|
void hsOscillator::AdjustWorldBounds(const hsMatrix44& l2w, const hsMatrix44& w2l, hsBounds3Ext& bnd) const |
|
{ |
|
if( GetDisabled() ) |
|
return; |
|
|
|
hsVector3 adj; |
|
adj.Set(0,1.f/fLocalZ.fZ,0); |
|
adj = l2w * adj; |
|
adj *= fMaxAmplitude * fWaves.GetCount(); |
|
|
|
bnd.Union(&adj); |
|
adj = -adj; |
|
bnd.Union(&adj); |
|
} |
|
|
|
void hsOscillator::IPerterb(const hsPoint3& in, hsGVertex3& out) const |
|
{ |
|
hsPoint3 pos = in; |
|
hsVector3 del(&pos, &fLocalCenter); |
|
hsScalar dot = del.InnerProduct(fLocalZ); |
|
pos += fLocalZ * -dot; |
|
|
|
hsVector3 accum; |
|
hsVector3 accumNorm; |
|
accum.Set(0,0,0); |
|
accumNorm.Set(0,0,0); |
|
int i; |
|
for( i = 0; i < fWaves.GetCount(); i++ ) |
|
{ |
|
fWaves[i].Accumulate(pos, fLocalZ, accum, accumNorm); |
|
} |
|
for( i = 0; i < fTempWaves.GetCount(); i++ ) |
|
{ |
|
fTempWaves[i].Accumulate(pos, fLocalZ, accum, accumNorm); |
|
} |
|
hsScalar atten = IAttenuate(pos); |
|
static int attenuating = 1; |
|
if( attenuating ) // nuke me |
|
accum *= atten; |
|
out.fLocalPos = in + accum; |
|
|
|
hsScalar invNorm = hsFastMath::InvSqrtAppr(accumNorm.MagnitudeSquared()); |
|
accumNorm *= invNorm; |
|
out.fNormal = accumNorm; |
|
} |
|
|
|
void hsOscillator::Read(hsStream* s) |
|
{ |
|
int n = s->ReadSwap32(); |
|
SetNumWaves(n); |
|
|
|
fWorldAttenScale.Read(s); |
|
fWorldCenterBounds.Read(s); |
|
|
|
fMinPeriod = s->ReadSwapScalar(); |
|
fMaxPeriod = s->ReadSwapScalar(); |
|
|
|
fMinAmplitude = s->ReadSwapScalar(); |
|
fMaxAmplitude = s->ReadSwapScalar(); |
|
|
|
fMinRate = s->ReadSwapScalar(); |
|
fMaxRate = s->ReadSwapScalar(); |
|
|
|
fMinLife = s->ReadSwapScalar(); |
|
fMaxLife = s->ReadSwapScalar(); |
|
|
|
int i; |
|
for( i = 0; i < fWaves.GetCount(); i++ ) |
|
fWaves[i].Kill(); |
|
|
|
fTempWaves.Reset(); |
|
} |
|
|
|
void hsOscillator::Load(hsStream* s, hsScalar secs) |
|
{ |
|
Read(s); |
|
|
|
int i; |
|
for( i = 0; i < fWaves.GetCount(); i++ ) |
|
fWaves[i].Load(s, secs); |
|
|
|
fTempWaves.Reset(); |
|
} |
|
|
|
void hsOscillator::Write(hsStream* s) |
|
{ |
|
s->WriteSwap32(fWaves.GetCount()); |
|
|
|
fWorldAttenScale.Write(s); |
|
fWorldCenterBounds.Write(s); |
|
|
|
s->WriteSwapScalar(fMinPeriod); |
|
s->WriteSwapScalar(fMaxPeriod); |
|
|
|
s->WriteSwapScalar(fMinAmplitude); |
|
s->WriteSwapScalar(fMaxAmplitude); |
|
|
|
s->WriteSwapScalar(fMinRate); |
|
s->WriteSwapScalar(fMaxRate); |
|
|
|
s->WriteSwapScalar(fMinLife); |
|
s->WriteSwapScalar(fMaxLife); |
|
|
|
} |
|
|
|
void hsOscillator::Save(hsStream* s, hsScalar secs) |
|
{ |
|
Write(s); |
|
|
|
int i; |
|
for( i = 0; i < fWaves.GetCount(); i++ ) |
|
fWaves[i].Save(s, secs); |
|
} |
|
|
|
void hsOscillator::SetNumWaves(int n) |
|
{ |
|
fWaves.SetCount(n); |
|
int i; |
|
for( i = 0; i < n; i++ ) |
|
fWaves[i].Kill(); |
|
} |
|
|
|
void hsOscillator::Init(int32_t nParams, hsScalar* params) |
|
{ |
|
// NumWaves = 1 |
|
// AttenScale = 2 |
|
// WorldCenterBounds = 6 |
|
// Period = 2 |
|
// Amp = 2 |
|
// Rate = 2 |
|
// Life = 2 |
|
|
|
hsAssert(17 == nParams, "Parameter input mismatch"); |
|
|
|
SetNumWaves(int(*params++)); |
|
|
|
fWorldAttenScale.fX = *params++; |
|
fWorldAttenScale.fY = *params++; |
|
fWorldAttenScale.fZ = 0; |
|
|
|
hsPoint3 pt; |
|
hsBounds3Ext bnd; |
|
pt.fX = *params++; |
|
pt.fY = *params++; |
|
pt.fZ = *params++; |
|
bnd.Reset(&pt); |
|
pt.fX = *params++; |
|
pt.fY = *params++; |
|
pt.fZ = *params++; |
|
bnd.Union(&pt); |
|
SetWorldCenterBounds(bnd); |
|
|
|
SetPeriodRange(params[0], params[1]); |
|
params += 2; |
|
|
|
SetAmplitudeRange(params[0], params[1]); |
|
params += 2; |
|
|
|
SetRateRange(params[0], params[1]); |
|
params += 2; |
|
|
|
SetLifeRange(params[0], params[1]); |
|
|
|
fTempWaves.Reset(); |
|
} |
|
|
|
|
|
#if 1 |
|
hsGTriMesh* hsOscillator::MakeWaveMesh(int nSpokes, const hsPoint3& center, hsScalar minRad, hsScalar maxRad, hsScalar uRange, hsScalar vRange, hsScalar attenStartFrac, hsBool32 stitch) |
|
{ |
|
hsGTriMesh* triMesh = new hsGTriMesh; |
|
|
|
hsTArray<hsScalar> radii; |
|
hsScalar cRad = 0; |
|
while( cRad < maxRad ) |
|
{ |
|
// OOPS - for the half circle, this should be PI*R/n, not 2PI. Don't fix until we've corrected the callers. Or we might want to leave it like |
|
// this anyway, since we're looking obliquely at these faces anyway, and this error stretches the side that perspective compresses. May |
|
// want to make the unstitched version wrong in the same way. |
|
hsScalar tRad = 2.f * hsScalarPI * cRad / nSpokes; |
|
if( tRad < minRad ) |
|
tRad = minRad; |
|
cRad += tRad; |
|
radii.Append(cRad); |
|
} |
|
|
|
int nShell = radii.GetCount(); |
|
|
|
int nTris = stitch |
|
? 2 * nSpokes * (nShell-1) + nSpokes |
|
: 2 * (nSpokes-1) * (nShell-1) + (nSpokes-1); |
|
int nVerts = nSpokes * nShell + 1; |
|
triMesh->AllocatePointers(nTris, nVerts, nVerts, nVerts); |
|
triMesh->SetNumTriVertex(nVerts); |
|
triMesh->SetNumPoints(nVerts); |
|
triMesh->SetNumUvs(nVerts); |
|
triMesh->SetHasColors(true); |
|
|
|
*triMesh->GetPoint(0) = center; |
|
triMesh->GetNormal(0)->Set(0,1.f,0); |
|
triMesh->GetColor(0)->Set(0,0,0,1.f); |
|
triMesh->GetUvs(0)->fX = triMesh->GetUvs(0)->fY = triMesh->GetUvs(0)->fZ = 0; |
|
|
|
hsScalar iToRadians = stitch |
|
? 2.f * hsScalarPI / nSpokes |
|
: hsScalarPI / nSpokes; |
|
hsScalar attenStart = maxRad * attenStartFrac; |
|
hsScalar attenEnd = maxRad; |
|
hsScalar attenScale = hsScalarInvert(attenEnd - attenStart); |
|
int i, j; |
|
for( i = 0; i < nSpokes; i++ ) |
|
{ |
|
hsScalar s = hsSine(i * iToRadians); |
|
hsScalar c = hsCosine(i * iToRadians); |
|
for( j = 0; j < nShell; j++ ) |
|
{ |
|
hsAssert(1 + i*nShell + j < nVerts, "Going out of range on verts"); |
|
hsGVertex3* vtx = triMesh->GetVertex(1 + i*nShell + j); |
|
hsColorRGBA* col = triMesh->GetColor(1 + i*nShell + j); |
|
hsGUv* uv = triMesh->GetUvs(1 + i*nShell + j); |
|
|
|
hsScalar x = c * radii[j]; |
|
hsScalar y = s * radii[j]; |
|
|
|
hsScalar u = x / uRange; |
|
hsScalar v = y / vRange; |
|
|
|
vtx->fLocalPos.fX = center.fX + x; |
|
vtx->fLocalPos.fY = center.fY + y; |
|
vtx->fLocalPos.fZ = 0.f; |
|
|
|
vtx->fNormal.Set(0,0,1.f); |
|
|
|
uv->fX = u; |
|
uv->fY = v; |
|
uv->fZ = 0.f; |
|
|
|
if( radii[j] > attenStart ) |
|
{ |
|
hsScalar a = (attenEnd - radii[j]) * attenScale; |
|
if( a < 0 ) |
|
a = 0; |
|
else if( a > 1.f ) |
|
a = 1.f; |
|
col->Set(0,0,0,a); |
|
} |
|
else |
|
col->Set(0,0,0,1.f); |
|
} |
|
} |
|
|
|
int spokeEnd = stitch ? nSpokes : nSpokes-1; |
|
int nextTri = 0; |
|
for( i = 0; i < spokeEnd; i++ ) |
|
{ |
|
hsTriangle3* tri = triMesh->GetTriFromPool(nextTri); |
|
tri->Zero(); |
|
tri->fOrigTri = tri; |
|
triMesh->SetTriangle(nextTri++, tri); |
|
|
|
tri->fVert[0] = triMesh->GetTriVertex(0); |
|
tri->fVert[0]->fVtx = triMesh->GetVertex(0); |
|
tri->fVert[0]->SetNumUvChannels(1); |
|
tri->fVert[0]->fUvChan[0] = triMesh->GetUvs(0); |
|
tri->fVert[0]->fVtxColor = triMesh->GetColor(0); |
|
|
|
int iv0 = 1 + i * nShell; |
|
int iv1 = i < nSpokes - 1 ? 1 + (i+1)*nShell : 1; |
|
hsAssert((iv0 < nVerts)&&(iv1 < nVerts), "Out of range on triverts"); |
|
|
|
tri->fVert[1] = triMesh->GetTriVertex(iv0); |
|
tri->fVert[1]->fVtx = triMesh->GetVertex(iv0); |
|
tri->fVert[1]->SetNumUvChannels(1); |
|
tri->fVert[1]->fUvChan[0] = triMesh->GetUvs(iv0); |
|
tri->fVert[1]->fVtxColor = triMesh->GetColor(iv0); |
|
|
|
tri->fVert[2] = triMesh->GetTriVertex(iv1); |
|
tri->fVert[2]->fVtx = triMesh->GetVertex(iv1); |
|
tri->fVert[2]->SetNumUvChannels(1); |
|
tri->fVert[2]->fUvChan[0] = triMesh->GetUvs(iv1); |
|
tri->fVert[2]->fVtxColor = triMesh->GetColor(iv1); |
|
|
|
tri->fVert[0]->fFlags = hsGTriVertex::kHasPointers |
|
| hsGTriVertex::kHasVertexUvs |
|
| hsGTriVertex::kHasVertexColors; |
|
tri->fVert[1]->fFlags = hsGTriVertex::kHasPointers |
|
| hsGTriVertex::kHasVertexUvs |
|
| hsGTriVertex::kHasVertexColors; |
|
tri->fVert[2]->fFlags = hsGTriVertex::kHasPointers |
|
| hsGTriVertex::kHasVertexUvs |
|
| hsGTriVertex::kHasVertexColors; |
|
|
|
tri->fFlags |= hsTriangle3::kHasVertexPosNorms |
|
| hsTriangle3::kHasVertexUvs |
|
| hsTriangle3::kHasVertexColors |
|
| hsTriangle3::kHasPointers; |
|
|
|
int iv2 = iv0 + 1; |
|
int iv3 = iv1 + 1; |
|
hsAssert((iv1 < nVerts)&&(iv2 < nVerts), "Out of range on triverts"); |
|
for( j = 0; j < nShell-1; j++ ) |
|
{ |
|
tri = triMesh->GetTriFromPool(nextTri); |
|
tri->Zero(); |
|
tri->fOrigTri = tri; |
|
triMesh->SetTriangle(nextTri++, tri); |
|
|
|
tri->fVert[0] = triMesh->GetTriVertex(iv0); |
|
tri->fVert[0]->fVtx = triMesh->GetVertex(iv0); |
|
tri->fVert[0]->SetNumUvChannels(1); |
|
tri->fVert[0]->fUvChan[0] = triMesh->GetUvs(iv0); |
|
tri->fVert[0]->fVtxColor = triMesh->GetColor(iv0); |
|
|
|
tri->fVert[1] = triMesh->GetTriVertex(iv2); |
|
tri->fVert[1]->fVtx = triMesh->GetVertex(iv2); |
|
tri->fVert[1]->SetNumUvChannels(1); |
|
tri->fVert[1]->fUvChan[1] = triMesh->GetUvs(iv2); |
|
tri->fVert[1]->fVtxColor = triMesh->GetColor(iv2); |
|
|
|
tri->fVert[2] = triMesh->GetTriVertex(iv3); |
|
tri->fVert[2]->fVtx = triMesh->GetVertex(iv3); |
|
tri->fVert[2]->SetNumUvChannels(1); |
|
tri->fVert[2]->fUvChan[0] = triMesh->GetUvs(iv3); |
|
tri->fVert[2]->fVtxColor = triMesh->GetColor(iv3); |
|
|
|
tri->fVert[0]->fFlags = hsGTriVertex::kHasPointers |
|
| hsGTriVertex::kHasVertexUvs |
|
| hsGTriVertex::kHasVertexColors; |
|
tri->fVert[1]->fFlags = hsGTriVertex::kHasPointers |
|
| hsGTriVertex::kHasVertexUvs |
|
| hsGTriVertex::kHasVertexColors; |
|
tri->fVert[2]->fFlags = hsGTriVertex::kHasPointers |
|
| hsGTriVertex::kHasVertexUvs |
|
| hsGTriVertex::kHasVertexColors; |
|
|
|
tri->fFlags |= hsTriangle3::kHasVertexPosNorms |
|
| hsTriangle3::kHasVertexUvs |
|
| hsTriangle3::kHasVertexColors |
|
| hsTriangle3::kHasPointers; |
|
|
|
tri = triMesh->GetTriFromPool(nextTri); |
|
tri->Zero(); |
|
tri->fOrigTri = tri; |
|
triMesh->SetTriangle(nextTri++, tri); |
|
|
|
tri->fVert[0] = triMesh->GetTriVertex(iv0); |
|
tri->fVert[0]->fVtx = triMesh->GetVertex(iv0); |
|
tri->fVert[0]->SetNumUvChannels(1); |
|
tri->fVert[0]->fUvChan[0] = triMesh->GetUvs(iv0); |
|
tri->fVert[0]->fVtxColor = triMesh->GetColor(iv0); |
|
|
|
tri->fVert[1] = triMesh->GetTriVertex(iv3); |
|
tri->fVert[1]->fVtx = triMesh->GetVertex(iv3); |
|
tri->fVert[1]->SetNumUvChannels(1); |
|
tri->fVert[1]->fUvChan[0] = triMesh->GetUvs(iv3); |
|
tri->fVert[1]->fVtxColor = triMesh->GetColor(iv3); |
|
|
|
tri->fVert[2] = triMesh->GetTriVertex(iv1); |
|
tri->fVert[2]->fVtx = triMesh->GetVertex(iv1); |
|
tri->fVert[2]->SetNumUvChannels(1); |
|
tri->fVert[2]->fUvChan[0] = triMesh->GetUvs(iv1); |
|
tri->fVert[2]->fVtxColor = triMesh->GetColor(iv1); |
|
|
|
tri->fVert[0]->fFlags = hsGTriVertex::kHasPointers |
|
| hsGTriVertex::kHasVertexUvs |
|
| hsGTriVertex::kHasVertexColors; |
|
tri->fVert[1]->fFlags = hsGTriVertex::kHasPointers |
|
| hsGTriVertex::kHasVertexUvs |
|
| hsGTriVertex::kHasVertexColors; |
|
tri->fVert[2]->fFlags = hsGTriVertex::kHasPointers |
|
| hsGTriVertex::kHasVertexUvs |
|
| hsGTriVertex::kHasVertexColors; |
|
|
|
tri->fFlags |= hsTriangle3::kHasVertexPosNorms |
|
| hsTriangle3::kHasVertexUvs |
|
| hsTriangle3::kHasVertexColors |
|
| hsTriangle3::kHasPointers; |
|
|
|
iv0++; |
|
iv1++; |
|
iv2++; |
|
iv3++; |
|
} |
|
} |
|
hsAssert(nextTri <= nTris, "Out of range on tris"); |
|
|
|
triMesh->StoreOrigPoints(); |
|
|
|
return triMesh; |
|
} |
|
#endif |