Bläddra i källkod

Working on the particle emitter

Panagiotis Christopoulos Charitos 15 år sedan
förälder
incheckning
1ae14006b3

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 492 - 455
build/debug/Makefile


+ 0 - 236
build/genmakefile.py

@@ -1,236 +0,0 @@
-#!/usr/bin/python3.1
-import sys, os, fnmatch, random, re
-from threading import Thread
-
-
-#=======================================================================================================================
-# GLOBAL VARS                                                                                                          =
-#=======================================================================================================================
-sourcePaths = []
-precompiledHeaders = []
-executableName = "unamed-project"
-compiler = ""
-compilerFlags = ""
-precompiledHeadersFlags = ""
-linkerFlags = ""
-sourceFilesRegExpr = r"^.*\.(c\+\+|cpp|cc|cxx|C|c)$"
-includePaths = []
-
-
-#=======================================================================================================================
-# getCommandOutput                                                                                                     =
-#=======================================================================================================================
-def getCommandOutput(command):
-	child = os.popen(command)
-	data = child.read()
-	err = child.close()
-	if err:
-		print("getCommandOutput failed:\n" + command)
-		exit(0)
-	return data
-
-
-#=======================================================================================================================
-# Threads                                                                                                              =
-#=======================================================================================================================
-threadList = []
-
-class TargetThread(Thread):
-	def __init__(self, tid, range):
-		Thread.__init__(self)
-		self.tid = tid
-		self.range = range
-		self.out_str = ""
-		
-	def run(self):
-		for i in self.range:
-			source_file = sourceFiles[i]
-			self.out_str += getCommandOutput(compiler + " -MM " + compilerFlags + " " + source_file.cppFile + " -MT " + source_file.objFile)
-			self.out_str += "\t@echo Compiling " + source_file.cppFile + "...\n"
-			self.out_str += "\t@$(CXX) $(INCPATH) $(CFLAGS) " + source_file.cppFile + " -o " + \
-			                source_file.objFile + "\n\n"
-			#print("Im thread %d and I will make depends for %s" %(self.tid, source_file.fname))
-			#print("Im thread %d and my i is %d" %(self.tid, i))
-
-
-#=======================================================================================================================
-# SourceFile                                                                                                           =
-#=======================================================================================================================
-class SourceFile:
-	def __init__(self):	
-		self.cppFile = ""
-		self.objFile = ""
-
-
-#=======================================================================================================================
-# main                                                                                                                 =
-#=======================================================================================================================
-
-# Read the arguments
-inputCfgFile = ""
-outputMakefile = ""
-
-i = 0
-while 1:
-	i = i+1
-	if i>=len(sys.argv): break
-
-	arg = sys.argv[i]
-	if arg == "-h" or arg == "-help" or arg == "--help":
-		print("Makefile generator by GODlike")
-		print("usage: " + sys.argv[0] + " [options] [-i input] [-o output]")
-		print("options:")
-		print("-h, -help, --help  Print this text")
-		print("-i                 Input config file. Default: gen.cfg.py")
-		print("-o                 Output makefile. Default: Makefile")
-		exit(0)
-	elif arg == "-i":
-		inputCfgFile = sys.argv[i+1]
-		i = i+1
-	elif arg == "-o":
-		outputMakefile = sys.argv[i+1]
-		i = i+1
-	else:
-		print("Unrecognized argument " + arg)
-	
-
-if outputMakefile == "":
-	outputMakefile = "Makefile"
-if inputCfgFile == "":
-	inputCfgFile = "gen.cfg.py"
-
-
-# Check if cfg exists
-if not os.path.exists(inputCfgFile):
-	print("File " + inputCfgFile + " doesn't exist")
-	exit(0)
-
-
-# compile the cfg
-source = ""
-f = open(inputCfgFile, "r")
-for line in f.readlines():
-	source += line
-	
-exec(compile(source, inputCfgFile, "exec"))
-
-
-# find the cpp files
-sourceFiles = []
-regexpr = re.compile(sourceFilesRegExpr)
-for sourceDir in sourcePaths:
-	files = os.listdir(sourceDir)
-	for file_ in files:
-		if not regexpr.match(file_): continue
-		
-		sfile = SourceFile()
-		
-		(fname_wo_ext, ext) = os.path.splitext(file_)
-		sfile.cppFile = sourceDir + "/" + file_
-		sfile.objFile = fname_wo_ext + ".o"
-		
-		# search all the source files and resolve conflicts in .o
-		for sfile1 in sourceFiles:
-			if sfile1.objFile == sfile.objFile:
-				print("There is a naming conflict between \"" + sfile1.cppFile + "\" and \"" + sfile.cppFile + "\" but dont worry.")
-				random.seed()
-				sfile.objFile = str(random.randint(1,99)) + "." + sfile.objFile;
-	
-		sourceFiles.append(sfile)
-	
-
-# now the precompiled headers
-phFiles = []
-for header in precompiledHeaders:
-	sFile = SourceFile()
-	(fnameWoExt, ext) = os.path.splitext(header)
-	sFile.cppFile = header
-	sFile.objFile = os.path.basename(fnameWoExt) + ".h.gch "
-	phFiles.append(sFile)
-
-
-# build the string
-masterStr = ""
-
-masterStr += "CXX = " + compiler + "\n"
-masterStr += "CFLAGS = " + compilerFlags + "\n"
-masterStr += "PHFLAGS = " + precompiledHeadersFlags + "\n"
-masterStr += "LFLAGS = " + linkerFlags + "\n"
-masterStr += "EXECUTABLE = " + executableName + "\n"
-
-masterStr += "INCPATH = "
-for path in includePaths:
-	masterStr += "-I" + path + " "
-	compilerFlags += " -I" + path + " "
-masterStr += "\n"
-
-masterStr += "SOURCES = "
-for source_file in sourceFiles:
-	masterStr += source_file.cppFile + " "
-masterStr += "\n"
-
-masterStr += "OBJECTS = "
-for source_file in sourceFiles:
-	masterStr += source_file.objFile + " "
-masterStr += "\n"
-
-masterStr += "PRECOMPILED_HEADERS = "
-for header in phFiles:
-	masterStr += header.objFile
-masterStr += "\n\n"
-
-masterStr += "all: $(PRECOMPILED_HEADERS) $(SOURCES) $(EXECUTABLE)\n\n"
-
-masterStr += "$(EXECUTABLE): $(OBJECTS)\n"
-masterStr += "\t@echo Linking...\n"
-masterStr += "\t@$(CXX) $(OBJECTS) $(LFLAGS) -o $(EXECUTABLE)\n"
-masterStr += "\t@echo All Done!\n\n"
-
-
-for header in phFiles:  
-	dependStr = getCommandOutput(compiler + " -MM " + compilerFlags + " " + header.cppFile + " -MT " + header.objFile)
-	masterStr += dependStr
-	masterStr += "\t@echo Pre-compiling header " + header.cppFile + "...\n"
-	masterStr += "\t@$(CXX) $(INCPATH) $(PHFLAGS) " + header.cppFile + " -x c++-header " + header.objFile + "\n\n"
-
-
-# write source file target
-threadsNum = os.sysconf('SC_NPROCESSORS_ONLN') + 1
-print("I will invoke %d threads to make the dependencies..." % threadsNum)
-num = len(sourceFiles);
-itemsPerThread = num // threadsNum;
-
-for i in range(0, threadsNum):
-	begin = i*itemsPerThread
-	if i == threadsNum-1:
-		end = num
-	else:
-		end = begin + itemsPerThread	
-	thread = TargetThread(i, range(int(begin), int(end)))
-	thread.start()
-	threadList.append(thread)
-
-for thread in threadList:
-	thread.join()
-
-for thread in threadList:
-	masterStr += thread.out_str
-
-#for source_file in sourceFiles:	
-	#masterStr += source_file.fname_wo_ext + ".o: " + source_file.path + source_file.fname_wo_ext + ".cpp"
-	#masterStr += getCommandOutput(compiler + " -M " + compilerFlags + " " + source_file.path + "/" + source_file.fname)
-	#masterStr += "\t@echo Compiling " + source_file.fname + "...\n"
-	#masterStr += "\t@$(CXX) $(INCPATH) $(CFLAGS) " + source_file.path + "/" + source_file.fname + "\n\n"
-
-
-masterStr += "clean:\n"
-masterStr += "\trm -f *.o\n"
-masterStr += "\trm -f *.gch\n"
-masterStr += "\trm -f *~\n"
-masterStr += "\trm -f $(EXECUTABLE)\n\n"
-
-
-# write file
-f = open(outputMakefile, "w")
-f.write(masterStr)
-print("File \"" + outputMakefile + "\" created!")

