//--------------------------------------------------------------- // Original Tribes 2 Editor by Drew "Mongo" Zilm // // Torque port and changes by Bruce "Monster" Wallace // Big thanks to Drew for creating the base this particle Editor // Was built from. And thanks to all those that helped or will // help make it a great tool. //--------------------------------------------------------------- // vers. 1.11a 09/05/02 Eric Forhan // *Numerous bugs repaired--caps, misspells, etc. // *Rearranged GUI--all particle and emitter settings on proper pages // maxed-out and tested most settings ranges. // *Found out that SpinSpeed is never saved or loaded (even in T2 version). // +(Fixed in 1.12) // *Made defaults.cs always run so that defaultEmitterNode is accessible // // notes: +Still does not run all the saved custom emitters // v. 1.12 repaired spinSpeed. Now saves and loads properly--EJF //------------Path Settings-------------------------------------- // I hope to eliminate the need for these soon // Path to exported particle datablocks $PE::SaveFilePath = expandFilename("~/Particles/"); // Path to particle .png files // Make sure particletest.png is here, or, if the image path is changed, then // change it in Saves.cs as well -- EJF $PE::ParticleImagePath = expandFilename("~/Particles/*.png"); //--------------------------------------------------------------- //set defaults function ParticleEditor::initializeParticleEditor(%this) { %this.maxSaves = 50; //edit mode $adjustment = 1; %this.editMode = "position"; //end edit mode %this.parChoices = 0; DefaultEmitter.particles.windCoefficient = 0; %this.initEmitterCount(); %this.FillTextureList(); %this.FillEmitterPopups(ParticleEditorEmitterPopup); %this.FillEmitterPopups(ParticleEditorReplacePopup); %this.FillLoadList(); %this.parIndex = 0; %this.saveIndex = 1; %this.parDataBlock = "DefaultEmitterNode"; %this.parCurrent = ""; %this.lifetimeMS = ""; } function ParticleEditor::initEmitterCount(%this) { for(%i = 0; %i < DataBlockGroup.getCount(); %i++) { %obj = DataBlockGroup.getObject(%i); if(%obj.getClassName() $= ParticleEmitterData) { %this.Emitters[%this.parChoices] = %obj.getName(); %this.parChoices++; } } // TODO: Add Datablocks saved in Saves.cs } function ParticleEditor::replaceDefaultEmitter(%this, %control) { %index = %this.findEmitterString(%control, %control.getValue()); if(%index) %this.setEmitter(%this.emitters[%index], DefaultEmitter); localClientConnection.transmitDataBlocks(0); } function ParticleEditor::changeEmitter(%this, %control, %value) { if(%value !$= "") { %this.parDataBlock = "DefaultEmitterNode"; PE_toggleDataBlock.setValue("Default"); %texture = DefaultEmitter.particles.textureName; %index = %this.findEmitterString(%control, %value); if(%control $= particleEditorEmitterPopup) { %this.setEmitter(DefaultEmitter, %this.emitters[%index]); EMITTER_TEXT.setValue(%this.emitters[%index]); %this.parIndex = %index; particleEditorSavePopup.setValue(""); } else if(%control $= particleEditorSavePopup) { %this.readSave($Particle::Save[%index]); %this.saveIndex = %index; ParticleEditorEmitterPopup.setValue(""); } if(%texture !$= DefaultEmitter.particles.textureName) localClientConnection.transmitDataBlocks(0); %this.getParticleMax(); %this.recreateEmitter(); } } function ParticleEditor::findEmitterString(%this, %source, %value) { %this.parCurrent = 0; if((%source $= particleEditorEmitterPopup) || (%source $= ParticleEditorReplacePopup)) { for(%i = 1; %i <= %this.parChoices; %i++) { if(%value $= %this.emitters[%i]) return %i; } } else if(%source $= particleEditorSavePopup) { for(%i = 1; ($Particle::Save[%i] !$= ""); %i++) { if(%value $= getField($Particle::Save[%i], 0)) return %i; } } return 0; } function ParticleEditor::nextEmitter(%this, %source) { %this.parDataBlock = "DefaultEmitterNode"; PE_toggleDataBlock.setValue("Default"); %texture = DefaultEmitter.particles.textureName; if(%source $= "DefaultCycleButton") { if (%this.parIndex && (%this.parIndex < %this.parChoices) ) %this.parIndex++; else %this.parIndex = 1; %this.setEmitter(DefaultEmitter, %this.emitters[%this.parIndex]); EMITTER_TEXT.setValue(%this.emitters[%this.parIndex]); particleEditorSavePopup.setValue(""); ParticleEditorEmitterPopup.setValue(%this.emitters[%this.parIndex]); } else if(%source $= "CustomCycleButton")//NewParticle.cs { if($Particle::Save[%this.saveIndex] $= "") %this.saveIndex = 1; if($Particle::Save[%this.saveIndex] $= "") return; %this.readSave($Particle::Save[%this.saveIndex]); %this.saveIndex++; } if(%texture !$= DefaultEmitter.particles.textureName) localClientConnection.transmitDataBlocks(0); %this.getParticleMax(); %this.recreateEmitter(); } function ParticleEditor::createEmitter(%this) { if(%this.lastPosition) { %position = %this.lastPosition; %this.lastPosition = false; } else %position = localClientConnection.getControlObject().getWorldBoxCenter(); %emitter = new ParticleEmitterNode() { position = %position; rotation = "1 0 0 0"; scale = "1 1 1"; dataBlock = %this.parDataBlock; emitter = DefaultEmitter; velocity = "1"; }; MissionCleanup.add( %emitter ); %this.parObject = %emitter; } function ParticleEditor::recreateEmitter(%this) { %obj = %this.parObject; %this.updateHUD(); if(%this.delay) //emitter is in a loop must handle this { cancel( %this.loopThread ); %this.loopThread = %this.schedule(( PE_emitterLife ), loopEmitter, %delay); if( isObject( %obj ) ) { %this.lastPosition = %obj.position; %obj.delete(); %this.parObject = false; } } else if(%this.parObject) //there is an object already { %this.lastPosition = %obj.position; %obj.delete(); %this.parObject = false; } else %this.lastPosition = false; %this.createEmitter(); localClientConnection.transmitDataBlocks(0); } function ParticleEditor::deleteCurrentObject(%this) { %obj = %this.parObject; if( %obj ) { Emitter_Text.setValue(""); ParticleEditorTextureList.setValue(""); ParticleEditorEmitterPopup.setValue(""); particleEditorSavePopup.setValue(""); PE_CurrentEmitter.setValue(""); %obj.delete(); } if( %this.delay ) { %this.delay = false; PE_modeButton.text = "Constant"; cancel(%this.loopThread); } %this.parObject = false; } function ParticleEditor::toggleParticleDatablock(%this, %control) { if(%this.parDataBlock $= "DefaultEmitterNode") { %this.parDataBlock = "DoubleTimeEmitterNode"; //%control.setValue("Double"); %control.setText("Double"); } else if(%this.parDataBlock $= "DoubleTimeEmitterNode") { %this.parDataBlock = "HalfTimeEmitterNode"; //%control.setValue("Half"); %control.setText("Half"); } else { %this.parDataBlock = "DefaultEmitterNode"; //%control.setValue("Default"); %control.setText("Default"); } if( %this.parObject ) %this.recreateEmitter(); } function ParticleEditor::colorParticle(%this, %word, %value) { if(%this.parCurrentMax) { for(%i = 0; %i < 4; %i++) { %this.rgb[%i] = getWord(DefaultParticle.colors[%this.parCurrent], %i); if(%i == %word) %this.rgb[%i] = %value; } DefaultParticle.colors[%this.parCurrent] = ""; DefaultParticle.colors[%this.parCurrent] = (%this.rgb[0] @ " " @ %this.rgb[1] @ " " @ %this.rgb[2] @ " " @ %this.rgb[3]); } } function ParticleEditor::dropEmitterAtCamera(%this) { %obj = %this.ParObject; if( isObject(%obj) ) { %obj.position = localClientConnection.getControlObject().getWorldBoxCenter(); %this.recreateEmitter(); } else if( %this.delay ) { %this.lastPosition = localClientConnection.getControlObject().getWorldBoxCenter(); %this.recreateEmitter(); } } function ParticleEditor::leaveEmitterInWorld(%this) { //you must reboot T2 to add a work in progress to the datablock list if( particleEditor.parObject ) { %emitterName = Emitter_Text.getValue(); if( isObject( %emitterName ) ) { if( !isObject( MissionParticles ) ) { %group = new simGroup( MissionParticles ); MissionGroup.add( MissionParticles ); } %emitter = new ParticleEmitterNode() { position = %this.parObject.position; rotation = "1 0 0 0"; scale = "1 1 1"; dataBlock = %this.parDataBlock; emitter = %emitterName; velocity = "1"; }; MissionParticles.add( %emitter ); %this.deleteCurrentObject(); } else MessageBoxOK( "Datablock Failure", "Current particle must be converted into a datablock by exporting from Load/Save menu and reloading Torque. Unable to place non-datablocks in mission."); } else MessageBoxOK( "Object Failed", "Currently there is no particle to add to the world."); } function ParticleEditor::replaceCurrentEmitter(%this) { //warning, no checks here but there is always a DefaultEmitter %this.setEmitter(%this.emitters[%this.parIndex], DefaultEmitter); } function ParticleEditor::nextParticle(%this) { if(%this.parCurrentMax)//if there are particles { if(%this.parCurrent >= (%this.parCurrentMax-1)) %this.parCurrent = 0; else %this.parCurrent++; } %this.updateHud(); } function ParticleEditor::checktime(%this, %value) { if(%this.parCurrent == 0) DefaultEmitter.particles.times[%this.parCurrent] = 0; else if((%this.parCurrent+1) == %this.parCurrentMax) DefaultEmitter.particles.times[%this.parCurrent] = 1; else { if(%value == 1) DefaultEmitter.particles.times[%this.parCurrent] = 0.99; else if(%value == 0) DefaultEmitter.particles.times[%this.parCurrent] = 0.01; else DefaultEmitter.particles.times[%this.parCurrent] = %value; } } function ParticleEditor::getParticleMax(%this) { %this.parCurrent = 0; %this.parCurrentMax = 0; for(%i = 0; DefaultParticle.times[%i] != 1; %i++) %this.parCurrentMax++; %this.parCurrentMax++; } function ParticleEditor::addParticle(%this) { if( %this.parCurrentMax < 5 ) { DefaultParticle.times[ (%this.parCurrentMax - 1) ] = 0.75; DefaultParticle.times[ %this.parCurrentMax ] = 1.0; //new end %this.parCurrentMax++; %this.recreateEmitter(); } } function ParticleEditor::removeParticle(%this) { if( %this.parCurrentMax > 2) { if( %this.parCurrent >= ( %this.parCurrentMax - 1) ) { %this.parCurrent = 0; Particle_Text.setValue(1); } DefaultParticle.times[ (%this.parCurrentMax - 2) ] = 1.0; //remove one %this.parCurrentMax = ( %this.parCurrentMax - 1 ); %this.recreateEmitter(); } } function ParticleEditor::setSameSize(%this) { for(%i = 0; %i < %this.parCurrentMax; %i++) { if( %i != %this.parCurrent ) DefaultParticle.sizes[ %i ] = DefaultParticle.sizes[ %this.parCurrent ]; %this.recreateEmitter(); } } function ParticleEditor::setEmitter(%this, %destination, %reference) { if(%reference.getClassName() $= "ParticleEmitterData") { %destination.ejectionPeriodMS = %reference.ejectionPeriodMS; %destination.periodVarianceMS = %reference.periodVarianceMS; %destination.ejectionVelocity = %reference.ejectionVelocity; %destination.velocityVariance = %reference.velocityVariance; %destination.ejectionOffset = %reference.ejectionOffset; %destination.thetaMin = %reference.thetaMin; %destination.thetaMax = %reference.thetaMax; %destination.phiReferenceVel = %reference.phiReferenceVel; %destination.phiVariance = %reference.phiVariance; %destination.overrideAdvances = %reference.overrideAdvances; PE_emitterLife.setValue( %reference.lifetimeMS ); %destination.orientParticles = %reference.orientParticles; %destination.orientOnVelocity = %reference.orientOnVelocity; //the following line had a spelling error, but fixing it causes errors in the PE //%desination.particles = %reference.particles; %this.setParticle(%reference, %destination); } else echo("Error: not an emitter object."); } function ParticleEditor::setParticle(%this, %reference, %destination) { if(%reference.particles.getClassName() $= "ParticleData") { %destination.particles.dragCoefficient = %reference.particles.dragCoefficient; %destination.particles.gravityCoefficient = %reference.particles.gravityCoefficient; %destination.particles.inheritedVelFactor = %reference.particles.inheritedVelFactor; %destination.particles.constantAcceleration = %reference.particles.constantAcceleration; %destination.particles.lifetimeMS = %reference.particles.lifetimeMS; %destination.particles.lifetimeVarianceMS = %reference.particles.lifetimeVarianceMS; %destination.particles.useInvAlpha = %reference.particles.useInvAlpha; %destination.particles.spinRandomMin = %reference.particles.spinRandomMin; %destination.particles.spinRandomMax = %reference.particles.spinRandomMax; %destination.particles.textureName = %reference.particles.textureName; // added by EJF %destination.particles.spinSpeed = %reference.particles.spinSpeed; // %destination.particles.windCoefficient = %reference.particles.windCoefficient; for(%i = 0; !%done; %i++) { if( %reference.particles.times[%i] == 1 ) %done = true; $Data::Block[0] = $Data::Block[0] @ %destination.particles.times[%i] = %reference.particles.times[%i]; } %done = false; for(%i = 0; !%done; %i++) { if( %reference.particles.times[%i] == 1 ) %done = true; $Data::Block[0] = $Data::Block[0] @ %destination.particles.colors[%i] = %reference.particles.colors[%i]; } %done = false; for(%i = 0; !%done; %i++) { if( %reference.particles.times[%i] == 1 ) %done = true; $Data::Block[0] = $Data::Block[0] @ %destination.particles.sizes[%i] = %reference.particles.sizes[%i]; } } else echo("Error: not a particle object."); } function ParticleEditor::printEmitter(%this, %reference) { error("**************Emitter*******************************"); echo("ejectionPeriodMS: " @ %reference.ejectionPeriodMS); echo("Variance MS: " @ %reference.periodVarianceMS); echo("Velocity: " @ %reference.ejectionVelocity); echo("VelVAR: " @ %reference.velocityVariance); echo("Offset: " @ %reference.ejectionOffset); echo("ThetaMIN: " @ %reference.thetaMin); echo("ThetaMAX: " @ %reference.thetaMax); echo("PHIrefVAL: " @ %reference.phiReferenceVel); echo("PHIVAR: " @ %reference.phiVariance); echo("OrientParticles: " @ %reference.orientParticles); echo("OrientOnVelocity: " @ %reference.orientOnVelocity); echo("overrideAdvances: " @ %reference.overrideAdvances); error("**************Emitter*******************************"); } function ParticleEditor::printParticle(%this, %reference) { error("**************Particle*******************************"); echo("Drag: " @ %reference.particles.dragCoefficient); echo("Gravity: " @ %reference.particles.gravityCoefficient); echo("Wind: " @ %reference.particles.windCoefficient); echo("InhVEL: " @ %reference.particles.inheritedVelFactor); echo("Accel: " @ %reference.particles.constantAcceleration); echo("Life: " @ %reference.particles.lifetimeMS); echo("LifeVAR: " @ %reference.particles.lifetimeVarianceMS); echo("InvAlpha: " @ %reference.particles.useInvAlpha); echo("SpinMIN: " @ %reference.particles.spinRandomMin); echo("SpinMAX: " @ %reference.particles.spinRandomMax); echo("Texture: " @ %reference.particles.textureName); echo("spinSpeed: " @ %reference.particles.spinSpeed); echo("Color 1: " @ %reference.particles.colors[0]); echo("Color 2: " @ %reference.particles.colors[1]); echo("Color 3: " @ %reference.particles.colors[2]); echo("Color 4: " @ %reference.particles.colors[3]); echo("Size 1: " @ %reference.particles.sizes[0]); echo("Size 2: " @ %reference.particles.sizes[1]); echo("Size 3: " @ %reference.particles.sizes[2]); echo("Size 4: " @ %reference.particles.sizes[3]); echo("Times 1: " @ %reference.particles.times[0]); echo("Times 2: " @ %reference.particles.times[1]); echo("Times 3: " @ %reference.particles.times[2]); echo("Times 4: " @ %reference.particles.times[3]); error("**************Particle*******************************"); } function ParticleEditor::getsavePattern(%this) { %i = 0; %emitterChars = 7; //7 characters %name = EMITTER_TEXT.getValue(); %length = strLen(%name); %substring = getSubStr( %name, ( %length - %emitterChars), %emitterChars); if( %substring $= "Emitter" ) %particleName = ( getSubStr(%name, 0, ( %length - %emitterChars )) @ "Particle" ); else { %particleName = ( %name @ "Particle" ); Emitter_Text.setValue( %name @ "Emitter" ); %this.updateHud(); } %file[%i] = ( EMITTER_TEXT.getValue() ); %file[%i++] = %particleName; %file[%i++] = DefaultEmitter.ejectionPeriodMS; %file[%i++] = DefaultEmitter.periodVarianceMS; %file[%i++] = DefaultEmitter.ejectionVelocity; %file[%i++] = DefaultEmitter.velocityVariance; %file[%i++] = DefaultEmitter.ejectionOffset; %file[%i++] = DefaultEmitter.thetaMin; %file[%i++] = DefaultEmitter.thetaMax; %file[%i++] = DefaultEmitter.phiReferenceVel; %file[%i++] = DefaultEmitter.phiVariance; %file[%i++] = DefaultEmitter.orientParticles; %file[%i++] = DefaultEmitter.orientOnVelocity; %file[%i++] = DefaultEmitter.overrideAdvances; %file[%i++] = PE_emitterLife.getValue(); %file[%i++] = DefaultEmitter.particles.dragCoefficient; %file[%i++] = DefaultEmitter.particles.gravityCoefficient; %file[%i++] = DefaultEmitter.particles.inheritedVelFactor; %file[%i++] = DefaultEmitter.particles.constantAcceleration; %file[%i++] = DefaultEmitter.particles.lifetimeMS; %file[%i++] = DefaultEmitter.particles.lifetimeVarianceMS; %file[%i++] = DefaultEmitter.particles.useInvAlpha; %file[%i++] = DefaultEmitter.particles.spinRandomMin; %file[%i++] = DefaultEmitter.particles.spinRandomMax; %file[%i++] = DefaultEmitter.particles.windCoefficient; %file[%i++] = DefaultEmitter.particles.textureName; //added spinspeed to saves --ejf %file[%i++] = DefaultEmitter.particles.spinSpeed; for(%j = 0; !%done; %j++) { if( DefaultEmitter.particles.times[%j] == 1 ) %done = true; %file[%i++] = DefaultEmitter.particles.times[%j]; } %done = false; for(%j = 0; !%done; %j++) { if( DefaultEmitter.particles.times[%j] == 1 ) %done = true; %file[%i++] = DefaultEmitter.particles.colors[%j]; } %done = false; for(%j = 0; !%done; %j++) { if( DefaultEmitter.particles.times[%j] == 1 ) %done = true; %file[%i++] = DefaultEmitter.particles.sizes[%j]; } %total = %i; %string = ""; for(%i=0; %i <= %total; %i++) { if(%i) %string = %string @ "\n" @ %file[%i]; else %string = %file[%i]; } return %string; } function ParticleEditor::readSave(%this, %list) { %i = 1; EMITTER_TEXT.setValue(getField(%list,0)); particleEditorEmitterPopup.setValue(""); particleEditorSavePopup.setValue(getField(%list,0)); DefaultEmitter.ejectionPeriodMS = getField(%list, (%i++)); DefaultEmitter.periodVarianceMS = getField(%list, (%i++)); DefaultEmitter.ejectionVelocity = getField(%list, (%i++)); DefaultEmitter.velocityVariance = getField(%list, (%i++)); DefaultEmitter.ejectionOffset = getField(%list, (%i++)); DefaultEmitter.thetaMin = getField(%list, (%i++)); DefaultEmitter.thetaMax = getField(%list, (%i++)); DefaultEmitter.phiReferenceVel = getField(%list, (%i++)); DefaultEmitter.phiVariance = getField(%list, (%i++)); DefaultEmitter.orientParticles = getField(%list, (%i++)); DefaultEmitter.orientOnVelocity = getField(%list, (%i++)); DefaultEmitter.overrideAdvances = getField(%list, (%i++)); PE_emitterLife.setValue( mFloor( getField(%list, (%i++)) ) ); DefaultEmitter.particles.dragCoefficient = getField(%list, (%i++)); DefaultEmitter.particles.gravityCoefficient = getField(%list, (%i++)); DefaultEmitter.particles.inheritedVelFactor = getField(%list, (%i++)); DefaultEmitter.particles.constantAcceleration = getField(%list, (%i++)); DefaultEmitter.particles.lifetimeMS = getField(%list, (%i++)); DefaultEmitter.particles.lifetimeVarianceMS = getField(%list, (%i++)); DefaultEmitter.particles.useInvAlpha = getField(%list, (%i++)); DefaultEmitter.particles.spinRandomMin = getField(%list, (%i++)); DefaultEmitter.particles.spinRandomMax = getField(%list, (%i++)); DefaultEmitter.particles.windCoefficient = getField(%list, (%i++)); DefaultEmitter.particles.textureName = getField(%list, (%i++)); //added spinSpeed--ejf DefaultEmitter.particles.spinSpeed = getField(%list, (%i++)); for(%j = 0; !%done; %j++) { if( DefaultEmitter.particles.times[%j] == 1 ) %done = true; DefaultEmitter.particles.times[%j] = getField(%list, %i++); } %done = false; for(%j = 0; !%done; %j++) { if( DefaultEmitter.particles.times[%j] == 1 ) %done = true; DefaultEmitter.particles.colors[%j] = getField(%list, %i++); } %done = false; for(%j = 0; !%done; %j++) { if( DefaultEmitter.particles.times[%j] == 1 ) %done = true; DefaultEmitter.particles.sizes[%j] = getField(%list, %i++); } ParticleEditorTextureList.setValue(DefaultEmitter.particles.textureName); } // TODO: Look over this and related functions and see if other options for saving would be useful or optimized. function ParticleEditor::saveEmitter(%this) { %control = particleEditorSavePopup; if(%this.parObject) { %list = %this.getSavePattern(); for(%i = 1;( (%i < %this.maxSaves) && (!%saved) ); %i++) { %emitter = Emitter_Text.getValue(); if( ($PARTICLE::SAVE[%i] $= "") || (%emitter $= getWord($PARTICLE::SAVE[%i],0)) ) { if( $PARTICLE::SAVE[%i] $= "" )//this is new %control.add(%emitter, (%i-1)); $PARTICLE::SAVE[%i] = %list; %this.changeEmitter(%control, %emitter); particleEditorSavePopup.setValue(%emitter); %saved = true; } } echo("Exporting $PARTICLE::* to Saves.cs"); export("$PARTICLE::*", "./Saves.cs", False); } } // TODO: Look at options for the save file path and look over this in general function ParticleEditor::createDataBlock(%this, %reference) { //name the particle appropriately %emitterChars = 7; //7 characters %name = EMITTER_TEXT.getValue(); %length = strLen(%name); %substring = getSubStr( %name, ( %length - %emitterChars), %emitterChars); if( %substring $= "Emitter" ) %particleName = ( getSubStr(%name, 0, ( %length - %emitterChars )) @ "Particle" ); else %particleName = ( %name @ "Particle" ); //call it a particle %this.saveEmitter(); $Data::Block[0] ="datablock ParticleData(" @ %particleName @ ")" @ "\n{" @ "\n dragCoefficient = " @ %reference.particles.dragCoefficient @ ";" @ "\n gravityCoefficient = " @ %reference.particles.gravityCoefficient @ ";" @ "\n windCoefficient = " @ %reference.particles.windCoefficient @ ";" @ "\n inheritedVelFactor = " @ %reference.particles.inheritedVelFactor @ ";" @ "\n constantAcceleration = " @ %reference.particles.constantAcceleration @ ";" @ "\n lifetimeMS = " @ %reference.particles.lifetimeMS @ ";" @ "\n lifetimeVarianceMS = " @ %reference.particles.lifetimeVarianceMS @ ";" @ "\n useInvAlpha = " @ %reference.particles.useInvAlpha @ ";" @ "\n spinRandomMin = " @ %reference.particles.spinRandomMin @ ";" @ "\n spinRandomMax = " @ %reference.particles.spinRandomMax @ ";" @ "\n textureName = \"" @ %reference.particles.texturename @ "\";" @ // added spinSpeed -- ejf "\n spinSpeed = " @ %reference.particles.spinSpeed @ ";"; for(%i = 0; !%done; %i++) { if( %reference.particles.times[%i] == 1 ) %done = true; $Data::Block[0] = $Data::Block[0] @ "\n times[" @ %i @ "] = " @ %reference.particles.times[%i] @ ";"; } %done = false; for(%i = 0; !%done; %i++) { if( %reference.particles.times[%i] == 1 ) %done = true; $Data::Block[0] = $Data::Block[0] @ "\n colors[" @ %i @ "] = \"" @ %reference.particles.colors[%i] @ "\";"; } %done = false; for(%i = 0; !%done; %i++) { if( %reference.particles.times[%i] == 1 ) %done = true; $Data::Block[0] = $Data::Block[0] @ "\n sizes[" @ %i @ "] = " @ %reference.particles.sizes[%i] @ ";"; } $Data::Block[0] = $Data::Block[0] @ "\n};\n\n"; //end particle data $Data::Block[1] = "datablock ParticleEmitterData(" @ EMITTER_TEXT.getValue() @ ")" @ "\n{" @ "\n ejectionPeriodMS = " @ %reference.ejectionPeriodMS @ ";" @ "\n periodVarianceMS = " @ %reference.periodVarianceMS @ ";" @ "\n ejectionVelocity = " @ %reference.ejectionVelocity @ ";" @ "\n velocityVariance = " @ %reference.velocityVariance @ ";" @ "\n ejectionOffset = " @ %reference.ejectionOffset @ ";" @ "\n thetaMin = " @ %reference.thetaMin @ ";" @ "\n thetaMax = " @ %reference.thetaMax @ ";" @ "\n phiReferenceVel = " @ %reference.phiReferenceVel @ ";" @ "\n phiVariance = " @ %reference.phiVariance @ ";" @ "\n overrideAdvances = " @ %reference.overrideAdvances @ ";"; if( PE_emitterLife.getValue() ) $Data::Block[1] = $Data::Block[1] @ "\n lifetimeMS = " @ PE_emitterLife.getValue() @ ";"; $Data::Block[1] = $Data::Block[1] @ "\n orientParticles= " @ %reference.orientParticles @ ";" @ "\n orientOnVelocity = " @ %reference.orientOnVelocity @ ";" @ "\n particles = \"" @ %particleName @ "\";" @ "\n};"; echo("Exporting Datablock...."); %filename = Emitter_Text.getValue(); %filename = fileBase( %filename ); if ( %filename $= "" ) return; new fileObject( "saveFile" ); saveFile.openForWrite( $PE::SaveFilePath @ %filename @ ".cs" ); saveFile.writeLine($Data::Block[0] @ $Data::Block[1]); saveFile.close(); saveFile.delete(); } function ParticleEditor::loopEmitter(%this, %delay) { %obj = %this.parObject; if(%this.delay) //keep looping { if( isObject( %obj ) ) { %this.lastPosition = %obj.position; %obj.delete(); %this.parObject = ""; %this.loopThread = %this.schedule( ( PE_emitterLifeDelay.getValue() ), loopEmitter, %delay); } else//create new one { %this.createEmitter(); %this.loopThread = %this.schedule( ( PE_emitterLife.getValue() ), loopEmitter, %delay); } } else //no more loops { if( !isObject(%obj) ) %this.createEmitter(); cancel(%this.loopThread); } } function ParticleEditor::toggleLoopDelay(%this, %delay) { if(%this.delay) { %this.delay = false; PE_modeButton.text = "Constant"; %this.loopEmitter(false); } else { %this.delay = true; PE_modeButton.text = "Simulation Loop"; %this.loopEmitter(%delay); } } function ParticleEditor::changeEmitterLife(%this, %value) { %obj = %this.parObject; %life = mFloor( %value ); PE_emitterLifeText.setValue( %life ); PE_emitterLifeTextWorld.setValue( %life ); if(%this.delay) { if( isObject(%obj) ) { %this.lastPosition = %obj.position; %obj.delete(); } %this.createEmitter(); cancel(%this.loopThread); if ( %life ) %this.loopThread = %this.schedule( ( PE_emitterLife.getValue() ), loopEmitter, %delay); else { PE_modeButton.text = "Constant"; %this.delay = false; } } } function ParticleEditor::changeOrientation(%this, %spot, %adjustment) { %obj = %this.parObject; if( isObject(%obj) ) { if( %this.editMode $= "position") %change = %obj.position; else %change = %obj.rotation; } else if( %this.delay ) //if its looping %change = %this.lastPosition; if( %change ) { for(%i = 0; %i < 3; %i++) { if(%i == %spot) %temp[%i] = ( getWord(%change, %spot) + %adjustment ); else { %temp[%i] = getWord(%change, %i); if( !%temp[%i] ) %temp[%i] = 0; } } if( %this.editMode $= "position") %change = (%temp[0] @ " " @ %temp[1] @ " " @ %temp[2]); else %change = (%temp[0] @ " " @ %temp[1] @ " " @ %temp[2]); if( isObject(%obj) ) %obj.position = %change; else %this.lastPosition = %change; %this.recreateEmitter(); } } function ParticleEditor::toggleEditMode(%this) { if( %this.EditMode $= "position" ) { %state = "Rotate"; %this.EditMode = "rotation"; } else { %state = "Move"; %this.EditMode = "position"; } Edit_Mode.setValue(%state); } function ParticleEditor::SaveMission(%this) { //open the save dialog if( !isObject( Emitter_Text.getValue() ) ) { MessageBoxYesNo("CONFIRM", "The current particle isn't a datablock and therefore can't be saved in mission.. save anyway?" , "canvas.pushDialog( EditorSaveMissionDlg ); "); } else canvas.pushDialog( EditorSaveMissionDlg ); } function ParticleEditor::nextTexture(%this, %change) { %current = ParticleEditorTextureList.getSelected(); if( %change > 0 ) //positive { %current++; } else if( %change < 0 ) //negative { %current--; if ( %current < 0 ) { %current = (ParticleEditorTextureList.size() - 2); } } ParticleEditorTextureList.setSelected( %current ); %currentValue = ParticleEditorTextureList.getValue(); %this.emitterSliderUpdate(ParticleEditorTextureList, %currentValue); } ////////////////////////////// //gui functions and controls ////////////////////////////// function particleEditor::onWake(%this) { if(!particleEditor.initialized) { ParticleEditor.initializeParticleEditor(); ParticleEditor.initialized = true; } ParticleEditor.soundHandle = alxPlay(AudioButtonOver, 0, 0, 0); if (!Canvas.isCursorOn()) CursorOn(); ParticleEditor.setPane(particleEditor.pane, particleEditor.tab); ParticleEditor.updatehud(); } function ParticleEditor::FillEmitterPopups(%this, %control) { if(ParticleEditor.parChoices) for(%i = 1; %i <= ParticleEditor.parChoices; %i++) %control.add(ParticleEditor.emitters[%i],(%i-1),1); } function ParticleEditorTextureList::FillItem() { %textures = 0; for(%i = 1; %i <= ParticleEditor.parChoices; %i++) { %duplicate = false; %current = ParticleEditor.Emitters[%i].particles.textureName; for(%j = 0; %j <= %textures; %j++) { if(%current $= %texture[%j]) %duplicate = true; } if((%current !$= "") && (!%duplicate)) { ParticleEditorTextureList.add(%current,(%i-1),1); %texture[%textures] = %current; %textures++; } } } function particleEditor::onSleep() { if(isObject(ParticleEditor.soundHandle)) { alxStop(ParticleEditor.soundHandle); ParticleEditor.soundHandle = ""; } if (Canvas.isCursorOn()) CursorOff(); } function ParticleEditor::updateHud(%this) { if(DefaultEmitter $= "") { EMITTER_TEXT.setValue(""); ParticleEditorEmitterPopup.setValue(""); } if( %this.parCurrentMax ) { PARTICLE_TEXT.setValue( ( %this.parCurrent + 1) ); PE_Total_Particles.setValue( %this.parCurrentMax -1 ); } else { PARTICLE_TEXT.setValue("0"); PE_Total_Particles.setValue("0"); } R_SLIDER.setValue(getWord(DefaultEmitter.particles.colors[ParticleEditor.parCurrent],0)); G_SLIDER.setValue(getWord(DefaultEmitter.particles.colors[ParticleEditor.parCurrent],1)); B_SLIDER.setValue(getWord(DefaultEmitter.particles.colors[ParticleEditor.parCurrent],2)); O_SLIDER.setValue(getWord(DefaultEmitter.particles.colors[ParticleEditor.parCurrent],3)); ParticleEditorTextureList.setValue(DefaultEmitter.particles.textureName); Wind_Slider.setValue(DefaultEmitter.particles.windCoefficient); PE_CurrentEmitter.setValue(EMITTER_TEXT.getValue()); ORIENT.setValue(DefaultEmitter.orientParticles); ORIENT_VELOCITY.setValue(DefaultEmitter.orientOnVelocity); OVERRIDE_ADVANCES.setValue(DefaultEmitter.overrideAdvances); EPERIOD_SLIDER.setValue(DefaultEmitter.ejectionPeriodMS); EVARIANCE_SLIDER.setValue(DefaultEmitter.periodVarianceMS); EVELOCITY_SLIDER.setValue(DefaultEmitter.ejectionVelocity); EOFFSET_SLIDER.setValue(DefaultEmitter.ejectionOffset); EVELVARIANCE_SLIDER.setValue(DefaultEmitter.velocityVariance); EOFFSET_SLIDER.setValue(DefaultEmitter.ejectionOffset); THETAMIN_SLIDER.setValue(DefaultEmitter.thetaMin); THETAMAX_SLIDER.setValue(DefaultEmitter.thetaMax); PHIREFVEL_SLIDER.setValue(DefaultEmitter.phiReferenceVel); PHIVAR_SLIDER.setValue(DefaultEmitter.phiVariance); SIZES_SLIDER.setValue(DefaultEmitter.particles.sizes[ParticleEditor.parCurrent]); TIMES_SLIDER.setValue(DefaultEmitter.particles.times[ParticleEditor.parCurrent]); if( (ParticleEditor.parCurrent) && (ParticleEditor.parCurrent < (ParticleEditor.parCurrentMax - 1)) ) { TIMES_SLIDER.setVisible(1); Blend_Text.setVisible(1); } else //hide them when they can't be used anyway { TIMES_SLIDER.setVisible(0); Blend_Text.setVisible(0); } DRAG_SLIDER.setValue(DefaultEmitter.particles.dragCoefficient); GRAVITY_SLIDER.setValue(DefaultEmitter.particles.gravityCoefficient); InVELOCITY_SLIDER.setValue(DefaultEmitter.particles.inheritedVelFactor); ConACC_SLIDER.setValue(DefaultEmitter.particles.constantAcceleration); INV_ALPHA.setValue(DefaultEmitter.particles.useInvAlpha); LifeMS_SLIDER.setValue(DefaultEmitter.particles.lifetimeMS); LifeVAR_SLIDER.setValue(DefaultEmitter.particles.lifetimeVarianceMS); SpinMIN_SLIDER.setValue(DefaultEmitter.particles.spinRandomMin); SpinMAX_SLIDER.setValue(DefaultEmitter.particles.spinRandomMax); //text PE_emitterLifeText.setValue(mFloor( PE_emitterLife.getValue() ) ); PE_emitterLifeTextWorld.setValue( PE_emitterLifeText.getValue() ); PE_redText.setValue(R_SLIDER.getValue()); PE_greenText.setValue(G_SLIDER.getValue()); PE_blueText.setValue(B_SLIDER.getValue()); PE_opacityText.setValue(O_SLIDER.getValue()); } function ParticleEditor::emitterSliderUpdate(%this, %slider, %value) { switch$ ( %slider ) { case "EPERIOD_SLIDER": DefaultEmitter.ejectionPeriodMS = %value; case "EVARIANCE_SLIDER": DefaultEmitter.periodVarianceMS = %value; case "EVELOCITY_SLIDER": DefaultEmitter.ejectionVelocity = %value; case "EVELVARIANCE_SLIDER": DefaultEmitter.velocityVariance = %value; case "EOFFSET_SLIDER": DefaultEmitter.ejectionOffset = %value; case "THETAMIN_SLIDER": DefaultEmitter.thetaMin = %value; case "THETAMAX_SLIDER": DefaultEmitter.thetaMax = %value; case "PHIREFVEL_SLIDER": DefaultEmitter.phiReferenceVel = %value; case "PHIVAR_SLIDER": DefaultEmitter.phiVariance = %value; case "ORIENT_VELOCITY": DefaultEmitter.orientOnVelocity = %value; case "ORIENT": DefaultEmitter.orientParticles = %value; case "OVERRIDE_ADVANCES": DefaultEmitter.overrideAdvances = %value; case "ParticleEditorTextureList": DefaultEmitter.particles.textureName = %value; case "Wind_Slider": DefaultEmitter.particles.windCoefficient = %value; case "SIZES_SLIDER": DefaultEmitter.particles.sizes[ParticleEditor.parCurrent] = %value; case "TIMES_SLIDER": ParticleEditor.checktime(%value); case "DRAG_SLIDER": DefaultEmitter.particles.dragCoefficient = %value; case "GRAVITY_SLIDER": DefaultEmitter.particles.gravityCoefficient = %value; case "InVELOCITY_SLIDER": DefaultEmitter.particles.inheritedVelFactor = %value; case "ConACC_SLIDER": DefaultEmitter.particles.constantAcceleration = %value; case "INV_ALPHA": DefaultEmitter.particles.useInvAlpha = %value; case "LifeMS_SLIDER": DefaultEmitter.particles.lifetimeMS = %value; case "LifeVAR_SLIDER": DefaultEmitter.particles.lifetimeVarianceMS = %value; case "SpinMIN_SLIDER": DefaultEmitter.particles.spinRandomMin = %value; case "SpinMAX_SLIDER": DefaultEmitter.particles.spinRandomMax = %value; case "SpinSPEED_SLIDER": DefaultEmitter.particles.spinSpeed = %value; case "R_SLIDER": ParticleEditor.colorParticle(0, %value); case "G_SLIDER": ParticleEditor.colorParticle(1, %value); case "B_SLIDER": ParticleEditor.colorParticle(2, %value); case "O_SLIDER": ParticleEditor.colorParticle(3, %value); } if(ParticleEditor.parObject) particleEditor.recreateEmitter(); } function ParticleEditor::setPane(%this, %pane, %tab) { if(%pane $= "") //set default pane { %pane = "LoadSavePane"; %tab = "LoadSaveTab"; } LoadSavePane.setVisible(false); Particle1Pane.setVisible(false); //Particle2Pane.setVisible(false); //Particle3Pane.setVisible(false); //Particle4Pane.setVisible(false); EmitterPane.setVisible(false); WorldPane.setVisible(false); LoadSaveTab.setValue(false); Particle1Tab.setValue(false); //Particle2Tab.setValue(false); //Particle3Tab.setValue(false); //Particle4Tab.setValue(false); EmitterTab.setValue(false); WorldTab.setValue(false); %pane.setVisible(true); %tab.setValue(true); ParticleEditor.pane = %pane; ParticleEditor.tab = %tab; } function ParticleEditor::fillLoadList() { for(%i = 1; ($PARTICLE::SAVE[%i] !$= ""); %i++) { particleEditorSavePopup.add(getWord($PARTICLE::SAVE[%i],0), (%i-1)); } } // TODO: Clean this function up function ParticleEditor::fillTextureList() { %index = 0; //initialize ParticleEditorTexturePopup.add( "particles" , %index ); %fileSpec = $PE::ParticleImagePath; %overhead = ( strLen(%fileSpec) - 4 ); //5 is for (*.png) for ( %file = findFirstFile( %fileSpec ); %file !$= ""; %file = findNextFile( %fileSpec ) ) { %length = strLen( %file ); %groupAdded = false; //%texture = getSubStr( %file, %overhead, (%length - 5) ); %texture = %file; //find root group if( (%lastGroup $= getSubStr( %file, %overhead, strLen(%lastGroup) ) ) && ( %lastGroup !$= "") )//same group as last? %group = %lastGroup; else { %groupIndex = %overhead; //start in the textures group %group = ""; for(%i = %overhead; %i < %length ; %i++) { %test = getSubStr( %file, %i, 1);//current char if( %test $= "/") //root down { %group = getSubStr( %file, %groupIndex, (%i - %groupIndex) ); %groupIndex = ( %i + 1 ); } } } //find out if this texture has a group available for(%j = 0; %j <= %index; %j++) { if( %group $= "") { %groupAdded = true; %flagged = false; %existing = false; for(%l = 0; !%flagged && !%existing; %l++) { if( ParticleEditorTexturePopup.texture[ 0, %l ] $= "" ) { ParticleEditorTexturePopup.texture[ 0, %l ] = %texture; %flagged = true; %lastGroup = %group; } if( ParticleEditorTexturePopup.texture[ 0, %l ] $= %texture ) { %existing = true; %flagged = true; %lastGroup = %group; } } } else if( (ParticleEditorTexturePopup.getTextByID( %j ) $= %group) ) { %groupAdded = true; %flagged = false; for(%l = 0; !%flagged; %l++) { if( ParticleEditorTexturePopup.texture[ %j, %l ] $= "" ) { ParticleEditorTexturePopup.texture[ %j, %l ] = %texture; %flagged = true; %lastGroup = %group; } } } } if( !%groupAdded )//making a new group { ParticleEditorTexturePopup.add( %group, ( %index++ ) ); ParticleEditorTexturePopup.texture[ %index, 0 ] = %texture; %lastGroup = %group; } } } function ParticleEditor::textureFill(%this, %element, %fileSpec) { ParticleEditorTextureList.clear(); for(%i = 0; ParticleEditorTexturePopup.texture[ %element, %i ] !$= ""; %i++) ParticleEditorTextureList.add( ParticleEditorTexturePopup.texture[ %element, %i ], %i ); }