diff --git a/agent.cpp b/agent.cpp new file mode 100644 index 0000000000..63aef1c6b4 --- /dev/null +++ b/agent.cpp @@ -0,0 +1,87 @@ +// +// agent.cpp +// interface +// +// Created by Philip Rosedale on 11/20/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#include +#include "agent.h" + +// Structure to hold references to other agents that are nearby + +const int MAX_AGENTS = 100; +struct AgentList { + in_addr sin_addr; + glm::vec3 position; +} agents[MAX_AGENTS]; +int num_agents = 0; + +// +// Process an incoming spaceserver packet telling you about other nearby agents +// +void update_agents(char * data, int length) { + std::string packet(data, length); + //std::string packet("127.0.0.1,"); + //std::cout << " Update Agents, string: " << packet << "\n"; + size_t spot; + size_t start_spot = 0; + spot = packet.find_first_of (",", 0); + while (spot != std::string::npos) { + std::string IPstring = packet.substr(start_spot, spot-start_spot); + //std::cout << "Found " << num_agents << + //" with IP " << IPstring << " from " << start_spot << " to " << spot << "\n"; + // Add the IP address to the agent table + add_agent(&IPstring); + start_spot = spot + 1; + if (start_spot < packet.length()) + spot = packet.find_first_of (",", start_spot); + else spot = std::string::npos; + } +} + +// +// Look for an agent by it's IP number, add if it does not exist in local list +// +int add_agent(std::string * IP) { + in_addr_t addr = inet_addr(IP->c_str()); + //std::cout << "Checking for " << IP->c_str() << " "; + for (int i = 0; i < num_agents; i++) { + if (agents[i].sin_addr.s_addr == addr) { + //std::cout << "Found!\n"; + return 0; + } + } + if (num_agents < MAX_AGENTS) { + agents[num_agents].sin_addr.s_addr = addr; + std::cout << "Added Agent # " << num_agents << " with IP " << + inet_ntoa(agents[num_agents].sin_addr) << "\n"; + num_agents++; + return 1; + } else { + std::cout << "Max agents reached fail!\n"; + return 0; + } +} + +// +// Broadcast data to all the other agents you are aware of, returns 1 for success +// +int broadcast(int handle, char * data, int length) { + sockaddr_in dest_address; + dest_address.sin_family = AF_INET; + dest_address.sin_port = htons( (unsigned short) UDP_PORT ); + + int sent_bytes; + for (int i = 0; i < num_agents; i++) { + dest_address.sin_addr.s_addr = agents[i].sin_addr.s_addr; + sent_bytes = sendto( handle, (const char*)data, length, + 0, (sockaddr*)&dest_address, sizeof(sockaddr_in) ); + if (sent_bytes != length) { + std::cout << "Broadcast packet fail!\n"; + return 0; + } + } + return 1; +} diff --git a/agent.h b/agent.h new file mode 100644 index 0000000000..ec3f42028b --- /dev/null +++ b/agent.h @@ -0,0 +1,24 @@ +// +// agent.h +// interface +// +// Created by Philip Rosedale on 11/20/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#ifndef interface_agent_h +#define interface_agent_h + +#include "glm/glm.hpp" +#include +#include +#include +#include +#include +#include "network.h" + +void update_agents(char * data, int length); +int add_agent(std::string * IP); +int broadcast(int handle, char * data, int length); + +#endif diff --git a/head.cpp b/head.cpp index f2132e788d..98cbf0d0d3 100644 --- a/head.cpp +++ b/head.cpp @@ -62,6 +62,125 @@ void readSensors() } +/* +void update_pos(float frametime) +// Using serial data, update avatar/render position and angles +{ + 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[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 + const float HEAD_ROTATION_SCALE = 0.20; + 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); + + // Update head_mouse model + const float MIN_MOUSE_RATE = 30.0; + const float MOUSE_SENSITIVITY = 0.1; + if (powf(measured_yaw_rate*measured_yaw_rate + + measured_pitch_rate*measured_pitch_rate, 0.5) > MIN_MOUSE_RATE) + { + head_mouse_x -= measured_yaw_rate*MOUSE_SENSITIVITY; + head_mouse_y += measured_pitch_rate*MOUSE_SENSITIVITY*(float)HEIGHT/(float)WIDTH; + } + head_mouse_x = max(head_mouse_x, 0); + head_mouse_x = min(head_mouse_x, WIDTH); + head_mouse_y = max(head_mouse_y, 0); + head_mouse_y = min(head_mouse_y, HEIGHT); + + // Update render direction (pitch/yaw) based on measured gyro rates + const int MIN_YAW_RATE = 300; + const float YAW_SENSITIVITY = 0.03; + const int MIN_PITCH_RATE = 300; + const float PITCH_SENSITIVITY = 0.04; + + if (fabs(measured_yaw_rate) > MIN_YAW_RATE) + { + if (measured_yaw_rate > 0) + render_yaw_rate -= (measured_yaw_rate - MIN_YAW_RATE) * YAW_SENSITIVITY * frametime; + else + render_yaw_rate -= (measured_yaw_rate + MIN_YAW_RATE) * YAW_SENSITIVITY * frametime; + } + if (fabs(measured_pitch_rate) > MIN_PITCH_RATE) + { + if (measured_pitch_rate > 0) + render_pitch_rate += (measured_pitch_rate - MIN_PITCH_RATE) * PITCH_SENSITIVITY * frametime; + else + render_pitch_rate += (measured_pitch_rate + MIN_PITCH_RATE) * PITCH_SENSITIVITY * frametime; + } + render_yaw += render_yaw_rate; + render_pitch += render_pitch_rate; + + // Decay render_pitch toward zero because we never look constantly up/down + render_pitch *= (1.f - 2.0*frametime); + + // Decay angular rates toward zero + render_pitch_rate *= (1.f - 5.0*frametime); + render_yaw_rate *= (1.f - 7.0*frametime); + + // Update slide left/right based on accelerometer reading + const int MIN_LATERAL_ACCEL = 20; + const float LATERAL_SENSITIVITY = 0.001; + if (fabs(measured_lateral_accel) > MIN_LATERAL_ACCEL) + { + if (measured_lateral_accel > 0) + lateral_vel += (measured_lateral_accel - MIN_LATERAL_ACCEL) * LATERAL_SENSITIVITY * frametime; + else + lateral_vel += (measured_lateral_accel + MIN_LATERAL_ACCEL) * LATERAL_SENSITIVITY * frametime; + } + + //slide += lateral_vel; + lateral_vel *= (1.f - 4.0*frametime); + + // Update fwd/back based on accelerometer reading + const int MIN_FWD_ACCEL = 20; + const float FWD_SENSITIVITY = 0.001; + + if (fabs(measured_fwd_accel) > MIN_FWD_ACCEL) + { + if (measured_fwd_accel > 0) + fwd_vel += (measured_fwd_accel - MIN_FWD_ACCEL) * FWD_SENSITIVITY * frametime; + else + fwd_vel += (measured_fwd_accel + MIN_FWD_ACCEL) * FWD_SENSITIVITY * frametime; + + } + // Decrease forward velocity + fwd_vel *= (1.f - 4.0*frametime); + + // Update forward vector based on pitch and yaw + fwd_vec[0] = -sinf(render_yaw*PI/180); + fwd_vec[1] = sinf(render_pitch*PI/180); + fwd_vec[2] = cosf(render_yaw*PI/180); + + // Advance location forward + location[0] += fwd_vec[0]*fwd_vel; + location[1] += fwd_vec[1]*fwd_vel; + location[2] += fwd_vec[2]*fwd_vel; + + // Slide location sideways + location[0] += fwd_vec[2]*-lateral_vel; + location[2] += fwd_vec[0]*lateral_vel; + + // Update head and manipulator objects with object with current location + myHead.setPos(glm::vec3(location[0], location[1], location[2])); + balls.updateHand(myHead.getPos() + myHand.getPos(), glm::vec3(0,0,0), myHand.getRadius()); +} +*/ + + void Head::addLean(float x, float z) { // Add Body lean as impulse leanSideways += x; diff --git a/interface.xcodeproj/project.pbxproj b/interface.xcodeproj/project.pbxproj index c4db3df7e8..46d29d8132 100644 --- a/interface.xcodeproj/project.pbxproj +++ b/interface.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 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 */; }; + D409B9A8165CA7BC0099B0B3 /* agent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D409B9A7165CA7BB0099B0B3 /* agent.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 */; }; @@ -69,6 +70,8 @@ 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 = ""; }; + D409B9A6165CA7A50099B0B3 /* agent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = agent.h; sourceTree = ""; }; + D409B9A7165CA7BB0099B0B3 /* agent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = agent.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; }; @@ -137,6 +140,8 @@ isa = PBXGroup; children = ( 08FB7796FE84155DC02AAC07 /* main.cpp */, + D409B9A6165CA7A50099B0B3 /* agent.h */, + D409B9A7165CA7BB0099B0B3 /* agent.cpp */, D409B988165849030099B0B3 /* cloud.h */, D409B989165849180099B0B3 /* cloud.cpp */, D4EE3BC015E746E900EE4C89 /* world.h */, @@ -230,6 +235,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 0430; + ORGANIZATIONNAME = "Rosedale Lab"; }; buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "interface" */; compatibilityVersion = "Xcode 3.2"; @@ -267,6 +273,7 @@ F68135561648617D003040E3 /* texture.cpp in Sources */, F681358B1648896D003040E3 /* lodepng.cpp in Sources */, D409B98A165849180099B0B3 /* cloud.cpp in Sources */, + D409B9A8165CA7BC0099B0B3 /* agent.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 1cabcd6b99..1aded4aa69 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 556fc539eb..f5c01eb1d0 100644 --- a/interface.xcodeproj/xcuserdata/philip.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist +++ b/interface.xcodeproj/xcuserdata/philip.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist @@ -16,5 +16,18 @@ landmarkName = "field_avg_neighbors(int index, glm::vec3 * result)" landmarkType = "7"> + + diff --git a/main.cpp b/main.cpp index 734d10ffbf..87cbc5c2c7 100644 --- a/main.cpp +++ b/main.cpp @@ -33,7 +33,6 @@ #include #include #include -#include "tga.h" // Texture loader library #include "glm/glm.hpp" #include @@ -46,10 +45,10 @@ #include "head.h" #include "hand.h" #include "particle.h" - #include "texture.h" - #include "cloud.h" +#include "agent.h" + //TGAImg Img; @@ -60,7 +59,7 @@ int serial_on = 0; // Is serial connection on/off? System wil int audio_on = 0; // Whether to turn on the audio support int simulate_on = 1; -// Network Socket Stuff +// Network Socket Stuff // For testing, add milliseconds of delay for received UDP packets int UDP_socket; int delay = 0; @@ -79,16 +78,9 @@ int target_display = 0; int head_mirror = 0; // Whether to mirror the head when viewing it -unsigned char last_key = 0; - -double ping = 0; - int WIDTH = 1200; int HEIGHT = 800; -#define BOTTOM_MARGIN 0 -#define RIGHT_MARGIN 0 - #define HAND_RADIUS 0.25 // Radius of in-world 'hand' of you Head myHead; // The rendered head of oneself or others Hand myHand(HAND_RADIUS, @@ -103,33 +95,20 @@ ParticleSystem balls(0, 0.0 // Gravity ); -Cloud cloud(250000, // Particles +Cloud cloud(0, // 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: -// element = [x/10 + (y/10)*10 + (z*/10)*100] -// -// The vec(x,y,z) corner of a field cell at element i is: -// -// z = (int)( i / 100) -// y = (int)(i % 100 / 10) -// x = (int)(i % 10) +float cubes_position[MAX_CUBES*3]; +float cubes_scale[MAX_CUBES]; +float cubes_color[MAX_CUBES*3]; +int cube_count = 0; #define RENDER_FRAME_MSECS 10 #define SLEEP 0 -#define NUM_TRIS 0 - -struct { - float vertices[NUM_TRIS * 3]; - float vel [NUM_TRIS * 3]; -}tris; - - -float yaw =0.f; // The yaw, pitch for the avatar head +float yaw =0.f; // The yaw, pitch for the avatar head float pitch = 0.f; // float start_yaw = 90.0; float render_yaw = start_yaw; @@ -165,7 +144,6 @@ 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) -int accel_x, accel_y; int speed; @@ -224,6 +202,10 @@ void Timer(int extra) glutTimerFunc(1000,Timer,0); gettimeofday(&timer_start, NULL); + + // Send a message to the spaceserver telling it we are ALIVE + notify_spaceserver(UDP_socket, location[0], location[1], location[2]); + } void display_stats(void) @@ -265,10 +247,7 @@ void initDisplay(void) void init(void) { - int i, j; - - load_png_as_texture(texture_filename); - printf("Texture loaded.\n"); + int i; if (audio_on) { Audio::init(); @@ -297,42 +276,20 @@ void init(void) myHead.setNoise(noise); } - // Init particles - float tri_scale, r; - const float VEL_SCALE = 0.00; - for (i = 0; i < NUM_TRIS; i++) - { - r = randFloat(); - if (r > .999) tri_scale = 0.7; - else if (r > 0.90) tri_scale = 0.1; - else tri_scale = 0.05; - - - glm::vec3 pos (randFloat() * WORLD_SIZE, - randFloat() * WORLD_SIZE, - randFloat() * WORLD_SIZE); - glm::vec3 verts[3]; - verts[j].x = pos.x + randFloat() * tri_scale - tri_scale/2.f; - verts[j].y = pos.y + randFloat() * tri_scale - tri_scale/2.f; - verts[j].z = pos.z + randFloat() * tri_scale - tri_scale/2.f; - tris.vertices[i*3] = verts[j].x; - tris.vertices[i*3 + 1] = verts[j].y; - tris.vertices[i*3 + 2] = verts[j].z; - - // reuse pos for the normal - //glm::normalize((pos += glm::cross(verts[1] - verts[0], verts[2] - verts[0]))); - //tris.normals[i*3] = pos.x; - //tris.normals[i*3+1] = pos.y; - //tris.normals[i*3+2] = pos.z; - - // Moving - white - //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; - tris.vel[i*3+2] = (randFloat() - 0.5)*VEL_SCALE; - + int index = 0; + float location[] = {0,0,0}; + float scale = 10.0; + int j = 0; + while (index < (MAX_CUBES/2)) { + index = 0; + j++; + makeCubes(location, scale, &index, cubes_position, cubes_scale, cubes_color); + std::cout << "Run " << j << " Made " << index << " cubes\n"; + cube_count = index; } + //load_png_as_texture(texture_filename); + if (serial_on) { // Call readsensors for a while to get stable initial values on sensors @@ -364,57 +321,6 @@ void terminate () { exit(EXIT_SUCCESS); } -const float SCALE_SENSORS = 0.3f; -const float SCALE_X = 2.f; -const float SCALE_Y = 1.f; - - -void update_tris() -{ - int i, j; - float field_val[3]; - float field_contrib[3]; - for (i = 0; i < NUM_TRIS; i++) - { - // 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; - - // 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]); - - - // 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)) { - tris.vertices[i*3+j] = min(WORLD_SIZE, tris.vertices[i*3+j]); - tris.vertices[i*3+j] = max(0.f, tris.vertices[i*3+j]); - tris.vel[i*3 + j]*= -1.0; - } - } - } -} - void reset_sensors() { // @@ -447,7 +353,7 @@ void update_pos(float frametime) float measured_fwd_accel = avg_adc_channels[2] - adc_channels[2]; // Update avatar head position based on measured gyro rates - const float HEAD_ROTATION_SCALE = 0.10; + const float HEAD_ROTATION_SCALE = 0.20; const float HEAD_LEAN_SCALE = 0.02; if (head_mirror) { myHead.addYaw(measured_yaw_rate * HEAD_ROTATION_SCALE * frametime); @@ -566,13 +472,16 @@ void update_pos(float frametime) // Update head and manipulator objects with object with current location myHead.setPos(glm::vec3(location[0], location[1], location[2])); balls.updateHand(myHead.getPos() + myHand.getPos(), glm::vec3(0,0,0), myHand.getRadius()); + + // Update all this stuff to any agents that are nearby and need to see it! + char test[] = "BXXX"; + broadcast(UDP_socket, test, strlen(test)); } void display(void) { - int i; - + glEnable (GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LINE_SMOOTH); @@ -599,30 +508,27 @@ void display(void) glRotatef(render_pitch, 1, 0, 0); glRotatef(render_yaw, 0, 1, 0); glTranslatef(location[0], location[1], location[2]); + + glPushMatrix(); + glTranslatef(WORLD_SIZE/2, WORLD_SIZE/2, WORLD_SIZE/2); + int i = 0; + while (i < cube_count) { + glPushMatrix(); + glTranslatef(cubes_position[i*3], cubes_position[i*3+1], cubes_position[i*3+2]); + glColor3fv(&cubes_color[i*3]); + glutSolidCube(cubes_scale[i]); + glPopMatrix(); + i++; + } + glPopMatrix(); + /* Draw Point Sprites */ - - //glActiveTexture(GL_TEXTURE0); - glEnable( GL_TEXTURE_2D ); - - //glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); - 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 ); + load_png_as_texture(texture_filename); - glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE ); - glEnable( GL_POINT_SPRITE_ARB ); - if (!display_head) { - glDrawElements(GL_POINTS, NUM_TRIS, GL_FLOAT, tris.vertices); - } glDisable( GL_POINT_SPRITE_ARB ); glDisable( GL_TEXTURE_2D ); - if (!display_head) cloud.render(); // Show field vectors if (display_field) field_render(); @@ -636,9 +542,13 @@ void display(void) // Render the world box if (!display_head) render_world_box(); + + glm::vec3 test(0.5, 0.5, 0.5); + render_vector(&test); glPopMatrix(); + // Render 2D overlay: I/O level bar graphs and text glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -708,14 +618,24 @@ void display(void) glutSwapBuffers(); framecount++; } - +void specialkey(int k, int x, int y) +{ + if (k == GLUT_KEY_UP) fwd_vel += 0.05; + if (k == GLUT_KEY_DOWN) fwd_vel -= 0.05; + if (k == GLUT_KEY_LEFT) { + if (glutGetModifiers() == GLUT_ACTIVE_SHIFT) lateral_vel -= 0.02; + else render_yaw_rate -= 0.25; + } + if (k == GLUT_KEY_RIGHT) { + if (glutGetModifiers() == GLUT_ACTIVE_SHIFT) lateral_vel += 0.02; + else render_yaw_rate += 0.25; + } + +} void key(unsigned char k, int x, int y) { // Process keypresses - - last_key = k; - - if (k == 'q') ::terminate(); + if (k == 'q') ::terminate(); if (k == '/') stats_on = !stats_on; // toggle stats if (k == 'n') { @@ -761,6 +681,9 @@ void key(unsigned char k, int x, int y) } } +// +// Check for and process incoming network packets +// void read_network() { // Receive packets @@ -771,15 +694,29 @@ void read_network() bytescount += bytes_recvd; // If packet is a Mouse data packet, copy it over if (incoming_packet[0] == 'M') { + // + // mouse location packet + // sscanf(incoming_packet, "M %d %d", &target_x, &target_y); target_display = 1; printf("X = %d Y = %d\n", target_x, target_y); } else if (incoming_packet[0] == 'P') { - // Ping packet - check time and record + // + // Ping packet - check time and record + // timeval check; gettimeofday(&check, NULL); ping_msecs = (float)diffclock(ping_start, check); - + } else if (incoming_packet[0] == 'S') { + // + // Message from Spaceserver + // + update_agents(&incoming_packet[1], bytes_recvd - 1); + } else if (incoming_packet[0] == 'B') { + // + // Broadcast packet from another agent + // + //std::cout << "Got broadcast from agent\n"; } } } @@ -795,7 +732,6 @@ void idle(void) // Simulation update_pos(1.f/FPS); if (simulate_on) { - update_tris(); field_simulate(1.f/FPS); myHead.simulate(1.f/FPS); myHand.simulate(1.f/FPS); @@ -836,8 +772,8 @@ void reshape(int width, int height) glLoadIdentity(); gluPerspective(45, //view angle 1.0, //aspect ratio - 1.0, //near clip - 200.0);//far clip + 0.1, //near clip + 50.0);//far clip glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -908,7 +844,7 @@ int main(int argc, char** argv) glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); - glutInitWindowSize(RIGHT_MARGIN + WIDTH, BOTTOM_MARGIN + HEIGHT); + glutInitWindowSize(WIDTH, HEIGHT); glutCreateWindow("Interface"); printf( "Created Display Window.\n" ); @@ -918,6 +854,7 @@ int main(int argc, char** argv) glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(key); + glutSpecialFunc(specialkey); glutMotionFunc(motionFunc); glutMouseFunc(mouseFunc); glutIdleFunc(idle); diff --git a/network.cpp b/network.cpp index 7ff2361714..e386ac913d 100644 --- a/network.cpp +++ b/network.cpp @@ -11,9 +11,6 @@ #include "network.h" -const int UDP_PORT = 30000; -const char DESTINATION_IP[] = "127.0.0.1"; - // Implementation of optional delay behavior using a ring buffer const int MAX_DELAY_PACKETS = 300; char delay_buffer[MAX_PACKET_SIZE*MAX_DELAY_PACKETS]; @@ -22,7 +19,7 @@ int delay_size_received[MAX_DELAY_PACKETS]; int next_to_receive = 0; int next_to_send = 0; -sockaddr_in address, dest_address, from; +sockaddr_in address, dest_address, spaceserver_address, from; socklen_t fromLength = sizeof( from ); int network_init() @@ -67,7 +64,11 @@ int network_init() dest_address.sin_family = AF_INET; dest_address.sin_addr.s_addr = inet_addr(DESTINATION_IP); dest_address.sin_port = htons( (unsigned short) UDP_PORT ); - + + spaceserver_address.sin_family = AF_INET; + spaceserver_address.sin_addr.s_addr = inet_addr(SPACESERVER_IP); + spaceserver_address.sin_port = htons( (unsigned short) SPACESERVER_PORT ); + from.sin_family = AF_INET; //from.sin_addr.s_addr = htonl(ip_address); from.sin_port = htons( (unsigned short) UDP_PORT ); @@ -86,6 +87,22 @@ timeval network_send_ping(int handle) { return check; } +int notify_spaceserver(int handle, float x, float y, float z) { + char data[100]; + sprintf(data, "%f,%f,%f", x, y, z); + //std::cout << "sending: " << data << "\n"; + int packet_size = strlen(data); + int sent_bytes = sendto( handle, (const char*)data, packet_size, + 0, (sockaddr*)&spaceserver_address, sizeof(sockaddr_in) ); + + if ( sent_bytes != packet_size ) + { + printf( "failed to send to spaceserver: return value = %d\n", sent_bytes ); + return false; + } + return sent_bytes; +} + int network_send(int handle, char * packet_data, int packet_size) { int sent_bytes = sendto( handle, (const char*)packet_data, packet_size, diff --git a/network.h b/network.h index 8f636f3cfc..e06f416b9e 100644 --- a/network.h +++ b/network.h @@ -16,11 +16,19 @@ #include #include "util.h" +// Port to use for communicating UDP with other nearby agents const int MAX_PACKET_SIZE = 1500; +const int UDP_PORT = 30001; +const char DESTINATION_IP[] = "127.0.0.1"; + +// Address and port of spaceserver process to advertise other agents +const char SPACESERVER_IP[] = "127.0.0.1"; +const int SPACESERVER_PORT = 40000; int network_init(); int network_send(int handle, char * packet_data, int packet_size); int network_receive(int handle, char * packet_data, int delay /*msecs*/); timeval network_send_ping(int handle); +int notify_spaceserver(int handle, float x, float y, float z); #endif diff --git a/tga.h b/tga.h deleted file mode 100644 index c45f1730c3..0000000000 --- a/tga.h +++ /dev/null @@ -1,470 +0,0 @@ -#include -#include -#include - -#define IMG_OK 0x1 -#define IMG_ERR_NO_FILE 0x2 -#define IMG_ERR_MEM_FAIL 0x4 -#define IMG_ERR_BAD_FORMAT 0x8 -#define IMG_ERR_UNSUPPORTED 0x40 - -class TGAImg - { - public: - TGAImg(); - ~TGAImg(); - int Load(char* szFilename); - int GetBPP(); - int GetWidth(); - int GetHeight(); - unsigned char* GetImg(); // Return a pointer to image data - unsigned char* GetPalette(); // Return a pointer to VGA palette - - private: - short int iWidth,iHeight,iBPP; - unsigned long lImageSize; - char bEnc; - unsigned char *pImage, *pPalette, *pData; - - // Internal workers - int ReadHeader(); - int LoadRawData(); - int LoadTgaRLEData(); - int LoadTgaPalette(); - void BGRtoRGB(); - void FlipImg(); - }; - - -TGAImg::TGAImg() -{ - pImage=pPalette=pData=NULL; - iWidth=iHeight=iBPP=bEnc=0; - lImageSize=0; -} - - -TGAImg::~TGAImg() -{ - if(pImage) - { - delete [] pImage; - pImage=NULL; - } - - if(pPalette) - { - delete [] pPalette; - pPalette=NULL; - } - - if(pData) - { - delete [] pData; - pData=NULL; - } -} - - -int TGAImg::Load(char* szFilename) -{ - using namespace std; - ifstream fIn; - unsigned long ulSize; - int iRet; - - // Clear out any existing image and palette - if(pImage) - { - delete [] pImage; - pImage=NULL; - } - - if(pPalette) - { - delete [] pPalette; - pPalette=NULL; - } - - // Open the specified file - fIn.open(szFilename,ios::binary); - - if(fIn==NULL) - return IMG_ERR_NO_FILE; - - // Get file size - fIn.seekg(0,ios_base::end); - ulSize=fIn.tellg(); - fIn.seekg(0,ios_base::beg); - - // Allocate some space - // Check and clear pDat, just in case - if(pData) - delete [] pData; - - pData=new unsigned char[ulSize]; - - if(pData==NULL) - { - fIn.close(); - return IMG_ERR_MEM_FAIL; - } - - // Read the file into memory - fIn.read((char*)pData,ulSize); - - fIn.close(); - - // Process the header - iRet=ReadHeader(); - - if(iRet!=IMG_OK) - return iRet; - - switch(bEnc) - { - case 1: // Raw Indexed - { - // Check filesize against header values - if((lImageSize+18+pData[0]+768)>ulSize) - return IMG_ERR_BAD_FORMAT; - - // Double check image type field - if(pData[1]!=1) - return IMG_ERR_BAD_FORMAT; - - // Load image data - iRet=LoadRawData(); - if(iRet!=IMG_OK) - return iRet; - - // Load palette - iRet=LoadTgaPalette(); - if(iRet!=IMG_OK) - return iRet; - - break; - } - - case 2: // Raw RGB - { - // Check filesize against header values - if((lImageSize+18+pData[0])>ulSize) - return IMG_ERR_BAD_FORMAT; - - // Double check image type field - if(pData[1]!=0) - return IMG_ERR_BAD_FORMAT; - - // Load image data - iRet=LoadRawData(); - if(iRet!=IMG_OK) - return iRet; - - BGRtoRGB(); // Convert to RGB - break; - } - - case 9: // RLE Indexed - { - // Double check image type field - if(pData[1]!=1) - return IMG_ERR_BAD_FORMAT; - - // Load image data - iRet=LoadTgaRLEData(); - if(iRet!=IMG_OK) - return iRet; - - // Load palette - iRet=LoadTgaPalette(); - if(iRet!=IMG_OK) - return iRet; - - break; - } - - case 10: // RLE RGB - { - // Double check image type field - if(pData[1]!=0) - return IMG_ERR_BAD_FORMAT; - - // Load image data - iRet=LoadTgaRLEData(); - if(iRet!=IMG_OK) - return iRet; - - BGRtoRGB(); // Convert to RGB - break; - } - - default: - return IMG_ERR_UNSUPPORTED; - } - - // Check flip bit - if((pData[17] & 0x20)==0) - FlipImg(); - - // Release file memory - delete [] pData; - pData=NULL; - - return IMG_OK; -} - - -int TGAImg::ReadHeader() // Examine the header and populate our class attributes -{ - short ColMapStart,ColMapLen; - short x1,y1,x2,y2; - - if(pData==NULL) - return IMG_ERR_NO_FILE; - - if(pData[1]>1) // 0 (RGB) and 1 (Indexed) are the only types we know about - return IMG_ERR_UNSUPPORTED; - - bEnc=pData[2]; // Encoding flag 1 = Raw indexed image - // 2 = Raw RGB - // 3 = Raw greyscale - // 9 = RLE indexed - // 10 = RLE RGB - // 11 = RLE greyscale - // 32 & 33 Other compression, indexed - - if(bEnc>11) // We don't want 32 or 33 - return IMG_ERR_UNSUPPORTED; - - - // Get palette info - memcpy(&ColMapStart,&pData[3],2); - memcpy(&ColMapLen,&pData[5],2); - - // Reject indexed images if not a VGA palette (256 entries with 24 bits per entry) - if(pData[1]==1) // Indexed - { - if(ColMapStart!=0 || ColMapLen!=256 || pData[7]!=24) - return IMG_ERR_UNSUPPORTED; - } - - // Get image window and produce width & height values - memcpy(&x1,&pData[8],2); - memcpy(&y1,&pData[10],2); - memcpy(&x2,&pData[12],2); - memcpy(&y2,&pData[14],2); - - iWidth=(x2-x1); - iHeight=(y2-y1); - - if(iWidth<1 || iHeight<1) - return IMG_ERR_BAD_FORMAT; - - // Bits per Pixel - iBPP=pData[16]; - - // Check flip / interleave byte - if(pData[17]>32) // Interleaved data - return IMG_ERR_UNSUPPORTED; - - // Calculate image size - lImageSize=(iWidth * iHeight * (iBPP/8)); - - return IMG_OK; -} - - -int TGAImg::LoadRawData() // Load uncompressed image data -{ - short iOffset; - - if(pImage) // Clear old data if present - delete [] pImage; - - pImage=new unsigned char[lImageSize]; - - if(pImage==NULL) - return IMG_ERR_MEM_FAIL; - - iOffset=pData[0]+18; // Add header to ident field size - - if(pData[1]==1) // Indexed images - iOffset+=768; // Add palette offset - - memcpy(pImage,&pData[iOffset],lImageSize); - - return IMG_OK; -} - - -int TGAImg::LoadTgaRLEData() // Load RLE compressed image data -{ - short iOffset,iPixelSize; - unsigned char *pCur; - unsigned long Index=0; - unsigned char bLength,bLoop; - - // Calculate offset to image data - iOffset=pData[0]+18; - - // Add palette offset for indexed images - if(pData[1]==1) - iOffset+=768; - - // Get pixel size in bytes - iPixelSize=iBPP/8; - - // Set our pointer to the beginning of the image data - pCur=&pData[iOffset]; - - // Allocate space for the image data - if(pImage!=NULL) - delete [] pImage; - - pImage=new unsigned char[lImageSize]; - - if(pImage==NULL) - return IMG_ERR_MEM_FAIL; - - // Decode - while(Index= MAX_CUBES) || (scale < SMALLEST_CUBE)) return; + if (randFloat() < 0.5) { + // Make a cube + for (i = 0; i < 3; i++) cubes_position[*index*3 + i] = location[i]; + cubes_scale[*index] = scale; + cubes_color[*index*3] = randFloat(); + cubes_color[*index*3 + 1] = randFloat(); + cubes_color[*index*3 + 2] = randFloat(); + *index += 1; + //std::cout << "Quad made at scale " << scale << "\n"; + } else { + for (i = 0; i < 8; i++) { + spot[0] = location[0] + (i%2)*scale/2.0; + spot[1] = location[1] + ((i/2)%2)*scale/2.0; + spot[2] = location[2] + ((i/4)%2)*scale/2.0; + //std::cout << spot[0] << "," << spot[1] << "," << spot[2] << "\n"; + makeCubes(spot, scale/2.0, index, cubes_position, cubes_scale, cubes_color); + } + } +} + +void render_vector(glm::vec3 * vec) +{ + // Show edge of world + glDisable(GL_LIGHTING); + glColor4f(1.0, 1.0, 1.0, 1.0); + glLineWidth(1.0); + glBegin(GL_LINES); + // Draw axes + glColor3f(1,0,0); + glVertex3f(-1,0,0); + glVertex3f(1,0,0); + glColor3f(0,1,0); + glVertex3f(0,-1,0); + glVertex3f(0, 1, 0); + glColor3f(0,0,1); + glVertex3f(0,0,-1); + glVertex3f(0, 0, 1); + // Draw vector + glColor3f(1,1,1); + glVertex3f(0,0,0); + glVertex3f(vec->x, vec->y, vec->z); + // Draw marker dots for magnitude + glEnd(); + float particle_attenuation_quadratic[] = { 0.0f, 0.0f, 2.0f }; // larger Z = smaller particles + glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, particle_attenuation_quadratic ); + glEnable(GL_POINT_SMOOTH); + glPointSize(10.0); + glBegin(GL_POINTS); + glColor3f(1,0,0); + glVertex3f(vec->x,0,0); + glColor3f(0,1,0); + glVertex3f(0,vec->y,0); + glColor3f(0,0,1); + glVertex3f(0,0,vec->z); + glEnd(); + +} + void render_world_box() { // Show edge of world @@ -39,6 +103,11 @@ void render_world_box() glEnd(); } +void outstring(char * string, int length) { + char out[length]; + memcpy(out, string, length); + std::cout << out << "\n"; +} double diffclock(timeval clock1,timeval clock2) { diff --git a/util.h b/util.h index 46e1447581..c6c2a319db 100644 --- a/util.h +++ b/util.h @@ -8,14 +8,20 @@ #ifndef interface_util_h #define interface_util_h + #include "glm/glm.hpp" +void outstring(char * string, int length); float randFloat(); void render_world_box(); +void render_vector(glm::vec3 * vec); void drawtext(int x, int y, float scale, float rotate, float thick, int mono, char *string, float r=1.0, float g=1.0, float b=1.0); void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, glm::vec3 vec, float r=1.0, float g=1.0, float b=1.0); double diffclock(timeval clock1,timeval clock2); +void makeCubes(float location[3], float scale, int * index, + float * cubes_position, float * cubes_scale, float * cubes_color); + #endif diff --git a/world.h b/world.h index e11976c1c8..106f47ff69 100644 --- a/world.h +++ b/world.h @@ -6,7 +6,7 @@ // Copyright (c) 2012 __MyCompanyName__. All rights reserved. // -// Simulation happens in positive cube with edge of size WORLD_SIZE +// Simulation happens in positive cube with edge of size WORLD_SIZE #ifndef interface_world_h #define interface_world_h @@ -14,5 +14,7 @@ const float WORLD_SIZE = 10.0; #define PI 3.14159265 +#define MAX_CUBES 2000 +#define SMALLEST_CUBE 0.01 #endif