src/thirdparty/particles/ParticleDLL/ParticleState.cpp

Go to the documentation of this file.
00001 // ParticleState.cpp
00002 //
00003 // Copyright 1998-2005 by David K. McAllister.
00004 //
00005 // This file implements the under-the-hood stuff that is not part of an API call.
00006 
00007 // To optimize action lists, at execute time check whether the first action can be combined with
00008 // the next action. If so, combine them. Then try again. When the current one can't be combined
00009 // with the next one anymore, execute it.
00010 
00011 // Doing this at run time instead of compile time should make it easier to store the state of
00012 // compound actions.
00013 
00014 #include "ParticleState.h"
00015 #include "papi.h"
00016 
00017 #include <iostream>
00018 #include <typeinfo>
00019 
00020 // This is global just as a cheezy way to change dt for all actions easily.
00021 float PActionBase::dt;
00022 
00023 std::vector<ParticleGroup> ParticleState::PGroups;
00024 std::vector<ActionList> ParticleState::ALists;
00025 
00026 // This is the global state. It is used for single-threaded apps.
00027 // Multithreaded apps should get a different ParticleState per thread from a hash table.
00028 ParticleState __ps;
00029 
00030 const pVec P010(0.0f, 1.0f, 0.0f);
00031 const pVec P000(0.0f, 0.0f, 0.0f);
00032 const pVec P111(1.0f, 1.0f, 1.0f);
00033 
00034 ParticleState::ParticleState() : Up(new PDPoint(P010)), Vel(new PDPoint(P000)), RotVel(new PDPoint(P000)),
00035         VertexB(new PDPoint(P000)), Size(new PDPoint(P111)), Color(new PDPoint(P111)), Alpha(new PDPoint(P111))
00036 {
00037     in_call_list = false;
00038     in_new_list = false;
00039     vertexB_tracks = true;
00040 
00041     dt = 1.0f;
00042 
00043     pgroup_id = -1;
00044     alist_id = -1;
00045     tid = 0; // This must be filled in if we're multi-threaded.
00046     ErrorCode = PERR_NO_ERROR;
00047 
00048     Age = 0.0f;
00049     AgeSigma = 0.0f;
00050     Mass = 1.0f;
00051 }
00052 
00053 ParticleState::~ParticleState()
00054 {
00055     delete Up;
00056     delete Vel;
00057     delete RotVel;
00058     delete VertexB;
00059     delete Size;
00060     delete Color;
00061     delete Alpha;
00062 }
00063 
00064 void ParticleState::SetError(const int err, const std::string &Str)
00065 {
00066     std::cerr << Str << std::endl;
00067 
00068     if(ErrorCode == PERR_NO_ERROR) // Keep the first error.
00069         ErrorCode = err;
00070 
00071     abort();
00072 }
00073 
00074 ParticleGroup &ParticleState::GetPGroup(int p_group_num)
00075 {
00076     if(p_group_num < 0) {
00077         std::cerr << "ERROR: Negative particle group number\n";
00078         abort(); // IERROR
00079     }
00080 
00081     if(p_group_num >= (int)PGroups.size()) {
00082         std::cerr << "ERROR: Bad particle group number\n";
00083         abort(); // IERROR
00084     }
00085 
00086     return PGroups[p_group_num];
00087 }
00088 
00089 ActionList &ParticleState::GetAList(int a_list_num)
00090 {
00091     if(a_list_num < 0) {
00092         std::cerr << "ERROR: Negative action list number\n";
00093         abort(); // IERROR
00094     }
00095 
00096     if(a_list_num >= (int)ALists.size()) {
00097         std::cerr << "ERROR: Bad action list number\n";
00098         abort(); // IERROR
00099     }
00100 
00101     return ALists[a_list_num];
00102 }
00103 
00104 // Return an index into the list of particle groups where
00105 // p_group_count groups can be added.
00106 int ParticleState::GeneratePGroups(int pgroups_requested)
00107 {
00108     int old_size = (int)PGroups.size();
00109     PGroups.resize(old_size + pgroups_requested);
00110 
00111     return old_size;
00112 }
00113 
00114 // Return an index into the list of action lists where
00115 // alists_requested lists can be added.
00116 int ParticleState::GenerateALists(int alists_requested)
00117 {
00118     int old_size = (int)ALists.size();
00119     ALists.resize(old_size + alists_requested);
00120 
00121     return old_size;
00122 }
00123 
00124 // Action API entry points call this to either store the action in a list or execute and delete it.
00125 void ParticleState::SendAction(PActionBase *S)
00126 {
00127     if(in_new_list) {
00128         // Add action S to the end of the current action list.
00129         ActionList &AList = GetAList(alist_id);
00130         AList.push_back(S);
00131     } else {
00132         // Immediate mode. Execute it.
00133         S->dt = dt; // This is a hack to provide local access to dt.
00134         ParticleGroup &pg = GetPGroup(pgroup_id);
00135         S->Execute(pg, pg.begin(), pg.end());
00136         delete S;
00137     }
00138 }
00139 
00140 // Execute an action list
00141 void ParticleState::ExecuteActionList(ActionList &AList)
00142 {
00143     ParticleGroup &pg = GetPGroup(pgroup_id);
00144     in_call_list = true;
00145 
00146     ActionList::iterator it = AList.begin();
00147     while(it != AList.end()) {
00148         // Make an action segment
00149         ActionList::iterator abeg = it;
00150         ActionList::iterator aend = it+1;
00151 
00152         // If the first one is connectable, try to connect some more.
00153         if(!(*abeg)->GetKillsParticles() && !(*abeg)->GetDoNotSegment())
00154             while(aend != AList.end() && !(*aend)->GetKillsParticles() && !(*aend)->GetDoNotSegment())
00155                 aend++;
00156 
00157         // Found a sub-list that can be done together. Now do them.
00158         ParticleList::iterator pbeg = pg.begin();
00159         ParticleList::iterator pend = min(pbeg + PWorkingSetSize, pg.end());
00160         bool one_pass = false;
00161         if(aend - abeg == 1) {
00162             pend = pg.end(); // If a single action, do the whole thing in one whack.
00163             one_pass = true;
00164         }
00165 
00166         ActionList::iterator ait = abeg;
00167         do {
00168             // For each chunk of particles, do all the actions in this sub-list
00169             ait = abeg;
00170             while(ait < aend) {
00171                 (*ait)->dt = dt; // This is a hack to provide local access to dt.
00172                 (*ait)->Execute(pg, pbeg, pend);
00173 
00174                 // This is a hack to handle our compound object experiment.
00175                 if(typeid(ait) == typeid(PAFountain))
00176                     ait += 6;
00177                 else
00178                     ait++;
00179             }
00180             pbeg = pend;
00181             pend = min(pend + PWorkingSetSize, pg.end());
00182         } while (!one_pass && pbeg != pg.end());
00183         it = ait;
00184     }
00185     in_call_list = false;
00186 }

Generated on Sat Mar 15 22:55:58 2008 for Armagetron Advanced by  doxygen 1.5.4