Project 1 – Gauntlet

by Max Hawkins @ 2:42 am 12 January 2011

Schotter

LibCinder Implementation

Processing/Processing.js Implementation

Text Rain

#include "cinder/app/AppBasic.h"
#include "cinder/gl/gl.h"
#include "cinder/Text.h"
#include "cinder/gl/GlslProg.h"
#include "cinder/gl/Texture.h"
#include "cinder/Rand.h"
#include "cinder/Capture.h"
 
#include "Kinect.h"
 
using namespace ci;
using namespace ci::app;
using namespace std;
 
/***************************
 Messy, but -probably- works
****************************/
 
class Letter {
public:
    static std::map<char, gl::Texture> textureForCharacter;
    static std::map<char, float> baselineOffsetForCharacter;
    static float fontSize;
    static bool texturesGenerated;
 
    Vec2f mPosition;
    Vec2f mVelocity;
    Vec2f mAcceleration;
    char mLetter;
 
    Letter(char letter, Vec2f position) {
 
        mAcceleration = Vec2f(0, 0.01);
        mPosition = position;
        mVelocity = Vec2f(0, 0);
 
        mLetter = letter;
 
        if (!texturesGenerated) {
            for(char character = 'A'; character < 'Z'; character++) {
                float baselineOffset = 0;
                std::string str(1, character);
                textureForCharacter[character] = gl::Texture( renderString( str, Font("Arial", fontSize), Color::white(), &baselineOffset ) );
                baselineOffsetForCharacter[character] = baselineOffset;
            }
            texturesGenerated = true;
        }
    }
 
    void update() {
        mVelocity += mAcceleration;
        mPosition += mVelocity;
    }
 
    void draw() {
        float brightness = 1 - (mPosition.y / getWindowHeight());
        gl::color(Color(1, brightness, brightness ));
        gl::draw( textureForCharacter[mLetter], mPosition - Vec2f( 0, baselineOffsetForCharacter[mLetter] ) );
    }
 
    Area frame() {
        return Area(mPosition + Vec2f(0, baselineOffsetForCharacter[mLetter]), textureForCharacter[mLetter].getSize());
    }
 
    void detectCollisions(const Surface8u &background) {
        const Area clippedFrame( frame().getClipBy( background.getBounds() ) );
 
        if (clippedFrame.getWidth() <= 0 || clippedFrame.getHeight() <= 0) return;
 
        float sum = 0; // probably bad. hm.
 
        uint8_t inc = background.getPixelInc();
 
        const uint8_t *line = background.getData( clippedFrame.getUL() );
 
        for( int32_t y = clippedFrame.y1; y < clippedFrame.y2; ++y ) {
 
            const uint8_t *pixel = line;
 
            for( int32_t x = clippedFrame.x1; x < clippedFrame.x2; ++x ) {
                if(*pixel > 150) {
                    sum++;
                }
                pixel += inc;
            }
 
            line += background.getRowBytes();
        }
 
        if (sum > 10 && mVelocity.y > 0) {
            mVelocity.y = 0;
        }
        if(sum > 20) {
            mVelocity.y -= sum * 0.0004;
        }
 
//        mVelocity -= percent * 5;
    }
 
 
};
bool Letter::texturesGenerated = false;
std::map<char, float> Letter::baselineOffsetForCharacter;
std::map<char, gl::Texture> Letter::textureForCharacter;
float Letter::fontSize = 18;
 
class TextRainApp : public AppBasic {
public:
	void setup();
	void mouseDown( MouseEvent event );	
	void update();
	void draw();
private:
    std::vector<Letter> letters;
    void emitRandomLetter();
    float mLastEmitTime;
    float mEmitInterval;
 
    float lastEmitLocation;
    int lastEmitCharacterIndex;
 
    Kinect				mKinect;
	gl::Texture			mColorTexture, mDepthTexture;
    Surface8u mDepthSurface;
 
};
 
void TextRainApp::setup()
{
    setFrameRate(30);
    mEmitInterval = 1;
    mLastEmitTime = -mEmitInterval;
 
    lastEmitCharacterIndex = 0;
    lastEmitLocation = 0;
 
    mKinect = Kinect( Kinect::Device() ); // the default Device implies the first Kinect connected
 
    gl::enableAdditiveBlending();
}
 
void TextRainApp::mouseDown( MouseEvent event )
{
}
 
void TextRainApp::emitRandomLetter() {
    //    char character = (char) Rand::randInt(97, 122);
    string poem = ("A ONE THAT IS NOT COLD IS SCARECLY A ONE AT ALL");
    lastEmitCharacterIndex += Rand::randInt(poem.length());
    char character = poem[lastEmitCharacterIndex % poem.length()];
 
    if(character == ' ') return;
 
    float horizontalEmitLocation = ((float)(lastEmitCharacterIndex % poem.length()) / poem.length()) * getWindowWidth();
    Vec2f startPosition = Vec2f(horizontalEmitLocation, -18);
    lastEmitLocation = horizontalEmitLocation;
 
    Letter letter(character, startPosition);
    letters.push_back(letter);
}
 
void TextRainApp::update()
{
    if ((getElapsedSeconds() - mLastEmitTime) > mEmitInterval) {
        emitRandomLetter();
        mLastEmitTime = getElapsedSeconds();
    }
 
	if( mKinect.checkNewDepthFrame() ) {
		mDepthTexture = mKinect.getDepthImage();
        mDepthSurface = Surface8u( mKinect.getDepthImage() );
    }
 
	if( mKinect.checkNewColorFrame() )
		mColorTexture = mKinect.getColorImage();
}
 
void TextRainApp::draw()
{
	// clear out the window with black
	gl::clear( Color( 0, 0, 0 ) ); 
 
    gl::color(Color::white());
 
    if (mColorTexture) {
        gl::draw(mColorTexture);
    }
 
    for (vector<Letter>::iterator iter = letters.begin(); iter != letters.end();) {
 
        iter->update();
        iter->draw();
 
        if (mDepthSurface) {
            iter->detectCollisions(mDepthSurface);
        }
 
        if (iter->mPosition.y > getWindowHeight() || iter->mPosition.y < -1000) {
            iter = letters.erase(iter);
        } else {
            iter = ++iter;
        }
 
    }
}
 
 
CINDER_APP_BASIC( TextRainApp, RendererGl )

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
(c) 2024 Interactive Art & Computational Design / Spring 2011 | powered by WordPress with Barecity