Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jeffrey Ventrella 2013-04-17 23:20:08 -07:00
commit bca2460395
14 changed files with 371 additions and 474 deletions

View file

@ -1,126 +0,0 @@
//
// FieldOfView.cpp
// interface
//
// Created by Tobias Schwinger on 3/21/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "FieldOfView.h"
#include <math.h>
#include <algorithm>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/matrix_inverse.hpp>
using namespace glm;
FieldOfView::FieldOfView() :
_matOrientation(mat4(1.0f)),
_vecBoundsLow(vec3(-1.0f,-1.0f,-1.0f)),
_vecBoundsHigh(vec3(1.0f,1.0f,1.0f)),
_valWidth(256.0f),
_valHeight(256.0f),
_valAngle(0.61),
_valZoom(1.0f),
_enmAspectBalancing(expose_less) {
}
mat4 FieldOfView::getViewerScreenXform() const {
mat4 projection;
vec3 low, high;
getFrustum(low, high);
// perspective projection? determine correct near distance
if (_valAngle != 0.0f) {
projection = translate(
frustum(low.x, high.x, low.y, high.y, low.z, high.z),
vec3(0.f, 0.f, -low.z) );
} else {
projection = ortho(low.x, high.x, low.y, high.y, low.z, high.z);
}
return projection;
}
mat4 FieldOfView::getWorldViewerXform() const {
return translate(affineInverse(_matOrientation),
vec3(0.0f, 0.0f, -_vecBoundsHigh.z) );
}
mat4 FieldOfView::getWorldScreenXform() const {
return translate(
getViewerScreenXform() * affineInverse(_matOrientation),
vec3(0.0f, 0.0f, -_vecBoundsHigh.z) );
}
mat4 FieldOfView::getViewerWorldXform() const {
vec3 n_translate = vec3(0.0f, 0.0f, _vecBoundsHigh.z);
return translate(
translate(mat4(1.0f), n_translate)
* _matOrientation, -n_translate );
}
float FieldOfView::getPixelSize() const {
vec3 low, high;
getFrustum(low, high);
return std::min(
abs(high.x - low.x) / _valWidth,
abs(high.y - low.y) / _valHeight);
}
void FieldOfView::getFrustum(vec3& low, vec3& high) const {
low = _vecBoundsLow;
high = _vecBoundsHigh;
// start with uniform zoom
float inv_zoom = 1.0f / _valZoom;
float adj_x = inv_zoom, adj_y = inv_zoom;
// balance aspect
if (_enmAspectBalancing != stretch) {
float f_aspect = (high.x - low.x) / (high.y - low.y);
float vp_aspect = _valWidth / _valHeight;
if ((_enmAspectBalancing == expose_more)
!= (f_aspect > vp_aspect)) {
// expose_more -> f_aspect <= vp_aspect <=> adj >= 1
// expose_less -> f_aspect > vp_aspect <=> adj < 1
adj_x = vp_aspect / f_aspect;
} else {
// expose_more -> f_aspect > vp_aspect <=> adj > 1
// expose_less -> f_aspect <= vp_aspect <=> adj <= 1
adj_y = f_aspect / vp_aspect;
}
}
// scale according to zoom / aspect correction
float ax = (low.x + high.x) / 2.0f, ay = (low.y + high.y) / 2.0f;
low.x = (low.x - ax) * adj_x + ax;
high.x = (high.x - ax) * adj_x + ax;
low.y = (low.y - ay) * adj_y + ay;
high.y = (high.y - ay) * adj_y + ay;
low.z = (low.z - high.z) * inv_zoom + high.z;
// calc and apply near distance based on near diagonal and perspective
float w = high.x - low.x, h = high.y - low.y;
high.z -= low.z;
low.z = _valAngle == 0.0f ? 0.0f :
sqrt(w*w+h*h) * 0.5f / tan(_valAngle * 0.5f);
high.z += low.z;
}

View file

@ -1,123 +0,0 @@
//
// FieldOfView.h
// interface
//
// Created by Tobias Schwinger on 3/21/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__FieldOfView__
#define __interface__FieldOfView__
#include <glm/glm.hpp>
//
// Viewing parameter encapsulation.
//
class FieldOfView {
glm::mat4 _matOrientation;
glm::vec3 _vecBoundsLow;
glm::vec3 _vecBoundsHigh;
float _valWidth;
float _valHeight;
float _valAngle;
float _valZoom;
int _enmAspectBalancing;
public:
FieldOfView();
// mutators
FieldOfView& setBounds(glm::vec3 const& low, glm::vec3 const& high) {
_vecBoundsLow = low; _vecBoundsHigh = high; return *this; }
FieldOfView& setOrientation(glm::mat4 const& matrix) { _matOrientation = matrix; return *this; }
FieldOfView& setPerspective(float angle) { _valAngle = angle; return *this; }
FieldOfView& setResolution(unsigned width, unsigned height) { _valWidth = width; _valHeight = height; return *this; }
FieldOfView& setZoom(float factor) { _valZoom = factor; return *this; }
enum aspect_balancing
{
expose_more,
expose_less,
stretch
};
FieldOfView& setAspectBalancing(aspect_balancing v) { _enmAspectBalancing = v; return *this; }
// dumb accessors
glm::mat4 const& getOrientation() const { return _matOrientation; }
float getWidthInPixels() const { return _valWidth; }
float getHeightInPixels() const { return _valHeight; }
float getPerspective() const { return _valAngle; }
// matrices
//
// Returns a full transformation matrix to project world coordinates
// onto the screen.
//
glm::mat4 getWorldScreenXform() const;
//
// Transforms world coordinates to viewer-relative coordinates.
//
// This matrix can be used as the modelview matrix in legacy GL code
// where the projection matrix is kept separately.
//
glm::mat4 getWorldViewerXform() const;
//
// Returns the transformation to of viewer-relative coordinates back
// to world space.
//
// This matrix can be used to set up a coordinate system for avatar
// rendering.
//
glm::mat4 getViewerWorldXform() const;
//
// Returns the transformation of viewer-relative coordinates to the
// screen.
//
// This matrix can be used as the projection matrix in legacy GL code.
//
glm::mat4 getViewerScreenXform() const;
// other useful information
//
// Returns the size of a pixel in world space, that is the minimum
// in respect to x/y screen directions.
//
float getPixelSize() const;
//
// Returns the frustum as used for the projection matrices.
// The result depdends on the bounds, eventually aspect correction
// for the current resolution, the perspective angle (specified in
// respect to diagonal) and zoom.
//
void getFrustum(glm::vec3& low, glm::vec3& high) const;
//
// Returns the z-offset from the origin to where orientation ia
// applied.
//
float getTransformOffset() const { return _vecBoundsHigh.z; }
//
// Returns the aspect ratio.
//
float getAspectRatio() const { return _valHeight / _valWidth; }
};
#endif

