#include "gosFXHeaders.hpp" #include //==========================================================================// // File: gosFX_Beam.cpp // // Project: gosFX // // Contents: Base gosFX::Beam Component // //--------------------------------------------------------------------------// // Date Who Modification // // 09/28/98 JTR Created // // // //--------------------------------------------------------------------------// // Copyright (C) 1997-1998, Virtual World Entertainment, Inc. // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //==========================================================================// // //############################################################################ //######################## gosFX::Beam__Specification ############################# //############################################################################ //------------------------------------------------------------------------------ // gosFX::Beam__Specification::Beam__Specification( Stuff::MemoryStream *stream, int gfx_version ): Effect__Specification(BeamClassID, stream, gfx_version) { Check_Pointer(this); Check_Object(stream); // //------------------- // Load in the curves //------------------- // m_profilesPerMeter.Load(stream, gfx_version); m_minimumDeviation.Load(stream, gfx_version); m_maximumDeviation.Load(stream, gfx_version); m_pDisplacement.Load(stream, gfx_version); m_pScale.Load(stream, gfx_version); m_pRed.Load(stream, gfx_version); m_pGreen.Load(stream, gfx_version); m_pBlue.Load(stream, gfx_version); m_pAlpha.Load(stream, gfx_version); m_pUOffset.Load(stream, gfx_version); m_pVOffset.Load(stream, gfx_version); m_pUSize.Load(stream, gfx_version); m_pVSize.Load(stream, gfx_version); int type; *stream >> m_maxProfileCount >> type >> m_insideOut >> m_randomDirections; m_profileType = static_cast(type); BuildTemplate(); } //------------------------------------------------------------------------------ // gosFX::Beam__Specification::Beam__Specification(): Effect__Specification(BeamClassID) { m_maxProfileCount = 0; m_profileType = e_Ribbon; m_insideOut = false; m_randomDirections = false; Check_Pointer(this); } //------------------------------------------------------------------------------ // gosFX::Beam__Specification::~Beam__Specification() { Check_Object(this); } //------------------------------------------------------------------------------ // gosFX::Beam__Specification* gosFX::Beam__Specification::Make( Stuff::MemoryStream *stream, int gfx_version ) { Check_Object(stream); gos_PushCurrentHeap(Heap); Beam__Specification *spec = new gosFX::Beam__Specification(stream, gfx_version); gos_PopCurrentHeap(); return spec; } //------------------------------------------------------------------------------ // void gosFX::Beam__Specification::Save(Stuff::MemoryStream *stream) { Check_Object(this); Check_Object(stream); BaseClass::Save(stream); // //---------------- // Save our curves //---------------- // m_profilesPerMeter.Save(stream); m_minimumDeviation.Save(stream); m_maximumDeviation.Save(stream); m_pDisplacement.Save(stream); m_pScale.Save(stream); m_pRed.Save(stream); m_pGreen.Save(stream); m_pBlue.Save(stream); m_pAlpha.Save(stream); m_pUOffset.Save(stream); m_pVOffset.Save(stream); m_pUSize.Save(stream); m_pVSize.Save(stream); *stream << m_maxProfileCount << static_cast(m_profileType); *stream << m_insideOut; *stream << m_randomDirections; } //------------------------------------------------------------------------------ // void gosFX::Beam__Specification::BuildDefaults() { Check_Object(this); BaseClass::BuildDefaults(); m_profilesPerMeter.SetCurve(.004f); m_minimumDeviation.SetCurve(0.0f); m_maximumDeviation.SetCurve(0.0f); m_pDisplacement.m_ageCurve.SetCurve(0.0f); m_pDisplacement.m_seeded = false; m_pDisplacement.m_seedCurve.SetCurve(1.0f); m_pScale.m_ageCurve.SetCurve(1.0f); m_pScale.m_seeded = false; m_pScale.m_seedCurve.SetCurve(1.0f); m_pRed.m_ageCurve.SetCurve(1.0f); m_pRed.m_seeded = false; m_pRed.m_seedCurve.SetCurve(1.0f); m_pGreen.m_ageCurve.SetCurve(1.0f); m_pGreen.m_seeded = false; m_pGreen.m_seedCurve.SetCurve(1.0f); m_pBlue.m_ageCurve.SetCurve(1.0f); m_pBlue.m_seeded = false; m_pBlue.m_seedCurve.SetCurve(1.0f); m_pAlpha.m_ageCurve.SetCurve(1.0f); m_pAlpha.m_seeded = false; m_pAlpha.m_seedCurve.SetCurve(1.0f); m_pUOffset.SetCurve(0.0f); m_pVOffset.SetCurve(0.0f); m_pUSize.SetCurve(1.0f); m_pVSize.SetCurve(1.0f); m_maxProfileCount = 2; m_profileType = e_Triangle; m_insideOut = false; m_randomDirections = false; BuildTemplate(); } //------------------------------------------------------------------------------ // bool gosFX::Beam__Specification::IsDataValid(bool fix_data) { Check_Object(this); if(m_maxProfileCount<2) { if(fix_data) { m_maxProfileCount=2; PAUSE(("Warning: Value \"maxProfileCount\" in Effect \"%s\" Is Out of Range and has been Reset",(char *)m_name)); } else return false; } // //----------------------------------------- // Make sure we don't overwrite MLR buffers //----------------------------------------- // int profile_limit = MidLevelRenderer::Limits::Max_Number_Vertices_Per_Effect/m_vertices.GetLength(); if (m_maxProfileCount > profile_limit) { if (fix_data) { m_maxProfileCount = profile_limit; PAUSE(("Warning: Max Profile Count in Effect \"%s\" is too big and has been reset",(char *)m_name)); } else return false; } Stuff::Scalar min,max; m_pScale.ExpensiveComputeRange(&min,&max); if (min<5.0f*Stuff::SMALL) { if (fix_data) m_pScale.SetMinimum(10.0f*Stuff::SMALL); else return false; } Stuff::Scalar max_offset, min_offset; Stuff::Scalar max_scale, min_scale; m_pUSize.ExpensiveComputeRange(&min_scale, &max_scale); Stuff::Scalar lower = min_scale; if (lower > 0.0f) lower = 0.0f; Stuff::Scalar upper = max_scale; // //------------------------------------ // Calculate the worst case UV offsets //------------------------------------ // m_pVOffset.ExpensiveComputeRange(&min_offset, &max_offset); lower += min_offset; upper += max_offset; if (upper > 99.0f || lower < -99.0f) { if(fix_data) { m_pVOffset.SetCurve(0.0f); PAUSE(("Warning: Curve \"VOffset\" in Effect \"%s\" Is Out of Range and has been Reset",(char *)m_name)); } else return false; } m_pVSize.ExpensiveComputeRange(&min_scale, &max_scale); lower = min_scale; if (lower > 0.0f) lower = 0.0f; upper = max_scale; // //------------------------------------ // Calculate the worst case UV offsets //------------------------------------ // max_offset, min_offset; m_pUOffset.ExpensiveComputeRange(&min_offset, &max_offset); lower += min_offset; upper += max_offset; if (upper > 99.0f || lower < -99.0f) { if(fix_data) { m_pUOffset.SetCurve(0.0f); PAUSE(("Warning: Curve \"UOffset\" in Effect \"%s\" Is Out of Range and has been Reset",(char *)m_name)); } else return false; } return BaseClass::IsDataValid(fix_data); } //------------------------------------------------------------------------------ // void gosFX::Beam__Specification::Copy(Beam__Specification *spec) { Check_Object(this); Check_Object(spec); BaseClass::Copy(spec); // //---------------- // Copy the curves //---------------- // gos_PushCurrentHeap(Heap); m_profilesPerMeter = spec->m_profilesPerMeter; m_minimumDeviation = spec->m_minimumDeviation; m_maximumDeviation = spec->m_maximumDeviation; m_pDisplacement = spec->m_pDisplacement; m_pScale = spec->m_pScale; m_pRed = spec->m_pRed; m_pGreen = spec->m_pGreen; m_pBlue = spec->m_pBlue; m_pAlpha = spec->m_pAlpha; m_pUOffset = spec->m_pUOffset; m_pVOffset = spec->m_pVOffset; m_pUSize = spec->m_pUSize; m_pVSize = spec->m_pVSize; m_maxProfileCount = spec->m_maxProfileCount; m_profileType = spec->m_profileType; m_vertices = spec->m_vertices; m_uvs = spec->m_uvs; m_insideOut = spec->m_insideOut; m_randomDirections = spec->m_randomDirections; gos_PopCurrentHeap(); } //------------------------------------------------------------------------------ // void gosFX::Beam__Specification::BuildTemplate() { Check_Object(this); switch (m_profileType) { case e_Ribbon: case e_AlignedRibbon: m_vertices.SetLength(2); m_vertices[0] = Stuff::Vector3D(1.0f, 0.0f, 0.0f); m_vertices[1] = Stuff::Vector3D(-1.0f, 0.0f, 0.0f); m_uvs.SetLength(2); m_uvs[0] = Stuff::Vector2DOf(0.0f, 0.0f); m_uvs[1] = Stuff::Vector2DOf(0.0f, 1.0f); break; case e_VerticalRibbon: m_vertices.SetLength(2); m_vertices[0] = Stuff::Vector3D(0.0f, 0.0f, -1.0f); m_vertices[1] = Stuff::Vector3D(0.0f, 0.0f, 1.0f); m_uvs.SetLength(2); m_uvs[0] = Stuff::Vector2DOf(0.0f, 0.0f); m_uvs[1] = Stuff::Vector2DOf(0.0f, 1.0f); break; case e_Triangle: m_vertices.SetLength(4); m_vertices[0] = Stuff::Vector3D(0.0f, 0.0f, 1.0f); m_vertices[1] = Stuff::Vector3D(-0.8660254f, 0.0f, -0.5f); m_vertices[2] = Stuff::Vector3D(0.8660254f, 0.0f, -0.5f); m_vertices[3] = Stuff::Vector3D(0.0f, 0.0f, 1.0f); m_uvs.SetLength(4); m_uvs[0] = Stuff::Vector2DOf(0.0f, 0.0f); m_uvs[1] = Stuff::Vector2DOf(0.0f, 1.0f/3.0f); m_uvs[2] = Stuff::Vector2DOf(0.0f, 2.0f/3.0f); m_uvs[3] = Stuff::Vector2DOf(0.0f, 1.0f); break; case e_Square: m_vertices.SetLength(5); m_vertices[0] = Stuff::Vector3D(0.0f, 0.0f, 1.0f); m_vertices[1] = Stuff::Vector3D(-1.0f, 0.0f, 0.0f); m_vertices[2] = Stuff::Vector3D(0.0f, 0.0f, -1.0f); m_vertices[3] = Stuff::Vector3D(1.0f, 0.0f, 0.0f); m_vertices[4] = Stuff::Vector3D(0.0f, 0.0f, 1.0f); m_uvs.SetLength(5); m_uvs[0] = Stuff::Vector2DOf(0.0f, 0.0f); m_uvs[1] = Stuff::Vector2DOf(0.0f, 0.25f); m_uvs[2] = Stuff::Vector2DOf(0.0f, 0.5f); m_uvs[3] = Stuff::Vector2DOf(0.0f, 0.75f); m_uvs[4] = Stuff::Vector2DOf(0.0f, 1.0f); break; case e_Cross: m_vertices.SetLength(5); m_vertices[0] = Stuff::Vector3D(0.0f, 0.0f, 0.0f); m_vertices[1] = Stuff::Vector3D(0.0f, 0.0f, 1.0f); m_vertices[2] = Stuff::Vector3D(-1.0f, 0.0f, 0.0f); m_vertices[3] = Stuff::Vector3D(0.0f, 0.0f, -1.0f); m_vertices[4] = Stuff::Vector3D(1.0f, 0.0f, 0.0f); m_uvs.SetLength(5); m_uvs[0] = Stuff::Vector2DOf(0.0f, 0.0f); m_uvs[1] = Stuff::Vector2DOf(0.0f, 1.0f); m_uvs[2] = Stuff::Vector2DOf(0.0f, 1.0f); m_uvs[3] = Stuff::Vector2DOf(0.0f, 1.0f); m_uvs[4] = Stuff::Vector2DOf(0.0f, 1.0f); break; case e_Pentagon: m_vertices.SetLength(6); m_vertices[0] = Stuff::Vector3D(0.0f, 0.0f, 1.0f); m_vertices[1] = Stuff::Vector3D(-0.9510565f, 0.0f, 0.309017f); m_vertices[2] = Stuff::Vector3D(-0.58778525f, 0.0f, -0.8090167f); m_vertices[3] = Stuff::Vector3D(0.58778525f, 0.0f, -0.8090167f); m_vertices[4] = Stuff::Vector3D(0.9510565f, 0.0f, 0.309017f); m_vertices[5] = Stuff::Vector3D(0.0f, 0.0f, 1.0f); m_uvs.SetLength(6); m_uvs[0] = Stuff::Vector2DOf(0.0f, 0.0f); m_uvs[1] = Stuff::Vector2DOf(0.0f, 0.2f); m_uvs[2] = Stuff::Vector2DOf(0.0f, 0.4f); m_uvs[3] = Stuff::Vector2DOf(0.0f, 0.6f); m_uvs[4] = Stuff::Vector2DOf(0.0f, 0.8f); m_uvs[5] = Stuff::Vector2DOf(0.0f, 1.0f); break; case e_Hexagon: m_vertices.SetLength(7); m_vertices[0] = Stuff::Vector3D(0.0f, 0.0f, 1.0f); m_vertices[1] = Stuff::Vector3D(-0.8660254f, 0.0f, 0.5f); m_vertices[2] = Stuff::Vector3D(-0.8660254f, 0.0f, -0.5f); m_vertices[3] = Stuff::Vector3D(0.0f, 0.0f, -1.0f); m_vertices[4] = Stuff::Vector3D(0.8660254f, 0.0f, -0.5f); m_vertices[5] = Stuff::Vector3D(0.8660254f, 0.0f, 0.5f); m_vertices[6] = Stuff::Vector3D(0.0f, 0.0f, 1.0f); m_uvs.SetLength(7); m_uvs[0] = Stuff::Vector2DOf(0.0f, 0.0f); m_uvs[1] = Stuff::Vector2DOf(0.0f, 1.0f/6.0f); m_uvs[2] = Stuff::Vector2DOf(0.0f, 2.0f/6.0f); m_uvs[3] = Stuff::Vector2DOf(0.0f, 0.5f); m_uvs[4] = Stuff::Vector2DOf(0.0f, 4.0f/6.0f); m_uvs[5] = Stuff::Vector2DOf(0.0f, 5.0f/6.0f); m_uvs[6] = Stuff::Vector2DOf(0.0f, 1.0f); break; } } //############################################################################ //############################ gosFX::Beam ############################### //############################################################################ gosFX::Beam::ClassData* gosFX::Beam::DefaultData = NULL; //------------------------------------------------------------------------------ // void gosFX::Beam::InitializeClass() { Verify(!DefaultData); DefaultData = new ClassData( BeamClassID, "gosFX::Beam", BaseClass::DefaultData, (Effect::Factory)&Make, (Specification::Factory)&Specification::Make ); Check_Object(DefaultData); } //------------------------------------------------------------------------------ // void gosFX::Beam::TerminateClass() { Check_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //------------------------------------------------------------------------------ // gosFX::Beam::Beam( Specification *spec, unsigned flags ): Effect(DefaultData, spec, flags) { Check_Pointer(this); Check_Object(spec); // //---------------------------------- // 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); size *= vertex_count*spec->m_maxProfileCount; size += sizeof(unsigned short)*(spec->m_maxProfileCount-1)*index_count; // //----------------------- // Allocate the tube mesh //----------------------- // gos_PushCurrentHeap(MidLevelRenderer::EffectHeap); m_mesh = new MidLevelRenderer::MLRIndexedTriangleCloud( spec->m_maxProfileCount*(vertex_count-1)*2 ); Check_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*, &m_data[size]); size += spec->m_maxProfileCount*vertex_count*sizeof(Stuff::Vector2DOf); 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; } //------------------------------------------------------------------------------ // void gosFX::Beam::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; profilem_maxProfileCount-1; ++profile) { unsigned short base = static_cast(profile * vertex_count); for (unsigned short panel=0; panelm_insideOut) { *indices++ = static_cast(base+panel+1); *indices++ = static_cast(base+panel); *indices++ = static_cast(base+panel+vertex_count+1); *indices++ = static_cast(base+panel+vertex_count); *indices++ = static_cast(base+panel+vertex_count+1); *indices++ = static_cast(base+panel); } else { *indices++ = static_cast(base+panel); *indices++ = static_cast(base+panel+1); *indices++ = static_cast(base+panel+vertex_count+1); *indices++ = static_cast(base+panel+vertex_count+1); *indices++ = static_cast(base+panel+vertex_count); *indices++ = static_cast(base+panel); } } } } else { Verify(vertex_count==5); for (unsigned short profile=0; profilem_maxProfileCount-1; ++profile) { unsigned short base = static_cast(profile * vertex_count); for (unsigned short panel=0; panel<4; ++panel) { if (spec->m_insideOut) { *indices++ = static_cast(base+panel+1); *indices++ = base; *indices++ = static_cast(base+panel+6); *indices++ = static_cast(base+5); *indices++ = static_cast(base+panel+6); *indices++ = base; } else { *indices++ = base; *indices++ = static_cast(base+panel+1); *indices++ = static_cast(base+panel+6); *indices++ = static_cast(base+panel+6); *indices++ = static_cast(base+5); *indices++ = base; } } } } } //------------------------------------------------------------------------------ // gosFX::Beam::~Beam() { Check_Object(this); Check_Object(m_mesh); delete m_mesh; } //------------------------------------------------------------------------------ // gosFX::Beam* gosFX::Beam::Make( Specification *spec, unsigned flags ) { Check_Object(spec); gos_PushCurrentHeap(Heap); Beam *tube = new gosFX::Beam(spec, flags); gos_PopCurrentHeap(); return tube; } //------------------------------------------------------------------------------ // void gosFX::Beam::Start(Effect::ExecuteInfo *info) { Check_Object(this); Check_Pointer(info); // //---------------------- // Let effect initialize //---------------------- // BaseClass::Start(info); // //-------------------------------------------------------------------------- // If the effect is off, we will create two profiles. If they effect is on, // we just keep doing what we do //-------------------------------------------------------------------------- // Specification *spec = GetSpecification(); Check_Object(spec); for (int i=0; im_maxProfileCount; ++i) CreateNewProfile(i); } //------------------------------------------------------------------------------ // bool gosFX::Beam::Execute(ExecuteInfo *base_info) { Check_Object(this); Check_Object(base_info); GFX_LOGIC("Execute::Beam"); // //---------------------------------------- // If we aren't supposed to execute, don't //---------------------------------------- // if (!IsExecuted()) return false; ExecuteInfo *info = Cast_Pointer(ExecuteInfo*, base_info); Check_Object(info); // //---------------------------------------------------------------------- // 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 local_to_world; local_to_world.Multiply(m_localToParent, *info->m_parentToWorld); Stuff::LinearMatrix4D world_to_new_local; world_to_new_local.Invert(local_to_world); // //-------------------------- // Figure out the birth rate //-------------------------- // Specification *spec = GetSpecification(); Check_Object(spec); Verify(spec->GetClassID() == BeamClassID); Stuff::Scalar dT = static_cast(info->m_time - m_lastRan); Verify(dT >= 0.0f); Stuff::Scalar prev_age = m_age; m_age += dT * m_ageRate; Max_Clamp(m_age, 1.0f); // //----------------------------------------------------- // Figure out how many profiles we will need this frame //----------------------------------------------------- // Check_Object(info->m_endPoint); Stuff::Vector3D core( info->m_endPoint->x - local_to_world(3,0), info->m_endPoint->y - local_to_world(3,1), info->m_endPoint->z - local_to_world(3,2) ); local_to_world.AlignLocalAxisToWorldVector(core, Stuff::Y_Axis, Stuff::Z_Axis, Stuff::X_Axis); m_activeProfileCount = static_cast(ceil(core.GetLength() * spec->m_profilesPerMeter.ComputeValue(m_age, m_seed))); Clamp(m_activeProfileCount, 2, spec->m_maxProfileCount); // //---------------------------------- // Deal with all the active profiles //---------------------------------- // Stuff::ExtentBox box(Stuff::Point3D::Identity, Stuff::Point3D::Identity); for (int i=0; im_profileToWorld = local_to_world; Stuff::Scalar progress = static_cast(i)/(m_activeProfileCount-1); profile->m_profileToWorld(3,0) = Stuff::Lerp(local_to_world(3,0), info->m_endPoint->x, progress); profile->m_profileToWorld(3,1) = Stuff::Lerp(local_to_world(3,1), info->m_endPoint->y, progress); profile->m_profileToWorld(3,2) = Stuff::Lerp(local_to_world(3,2), info->m_endPoint->z, progress); Stuff::Sphere bounds; AnimateProfile(i, world_to_new_local, info->m_time, &bounds); // //--------------------- // Deal with the bounds //--------------------- // if (!i) { box.maxX = bounds.center.x + bounds.radius; box.minX = bounds.center.x - bounds.radius; box.maxY = bounds.center.y + bounds.radius; box.minY = bounds.center.y - bounds.radius; box.maxZ = bounds.center.z + bounds.radius; box.minZ = bounds.center.z - bounds.radius; } else { Stuff::ExtentBox local_box; local_box.maxX = bounds.center.x + bounds.radius; local_box.minX = bounds.center.x - bounds.radius; local_box.maxY = bounds.center.y + bounds.radius; local_box.minY = bounds.center.y - bounds.radius; local_box.maxZ = bounds.center.z + bounds.radius; local_box.minZ = bounds.center.z - bounds.radius; box.Union(box, local_box); } } // //----------------------------------------------- // Put the age back and run the base effect stuff //----------------------------------------------- // m_age = prev_age; if (!BaseClass::Execute(info)) return false; // //-------------------------------------------- // Now, build a info->m_bounds around this box //-------------------------------------------- // Verify(box.maxX >= box.minX); Verify(box.maxY >= box.minY); Verify(box.maxZ >= box.minZ); Stuff::OBB local_bounds = Stuff::OBB::Identity; local_bounds.axisExtents.x = 0.5f * (box.maxX - box.minX); local_bounds.axisExtents.y = 0.5f * (box.maxY - box.minY); local_bounds.axisExtents.z = 0.5f * (box.maxZ - box.minZ); local_bounds.localToParent(3,0) = box.minX + local_bounds.axisExtents.x; local_bounds.localToParent(3,1) = box.minY + local_bounds.axisExtents.y; local_bounds.localToParent(3,2) = box.minZ + local_bounds.axisExtents.z; local_bounds.sphereRadius = local_bounds.axisExtents.GetLength() + Stuff::SMALL; Stuff::OBB parent_bounds; parent_bounds.Multiply(local_bounds, m_localToParent); info->m_bounds->Union(*info->m_bounds, parent_bounds); return true; } //------------------------------------------------------------------------------ // void gosFX::Beam::Kill() { Check_Object(this); // //------------------------------------------------------------- // Destroy all the profiles and set up an empty profile cloud //------------------------------------------------------------- // m_activeProfileCount = 0; // //---------------------------------------- // Now let the base effect handle stopping //---------------------------------------- // BaseClass::Kill(); } //------------------------------------------------------------------------------ // void gosFX::Beam::CreateNewProfile(unsigned index) { Check_Object(this); // //---------------------------------------------------- // Figure out the age and age rate of the new profile //---------------------------------------------------- // Specification *spec = GetSpecification(); Check_Object(spec); Profile *profile = GetProfile(index); Check_Object(profile); Stuff::Scalar min_seed = spec->m_minimumChildSeed.ComputeValue(m_age, m_seed); Stuff::Scalar seed_range = spec->m_maximumChildSeed.ComputeValue(m_age, m_seed) - min_seed; Stuff::Scalar seed = Stuff::Random::GetFraction()*seed_range + min_seed; Clamp(seed, 0.0f, 1.0f); profile->m_seed = seed; // //------------------------------------------------------------------ // Establish the base position and figure out the direction of drift //------------------------------------------------------------------ // ComputeDirection(index); } //------------------------------------------------------------------------------ // void gosFX::Beam::ComputeDirection(unsigned index) { Specification *spec = GetSpecification(); Check_Object(spec); Profile *profile = GetProfile(index); Check_Object(profile); Stuff::Scalar seed = profile->m_seed; Stuff::Scalar pitch_min = spec->m_minimumDeviation.ComputeValue(m_age, seed); Stuff::Scalar pitch_range = spec->m_maximumDeviation.ComputeValue(m_age, seed) - pitch_min; if (pitch_range < 0.0f) pitch_range = 0.0f; Stuff::Radian angle = pitch_min + Stuff::Random::GetFraction() * pitch_range; Stuff::SinCosPair xy(angle); profile->m_direction.x = (Stuff::Random::GetFraction() >= 0.5f) ? xy.sine : -xy.sine; profile->m_direction.y = 0.0f; profile->m_direction.z = xy.cosine; Check_Object(&profile->m_direction); } //------------------------------------------------------------------------------ // void gosFX::Beam::AnimateProfile( unsigned profile_index, const Stuff::LinearMatrix4D &world_to_new_local, Stuff::Time till, Stuff::Sphere *bounds ) { Check_Object(this); // //---------------------------------------------------- // If the profile gets too old, don't do anything else //---------------------------------------------------- // Profile *profile = GetProfile(profile_index); Check_Object(profile); // //-------------------------------------------------------------------- // Figure out the scale and displacement of the profile in world space //-------------------------------------------------------------------- // Set_Statistic(Beam_Count, Beam_Count+1); Stuff::Scalar seed = profile->m_seed; Specification *spec = GetSpecification(); Check_Object(spec); Stuff::Scalar age = m_age; Stuff::Scalar scale = spec->m_pScale.ComputeValue(age, seed); Verify(scale > 0.0f); Stuff::Scalar disp = spec->m_pDisplacement.ComputeValue(age, seed); Stuff::Point3D offset; if (spec->m_randomDirections) ComputeDirection(profile_index); offset.Multiply(profile->m_direction, disp); // //------------------------------------------------- // Now build the template to new local space matrix //------------------------------------------------- // Stuff::AffineMatrix4D template_to_profile(true); template_to_profile(0,0) = scale; template_to_profile(1,1) = scale; template_to_profile(2,2) = scale; template_to_profile.BuildTranslation(offset); Stuff::AffineMatrix4D template_to_world; template_to_world.Multiply(template_to_profile, profile->m_profileToWorld); Stuff::AffineMatrix4D template_to_new_local; template_to_new_local.Multiply(template_to_world, world_to_new_local); bounds->center = template_to_new_local; bounds->radius = scale; // //------------------------------------------------------------------------ // Now we just multiply the template through to the vertices unless we are // doing the aligned ribbon //------------------------------------------------------------------------ // unsigned i; unsigned vertex_count = spec->m_vertices.GetLength(); Verify(vertex_count < 8); unsigned vertex_index = profile_index * vertex_count; if (spec->m_profileType != Specification::e_AlignedRibbon) { Check_Pointer(m_P_vertices); for (i=0; im_vertices[i], template_to_new_local ); } } // //------------------------------ // Figure out the UV adjustments //------------------------------ // Check_Pointer(m_P_uvs); Stuff::Scalar u = spec->m_pUOffset.ComputeValue(age, seed); Stuff::Scalar v = spec->m_pVOffset.ComputeValue(age, seed); Stuff::Scalar u2 = spec->m_pUSize.ComputeValue(age, seed); Stuff::Scalar v2 = spec->m_pVSize.ComputeValue(age, seed); u += u2*profile_index; for (i=0; im_uvs[i].y*v2 + v; } // //--------------------------- // Lastly, animate the colors //--------------------------- // Check_Pointer(m_P_colors); Stuff::RGBAColor color; color.red = spec->m_pRed.ComputeValue(age, seed); color.green = spec->m_pGreen.ComputeValue(age, seed); color.blue = spec->m_pBlue.ComputeValue(age, seed); color.alpha = spec->m_pAlpha.ComputeValue(age, seed); for (i=0; i1) { MidLevelRenderer::DrawEffectInformation dInfo; dInfo.effect = m_mesh; Specification *spec = GetSpecification(); Check_Object(spec); dInfo.state.Combine(info->m_state, spec->m_state); dInfo.clippingFlags = info->m_clippingFlags; Stuff::LinearMatrix4D local_to_world; local_to_world.Multiply(m_localToParent, *info->m_parentToWorld); dInfo.effectToWorld = &local_to_world; unsigned vertex_count = spec->m_vertices.GetLength(); m_vertexCount = m_activeProfileCount * vertex_count; m_triangleCount = 2 * (m_activeProfileCount-1) * (vertex_count-1); // //------------------------------------------------------------------- // If we are doing the aligned ribbon, we will have to orient each of // the profiles and then compute its vertex positions accordingly //------------------------------------------------------------------- // if (spec->m_profileType == Specification::e_AlignedRibbon) { int vertex = 0; unsigned vertex_count = spec->m_vertices.GetLength(); Verify(vertex_count < 8); Stuff::Point3D camera_in_world(info->m_clipper->GetCameraToWorldMatrix()); Stuff::LinearMatrix4D world_to_local; world_to_local.Invert(local_to_world); // //---------------------------------------------------------------- // go thru all the profiles and figure out where they are in local // space //---------------------------------------------------------------- // for (int i=0; im_profileToWorld); // //--------------------------------------------------------- // Figure out the scale and displacement of the template in // profile space //--------------------------------------------------------- // Stuff::Scalar age = m_age; Stuff::Scalar seed = profile->m_seed; Stuff::Scalar scale = spec->m_pScale.ComputeValue(age, seed); Stuff::Scalar disp = spec->m_pDisplacement.ComputeValue(age, seed); Stuff::Point3D offset_in_profile; offset_in_profile.Multiply(profile->m_direction, disp); // //---------------------------------------------------------- // Figure out the direction that we want the profile to face // and build a rotation vector that does it //---------------------------------------------------------- // Stuff::Vector3D direction; direction.Subtract(camera_in_profile, offset_in_profile); Stuff::LinearMatrix4D template_rotation(true); template_rotation.AlignLocalAxisToWorldVector( direction, Stuff::Z_Axis, Stuff::Y_Axis, -1 ); // //------------------------------------------------- // Now build the template to new local space matrix //------------------------------------------------- // Stuff::AffineMatrix4D template_to_profile; template_to_profile(0,0) = scale*template_rotation(0,0); template_to_profile(0,1) = scale*template_rotation(0,1); template_to_profile(0,2) = scale*template_rotation(0,2); template_to_profile(1,0) = scale*template_rotation(1,0); template_to_profile(1,1) = scale*template_rotation(1,1); template_to_profile(1,2) = scale*template_rotation(1,2); template_to_profile(2,0) = scale*template_rotation(2,0); template_to_profile(2,1) = scale*template_rotation(2,1); template_to_profile(2,2) = scale*template_rotation(2,2); template_to_profile.BuildTranslation(offset_in_profile); Stuff::AffineMatrix4D template_to_world; template_to_world.Multiply(template_to_profile, profile->m_profileToWorld); Stuff::AffineMatrix4D template_to_local; template_to_local.Multiply(template_to_world, world_to_local); // //------------------------------------ // Multiply the points thru the matrix //------------------------------------ // for (int v=0; vm_vertices[v], template_to_local ); } } } // //-------------------- // Now draw the effect //-------------------- // info->m_clipper->DrawEffect(&dInfo); } BaseClass::Draw(info); } //------------------------------------------------------------------------------ // void gosFX::Beam::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); }