Merge pull request #365 from PhilipRosedale/master

Made Transmitter it's own class, removed V1 Transmitter code (Glass and Android)
This commit is contained in:
ZappoMan 2013-05-21 13:45:15 -07:00
commit 6f0035b297
5 changed files with 61 additions and 214 deletions

View file

@ -156,6 +156,7 @@ Application::Application(int& argc, char** argv) :
_bytesCount(0)
{
gettimeofday(&_applicationStartupTime, NULL);
_window->setWindowTitle("Interface");
printLog("Interface Startup:\n");
_voxels.setViewFrustum(&_viewFrustum);
@ -315,6 +316,10 @@ void Application::paintGL() {
0.0f,
//-_myAvatar.getAbsoluteHeadPitch(),
0.0f);
// Take a look at whether we are inside head, don't render it if so.
const float HEAD_RENDER_DISTANCE = 0.5;
glm::vec3 distanceToHead(_myCamera.getPosition() - _myAvatar.getSpringyHeadPosition());
if (glm::length(distanceToHead) < HEAD_RENDER_DISTANCE) { _myAvatar.setDisplayingHead(false); }
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
_myCamera.setTargetPosition(_myAvatar.getHeadPosition());
@ -408,14 +413,16 @@ void Application::paintGL() {
}
}
_frameCount++;
_frameCount++;
// If application has just started, report time from startup to now (first frame display)
if (_justStarted) {
float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime))/1000000.0;
_justStarted = false;
char title[30];
snprintf(title, 30, "Interface: %4.2f seconds", startupTime);
char title[50];
sprintf(title, "Interface: %4.2f seconds\n", startupTime);
printLog("%s", title);
_window->setWindowTitle(title);
}
}
@ -846,19 +853,18 @@ void Application::idle() {
timeval check;
gettimeofday(&check, NULL);
// Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time
// Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran
if (diffclock(&_lastTimeIdle, &check) > IDLE_SIMULATE_MSECS) {
float deltaTime = 1.f/_fps;
// Use Transmitter Hand to move hand if connected, else use mouse
if (_myAvatar.isTransmitterV2Connected()) {
const float HAND_FORCE_SCALING = 0.05f;
const float* handAcceleration = _myAvatar.getTransmitterHandLastAcceleration();
_myAvatar.setMovedHandOffset(glm::vec3(-handAcceleration[0] * HAND_FORCE_SCALING,
handAcceleration[1] * HAND_FORCE_SCALING,
handAcceleration[2] * HAND_FORCE_SCALING));
// Use Transmitter Hand to move hand if connected, else use mouse
if (_myTransmitter.isConnected()) {
const float HAND_FORCE_SCALING = 0.01f;
glm::vec3 estimatedRotation = _myTransmitter.getEstimatedRotation();
glm::vec3 handForce(-estimatedRotation.z, -estimatedRotation.x, estimatedRotation.y);
_myAvatar.setMovedHandOffset(handForce * HAND_FORCE_SCALING);
} else {
// update behaviors for avatar hand movement: handControl takes mouse values as input,
// and gives back 3D values modulated for smooth transitioning between interaction modes.
@ -964,20 +970,26 @@ void Application::idle() {
networkReceive(0);
}
//loop through all the remote avatars and simulate them...
//loop through all the other avatars and simulate them...
AgentList* agentList = AgentList::getInstance();
agentList->lock();
for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
if (agent->getLinkedData() != NULL) {
Avatar *avatar = (Avatar *)agent->getLinkedData();
avatar->simulate(deltaTime);
avatar->simulate(deltaTime, false);
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
}
}
agentList->unlock();
// Simulate myself
_myAvatar.setGravity(getGravity(_myAvatar.getPosition()));
_myAvatar.simulate(deltaTime);
if (_transmitterDrives->isChecked() && _myTransmitter.isConnected()) {
_myAvatar.simulate(deltaTime, &_myTransmitter);
} else {
_myAvatar.simulate(deltaTime, NULL);
}
// Update audio stats for procedural sounds
#ifndef _WIN32
@ -1044,7 +1056,7 @@ void Application::setRenderFirstPerson(bool firstPerson) {
a.distance = 0.0f;
a.tightness = 100.0f;
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON, a);
_myAvatar.setDisplayingHead(false);
_myAvatar.setDisplayingHead(true);
} else {
Camera::CameraFollowingAttributes a;
@ -1204,6 +1216,9 @@ void Application::initMenu() {
_gyroLook->setChecked(true);
(_mouseLook = optionsMenu->addAction("Mouse Look"))->setCheckable(true);
_mouseLook->setChecked(false);
(_transmitterDrives = optionsMenu->addAction("Transmitter Drive"))->setCheckable(true);
_transmitterDrives->setChecked(true);
optionsMenu->addAction("Fullscreen", this, SLOT(setFullscreen(bool)), Qt::Key_F)->setCheckable(true);
QMenu* renderMenu = menuBar->addMenu("Render");
@ -1351,7 +1366,7 @@ void Application::updateAvatar(float deltaTime) {
float measuredYawRate = _serialPort.getLastYawRate();
// Update gyro-based mouse (X,Y on screen)
const float MIN_MOUSE_RATE = 1.0;
const float MIN_MOUSE_RATE = 3.0;
const float HORIZONTAL_PIXELS_PER_DEGREE = 2880.f / 45.f;
const float VERTICAL_PIXELS_PER_DEGREE = 1800.f / 30.f;
if (powf(measuredYawRate * measuredYawRate +
@ -1757,8 +1772,8 @@ void Application::displayOverlay() {
if (_displayLevels) _serialPort.renderLevels(_glWidget->width(), _glWidget->height());
// Show hand transmitter data if detected
if (_myAvatar.isTransmitterV2Connected()) {
_myAvatar.transmitterV2RenderLevels(_glWidget->width(), _glWidget->height());
if (_myTransmitter.isConnected()) {
_myTransmitter.renderLevels(_glWidget->width(), _glWidget->height());
}
// Display stats and log text onscreen
glLineWidth(1.0f);
@ -2055,6 +2070,7 @@ void Application::resetSensors() {
}
QCursor::setPos(_headMouseX, _headMouseY);
_myAvatar.reset();
_myTransmitter.resetLevels();
}
static void setShortcutsEnabled(QWidget* widget, bool enabled) {
@ -2111,13 +2127,9 @@ void* Application::networkReceive(void* args) {
app->_bytesCount += bytesReceived;
switch (app->_incomingPacket[0]) {
case PACKET_HEADER_TRANSMITTER_DATA_V1:
// V1 = android app, or the Google Glass
app->_myAvatar.processTransmitterData(app->_incomingPacket, bytesReceived);
break;
case PACKET_HEADER_TRANSMITTER_DATA_V2:
// V2 = IOS transmitter app
app->_myAvatar.processTransmitterDataV2(app->_incomingPacket, bytesReceived);
app->_myTransmitter.processIncomingData(app->_incomingPacket, bytesReceived);
break;
case PACKET_HEADER_MIXED_AUDIO:

View file

@ -137,6 +137,7 @@ private:
QAction* _lookingInMirror; // Are we currently rendering one's own head as if in mirror?
QAction* _gyroLook; // Whether to allow the gyro data from head to move your view
QAction* _mouseLook; // Whether the have the mouse near edge of screen move your view
QAction* _transmitterDrives; // Whether to have Transmitter data move/steer the Avatar
QAction* _renderVoxels; // Whether to render voxels
QAction* _renderVoxelTextures; // Whether to render noise textures on voxels
QAction* _renderStarsOn; // Whether to display the stars
@ -192,6 +193,8 @@ private:
Avatar _myAvatar; // The rendered avatar of oneself
Transmitter _myTransmitter; // Gets UDP data from transmitter app used to animate the avatar
Camera _myCamera; // My view onto the world
Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode

View file

@ -77,11 +77,6 @@ Avatar::Avatar(bool isMine) :
_speed(0.0f),
_maxArmLength(0.0f),
_orientation(),
_transmitterIsFirstData(true),
_transmitterHz(0.0f),
_transmitterPackets(0),
_transmitterInitialReading(0.0f, 0.0f, 0.0f),
_isTransmitterV2Connected(false),
_pelvisStandingHeight(0.0f),
_displayingHead(true),
_distanceToNearestAvatar(std::numeric_limits<float>::max()),
@ -215,7 +210,7 @@ void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int scree
return;
}
void Avatar::simulate(float deltaTime) {
void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
//figure out if the mouse cursor is over any body spheres...
if (_isMine) {
@ -269,7 +264,8 @@ void Avatar::simulate(float deltaTime) {
if (_isMine) {
_thrust = glm::vec3(0.0f, 0.0f, 0.0f);
// Add Thrusts from keyboard
if (_driveKeys[FWD ]) {_thrust += THRUST_MAG * deltaTime * _orientation.getFront();}
if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG * deltaTime * _orientation.getFront();}
if (_driveKeys[RIGHT ]) {_thrust += THRUST_MAG * deltaTime * _orientation.getRight();}
@ -278,6 +274,24 @@ void Avatar::simulate(float deltaTime) {
if (_driveKeys[DOWN ]) {_thrust -= THRUST_MAG * deltaTime * _orientation.getUp();}
if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;}
if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG * deltaTime;}
// Add thrusts from Transmitter
if (transmitter) {
glm::vec3 rotation = transmitter->getEstimatedRotation();
const float TRANSMITTER_MIN_RATE = 1.f;
const float TRANSMITTER_LATERAL_FORCE_SCALE = 25.f;
const float TRANSMITTER_FWD_FORCE_SCALE = 50.f;
const float TRANSMITTER_YAW_SCALE = 7.0f;
if (fabs(rotation.z) > TRANSMITTER_MIN_RATE) {
_thrust += rotation.z * TRANSMITTER_LATERAL_FORCE_SCALE * deltaTime * _orientation.getRight();
}
if (fabs(rotation.x) > TRANSMITTER_MIN_RATE) {
_thrust += -rotation.x * TRANSMITTER_FWD_FORCE_SCALE * deltaTime * _orientation.getFront();
}
if (fabs(rotation.y) > TRANSMITTER_MIN_RATE) {
_bodyYawDelta += rotation.y * TRANSMITTER_YAW_SCALE * deltaTime;
}
}
}
// update body yaw by body yaw delta
@ -1153,169 +1167,6 @@ void Avatar::renderBody(bool lookingInMirror) {
}
}
//
// Process UDP interface data from Android transmitter or Google Glass
//
void Avatar::processTransmitterData(unsigned char* packetData, int numBytes) {
// Read a packet from a transmitter app, process the data
float
accX, accY, accZ, // Measured acceleration
graX, graY, graZ, // Gravity
gyrX, gyrY, gyrZ, // Gyro velocity in radians/sec as (pitch, roll, yaw)
linX, linY, linZ, // Linear Acceleration (less gravity)
rot1, rot2, rot3, rot4; // Rotation of device:
// rot1 = roll, ranges from -1 to 1, 0 = flat on table
// rot2 = pitch, ranges from -1 to 1, 0 = flat on table
// rot3 = yaw, ranges from -1 to 1
char device[100]; // Device ID
enum deviceTypes { DEVICE_GLASS, DEVICE_ANDROID, DEVICE_IPHONE, DEVICE_UNKNOWN };
sscanf((char *)packetData,
"tacc %f %f %f gra %f %f %f gyr %f %f %f lin %f %f %f rot %f %f %f %f dna \"%s",
&accX, &accY, &accZ,
&graX, &graY, &graZ,
&gyrX, &gyrY, &gyrZ,
&linX, &linY, &linZ,
&rot1, &rot2, &rot3, &rot4, (char *)&device);
// decode transmitter device type
deviceTypes deviceType = DEVICE_UNKNOWN;
if (strcmp(device, "ADR")) {
deviceType = DEVICE_ANDROID;
} else {
deviceType = DEVICE_GLASS;
}
if (_transmitterPackets++ == 0) {
// If first packet received, note time, turn head spring return OFF, get start rotation
gettimeofday(&_transmitterTimer, NULL);
if (deviceType == DEVICE_GLASS) {
_head.setReturnToCenter(true);
_head.setSpringScale(10.f);
printLog("Using Google Glass to drive head, springs ON.\n");
} else {
_head.setReturnToCenter(false);
printLog("Using Transmitter %s to drive head, springs OFF.\n", device);
}
//printLog("Packet: [%s]\n", packetData);
//printLog("Version: %s\n", device);
_transmitterInitialReading = glm::vec3(rot3, rot2, rot1);
}
const int TRANSMITTER_COUNT = 100;
if (_transmitterPackets % TRANSMITTER_COUNT == 0) {
// Every 100 packets, record the observed Hz of the transmitter data
timeval now;
gettimeofday(&now, NULL);
double msecsElapsed = diffclock(&_transmitterTimer, &now);
_transmitterHz = static_cast<float>((double)TRANSMITTER_COUNT / (msecsElapsed / 1000.0));
_transmitterTimer = now;
printLog("Transmitter Hz: %3.1f\n", _transmitterHz);
}
//printLog("Gyr: %3.1f, %3.1f, %3.1f\n", glm::degrees(gyrZ), glm::degrees(-gyrX), glm::degrees(gyrY));
//printLog("Rot: %3.1f, %3.1f, %3.1f, %3.1f\n", rot1, rot2, rot3, rot4);
// Update the head with the transmitter data
glm::vec3 eulerAngles((rot3 - _transmitterInitialReading.x) * 180.f,
-(rot2 - _transmitterInitialReading.y) * 180.f,
(rot1 - _transmitterInitialReading.z) * 180.f);
if (eulerAngles.x > 180.f) { eulerAngles.x -= 360.f; }
if (eulerAngles.x < -180.f) { eulerAngles.x += 360.f; }
glm::vec3 angularVelocity;
if (deviceType != DEVICE_GLASS) {
angularVelocity = glm::vec3(glm::degrees(gyrZ), glm::degrees(-gyrX), glm::degrees(gyrY));
setHeadFromGyros(&eulerAngles, &angularVelocity,
(_transmitterHz == 0.f) ? 0.f : 1.f / _transmitterHz, 1.0);
} else {
angularVelocity = glm::vec3(glm::degrees(gyrY), glm::degrees(-gyrX), glm::degrees(-gyrZ));
setHeadFromGyros(&eulerAngles, &angularVelocity,
(_transmitterHz == 0.f) ? 0.f : 1.f / _transmitterHz, 1000.0);
}
}
//
// Process UDP data from version 2 Transmitter acting as Hand
//
void Avatar::processTransmitterDataV2(unsigned char* packetData, int numBytes) {
if (numBytes == 3 + sizeof(_transmitterHandLastRotationRates) +
sizeof(_transmitterHandLastAcceleration)) {
memcpy(_transmitterHandLastRotationRates, packetData + 2,
sizeof(_transmitterHandLastRotationRates));
memcpy(_transmitterHandLastAcceleration, packetData + 3 +
sizeof(_transmitterHandLastRotationRates),
sizeof(_transmitterHandLastAcceleration));
// Convert from transmitter units to internal units
for (int i = 0; i < 3; i++) {
_transmitterHandLastRotationRates[i] *= 180.f / PI;
_transmitterHandLastAcceleration[i] *= GRAVITY_EARTH;
}
if (!_isTransmitterV2Connected) {
printf("Transmitter V2 Connected.\n");
_isTransmitterV2Connected = true;
}
} else {
printf("Transmitter V2 packet read error.\n");
}
}
void Avatar::transmitterV2RenderLevels(int width, int height) {
char val[50];
const int LEVEL_CORNER_X = 10;
const int LEVEL_CORNER_Y = 400;
// Draw the numeric degree/sec values from the gyros
sprintf(val, "Yaw %4.1f", _transmitterHandLastRotationRates[1]);
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y, 0.10, 0, 1.0, 1, val, 0, 1, 0);
sprintf(val, "Pitch %4.1f", _transmitterHandLastRotationRates[0]);
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 15, 0.10, 0, 1.0, 1, val, 0, 1, 0);
sprintf(val, "Roll %4.1f", _transmitterHandLastRotationRates[2]);
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 30, 0.10, 0, 1.0, 1, val, 0, 1, 0);
sprintf(val, "X %4.3f", _transmitterHandLastAcceleration[0]);
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 45, 0.10, 0, 1.0, 1, val, 0, 1, 0);
sprintf(val, "Y %4.3f", _transmitterHandLastAcceleration[1]);
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 60, 0.10, 0, 1.0, 1, val, 0, 1, 0);
sprintf(val, "Z %4.3f", _transmitterHandLastAcceleration[2]);
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 75, 0.10, 0, 1.0, 1, val, 0, 1, 0);
// Draw the levels as horizontal lines
const int LEVEL_CENTER = 150;
const float ACCEL_VIEW_SCALING = 50.f;
glLineWidth(2.0);
glColor4f(1, 1, 1, 1);
glBegin(GL_LINES);
// Gyro rates
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 3);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _transmitterHandLastRotationRates[1], LEVEL_CORNER_Y - 3);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 12);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _transmitterHandLastRotationRates[0], LEVEL_CORNER_Y + 12);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 27);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _transmitterHandLastRotationRates[2], LEVEL_CORNER_Y + 27);
// Acceleration
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 42);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_transmitterHandLastAcceleration[0] * ACCEL_VIEW_SCALING),
LEVEL_CORNER_Y + 42);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 57);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_transmitterHandLastAcceleration[1] * ACCEL_VIEW_SCALING),
LEVEL_CORNER_Y + 57);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 72);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_transmitterHandLastAcceleration[2] * ACCEL_VIEW_SCALING),
LEVEL_CORNER_Y + 72);
glEnd();
// Draw green vertical centerline
glColor4f(0, 1, 0, 0.5);
glBegin(GL_LINES);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 6);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 30);
glEnd();
}
void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity, float deltaTime, float smoothingTime) {
//
// Given absolute position and angular velocity information, update the avatar's head angles

View file

@ -20,6 +20,7 @@
#include "SerialInterface.h"
#include "Balls.h"
#include "Head.h"
#include "Transmitter.h"
enum DriveKeys
{
@ -109,7 +110,7 @@ public:
void setMousePressed(bool pressed);
void render(bool lookingInMirror, glm::vec3 cameraPosition);
void renderBody(bool lookingInMirror);
void simulate(float);
void simulate(float deltaTime, Transmitter* transmitter);
void setMovedHandOffset(glm::vec3 movedHandOffset) { _movedHandOffset = movedHandOffset; }
void updateArmIKAndConstraints( float deltaTime );
void setDisplayingHead( bool displayingHead );
@ -122,16 +123,6 @@ public:
void setThrust(glm::vec3 newThrust) { _thrust = newThrust; };
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
glm::vec3 getThrust() { return _thrust; };
// Related to getting transmitter UDP data used to animate the avatar hand
void processTransmitterData(unsigned char * packetData, int numBytes);
void processTransmitterDataV2(unsigned char * packetData, int numBytes);
const bool isTransmitterV2Connected() const { return _isTransmitterV2Connected; };
const float* getTransmitterHandLastAcceleration() const { return _transmitterHandLastAcceleration; };
const float* getTransmitterHandLastRotationRates() const { return _transmitterHandLastRotationRates; };
void transmitterV2RenderLevels(int width, int height);
float getTransmitterHz() { return _transmitterHz; };
void writeAvatarDataToFile();
void readAvatarDataFromFile();
@ -179,15 +170,6 @@ private:
float _maxArmLength;
Orientation _orientation;
int _driveKeys[MAX_DRIVE_KEYS];
bool _transmitterIsFirstData;
timeval _transmitterTimeLastReceived;
timeval _transmitterTimer;
float _transmitterHz;
int _transmitterPackets;
glm::vec3 _transmitterInitialReading;
float _transmitterHandLastRotationRates[3];
float _transmitterHandLastAcceleration[3];
bool _isTransmitterV2Connected;
float _pelvisStandingHeight;
float _height;
Balls* _balls;

View file

@ -28,7 +28,6 @@ const PACKET_HEADER PACKET_HEADER_ERASE_VOXEL = 'E';
const PACKET_HEADER PACKET_HEADER_VOXEL_DATA = 'V';
const PACKET_HEADER PACKET_HEADER_VOXEL_DATA_MONOCHROME = 'v';
const PACKET_HEADER PACKET_HEADER_BULK_AVATAR_DATA = 'X';
const PACKET_HEADER PACKET_HEADER_TRANSMITTER_DATA_V1 = 't';
const PACKET_HEADER PACKET_HEADER_TRANSMITTER_DATA_V2 = 'T';
const PACKET_HEADER PACKET_HEADER_ENVIRONMENT_DATA = 'e';
const PACKET_HEADER PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L';