overte/interface/src/BuckyBalls.cpp
Andrew Meadows 607094075c Revert "Merge pull request #2834 from andrew/thermonuclear"
This reverts commit e088c3d115, reversing
changes made to d124c0319d.
2014-05-13 10:38:56 -07:00

179 lines
7.2 KiB
C++

//
// BuckyBalls.cpp
// interface/src
//
// Created by Philip on 1/2/14.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "BuckyBalls.h"
#include "Util.h"
#include "world.h"
#include "devices/SixenseManager.h"
const int NUM_ELEMENTS = 3;
const float RANGE_BBALLS = 0.5f;
const float SIZE_BBALLS = 0.02f;
const float CORNER_BBALLS = 2.f;
const float GRAVITY_BBALLS = -0.25f;
const float BBALLS_ATTRACTION_DISTANCE = SIZE_BBALLS / 2.f;
const float COLLISION_RADIUS = 0.01f;
const float INITIAL_VELOCITY = 0.3f;
glm::vec3 colors[NUM_ELEMENTS];
// Make some bucky balls for the avatar
BuckyBalls::BuckyBalls() {
_bballIsGrabbed[0] = 0;
_bballIsGrabbed[1] = 0;
colors[0] = glm::vec3(0.13f, 0.55f, 0.13f);
colors[1] = glm::vec3(0.64f, 0.16f, 0.16f);
colors[2] = glm::vec3(0.31f, 0.58f, 0.80f);
qDebug("Creating buckyballs...");
for (int i = 0; i < NUM_BBALLS; i++) {
_bballPosition[i] = CORNER_BBALLS + randVector() * RANGE_BBALLS;
int element = (rand() % NUM_ELEMENTS);
if (element == 0) {
_bballRadius[i] = SIZE_BBALLS;
_bballColor[i] = colors[0];
} else if (element == 1) {
_bballRadius[i] = SIZE_BBALLS / 2.f;
_bballColor[i] = colors[1];
} else {
_bballRadius[i] = SIZE_BBALLS * 2.f;
_bballColor[i] = colors[2];
}
_bballColliding[i] = 0.f;
_bballElement[i] = element;
if (_bballElement[i] != 1) {
_bballVelocity[i] = randVector() * INITIAL_VELOCITY;
} else {
_bballVelocity[i] = glm::vec3(0);
}
}
}
void BuckyBalls::grab(PalmData& palm, float deltaTime) {
float penetration;
glm::vec3 fingerTipPosition = palm.getFingerTipPosition();
if (palm.getControllerButtons() & BUTTON_FWD) {
if (!_bballIsGrabbed[palm.getSixenseID()]) {
// Look for a ball to grab
for (int i = 0; i < NUM_BBALLS; i++) {
glm::vec3 diff = _bballPosition[i] - fingerTipPosition;
penetration = glm::length(diff) - (_bballRadius[i] + COLLISION_RADIUS);
if (penetration < 0.f) {
_bballIsGrabbed[palm.getSixenseID()] = i;
}
}
}
if (_bballIsGrabbed[palm.getSixenseID()]) {
// If ball being grabbed, move with finger
glm::vec3 diff = _bballPosition[_bballIsGrabbed[palm.getSixenseID()]] - fingerTipPosition;
penetration = glm::length(diff) - (_bballRadius[_bballIsGrabbed[palm.getSixenseID()]] + COLLISION_RADIUS);
_bballPosition[_bballIsGrabbed[palm.getSixenseID()]] -= glm::normalize(diff) * penetration;
glm::vec3 fingerTipVelocity = palm.getTipVelocity();
if (_bballElement[_bballIsGrabbed[palm.getSixenseID()]] != 1) {
_bballVelocity[_bballIsGrabbed[palm.getSixenseID()]] = fingerTipVelocity;
}
_bballPosition[_bballIsGrabbed[palm.getSixenseID()]] = fingerTipPosition;
_bballColliding[_bballIsGrabbed[palm.getSixenseID()]] = 1.f;
}
} else {
_bballIsGrabbed[palm.getSixenseID()] = 0;
}
}
const float COLLISION_BLEND_RATE = 0.5f;
const float ATTRACTION_BLEND_RATE = 0.9f;
const float ATTRACTION_VELOCITY_BLEND_RATE = 0.10f;
void BuckyBalls::simulate(float deltaTime, const HandData* handData) {
// First, update the grab behavior from the hand controllers
for (size_t i = 0; i < handData->getNumPalms(); ++i) {
PalmData palm = handData->getPalms()[i];
grab(palm, deltaTime);
}
// Look for collisions
for (int i = 0; i < NUM_BBALLS; i++) {
if (_bballElement[i] != 1) {
// For 'interacting' elements, look for other balls to interact with
for (int j = 0; j < NUM_BBALLS; j++) {
if (i != j) {
glm::vec3 diff = _bballPosition[i] - _bballPosition[j];
float diffLength = glm::length(diff);
float penetration = diffLength - (_bballRadius[i] + _bballRadius[j]);
if (diffLength != 0) {
if (penetration < 0.f) {
// Colliding - move away and transfer velocity
_bballPosition[i] -= glm::normalize(diff) * penetration * COLLISION_BLEND_RATE;
if (glm::dot(_bballVelocity[i], diff) < 0.f) {
_bballVelocity[i] = _bballVelocity[i] * (1.f - COLLISION_BLEND_RATE) +
glm::reflect(_bballVelocity[i], glm::normalize(diff)) * COLLISION_BLEND_RATE;
}
} else if ((penetration > EPSILON) && (penetration < BBALLS_ATTRACTION_DISTANCE)) {
// If they get close to each other, bring them together with magnetic force
_bballPosition[i] -= glm::normalize(diff) * penetration * ATTRACTION_BLEND_RATE;
// Also make their velocities more similar
_bballVelocity[i] = _bballVelocity[i] * (1.f - ATTRACTION_VELOCITY_BLEND_RATE) + _bballVelocity[j] * ATTRACTION_VELOCITY_BLEND_RATE;
}
}
}
}
}
}
// Update position and bounce on walls
const float BBALL_CONTINUOUS_DAMPING = 0.00f;
const float BBALL_WALL_COLLISION_DAMPING = 0.2f;
const float COLLISION_DECAY_RATE = 0.8f;
for (int i = 0; i < NUM_BBALLS; i++) {
_bballPosition[i] += _bballVelocity[i] * deltaTime;
if (_bballElement[i] != 1) {
_bballVelocity[i].y += GRAVITY_BBALLS * deltaTime;
}
_bballVelocity[i] -= _bballVelocity[i] * BBALL_CONTINUOUS_DAMPING * deltaTime;
for (int j = 0; j < 3; j++) {
if ((_bballPosition[i][j] + _bballRadius[i]) > (CORNER_BBALLS + RANGE_BBALLS)) {
_bballPosition[i][j] = (CORNER_BBALLS + RANGE_BBALLS) - _bballRadius[i];
_bballVelocity[i][j] *= -(1.f - BBALL_WALL_COLLISION_DAMPING);
}
if ((_bballPosition[i][j] - _bballRadius[i]) < (CORNER_BBALLS -RANGE_BBALLS)) {
_bballPosition[i][j] = (CORNER_BBALLS -RANGE_BBALLS) + _bballRadius[i];
_bballVelocity[i][j] *= -(1.f - BBALL_WALL_COLLISION_DAMPING);
}
}
_bballColliding[i] *= COLLISION_DECAY_RATE;
if (_bballColliding[i] < 0.1f) {
_bballColliding[i] = 0.f;
}
}
}
void BuckyBalls::render() {
glEnable(GL_LIGHTING);
for (int i = 0; i < NUM_BBALLS; i++) {
if (_bballColliding[i] > 0.f) {
const float GRAB_BRIGHTEN = 1.15f;
glColor3f(_bballColor[i].x * GRAB_BRIGHTEN, _bballColor[i].y * GRAB_BRIGHTEN, _bballColor[i].z * GRAB_BRIGHTEN);
} else {
glColor3f(_bballColor[i].x, _bballColor[i].y, _bballColor[i].z);
}
glPushMatrix();
glTranslatef(_bballPosition[i].x, _bballPosition[i].y, _bballPosition[i].z);
glutSolidSphere(_bballRadius[i], 15, 15);
glPopMatrix();
}
}