void ParticleController::doubleDensityRelaxation( float neighborhood, float restDensity, float stiffnessParameter, float stiffnessParameterNear ) { float neighborhoodSqrd = neighborhood * neighborhood; for ( list<Particle>::iterator p1 = mParticles.begin(); p1 != mParticles.end(); ++p1 ){ p1->mDensity = 0.0f; p1->mNearDensity = 0.0f; for ( list<Particle>::iterator p2 = p1->mNeighbors.begin(); p2 != p1->mNeighbors.end(); ++p2 ){ Vec2f rij = p1->mPos - p2->mPos; float rijSqrd = rij.lengthSquared(); float q = rijSqrd / neighborhoodSqrd; p1->mDensity += ( 1-q ) * ( 1-q ); p1->mNearDensity += ( 1-q ) * ( 1-q ) * ( 1-q ); } p1->mPressure = stiffnessParameter * ( p1->mDensity - restDensity ); p1->mNearPressure = stiffnessParameterNear * p1->mNearDensity; Vec2f dpos = Vec2f::zero(); for ( list<Particle>::iterator p2 = p1->mNeighbors.begin(); p2 != p1->mNeighbors.end(); ++p2 ){ Vec2f rij = p1->mPos - p2->mPos; float rijSqrd = rij.lengthSquared(); float q = rijSqrd / neighborhoodSqrd; Vec2f DPos = rij.normalized() * ( p1->mPressure * ( 1-q ) + p1->mNearPressure * ( 1-q ) * ( 1-q ) ); p2->mPos += DPos/2; dpos -= DPos/2; } p1->mPos += dpos; } }
//--------------------------------------------------------------------------------------------------- void FactionState::ProcessAction(AIAction action, const ActionBuffer& commandBuffer) { ShipState* ship; uint32_t shipId; switch (action) { case kForce: shipId = commandBuffer.ReadUInt(); ship = battle_.ships().has(shipId) ? &battle_.ships().lookup(shipId) : nullptr; if (ship != nullptr && &ship->faction() == this) { Vec2f force = commandBuffer.ReadVec2f(); float totalForceSquared = force.lengthSquared(); if (totalForceSquared > AICommand::kMaxForce*AICommand::kMaxForce) force = force.normalized() * AICommand::kMaxForce; ship->set_force(force); } break; case kFire: shipId = commandBuffer.ReadUInt(); ship = battle_.ships().has(shipId) ? &battle_.ships().lookup(shipId) : nullptr; if (ship != nullptr && &ship->faction() == this) battle_.Fire(*ship); break; } }
void WaterSimApp::mouseMove( MouseEvent event ) { Vec2f delta = Vec2f( getWindowWidth(), getWindowHeight() ) / 2.0f - event.getPos(); if( delta.lengthSquared() > 5 ) { mGravityVector = delta.normalized() * 9.8f; mGravityVector.y = -mGravityVector.y; } }
void draw() { glPushMatrix(); gl::translate(pos); gl::color(TILECOLOR); gl::draw(*hex); gl::color(TILECOLOR2); glBegin(GL_TRIANGLE_FAN); PolyLine<Vec2f>::iterator pt; for(pt = hex->begin(); pt < hex->end(); pt++) { gl::vertex(*pt); } glEnd(); /* gl::color(Color(1.0f, .0f, .0f)); for(pt = hex->begin(); pt < hex->end() - 1; pt++) { gl::vertex(*pt); } */ for(int i = 0; i < 6; i++) { if(connections[i]) { Vec2f v = (connections[i]->pos - pos)/2.0f; gl::color(Color(.0f, 1.0f, .0f)); gl::drawLine(Vec2f(.0f, .0f), v); } if(state[i]) { Vec2f p = cart(TILERAD_MIN - 2.0f, -M_PI/2 - i * M_PI/3.0f); gl::color(Color(1.0f, .0f, .0f)); // gl::drawSolidCircle(p, 5.0f, 32); Vec2f pnorm = p.normalized(); pnorm.rotate(-M_PI/2.0f); Vec2f p0 = p - 22.0f * pnorm; Vec2f p1 = p + 22.0f * pnorm; gl::drawLine(p0, p1); } } glPopMatrix(); }
void Turtle::init( Vec2f position, Vec2f direction, float length) { mStartPosition = position; mCurrentPosition = mStartPosition; mLength = length; mDirection = direction.normalized(); branchNow = false; branched = false; }
void Particle::pullToCenter(const Vec2f ¢er) { Vec2f dirToCenter = m_loc - center; float distToCenter = dirToCenter.length(); if (distToCenter > voidnoise::Settings::get().gravityDistance) { m_acc -= dirToCenter.normalized() * ((distToCenter - voidnoise::Settings::get().gravityDistance) * voidnoise::Settings::get().gravity); } }
void RenderMesh2D::setAsLine( const Vec2f &begin, const Vec2f &end, float width ) { Vec2f ray = end - begin; Vec2f side = ray.normalized() * width; Vec2f N( -side.y, side.x ); Vec2f S = -N; if( vertices.size() != 4 ) { vertices.assign( 4, Vertex() ); } vertices.at(0).position = begin + S; vertices.at(1).position = begin + N; vertices.at(2).position = end + S; vertices.at(3).position = end + N; }
void ParticleController::applyViscosity( float neighborhood, float viscositySigma, float viscosityBeta ) { float neighborhoodSqrd = neighborhood * neighborhood; for ( list<Particle>::iterator p1 = mParticles.begin(); p1 != mParticles.end(); ++p1 ){ for ( list<Particle>::iterator p2 = p1->mNeighbors.begin(); p2 != p1->mNeighbors.end(); ++p2 ){ Vec2f rij = p1->mPos - p2->mPos; float rijSqrd = rij.lengthSquared(); float u = ( p1->mVel - p2->mVel ).dot( rij.normalized() ); float q = rijSqrd / neighborhoodSqrd; if ( u > 0 ){ Vec2f I = ( 1 - q ) * ( ( viscositySigma * u ) + ( viscosityBeta * u * u ) ) * rij.normalized(); p1->mVel -= I/2; p2->mVel += I/2; } } } }
void DelayFeedback::addSplash( const Vec2f &pos ) { mSplashes.push_back( Splash() ); auto &splash = mSplashes.back(); splash.mCenter = pos; splash.mAlpha = 1; float radiusMin = ( 1 - (float)pos.y / (float)getWindowHeight() ) * MAX_RADIUS / 2; splash.mRadius = randFloat( radiusMin, 30 ); float endRadius = randFloat( MAX_RADIUS * 0.9f, MAX_RADIUS ); timeline().apply( &splash.mRadius, endRadius, 7, EaseOutExpo() ); timeline().apply( &splash.mAlpha, 0.0f, 7 ); float h = math<float>::min( 1, mPerlin.fBm( pos.normalized() ) * 7.0f ); splash.mColorHsv = Vec3f( fabsf( h ), 1, 1 ); }
void Ball::collideWith(BallRef other) { // calculate minimal distance between balls static float minimal = 2 * RADIUS; // 1) we have already established that the two balls are colliding, // let's move back in time to the moment before collision mPosition -= mVelocity; other->mPosition -= other->mVelocity; // 2) convert to simple 1-dimensional collision // by projecting onto line through both centers Vec2f line = other->mPosition - mPosition; Vec2f unit = line.normalized(); float distance = line.dot(unit); float velocity_a = mVelocity.dot(unit); float velocity_b = other->mVelocity.dot(unit); if(velocity_a == velocity_b) return; // no collision will happen // 3) find time of collision float t = (minimal - distance) / (velocity_b - velocity_a); // 4) move to that moment in time mPosition += t * mVelocity; other->mPosition += t * other->mVelocity; // 5) exchange velocities mVelocity -= velocity_a * unit; mVelocity += velocity_b * unit; other->mVelocity -= velocity_b * unit; other->mVelocity += velocity_a * unit; // 6) move forward to current time mPosition += (1.0f - t) * mVelocity; other->mPosition += (1.0f - t) * other->mVelocity; // 7) make sure the balls stay within window collideWithWindow(); other->collideWithWindow(); }
void RenderMesh2D::setAsCappedLine( const ci::Vec2f &begin, const ci::Vec2f &end, float width ) { Vec2f ray = end - begin; Vec2f cap = ray.normalized() * width; Vec2f N( -cap.y, cap.x ); Vec2f S = -N; Vec2f NW = N - cap; Vec2f NE = N + cap; Vec2f SE = -NW; Vec2f SW = -NE; if( vertices.size() != 8 ) { vertices.assign( 8, Vertex() ); } vertices.at(0).position = begin + SW; vertices.at(1).position = begin + NW; vertices.at(2).position = begin + S; vertices.at(3).position = begin + N; vertices.at(4).position = end + S; vertices.at(5).position = end + N; vertices.at(6).position = end + SE; vertices.at(7).position = end + NE; }
ParkingSpace(float w, float l, Vec2f loc, Vec2f dir) : _width(w) , _length(l) , _location(loc) , _entryDir(dir.normalized()) { }
void cApp::update(){ /* add particle */ int numPs = ps.size(); if( frame%100 != 0 ){ int num = randInt(10, 30); for( int i=0; i<num; i++ ){ // pick up color int cid = numPs + i; int cidx = cid % mColorSample1.size(); int cidy = cid / mColorSample1.size(); cidx %= mColorSample1.size(); cidy %= mColorSample1[0].size(); ColorAf col = mColorSample1[cidx][cidy]; float angle = mPlns[1].fBm( cid*0.01 ) * 10.0; Vec2f vel = Vec2f(1,1) * randFloat(10, 20); vel.rotate(angle); ps.push_back( Vec2f(0,0) ); cs.push_back( col ); vs.push_back( vel ); } }else{ int num = randInt(20000, 30000); for( int i=0; i<num; i++ ){ // pick up color int cid = numPs + i; int cidx = cid % mColorSample1.size(); int cidy = cid / mColorSample1.size(); cidx %= mColorSample1.size(); cidy %= mColorSample1[0].size(); ColorAf col = mColorSample1[cidx][cidy]; Vec3f n = mPlns[0].dfBm( frame, col.r*col.g, col.b ); Vec2f vel; vel.x = n.x * n.y * 20; vel.y = n.y * n.z * 20; if(vel.length() <= 20){ vel = vel.normalized() * lmap(abs(n.z), 0.0f, 1.0f, 0.7f, 1.0f) *20; } ps.push_back( Vec2f(0,0) ); cs.push_back( col ); vs.push_back( vel ); } } /* update particle */ for( int i=0; i<ps.size(); i++ ){ Vec2f & p = ps[i]; Vec2f & v = vs[i]; ColorAf & c = cs[i]; Vec3f n = mPlns[1].dfBm( frame*0.01, i*0.01, c.b*0.5 ); c.r += n.x * 0.02; c.g += n.y * 0.02; c.b += n.z * 0.02; Vec2f new_vel; new_vel.x = n.x; new_vel.y = n.y; v += new_vel*2; p += v; v *= 0.999; c.a *= 0.999; } /* remove */ vector<Vec2f>::iterator pit = ps.begin(); vector<Vec2f>::iterator vit = vs.begin(); vector<ColorAf>::iterator cit = cs.begin(); int xmin = -mExp.mFbo.getWidth()/2; int xmax = mExp.mFbo.getWidth()/2; int ymin = -mExp.mFbo.getHeight()/2; int ymax = mExp.mFbo.getHeight()/2; while ( pit!=ps.end() ) { Vec2f & p = *pit; if( (p.x<xmin || xmax<p.x) || p.y<ymin || ymax<p.y ){ pit = ps.erase(pit); vit = vs.erase(vit); cit = cs.erase(cit); }else{ pit++; vit++; cit++; } } frame++; }
void update(float dt, vector<Planet*>& planets, paramStruct& params) { if(charging && charge < MAXCHARGE) charge += dt * 1.5f; pars = params; if(jumpInert > .0f) jumpInert-=dt; if(jumpInert < .0f) jumpInert = .0f; if(turn != params.turn) { charging = false; charge = .0f; } turn = params.turn; pos += vel * dt; if(pos.x > getWindowWidth()) { pos.x = pos.x-getWindowWidth(); } if(pos.x < 0) { pos.x = getWindowWidth()+pos.x; } if(pos.y > getWindowHeight()) { pos.y = pos.y-getWindowHeight(); } if(pos.y < 0) { pos.y = getWindowHeight()+pos.y; } Planet* closest = planets[0]; float dst = 999999999.0f; vector<Planet*>::iterator it; for(it = planets.begin(); it < planets.end(); it++) { Vec2f moonToPlanet = ((*it)->pos - pos); if(moonToPlanet.length() < dst) { closest = (*it); dst = moonToPlanet.length(); } // vel += moonToPlanet.normalized() * 1.0f * (*it)->radius * (*it)->radius * 3.14 / (math<float>::max(moonToPlanet.length() * moonToPlanet.length(), 80.0f)); // vel += moonToPlanet.normalized() * params.distFactor * moonToPlanet.length();//20000.0f/(math<float>::max(moonToPlanet.length(), 100.0f)); // vel += (-params.repulse)* moonToPlanet.normalized() / moonToPlanet.length(); } nearest = closest; Vec2f moonToPlanet = closest->pos - pos; if(!closestPlanet && moonToPlanet.length() > closest->radius * 2.5f) { vel += moonToPlanet.normalized() * 36.5f * pars.speed * closest->radius * closest->radius * closest->radius * (2.0f/3.0f) * M_PI / (math<float>::max(moonToPlanet.length() * moonToPlanet.length(), 80.0f)); } if(!jumpInert && !closestPlanet && moonToPlanet.length() < closest->radius * 1.7f && losing.size() == 0) { closestPlanet = closest; } if(closestPlanet && !jumpInert && losing.size() == 0) { Vec2f m2cp = (closestPlanet->pos - pos); Vec2f r = pos - closestPlanet->pos; r.normalize(); r.rotate(M_PI/1.97f); vel = r * 300.0f * pars.speed; if(m2cp.length() < closestPlanet->radius) { pos += -m2cp.normalized() * (5.0f + closestPlanet->radius - m2cp.length()); } } //vel /= planets.size(); // // Vec2f newpos = (pos + vel * dt); // for(it = planets.begin(); it < planets.end(); it++) // { // if(newpos.distance((*it)->pos) < (*it)->radius * 1.5f) // vel -= ((*it)->pos - pos); // } closest = 0; delete closest; // particles vector<Particle*>::iterator pit; for(pit = losing.begin(); pit < losing.end(); pit++) { (*pit)->update(dt); if((*pit)->time > (*pit)->lt) losing.erase(pit); } }
void CudaRenderer::constructBlurLUT(void) { // start by constructing low-discrepancy unit square int N = 100; // number of samples int S = 24; // max radius // init to random Array<Vec2f> pos; for (int i=0; i < N; i++) { Vec2f p; p.x = (float)hashBits(i) / (float)(((U64)1)<<32); p.y = (float)hashBits(i+N) / (float)(((U64)1)<<32); pos.add(p); } // relax by repulsion force Array<Vec2f> force; force.resize(N); for (int i=0; i < 20; i++) { for (int j=0; j < N; j++) { Vec2f f(0.f, 0.f); Vec2f p = pos[j]; for (int k=0; k < N; k++) { if (k==j) continue; Vec2f q = pos[k]; Vec2f d = p-q; if (d.x > .5f) d.x -= 1.f; if (d.y > .5f) d.y -= 1.f; if (d.x < -.5f) d.x += 1.f; if (d.y < -.5f) d.y += 1.f; float d2 = (d.x*d.x + d.y*d.y); float m = 1.f/d2; m *= .0001f; f += d.normalized() * m; } float flen = f.length(); flen = min(flen, .2f); f = f.normalized() * flen; force[j] = f; } for (int j=0; j < N; j++) { Vec2f p = pos[j]; p += force[j]; while (p.x > 1.f) p.x -= 1.f; while (p.y > 1.f) p.y -= 1.f; while (p.x < 0.f) p.x += 1.f; while (p.y < 0.f) p.y += 1.f; pos[j] = p; } } // form into a disc for (int i=0; i < N; i++) { Vec2f p = pos[i]; float an = p.x * 2.f * 3.14159f; float d = p.y; // inverse square weighting p.x = d * sinf(an); p.y = d * cosf(an); p = (p + 1.f) * .5f; pos[i] = p; } // work with pixels from now on Array<Vec2i> ipos; for (int i=0; i < N; i++) { Vec2f p = pos[i]; p.x = min(max(p.x, 0.f), 1.f); p.y = min(max(p.y, 0.f), 1.f); p = (pos[i] - .5f) * 2.f * (float)S; int x = (int)(p.x+.5f); int y = (int)(p.y+.5f); ipos.add(Vec2i(x, y)); } // trim set to unique pixels Set<Vec2i> used; Array<Vec2i> iposTemp = ipos; ipos.clear(); for (int i=0; i < N; i++) { Vec2i p = iposTemp[i]; if (used.contains(p)) continue; used.add(p); ipos.add(p); } N = ipos.getSize(); printf("CudaRenderer: blur LUT has %d samples\n", ipos.getSize()); // sort according to distance for (int i=0; i < N; i++) { int dmin = -1; int imin = 0; for (int j=i; j < N; j++) { Vec2i p = ipos[j]; int d = p.x*p.x + p.y*p.y; if (d < dmin || dmin < 0) { dmin = d; imin = j; } } swap(ipos[i], ipos[imin]); } // construct bitmap for support find Array<int> bmap; bmap.resize(4*S*S); for (int i=0; i < bmap.getSize(); i++) bmap[i] = -1; // blit seeds for (int i=0; i < N; i++) { Vec2i p = ipos[i]; p.x += S; p.y += S; p.x = min(max(p.x, 0), 2*S-1); p.y = min(max(p.y, 0), 2*S-1); bmap[p.x + 2*S*p.y] = i; } // fill until full for(;;) { Array<int> bmapTemp = bmap; bool changed = false; for (int y=0; y < 2*S; y++) for (int x=0; x < 2*S; x++) { int d2 = sqr(x-S) + sqr(y-S); if (d2 > S*S) continue; int b = bmap[x+2*S*y]; if (b >= 0) continue; int x0 = max(x-1, 0); int x1 = min(x+1, 2*S-1); int y0 = max(y-1, 0); int y1 = min(y+1, 2*S-1); for (int py=y0; py<=y1; py++) for (int px=x0; px<=x1; px++) { int c = bmap[px+2*S*py]; if (c >= 0) b = c; } if (b >= 0) { changed = true; bmapTemp[x+2*S*y] = b; } } if (!changed) break; bmap = bmapTemp; } // count weights Array<int> weight; weight.resize(N); for (int i=0; i < N; i++) weight[i] = 0; for (int i=0; i < 4*S*S; i++) { int b = bmap[i]; if (b >= 0) weight[b]++; } // construct lut for (int i=0; i < N; i++) m_blurLUT.add(Vec3i(ipos[i].x, ipos[i].y, weight[i])); // convert bitmap into lut #if 0 m_blurLUT.clear(); for (int y=0; y < 2*S; y++) for (int x=0; x < 2*S; x++) { int b = bmap[x+2*S*y]; if (b < 0) continue; m_blurLUT.add(Vec3i(x-S, y-S, hashBits(b))); } #endif }
void Branch::calcPath() { // TODO: build this up sequentially #if 1 mLength = 0.f; for ( int i = 0; i < mMaxIterations; i++ ) { bool lastArc = false; Vec2f targetDir = mTargetPosition - mCurrentPosition; if ( mCurrentPosition.distanceSquared( mTargetPosition ) < ( mStemLengthMax * mStemLengthMax ) ) { // add the target if it is in the direction range in the next step lastArc = true; } if ( i == 0 ) { addArc( mCurrentPosition ); if ( lastArc ) mCurrentPosition = mTargetPosition; else mCurrentPosition += mStemLengthMin * targetDir.normalized(); addArc( mCurrentPosition ); mLength += mStemLengthMin; } else { // current direction size_t segmentNum = mPath.getNumSegments(); Vec2f p0 = mPath.getSegmentPosition( segmentNum - 1, 1.f ); Vec2f currentDir = p0 - mPath.getSegmentPosition( segmentNum - 1, .98f ); // minimum angle between the current direction and the target float angleDir = math< float >::atan2( currentDir.y, currentDir.x ); float angleTarget = math< float >::atan2( targetDir.y, targetDir.x ); float angle = angleTarget - angleDir; if ( angle > M_PI ) angle -= 2 * M_PI; else if ( angle < -M_PI ) angle += 2 * M_PI; #if 0 /* direction range towards the target is the intersection of the bearing angle interval around the target and the current direction, if the intersecion is empty, the maximum angle is used in that direction */ float angleMin = math< float >::clamp( angle - mStemBearingDelta, -mStemBearingDelta, mStemBearingDelta ); float angleMax = math< float >::clamp( angle + mStemBearingDelta, -mStemBearingDelta, mStemBearingDelta ); #endif // FIXME: bearing delta .25 breaks continuity? // this algorithm tends to keep the target in sight better float angleMin, angleMax; if ( lastArc ) { // get as close to the target as possible with the last arc if ( ( angle > -mStemBearingDelta ) && ( angle < mStemBearingDelta ) ) angleMin = angleMax = angle; else if ( angle <= -mStemBearingDelta ) angleMin = angleMax = -mStemBearingDelta; else if ( angle >= mStemBearingDelta ) angleMin = angleMax = mStemBearingDelta; } else if ( angle <= -mStemBearingDelta ) // the angle is the maximum if the target is outside the range { angleMin = angleMax = -mStemBearingDelta; } else if ( angle >= mStemBearingDelta ) { angleMin = angleMax = mStemBearingDelta; } else // inside the range on the left handside, allow leftward movements only if ( angle < 0.f ) { angleMin = -mStemBearingDelta; angleMax = 0.f; } else // inside the range on the right handside, allow rightward movements only if ( angle > 0.f ) { angleMin = 0.f; angleMax = mStemBearingDelta; } else // angle = 0, turn is allowed to either side { angleMin = -mStemBearingDelta; angleMax = mStemBearingDelta; } float bearingMin = angleDir + angleMin; float bearingMax = angleDir + angleMax; float stemDistance; if ( lastArc ) stemDistance = targetDir.length(); else stemDistance = Rand::randFloat( mStemLengthMin, mStemLengthMax ); float stemBearingAngle = Rand::randFloat( bearingMin, bearingMax ); Vec2f bearing( math< float >::cos( stemBearingAngle ), math< float >::sin( stemBearingAngle ) ); mCurrentPosition += stemDistance * bearing; addArc( mCurrentPosition ); mLength += stemDistance; } if ( lastArc ) break; } #endif #if 0 // simple algorithm with big curly movements for ( int i = 0; i < mMaxIterations; i++ ) { Vec2f d = mTargetPosition - mCurrentPosition; float stemDistance = Rand::randFloat( mStemLengthMin, mStemLengthMax ); if ( d.length() < stemDistance ) { mCurrentPosition = mTargetPosition; addArc( mCurrentPosition ); break; } else { float stemBearingAngle = Rand::randFloat( mStemBearingDelta ); Vec2f bearing( d.normalized() ); bearing.rotate( ( ( i & 1 ) ? 1 : -1 ) * stemBearingAngle ); mCurrentPosition += stemDistance * bearing; addArc( mCurrentPosition ); } } #endif }