diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000..1b81a9d586 Binary files /dev/null and b/.DS_Store differ diff --git a/audio.cpp b/audio.cpp index c05d98ce1d..13f6d54ec9 100644 --- a/audio.cpp +++ b/audio.cpp @@ -5,6 +5,14 @@ // Created by Seiji Emery on 9/2/12. // Copyright (c) 2012 __MyCompanyName__. All rights reserved. // + +/** + * @file audio.cpp + * Low level audio i/o portaudio wrapper. + * + * @author Seiji Emery + * + */ #include #include @@ -18,7 +26,25 @@ Audio::AudioData *Audio::data; PaStream *Audio::stream; PaError Audio::err; float Audio::AudioData::inputGain; - +/** + * Audio callback used by portaudio. + * Communicates with Audio via a shared pointer to Audio::data. + * Writes input audio channels (if they exist) into Audio::data->buffer, + multiplied by Audio::data->inputGain. + * Then writes Audio::data->buffer into output audio channels, and clears + the portion of Audio::data->buffer that has been read from for reuse. + * + * @param[in] inputBuffer A pointer to an internal portaudio data buffer containing data read by portaudio. + * @param[out] outputBuffer A pointer to an internal portaudio data buffer to be read by the configured output device. + * @param[in] frames Number of frames that portaudio requests to be read/written. + (Valid size of input/output buffers = frames * number of channels (2) * sizeof data type (float)). + * @param[in] timeInfo Portaudio time info. Currently unused. + * @param[in] statusFlags Portaudio status flags. Currently unused. + * @param[in] userData Pointer to supplied user data (in this case, a pointer to Audio::data). + Used to communicate with external code (since portaudio calls this function from another thread). + * @return Should be of type PaStreamCallbackResult. Return paComplete to end the stream, or paContinue to continue (default). + Can be used to end the stream from within the callback. + */ int audioCallback (const void *inputBuffer, void *outputBuffer, unsigned long frames, @@ -30,25 +56,56 @@ int audioCallback (const void *inputBuffer, float *input = (float*)inputBuffer; float *output = (float*)outputBuffer; - if (input != NULL) { + #if WRITE_AUDIO_INPUT_TO_OUTPUT + if (input != NULL) {// && Audio::writeAudioInputToOutput) { // combine input into data buffer // temp variables (frames and bufferPos need to remain untouched so they can be used in the second block of code) unsigned int f = (unsigned int)frames, p = data->bufferPos; for (; p < data->bufferLength && f > 0; --f, ++p) { + #if WRITE_AUDIO_INPUT_TO_BUFFER + data->buffer[p].l += + data->inputBuffer[p].l = (*input++) * data->inputGain; + data->buffer[p].r += + data->inputBuffer[p].r = (*input++) * data->inputGain; + #else data->buffer[p].l += (*input++) * data->inputGain; data->buffer[p].r += (*input++) * data->inputGain; + #endif } if (f > 0) { // handle data->buffer wraparound for (p = 0; f > 0; --f, ++p) { + #if WRITE_AUDIO_INPUT_TO_BUFFER + data->buffer[p].l += + data->inputBuffer[p].l = (*input++) * data->inputGain; + data->buffer[p].r += + data->inputBuffer[p].r = (*input++) * data->inputGain; + #else data->buffer[p].l += (*input++) * data->inputGain; data->buffer[p].r += (*input++) * data->inputGain; + #endif + } + } + } + #elif WRITE_AUDIO_INPUT_TO_BUFFER + if (input != NULL) {// && Audio::writeAudioInputToBuffer) { + unsigned int f = (unsigned int)frames, + p = data->bufferPos; + for (; p < data->bufferLength && f > 0; --f, ++p) { + data->inputBuffer[p].l = (*input++) * data->inputGain; + data->inputBuffer[p].r = (*input++) * data->inputGain; + } + if (f > 0) { + // handle data->buffer wraparound + for (p = 0; f > 0; --f, ++p) { + data->inputBuffer[p].l = (*input++) * data->inputGain; + data->inputBuffer[p].r = (*input++) * data->inputGain; } } } - + #endif // Write data->buffer into outputBuffer if (data->bufferPos + frames >= data->bufferLength) { // wraparound: write first section (end of buffer) first @@ -71,10 +128,14 @@ int audioCallback (const void *inputBuffer, return paContinue; } -/* - ** Initializes portaudio, and creates and starts an audio stream. +/** + * Initialize portaudio and start an audio stream. + * Should be called at the beginning of program exection. + * @seealso Audio::terminate + * @return Returns true if successful or false if an error occurred. + Use Audio::getError() to retrieve the error code. */ -void Audio::init() +bool Audio::init() { initialized = true; @@ -87,7 +148,7 @@ void Audio::init() 2, // input channels 2, // output channels paFloat32, // sample format - 44100, // sample rate + 44100, // sample rate (hz) 256, // frames per buffer audioCallback, // callback function (void*)data); // user data to be passed to callback @@ -96,19 +157,25 @@ void Audio::init() err = Pa_StartStream(stream); if (err != paNoError) goto error; - return; + return paNoError; error: fprintf(stderr, "-- Failed to initialize portaudio --\n"); fprintf(stderr, "PortAudio error (%d): %s\n", err, Pa_GetErrorText(err)); - exit(err); // replace w/ return value error code? + initialized = false; + delete[] data; + return false; } -/* - ** Closes the running audio stream, and deinitializes portaudio. +/** + * Close the running audio stream, and deinitialize portaudio. + * Should be called at the end of program execution. + * @return Returns true if the initialization was successful, or false if an error occured. + The error code may be retrieved by Audio::getError(). */ -void Audio::terminate () +bool Audio::terminate () { - if (!initialized) return; + if (!initialized) + return true; initialized = false; // err = Pa_StopStream(stream); // if (err != paNoError) goto error; @@ -121,14 +188,24 @@ void Audio::terminate () err = Pa_Terminate(); if (err != paNoError) goto error; - return; + return true; error: fprintf(stderr, "-- portaudio termination error --\n"); fprintf(stderr, "PortAudio error (%d): %s\n", err, Pa_GetErrorText(err)); - exit(err); + return false; } -void Audio::writeAudio (unsigned int offset, unsigned int length, float *left, float *right) { +/** + * Write a stereo audio stream (float*) to the audio buffer. + * Values should be clamped between -1.0f and 1.0f. + * @param[in] offset Write offset from the start of the audio buffer. + * @param[in] length Length of audio channels to be read. + * @param[in] left Left channel of the audio stream. + * @param[in] right Right channel of the audio stream. + */ +void Audio::writeAudio (unsigned int offset, unsigned int length, float const *left, float const *right) { + if (data->buffer == NULL) + return; if (length > data->bufferLength) { fprintf(stderr, "Audio::writeAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength); length = data->bufferLength; @@ -149,7 +226,17 @@ void Audio::writeAudio (unsigned int offset, unsigned int length, float *left, f } } -void Audio::writeTone (unsigned int offset, unsigned int length, float left, float right) { +/** + * Write a repeated stereo sample (float) to the audio buffer. + * Values should be clamped between -1.0f and 1.0f. + * @param[in] offset Write offset from the start of the audio buffer. + * @param[in] length Length of tone. + * @param[in] left Left component. + * @param[in] right Right component. + */ +void Audio::writeTone (unsigned int offset, unsigned int length, float const left, float const right) { + if (data->buffer == NULL) + return; if (length > data->bufferLength) { fprintf(stderr, "Audio::writeTone length exceeded (%d). Truncating to %d.\n", length, data->bufferLength); length = data->bufferLength; @@ -170,7 +257,18 @@ void Audio::writeTone (unsigned int offset, unsigned int length, float left, flo } } -void Audio::addAudio (unsigned int offset, unsigned int length, float *left, float *right) { +/** + * Write a stereo audio stream (float*) to the audio buffer. + * Audio stream is added to the existing contents of the audio buffer. + * Values should be clamped between -1.0f and 1.0f. + * @param[in] offset Write offset from the start of the audio buffer. + * @param[in] length Length of audio channels to be read. + * @param[in] left Left channel of the audio stream. + * @param[in] right Right channel of the audio stream. + */ +void Audio::addAudio (unsigned int offset, unsigned int length, float const *left, float const *right) { + if (data->buffer == NULL) + return; if (length > data->bufferLength) { fprintf(stderr, "Audio::addAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength); length = data->bufferLength; @@ -191,7 +289,18 @@ void Audio::addAudio (unsigned int offset, unsigned int length, float *left, flo } } -void Audio::addTone (unsigned int offset, unsigned int length, float left, float right) { +/** + * Write a repeated stereo sample (float) to the audio buffer. + * Sample is added to the existing contents of the audio buffer. + * Values should be clamped between -1.0f and 1.0f. + * @param[in] offset Write offset from the start of the audio buffer. + * @param[in] length Length of tone. + * @param[in] left Left component. + * @param[in] right Right component. + */ +void Audio::addTone (unsigned int offset, unsigned int length, float const left, float const right) { + if (data->buffer == NULL) + return; if (length > data->bufferLength) { fprintf(stderr, "Audio::writeTone length exceeded (%d). Truncating to %d.\n", length, data->bufferLength); length = data->bufferLength; @@ -211,8 +320,14 @@ void Audio::addTone (unsigned int offset, unsigned int length, float left, float } } } - +/** + * Clear a section of the audio buffer. + * @param[in] offset Offset from the start of the audio buffer. + * @param[in] length Length of section to clear. + */ void Audio::clearAudio(unsigned int offset, unsigned int length) { + if (data->buffer == NULL) + return; if (length > data->bufferLength) { fprintf(stderr, "Audio::clearAudio length exceeded (%d). Truncating to %d.\n", length, data->bufferLength); length = data->bufferLength; @@ -231,7 +346,39 @@ void Audio::clearAudio(unsigned int offset, unsigned int length) { } } - +/** + * Read audio input into the target buffer. + * @param[in] offset Offset from the start of the input audio buffer to read from. + * @param[in] length Length of the target buffer. + * @param[out] left Left channel of the target buffer. + * @param[out] right Right channel of the target buffer. + */ +void Audio::readAudioInput (unsigned int offset, unsigned int length, float *left, float *right) { +#if WRITE_AUDIO_INPUT_TO_BUFFER + if (data->inputBuffer == NULL) + return; + if (length + offset > data->bufferLength) { + fprintf(stderr, "Audio::readAudioInput length exceeded (%d + %d). Truncating to %d + %d.\n", offset, length, offset, data->bufferLength - offset); + length = data->bufferLength - offset; + } + unsigned int p = data->bufferPos + offset; + if (p > data->bufferLength) + p -= data->bufferLength; + for (; p < data->bufferLength && length > 0; --length, ++p) { + *left++ = data->inputBuffer[p].l; + *right++ = data->inputBuffer[p].r; + } + if (length > 0) { + p = 0; + for (; length > 0; --length, ++p) { + *left++ = data->inputBuffer[p].l; + *right++ = data->inputBuffer[p].r; + } + } +#else + return; +#endif +} diff --git a/audio.h b/audio.h index 2daa5abd94..f626b8afde 100644 --- a/audio.h +++ b/audio.h @@ -11,8 +11,135 @@ #include "portaudio.h" -typedef short sample_t; +// Note: main documentation in audio.cpp +/** + * If enabled, direct the audio callback to write the audio input buffer + * directly into the audio output buffer. + */ +#define WRITE_AUDIO_INPUT_TO_OUTPUT 1 +/** + * If enabled, create an additional buffer to store audio input + * and direct the audio callback to write the audio input to this buffer. + */ +#define WRITE_AUDIO_INPUT_TO_BUFFER 0 + +// Note: I initially used static const bools within the Audio class and normal +// 'if' blocks instead of preprocessor - under the assumption that the compiler +// would optimize out the redundant code. +// However, as that apparently did not work (for some reason or another - even +// with full compiler optimization turned on), I've switched to using preprocessor +// macros instead (which is probably faster anyways (at compile-time)). + +/** + * Low level audio interface. + * + * Contains static methods that write to an internal audio buffer, which + is read from by a portaudio callback. + * Responsible for initializing and terminating portaudio. Audio::init() + and Audio::terminate() should be called at the beginning and end of + program execution. + */ +class Audio { +public: + // Initializes portaudio. Should be called at the beginning of program execution. + static bool init (); + // Deinitializes portaudio. Should be called at the end of program execution. + static bool terminate (); + + // Write methods: write to internal audio buffer. + static void writeAudio (unsigned int offset, unsigned int length, float const *left, float const *right); + static void addAudio (unsigned int offset, unsigned int length, float const *left, float const *right); + static void writeTone (unsigned int offset, unsigned int length, float const left, float const right); + static void addTone (unsigned int offset, unsigned int length, float const left, float const right); + static void clearAudio (unsigned int offset, unsigned int length); + + // Read data from internal 'input' audio buffer to an external audio buffer. + // (*only* works if WRITE_AUDIO_INPUT_TO_BUFFER is enabled). + static void readAudioInput (unsigned int offset, unsigned int length, float *left, float *right); + + /** + * Set the audio input gain. (multiplier applied to mic input) + */ + static void setInputGain (float gain) { + data->inputGain = gain; + } + /** + * Get the internal portaudio error code (paNoError if none). + * Use in conjunction with Audio::init() or Audio::terminate(), as it is not + impacted by any other methods. + */ + const PaError getError () { return err; } + +private: + /** + * Set to true by Audio::init() and false by Audio::terminate(). + * Used to prevent Audio::terminate() from deleting uninitialized memory. + */ + static bool initialized; + + /** + * Internal audio data. + * Used to communicate with the audio callback code via a shared pointer. + */ + static struct AudioData { + /** + * Internal (stereo) audio buffer. + * Written to by Audio I/O methods and the audio callback. + * As this is a ring buffer, it should not be written to directly – thus methods + like Audio::writeAudio are provided. + */ + struct BufferFrame{ + float l, r; + } *buffer, *inputBuffer; + /** + * Length of the audio buffer. + */ + const static unsigned int bufferLength = 1000; + /** + * Current position (start) within the ring buffer. + * Updated by the audio callback. + */ + unsigned int bufferPos; + /** + * Audio input gain (multiplier applied to the incoming audio stream). + * Use Audio::setInputGain() to modify this. + */ + static float inputGain;// = 1.f; + + AudioData () : bufferPos(0) { + inputGain = 1.0f; + buffer = new BufferFrame[bufferLength]; + memset((float*)buffer, 0, sizeof(float) * bufferLength * 2); + #if WRITE_AUDIO_INPUT_TO_BUFFER + inputBuffer = new BufferFrame[bufferLength]; + memset((float*)inputBuffer, 0, sizeof(float) * bufferLength * 2); + #else + inputBuffer = NULL; + #endif + } + ~AudioData () { + delete[] buffer; + #if WRITE_AUDIO_INPUT_TO_BUFFER + delete[] inputBuffer; + #endif + } + }*data; + /** + * Internal audio stream handle. + */ + static PaStream *stream; + /** + * Internal error code (used only by Audio::init() and Audio::terminate()). + */ + static PaError err; + + Audio (); // prevent instantiation (private constructor) + + friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*); +}; + +// Audio callback called by portaudio. int audioCallback (const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, @@ -20,55 +147,5 @@ int audioCallback (const void *inputBuffer, PaStreamCallbackFlags statusFlags, void *userData); -/* - ** TODO: Docs - */ -class Audio { -public: - static void init (); - static void terminate (); - - // Audio values clamped betewen -1.0f and 1.0f - static void writeAudio (unsigned int offset, unsigned int length, float *left, float *right); - static void addAudio (unsigned int offset, unsigned int length, float *left, float *right); - static void writeTone (unsigned int offset, unsigned int length, float left, float right); - static void addTone (unsigned int offset, unsigned int length, float left, float right); - static void clearAudio (unsigned int offset, unsigned int length); - - static void setInputGain (float gain) { - data->inputGain = gain; - } - -private: - static bool initialized; - - static struct AudioData { - struct BufferFrame{ - float l, r; - } *buffer; - const static unsigned int bufferLength = 1000; - unsigned int bufferPos; - static float inputGain;// = 1.f; - - AudioData () : bufferPos(0) { - inputGain = 1.0f; - buffer = new BufferFrame[bufferLength]; - for (unsigned int i = 0; i < bufferLength; ++i) { - buffer[i].l = buffer[i].r = 0; - } - } - ~AudioData () { - delete[] buffer; - } - - }*data; - static PaStream *stream; - static PaError err; - - Audio (); // prevent instantiation (private constructor) - - - friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*); -}; #endif diff --git a/field.cpp b/field.cpp index 1232c50b76..9abd2b9feb 100644 --- a/field.cpp +++ b/field.cpp @@ -107,3 +107,4 @@ void field_render() glEnd(); } + diff --git a/field.h b/field.h index 8867123fdf..9c565861b9 100644 --- a/field.h +++ b/field.h @@ -9,6 +9,8 @@ #ifndef interface_field_h #define interface_field_h +#include + // Field is a lattice of vectors uniformly distributed FIELD_ELEMENTS^(1/3) on side const int FIELD_ELEMENTS = 1000; @@ -18,4 +20,15 @@ int field_value(float *ret, float *pos); void field_render(); void field_add(float* add, float *loc); +class Field { +public: + static void init (); + static int addTo (const glm::vec3 &pos, glm::vec3 &v); + +private: + const static unsigned int fieldSize = 1000; + const static float fieldScale; // defined in cpp – inline const float definitions not allowed in standard C++?! (allowed in C++0x) + static glm::vec3 field[fieldSize]; +}; + #endif diff --git a/interface.xcodeproj/project.pbxproj b/interface.xcodeproj/project.pbxproj index a47dfaf8e4..8380081120 100644 --- a/interface.xcodeproj/project.pbxproj +++ b/interface.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ B6BDADE215F44AA5002A07DF /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6BDADD815F444C1002A07DF /* CoreAudio.framework */; }; B6BDADE315F44AB0002A07DF /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6BDADDA15F444C9002A07DF /* AudioToolbox.framework */; }; B6BDADE415F44AC7002A07DF /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6BDADDC15F444D3002A07DF /* AudioUnit.framework */; }; + B6BDAE4415F6BE53002A07DF /* particle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6BDAE4315F6BE53002A07DF /* particle.cpp */; }; D40BDFD513404BA300B0BE1F /* GLUT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40BDFD413404BA300B0BE1F /* GLUT.framework */; }; D40BDFD713404BB300B0BE1F /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40BDFD613404BB300B0BE1F /* OpenGL.framework */; }; D4EE3BBC15E45FFE00EE4C89 /* SerialInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D4EE3BBB15E45FFE00EE4C89 /* SerialInterface.cpp */; }; @@ -46,6 +47,8 @@ B6BDADDA15F444C9002A07DF /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; B6BDADDC15F444D3002A07DF /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; }; B6BDADDE15F444DB002A07DF /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; + B6BDAE4115F6BE4D002A07DF /* particle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = particle.h; sourceTree = ""; }; + B6BDAE4315F6BE53002A07DF /* particle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = particle.cpp; sourceTree = ""; }; C6859E8B029090EE04C91782 /* test_c_plus.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = test_c_plus.1; sourceTree = ""; }; D40BDFD413404BA300B0BE1F /* GLUT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLUT.framework; path = /System/Library/Frameworks/GLUT.framework; sourceTree = ""; }; D40BDFD613404BB300B0BE1F /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; @@ -99,6 +102,8 @@ isa = PBXGroup; children = ( 08FB7796FE84155DC02AAC07 /* main.cpp */, + B6BDAE4115F6BE4D002A07DF /* particle.h */, + B6BDAE4315F6BE53002A07DF /* particle.cpp */, D4EE3BC015E746E900EE4C89 /* world.h */, D4EE3BC415EBD90C00EE4C89 /* network.h */, D4EE3BC515EBD93400EE4C89 /* network.cpp */, @@ -189,6 +194,7 @@ D4EE3BC215E761B000EE4C89 /* util.cpp in Sources */, D4EE3BC615EBD93600EE4C89 /* network.cpp in Sources */, B6BDADD415F4085B002A07DF /* audio.cpp in Sources */, + B6BDAE4415F6BE53002A07DF /* particle.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -210,6 +216,10 @@ "\"$(SRCROOT)\"", /usr/local/lib, ); + OTHER_CPLUSPLUSFLAGS = ( + "-O3", + "$(OTHER_CFLAGS)", + ); PRODUCT_NAME = interface; }; name = Debug; @@ -227,6 +237,10 @@ "\"$(SRCROOT)\"", /usr/local/lib, ); + OTHER_CPLUSPLUSFLAGS = ( + "-O3", + "$(OTHER_CFLAGS)", + ); PRODUCT_NAME = interface; }; name = Release; diff --git a/interface.xcodeproj/project.xcworkspace/xcuserdata/Seiji.xcuserdatad/UserInterfaceState.xcuserstate b/interface.xcodeproj/project.xcworkspace/xcuserdata/Seiji.xcuserdatad/UserInterfaceState.xcuserstate index 9269fb4058..de265ecd95 100644 Binary files a/interface.xcodeproj/project.xcworkspace/xcuserdata/Seiji.xcuserdatad/UserInterfaceState.xcuserstate and b/interface.xcodeproj/project.xcworkspace/xcuserdata/Seiji.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/interface.xcodeproj/xcuserdata/Seiji.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist b/interface.xcodeproj/xcuserdata/Seiji.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist index 14b6b13434..14577d4dbc 100644 --- a/interface.xcodeproj/xcuserdata/Seiji.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist +++ b/interface.xcodeproj/xcuserdata/Seiji.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist @@ -29,5 +29,19 @@ landmarkName = "main(int argc, char** argv)" landmarkType = "7"> + + diff --git a/main.cpp b/main.cpp index 6db95940cd..22bfb46c59 100644 --- a/main.cpp +++ b/main.cpp @@ -766,7 +766,7 @@ void key(unsigned char k, int x, int y) field_add(add, pos); } if (k == 't') { - Audio::writeTone(0, 150, 0.5f, 0.5f); + Audio::writeTone(0, 400, 1.0f, 0.5f); } } diff --git a/particle.cpp b/particle.cpp new file mode 100644 index 0000000000..c5cc15162b --- /dev/null +++ b/particle.cpp @@ -0,0 +1,67 @@ +// +// particle.cpp +// interface +// +// Created by Seiji Emery on 9/4/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#include "particle.h" + +void ParticleSystem::simulate (float deltaTime) { + for (unsigned int i = 0; i < particleCount; ++i) { + // Move particles + particles[i].position += particles[i].velocity * deltaTime; + + // Add gravity + particles[i].velocity.y -= gravity; + + // Drag: decay velocity + particles[i].velocity *= 0.99; + + // Add velocity from field + //Field::addTo(particles[i].velocity); + //particles[i].velocity += Field::valueAt(particles[i].position); + + if (wrapBounds) { + // wrap around bounds + if (particles[i].position.x > bounds.x) + particles[i].position.x -= bounds.x; + else if (particles[i].position.x < 0.0f) + particles[i].position.x += bounds.x; + + if (particles[i].position.y > bounds.y) + particles[i].position.y -= bounds.y; + else if (particles[i].position.y < 0.0f) + particles[i].position.y += bounds.y; + + if (particles[i].position.z > bounds.z) + particles[i].position.z -= bounds.z; + else if (particles[i].position.z < 0.0f) + particles[i].position.z += bounds.z; + } else { + // Bounce at bounds + if (particles[i].position.x > bounds.x + || particles[i].position.x < 0.f) { + particles[i].velocity.x *= -1; + } + if (particles[i].position.y > bounds.y + || particles[i].position.y < 0.f) { + particles[i].velocity.y *= -1; + } + if (particles[i].position.z > bounds.z + || particles[i].position.z < 0.f) { + particles[i].velocity.z *= -1; + } + } + } +} + + + + + + + + + diff --git a/particle.h b/particle.h new file mode 100644 index 0000000000..68982377cf --- /dev/null +++ b/particle.h @@ -0,0 +1,30 @@ +// +// particle.h +// interface +// +// Created by Seiji Emery on 9/4/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#ifndef interface_particle_h +#define interface_particle_h + +#include + +class ParticleSystem { +public: + void simulate (float deltaTime); + void draw (); + +private: + struct Particle { + glm::vec3 position, velocity; + } *particles; + unsigned int particleCount; + + glm::vec3 bounds; + const static bool wrapBounds = false; + const static float gravity = 0.0001; +}; + +#endif