+ 29 - 16
docs/manual

@@ -26,8 +26,7 @@ Building
 ========
 
 AnKi build system is very Linux specific (GNU make only) at the moment. It
-also requires a few extra development libraries. You can also find a custom
-build system that generates GNU makefiles.
+also requires a few extra development libraries.
 
 To download the latest release from the SVN repository type:
 
@@ -119,24 +118,38 @@ install it using the packet manager of your choice.
 In Ubuntu type: $ sudo apt-get install libboost<version>-dev-all
 
 
-Generating makefiles and building AnKi
---------------------------------------
+Building AnKi and optionally generating makefiles
+-------------------------------------------------
+
+Inside the build directory you can find 4 build targets containing GNU
+makefiles. If you want to build AnKi just type "make".
+
+**WARNING**: Sometimes I forget to update all the targets. The debug is always 
+updated though.
+
+AnKi uses a build system that generates the above makefiles. This build system
+is no longer part of AnKi and its located in a different repository. This tool
+is called gBuildSystem and you can find it in
+http://godlike-projects.googlecode.com/svn/trunk/gBuildSystem. Downloaded it
+using SVN:
+
+$ svn checkout http://godlike-projects.googlecode.com/svn/trunk/gBuildSystem
 
-There are 4 build targets in the build directory. There is also a build system
-that generates GNU makefiles (it requires Python 3 installed). If you want to 
-generate the makefile for the debug target (for example) do the following:
+
+gBuildSystem only purpose is to re-generate these makefiles in case you have
+made changes in code structure (renaming/moving/deleting/adding files) or in the
+includes (#include) or your have the external libs in different paths.
+gBuildSystem requires the gen.cfg.py files (something like CMakeLists.txt).
+gen.cfg.py format is pretty straightforward and minimal.
+
+If you want to generate the makefile for the debug target (for example) do the
+following:
 
 #) $ cd <path to anki>/build/debug
-#) $ ../genmakefile.py
+#) $ <path to gBuildSystem>/gbs.py
 #) $ make
 
 And the build process will begin. 
-
-The gen.cfg.py files contain the build options of every target. Their format
-is pretty straightforward and minimal.
-
-**WARNING**: Sometimes I forget to update all the targets. The debug is always 
-updated though.
   
 
 ======
@@ -157,8 +170,8 @@ The engine requires:
 - Linux OS
 - Proprietary GPU drivers
 
-Development rig: Ubuntu 9.10, AMD Radeon 4870 w/ Catalyst 10.6. So it should be
-working on similar systems.
+Development rig: Ubuntu 10.04, AMD Radeon 4870 w/ Catalyst 10.04. So it should
+be working on similar systems.
 
 
 ==============================================

+ 24 - 15
docs/manual.html

@@ -304,7 +304,7 @@ ul.auto-toc {
 <li><a class="reference internal" href="#boost" id="id8">boost</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#generating-makefiles-and-building-anki" id="id9">Generating makefiles and building AnKi</a></li>
+<li><a class="reference internal" href="#building-anki-and-optionally-generating-makefiles" id="id9">Building AnKi and optionally generating makefiles</a></li>
 </ul>
 </li>
 <li><a class="reference internal" href="#assets" id="id10">Assets</a></li>
@@ -336,8 +336,7 @@ non-GPLv3 licensed software then you have to apply for a commercial license.</p>
 <div class="section" id="building">
 <h1><a class="toc-backref" href="#id2">Building</a></h1>
 <p>AnKi build system is very Linux specific (GNU make only) at the moment. It
-also requires a few extra development libraries. You can also find a custom
-build system that generates GNU makefiles.</p>
+also requires a few extra development libraries.</p>
 <p>To download the latest release from the SVN repository type:</p>
 <p>$ svn checkout <a class="reference external" href="http://anki-3d-engine.googlecode.com/svn/trunk/">http://anki-3d-engine.googlecode.com/svn/trunk/</a> anki</p>
 <div class="section" id="required-libraries">
@@ -416,21 +415,31 @@ install it using the packet manager of your choice.</p>
 <p>In Ubuntu type: $ sudo apt-get install libboost&lt;version&gt;-dev-all</p>
 </div>
 </div>
-<div class="section" id="generating-makefiles-and-building-anki">
-<h2><a class="toc-backref" href="#id9">Generating makefiles and building AnKi</a></h2>
-<p>There are 4 build targets in the build directory. There is also a build system
-that generates GNU makefiles (it requires Python 3 installed). If you want to
-generate the makefile for the debug target (for example) do the following:</p>
+<div class="section" id="building-anki-and-optionally-generating-makefiles">
+<h2><a class="toc-backref" href="#id9">Building AnKi and optionally generating makefiles</a></h2>
+<p>Inside the build directory you can find 4 build targets containing GNU
+makefiles. If you want to build AnKi just type &quot;make&quot;.</p>
+<p><strong>WARNING</strong>: Sometimes I forget to update all the targets. The debug is always
+updated though.</p>
+<p>AnKi uses a build system that generates the above makefiles. This build system
+is no longer part of AnKi and its located in a different repository. This tool
+is called gBuildSystem and you can find it in
+<a class="reference external" href="http://godlike-projects.googlecode.com/svn/trunk/gBuildSystem">http://godlike-projects.googlecode.com/svn/trunk/gBuildSystem</a>. Downloaded it
+using SVN:</p>
+<p>$ svn checkout <a class="reference external" href="http://godlike-projects.googlecode.com/svn/trunk/gBuildSystem">http://godlike-projects.googlecode.com/svn/trunk/gBuildSystem</a></p>
+<p>gBuildSystem only purpose is to re-generate these makefiles in case you have
+made changes in code structure (renaming/moving/deleting/adding files) or in the
+includes (#include) or your have the external libs in different paths.
+gBuildSystem requires the gen.cfg.py files (something like CMakeLists.txt).
+gen.cfg.py format is pretty straightforward and minimal.</p>
+<p>If you want to generate the makefile for the debug target (for example) do the
+following:</p>
 <ol class="arabic simple">
 <li>$ cd &lt;path to anki&gt;/build/debug</li>
-<li>$ ../genmakefile.py</li>
+<li>$ &lt;path to gBuildSystem&gt;/gbs.py</li>
 <li>$ make</li>
 </ol>
 <p>And the build process will begin.</p>
-<p>The gen.cfg.py files contain the build options of every target. Their format
-is pretty straightforward and minimal.</p>
-<p><strong>WARNING</strong>: Sometimes I forget to update all the targets. The debug is always
-updated though.</p>
 </div>
 </div>
 <div class="section" id="assets">
@@ -446,8 +455,8 @@ build it, the application will fail to run.</p>
 <li>Linux OS</li>
 <li>Proprietary GPU drivers</li>
 </ul>
-<p>Development rig: Ubuntu 9.10, AMD Radeon 4870 w/ Catalyst 10.6. So it should be
-working on similar systems.</p>
+<p>Development rig: Ubuntu 10.04, AMD Radeon 4870 w/ Catalyst 10.04. So it should
+be working on similar systems.</p>
 </div>
 <div class="section" id="generating-source-code-documentation-doxygen">
 <h1><a class="toc-backref" href="#id12">Generating source code documentation (doxygen)</a></h1>

+ 7 - 3
src/Resources/Core/Resource.h

@@ -1,5 +1,5 @@
-#ifndef _RESOURCE_H_
-#define _RESOURCE_H_
+#ifndef RESOURCE_H
+#define RESOURCE_H
 
 #include "Common.h"
 #include "Util.h"
@@ -28,7 +28,8 @@ class Resource
 			RT_SKELETON,
 			RT_SKEL_ANIM,
 			RT_LIGHT_PROPS,
-			RT_EXTENSION
+			RT_EXTENSION,
+			RT_PARTICLE_EMITTER_PROPS
 		};
 
 	PROPERTY_R(string, path, getRsrcPath);
@@ -47,6 +48,9 @@ class Resource
 		 */
 		virtual bool load(const char* filename) = 0;
 
+		/**
+		 * Special unload func for stuff that the destructor cannot cleanup (eg OpenGL stuff)
+		 */
 		virtual void unload() = 0;
 };
 

+ 35 - 0
src/Resources/ParticleEmitterProps.cpp

@@ -0,0 +1,35 @@
+#include <cstring>
+#include "ParticleEmitterProps.h"
+
+
+//======================================================================================================================
+// Constructor                                                                                                         =
+//======================================================================================================================
+ParticleEmitterPropsStruct::ParticleEmitterPropsStruct():
+	particleLifeMargin(0.0),
+	forceDirectionMargin(0.0),
+	forceMagnitudeMargin(0.0),
+	particleMassMargin(0.0),
+	gravityMargin(0.0),
+	startingPos(0.0),
+	startingPosMargin(0.0),
+	usingWorldGrav(true)
+{}
+
+
+//======================================================================================================================
+// Constructor [copy]                                                                                                  =
+//======================================================================================================================
+ParticleEmitterPropsStruct::ParticleEmitterPropsStruct(const ParticleEmitterPropsStruct& a)
+{
+	memcpy(this, &(const_cast<ParticleEmitterPropsStruct&>(a)), sizeof(ParticleEmitterPropsStruct));
+}
+
+
+//======================================================================================================================
+// load                                                                                                                =
+//======================================================================================================================
+bool ParticleEmitterProps::load(const char* filename)
+{
+	// dummy load
+}

+ 77 - 0
src/Resources/ParticleEmitterProps.h

@@ -0,0 +1,77 @@
+#ifndef PARTICLEEMITTERPROPS_H
+#define PARTICLEEMITTERPROPS_H
+
+#include "Common.h"
+#include "Math.h"
+#include "Resource.h"
+
+
+/**
+ * This is the properties of the particle emitter resource. Its a separate class from ParticleEmitterProps cause
+ * ParticleEmitter SceneNode subclass it.
+ */
+class ParticleEmitterPropsStruct
+{
+	public:
+		/**
+		 * @name Particle properties
+		 */
+		/**@{*/
+		float particleLife; ///< Required
+		float particleLifeMargin;
+
+		Vec3 forceDirection; ///< Required
+		Vec3 forceDirectionMargin;
+		float forceMagnitude; ///< Required
+		float forceMagnitudeMargin;
+
+		float particleMass; ///< Required
+		float particleMassMargin;
+
+		Vec3 gravity; ///< If not set then it uses the world's default
+		Vec3 gravityMargin;
+
+		Vec3 startingPos; ///< If not set the default is zero
+		Vec3 startingPosMargin;
+		/**@}*/
+
+		/**
+		 * @name Emitter properties
+		 */
+		/**@{*/
+		uint maxNumOfParticles; ///< The size of the particles vector. Required
+		float emittionPeriod; ///< How often the emitter emits new particles. In ms. Required
+		uint particlesPerEmittion; ///< How many particles are emitted every emittion. Required
+		/**@}*/
+
+		ParticleEmitterPropsStruct();
+		ParticleEmitterPropsStruct(const ParticleEmitterPropsStruct& a);
+
+	protected:
+		bool usingWorldGrav; ///< This flag indicates if we should use the default world gravity or to override it
+};
+
+
+
+/**
+ * The actual particle emitter resource
+ */
+class ParticleEmitterProps: public ParticleEmitterPropsStruct, public Resource
+{
+	public:
+		ParticleEmitterProps();
+
+		bool load(const char* filename);
+		void unload();
+};
+
+
+inline ParticleEmitterProps::ParticleEmitterProps():
+	Resource(RT_PARTICLE_EMITTER_PROPS)
+{}
+
+
+inline void ParticleEmitterProps::unload()
+{}
+
+#endif

+ 5 - 124
src/Scene/ParticleEmitter.cpp

@@ -10,7 +10,7 @@
 //======================================================================================================================
 void ParticleEmitter::Particle::render()
 {
-	if(lifeTillDeath < 0) return;
+	/*if(lifeTillDeath < 0) return;
 
 	glPushMatrix();
 	app->getMainRenderer()->multMatrix(getWorldTransform());
@@ -19,7 +19,7 @@ void ParticleEmitter::Particle::render()
 		glVertex3fv(&(Vec3(0.0))[0]);
 	glEnd();
 
-	glPopMatrix();
+	glPopMatrix();*/
 }
 
 
@@ -28,38 +28,10 @@ void ParticleEmitter::Particle::render()
 //======================================================================================================================
 void ParticleEmitter::init(const char* filename)
 {
-	// dummy props init
-	maxParticleLife = 400;
-	minParticleLife = 100;
-	minDirection = Vec3(-0.1, 1.0, 0.0);
-	maxDirection = Vec3(0.1, 1.0, 0.0);
-	minForceMagnitude = 1.0;
-	maxForceMagnitude = 2.0;
-	minParticleMass = 1.0;
-	maxParticleMass = 2.0;
-	minGravity = Vec3(0.0, 0.0, 0.0);
-	minGravity = Vec3(0.0, -1.0, 0.0);
-	minStartingPos = Vec3(-1.0, -1.0, -1.0);
-	maxStartingPos = Vec3(1.0, 1.0, 1.0);
-	maxNumOfParticles = 5;
-	emittionPeriod = 1000;
+	ParticleEmitterProps props;
+	//ParticleEmitterProps* me = this;
+	//(*this) = props;
 
-	// init the particles
-	btCollisionShape* colShape = new btSphereShape(0.1);
-
-	particles.resize(maxNumOfParticles);
-	for(uint i=0; i<maxNumOfParticles; i++)
-	{
-		particles[i] = new Particle;
-		float mass = Util::randRange(minParticleMass, maxParticleMass);
-		btRigidBody* body = app->getScene()->getPhysics()->createNewRigidBody(mass, Transform::getIdentity(), colShape, particles[i],
-		                                                                        Physics::CG_PARTICLE, Physics::CG_MAP);
-		//body->forceActivationState(DISABLE_SIMULATION);
-	}
-
-	/*btDiscreteDynamicsWorld* btWorld = app->getScene()->getPhysics()->getDynamicsWorld();
-	btWorld->getBroadphase()->resetPool(btWorld->getDispatcher());
-	btWorld->getConstraintSolver()->reset();*/
 }
 
 
@@ -68,98 +40,7 @@ void ParticleEmitter::init(const char* filename)
 //======================================================================================================================
 void ParticleEmitter::update()
 {
-	uint crntTime = app->getTicks();
-
-	// decrease particle life and deactivate the dead particles
-	for(Vec<Particle*>::iterator it=particles.begin(); it!=particles.end(); ++it)
-	{
-		Particle* part = *it;
-		if(part->lifeTillDeath < 0) continue; // its already dead so dont deactivate it again
-
-		part->lifeTillDeath -= crntTime-timeOfPrevUpdate;
-		if(part->lifeTillDeath < 1)
-		{
-			part->body->setActivationState(DISABLE_SIMULATION);
-		}
-	}
-
-	// emit new particles
-	DEBUG_ERR(particlesPerEmittion == 0);
-	if((crntTime - timeOfPrevEmittion) > emittionPeriod)
-	{
-		uint partNum = 0;
-		for(Vec<Particle*>::iterator it=particles.begin(); it!=particles.end(); ++it)
-		{
-			Particle* part = *it;
-			if(part->lifeTillDeath > 0) continue; // its alive so skip it
-
-			// reinit a dead particle
-			//
-
-			// activate it (Bullet stuff)
-			part->body->forceActivationState(ACTIVE_TAG);
-			part->body->clearForces();
-
-			// life
-			if(minParticleLife != maxParticleLife)
-				part->lifeTillDeath = Util::randRange(minParticleLife, maxParticleLife);
-			else
-				part->lifeTillDeath = minParticleLife;
-
-			// force
-			Vec3 forceDir;
-			if(minDirection != maxDirection)
-			{
-				forceDir = Vec3(Util::randRange(minDirection.x , maxDirection.x), Util::randRange(minDirection.y , maxDirection.y),
-			                                    Util::randRange(minDirection.z , maxDirection.z));
-			}
-			else
-			{
-				forceDir = minDirection;
-			}
-			forceDir.normalize();
-
-			if(minForceMagnitude != maxForceMagnitude)
-				part->body->applyCentralForce(toBt(forceDir * Util::randRange(minForceMagnitude, maxForceMagnitude)));
-			else
-				part->body->applyCentralForce(toBt(forceDir * minForceMagnitude));
-
-			// gravity
-			Vec3 grav;
-			if(minGravity != maxGravity)
-			{
-				grav = Vec3(Util::randRange(minGravity.x,maxGravity.x), Util::randRange(minGravity.y,maxGravity.y),
-			              Util::randRange(minGravity.z,maxGravity.z));
-			}
-			else
-			{
-				grav = minGravity;
-			}
-			part->body->setGravity(toBt(grav));
-
-			// starting pos
-			Vec3 pos;
-			if(minStartingPos != maxStartingPos)
-			{
-				pos = Vec3(Util::randRange(minStartingPos.x,maxStartingPos.x), Util::randRange(minStartingPos.y,maxStartingPos.y),
-			              Util::randRange(minStartingPos.z,maxStartingPos.z));
-			}
-			else
-			{
-				pos = minStartingPos;
-			}
-			pos += getWorldTransform().getOrigin();
-			part->body->setWorldTransform(toBt(Mat4(pos, Mat3::getIdentity(), 1.0)));
-
-			// do the rest
-			++partNum;
-			if(partNum >= particlesPerEmittion) break;
-		} // end for all particles
-
-		timeOfPrevEmittion = crntTime;
-	} // end if can emit
 
-	timeOfPrevUpdate = crntTime;
 }
 
 

+ 16 - 32
src/Scene/ParticleEmitter.h

@@ -1,68 +1,52 @@
 #ifndef _PARTICLEEMITTER_H_
 #define _PARTICLEEMITTER_H_
 
+#include <boost/ptr_container/ptr_vector.hpp>
 #include "Common.h"
 #include "SceneNode.h"
 #include "MeshNode.h"
 #include "GhostNode.h"
 #include "PhyCommon.h"
+#include "ParticleEmitterProps.h"
 
 
 /**
- * @brief The particle emitter scene node
- *
- * This scene node emitts @ref ParticleEmitter:Particle particle nodes in space.
+ * The particle emitter scene node. This scene node emitts @ref ParticleEmitter:Particle particle nodes in space.
  */
-class ParticleEmitter: public SceneNode
+class ParticleEmitter: public SceneNode, public ParticleEmitterPropsStruct
 {
 	public:
 
 		/**
-		 * @brief The scene node particle class
+		 * The scene node particle class
 		 */
 		class Particle: public GhostNode
 		{
 			public:
-				int lifeTillDeath; ///< Life till death. If < 0 then dead. In ms
+				float timeOfDeath; ///< Life till death. If < 0 then dead. In seconds
 				btRigidBody* body;
 
-				Particle(): lifeTillDeath(-1) {}
+				Particle(): timeOfDeath(-1.0) {}
 				void render();
 				void renderDepth() {};
 		};
 
-		// the particle properties
-		uint minParticleLife;
-		uint maxParticleLife;
-		Vec3 minDirection;
-		Vec3 maxDirection;
-		float minForceMagnitude;
-		float maxForceMagnitude;
-		float minParticleMass;
-		float maxParticleMass;
-		Vec3 minGravity;
-		Vec3 maxGravity;
-		Vec3 minStartingPos;
-		Vec3 maxStartingPos;
-
-		// the emittion properties
-		uint maxNumOfParticles; ///< The size of the particles vector
-		uint emittionPeriod; ///< How often the emitter emits new particles. In ms
-		uint particlesPerEmittion; ///< How many particles are emitted every emittion
-
-
 		// the changeable vars
-		Vec<Particle*> particles;
-		uint timeOfPrevUpdate;
-		uint timeOfPrevEmittion;
+		ptr_vector<Particle> particles;
+		float timeOfPrevUpdate;
+		float timeOfPrevEmittion;
 
 		// funcs
-		ParticleEmitter(): SceneNode(NT_PARTICLE_EMITTER) {}
+		ParticleEmitter();
 		void render();
-		void renderDepth() {}
 		void init(const char* filename);
 		void deinit() {}
 		void update();
 };
 
+
+inline ParticleEmitter::ParticleEmitter():
+	SceneNode(NT_PARTICLE_EMITTER)
+{}
+
 #endif

+ 26 - 17
src/Util/Tokenizer/Scanner.cpp

@@ -150,7 +150,7 @@ void Scanner::initAsciiMap()
 	asciiLookupTable['/'] = asciiLookupTable['~'] = asciiLookupTable['%'] = asciiLookupTable['#'] = AC_SPECIAL;
 	asciiLookupTable['^'] = AC_SPECIAL;
 
-	asciiLookupTable['\t'] = asciiLookupTable[' '] = asciiLookupTable['\0'] = asciiLookupTable['\r'] = AC_WHITESPACE;
+	asciiLookupTable['\t'] = asciiLookupTable[' '] = asciiLookupTable['\0'] = AC_WHITESPACE;
 	asciiLookupTable['\n'] = AC_ERROR; // newline is unacceptable char
 	                   
 	asciiLookupTable['\"']         = AC_DOUBLEQUOTE;
@@ -201,6 +201,15 @@ char Scanner::getNextChar()
 	else
 		++pchar;
 
+	if(*pchar == '\r') // windows crap
+	{
+		*pchar = '\0';
+	}
+	else if(lookupAscii(*pchar) == AC_ERROR)
+	{
+		ERROR("Unacceptable char 0x" << int(*pchar));
+	}
+
 	return *pchar;
 }
 
