📄 tube.cpp
字号:
m_vertices[6] = Stuff::Vector3D(0.0f, 0.0f, 1.0f);
m_uvs.SetLength(7);
m_uvs[0] = Stuff::Vector2DOf<Stuff::Scalar>(0.0f, 0.0f);
m_uvs[1] = Stuff::Vector2DOf<Stuff::Scalar>(0.0f, 1.0f/6.0f);
m_uvs[2] = Stuff::Vector2DOf<Stuff::Scalar>(0.0f, 2.0f/6.0f);
m_uvs[3] = Stuff::Vector2DOf<Stuff::Scalar>(0.0f, 0.5f);
m_uvs[4] = Stuff::Vector2DOf<Stuff::Scalar>(0.0f, 4.0f/6.0f);
m_uvs[5] = Stuff::Vector2DOf<Stuff::Scalar>(0.0f, 5.0f/6.0f);
m_uvs[6] = Stuff::Vector2DOf<Stuff::Scalar>(0.0f, 1.0f);
break;
}
}
//------------------------------------------------------------------------------
//
bool
gosFX::Tube__Specification::CalculateUBias(bool adjust)
{
Check_Object(this);
//
//----------------------------------
// Calculate the worst case UV scale
//----------------------------------
//
int max_index = m_maxProfileCount-1;
Stuff::Scalar max_scale, min_scale;
Retry:
m_pUSize.ExpensiveComputeRange(&min_scale, &max_scale);
Stuff::Scalar lower = min_scale * max_index;
if (lower > 0.0f)
lower = 0.0f;
Stuff::Scalar upper = max_scale * max_index;
//
//------------------------------------
// Calculate the worst case UV offsets
//------------------------------------
//
Stuff::Scalar max_offset, min_offset;
m_pUOffset.ExpensiveComputeRange(&min_offset, &max_offset);
lower += min_offset;
upper += max_offset;
if (upper - lower >= 198.0f)
{
if (!adjust)
return false;
lower = max_offset - min_offset;
Stuff::Scalar scale = static_cast<Stuff::Scalar>(floor((198.0f-lower)/max_index));
m_pUSize.m_ageCurve.SetCurve(scale);
m_pUSize.m_seeded = false;
goto Retry;
}
lower += 99.0f;
if (lower < 0.0f)
{
m_UBias = static_cast<Stuff::Scalar>(floor(0.5f-lower));
return true;
}
upper -= 99.0f;
if (upper > 0.0f)
{
m_UBias = static_cast<Stuff::Scalar>(floor(0.5f-upper));
return true;
}
m_UBias = 0.0f;
return true;
}
//############################################################################
//############################ gosFX::Tube ###############################
//############################################################################
gosFX::Tube::ClassData*
gosFX::Tube::DefaultData = NULL;
//------------------------------------------------------------------------------
//
void
gosFX::Tube::InitializeClass()
{
Verify(!DefaultData);
Verify(gos_GetCurrentHeap() == Heap);
DefaultData =
new ClassData(
TubeClassID,
"gosFX::Tube",
Effect::DefaultData,
(Effect::Factory)&Make,
(Specification::Factory)&Specification::Make
);
Register_Object(DefaultData);
}
//------------------------------------------------------------------------------
//
void
gosFX::Tube::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//------------------------------------------------------------------------------
//
gosFX::Tube::Tube(
Specification *spec,
unsigned flags
):
Effect(DefaultData, spec, flags)
{
Check_Pointer(this);
Check_Object(spec);
Verify(gos_GetCurrentHeap() == Heap);
//
//----------------------------------
// Figure out how much space we need
//----------------------------------
//
m_profiles.SetLength(spec->m_maxProfileCount);
unsigned vertex_count = spec->m_vertices.GetLength();
Verify(vertex_count < 8);
unsigned index_count = (vertex_count - 1)*6;
unsigned size =
sizeof(Stuff::Point3D)
+ sizeof(Stuff::RGBAColor)
+ sizeof(Stuff::Vector2DOf<Stuff::Scalar>);
size *= vertex_count*spec->m_maxProfileCount;
size += sizeof(unsigned short)*(spec->m_maxProfileCount-1)*index_count;
//
//-----------------------
// Allocate the tube mesh
//-----------------------
//
gos_PushCurrentHeap(MidLevelRenderer::Heap);
m_mesh =
new MidLevelRenderer::MLRIndexedTriangleCloud(
spec->m_maxProfileCount*(vertex_count-1)*2
);
Register_Object(m_mesh);
gos_PopCurrentHeap();
//
//------------------------------------------------
// Set up the data pointers into the channel block
//------------------------------------------------
//
m_triangleCount = 0;
m_vertexCount = 0;
m_data.SetLength(size);
m_P_vertices = Cast_Pointer(Stuff::Point3D*, &m_data[0]);
size = spec->m_maxProfileCount*vertex_count*sizeof(Stuff::Point3D);
m_P_colors = Cast_Pointer(Stuff::RGBAColor*, &m_data[size]);
size += spec->m_maxProfileCount*vertex_count*sizeof(Stuff::RGBAColor);
m_P_uvs = Cast_Pointer(Stuff::Vector2DOf<Stuff::Scalar>*, &m_data[size]);
size += spec->m_maxProfileCount*vertex_count*sizeof(Stuff::Vector2DOf<Stuff::Scalar>);
unsigned short *mesh_indices = Cast_Pointer(unsigned short*, &m_data[size]);
m_mesh->SetData(
&m_triangleCount,
&m_vertexCount,
mesh_indices,
m_P_vertices,
m_P_colors,
m_P_uvs
);
BuildMesh(mesh_indices);
//
//-------------------------------
// Set up an empty profile cloud
//-------------------------------
//
m_activeProfileCount = 0;
m_headProfile = -1;
m_tailProfile = -1;
m_birthAccumulator = 0.0f;
}
//------------------------------------------------------------------------------
//
void
gosFX::Tube::BuildMesh(unsigned short *indices)
{
Check_Object(this);
Check_Pointer(indices);
//
//--------------------------------------
// Figure out the parameters of the mesh
//--------------------------------------
//
Specification *spec = GetSpecification();
Check_Object(spec);
unsigned vertex_count = spec->m_vertices.GetLength();
Verify(vertex_count < 8);
//
//-------------------------------------------------
// Crosses are built different from everything else
//-------------------------------------------------
//
if (spec->m_profileType != Specification::e_Cross)
{
for (unsigned short profile=0; profile<spec->m_maxProfileCount-1; ++profile)
{
unsigned short base = static_cast<short>(profile * vertex_count);
for (unsigned short panel=0; panel<vertex_count-1; ++panel)
{
if (spec->m_insideOut)
{
*indices++ = static_cast<short>(base+panel+1);
*indices++ = static_cast<short>(base+panel);
*indices++ = static_cast<short>(base+panel+vertex_count+1);
*indices++ = static_cast<short>(base+panel+vertex_count);
*indices++ = static_cast<short>(base+panel+vertex_count+1);
*indices++ = static_cast<short>(base+panel);
}
else
{
*indices++ = static_cast<short>(base+panel);
*indices++ = static_cast<short>(base+panel+1);
*indices++ = static_cast<short>(base+panel+vertex_count+1);
*indices++ = static_cast<short>(base+panel+vertex_count+1);
*indices++ = static_cast<short>(base+panel+vertex_count);
*indices++ = static_cast<short>(base+panel);
}
}
}
}
else
{
Verify(vertex_count==5);
for (unsigned short profile=0; profile<spec->m_maxProfileCount-1; ++profile)
{
unsigned short base = static_cast<short>(profile * vertex_count);
for (unsigned short panel=0; panel<4; ++panel)
{
if (spec->m_insideOut)
{
*indices++ = static_cast<short>(base+panel+1);
*indices++ = base;
*indices++ = static_cast<short>(base+panel+6);
*indices++ = static_cast<short>(base+5);
*indices++ = static_cast<short>(base+panel+6);
*indices++ = base;
}
else
{
*indices++ = base;
*indices++ = static_cast<short>(base+panel+1);
*indices++ = static_cast<short>(base+panel+6);
*indices++ = static_cast<short>(base+panel+6);
*indices++ = static_cast<short>(base+5);
*indices++ = base;
}
}
}
}
}
//------------------------------------------------------------------------------
//
gosFX::Tube::~Tube()
{
Unregister_Object(m_mesh);
delete m_mesh;
}
//------------------------------------------------------------------------------
//
gosFX::Tube*
gosFX::Tube::Make(
Specification *spec,
unsigned flags
)
{
Check_Object(spec);
gos_PushCurrentHeap(Heap);
Tube *tube = new gosFX::Tube(spec, flags);
gos_PopCurrentHeap();
return tube;
}
//------------------------------------------------------------------------------
//
void
gosFX::Tube::Start(ExecuteInfo *info)
{
Check_Object(this);
Check_Pointer(info);
//
//----------------------
// Let effect initialize
//----------------------
//
Effect::Start(info);
//
//--------------------------------------------------------------------------
// If the effect is off, we will create two profiles. If they effect is on,
// we just keep doing what we do
//--------------------------------------------------------------------------
//
m_birthAccumulator = 1.0f;
}
//------------------------------------------------------------------------------
//
bool gosFX::Tube::Execute(ExecuteInfo *info)
{
Check_Object(this);
Check_Object(info);
//
//----------------------------------------
// If we aren't supposed to execute, don't
//----------------------------------------
//
if (!IsExecuted())
return false;
//
//----------------------------------------------------------------------
// Update the head of the tube to the current location, then compute the
// inverse transformation to keep all particles in their place of origin
//----------------------------------------------------------------------
//
Stuff::LinearMatrix4D new_world_to_local;
Stuff::LinearMatrix4D local_to_world;
local_to_world.Multiply(m_localToParent, *info->m_parentToWorld);
new_world_to_local.Invert(local_to_world);
//
//--------------------------
// Figure out the birth rate
//--------------------------
//
Specification *spec = GetSpecification();
Check_Object(spec);
Stuff::Scalar dT =
static_cast<Stuff::Scalar>(info->m_time - m_lastRan);
Verify(dT >= 0.0f);
Stuff::Scalar prev_age = m_age;
m_age += dT * m_ageRate;
if (m_age >= 1.0f)
m_birthAccumulator = 0.0f;
else
{
Stuff::Scalar new_life =
spec->m_profilesPerSecond.ComputeValue(m_age, m_seed);
Min_Clamp(new_life, 0.0f);
m_birthAccumulator += dT * new_life;
//
//------------------------------------------------------------------
// If it is time for a new child and there is room, move the head of
// the tube and create the new profile, then clear out the integer
// part of the accumulator - stacking up would look stupid
//------------------------------------------------------------------
//
if (m_birthAccumulator >= 1.0f && m_activeProfileCount < spec->m_maxProfileCount)
{
if (!m_activeProfileCount)
{
m_headProfile = 1;
m_tailProfile = spec->m_maxProfileCount-1;
CreateNewProfile(0, local_to_world);
m_activeProfileCount = 2;
}
else
{
m_profiles[m_headProfile].m_profileToWorld = local_to_world;
if (++m_headProfile == spec->m_maxProfileCount)
m_headProfile = 0;
}
CreateNewProfile(m_headProfile, local_to_world);
m_birthAccumulator -= static_cast<Stuff::Scalar>(floor(m_birthAccumulator));
}
else
m_profiles[m_headProfile].m_profileToWorld = local_to_world;
}
//
//--------------------------------------------------------------------
// If we don't have any profiles, just execute the children and return
//--------------------------------------------------------------------
//
if (!m_activeProfileCount)
{
m_age = prev_age;
return Effect::Execute(info);
}
//
//----------------------------------
// Deal with all the active profiles
//----------------------------------
//
Stuff::ExtentBox box(Stuff::Point3D::Identity, Stuff::Point3D::Identity);
int i = m_headProfile;
int profile_count = 0;
Verify(i >= 0);
do
{
//
//----------------------------------------------------------------------
// Age and animate the profile. If the profile should die, it becomes
// the end of the tail
//----------------------------------------------------------------------
//
Profile *profile = GetProfile(i);
Check_Object(profile);
Verify (profile->m_age < 1.0f);
profile->m_age += dT*profile->m_ageRate;
Stuff::Sphere bounds;
if (!AnimateProfile(i, profile_count, new_world_to_local, info->m_time, &bounds))
{
m_tailProfile = i;
break;
}
//
//---------------------
// Deal with the bounds
//---------------------
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -