diff --git a/.DS_Store b/.DS_Store index 361ab67534..8a70b493dd 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/SerialInterface.cpp b/SerialInterface.cpp index 3d95fbbc16..e3b63fcdae 100644 --- a/SerialInterface.cpp +++ b/SerialInterface.cpp @@ -58,8 +58,12 @@ int init_port(int baud) int read_sensors(int first_measurement, float * avg_adc_channels, int * adc_channels) { + // Channels: + // 0, 1 = Head Pitch and Yaw + // 2,3,4 = Head XYZ Acceleration + // int samples_read = 0; - const float AVG_RATE = 0.001; // 0.00001; + const float AVG_RATE[] = {0.001, 0.001, 0.01, 0.01, 0.01}; char bufchar[1]; while (read(serial_fd, bufchar, 1) > 0) { @@ -72,20 +76,18 @@ int read_sensors(int first_measurement, float * avg_adc_channels, int * adc_chan // At end - Extract value from string to variables if (serial_buffer[0] != 'p') { - sscanf(serial_buffer, "%d %d %d %d %d %d %d %d", /* Needs to match Num Channels */ + sscanf(serial_buffer, "%d %d %d %d %d", /* Needs to match Num Channels */ &adc_channels[0], &adc_channels[1], &adc_channels[2], &adc_channels[3], - &adc_channels[4], - &adc_channels[5], - &adc_channels[6], - &adc_channels[7]); + &adc_channels[4] + ); for (int i = 0; i < NUM_CHANNELS; i++) { if (!first_measurement) - avg_adc_channels[i] = (1.f - AVG_RATE)*avg_adc_channels[i] + - AVG_RATE*(float)adc_channels[i]; + avg_adc_channels[i] = (1.f - AVG_RATE[i])*avg_adc_channels[i] + + AVG_RATE[i]*(float)adc_channels[i]; else { avg_adc_channels[i] = (float)adc_channels[i]; diff --git a/SerialInterface.h b/SerialInterface.h index e2bb82fde1..3fd7a2146e 100644 --- a/SerialInterface.h +++ b/SerialInterface.h @@ -9,7 +9,7 @@ int init_port (int baud); int read_sensors(int first_measurement, float * avg_adc_channels, int * adc_channels); -#define NUM_CHANNELS 8 -#define SERIAL_PORT_NAME "/dev/tty.usbmodem411" +#define NUM_CHANNELS 5 +#define SERIAL_PORT_NAME "/dev/tty.usbmodem641" #endif diff --git a/cloud.cpp b/cloud.cpp new file mode 100644 index 0000000000..18a05ced44 --- /dev/null +++ b/cloud.cpp @@ -0,0 +1,119 @@ +// +// cloud.cpp +// interface +// +// Created by Philip Rosedale on 11/17/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#include +#include "cloud.h" +#include "util.h" + +Cloud::Cloud(int num, + glm::vec3 box, + int wrap) { + // Create and initialize particles + int i; + bounds = box; + count = num; + wrapBounds = wrap; + particles = new Particle[count]; + + for (i = 0; i < count; i++) { + particles[i].position.x = randFloat()*box.x; + particles[i].position.y = randFloat()*box.y; + particles[i].position.z = randFloat()*box.z; + + particles[i].velocity.x = 0; //randFloat() - 0.5; + particles[i].velocity.y = 0; //randFloat() - 0.5; + particles[i].velocity.z = 0; //randFloat() - 0.5; + + } +} + + +void Cloud::render() { + + float particle_attenuation_quadratic[] = { 0.0f, 0.0f, 2.0f }; + + glEnable( GL_TEXTURE_2D ); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, particle_attenuation_quadratic ); + + float maxSize = 0.0f; + glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); + glPointSize( maxSize ); + glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, maxSize ); + glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 0.001f ); + + glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE ); + glEnable( GL_POINT_SPRITE_ARB ); + glBegin( GL_POINTS ); + for (int i = 0; i < count; i++) + { + glVertex3f(particles[i].position.x, + particles[i].position.y, + particles[i].position.z); + } + glEnd(); + glDisable( GL_POINT_SPRITE_ARB ); + glDisable( GL_TEXTURE_2D ); +} + +void Cloud::simulate (float deltaTime) { + int i; + for (i = 0; i < count; ++i) { + + // Update position + //particles[i].position += particles[i].velocity*deltaTime; + particles[i].position += particles[i].velocity; + + // Decay Velocity (Drag) + const float CONSTANT_DAMPING = 1.0; + particles[i].velocity *= (1.f - CONSTANT_DAMPING*deltaTime); + + // Interact with Field + const float FIELD_COUPLE = 0.0000001; + field_interact(&particles[i].position, &particles[i].velocity, FIELD_COUPLE); + + // Bounce or Wrap + 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) { + if (particles[i].position.x > bounds.x) particles[i].position.x = bounds.x; + else particles[i].position.x = 0.f; + particles[i].velocity.x *= -1; + } + if (particles[i].position.y > bounds.y + || particles[i].position.y < 0.f) { + if (particles[i].position.y > bounds.y) particles[i].position.y = bounds.y; + else particles[i].position.y = 0.f; + particles[i].velocity.y *= -1; + } + if (particles[i].position.z > bounds.z + || particles[i].position.z < 0.f) { + if (particles[i].position.z > bounds.z) particles[i].position.z = bounds.z; + else particles[i].position.z = 0.f; + particles[i].velocity.z *= -1; + } + } + } + } diff --git a/cloud.h b/cloud.h new file mode 100644 index 0000000000..575501be25 --- /dev/null +++ b/cloud.h @@ -0,0 +1,32 @@ +// +// cloud.h +// interface +// +// Created by Philip Rosedale on 11/17/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#ifndef interface_cloud_h +#define interface_cloud_h + +#include "field.h" + +class Cloud { +public: + Cloud(int num, + glm::vec3 box, + int wrap); + + void simulate(float deltaTime); + void render(); + +private: + struct Particle { + glm::vec3 position, velocity; + } *particles; + unsigned int count; + glm::vec3 bounds; + bool wrapBounds; +}; + +#endif diff --git a/field.cpp b/field.cpp index b4a9351a46..d08c93822c 100644 --- a/field.cpp +++ b/field.cpp @@ -60,6 +60,21 @@ void field_add(float* add, float *pos) } } +void field_interact(glm::vec3 * pos, glm::vec3 * vel, float coupling) { + + int index = (int)(pos->x/WORLD_SIZE*10.0) + + (int)(pos->y/WORLD_SIZE*10.0)*10 + + (int)(pos->z/WORLD_SIZE*10.0)*100; + if ((index >= 0) && (index < FIELD_ELEMENTS)) { + // Add velocity to particle from field + *vel += field[index].val; + // Add back to field from particle velocity + glm::vec3 temp = *vel; + temp *= coupling; + field[index].val += temp; + } +} + void field_avg_neighbors(int index, glm::vec3 * result) { // Given index to field element i, return neighbor field values glm::vec3 neighbors(0,0,0); diff --git a/field.h b/field.h index ca62f91cec..e1d26206f2 100644 --- a/field.h +++ b/field.h @@ -27,17 +27,7 @@ void field_init(); int field_value(float *ret, float *pos); void field_render(); void field_add(float* add, float *loc); +void field_interact(glm::vec3 * pos, glm::vec3 * vel, float coupling); void field_simulate(float dt); -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/hardware/head_hand/head_hand.pde b/hardware/head_hand/head_hand.pde index 7e4bb60955..2dbdecdb86 100644 --- a/hardware/head_hand/head_hand.pde +++ b/hardware/head_hand/head_hand.pde @@ -4,16 +4,16 @@ Read a set of analog input lines and echo their readings over the serial port wi // ADC PIN MAPPINGS // -// 0, 1 = Head Pitch, Yaw gyro -// 2,3,4 = Head Accelerometer -// 10,11,12 = Hand Accelerometer +// 15,16 = Head Pitch, Yaw gyro +// 17,18,19 = Head Accelerometer -#define NUM_CHANNELS 8 -#define AVERAGE_COUNT 100 -#define TOGGLE_LED_SAMPLES 1000 -int inputPins[NUM_CHANNELS] = {0,1,2,3,4,10,11,12}; +#define NUM_CHANNELS 5 +#define MSECS_PER_SAMPLE 10 +int inputPins[NUM_CHANNELS] = {19,20,15,16,17}; + +unsigned int time; int measured[NUM_CHANNELS]; float accumulate[NUM_CHANNELS]; @@ -29,24 +29,30 @@ void setup() accumulate[i] = measured[i]; } pinMode(BOARD_LED_PIN, OUTPUT); + time = millis(); } void loop() { int i; - sampleCount++; + sampleCount++; for (i = 0; i < NUM_CHANNELS; i++) { - if (sampleCount % AVERAGE_COUNT == 0) { - measured[i] = accumulate[i] / AVERAGE_COUNT; - SerialUSB.print(measured[i]); - SerialUSB.print(" "); - accumulate[i] = 0; - } else { - accumulate[i] += analogRead(inputPins[i]); - } + accumulate[i] += analogRead(inputPins[i]); } - if (sampleCount % AVERAGE_COUNT == 0) SerialUSB.println(""); - if (sampleCount % TOGGLE_LED_SAMPLES == 0) toggleLED(); + if ((millis() - time) >= MSECS_PER_SAMPLE) { + time = millis(); + for (i = 0; i < NUM_CHANNELS; i++) { + measured[i] = accumulate[i] / sampleCount; + SerialUSB.print(measured[i]); + SerialUSB.print(" "); + accumulate[i] = 0; + } + //SerialUSB.print("("); + //SerialUSB.print(sampleCount); + //SerialUSB.print(")"); + SerialUSB.println(""); + sampleCount = 0; + } } diff --git a/head.cpp b/head.cpp index bf1478db02..f2132e788d 100644 --- a/head.cpp +++ b/head.cpp @@ -43,6 +43,8 @@ Head::Head() PitchTarget = YawTarget = 0; NoiseEnvelope = 1.0; PupilConverge = 2.1; + leanForward = 0.0; + leanSideways = 0.0; setNoise(0); } @@ -51,10 +53,22 @@ void Head::reset() position = glm::vec3(0,0,0); Pitch = 0; Yaw = 0; + leanForward = leanSideways = 0; +} + +// Read the sensors +void readSensors() +{ + +} + +void Head::addLean(float x, float z) { + // Add Body lean as impulse + leanSideways += x; + leanForward += z; } // Simulate the head over time - void Head::simulate(float deltaTime) { if (!noise) @@ -71,6 +85,9 @@ void Head::simulate(float deltaTime) Roll *= (1.f - DECAY*deltaTime); } + leanForward *= (1.f - DECAY*30.f*deltaTime); + leanSideways *= (1.f - DECAY*30.f*deltaTime); + if (noise) { Pitch += (randFloat() - 0.5)*0.05*NoiseEnvelope; @@ -118,6 +135,7 @@ void Head::render() glPushMatrix(); glLoadIdentity(); glTranslatef(0.f, 0.f, -7.f); + glTranslatef(leanSideways, 0.f, leanForward); glRotatef(Yaw/2.0, 0, 1, 0); glRotatef(Pitch/2.0, 1, 0, 0); glRotatef(Roll/2.0, 0, 0, 1); @@ -160,6 +178,7 @@ void Head::render() } glPopMatrix(); + // Mouth glPushMatrix(); glTranslatef(0,-0.3,0.75); diff --git a/head.h b/head.h index eef04f2eb3..be228137ec 100644 --- a/head.h +++ b/head.h @@ -34,6 +34,8 @@ class Head { float MouthYaw; float MouthWidth; float MouthHeight; + float leanForward; + float leanSideways; float PitchTarget; float YawTarget; @@ -44,6 +46,8 @@ class Head { glm::vec3 position; + void readSensors(); + public: Head(void); void reset(); @@ -52,6 +56,7 @@ public: void setYaw(float y) {Yaw = y; } void addPitch(float p) {Pitch -= p; } void addYaw(float y){Yaw -= y; } + void addLean(float x, float z); void getPitch(float); void render(); void simulate(float); diff --git a/interface.xcodeproj/project.pbxproj b/interface.xcodeproj/project.pbxproj index 19f14f81cd..c4db3df7e8 100644 --- a/interface.xcodeproj/project.pbxproj +++ b/interface.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 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 */; }; + D409B98A165849180099B0B3 /* cloud.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D409B989165849180099B0B3 /* cloud.cpp */; }; D40BDFD513404BA300B0BE1F /* GLUT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40BDFD413404BA300B0BE1F /* GLUT.framework */; }; D40BDFD713404BB300B0BE1F /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40BDFD613404BB300B0BE1F /* OpenGL.framework */; }; D40FD5FB164AF1C200878184 /* int-texture256-v2.png in CopyFiles */ = {isa = PBXBuildFile; fileRef = D40FD5FA164AF1A700878184 /* int-texture256-v2.png */; }; @@ -66,6 +67,8 @@ 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 = ""; }; + D409B988165849030099B0B3 /* cloud.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cloud.h; sourceTree = ""; }; + D409B989165849180099B0B3 /* cloud.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cloud.cpp; 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 = ""; }; D40FD5FA164AF1A700878184 /* int-texture256-v2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "int-texture256-v2.png"; sourceTree = SOURCE_ROOT; }; @@ -134,6 +137,8 @@ isa = PBXGroup; children = ( 08FB7796FE84155DC02AAC07 /* main.cpp */, + D409B988165849030099B0B3 /* cloud.h */, + D409B989165849180099B0B3 /* cloud.cpp */, D4EE3BC015E746E900EE4C89 /* world.h */, B6BDAE4315F6BE53002A07DF /* particle.cpp */, B6BDAE4115F6BE4D002A07DF /* particle.h */, @@ -261,6 +266,7 @@ D4EFE3D0162A2DA000DC5C59 /* hand.cpp in Sources */, F68135561648617D003040E3 /* texture.cpp in Sources */, F681358B1648896D003040E3 /* lodepng.cpp in Sources */, + D409B98A165849180099B0B3 /* cloud.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/interface.xcodeproj/project.xcworkspace/xcuserdata/philip.xcuserdatad/UserInterfaceState.xcuserstate b/interface.xcodeproj/project.xcworkspace/xcuserdata/philip.xcuserdatad/UserInterfaceState.xcuserstate index 7f7bb244ff..1cabcd6b99 100644 Binary files a/interface.xcodeproj/project.xcworkspace/xcuserdata/philip.xcuserdatad/UserInterfaceState.xcuserstate and b/interface.xcodeproj/project.xcworkspace/xcuserdata/philip.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/interface.xcodeproj/xcuserdata/philip.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist b/interface.xcodeproj/xcuserdata/philip.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist index d8e15f635a..556fc539eb 100644 --- a/interface.xcodeproj/xcuserdata/philip.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist +++ b/interface.xcodeproj/xcuserdata/philip.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist @@ -8,11 +8,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "field.cpp" - timestampString = "372274896.176083" + timestampString = "374955033.430214" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "83" - endingLineNumber = "83" + startingLineNumber = "98" + endingLineNumber = "98" landmarkName = "field_avg_neighbors(int index, glm::vec3 * result)" landmarkType = "7"> diff --git a/main.cpp b/main.cpp index ecfc6dddcf..af3a6c2b06 100644 --- a/main.cpp +++ b/main.cpp @@ -49,12 +49,16 @@ #include "texture.h" +#include "cloud.h" + //TGAImg Img; using namespace std; // Junk for talking to the Serial Port int serial_on = 0; // Is serial connection on/off? System will try +int audio_on = 0; // Whether to turn on the audio support +int simulate_on = 1; // Network Socket Stuff // For testing, add milliseconds of delay for received UDP packets @@ -73,6 +77,8 @@ int bytescount = 0; int target_x, target_y; int target_display = 0; +int head_mirror = 0; // Whether to mirror the head when viewing it + unsigned char last_key = 0; double ping = 0; @@ -89,15 +95,18 @@ Hand myHand(HAND_RADIUS, glm::vec3(0,1,1)); // My hand (used to manipulate things in world) glm::vec3 box(WORLD_SIZE,WORLD_SIZE,WORLD_SIZE); -ParticleSystem balls(1000, +ParticleSystem balls(0, box, - false, // Wrap? - 0.02, // Noise + false, // Wrap? + 0.02, // Noise 0.3, // Size scale - 0.0 // Gravity + 0.0 // Gravity ); - +Cloud cloud(250000, // Particles + box, // Bounding Box + false // Wrap + ); // FIELD INFORMATION // If the simulation 'world' is a box with 10M boundaries, the offset to a field cell is given by: @@ -112,15 +121,11 @@ ParticleSystem balls(1000, #define RENDER_FRAME_MSECS 10 #define SLEEP 0 -#define NUM_TRIS 100000 +#define NUM_TRIS 0 + struct { float vertices[NUM_TRIS * 3]; -// float normals [NUM_TRIS * 3]; -// float colors [NUM_TRIS * 3]; float vel [NUM_TRIS * 3]; - glm::vec3 vel1[NUM_TRIS]; - glm::vec3 vel2[NUM_TRIS]; - int element[NUM_TRIS]; }tris; @@ -153,8 +158,9 @@ int display_head = 0; int display_hand = 0; int display_field = 0; -int display_head_mouse = 1; // Display sample mouse pointer controlled by head movement -int head_mouse_x, head_mouse_y; +int display_head_mouse = 1; // Display sample mouse pointer controlled by head movement +int head_mouse_x, head_mouse_y; +int head_lean_x, head_lean_y; int mouse_x, mouse_y; // Where is the mouse int mouse_pressed = 0; // true if mouse has been pressed (clear when finished) @@ -194,7 +200,7 @@ double elapsedTime; // 1. Add to the XCode project in the Resources/images group // (ensure "Copy file" is checked // 2. Add to the "Copy files" build phase in the project -char texture_filename[] = "int-texture256-v4.png"; +char texture_filename[] = "./int-texture256-v4.png"; unsigned int texture_width = 256; unsigned int texture_height = 256; @@ -264,8 +270,10 @@ void init(void) load_png_as_texture(texture_filename); printf("Texture loaded.\n"); - Audio::init(); - printf( "Audio started.\n" ); + if (audio_on) { + Audio::init(); + printf( "Audio started.\n" ); + } // Clear serial channels for (i = i; i < NUM_CHANNELS; i++) @@ -276,6 +284,8 @@ void init(void) head_mouse_x = WIDTH/2; head_mouse_y = HEIGHT/2; + head_lean_x = WIDTH/2; + head_lean_y = HEIGHT/2; // Initialize Field values field_init(); @@ -316,7 +326,6 @@ void init(void) //tris.normals[i*3+2] = pos.z; // Moving - white - tris.element[i] = 1; //tris.colors[i*3] = 1.0; tris.colors[i*3+1] = 1.0; tris.colors[i*3+2] = 1.0; tris.vel[i*3] = (randFloat() - 0.5)*VEL_SCALE; tris.vel[i*3+1] = (randFloat() - 0.5)*VEL_SCALE; @@ -349,7 +358,9 @@ void terminate () { // Close serial port //close(serial_fd); - Audio::terminate(); + if (audio_on) { + Audio::terminate(); + } exit(EXIT_SUCCESS); } @@ -365,39 +376,34 @@ void update_tris() float field_contrib[3]; for (i = 0; i < NUM_TRIS; i++) { - if (tris.element[i] == 1) // If moving object, move and drag - { - // Update position - tris.vertices[i*3+0] += tris.vel[i*3]; - tris.vertices[i*3+1] += tris.vel[i*3+1]; - tris.vertices[i*3+2] += tris.vel[i*3+2]; - - // Add a little gravity - //tris.vel[i*3+1] -= 0.0001; - - const float DRAG = 0.99; - // Drag: Decay velocity - tris.vel[i*3] *= DRAG; - tris.vel[i*3+1] *= DRAG; - tris.vel[i*3+2] *= DRAG; - } + // Update position + tris.vertices[i*3+0] += tris.vel[i*3]; + tris.vertices[i*3+1] += tris.vel[i*3+1]; + tris.vertices[i*3+2] += tris.vel[i*3+2]; + + // Add a little gravity + //tris.vel[i*3+1] -= 0.0001; + + const float DRAG = 0.99; + // Drag: Decay velocity + tris.vel[i*3] *= DRAG; + tris.vel[i*3+1] *= DRAG; + tris.vel[i*3+2] *= DRAG; - if (tris.element[i] == 1) - { - // Read and add velocity from field - field_value(field_val, &tris.vertices[i*3]); - tris.vel[i*3] += field_val[0]; - tris.vel[i*3+1] += field_val[1]; - tris.vel[i*3+2] += field_val[2]; + // Read and add velocity from field + field_value(field_val, &tris.vertices[i*3]); + tris.vel[i*3] += field_val[0]; + tris.vel[i*3+1] += field_val[1]; + tris.vel[i*3+2] += field_val[2]; + + // Add a tiny bit of energy back to the field + const float FIELD_COUPLE = 0.0000001; + field_contrib[0] = tris.vel[i*3]*FIELD_COUPLE; + field_contrib[1] = tris.vel[i*3+1]*FIELD_COUPLE; + field_contrib[2] = tris.vel[i*3+2]*FIELD_COUPLE; + field_add(field_contrib, &tris.vertices[i*3]); - // Add a tiny bit of energy back to the field - const float FIELD_COUPLE = 0.0000001; - field_contrib[0] = tris.vel[i*3]*FIELD_COUPLE; - field_contrib[1] = tris.vel[i*3+1]*FIELD_COUPLE; - field_contrib[2] = tris.vel[i*3+2]*FIELD_COUPLE; - field_add(field_contrib, &tris.vertices[i*3]); - } - + // bounce at edge of world for (j=0; j < 3; j++) { if ((tris.vertices[i*3+j] > WORLD_SIZE) || (tris.vertices[i*3+j] < 0.0)) { @@ -424,6 +430,9 @@ void reset_sensors() fwd_vel = 0.0; head_mouse_x = WIDTH/2; head_mouse_y = HEIGHT/2; + head_lean_x = WIDTH/2; + head_lean_y = HEIGHT/2; + myHead.reset(); myHand.reset(); if (serial_on) read_sensors(1, &avg_adc_channels[0], &adc_channels[0]); @@ -434,12 +443,21 @@ void update_pos(float frametime) { float measured_pitch_rate = adc_channels[0] - avg_adc_channels[0]; float measured_yaw_rate = adc_channels[1] - avg_adc_channels[1]; - float measured_lateral_accel = adc_channels[2] - avg_adc_channels[2]; - float measured_fwd_accel = avg_adc_channels[3] - adc_channels[3]; + float measured_lateral_accel = adc_channels[3] - avg_adc_channels[3]; + float measured_fwd_accel = avg_adc_channels[2] - adc_channels[2]; // Update avatar head position based on measured gyro rates - myHead.addYaw(measured_yaw_rate * 1.20 * frametime); - myHead.addPitch(measured_pitch_rate * -1.0 * frametime); + const float HEAD_ROTATION_SCALE = 0.10; + const float HEAD_LEAN_SCALE = 0.02; + if (head_mirror) { + myHead.addYaw(measured_yaw_rate * HEAD_ROTATION_SCALE * frametime); + myHead.addPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); + myHead.addLean(measured_lateral_accel * frametime * HEAD_LEAN_SCALE, measured_fwd_accel*frametime * HEAD_LEAN_SCALE); + } else { + myHead.addYaw(measured_yaw_rate * -HEAD_ROTATION_SCALE * frametime); + myHead.addPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); + myHead.addLean(measured_lateral_accel * frametime * -HEAD_LEAN_SCALE, measured_fwd_accel*frametime * HEAD_LEAN_SCALE); + } // Decay avatar head back toward zero //pitch *= (1.f - 5.0*frametime); //yaw *= (1.f - 7.0*frametime); @@ -459,6 +477,7 @@ void update_pos(float frametime) head_mouse_y = min(head_mouse_y, HEIGHT); // Update hand/manipulator location for measured forces from serial channel + /* const float MIN_HAND_ACCEL = 30.0; const float HAND_FORCE_SCALE = 0.5; glm::vec3 hand_accel(-(avg_adc_channels[6] - adc_channels[6]), @@ -469,6 +488,7 @@ void update_pos(float frametime) { myHand.addVel(frametime*hand_accel*HAND_FORCE_SCALE); } + */ // Update render direction (pitch/yaw) based on measured gyro rates const int MIN_YAW_RATE = 300; @@ -594,23 +614,25 @@ void display(void) glPointSize( maxSize ); glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, maxSize ); glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 0.001f ); - glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE ); - - glEnable( GL_POINT_SPRITE_ARB ); - glBegin( GL_POINTS ); - { - for (i = 0; i < NUM_TRIS; i++) - { - glVertex3f(tris.vertices[i*3], - tris.vertices[i*3+1], - tris.vertices[i*3+2]); - } - } - glEnd(); - - glDisable( GL_TEXTURE_2D ); - glDisable( GL_POINT_SPRITE_ARB ); + glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE ); + glEnable( GL_POINT_SPRITE_ARB ); + if (!display_head) { + glBegin( GL_POINTS ); + { + for (i = 0; i < NUM_TRIS; i++) + { + glVertex3f(tris.vertices[i*3], + tris.vertices[i*3+1], + tris.vertices[i*3+2]); + } + } + glEnd(); + } + glDisable( GL_POINT_SPRITE_ARB ); + glDisable( GL_TEXTURE_2D ); + + if (!display_head) cloud.render(); // Show field vectors if (display_field) field_render(); @@ -619,10 +641,10 @@ void display(void) if (display_hand) myHand.render(); - balls.render(); + if (!display_head) balls.render(); // Render the world box - render_world_box(); + if (!display_head) render_world_box(); glPopMatrix(); @@ -635,10 +657,10 @@ void display(void) glDisable(GL_LIGHTING); //drawvec3(100, 100, 0.15, 0, 1.0, 0, myHead.getPos(), 0, 1, 0); - + glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, pointer_attenuation_quadratic ); + if (mouse_pressed == 1) { - glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, pointer_attenuation_quadratic ); glPointSize( 10.0f ); glColor3f(1,1,1); //glEnable(GL_POINT_SMOOTH); @@ -649,7 +671,7 @@ void display(void) sprintf(val, "%d,%d", target_x, target_y); drawtext(target_x, target_y-20, 0.08, 0, 1.0, 0, val, 0, 1, 0); } - if (display_head_mouse) + if (display_head_mouse && !display_head) { glPointSize(10.0f); glColor4f(1.0, 1.0, 0.0, 0.8); @@ -706,7 +728,7 @@ void key(unsigned char k, int x, int y) if (k == '/') stats_on = !stats_on; // toggle stats if (k == 'n') { - noise_on = !noise_on; // Toggle noise + noise_on = !noise_on; // Toggle noise if (noise_on) { myHand.setNoise(noise); @@ -731,6 +753,7 @@ void key(unsigned char k, int x, int y) if (k == ' ') reset_sensors(); if (k == 'a') render_yaw_rate -= 0.25; if (k == 'd') render_yaw_rate += 0.25; + if (k == 'o') simulate_on = !simulate_on; if (k == 'p') { // Add to field vector @@ -738,7 +761,7 @@ void key(unsigned char k, int x, int y) float add[] = {0.001, 0.001, 0.001}; field_add(add, pos); } - if (k == 't') { + if ((k == 't') && (audio_on)) { Audio::writeTone(0, 400, 1.0f, 0.5f); } if (k == '1') @@ -780,11 +803,14 @@ void idle(void) { // Simulation update_pos(1.f/FPS); - update_tris(); - field_simulate(1.f/FPS); - myHead.simulate(1.f/FPS); - myHand.simulate(1.f/FPS); - balls.simulate(1.f/FPS); + if (simulate_on) { + update_tris(); + field_simulate(1.f/FPS); + myHead.simulate(1.f/FPS); + myHand.simulate(1.f/FPS); + balls.simulate(1.f/FPS); + cloud.simulate(1.f/FPS); + } if (!step_on) glutPostRedisplay(); last_frame = check;