#include "gosFXHeaders.hpp" #include //==========================================================================// // File: gosFX_PointCloud.cpp // // Project: gosFX // // Contents: Base gosFX::PointCloud 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::PointCloud__Specification ############################# //############################################################################ //------------------------------------------------------------------------------ // gosFX::PointCloud__Specification::PointCloud__Specification( Stuff::RegisteredClass::ClassID class_id, Stuff::MemoryStream *stream, int gfx_version ): ParticleCloud__Specification(class_id, stream, gfx_version) { Check_Pointer(this); Verify(m_class == PointCloudClassID); m_totalParticleSize = gosFX::PointCloud::ParticleSize; m_particleClassSize = sizeof(gosFX::PointCloud::Particle); } //------------------------------------------------------------------------------ // gosFX::PointCloud__Specification::PointCloud__Specification( Stuff::RegisteredClass::ClassID class_id ): ParticleCloud__Specification(class_id) { Check_Pointer(this); m_totalParticleSize = gosFX::PointCloud::ParticleSize; m_particleClassSize = sizeof(gosFX::PointCloud::Particle); } //------------------------------------------------------------------------------ // gosFX::PointCloud__Specification::~PointCloud__Specification() { Check_Object(this); } //------------------------------------------------------------------------------ // gosFX::PointCloud__Specification* gosFX::PointCloud__Specification::Make( Stuff::MemoryStream *stream, int gfx_version ) { Check_Object(stream); gos_PushCurrentHeap(Heap); PointCloud__Specification *spec = new gosFX::PointCloud__Specification(PointCloudClassID, stream, gfx_version); gos_PopCurrentHeap(); return spec; } //------------------------------------------------------------------------------ // bool gosFX::PointCloud__Specification::IsDataValid(bool fix_data) { Check_Object(this); // //----------------------------------------- // Make sure we don't overwrite MLR buffers //----------------------------------------- // int particle_limit = MidLevelRenderer::Limits::Max_Number_Vertices_Per_Effect; if (m_maxParticleCount > particle_limit) { if (fix_data) { m_maxParticleCount = particle_limit; PAUSE(("Warning: Max Particle Count in Effect \"%s\" is too big and has been reset",(char *)m_name)); } else return false; } return BaseClass::IsDataValid(fix_data); } //############################################################################ //############################## gosFX::PointCloud ################################ //############################################################################ gosFX::PointCloud::ClassData* gosFX::PointCloud::DefaultData = NULL; //------------------------------------------------------------------------------ // void gosFX::PointCloud::InitializeClass() { Verify(!DefaultData); DefaultData = new ClassData( PointCloudClassID, "gosFX::PointCloud", BaseClass::DefaultData, (Effect::Factory)&Make, (Specification::Factory)&Specification::Make ); Check_Object(DefaultData); } //------------------------------------------------------------------------------ // void gosFX::PointCloud::TerminateClass() { Check_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //------------------------------------------------------------------------------ // gosFX::PointCloud::PointCloud( ClassData *class_data, Specification *spec, unsigned flags ): ParticleCloud(class_data, spec, flags) { Check_Object(spec); gos_PushCurrentHeap(MidLevelRenderer::EffectHeap); m_cloudImplementation = new MidLevelRenderer::MLRPointCloud(spec->m_maxParticleCount); Check_Object(m_cloudImplementation); gos_PopCurrentHeap(); unsigned index = spec->m_maxParticleCount*sizeof(Particle); m_P_localTranslation = Cast_Pointer(Stuff::Point3D*, &m_data[index]); index += spec->m_maxParticleCount*sizeof(Stuff::Point3D); m_P_color = Cast_Pointer(Stuff::RGBAColor*, &m_data[index]); m_cloudImplementation->SetData( Cast_Pointer(const int *, &m_activeParticleCount), m_P_localTranslation, m_P_color ); } //------------------------------------------------------------------------------ // gosFX::PointCloud::~PointCloud() { Check_Object(this); Check_Object(m_cloudImplementation); delete m_cloudImplementation; } //------------------------------------------------------------------------------ // gosFX::PointCloud* gosFX::PointCloud::Make( Specification *spec, unsigned flags ) { Check_Object(spec); gos_PushCurrentHeap(Heap); PointCloud *cloud = new gosFX::PointCloud(DefaultData, spec, flags); gos_PopCurrentHeap(); return cloud; } //------------------------------------------------------------------------------ // bool gosFX::PointCloud::Execute(ExecuteInfo *info) { Check_Object(this); Check_Object(info); GFX_LOGIC("Execute::PointCloud"); // //---------------------------------------- // If we aren't supposed to execute, don't //---------------------------------------- // if (!IsExecuted()) return false; // //------------------------------------------------------------------ // Animate the particles. If it is time for us to die, return false //------------------------------------------------------------------ // if (!BaseClass::Execute(info)) return false; // //----------------------------------------------------------------------- // If there are active particles to animate, get the current center point // of the bounds //----------------------------------------------------------------------- // if (m_activeParticleCount > 0) { GFX_LOGIC("Execute::ComputeBounds::PointCloud"); Stuff::ExtentBox box(Stuff::Point3D::Identity, Stuff::Point3D::Identity); Stuff::Point3D *vertex = &m_P_localTranslation[0]; unsigned i=0; // //------------------------------------------------------------------- // If there is no bounds yet, we need to create our extent box around // the first legal point we find //------------------------------------------------------------------- // while (im_age < 1.0f) { Check_Object(vertex); box.maxX = vertex->x; box.minX = vertex->x; box.maxY = vertex->y; box.minY = vertex->y; box.maxZ = vertex->z; box.minZ = vertex->z; ++vertex; ++i; break; } ++vertex; ++i; } // //----------------------------- // Look for the other particles //----------------------------- // while (im_age < 1.0f) { Check_Object(vertex); if (vertex->x > box.maxX) box.maxX = vertex->x; else if (vertex->x < box.minX) box.minX = vertex->x; if (vertex->y > box.maxY) box.maxY = vertex->y; else if (vertex->y < box.minY) box.minY = vertex->y; if (vertex->z > box.maxZ) box.maxZ = vertex->z; else if (vertex->z < box.minZ) box.minZ = vertex->z; } ++vertex; ++i; } // //------------------------------------ // 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); } // //---------------------------------------------- // Tell our caller that we get to keep executing //---------------------------------------------- // return true; } //------------------------------------------------------------------------------ // void gosFX::PointCloud::CreateNewParticle( unsigned index, Stuff::Point3D *translation ) { Check_Object(this); Check_Pointer(translation); // //----------------------------------------------------------------------- // Let our parent do creation, then turn on the particle in the cloud and // set its position //----------------------------------------------------------------------- // BaseClass::CreateNewParticle(index, translation); m_cloudImplementation->TurnOn(index); Verify(m_cloudImplementation->IsOn(index)); m_P_localTranslation[index] = *translation; } //------------------------------------------------------------------------------ // bool gosFX::PointCloud::AnimateParticle( unsigned index, const Stuff::LinearMatrix4D *world_to_new_local, Stuff::Time till ) { Check_Object(this); PARTICLE_LOGIC("Point"); // //----------------------------------------------------------------------- // If this cloud is unparented, we need to transform the point from local // space into world space and set the internal position/velocity pointers // to these temporary values //----------------------------------------------------------------------- // Particle *particle = GetParticle(index); Check_Object(particle); Stuff::Scalar age = particle->m_age; if (age >= 1.0f) return false; Set_Statistic(Point_Count, Point_Count+1); Stuff::Vector3D *velocity = &particle->m_localLinearVelocity; Stuff::Point3D *translation = &m_P_localTranslation[index]; int sim_mode = GetSimulationMode(); if (sim_mode == DynamicWorldSpaceSimulationMode) { Check_Object(translation); Check_Object(velocity); particle->m_worldLinearVelocity.Multiply(*velocity, m_localToWorld); particle->m_worldTranslation.Multiply(*translation, m_localToWorld); translation = &particle->m_worldTranslation; velocity = &particle->m_worldLinearVelocity; } Check_Object(translation); Check_Object(velocity); // //------------------------------------------------------------------ // First, calculate the drag on the particle. Drag can never assist // velocity //------------------------------------------------------------------ // Stuff::Scalar seed = particle->m_seed; Specification *spec = GetSpecification(); Check_Object(spec); Stuff::Vector3D ether; ether.x = spec->m_pEtherVelocityX.ComputeValue(age, seed); ether.y = spec->m_pEtherVelocityY.ComputeValue(age, seed); ether.z = spec->m_pEtherVelocityZ.ComputeValue(age, seed); Stuff::Vector3D accel(Stuff::Vector3D::Identity); // //------------------------------------------------------------------- // Deal with pseudo-world simulation. In this mode, we interpret the // forces as if they are already in worldspace, and we transform them // back to local space //------------------------------------------------------------------- // Stuff::Scalar drag = -spec->m_pDrag.ComputeValue(age, seed); Max_Clamp(drag, 0.0f); if (sim_mode == StaticWorldSpaceSimulationMode) { Stuff::LinearMatrix4D world_to_effect; world_to_effect.Invert(m_localToWorld); Stuff::Vector3D local_ether; local_ether.MultiplyByInverse(ether, world_to_effect); Stuff::Vector3D rel_vel; rel_vel.Subtract(*velocity, local_ether); accel.Multiply(rel_vel, drag); // //----------------------------------------- // Now, add in acceleration of the particle //----------------------------------------- // Stuff::Vector3D world_accel; world_accel.x = spec->m_pAccelerationX.ComputeValue(age, seed); world_accel.y = spec->m_pAccelerationY.ComputeValue(age, seed); world_accel.z = spec->m_pAccelerationZ.ComputeValue(age, seed); Stuff::Vector3D local_accel; local_accel.Multiply(world_accel, world_to_effect); accel += local_accel; } // //---------------------------------------------------------------------- // Otherwise, just add the forces in the same space the particles are in //---------------------------------------------------------------------- // else { Stuff::Vector3D rel_vel; rel_vel.Subtract(*velocity, ether); accel.Multiply(rel_vel, drag); // //----------------------------------------- // Now, add in acceleration of the particle //----------------------------------------- // accel.x += spec->m_pAccelerationX.ComputeValue(age, seed); accel.y += spec->m_pAccelerationY.ComputeValue(age, seed); accel.z += spec->m_pAccelerationZ.ComputeValue(age, seed); } // //------------------------------------------------- // Compute the particle's new velocity and position //------------------------------------------------- // Stuff::Scalar time_slice = static_cast(till - m_lastRan); velocity->AddScaled(*velocity, accel, time_slice); translation->AddScaled(*translation, *velocity, time_slice); // //--------------------------------------------------------------------- // If we are unparented, we need to transform the velocity and position // data back into the NEW local space //--------------------------------------------------------------------- // if (sim_mode == DynamicWorldSpaceSimulationMode) { Check_Object(world_to_new_local); particle->m_localLinearVelocity.Multiply( particle->m_worldLinearVelocity, *world_to_new_local ); m_P_localTranslation[index].Multiply( particle->m_worldTranslation, *world_to_new_local ); } return true; } //------------------------------------------------------------------------------ // void gosFX::PointCloud::DestroyParticle(unsigned index) { Check_Object(this); m_cloudImplementation->TurnOff(index); Verify(!m_cloudImplementation->IsOn(index)); BaseClass::DestroyParticle(index); } //------------------------------------------------------------------------------ // void gosFX::PointCloud::Draw(DrawInfo *info) { Check_Object(this); Check_Object(info); GFX_RENDER("PointCloud"); // //----------------------------------------------------------------- // If there are particles to draw, first update the particle colors //----------------------------------------------------------------- // if (m_activeParticleCount) { Specification *spec = GetSpecification(); Check_Object(spec); Check_Pointer(m_P_color); for (unsigned i=0; im_age; if (age < 1.0f) { Stuff::Scalar seed = particle->m_seed; m_P_color[i].red = spec->m_pRed.ComputeValue(age, seed); m_P_color[i].green = spec->m_pGreen.ComputeValue(age, seed); m_P_color[i].blue = spec->m_pBlue.ComputeValue(age, seed); m_P_color[i].alpha = spec->m_pAlpha.ComputeValue(age, seed); } } // //--------------------- // Now actually draw it //--------------------- // MidLevelRenderer::DrawEffectInformation dInfo; dInfo.effect = m_cloudImplementation; 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; info->m_clipper->DrawEffect(&dInfo); } BaseClass::Draw(info); } //------------------------------------------------------------------------------ // void gosFX::PointCloud::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); }