Mercurial > hg > opencollidoscope
view CollidoscopeApp/src/ParticleController.cpp @ 5:75b744078d66
added license
author | Fiore Martin <f.martin@qmul.ac.uk> |
---|---|
date | Wed, 13 Jul 2016 16:06:46 +0200 |
parents | ab6db404403a |
children | 4dad0b810f18 |
line wrap: on
line source
/* Copyright (C) 2015 Fiore Martin Copyright (C) 2016 Queen Mary University of London Author: Fiore Martin This file is part of Collidoscope. Collidoscope 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 3 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, see <http://www.gnu.org/licenses/>. */ #include "ParticleController.h" #include "cinder/Rand.h" #include <type_traits> using namespace ci; using std::list; ParticleController::ParticleController() : mNumParticles( 0 ) { // uses Cinder (and OpenGL) virtual buffer object based drawing // see ParticleSphereCPU example in Cinder library mParticles.assign( kMaxParticles, Particle() ); mParticlePositions.assign( kMaxParticles, vec2( -1, -1 ) ); mParticleVbo = gl::Vbo::create( GL_ARRAY_BUFFER, mParticlePositions, GL_DYNAMIC_DRAW ); geom::BufferLayout particleLayout; particleLayout.append( geom::Attrib::POSITION, 2, sizeof( vec2 ), 0 ); auto mesh = gl::VboMesh::create( mParticlePositions.size(), GL_POINTS, { { particleLayout, mParticleVbo } } ); // creates glsl program to run the batch with #if ! defined( CINDER_GL_ES ) auto glsl = gl::GlslProg::create( gl::GlslProg::Format() .vertex( CI_GLSL( 150, uniform mat4 ciModelViewProjection; in vec4 ciPosition; void main( void ) { gl_Position = ciModelViewProjection * ciPosition; gl_PointSize = 1.0; } ) ) .fragment( CI_GLSL( 150, out vec4 oColor; void main( void ) { oColor = vec4( 1.0f, 1.0f, 1.0f, 1.0f ); } ) ) ); mParticleBatch = gl::Batch::create( mesh, glsl ); #else auto glsl = gl::GlslProg::create( gl::GlslProg::Format() .vertex( CI_GLSL( 100, uniform mat4 ciModelViewProjection; attribute vec4 ciPosition; void main( void ) { gl_Position = ciModelViewProjection * ciPosition; gl_PointSize = 1.0; } ) ) .fragment( CI_GLSL( 100, precision highp float; void main( void ) { gl_FragColor = vec4( 1, 1, 1, 1 ); } ) ) ); mParticleBatch = gl::Batch::create( mesh, glsl ); #endif } void ParticleController::updateParticles() { // update the positions of the particles and dispose them if they're reached their timespan for ( size_t i = 0; i < mNumParticles; i++ ){ Particle &particle = mParticles[i]; vec2 &pos = mParticlePositions[i]; particle.mAge++; if ( (!particle.mFlyOver && particle.mAge > particle.mLifespan) || (particle.mFlyOver && particle.mAge >= 300) ){ // dispose particle mParticles[i] = mParticles[mNumParticles - 1]; mParticlePositions[i] = mParticlePositions[mNumParticles - 1]; mParticlePositions[mNumParticles - 1].x = -1.0f; mParticlePositions[mNumParticles - 1].y = -1.0f; mNumParticles--; continue; } pos += particle.mVel; if ( ci::distance( pos, particle.mCloudCenter ) > particle.mCloudSize && !particle.mFlyOver ){ particle.mVel = rotate<float>( particle.mVel, 5 ); } } // Copy particle data onto the GPU. // Map the GPU memory and write over it. void *gpuMem = mParticleVbo->mapReplace(); memcpy( gpuMem, mParticlePositions.data(), mParticlePositions.size() * sizeof( vec2 ) ); mParticleVbo->unmap(); } void ParticleController::addParticles(int amount, const vec2 &initialLocation, const float cloudSize) { // reduce the particles liearly to the total number of particles already present // the more particles aleary present the less particle are added int reduction = ci::lmap<int>(mNumParticles, 0, kMaxParticles, 0, kMaxParticleAdd); amount -= reduction; if ( mNumParticles + amount > kMaxParticles ){ //a.k.a. return if reached kMaxParticles amount = kMaxParticles - mNumParticles; } if( amount <= 0 ) return; for( size_t i = 0; i < amount; i++ ){ // init new particle Particle &particle = mParticles[mNumParticles + i]; vec2 &pos = mParticlePositions[mNumParticles + i]; pos = initialLocation + Rand::randVec2() * 5.0f; // find a location nearby the initial location particle.mCloudCenter = pos; particle.mVel = Rand::randVec2() * Rand::randFloat( 1.0f, 5.0f ); particle.mCloudSize = cloudSize; particle.mAge = 0; particle.mLifespan = Rand::randInt( 30, 60 ); particle.mFlyOver = (Rand::randInt( 500 ) == 0); } mNumParticles += amount ; }