From 113961fd2a2203434b03766d722a0f8c0854bfd0 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Thu, 19 Jul 2012 19:29:15 +0200 Subject: WINTERMUTE: Change all folder-names to lowercase. --- engines/wintermute/base/particles/PartEmitter.cpp | 1199 ++++++++++++++++++++ engines/wintermute/base/particles/PartEmitter.h | 139 +++ engines/wintermute/base/particles/PartForce.cpp | 59 + engines/wintermute/base/particles/PartForce.h | 57 + engines/wintermute/base/particles/PartParticle.cpp | 257 +++++ engines/wintermute/base/particles/PartParticle.h | 90 ++ 6 files changed, 1801 insertions(+) create mode 100644 engines/wintermute/base/particles/PartEmitter.cpp create mode 100644 engines/wintermute/base/particles/PartEmitter.h create mode 100644 engines/wintermute/base/particles/PartForce.cpp create mode 100644 engines/wintermute/base/particles/PartForce.h create mode 100644 engines/wintermute/base/particles/PartParticle.cpp create mode 100644 engines/wintermute/base/particles/PartParticle.h (limited to 'engines/wintermute/base/particles') diff --git a/engines/wintermute/base/particles/PartEmitter.cpp b/engines/wintermute/base/particles/PartEmitter.cpp new file mode 100644 index 0000000000..81147a5432 --- /dev/null +++ b/engines/wintermute/base/particles/PartEmitter.cpp @@ -0,0 +1,1199 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/dcgf.h" +#include "engines/wintermute/base/particles/PartEmitter.h" +#include "engines/wintermute/base/particles/PartParticle.h" +#include "engines/wintermute/math/Vector2.h" +#include "engines/wintermute/math/Matrix4.h" +#include "engines/wintermute/base/scriptables/ScValue.h" +#include "engines/wintermute/base/scriptables/ScStack.h" +#include "engines/wintermute/base/BGame.h" +#include "engines/wintermute/base/BRegion.h" +#include "engines/wintermute/base/BFileManager.h" +#include "engines/wintermute/utils/utils.h" +#include "engines/wintermute/PlatformSDL.h" +#include "common/str.h" +#include "common/math.h" + +namespace WinterMute { + +IMPLEMENT_PERSISTENT(CPartEmitter, false) + +////////////////////////////////////////////////////////////////////////// +CPartEmitter::CPartEmitter(CBGame *inGame, CBScriptHolder *Owner) : CBObject(inGame) { + _width = _height = 0; + + CBPlatform::setRectEmpty(&_border); + _borderThicknessLeft = _borderThicknessRight = _borderThicknessTop = _borderThicknessBottom = 0; + + _angle1 = _angle2 = 0; + + _velocity1 = _velocity2 = 0.0f; + _velocityZBased = false; + + _scale1 = _scale2 = 100.0f; + _scaleZBased = false; + + _maxParticles = 100; + + _lifeTime1 = _lifeTime2 = 1000; + _lifeTimeZBased = false; + + _lastGenTime = 0; + _genInterval = 0; + _genAmount = 1; + + _overheadTime = 0; + _running = false; + + _maxBatches = 0; + _batchesGenerated = 0; + + _fadeInTime = _fadeOutTime = 0; + + _alpha1 = _alpha2 = 255; + _alphaTimeBased = false; + + _rotation1 = _rotation2 = 0.0f; + _angVelocity1 = _angVelocity2 = 0.0f; + + _growthRate1 = _growthRate2 = 0.0f; + _exponentialGrowth = false; + + _useRegion = false; + + _emitEvent = NULL; + _owner = Owner; +} + + +////////////////////////////////////////////////////////////////////////// +CPartEmitter::~CPartEmitter(void) { + for (int i = 0; i < _particles.getSize(); i++) { + delete _particles[i]; + } + _particles.removeAll(); + + for (int i = 0; i < _forces.getSize(); i++) { + delete _forces[i]; + } + _forces.removeAll(); + + + for (int i = 0; i < _sprites.getSize(); i++) { + delete [] _sprites[i]; + } + _sprites.removeAll(); + + delete[] _emitEvent; + _emitEvent = NULL; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::addSprite(const char *filename) { + if (!filename) return STATUS_FAILED; + + // do we already have the file? + for (int i = 0; i < _sprites.getSize(); i++) { + if (scumm_stricmp(filename, _sprites[i]) == 0) return STATUS_OK; + } + + // check if file exists + Common::SeekableReadStream *File = _gameRef->_fileManager->openFile(filename); + if (!File) { + _gameRef->LOG(0, "Sprite '%s' not found", filename); + return STATUS_FAILED; + } else _gameRef->_fileManager->closeFile(File); + + char *Str = new char[strlen(filename) + 1]; + strcpy(Str, filename); + _sprites.add(Str); + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::removeSprite(const char *filename) { + for (int i = 0; i < _sprites.getSize(); i++) { + if (scumm_stricmp(filename, _sprites[i]) == 0) { + delete [] _sprites[i]; + _sprites.removeAt(i); + return STATUS_OK; + } + } + return STATUS_FAILED; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::initParticle(CPartParticle *particle, uint32 currentTime, uint32 timerDelta) { + if (!particle) return STATUS_FAILED; + if (_sprites.getSize() == 0) return STATUS_FAILED; + + int posX = CBUtils::randomInt(_posX, _posX + _width); + int posY = CBUtils::randomInt(_posY, _posY + _height); + float posZ = CBUtils::randomFloat(0.0f, 100.0f); + + float velocity; + if (_velocityZBased) velocity = _velocity1 + posZ * (_velocity2 - _velocity1) / 100; + else velocity = CBUtils::randomFloat(_velocity1, _velocity2); + + float scale; + if (_scaleZBased) scale = _scale1 + posZ * (_scale2 - _scale1) / 100; + else scale = CBUtils::randomFloat(_scale1, _scale2); + + int lifeTime; + if (_lifeTimeZBased) lifeTime = _lifeTime2 - posZ * (_lifeTime2 - _lifeTime1) / 100; + else lifeTime = CBUtils::randomInt(_lifeTime1, _lifeTime2); + + float angle = CBUtils::randomAngle(_angle1, _angle2); + int spriteIndex = CBUtils::randomInt(0, _sprites.getSize() - 1); + + float rotation = CBUtils::randomAngle(_rotation1, _rotation2); + float angVelocity = CBUtils::randomFloat(_angVelocity1, _angVelocity2); + float growthRate = CBUtils::randomFloat(_growthRate1, _growthRate2); + + if (!CBPlatform::isRectEmpty(&_border)) { + int thicknessLeft = (int)(_borderThicknessLeft - (float)_borderThicknessLeft * posZ / 100.0f); + int thicknessRight = (int)(_borderThicknessRight - (float)_borderThicknessRight * posZ / 100.0f); + int thicknessTop = (int)(_borderThicknessTop - (float)_borderThicknessTop * posZ / 100.0f); + int thicknessBottom = (int)(_borderThicknessBottom - (float)_borderThicknessBottom * posZ / 100.0f); + + particle->_border = _border; + particle->_border.left += thicknessLeft; + particle->_border.right -= thicknessRight; + particle->_border.top += thicknessTop; + particle->_border.bottom -= thicknessBottom; + } + + Vector2 vecPos((float)posX, (float)posY); + Vector2 vecVel(0, velocity); + + Matrix4 matRot; + matRot.rotationZ(Common::deg2rad(CBUtils::normalizeAngle(angle - 180))); + matRot.transformVector2(vecVel); + + if (_alphaTimeBased) { + particle->_alpha1 = _alpha1; + particle->_alpha2 = _alpha2; + } else { + int alpha = CBUtils::randomInt(_alpha1, _alpha2); + particle->_alpha1 = alpha; + particle->_alpha2 = alpha; + } + + particle->_creationTime = currentTime; + particle->_pos = vecPos; + particle->_posZ = posZ; + particle->_velocity = vecVel; + particle->_scale = scale; + particle->_lifeTime = lifeTime; + particle->_rotation = rotation; + particle->_angVelocity = angVelocity; + particle->_growthRate = growthRate; + particle->_exponentialGrowth = _exponentialGrowth; + particle->_isDead = DID_FAIL(particle->setSprite(_sprites[spriteIndex])); + particle->fadeIn(currentTime, _fadeInTime); + + + if (particle->_isDead) return STATUS_FAILED; + else return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::update() { + if (!_running) return STATUS_OK; + else return updateInternal(_gameRef->_timer, _gameRef->_timerDelta); +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::updateInternal(uint32 currentTime, uint32 timerDelta) { + int numLive = 0; + + for (int i = 0; i < _particles.getSize(); i++) { + _particles[i]->update(this, currentTime, timerDelta); + + if (!_particles[i]->_isDead) numLive++; + } + + + // we're understaffed + if (numLive < _maxParticles) { + bool needsSort = false; + if ((int)(currentTime - _lastGenTime) > _genInterval) { + _lastGenTime = currentTime; + _batchesGenerated++; + + if (_maxBatches > 0 && _batchesGenerated > _maxBatches) { + return STATUS_OK; + } + + int toGen = MIN(_genAmount, _maxParticles - numLive); + while (toGen > 0) { + int firstDeadIndex = -1; + for (int i = 0; i < _particles.getSize(); i++) { + if (_particles[i]->_isDead) { + firstDeadIndex = i; + break; + } + } + + CPartParticle *particle; + if (firstDeadIndex >= 0) particle = _particles[firstDeadIndex]; + else { + particle = new CPartParticle(_gameRef); + _particles.add(particle); + } + initParticle(particle, currentTime, timerDelta); + needsSort = true; + + toGen--; + } + } + if (needsSort && (_scaleZBased || _velocityZBased || _lifeTimeZBased)) + sortParticlesByZ(); + + // we actually generated some particles and we're not in fast-forward mode + if (needsSort && _overheadTime == 0) { + if (_owner && _emitEvent) _owner->applyEvent(_emitEvent); + } + } + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::display(CBRegion *region) { + if (_sprites.getSize() <= 1) _gameRef->_renderer->startSpriteBatch(); + + for (int i = 0; i < _particles.getSize(); i++) { + if (region != NULL && _useRegion) { + if (!region->pointInRegion((int)_particles[i]->_pos.x, (int)_particles[i]->_pos.y)) continue; + } + + _particles[i]->display(this); + } + + if (_sprites.getSize() <= 1) _gameRef->_renderer->endSpriteBatch(); + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::start() { + for (int i = 0; i < _particles.getSize(); i++) { + _particles[i]->_isDead = true; + } + _running = true; + _batchesGenerated = 0; + + + if (_overheadTime > 0) { + uint32 delta = 500; + int steps = _overheadTime / delta; + uint32 currentTime = _gameRef->_timer - _overheadTime; + + for (int i = 0; i < steps; i++) { + updateInternal(currentTime, delta); + currentTime += delta; + } + _overheadTime = 0; + } + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::sortParticlesByZ() { + // sort particles by _posY + qsort(_particles.getData(), _particles.getSize(), sizeof(CPartParticle *), CPartEmitter::compareZ); + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +int CPartEmitter::compareZ(const void *obj1, const void *obj2) { + CPartParticle *p1 = *(CPartParticle **)obj1; + CPartParticle *p2 = *(CPartParticle **)obj2; + + if (p1->_posZ < p2->_posZ) return -1; + else if (p1->_posZ > p2->_posZ) return 1; + else return 0; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::setBorder(int x, int y, int width, int height) { + CBPlatform::setRect(&_border, x, y, x + width, y + height); + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::setBorderThickness(int thicknessLeft, int thicknessRight, int thicknessTop, int thicknessBottom) { + _borderThicknessLeft = thicknessLeft; + _borderThicknessRight = thicknessRight; + _borderThicknessTop = thicknessTop; + _borderThicknessBottom = thicknessBottom; + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +CPartForce *CPartEmitter::addForceByName(const char *name) { + CPartForce *force = NULL; + + for (int i = 0; i < _forces.getSize(); i++) { + if (scumm_stricmp(name, _forces[i]->_name) == 0) { + force = _forces[i]; + break; + } + } + if (!force) { + force = new CPartForce(_gameRef); + if (force) { + force->setName(name); + _forces.add(force); + } + } + return force; +} + + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::addForce(const char *name, CPartForce::TForceType type, int posX, int posY, float angle, float strength) { + CPartForce *force = addForceByName(name); + if (!force) return STATUS_FAILED; + + force->_type = type; + force->_pos = Vector2(posX, posY); + + force->_direction = Vector2(0, strength); + Matrix4 matRot; + matRot.rotationZ(Common::deg2rad(CBUtils::normalizeAngle(angle - 180))); + matRot.transformVector2(force->_direction); + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::removeForce(const char *name) { + for (int i = 0; i < _forces.getSize(); i++) { + if (scumm_stricmp(name, _forces[i]->_name) == 0) { + delete _forces[i]; + _forces.removeAt(i); + return STATUS_OK; + } + } + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +// high level scripting interface +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name) { + ////////////////////////////////////////////////////////////////////////// + // SetBorder + ////////////////////////////////////////////////////////////////////////// + if (strcmp(name, "SetBorder") == 0) { + stack->correctParams(4); + int borderX = stack->pop()->getInt(); + int borderY = stack->pop()->getInt(); + int borderWidth = stack->pop()->getInt(); + int borderHeight = stack->pop()->getInt(); + + stack->pushBool(DID_SUCCEED(setBorder(borderX, borderY, borderWidth, borderHeight))); + + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // SetBorderThickness + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "SetBorderThickness") == 0) { + stack->correctParams(4); + int left = stack->pop()->getInt(); + int right = stack->pop()->getInt(); + int top = stack->pop()->getInt(); + int bottom = stack->pop()->getInt(); + + stack->pushBool(DID_SUCCEED(setBorderThickness(left, right, top, bottom))); + + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // AddSprite + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "AddSprite") == 0) { + stack->correctParams(1); + const char *spriteFile = stack->pop()->getString(); + stack->pushBool(DID_SUCCEED(addSprite(spriteFile))); + + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // RemoveSprite + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "RemoveSprite") == 0) { + stack->correctParams(1); + const char *spriteFile = stack->pop()->getString(); + stack->pushBool(DID_SUCCEED(removeSprite(spriteFile))); + + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Start + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Start") == 0) { + stack->correctParams(1); + _overheadTime = stack->pop()->getInt(); + stack->pushBool(DID_SUCCEED(start())); + + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Stop + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Stop") == 0) { + stack->correctParams(0); + + for (int i = 0; i < _particles.getSize(); i++) { + delete _particles[i]; + } + _particles.removeAll(); + + _running = false; + stack->pushBool(true); + + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Pause + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Pause") == 0) { + stack->correctParams(0); + _running = false; + stack->pushBool(true); + + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Resume + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Resume") == 0) { + stack->correctParams(0); + _running = true; + stack->pushBool(true); + + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // AddGlobalForce + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "AddGlobalForce") == 0) { + stack->correctParams(3); + const char *forceName = stack->pop()->getString(); + float angle = stack->pop()->getFloat(); + float strength = stack->pop()->getFloat(); + + stack->pushBool(DID_SUCCEED(addForce(forceName, CPartForce::FORCE_GLOBAL, 0, 0, angle, strength))); + + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // AddPointForce + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "AddPointForce") == 0) { + stack->correctParams(5); + const char *forceName = stack->pop()->getString(); + int posX = stack->pop()->getInt(); + int posY = stack->pop()->getInt(); + float angle = stack->pop()->getFloat(); + float strength = stack->pop()->getFloat(); + + stack->pushBool(DID_SUCCEED(addForce(forceName, CPartForce::FORCE_GLOBAL, posX, posY, angle, strength))); + + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // RemoveForce + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "RemoveForce") == 0) { + stack->correctParams(1); + const char *forceName = stack->pop()->getString(); + + stack->pushBool(DID_SUCCEED(removeForce(forceName))); + + return STATUS_OK; + } + + else return CBObject::scCallMethod(script, stack, thisStack, name); +} + +////////////////////////////////////////////////////////////////////////// +CScValue *CPartEmitter::scGetProperty(const char *name) { + _scValue->setNULL(); + + ////////////////////////////////////////////////////////////////////////// + // Type + ////////////////////////////////////////////////////////////////////////// + if (strcmp(name, "Type") == 0) { + _scValue->setString("particle-emitter"); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // X + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "X") == 0) { + _scValue->setInt(_posX); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // Y + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Y") == 0) { + _scValue->setInt(_posY); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // Width + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Width") == 0) { + _scValue->setInt(_width); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // Height + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Height") == 0) { + _scValue->setInt(_height); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Scale1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Scale1") == 0) { + _scValue->setFloat(_scale1); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // Scale2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Scale2") == 0) { + _scValue->setFloat(_scale2); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // ScaleZBased + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "ScaleZBased") == 0) { + _scValue->setBool(_scaleZBased); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Velocity1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Velocity1") == 0) { + _scValue->setFloat(_velocity1); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // Velocity2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Velocity2") == 0) { + _scValue->setFloat(_velocity2); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // VelocityZBased + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "VelocityZBased") == 0) { + _scValue->setBool(_velocityZBased); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // LifeTime1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "LifeTime1") == 0) { + _scValue->setInt(_lifeTime1); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // LifeTime2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "LifeTime2") == 0) { + _scValue->setInt(_lifeTime2); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // LifeTimeZBased + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "LifeTimeZBased") == 0) { + _scValue->setBool(_lifeTimeZBased); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Angle1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Angle1") == 0) { + _scValue->setInt(_angle1); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // Angle2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Angle2") == 0) { + _scValue->setInt(_angle2); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // AngVelocity1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "AngVelocity1") == 0) { + _scValue->setFloat(_angVelocity1); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // AngVelocity2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "AngVelocity2") == 0) { + _scValue->setFloat(_angVelocity2); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Rotation1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Rotation1") == 0) { + _scValue->setFloat(_rotation1); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // Rotation2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Rotation2") == 0) { + _scValue->setFloat(_rotation2); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Alpha1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Alpha1") == 0) { + _scValue->setInt(_alpha1); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // Alpha2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Alpha2") == 0) { + _scValue->setInt(_alpha2); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // AlphaTimeBased + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "AlphaTimeBased") == 0) { + _scValue->setBool(_alphaTimeBased); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // MaxParticles + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "MaxParticles") == 0) { + _scValue->setInt(_maxParticles); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // NumLiveParticles (RO) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "NumLiveParticles") == 0) { + int numAlive = 0; + for (int i = 0; i < _particles.getSize(); i++) { + if (_particles[i] && !_particles[i]->_isDead) numAlive++; + } + _scValue->setInt(numAlive); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // GenerationInterval + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GenerationInterval") == 0) { + _scValue->setInt(_genInterval); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // GenerationAmount + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GenerationAmount") == 0) { + _scValue->setInt(_genAmount); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // MaxBatches + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "MaxBatches") == 0) { + _scValue->setInt(_maxBatches); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // FadeInTime + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "FadeInTime") == 0) { + _scValue->setInt(_fadeInTime); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // FadeOutTime + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "FadeOutTime") == 0) { + _scValue->setInt(_fadeOutTime); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // GrowthRate1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GrowthRate1") == 0) { + _scValue->setFloat(_growthRate1); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // GrowthRate2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GrowthRate2") == 0) { + _scValue->setFloat(_growthRate2); + return _scValue; + } + ////////////////////////////////////////////////////////////////////////// + // ExponentialGrowth + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "ExponentialGrowth") == 0) { + _scValue->setBool(_exponentialGrowth); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // UseRegion + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "UseRegion") == 0) { + _scValue->setBool(_useRegion); + return _scValue; + } + + ////////////////////////////////////////////////////////////////////////// + // EmitEvent + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "EmitEvent") == 0) { + if (!_emitEvent) _scValue->setNULL(); + else _scValue->setString(_emitEvent); + return _scValue; + } + + else return CBObject::scGetProperty(name); +} + + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::scSetProperty(const char *name, CScValue *value) { + ////////////////////////////////////////////////////////////////////////// + // X + ////////////////////////////////////////////////////////////////////////// + if (strcmp(name, "X") == 0) { + _posX = value->getInt(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // Y + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Y") == 0) { + _posY = value->getInt(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // Width + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Width") == 0) { + _width = value->getInt(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // Height + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Height") == 0) { + _height = value->getInt(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Scale1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Scale1") == 0) { + _scale1 = value->getFloat(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // Scale2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Scale2") == 0) { + _scale2 = value->getFloat(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // ScaleZBased + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "ScaleZBased") == 0) { + _scaleZBased = value->getBool(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Velocity1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Velocity1") == 0) { + _velocity1 = value->getFloat(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // Velocity2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Velocity2") == 0) { + _velocity2 = value->getFloat(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // VelocityZBased + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "VelocityZBased") == 0) { + _velocityZBased = value->getBool(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // LifeTime1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "LifeTime1") == 0) { + _lifeTime1 = value->getInt(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // LifeTime2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "LifeTime2") == 0) { + _lifeTime2 = value->getInt(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // LifeTimeZBased + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "LifeTimeZBased") == 0) { + _lifeTimeZBased = value->getBool(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Angle1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Angle1") == 0) { + _angle1 = value->getInt(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // Angle2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Angle2") == 0) { + _angle2 = value->getInt(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // AngVelocity1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "AngVelocity1") == 0) { + _angVelocity1 = value->getFloat(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // AngVelocity2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "AngVelocity2") == 0) { + _angVelocity2 = value->getFloat(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Rotation1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Rotation1") == 0) { + _rotation1 = value->getFloat(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // Rotation2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Rotation2") == 0) { + _rotation2 = value->getFloat(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Alpha1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Alpha1") == 0) { + _alpha1 = value->getInt(); + if (_alpha1 < 0) _alpha1 = 0; + if (_alpha1 > 255) _alpha1 = 255; + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // Alpha2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "Alpha2") == 0) { + _alpha2 = value->getInt(); + if (_alpha2 < 0) _alpha2 = 0; + if (_alpha2 > 255) _alpha2 = 255; + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // AlphaTimeBased + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "AlphaTimeBased") == 0) { + _alphaTimeBased = value->getBool(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // MaxParticles + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "MaxParticles") == 0) { + _maxParticles = value->getInt(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GenerationInterval + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GenerationInterval") == 0) { + _genInterval = value->getInt(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // GenerationAmount + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GenerationAmount") == 0) { + _genAmount = value->getInt(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // MaxBatches + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "MaxBatches") == 0) { + _maxBatches = value->getInt(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // FadeInTime + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "FadeInTime") == 0) { + _fadeInTime = value->getInt(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // FadeOutTime + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "FadeOutTime") == 0) { + _fadeOutTime = value->getInt(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GrowthRate1 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GrowthRate1") == 0) { + _growthRate1 = value->getFloat(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // GrowthRate2 + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "GrowthRate2") == 0) { + _growthRate2 = value->getFloat(); + return STATUS_OK; + } + ////////////////////////////////////////////////////////////////////////// + // ExponentialGrowth + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "ExponentialGrowth") == 0) { + _exponentialGrowth = value->getBool(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // UseRegion + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "UseRegion") == 0) { + _useRegion = value->getBool(); + return STATUS_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // EmitEvent + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(name, "EmitEvent") == 0) { + delete[] _emitEvent; + _emitEvent = NULL; + if (!value->isNULL()) CBUtils::setString(&_emitEvent, value->getString()); + return STATUS_OK; + } + + else return CBObject::scSetProperty(name, value); +} + + +////////////////////////////////////////////////////////////////////////// +const char *CPartEmitter::scToString() { + return "[particle emitter]"; +} + + + + +////////////////////////////////////////////////////////////////////////// +bool CPartEmitter::persist(CBPersistMgr *persistMgr) { + CBObject::persist(persistMgr); + + persistMgr->transfer(TMEMBER(_width)); + persistMgr->transfer(TMEMBER(_height)); + + persistMgr->transfer(TMEMBER(_angle1)); + persistMgr->transfer(TMEMBER(_angle2)); + + persistMgr->transfer(TMEMBER(_velocity1)); + persistMgr->transfer(TMEMBER(_velocity2)); + persistMgr->transfer(TMEMBER(_velocityZBased)); + + persistMgr->transfer(TMEMBER(_scale1)); + persistMgr->transfer(TMEMBER(_scale2)); + persistMgr->transfer(TMEMBER(_scaleZBased)); + + persistMgr->transfer(TMEMBER(_maxParticles)); + + persistMgr->transfer(TMEMBER(_lifeTime1)); + persistMgr->transfer(TMEMBER(_lifeTime2)); + persistMgr->transfer(TMEMBER(_lifeTimeZBased)); + + persistMgr->transfer(TMEMBER(_genInterval)); + persistMgr->transfer(TMEMBER(_genAmount)); + + persistMgr->transfer(TMEMBER(_running)); + persistMgr->transfer(TMEMBER(_overheadTime)); + + persistMgr->transfer(TMEMBER(_border)); + persistMgr->transfer(TMEMBER(_borderThicknessLeft)); + persistMgr->transfer(TMEMBER(_borderThicknessRight)); + persistMgr->transfer(TMEMBER(_borderThicknessTop)); + persistMgr->transfer(TMEMBER(_borderThicknessBottom)); + + persistMgr->transfer(TMEMBER(_fadeInTime)); + persistMgr->transfer(TMEMBER(_fadeOutTime)); + + persistMgr->transfer(TMEMBER(_alpha1)); + persistMgr->transfer(TMEMBER(_alpha2)); + persistMgr->transfer(TMEMBER(_alphaTimeBased)); + + persistMgr->transfer(TMEMBER(_angVelocity1)); + persistMgr->transfer(TMEMBER(_angVelocity2)); + + persistMgr->transfer(TMEMBER(_rotation1)); + persistMgr->transfer(TMEMBER(_rotation2)); + + persistMgr->transfer(TMEMBER(_growthRate1)); + persistMgr->transfer(TMEMBER(_growthRate2)); + persistMgr->transfer(TMEMBER(_exponentialGrowth)); + + persistMgr->transfer(TMEMBER(_useRegion)); + + persistMgr->transfer(TMEMBER_INT(_maxBatches)); + persistMgr->transfer(TMEMBER_INT(_batchesGenerated)); + + persistMgr->transfer(TMEMBER(_emitEvent)); + persistMgr->transfer(TMEMBER(_owner)); + + + _sprites.persist(persistMgr); + + int numForces; + if (persistMgr->_saving) { + numForces = _forces.getSize(); + persistMgr->transfer(TMEMBER(numForces)); + for (int i = 0; i < _forces.getSize(); i++) { + _forces[i]->persist(persistMgr); + } + } else { + persistMgr->transfer(TMEMBER(numForces)); + for (int i = 0; i < numForces; i++) { + CPartForce *force = new CPartForce(_gameRef); + force->persist(persistMgr); + _forces.add(force); + } + } + + int numParticles; + if (persistMgr->_saving) { + numParticles = _particles.getSize(); + persistMgr->transfer(TMEMBER(numParticles)); + for (int i = 0; i < _particles.getSize(); i++) { + _particles[i]->persist(persistMgr); + } + } else { + persistMgr->transfer(TMEMBER(numParticles)); + for (int i = 0; i < numParticles; i++) { + CPartParticle *particle = new CPartParticle(_gameRef); + particle->persist(persistMgr); + _particles.add(particle); + } + } + + return STATUS_OK; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/base/particles/PartEmitter.h b/engines/wintermute/base/particles/PartEmitter.h new file mode 100644 index 0000000000..5156783653 --- /dev/null +++ b/engines/wintermute/base/particles/PartEmitter.h @@ -0,0 +1,139 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_PARTEMITTER_H +#define WINTERMUTE_PARTEMITTER_H + + +#include "engines/wintermute/base/BObject.h" +#include "engines/wintermute/base/particles/PartForce.h" + +namespace WinterMute { +class CBRegion; +class CPartParticle; +class CPartEmitter : public CBObject { +public: + DECLARE_PERSISTENT(CPartEmitter, CBObject) + + CPartEmitter(CBGame *inGame, CBScriptHolder *Owner); + virtual ~CPartEmitter(void); + + int _width; + int _height; + + int _angle1; + int _angle2; + + float _rotation1; + float _rotation2; + + float _angVelocity1; + float _angVelocity2; + + float _growthRate1; + float _growthRate2; + bool _exponentialGrowth; + + float _velocity1; + float _velocity2; + bool _velocityZBased; + + float _scale1; + float _scale2; + bool _scaleZBased; + + int _maxParticles; + + int _lifeTime1; + int _lifeTime2; + bool _lifeTimeZBased; + + int _genInterval; + int _genAmount; + + bool _running; + int _overheadTime; + + int _maxBatches; + int _batchesGenerated; + + Rect32 _border; + int _borderThicknessLeft; + int _borderThicknessRight; + int _borderThicknessTop; + int _borderThicknessBottom; + + int _fadeInTime; + int _fadeOutTime; + + int _alpha1; + int _alpha2; + bool _alphaTimeBased; + + bool _useRegion; + + char *_emitEvent; + CBScriptHolder *_owner; + + bool start(); + + bool update(); + bool display() { return display(NULL); } // To avoid shadowing the inherited display-function. + bool display(CBRegion *region); + + bool sortParticlesByZ(); + bool addSprite(const char *filename); + bool removeSprite(const char *filename); + bool setBorder(int x, int y, int width, int height); + bool setBorderThickness(int thicknessLeft, int thicknessRight, int thicknessTop, int thicknessBottom); + + bool addForce(const char *name, CPartForce::TForceType type, int posX, int posY, float angle, float strength); + bool removeForce(const char *name); + + CBArray _forces; + + // scripting interface + virtual CScValue *scGetProperty(const char *name); + virtual bool scSetProperty(const char *name, CScValue *value); + virtual bool scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name); + virtual const char *scToString(); + + +private: + CPartForce *addForceByName(const char *name); + int static compareZ(const void *obj1, const void *obj2); + bool initParticle(CPartParticle *particle, uint32 currentTime, uint32 timerDelta); + bool updateInternal(uint32 currentTime, uint32 timerDelta); + uint32 _lastGenTime; + CBArray _particles; + CBArray _sprites; +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/base/particles/PartForce.cpp b/engines/wintermute/base/particles/PartForce.cpp new file mode 100644 index 0000000000..b864c05292 --- /dev/null +++ b/engines/wintermute/base/particles/PartForce.cpp @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/dcgf.h" +#include "engines/wintermute/persistent.h" +#include "engines/wintermute/base/particles/PartForce.h" +#include "engines/wintermute/base/BPersistMgr.h" + +namespace WinterMute { + +////////////////////////////////////////////////////////////////////////// +CPartForce::CPartForce(CBGame *inGame) : CBNamedObject(inGame) { + _pos = Vector2(0.0f, 0.0f); + _direction = Vector2(0.0f, 0.0f); + _type = FORCE_POINT; +} + + +////////////////////////////////////////////////////////////////////////// +CPartForce::~CPartForce(void) { +} + + +////////////////////////////////////////////////////////////////////////// +bool CPartForce::persist(CBPersistMgr *persistMgr) { + persistMgr->transfer(TMEMBER(_name)); + persistMgr->transfer(TMEMBER(_pos)); + persistMgr->transfer(TMEMBER(_direction)); + persistMgr->transfer(TMEMBER_INT(_type)); + + return STATUS_OK; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/base/particles/PartForce.h b/engines/wintermute/base/particles/PartForce.h new file mode 100644 index 0000000000..640c8d7f20 --- /dev/null +++ b/engines/wintermute/base/particles/PartForce.h @@ -0,0 +1,57 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_PARTFORCE_H +#define WINTERMUTE_PARTFORCE_H + + +#include "engines/wintermute/base/BBase.h" +#include "engines/wintermute/base/BNamedObject.h" +#include "engines/wintermute/math/Vector2.h" + +namespace WinterMute { + +class CPartForce : public CBNamedObject { +public: + enum TForceType { + FORCE_POINT, FORCE_GLOBAL + }; + + CPartForce(CBGame *inGame); + virtual ~CPartForce(void); + + Vector2 _pos; + Vector2 _direction; + TForceType _type; + + bool persist(CBPersistMgr *PersistMgr); +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/base/particles/PartParticle.cpp b/engines/wintermute/base/particles/PartParticle.cpp new file mode 100644 index 0000000000..aa641f0a1c --- /dev/null +++ b/engines/wintermute/base/particles/PartParticle.cpp @@ -0,0 +1,257 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/dcgf.h" +#include "engines/wintermute/base/particles/PartParticle.h" +#include "engines/wintermute/base/particles/PartEmitter.h" +#include "engines/wintermute/base/BSprite.h" +#include "engines/wintermute/base/BGame.h" +#include "engines/wintermute/utils/utils.h" +#include "engines/wintermute/PlatformSDL.h" +#include "common/str.h" +#include + +namespace WinterMute { + +////////////////////////////////////////////////////////////////////////// +CPartParticle::CPartParticle(CBGame *inGame) : CBBase(inGame) { + _pos = Vector2(0.0f, 0.0f); + _posZ = 0.0f; + _velocity = Vector2(0.0f, 0.0f); + _scale = 100.0f; + _sprite = NULL; + _creationTime = 0; + _lifeTime = 0; + _isDead = true; + CBPlatform::setRectEmpty(&_border); + + _state = PARTICLE_NORMAL; + _fadeStart = 0; + _fadeTime = 0; + _currentAlpha = 255; + + _alpha1 = _alpha2 = 255; + + _rotation = 0.0f; + _angVelocity = 0.0f; + + _growthRate = 0.0f; + _exponentialGrowth = false; +} + + +////////////////////////////////////////////////////////////////////////// +CPartParticle::~CPartParticle(void) { + delete _sprite; + _sprite = NULL; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartParticle::setSprite(const char *filename) { + if (_sprite && _sprite->_filename && scumm_stricmp(filename, _sprite->_filename) == 0) { + _sprite->reset(); + return STATUS_OK; + } + + delete _sprite; + _sprite = NULL; + + CSysClassRegistry::getInstance()->_disabled = true; + _sprite = new CBSprite(_gameRef, _gameRef); + if (_sprite && DID_SUCCEED(_sprite->loadFile(filename))) { + CSysClassRegistry::getInstance()->_disabled = false; + return STATUS_OK; + } else { + delete _sprite; + _sprite = NULL; + CSysClassRegistry::getInstance()->_disabled = false; + return STATUS_FAILED; + } + +} + +////////////////////////////////////////////////////////////////////////// +bool CPartParticle::update(CPartEmitter *emitter, uint32 currentTime, uint32 timerDelta) { + if (_state == PARTICLE_FADEIN) { + if (currentTime - _fadeStart >= (uint32)_fadeTime) { + _state = PARTICLE_NORMAL; + _currentAlpha = _alpha1; + } else _currentAlpha = (int)(((float)currentTime - (float)_fadeStart) / (float)_fadeTime * _alpha1); + + return STATUS_OK; + } else if (_state == PARTICLE_FADEOUT) { + if (currentTime - _fadeStart >= (uint32)_fadeTime) { + _isDead = true; + return STATUS_OK; + } else _currentAlpha = _fadeStartAlpha - (int)(((float)currentTime - (float)_fadeStart) / (float)_fadeTime * _fadeStartAlpha); + + return STATUS_OK; + } else { + // time is up + if (_lifeTime > 0) { + if (currentTime - _creationTime >= (uint32)_lifeTime) { + if (emitter->_fadeOutTime > 0) + fadeOut(currentTime, emitter->_fadeOutTime); + else + _isDead = true; + } + } + + // particle hit the border + if (!_isDead && !CBPlatform::isRectEmpty(&_border)) { + Point32 p; + p.x = (int32)_pos.x; + p.y = (int32)_pos.y; + if (!CBPlatform::ptInRect(&_border, p)) + fadeOut(currentTime, emitter->_fadeOutTime); + } + if (_state != PARTICLE_NORMAL) return STATUS_OK; + + // update alpha + if (_lifeTime > 0) { + int age = (int)(currentTime - _creationTime); + int alphaDelta = (int)(_alpha2 - _alpha1); + + _currentAlpha = _alpha1 + (int)(((float)alphaDelta / (float)_lifeTime * (float)age)); + } + + // update position + float elapsedTime = (float)timerDelta / 1000.f; + + for (int i = 0; i < emitter->_forces.getSize(); i++) { + CPartForce *force = emitter->_forces[i]; + switch (force->_type) { + case CPartForce::FORCE_GLOBAL: + _velocity += force->_direction * elapsedTime; + break; + + case CPartForce::FORCE_POINT: { + Vector2 vecDist = force->_pos - _pos; + float dist = fabs(vecDist.length()); + + dist = 100.0f / dist; + + _velocity += force->_direction * dist * elapsedTime; + } + break; + } + } + _pos += _velocity * elapsedTime; + + // update rotation + _rotation += _angVelocity * elapsedTime; + _rotation = CBUtils::normalizeAngle(_rotation); + + // update scale + if (_exponentialGrowth) + _scale += _scale / 100.0f * _growthRate * elapsedTime; + else + _scale += _growthRate * elapsedTime; + + if (_scale <= 0.0f) + _isDead = true; + + + return STATUS_OK; + } +} + +////////////////////////////////////////////////////////////////////////// +bool CPartParticle::display(CPartEmitter *emitter) { + if (!_sprite) return STATUS_FAILED; + if (_isDead) return STATUS_OK; + + _sprite->GetCurrentFrame(); + return _sprite->display(_pos.x, _pos.y, + NULL, + _scale, _scale, + BYTETORGBA(255, 255, 255, _currentAlpha), + _rotation, + emitter->_blendMode); +} + + +////////////////////////////////////////////////////////////////////////// +bool CPartParticle::fadeIn(uint32 currentTime, int fadeTime) { + _currentAlpha = 0; + _fadeStart = currentTime; + _fadeTime = fadeTime; + _state = PARTICLE_FADEIN; + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartParticle::fadeOut(uint32 currentTime, int fadeTime) { + //_currentAlpha = 255; + _fadeStartAlpha = _currentAlpha; + _fadeStart = currentTime; + _fadeTime = fadeTime; + _state = PARTICLE_FADEOUT; + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CPartParticle::persist(CBPersistMgr *persistMgr) { + persistMgr->transfer(TMEMBER(_alpha1)); + persistMgr->transfer(TMEMBER(_alpha2)); + persistMgr->transfer(TMEMBER(_border)); + persistMgr->transfer(TMEMBER(_pos)); + persistMgr->transfer(TMEMBER(_posZ)); + persistMgr->transfer(TMEMBER(_velocity)); + persistMgr->transfer(TMEMBER(_scale)); + persistMgr->transfer(TMEMBER(_creationTime)); + persistMgr->transfer(TMEMBER(_lifeTime)); + persistMgr->transfer(TMEMBER(_isDead)); + persistMgr->transfer(TMEMBER_INT(_state)); + persistMgr->transfer(TMEMBER(_fadeStart)); + persistMgr->transfer(TMEMBER(_fadeTime)); + persistMgr->transfer(TMEMBER(_currentAlpha)); + persistMgr->transfer(TMEMBER(_angVelocity)); + persistMgr->transfer(TMEMBER(_rotation)); + persistMgr->transfer(TMEMBER(_growthRate)); + persistMgr->transfer(TMEMBER(_exponentialGrowth)); + persistMgr->transfer(TMEMBER(_fadeStartAlpha)); + + if (persistMgr->_saving) { + persistMgr->transfer(TMEMBER(_sprite->_filename)); + } else { + char *filename; + persistMgr->transfer(TMEMBER(filename)); + CSysClassRegistry::getInstance()->_disabled = true; + setSprite(filename); + CSysClassRegistry::getInstance()->_disabled = false; + delete[] filename; + filename = NULL; + } + + return STATUS_OK; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/base/particles/PartParticle.h b/engines/wintermute/base/particles/PartParticle.h new file mode 100644 index 0000000000..ab5730d3c5 --- /dev/null +++ b/engines/wintermute/base/particles/PartParticle.h @@ -0,0 +1,90 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_PARTPARTICLE_H +#define WINTERMUTE_PARTPARTICLE_H + + +#include "engines/wintermute/base/BBase.h" +#include "engines/wintermute/math/Rect32.h" +#include "engines/wintermute/math/Vector2.h" + +namespace WinterMute { + +class CPartEmitter; +class CBSprite; +class CBPersistMgr; + +class CPartParticle : public CBBase { +public: + enum TParticleState { + PARTICLE_NORMAL, PARTICLE_FADEIN, PARTICLE_FADEOUT + }; + + CPartParticle(CBGame *inGame); + virtual ~CPartParticle(void); + + float _growthRate; + bool _exponentialGrowth; + + float _rotation; + float _angVelocity; + + int _alpha1; + int _alpha2; + + Rect32 _border; + Vector2 _pos; + float _posZ; + Vector2 _velocity; + float _scale; + CBSprite *_sprite; + uint32 _creationTime; + int _lifeTime; + bool _isDead; + TParticleState _state; + + bool update(CPartEmitter *emitter, uint32 currentTime, uint32 timerDelta); + bool display(CPartEmitter *emitter); + + bool setSprite(const char *filename); + + bool fadeIn(uint32 currentTime, int fadeTime); + bool fadeOut(uint32 currentTime, int fadeTime); + + bool persist(CBPersistMgr *PersistMgr); +private: + uint32 _fadeStart; + int _fadeTime; + int _currentAlpha; + int _fadeStartAlpha; +}; + +} // end of namespace WinterMute + +#endif -- cgit v1.2.3