@@ -315,7 +324,7 @@ const Scanner::Token& Scanner::getNextToken()
 	}
 	else if(*pchar == '.')
 	{
-		uint asc = asciiLookup(getNextChar());
+		uint asc = lookupAscii(getNextChar());
 		putBackChar();
 		if(asc == AC_DIGIT)
 			checkNumber();
@@ -324,7 +333,7 @@ const Scanner::Token& Scanner::getNextToken()
 	}
 	else if(*pchar=='\0') // if newline
 	{
-		if(asciiLookup(getNextChar()) == AC_EOF)
+		if(lookupAscii(getNextChar()) == AC_EOF)
 			crntToken.code = TC_EOF;
 		else
 			crntToken.code = TC_NEWLINE;
@@ -332,7 +341,7 @@ const Scanner::Token& Scanner::getNextToken()
 	else
 	{
 		crappyLabel:
-		switch(asciiLookup(*pchar))
+		switch(lookupAscii(*pchar))
 		{
 			case AC_WHITESPACE : getNextChar();  goto start;
 			case AC_LETTER     : checkWord();    break;
@@ -371,7 +380,7 @@ bool Scanner::checkWord()
 	{
 		*tmpStr++ = ch;
 		ch = getNextChar();
-	}while (asciiLookup(ch)==AC_LETTER || asciiLookup(ch)==AC_DIGIT);
+	}while (lookupAscii(ch)==AC_LETTER || lookupAscii(ch)==AC_DIGIT);
 
 	*tmpStr = '\0'; // finalize it
 
@@ -478,7 +487,7 @@ bool Scanner::checkNumber()
 	// begin
 		if(*pchar == '0')
 			goto _0;
-		else if(asciiLookup(*pchar) == AC_DIGIT)
+		else if(lookupAscii(*pchar) == AC_DIGIT)
 		{
 			num = num*10 + *pchar-'0';
 			goto _0_9;
@@ -492,7 +501,7 @@ bool Scanner::checkNumber()
 	_0:
 		*tmpStr++ = *pchar;
 		getNextChar();
-		asc = asciiLookup(*pchar);
+		asc = lookupAscii(*pchar);
 		if (*pchar == 'x' || *pchar == 'X')
 			goto _0x;
 		else if(*pchar == 'e' || *pchar == 'E')
@@ -513,7 +522,7 @@ bool Scanner::checkNumber()
 	_0x:
 		*tmpStr++ = *pchar;
 		getNextChar();
-		asc = asciiLookup(*pchar);
+		asc = lookupAscii(*pchar);
 		if((asc == AC_DIGIT)  ||
 				(*pchar >= 'a' && *pchar <= 'f') ||
 				(*pchar >= 'A' && *pchar <= 'F'))
@@ -535,7 +544,7 @@ bool Scanner::checkNumber()
 	_0x0_9orA_F:
 		*tmpStr++ = *pchar;
 		getNextChar();
-		asc = asciiLookup(*pchar);
+		asc = lookupAscii(*pchar);
 		if((asc == AC_DIGIT)         ||
 				(*pchar >= 'a' && *pchar <= 'f') ||
 				(*pchar >= 'A' && *pchar <= 'F'))
@@ -559,7 +568,7 @@ bool Scanner::checkNumber()
 	_0_9:
 		*tmpStr++ = *pchar;
 		getNextChar();
-		asc = asciiLookup(*pchar);
+		asc = lookupAscii(*pchar);
 		if(asc == AC_DIGIT)
 		{
 			num = num * 10 + *pchar - '0';
@@ -578,7 +587,7 @@ bool Scanner::checkNumber()
 	_float:
 		*tmpStr++ = *pchar;
 		getNextChar();
-		asc = asciiLookup(*pchar);
+		asc = lookupAscii(*pchar);
 		crntToken.dataType = DT_FLOAT;
 		if(asc == AC_DIGIT)
 		{
@@ -607,7 +616,7 @@ bool Scanner::checkNumber()
 	_0_9_dot_0_9_f:
 		*tmpStr++ = *pchar;
 		getNextChar();
-		asc = asciiLookup(*pchar);
+		asc = lookupAscii(*pchar);
 
 		if(asc == AC_SPECIAL || asc == AC_WHITESPACE || asc == AC_EOF)
 			goto finalize;
@@ -618,7 +627,7 @@ bool Scanner::checkNumber()
 	_0_9_dot_0_9_e:
 		*tmpStr++ = *pchar;
 		getNextChar();
-		asc = asciiLookup(*pchar);
+		asc = lookupAscii(*pchar);
 		crntToken.dataType = DT_FLOAT;
 
 		if(*pchar == '+' || *pchar == '-')
@@ -640,7 +649,7 @@ bool Scanner::checkNumber()
 	_0_9_dot_0_9_e_sign:
 		*tmpStr++ = *pchar;
 		getNextChar();
-		asc = asciiLookup(*pchar);
+		asc = lookupAscii(*pchar);
 
 		if(asc == AC_DIGIT)
 		{
@@ -655,7 +664,7 @@ bool Scanner::checkNumber()
 	_0_9_dot_0_9_e_sign_0_9:
 		*tmpStr++ = *pchar;
 		getNextChar();
-		asc = asciiLookup(*pchar);
+		asc = lookupAscii(*pchar);
 
 		if(asc == AC_DIGIT)
 		{
@@ -694,11 +703,11 @@ bool Scanner::checkNumber()
 		crntToken.code = TC_ERROR;
 
 		// run until white space or special
-		asc = asciiLookup(*pchar);
+		asc = lookupAscii(*pchar);
 		while(asc!=AC_WHITESPACE && asc!=AC_SPECIAL && asc!=AC_EOF)
 		{
 			*tmpStr++ = *pchar;
-			asc = asciiLookup(getNextChar());
+			asc = lookupAscii(getNextChar());
 		}
 
 		*tmpStr = '\0';

+ 8 - 5
src/Util/Tokenizer/Scanner.h

@@ -242,7 +242,7 @@ class Scanner
 		/**@{*/
 		ifstream inFstream; ///< The file stream. Used if the @ref Scanner is initiated using @ref loadFile
 		istream* inStream; ///< Points to either @ref inFstream or an external std::istream
-		char scriptName[512]; ///< The name of the input stream. Mainly used for the error messages
+		char scriptName[512]; ///< The name of the input stream. Mainly used for error messaging
 		/**@}*/
 
 		/**
@@ -281,10 +281,7 @@ class Scanner
 		/**
 		 * To save us from typing for example asciiLookupTable[(int)'a']
 		 */
-		inline AsciiFlag asciiLookup(char ch_)
-		{
-			return asciiLookupTable[(int)ch_];
-		}
+		AsciiFlag lookupAscii(char ch_);
 }; // end class Scanner
 
 
@@ -339,4 +336,10 @@ inline const char* Scanner::Token::getString() const
 	return asString;
 }
 
+
+inline Scanner::AsciiFlag Scanner::lookupAscii(char ch_)
+{
+	return asciiLookupTable[(int)ch_];
+}
+
 #endif

Vissa filer visades inte eftersom för många filer har ändrats