View file

@ -7,7 +7,6 @@
//
#include "InterfaceConfig.h"
#include "FieldOfView.h"
#include "Stars.h"
#define __interface__Starfield_impl__
@ -23,8 +22,8 @@ Stars::~Stars() {
delete _ptrController;
}
bool Stars::readInput(const char* url, unsigned limit) {
return _ptrController->readInput(url, limit);
bool Stars::readInput(const char* url, const char* cacheFile, unsigned limit) {
return _ptrController->readInput(url, cacheFile, limit);
}
bool Stars::setResolution(unsigned k) {
@ -35,8 +34,9 @@ float Stars::changeLOD(float fraction, float overalloc, float realloc) {
return float(_ptrController->changeLOD(fraction, overalloc, realloc));
}
void Stars::render(FieldOfView const& fov) {
_ptrController->render(fov.getPerspective(), fov.getAspectRatio(), fov.getOrientation());
void Stars::render(float fovDiagonal, float aspect, glm::mat4 const& view) {
_ptrController->render(fovDiagonal, aspect, glm::affineInverse(view));
}

View file

@ -9,7 +9,7 @@
#ifndef __interface__Stars__
#define __interface__Stars__
#include "FieldOfView.h"
#include <glm/glm.hpp>
namespace starfield { class Controller; }
@ -31,13 +31,13 @@ class Stars {
* The limit parameter allows to reduce the number of stars
* that are loaded, keeping the brightest ones.
*/
bool readInput(const char* url, unsigned limit = 200000);
bool readInput(const char* url, const char* cacheFile = 0l, unsigned limit = 200000);
/**
* Renders the starfield from a local viewer's perspective.
* The parameter specifies the field of view.
*/
void render(FieldOfView const& fov);
void render(float fovDiagonal, float aspect, glm::mat4 const& view);
/**
* Sets the resolution for FOV culling.

View file

@ -11,12 +11,44 @@
#include <cstring>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <SharedUtil.h>
#include "world.h"
#include "Util.h"
void eulerToOrthonormals(glm::vec3 * angles, glm::vec3 * fwd, glm::vec3 * left, glm::vec3 * up) {
//
// Converts from three euler angles to the associated orthonormal vectors
//
// Angles contains (pitch, yaw, roll) in radians
//
// First, create the quaternion associated with these euler angles
glm::quat q(glm::vec3(angles->x, angles->y, angles->z));
// Next, create a rotation matrix from that quaternion
glm::mat4 rotation;
rotation = glm::mat4_cast(q);
// Transform the original vectors by the rotation matrix to get the new vectors
glm::vec4 u(0,1,0,0);
glm::vec4 l(1,0,0,0);
glm::vec4 f(0,0,1,0);
glm::vec4 uNew = u*rotation;
glm::vec4 lNew = l*rotation;
glm::vec4 fNew = f*rotation;
// Copy the answers to output vectors
up->x = uNew.x; up->y = uNew.y; up->z = uNew.z;
left->x = lNew.x; left->y = lNew.y; left->z = lNew.z;
fwd->x = fNew.x; fwd->y = fNew.y; fwd->z = fNew.z;
}
// Return the azimuth angle in degrees between two points.
float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos) {
return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z) * 180.0f / PIf;
@ -227,6 +259,13 @@ void renderOrientationDirections( glm::vec3 position, Orientation orientation, f
glEnd();
}
bool closeEnoughForGovernmentWork(float a, float b) {
float distance = std::abs(a-b);
//printf("closeEnoughForGovernmentWork() a=%1.10f b=%1.10f distance=%1.10f\n",a,b,distance);
return (distance < 0.00001f);
}
void testOrientationClass() {
printf("\n----------\ntestOrientationClass()\n----------\n\n");
@ -236,14 +275,45 @@ void testOrientationClass() {
// ( yaw , pitch, roll , front.x , front.y , front.z , up.x , up.y , up.z , right.x , right.y , right.z )
// simple yaw tests
oTestCase( 0.f , 0.f , 0.f , 0.f , 0.f , 1.0f , 0.f , 1.0f , 0.f , -1.0f , 0.f , 0.f ),
oTestCase( 90.0f, 0.f , 0.f , 1.0f , 0.f , 0.f , 0.f , 1.0f , 0.f , 0.0f , 0.f , 1.0f ),
oTestCase(180.0f, 0.f , 0.f , 0.f , 0.f , -1.0f , 0.f , 1.0f , 0.f , 1.0f , 0.f , 0.f ),
oTestCase(270.0f, 0.f , 0.f , -1.0f , 0.f , 0.f , 0.f , 1.0f , 0.f , 0.0f , 0.f , -1.0f ),
oTestCase( 0.f , 0.f , 0.f , 0.f , 0.f , 1.0f , 0.f , 1.0f , 0.f , -1.0f , 0.f , 0.f ),
oTestCase(45.0f , 0.f , 0.f , 0.707107f , 0.f , 0.707107f , 0.f , 1.0f , 0.f , -0.707107f, 0.f , 0.707107f),
oTestCase( 90.0f, 0.f , 0.f , 1.0f , 0.f , 0.f , 0.f , 1.0f , 0.f , 0.0f , 0.f , 1.0f ),
oTestCase(135.0f, 0.f , 0.f , 0.707107f , 0.f ,-0.707107f , 0.f , 1.0f , 0.f , 0.707107f, 0.f , 0.707107f),
oTestCase(180.0f, 0.f , 0.f , 0.f , 0.f , -1.0f , 0.f , 1.0f , 0.f , 1.0f , 0.f , 0.f ),
oTestCase(225.0f, 0.f , 0.f , -0.707107f , 0.f ,-0.707107f , 0.f , 1.0f , 0.f , 0.707107f, 0.f , -0.707107f),
oTestCase(270.0f, 0.f , 0.f , -1.0f , 0.f , 0.f , 0.f , 1.0f , 0.f , 0.0f , 0.f , -1.0f ),
oTestCase(315.0f, 0.f , 0.f , -0.707107f , 0.f , 0.707107f , 0.f , 1.0f , 0.f , -0.707107f, 0.f , -0.707107f),
oTestCase(-45.0f, 0.f , 0.f , -0.707107f , 0.f , 0.707107f , 0.f , 1.0f , 0.f , -0.707107f, 0.f , -0.707107f),
oTestCase(-90.0f, 0.f , 0.f , -1.0f , 0.f , 0.f , 0.f , 1.0f , 0.f , 0.0f , 0.f , -1.0f ),
oTestCase(-135.0f,0.f , 0.f , -0.707107f , 0.f ,-0.707107f , 0.f , 1.0f , 0.f , 0.707107f, 0.f , -0.707107f),
oTestCase(-180.0f,0.f , 0.f , 0.f , 0.f , -1.0f , 0.f , 1.0f , 0.f , 1.0f , 0.f , 0.f ),
oTestCase(-225.0f,0.f , 0.f , 0.707107f , 0.f ,-0.707107f , 0.f , 1.0f , 0.f , 0.707107f, 0.f , 0.707107f),
oTestCase(-270.0f,0.f , 0.f , 1.0f , 0.f , 0.f , 0.f , 1.0f , 0.f , 0.0f , 0.f , 1.0f ),
oTestCase(-315.0f,0.f , 0.f , 0.707107f , 0.f , 0.707107f , 0.f , 1.0f , 0.f , -0.707107f, 0.f , 0.707107f),
// simple pitch tests
oTestCase( 0.f ,90.f , 0.f , 0.f , 1.0f , 0.0f , 0.f , 0.0f , -1.0f, -1.0f , 0.f , 0.f ),
oTestCase( 0.f , 0.f , 0.f , 0.f, 0.f , 1.0f , 0.f , 1.0f , 0.f , -1.0f , 0.f , 0.f ),
oTestCase( 0.f ,45.0f , 0.f , 0.f, 0.707107f , 0.707107f, 0.f ,0.707107f, -0.707107f, -1.0f , 0.f , 0.f ),
oTestCase( 0.f ,90.f , 0.f , 0.f, 1.0f , 0.0f , 0.f ,0.0f , -1.0f , -1.0f , 0.f , 0.f ),
oTestCase( 0.f ,135.0f, 0.f , 0.f, 0.707107f , -0.707107f, 0.f ,-0.707107f, -0.707107f, -1.0f , 0.f , 0.f ),
oTestCase( 0.f ,180.f , 0.f , 0.f, 0.0f ,-1.0f , 0.f ,-1.0f , 0.f , -1.0f , 0.f , 0.f ),
oTestCase( 0.f ,225.0f, 0.f , 0.f,-0.707107f , -0.707107f, 0.f ,-0.707107f, 0.707107f, -1.0f , 0.f , 0.f ),
oTestCase( 0.f ,270.f , 0.f , 0.f,-1.0f , 0.0f , 0.f ,0.0f , 1.0f , -1.0f , 0.f , 0.f ),
oTestCase( 0.f ,315.0f, 0.f , 0.f,-0.707107f , 0.707107f, 0.f , 0.707107f, 0.707107f, -1.0f , 0.f , 0.f ),
// simple roll tests
oTestCase( 0.f , 0.f , 0.f , 0.f , 0.f , 1.0f , 0.f , 1.0f ,0.0f , -1.0f , 0.f , 0.0f ),
oTestCase( 0.f , 0.f ,45.0f , 0.f , 0.f , 1.0f , 0.707107f , 0.707107f ,0.0f , -0.707107f, 0.707107f, 0.0f ),
oTestCase( 0.f , 0.f ,90.f , 0.f , 0.f , 1.0f , 1.0f , 0.0f ,0.0f , 0.0f , 1.0f , 0.0f ),
oTestCase( 0.f , 0.f ,135.0f , 0.f , 0.f , 1.0f , 0.707107f , -0.707107f,0.0f , 0.707107f , 0.707107f, 0.0f ),
oTestCase( 0.f , 0.f ,180.f , 0.f , 0.f , 1.0f , 0.0f , -1.0f ,0.0f , 1.0f , 0.0f , 0.0f ),
oTestCase( 0.f , 0.f ,225.0f , 0.f , 0.f , 1.0f , -0.707107f, -0.707107f,0.0f , 0.707107f ,-0.707107f, 0.0f ),
oTestCase( 0.f , 0.f ,270.f , 0.f , 0.f , 1.0f , -1.0f , 0.0f ,0.0f , 0.0f , -1.0f , 0.0f ),
oTestCase( 0.f , 0.f ,315.0f , 0.f , 0.f , 1.0f , -0.707107f, 0.707107f ,0.0f , -0.707107f,-0.707107f, 0.0f ),
// yaw combo tests
oTestCase( 90.f , 90.f , 0.f , 0.f , 1.0f , 0.0f , -1.0f , 0.0f , 0.f , 0.0f , 0.f , 1.0f ),
oTestCase( 90.f , 0.f , 90.f , 1.0f , 0.0f, 0.f , 0.0f , 0.0f , -1.f , 0.0f , 1.0f , 0.0f ),
};
int failedCount = 0;
@ -267,33 +337,43 @@ void testOrientationClass() {
glm::vec3 up = o1.getUp();
glm::vec3 right = o1.getRight();
printf("\n-----\nTest: %d - yaw=%f , pitch=%f , roll=%f \n\n",i+1,yaw,pitch,roll);
printf("\n-----\nTest: %d - yaw=%f , pitch=%f , roll=%f \n",i+1,yaw,pitch,roll);
printf(" +front.x=%f, front.y=%f, front.z=%f\n",front.x,front.y,front.z);
if (front.x == tests[i].frontX && front.y == tests[i].frontY && front.z == tests[i].frontZ) {
printf("\nFRONT\n");
printf(" + received: front.x=%f, front.y=%f, front.z=%f\n",front.x,front.y,front.z);
if (closeEnoughForGovernmentWork(front.x, tests[i].frontX)
&& closeEnoughForGovernmentWork(front.y, tests[i].frontY)
&& closeEnoughForGovernmentWork(front.z, tests[i].frontZ)) {
printf(" front vector PASSES!\n");
} else {
printf(" front vector FAILED! expected: \n");
printf(" front.x=%f, front.y=%f, front.z=%f\n",tests[i].frontX,tests[i].frontY,tests[i].frontZ);
printf(" expected: front.x=%f, front.y=%f, front.z=%f\n",tests[i].frontX,tests[i].frontY,tests[i].frontZ);
printf(" front vector FAILED! \n");
passed = false;
}
printf(" +up.x=%f, up.y=%f, up.z=%f\n",up.x,up.y,up.z);
if (up.x == tests[i].upX && up.y == tests[i].upY && up.z == tests[i].upZ) {
printf("\nUP\n");
printf(" + received: up.x=%f, up.y=%f, up.z=%f\n",up.x,up.y,up.z);
if (closeEnoughForGovernmentWork(up.x, tests[i].upX)
&& closeEnoughForGovernmentWork(up.y, tests[i].upY)
&& closeEnoughForGovernmentWork(up.z, tests[i].upZ)) {
printf(" up vector PASSES!\n");
} else {
printf(" up vector FAILED! expected: \n");
printf(" up.x=%f, up.y=%f, up.z=%f\n",tests[i].upX,tests[i].upY,tests[i].upZ);
printf(" expected: up.x=%f, up.y=%f, up.z=%f\n",tests[i].upX,tests[i].upY,tests[i].upZ);
printf(" up vector FAILED!\n");
passed = false;
}
printf(" +right.x=%f, right.y=%f, right.z=%f\n",right.x,right.y,right.z);
if (right.x == tests[i].rightX && right.y == tests[i].rightY && right.z == tests[i].rightZ) {
printf("\nRIGHT\n");
printf(" + received: right.x=%f, right.y=%f, right.z=%f\n",right.x,right.y,right.z);
if (closeEnoughForGovernmentWork(right.x, tests[i].rightX)
&& closeEnoughForGovernmentWork(right.y, tests[i].rightY)
&& closeEnoughForGovernmentWork(right.z, tests[i].rightZ)) {
printf(" right vector PASSES!\n");
} else {
printf(" right vector FAILED! expected: \n");
printf(" right.x=%f, right.y=%f, right.z=%f\n",tests[i].rightX,tests[i].rightY,tests[i].rightZ);
printf(" expected: right.x=%f, right.y=%f, right.z=%f\n",tests[i].rightX,tests[i].rightY,tests[i].rightZ);
printf(" right vector FAILED!\n");
passed = false;
}
@ -309,5 +389,3 @@ void testOrientationClass() {

View file

@ -19,6 +19,7 @@
#include <Orientation.h>
void eulerToOrthonormals(glm::vec3 * angles, glm::vec3 * fwd, glm::vec3 * left, glm::vec3 * up);
float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos);
float angle_to(glm::vec3 head_pos, glm::vec3 source_pos, float render_yaw, float head_yaw);

View file

@ -54,7 +54,7 @@
#include "Audio.h"
#endif
#include "FieldOfView.h"
#include "AngleUtil.h"
#include "Stars.h"
#include "MenuRow.h"
@ -96,6 +96,7 @@ int headMirror = 1; // Whether to mirror own head when viewing
int WIDTH = 1200; // Window size
int HEIGHT = 800;
int fullscreen = 0;
float aspectRatio = 1.0f;
bool wantColorRandomizer = true; // for addSphere and load file
@ -109,12 +110,8 @@ Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the v
// Starfield information
char starFile[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
FieldOfView fov;
char starCacheFile[] = "cachedStars.txt";
Stars stars;
#ifdef STARFIELD_KEYS
int starsTiles = 20;
double starsLod = 1.0;
#endif
bool showingVoxels = true;
@ -302,7 +299,7 @@ void init(void)
headMouseX = WIDTH/2;
headMouseY = HEIGHT/2;
stars.readInput(starFile, 0);
stars.readInput(starFile, starCacheFile, 0);
// Initialize Field values
field = Field();
@ -765,18 +762,12 @@ void display(void)
glRotatef ( whichCamera.getYaw(), 0, 1, 0 );
glTranslatef( -whichCamera.getPosition().x, -whichCamera.getPosition().y, -whichCamera.getPosition().z );
//quick test for camera ortho-normal sanity check...
if (::starsOn) {
// should be the first rendering pass - w/o depth buffer / lighting
stars.render(fov);
glm::mat4 view;
glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
stars.render(angleConvert<Degrees,Radians>(whichCamera.getFieldOfView()), aspectRatio, view);
}
glEnable(GL_LIGHTING);
@ -1277,13 +1268,6 @@ void key(unsigned char k, int x, int y)
if (k == ' ') reset_sensors();
if (k == 't') renderPitchRate -= KEYBOARD_PITCH_RATE;
if (k == 'g') renderPitchRate += KEYBOARD_PITCH_RATE;
#ifdef STARFIELD_KEYS
if (k == 'u') stars.setResolution(starsTiles += 1);
if (k == 'j') stars.setResolution(starsTiles = max(starsTiles-1,1));
if (k == 'i') if (starsLod < 1.0) starsLod = stars.changeLOD(1.01);
if (k == 'k') if (starsLod > 0.01) starsLod = stars.changeLOD(0.99);
if (k == 'r') stars.readInput(starFile, 0);
#endif
if (k == 'a') myAvatar.setDriveKeys(ROT_LEFT, 1);
if (k == 'd') myAvatar.setDriveKeys(ROT_RIGHT, 1);
}
@ -1401,7 +1385,7 @@ void reshape(int width, int height)
{
WIDTH = width;
HEIGHT = height;
float aspectRatio = ((float)width/(float)height); // based on screen resize
aspectRatio = ((float)width/(float)height); // based on screen resize
float fov;
float nearClip;
@ -1429,14 +1413,6 @@ void reshape(int width, int height)
glMatrixMode(GL_PROJECTION); //hello
// XXXBHG - Note: this is Tobias's code for loading the perspective matrix. At Philip's suggestion, I'm removing
// it and putting back our old code that simply loaded the fov, ratio, and near/far clips. But I'm keeping this here
// for reference for now.
//fov.setResolution(width, height)
// .setBounds(glm::vec3(-0.5f,-0.5f,-500.0f), glm::vec3(0.5f, 0.5f, 0.1f) )
// .setPerspective(0.7854f);
//glLoadMatrixf(glm::value_ptr(fov.getViewerScreenXform()));
glLoadIdentity();
// XXXBHG - If we're in view frustum mode, then we need to do this little bit of hackery so that
@ -1507,7 +1483,20 @@ void audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort) {
int main(int argc, const char * argv[])
{
// Quick test of the Orientation class on startup!
testOrientationClass();
//testOrientationClass(); // PER - commented out to test orthonormal code
//
// For Brad: Demo of function to test conversion of euler angles to orthonormals
// (Note that the euler angles order is Pitch, Yaw, Roll, and in radians)
//
glm::vec3 angles(0, PI/4, 0);
glm::vec3 fwd, left, up;
eulerToOrthonormals(&angles, &fwd, &left, &up);
printf("fwd: %4.2f, %4.2f, %4.2f\n", fwd.x, fwd.y, fwd.z);
printf("left: %4.2f, %4.2f, %4.2f\n", left.x, left.y, left.z);
printf("up: %4.2f, %4.2f, %4.2f\n", up.x, up.y, up.z);
AgentList::createInstance(AGENT_TYPE_INTERFACE);

View file

@ -25,8 +25,8 @@
#define STARFIELD_LOW_MEMORY 0 // set to 1 not to use 16-bit types
#endif
#ifndef STARFIELD_DEBUG_LOD
#define STARFIELD_DEBUG_LOD 0 // set to 1 to peek behind the scenes
#ifndef STARFIELD_DEBUG_CULLING
#define STARFIELD_DEBUG_CULLING 0 // set to 1 to peek behind the scenes
#endif
#ifndef STARFIELD_MULTITHREADING
@ -64,7 +64,6 @@
#include <glm/gtc/matrix_inverse.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/matrix_access.hpp>
#include <glm/gtc/swizzle.hpp>
#include "UrlReader.h"
#include "AngleUtil.h"
@ -80,13 +79,11 @@ namespace starfield {
using glm::vec4;
using glm::dot;
using glm::normalize;
using glm::swizzle;
using glm::X;
using glm::Y;
using glm::Z;
using glm::W;
using glm::mat4;
using glm::column;
using glm::row;
using namespace std;

View file

@ -109,11 +109,11 @@ namespace starfield {
_ptrRenderer(0l) {
}
bool readInput(const char* url, unsigned limit)
bool readInput(const char* url, const char* cacheFile, unsigned limit)
{
InputVertices vertices;
if (! Loader().loadVertices(vertices, url, limit))
if (! Loader().loadVertices(vertices, url, cacheFile, limit))
return false;
BrightnessLevels brightness;

View file

@ -33,7 +33,7 @@ namespace starfield {
public:
bool loadVertices(
InputVertices& destination, char const* url, unsigned limit)
InputVertices& destination, char const* url, char const* cacheFile, unsigned limit)
{
_ptrVertices = & destination;
_valLimit = limit;
@ -43,7 +43,7 @@ namespace starfield {
#endif
_strUrl = url; // in case we fail early
if (! UrlReader::readUrl(url, *this))
if (! UrlReader::readUrl(url, *this, cacheFile))
{
fprintf(stderr, "%s:%d: %s\n",
_strUrl, _valLineNo, getError());

View file

@ -149,7 +149,7 @@ namespace starfield {
matrix[3][2] = 0.0f;
// extract local z vector
vec3 ahead = swizzle<X,Y,Z>( column(matrix, 2) );
vec3 ahead = vec3(matrix[2]);
float azimuth = atan2(ahead.x,-ahead.z) + Radians::pi();
float altitude = atan2(-ahead.y, hypotf(ahead.x, ahead.z));
@ -163,7 +163,7 @@ namespace starfield {
// fprintf(stderr, "Stars.cpp: starting on tile #%d\n", tileIndex);
#if STARFIELD_DEBUG_LOD
#if STARFIELD_DEBUG_CULLING
mat4 matrix_debug = glm::translate(
glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f),
vec3(0.0f, 0.0f, -4.0f)) * glm::affineInverse(matrix);
@ -173,7 +173,7 @@ namespace starfield {
* glm::affineInverse(matrix);
this->_itrOutIndex = (unsigned*) _arrBatchOffs;
this->_vecWxform = swizzle<X,Y,Z>(row(matrix, 3));
this->_vecWxform = vec3(row(matrix, 3));
this->_valHalfPersp = halfPersp;
this->_valMinBright = minBright;
@ -181,13 +181,13 @@ namespace starfield {
_arrTile, _arrTile + _objTiling.getTileCount(),
(Tile**) _arrBatchCount));
#if STARFIELD_DEBUG_LOD
#if STARFIELD_DEBUG_CULLING
# define matrix matrix_debug
#endif
this->glBatch(glm::value_ptr(matrix), prepareBatch(
(unsigned*) _arrBatchOffs, _itrOutIndex) );
#if STARFIELD_DEBUG_LOD
#if STARFIELD_DEBUG_CULLING
# undef matrix
#endif
}

View file

@ -82,7 +82,10 @@ void AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
memcpy(&_handPosition, sourceBuffer, sizeof(float) * 3);
sourceBuffer += sizeof(float) * 3;
//printf( "_bodyYaw = %f", _bodyYaw );
//std::cout << _handPosition.x << ", " << _handPosition.y << ", " << _handPosition.z << "\n";
//std::cout << _bodyPosition.x << ", " << _bodyPosition.y << ", " << _bodyPosition.z << "\n";

View file

@ -6,13 +6,17 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "UrlReader.h"
#include <new>
#ifdef _WIN32
#define NOCURL_IN_WINDOWS
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifndef NOCURL_IN_WINDOWS
#include <curl/curl.h>
size_t const UrlReader::max_read_ahead = CURL_MAX_WRITE_SIZE;
@ -21,6 +25,7 @@ size_t const UrlReader::max_read_ahead = 0;
#endif
char const* const UrlReader::success = "UrlReader: Success!";
char const* const UrlReader::success_cached = "UrlReader:: Using local file.";
char const* const UrlReader::error_init_failed = "UrlReader: Initialization failed.";
char const* const UrlReader::error_aborted = "UrlReader: Processing error.";
char const* const UrlReader::error_buffer_overflow = "UrlReader: Buffer overflow.";
@ -29,7 +34,7 @@ char const* const UrlReader::error_leftover_input = "UrlReader: Incomplete pro
#define hnd_curl static_cast<CURL*>(_ptrImpl)
UrlReader::UrlReader()
: _ptrImpl(0l), _arrXtra(0l), _strError(0l) {
: _ptrImpl(0l), _arrXtra(0l), _strError(0l), _arrCacheRdBuf(0l) {
_arrXtra = new(std::nothrow) char[max_read_ahead];
if (! _arrXtra) { _strError = error_init_failed; return; }
@ -39,12 +44,14 @@ UrlReader::UrlReader()
curl_easy_setopt(hnd_curl, CURLOPT_NOSIGNAL, 1l);
curl_easy_setopt(hnd_curl, CURLOPT_FAILONERROR, 1l);
curl_easy_setopt(hnd_curl, CURLOPT_FILETIME, 1l);
curl_easy_setopt(hnd_curl, CURLOPT_ENCODING, "");
#endif
}
UrlReader::~UrlReader() {
delete _arrXtra;
delete[] _arrXtra;
delete[] _arrCacheRdBuf;
#ifndef NOCURL_IN_WINDOWS
if (! hnd_curl) return;
curl_easy_cleanup(hnd_curl);
@ -78,14 +85,42 @@ void UrlReader::getinfo(char const*& url,
char const*& type, int64_t& length, int64_t& stardate) {
#ifndef NOCURL_IN_WINDOWS
double clen;
long time;
curl_easy_getinfo(hnd_curl, CURLINFO_FILETIME, & time);
// check caching file time whether we actually want to download anything
if (_strCacheFile != 0l) {
struct stat s;
stat(_strCacheFile, & s);
if (time > s.st_mtime) {
// file on server is newer -> update cache file
_ptrCacheFile = fopen(_strCacheFile, "wb");
if (_ptrCacheFile != 0l) {
_valCacheMode = cache_write;
}
} else {
// file on server is older -> use cache file
if (! _arrCacheRdBuf) {
_arrCacheRdBuf = new (std::nothrow) char[max_read_ahead];
if (! _arrCacheRdBuf) {
_valCacheMode = no_cache;
}
}
_ptrCacheFile = fopen(_strCacheFile, "rb");
if (_ptrCacheFile != 0l) {
_valCacheMode = cache_read;
}
_strError = success_cached;
}
}
curl_easy_getinfo(hnd_curl, CURLINFO_EFFECTIVE_URL, & url);
curl_easy_getinfo(hnd_curl, CURLINFO_CONTENT_TYPE, & type);
double clen;
curl_easy_getinfo(hnd_curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, & clen);
length = static_cast<int64_t>(clen);
long time;
curl_easy_getinfo(hnd_curl, CURLINFO_FILETIME, & time);
stardate = time;
#endif

View file

@ -12,119 +12,132 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
/**
* UrlReader class that encapsulates a context for sequential data retrieval
* via URLs. Use one per thread.
*/
#include <stdio.h>
//
// UrlReader class that encapsulates a context for sequential data retrieval
// via URLs. Use one per thread.
//
class UrlReader {
enum CacheMode { no_cache, cache_write, cache_read };
void* _ptrImpl;
char* _arrXtra;
char const* _strError;
void* _ptrStream;
char const* _strCacheFile;
FILE* _ptrCacheFile;
char* _arrCacheRdBuf;
CacheMode _valCacheMode;
size_t _valXtraSize;
public:
/**
* Constructor - performs initialization, never throws.
*/
//
// Constructor - performs initialization, never throws.
//
UrlReader();
/**
* Destructor - frees resources, never throws.
*/
//
// Destructor - frees resources, never throws.
//
~UrlReader();
/**
* Reads data from an URL and forwards it to the instance of a class
* fulfilling the ContentStream concept.
*
* The call protocol on the ContentStream is detailed as follows:
*
* 1. begin(char const* url,
* char const* content_type, uint64_t bytes, uint64_t stardate)
*
* All information except 'url' is optional; 'content_type' can
* be a null pointer - 'bytes' and 'stardate' can be equal to
* to 'unavailable'.
*
* 2. transfer(char* buffer, size_t bytes)
*
* Called until all data has been received. The number of bytes
* actually processed should be returned.
* Unprocessed data is stored in an extra buffer whose size is
* given by the constant UrlReader::max_read_ahead - it can be
* assumed to be reasonably large for on-the-fly parsing.
*
* 3. end(bool ok)
*
* Called at the end of the transfer.
*
* Returns the same success code
*/
//
// Reads data from an URL and forwards it to the instance of a class
// fulfilling the ContentStream concept.
//
// The call protocol on the ContentStream is detailed as follows:
//
// 1. begin(char const* url,
// char const* content_type, uint64_t bytes, uint64_t stardate)
//
// All information except 'url' is optional; 'content_type' can
// be a null pointer - 'bytes' and 'stardate' can be equal to
// to 'unavailable'.
//
// 2. transfer(char* buffer, size_t bytes)
//
// Called until all data has been received. The number of bytes
// actually processed should be returned.
// Unprocessed data is stored in an extra buffer whose size is
// given by the constant UrlReader::max_read_ahead - it can be
// assumed to be reasonably large for on-the-fly parsing.
//
// 3. end(bool ok)
//
// Called at the end of the transfer.
//
// Returns the same success code
//
template< class ContentStream >
bool readUrl(char const* url, ContentStream& s);
bool readUrl(char const* url, ContentStream& s, char const* cacheFile = 0l);
/**
* Returns a pointer to a static C-string that describes the error
* condition.
*/
//
// Returns a pointer to a static C-string that describes the error
// condition.
//
inline char const* getError() const;
/**
* Can be called by the stream to set a user-defined error string.
*/
//
// Can be called by the stream to set a user-defined error string.
//
inline void setError(char const* static_c_string);
/**
* Pointer to the C-string returned by a call to 'readUrl' when no
* error occurred.
*/
//
// Pointer to the C-string returned by a call to 'readUrl' when no
// error occurred.
//
static char const* const success;
/**
* Pointer to the C-string returned by a call to 'readUrl' when the
* initialization has failed.
*/
//
// Pointer to the C-string returned by a call to 'readUrl' when no
// error occurred and a local file has been read instead of the
// network stream.
//
static char const* const success_cached;
//
// Pointer to the C-string returned by a call to 'readUrl' when the
// initialization has failed.
//
static char const* const error_init_failed;
/**
* Pointer to the C-string returned by a call to 'readUrl' when the
* transfer has been aborted by the client.
*/
//
// Pointer to the C-string returned by a call to 'readUrl' when the
// transfer has been aborted by the client.
//
static char const* const error_aborted;
/**
* Pointer to the C-string returned by a call to 'readUrl' when
* leftover input from incomplete processing caused a buffer
* overflow.
*/
//
// Pointer to the C-string returned by a call to 'readUrl' when
// leftover input from incomplete processing caused a buffer
// overflow.
//
static char const* const error_buffer_overflow;
/**
* Pointer to the C-string return by a call to 'readUrl' when the
* input provided was not completely consumed.
*/
//
// Pointer to the C-string return by a call to 'readUrl' when the
// input provided was not completely consumed.
//
static char const* const error_leftover_input;
/**
* Constant of the maximum number of bytes that are buffered
* between invocations of 'transfer'.
*/
//
// Constant of the maximum number of bytes that are buffered
// between invocations of 'transfer'.
//
static size_t const max_read_ahead;
/**
* Constant representing absent information in the call to the
* 'begin' member function of the target stream.
*/
//
// Constant representing absent information in the call to the
// 'begin' member function of the target stream.
//
static int const unavailable = -1;
/**
* Constant for requesting to abort the current transfer when
* returned by the 'transfer' member function of the target stream.
*/
//
// Constant for requesting to abort the current transfer when
// returned by the 'transfer' member function of the target stream.
//
static size_t const abort = ~0u;
private:
@ -143,38 +156,105 @@ class UrlReader {
// synthesized callback
template< class Stream >
static size_t callback_template(
char *input, size_t size, size_t nmemb, void* thiz);
template< class Stream > static size_t callback_template(char *input, size_t size,
size_t nmemb, void* thiz);
template< class Stream > size_t feedBuffered(Stream* stream,
char* input, size_t size);
};
template< class ContentStream >
bool UrlReader::readUrl(char const* url, ContentStream& s) {
bool UrlReader::readUrl(char const* url, ContentStream& s, char const* cacheFile) {
if (! _ptrImpl) return false;
_strCacheFile = cacheFile;
_ptrCacheFile = 0l;
_valCacheMode = no_cache; // eventually set later
_strError = success;
_ptrStream = & s;
_valXtraSize = ~size_t(0);
this->perform(url, & callback_template<ContentStream>);
s.end(_strError == success);
return _strError == success;
if (_ptrCacheFile != 0l) {
fclose(_ptrCacheFile);
}
return _strError == success || _strError == success_cached;
}
inline char const* UrlReader::getError() const { return this->_strError; }
inline void UrlReader::setError(char const* static_c_string) {
inline void UrlReader::setError(char const* staticCstring) {
if (this->_strError == success)
this->_strError = static_c_string;
if (this->_strError == success || this->_strError == success_cached)
this->_strError = staticCstring;
}
template< class Stream >
size_t UrlReader::callback_template(
char *input, size_t size, size_t nmemb, void* thiz) {
size_t UrlReader::feedBuffered(Stream* stream, char* input, size_t size) {
size_t inputOffset = 0u;
size *= nmemb;
while (true) {
char* buffer = input + inputOffset;
size_t bytes = size - inputOffset;
// data in extra buffer?
if (_valXtraSize > 0) {
// fill extra buffer with beginning of input
size_t fill = max_read_ahead - _valXtraSize;
if (bytes < fill) fill = bytes;
memcpy(_arrXtra + _valXtraSize, buffer, fill);
// use extra buffer for next transfer
buffer = _arrXtra;
bytes = _valXtraSize + fill;
inputOffset += fill;
}
// call 'transfer'
size_t processed = stream->transfer(buffer, bytes);
if (processed == abort) {
setError(error_aborted);
return 0u;
} else if (! processed && ! input) {
setError(error_leftover_input);
return 0u;
}
size_t unprocessed = bytes - processed;
// can switch to input buffer, now?
if (buffer == _arrXtra && unprocessed <= inputOffset) {
_valXtraSize = 0u;
inputOffset -= unprocessed;
} else { // no? unprocessed data -> extra buffer
if (unprocessed > max_read_ahead) {
setError(error_buffer_overflow);
return 0;
}
_valXtraSize = unprocessed;
memmove(_arrXtra, buffer + processed, unprocessed);
if (inputOffset == size || buffer != _arrXtra) {
return size;
}
}
} // while
}
template< class Stream >
size_t UrlReader::callback_template(char *input, size_t size, size_t nmemb, void* thiz) {
size_t result = 0u;
UrlReader* me = static_cast<UrlReader*>(thiz);
Stream* stream = static_cast<Stream*>(me->_ptrStream);
size *= nmemb;
// first call?
if (me->_valXtraSize == ~size_t(0)) {
@ -184,65 +264,28 @@ size_t UrlReader::callback_template(
char const* url, * type;
int64_t length, stardate;
me->getinfo(url, type, length, stardate);
stream->begin(url, type, length, stardate);
if (me->_valCacheMode != cache_read) {
stream->begin(url, type, length, stardate);
}
}
do {
// will have to repeat from here when reading a local file
size_t input_offset = 0u;
while (true) {
char* buffer = input + input_offset;
size_t bytes = size - input_offset;
// data in extra buffer?
if (me->_valXtraSize > 0) {
// fill extra buffer with beginning of input
size_t fill = max_read_ahead - me->_valXtraSize;
if (bytes < fill) fill = bytes;
memcpy(me->_arrXtra + me->_valXtraSize, buffer, fill);
// use extra buffer for next transfer
buffer = me->_arrXtra;
bytes = me->_valXtraSize + fill;
input_offset += fill;
// read from cache file?
if (me->_valCacheMode == cache_read) {
// change input buffer and start
input = me->_arrCacheRdBuf;
size = fread(input, 1, max_read_ahead, me->_ptrCacheFile);
nmemb = 1;
} else if (me->_valCacheMode == cache_write) {
fwrite(input, 1, size, me->_ptrCacheFile);
}
// call 'transfer'
size_t processed = stream->transfer(buffer, bytes);
if (processed == abort) {
result = me->feedBuffered(stream, input, size);
me->setError(error_aborted);
return 0u;
} while (me->_valCacheMode == cache_read && result != 0 && ! feof(me->_ptrCacheFile));
} else if (! processed && ! input) {
me->setError(error_leftover_input);
return 0u;
}
size_t unprocessed = bytes - processed;
// can switch to input buffer, now?
if (buffer == me->_arrXtra && unprocessed <= input_offset) {
me->_valXtraSize = 0u;
input_offset -= unprocessed;
} else { // no? unprocessed data -> extra buffer
if (unprocessed > max_read_ahead) {
me->setError(error_buffer_overflow);
return 0;
}
me->_valXtraSize = unprocessed;
memmove(me->_arrXtra, buffer + processed, unprocessed);
if (input_offset == size || buffer != me->_arrXtra) {
return size;
}
}
} // for
return me->_valCacheMode != cache_read ? result : 0;
}
#endif /* defined(__hifi__UrlReader__) */