mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 16:13:28 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
b3bb33e48c
17 changed files with 1445 additions and 8 deletions
|
@ -93,6 +93,7 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
|||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(metavoxels ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
||||
|
@ -135,7 +136,7 @@ if (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
|||
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
|
||||
endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
||||
|
||||
qt5_use_modules(${TARGET_NAME} Core Gui Multimedia Network OpenGL Svg WebKit WebKitWidgets)
|
||||
qt5_use_modules(${TARGET_NAME} Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets)
|
||||
|
||||
# include headers for interface and InterfaceConfig.
|
||||
include_directories(
|
||||
|
|
171
interface/resources/scripts/sphere.js
Normal file
171
interface/resources/scripts/sphere.js
Normal file
|
@ -0,0 +1,171 @@
|
|||
//
|
||||
// sphere.js
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/17/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
function strictIndexOf(array, element) {
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (array[i] == element) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
var colorIndex;
|
||||
var normalIndex;
|
||||
var visitor;
|
||||
var info;
|
||||
|
||||
var MAX_DEPTH = 4;
|
||||
|
||||
var sphereCenter = [ 0.5, 0.5, 0.5 ];
|
||||
var sphereColor = 0xFFFF00FF;
|
||||
var sphereRadius = 0.25;
|
||||
var sphereRadiusSquared = sphereRadius * sphereRadius;
|
||||
|
||||
function lengthSquared(x, y, z) {
|
||||
return x*x + y*y + z*z;
|
||||
}
|
||||
|
||||
function setNormal(vector) {
|
||||
if (normalIndex != -1) {
|
||||
var length = Math.sqrt(lengthSquared(vector[0], vector[1], vector[2]));
|
||||
if (length == 0.0) {
|
||||
info.attributeValues[normalIndex] = 0x007F00;
|
||||
|
||||
} else {
|
||||
var scale = 127.0 / length;
|
||||
info.attributeValues[normalIndex] =
|
||||
(Math.floor(vector[0] * scale) & 0xFF) << 16 |
|
||||
(Math.floor(vector[1] * scale) & 0xFF) << 8 |
|
||||
Math.floor(vector[2] * scale) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function guide(minimum, size, depth) {
|
||||
info.minimum = minimum;
|
||||
info.size = size;
|
||||
|
||||
// start with a relative fast bounding volume test to find most non-intersecting states
|
||||
var maximum = [ minimum[0] + size, minimum[1] + size, minimum[2] + size ];
|
||||
if (minimum[0] >= sphereCenter[0] + sphereRadius ||
|
||||
minimum[1] >= sphereCenter[1] + sphereRadius ||
|
||||
minimum[2] >= sphereCenter[2] + sphereRadius ||
|
||||
maximum[0] <= sphereCenter[0] - sphereRadius ||
|
||||
maximum[1] <= sphereCenter[1] - sphereRadius ||
|
||||
maximum[2] <= sphereCenter[2] - sphereRadius) {
|
||||
info.isLeaf = true;
|
||||
if (colorIndex != -1) {
|
||||
info.attributeValues[colorIndex] = 0x0;
|
||||
}
|
||||
visitor.visit(info);
|
||||
return;
|
||||
}
|
||||
|
||||
var halfSize = size / 2;
|
||||
var center = [ minimum[0] + halfSize, minimum[1] + halfSize, minimum[2] + halfSize ];
|
||||
var vector = [ center[0] - sphereCenter[0], center[1] - sphereCenter[1], center[2] - sphereCenter[2] ];
|
||||
|
||||
// count the number of points inside the sphere
|
||||
var inside = 0;
|
||||
if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - minimum[2]) <=
|
||||
sphereRadiusSquared) {
|
||||
inside++;
|
||||
}
|
||||
if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - minimum[2]) <=
|
||||
sphereRadiusSquared) {
|
||||
inside++;
|
||||
}
|
||||
if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - minimum[2]) <=
|
||||
sphereRadiusSquared) {
|
||||
inside++;
|
||||
}
|
||||
if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - minimum[2]) <=
|
||||
sphereRadiusSquared) {
|
||||
inside++;
|
||||
}
|
||||
if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - maximum[2]) <=
|
||||
sphereRadiusSquared) {
|
||||
inside++;
|
||||
}
|
||||
if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - maximum[2]) <=
|
||||
sphereRadiusSquared) {
|
||||
inside++;
|
||||
}
|
||||
if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - maximum[2]) <=
|
||||
sphereRadiusSquared) {
|
||||
inside++;
|
||||
}
|
||||
if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - maximum[2]) <=
|
||||
sphereRadiusSquared) {
|
||||
inside++;
|
||||
}
|
||||
|
||||
// see if all points are in the sphere
|
||||
if (inside == 8) {
|
||||
info.isLeaf = true;
|
||||
if (colorIndex != -1) {
|
||||
info.attributeValues[colorIndex] = sphereColor;
|
||||
}
|
||||
setNormal(vector);
|
||||
visitor.visit(info);
|
||||
return;
|
||||
}
|
||||
|
||||
// if we've reached max depth, compute alpha using a volume estimate
|
||||
if (depth == MAX_DEPTH) {
|
||||
info.isLeaf = true;
|
||||
if (inside >= 3) {
|
||||
if (colorIndex != -1) {
|
||||
info.attributeValues[colorIndex] = sphereColor;
|
||||
}
|
||||
setNormal(vector);
|
||||
|
||||
} else {
|
||||
if (colorIndex != -1) {
|
||||
info.attributeValues[colorIndex] = 0x0;
|
||||
}
|
||||
}
|
||||
visitor.visit(info);
|
||||
return;
|
||||
}
|
||||
|
||||
// recurse
|
||||
info.isLeaf = false;
|
||||
if (!visitor.visit(info)) {
|
||||
return;
|
||||
}
|
||||
depth += 1;
|
||||
guide(minimum, halfSize, depth);
|
||||
guide([ center[0], minimum[1], minimum[2] ], halfSize, depth);
|
||||
guide([ minimum[0], center[1], minimum[2] ], halfSize, depth);
|
||||
guide([ center[0], center[1], minimum[2] ], halfSize, depth);
|
||||
guide([ minimum[0], minimum[1], center[2] ], halfSize, depth);
|
||||
guide([ center[0], minimum[1], center[2] ], halfSize, depth);
|
||||
guide([ minimum[0], center[1], center[2] ], halfSize, depth);
|
||||
guide([ center[0], center[1], center[2] ], halfSize, depth);
|
||||
}
|
||||
|
||||
(function(visitation) {
|
||||
var attributes = visitation.visitor.getAttributes();
|
||||
colorIndex = strictIndexOf(attributes, AttributeRegistry.colorAttribute);
|
||||
normalIndex = strictIndexOf(attributes, AttributeRegistry.normalAttribute);
|
||||
visitor = visitation.visitor;
|
||||
info = { attributeValues: new Array(attributes.length) };
|
||||
|
||||
// have the sphere orbit the center and pulse in size
|
||||
var time = new Date().getTime();
|
||||
var ROTATE_PERIOD = 400.0;
|
||||
sphereCenter[0] = 0.5 + 0.25 * Math.cos(time / ROTATE_PERIOD);
|
||||
sphereCenter[2] = 0.5 + 0.25 * Math.sin(time / ROTATE_PERIOD);
|
||||
var PULSE_PERIOD = 300.0;
|
||||
sphereRadius = 0.25 + 0.0625 * Math.cos(time / PULSE_PERIOD);
|
||||
sphereRadiusSquared = sphereRadius * sphereRadius;
|
||||
|
||||
guide(visitation.info.minimum, visitation.info.size, 0);
|
||||
})
|
25
interface/resources/shaders/metavoxel_point.vert
Normal file
25
interface/resources/shaders/metavoxel_point.vert
Normal file
|
@ -0,0 +1,25 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// metavoxel_point.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/12/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
uniform float pointScale;
|
||||
|
||||
void main(void) {
|
||||
|
||||
// standard diffuse lighting
|
||||
gl_FrontColor = vec4(gl_Color.rgb * (gl_LightModel.ambient.rgb + gl_LightSource[0].ambient.rgb +
|
||||
gl_LightSource[0].diffuse.rgb * max(0.0, dot(gl_NormalMatrix * gl_Normal, gl_LightSource[0].position.xyz))),
|
||||
gl_Color.a);
|
||||
|
||||
// extract the first three components of the vertex for position
|
||||
gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0);
|
||||
|
||||
// the final component is the size in world space
|
||||
gl_PointSize = pointScale * gl_Vertex.w / gl_Position.w;
|
||||
}
|
|
@ -1858,6 +1858,8 @@ void Application::init() {
|
|||
_particles.init();
|
||||
_particles.setViewFrustum(getViewFrustum());
|
||||
|
||||
_metavoxels.init();
|
||||
|
||||
_particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_myAvatar);
|
||||
|
||||
_palette.init(_glWidget->width(), _glWidget->height());
|
||||
|
@ -2376,6 +2378,15 @@ void Application::updateParticles(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::updateMetavoxels(float deltaTime) {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()");
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) {
|
||||
_metavoxels.simulate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::updateTransmitter(float deltaTime) {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateTransmitter()");
|
||||
|
@ -2521,6 +2532,7 @@ void Application::update(float deltaTime) {
|
|||
updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); //loop through all the other avatars and simulate them...
|
||||
updateMyAvatarSimulation(deltaTime); // Simulate myself
|
||||
updateParticles(deltaTime); // Simulate particle cloud movements
|
||||
updateMetavoxels(deltaTime); // update metavoxels
|
||||
updateTransmitter(deltaTime); // transmitter drive or pick
|
||||
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
|
||||
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||
|
@ -3068,6 +3080,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
}
|
||||
}
|
||||
|
||||
// also, metavoxels
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... metavoxels...");
|
||||
_metavoxels.render();
|
||||
}
|
||||
|
||||
// render particles...
|
||||
_particles.render();
|
||||
|
||||
|
|
|
@ -58,9 +58,10 @@
|
|||
#include "renderer/AmbientOcclusionEffect.h"
|
||||
#include "renderer/GeometryCache.h"
|
||||
#include "renderer/GlowEffect.h"
|
||||
#include "renderer/VoxelShader.h"
|
||||
#include "renderer/MetavoxelSystem.h"
|
||||
#include "renderer/PointShader.h"
|
||||
#include "renderer/TextureCache.h"
|
||||
#include "renderer/VoxelShader.h"
|
||||
#include "ui/BandwidthDialog.h"
|
||||
#include "ui/ChatEntry.h"
|
||||
#include "ui/VoxelStatsDialog.h"
|
||||
|
@ -282,6 +283,7 @@ private:
|
|||
void updateThreads(float deltaTime);
|
||||
void updateMyAvatarSimulation(float deltaTime);
|
||||
void updateParticles(float deltaTime);
|
||||
void updateMetavoxels(float deltaTime);
|
||||
void updateTransmitter(float deltaTime);
|
||||
void updateCamera(float deltaTime);
|
||||
void updateDialogs(float deltaTime);
|
||||
|
@ -362,6 +364,8 @@ private:
|
|||
QByteArray _voxelsFilename;
|
||||
bool _wantToKillLocalVoxels;
|
||||
|
||||
MetavoxelSystem _metavoxels;
|
||||
|
||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
|
||||
Oscilloscope _audioScope;
|
||||
|
|
|
@ -174,9 +174,8 @@ void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples,
|
|||
if (sourceAudioFormat == destinationAudioFormat) {
|
||||
memcpy(destinationSamples, sourceSamples, numSourceSamples * sizeof(int16_t));
|
||||
} else {
|
||||
int destinationChannels = (destinationAudioFormat.channelCount() >= 2) ? 2 : destinationAudioFormat.channelCount();
|
||||
float sourceToDestinationFactor = (sourceAudioFormat.sampleRate() / (float) destinationAudioFormat.sampleRate())
|
||||
* (sourceAudioFormat.channelCount() / (float) destinationChannels);
|
||||
* (sourceAudioFormat.channelCount() / (float) destinationAudioFormat.channelCount());
|
||||
|
||||
// take into account the number of channels in source and destination
|
||||
// accomodate for the case where have an output with > 2 channels
|
||||
|
@ -203,14 +202,15 @@ void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples,
|
|||
// upsample from 24 to 48
|
||||
// for now this only supports a stereo to stereo conversion - this is our case for network audio to output
|
||||
int sourceIndex = 0;
|
||||
int destinationToSourceFactor = (1 / sourceToDestinationFactor);
|
||||
int dtsSampleRateFactor = (destinationAudioFormat.sampleRate() / sourceAudioFormat.sampleRate());
|
||||
int sampleShift = destinationAudioFormat.channelCount() * dtsSampleRateFactor;
|
||||
int destinationToSourceFactor = (1 / sourceToDestinationFactor);
|
||||
|
||||
for (int i = 0; i < numDestinationSamples; i += destinationAudioFormat.channelCount() * dtsSampleRateFactor) {
|
||||
for (int i = 0; i < numDestinationSamples; i += sampleShift) {
|
||||
sourceIndex = (i / destinationToSourceFactor);
|
||||
|
||||
// fill the L/R channels and make the rest silent
|
||||
for (int j = i; j < i + (dtsSampleRateFactor * destinationAudioFormat.channelCount()); j++) {
|
||||
for (int j = i; j < i + sampleShift; j++) {
|
||||
if (j % destinationAudioFormat.channelCount() == 0) {
|
||||
// left channel
|
||||
destinationSamples[j] = sourceSamples[sourceIndex];
|
||||
|
|
|
@ -285,7 +285,8 @@ Menu::Menu() :
|
|||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ParticleCloud, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false);
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, false);
|
||||
|
||||
|
||||
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options");
|
||||
|
||||
|
|
|
@ -219,6 +219,7 @@ namespace MenuOption {
|
|||
const QString Login = "Login";
|
||||
const QString LookAtIndicator = "Look-at Indicator";
|
||||
const QString LookAtVectors = "Look-at Vectors";
|
||||
const QString Metavoxels = "Metavoxels";
|
||||
const QString Mirror = "Mirror";
|
||||
const QString MoveWithLean = "Move with Lean";
|
||||
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
|
||||
|
|
122
interface/src/renderer/MetavoxelSystem.cpp
Normal file
122
interface/src/renderer/MetavoxelSystem.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
//
|
||||
// MetavoxelSystem.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/10/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QtDebug>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MetavoxelSystem.h"
|
||||
|
||||
ProgramObject MetavoxelSystem::_program;
|
||||
int MetavoxelSystem::_pointScaleLocation;
|
||||
|
||||
MetavoxelSystem::MetavoxelSystem() :
|
||||
_pointVisitor(_points),
|
||||
_buffer(QOpenGLBuffer::VertexBuffer) {
|
||||
}
|
||||
|
||||
void MetavoxelSystem::init() {
|
||||
if (!_program.isLinked()) {
|
||||
switchToResourcesParentIfRequired();
|
||||
_program.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/metavoxel_point.vert");
|
||||
_program.link();
|
||||
|
||||
_pointScaleLocation = _program.uniformLocation("pointScale");
|
||||
}
|
||||
|
||||
AttributeRegistry::getInstance()->configureScriptEngine(&_scriptEngine);
|
||||
|
||||
QFile scriptFile("resources/scripts/sphere.js");
|
||||
scriptFile.open(QIODevice::ReadOnly);
|
||||
QScriptValue guideFunction = _scriptEngine.evaluate(QTextStream(&scriptFile).readAll());
|
||||
_data.setAttributeValue(MetavoxelPath(), AttributeValue(AttributeRegistry::getInstance()->getGuideAttribute(),
|
||||
encodeInline(PolymorphicDataPointer(new ScriptedMetavoxelGuide(guideFunction)))));
|
||||
|
||||
_buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||
_buffer.create();
|
||||
}
|
||||
|
||||
void MetavoxelSystem::simulate(float deltaTime) {
|
||||
_points.clear();
|
||||
_data.guide(_pointVisitor);
|
||||
|
||||
_buffer.bind();
|
||||
int bytes = _points.size() * sizeof(Point);
|
||||
if (_buffer.size() < bytes) {
|
||||
_buffer.allocate(_points.constData(), bytes);
|
||||
} else {
|
||||
_buffer.write(0, _points.constData(), bytes);
|
||||
}
|
||||
_buffer.release();
|
||||
}
|
||||
|
||||
void MetavoxelSystem::render() {
|
||||
int viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
const int VIEWPORT_WIDTH_INDEX = 2;
|
||||
const int VIEWPORT_HEIGHT_INDEX = 3;
|
||||
float viewportWidth = viewport[VIEWPORT_WIDTH_INDEX];
|
||||
float viewportHeight = viewport[VIEWPORT_HEIGHT_INDEX];
|
||||
float viewportDiagonal = sqrtf(viewportWidth*viewportWidth + viewportHeight*viewportHeight);
|
||||
float worldDiagonal = glm::distance(Application::getInstance()->getViewFrustum()->getNearBottomLeft(),
|
||||
Application::getInstance()->getViewFrustum()->getNearTopRight());
|
||||
|
||||
_program.bind();
|
||||
_program.setUniformValue(_pointScaleLocation, viewportDiagonal *
|
||||
Application::getInstance()->getViewFrustum()->getNearClip() / worldDiagonal);
|
||||
|
||||
_buffer.bind();
|
||||
|
||||
Point* pt = 0;
|
||||
glVertexPointer(4, GL_FLOAT, sizeof(Point), &pt->vertex);
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Point), &pt->color);
|
||||
glNormalPointer(GL_BYTE, sizeof(Point), &pt->normal);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
|
||||
|
||||
glDrawArrays(GL_POINTS, 0, _points.size());
|
||||
|
||||
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
_buffer.release();
|
||||
|
||||
_program.release();
|
||||
}
|
||||
|
||||
MetavoxelSystem::PointVisitor::PointVisitor(QVector<Point>& points) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() <<
|
||||
AttributeRegistry::getInstance()->getColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getNormalAttribute()),
|
||||
_points(points) {
|
||||
}
|
||||
|
||||
bool MetavoxelSystem::PointVisitor::visit(const MetavoxelInfo& info) {
|
||||
if (!info.isLeaf) {
|
||||
return true;
|
||||
}
|
||||
QRgb color = info.attributeValues.at(0).getInlineValue<QRgb>();
|
||||
QRgb normal = info.attributeValues.at(1).getInlineValue<QRgb>();
|
||||
int alpha = qAlpha(color);
|
||||
if (alpha > 0) {
|
||||
Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size),
|
||||
{ qRed(color), qGreen(color), qBlue(color), alpha }, { qRed(normal), qGreen(normal), qBlue(normal) } };
|
||||
_points.append(point);
|
||||
}
|
||||
return false;
|
||||
}
|
61
interface/src/renderer/MetavoxelSystem.h
Normal file
61
interface/src/renderer/MetavoxelSystem.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// MetavoxelSystem.h
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/10/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__MetavoxelSystem__
|
||||
#define __interface__MetavoxelSystem__
|
||||
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QScriptEngine>
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <MetavoxelData.h>
|
||||
|
||||
#include "ProgramObject.h"
|
||||
|
||||
/// Renders a metavoxel tree.
|
||||
class MetavoxelSystem {
|
||||
public:
|
||||
|
||||
MetavoxelSystem();
|
||||
|
||||
void init();
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
private:
|
||||
|
||||
class Point {
|
||||
public:
|
||||
glm::vec4 vertex;
|
||||
quint8 color[4];
|
||||
quint8 normal[3];
|
||||
};
|
||||
|
||||
class PointVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
PointVisitor(QVector<Point>& points);
|
||||
virtual bool visit(const MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
QVector<Point>& _points;
|
||||
};
|
||||
|
||||
static ProgramObject _program;
|
||||
static int _pointScaleLocation;
|
||||
|
||||
QScriptEngine _scriptEngine;
|
||||
MetavoxelData _data;
|
||||
QVector<Point> _points;
|
||||
PointVisitor _pointVisitor;
|
||||
QOpenGLBuffer _buffer;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__MetavoxelSystem__) */
|
20
libraries/metavoxels/CMakeLists.txt
Normal file
20
libraries/metavoxels/CMakeLists.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
|
||||
|
||||
set(TARGET_NAME metavoxels)
|
||||
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
|
||||
qt5_use_modules(${TARGET_NAME} Widgets Script)
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
143
libraries/metavoxels/src/AttributeRegistry.cpp
Normal file
143
libraries/metavoxels/src/AttributeRegistry.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
//
|
||||
// AttributeRegistry.cpp
|
||||
// metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/6/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QScriptEngine>
|
||||
|
||||
#include "AttributeRegistry.h"
|
||||
#include "MetavoxelData.h"
|
||||
|
||||
AttributeRegistry AttributeRegistry::_instance;
|
||||
|
||||
AttributeRegistry::AttributeRegistry() :
|
||||
_guideAttribute(registerAttribute(new PolymorphicAttribute("guide", PolymorphicDataPointer(new DefaultMetavoxelGuide())))),
|
||||
_colorAttribute(registerAttribute(new QRgbAttribute("color"))),
|
||||
_normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) {
|
||||
}
|
||||
|
||||
void AttributeRegistry::configureScriptEngine(QScriptEngine* engine) {
|
||||
QScriptValue registry = engine->newObject();
|
||||
registry.setProperty("colorAttribute", engine->newQObject(_colorAttribute.data()));
|
||||
registry.setProperty("normalAttribute", engine->newQObject(_normalAttribute.data()));
|
||||
registry.setProperty("getAttribute", engine->newFunction(getAttribute, 1));
|
||||
engine->globalObject().setProperty("AttributeRegistry", registry);
|
||||
}
|
||||
|
||||
AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) {
|
||||
AttributePointer& pointer = _attributes[attribute->getName()];
|
||||
if (!pointer) {
|
||||
pointer = attribute;
|
||||
}
|
||||
return pointer;
|
||||
}
|
||||
|
||||
QScriptValue AttributeRegistry::getAttribute(QScriptContext* context, QScriptEngine* engine) {
|
||||
return engine->newQObject(_instance.getAttribute(context->argument(0).toString()).data(), QScriptEngine::QtOwnership,
|
||||
QScriptEngine::PreferExistingWrapperObject);
|
||||
}
|
||||
|
||||
AttributeValue::AttributeValue(const AttributePointer& attribute) :
|
||||
_attribute(attribute), _value(attribute ? attribute->getDefaultValue() : NULL) {
|
||||
}
|
||||
|
||||
AttributeValue::AttributeValue(const AttributePointer& attribute, void* value) :
|
||||
_attribute(attribute), _value(value) {
|
||||
}
|
||||
|
||||
void* AttributeValue::copy() const {
|
||||
return _attribute->create(_value);
|
||||
}
|
||||
|
||||
bool AttributeValue::isDefault() const {
|
||||
return !_attribute || _attribute->equal(_value, _attribute->getDefaultValue());
|
||||
}
|
||||
|
||||
bool AttributeValue::operator==(const AttributeValue& other) const {
|
||||
return _attribute == other._attribute && (!_attribute || _attribute->equal(_value, other._value));
|
||||
}
|
||||
|
||||
bool AttributeValue::operator==(void* other) const {
|
||||
return _attribute && _attribute->equal(_value, other);
|
||||
}
|
||||
|
||||
OwnedAttributeValue::OwnedAttributeValue(const AttributePointer& attribute) :
|
||||
AttributeValue(attribute, attribute ? attribute->create() : NULL) {
|
||||
}
|
||||
|
||||
OwnedAttributeValue::OwnedAttributeValue(const AttributePointer& attribute, void* value) :
|
||||
AttributeValue(attribute, attribute ? attribute->create(value) : NULL) {
|
||||
}
|
||||
|
||||
OwnedAttributeValue::OwnedAttributeValue(const AttributeValue& other) :
|
||||
AttributeValue(other.getAttribute(), other.getAttribute() ? other.copy() : NULL) {
|
||||
}
|
||||
|
||||
OwnedAttributeValue::~OwnedAttributeValue() {
|
||||
if (_attribute) {
|
||||
_attribute->destroy(_value);
|
||||
}
|
||||
}
|
||||
|
||||
OwnedAttributeValue& OwnedAttributeValue::operator=(const AttributeValue& other) {
|
||||
if (_attribute) {
|
||||
_attribute->destroy(_value);
|
||||
}
|
||||
if ((_attribute = other.getAttribute())) {
|
||||
_value = _attribute->create(other.getValue());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Attribute::Attribute(const QString& name) {
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
Attribute::~Attribute() {
|
||||
}
|
||||
|
||||
QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) :
|
||||
InlineAttribute<QRgb>(name, defaultValue) {
|
||||
}
|
||||
|
||||
bool QRgbAttribute::merge(void*& parent, void* children[]) const {
|
||||
QRgb firstValue = decodeInline<QRgb>(children[0]);
|
||||
int totalRed = qRed(firstValue);
|
||||
int totalGreen = qGreen(firstValue);
|
||||
int totalBlue = qBlue(firstValue);
|
||||
int totalAlpha = qAlpha(firstValue);
|
||||
bool allChildrenEqual = true;
|
||||
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
|
||||
QRgb value = decodeInline<QRgb>(children[i]);
|
||||
totalRed += qRed(value);
|
||||
totalGreen += qGreen(value);
|
||||
totalBlue += qBlue(value);
|
||||
totalAlpha += qAlpha(value);
|
||||
allChildrenEqual &= (firstValue == value);
|
||||
}
|
||||
parent = encodeInline(qRgba(totalRed / MERGE_COUNT, totalGreen / MERGE_COUNT,
|
||||
totalBlue / MERGE_COUNT, totalAlpha / MERGE_COUNT));
|
||||
return allChildrenEqual;
|
||||
}
|
||||
|
||||
void* QRgbAttribute::createFromScript(const QScriptValue& value, QScriptEngine* engine) const {
|
||||
return encodeInline((QRgb)value.toUInt32());
|
||||
}
|
||||
|
||||
PolymorphicData::~PolymorphicData() {
|
||||
}
|
||||
|
||||
template<> PolymorphicData* QExplicitlySharedDataPointer<PolymorphicData>::clone() {
|
||||
return d->clone();
|
||||
}
|
||||
|
||||
PolymorphicAttribute::PolymorphicAttribute(const QString& name, const PolymorphicDataPointer& defaultValue) :
|
||||
InlineAttribute<PolymorphicDataPointer>(name, defaultValue) {
|
||||
}
|
||||
|
||||
bool PolymorphicAttribute::merge(void*& parent, void* children[]) const {
|
||||
return false;
|
||||
}
|
275
libraries/metavoxels/src/AttributeRegistry.h
Normal file
275
libraries/metavoxels/src/AttributeRegistry.h
Normal file
|
@ -0,0 +1,275 @@
|
|||
//
|
||||
// AttributeRegistry.h
|
||||
// metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/6/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__AttributeRegistry__
|
||||
#define __interface__AttributeRegistry__
|
||||
|
||||
#include <QColor>
|
||||
#include <QExplicitlySharedDataPointer>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QSharedData>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
|
||||
#include "Bitstream.h"
|
||||
|
||||
class QScriptContext;
|
||||
class QScriptEngine;
|
||||
class QScriptValue;
|
||||
|
||||
class Attribute;
|
||||
|
||||
typedef QSharedPointer<Attribute> AttributePointer;
|
||||
|
||||
/// Maintains information about metavoxel attribute types.
|
||||
class AttributeRegistry {
|
||||
public:
|
||||
|
||||
/// Returns a pointer to the singleton registry instance.
|
||||
static AttributeRegistry* getInstance() { return &_instance; }
|
||||
|
||||
AttributeRegistry();
|
||||
|
||||
/// Configures the supplied script engine with the global AttributeRegistry property.
|
||||
void configureScriptEngine(QScriptEngine* engine);
|
||||
|
||||
/// Registers an attribute with the system. The registry assumes ownership of the object.
|
||||
/// \return either the pointer passed as an argument, if the attribute wasn't already registered, or the existing
|
||||
/// attribute
|
||||
AttributePointer registerAttribute(Attribute* attribute) { return registerAttribute(AttributePointer(attribute)); }
|
||||
|
||||
/// Registers an attribute with the system.
|
||||
/// \return either the pointer passed as an argument, if the attribute wasn't already registered, or the existing
|
||||
/// attribute
|
||||
AttributePointer registerAttribute(AttributePointer attribute);
|
||||
|
||||
/// Retrieves an attribute by name.
|
||||
AttributePointer getAttribute(const QString& name) const { return _attributes.value(name); }
|
||||
|
||||
/// Returns a reference to the standard PolymorphicDataPointer "guide" attribute.
|
||||
const AttributePointer& getGuideAttribute() const { return _guideAttribute; }
|
||||
|
||||
/// Returns a reference to the standard QRgb "color" attribute.
|
||||
const AttributePointer& getColorAttribute() const { return _colorAttribute; }
|
||||
|
||||
/// Returns a reference to the standard QRgb "normal" attribute.
|
||||
const AttributePointer& getNormalAttribute() const { return _normalAttribute; }
|
||||
|
||||
private:
|
||||
|
||||
static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine);
|
||||
|
||||
static AttributeRegistry _instance;
|
||||
|
||||
QHash<QString, AttributePointer> _attributes;
|
||||
AttributePointer _guideAttribute;
|
||||
AttributePointer _colorAttribute;
|
||||
AttributePointer _normalAttribute;
|
||||
};
|
||||
|
||||
/// Converts a value to a void pointer.
|
||||
template<class T> inline void* encodeInline(T value) {
|
||||
return *(void**)&value;
|
||||
}
|
||||
|
||||
/// Extracts a value from a void pointer.
|
||||
template<class T> inline T decodeInline(void* value) {
|
||||
return *(T*)&value;
|
||||
}
|
||||
|
||||
/// Pairs an attribute value with its type.
|
||||
class AttributeValue {
|
||||
public:
|
||||
|
||||
AttributeValue(const AttributePointer& attribute = AttributePointer());
|
||||
AttributeValue(const AttributePointer& attribute, void* value);
|
||||
|
||||
AttributePointer getAttribute() const { return _attribute; }
|
||||
void* getValue() const { return _value; }
|
||||
|
||||
template<class T> void setInlineValue(T value) { _value = encodeInline(value); }
|
||||
template<class T> T getInlineValue() const { return decodeInline<T>(_value); }
|
||||
|
||||
template<class T> T* getPointerValue() const { return static_cast<T*>(_value); }
|
||||
|
||||
void* copy() const;
|
||||
|
||||
bool isDefault() const;
|
||||
|
||||
bool operator==(const AttributeValue& other) const;
|
||||
bool operator==(void* other) const;
|
||||
|
||||
protected:
|
||||
|
||||
AttributePointer _attribute;
|
||||
void* _value;
|
||||
};
|
||||
|
||||
// Assumes ownership of an attribute value.
|
||||
class OwnedAttributeValue : public AttributeValue {
|
||||
public:
|
||||
|
||||
OwnedAttributeValue(const AttributePointer& attribute = AttributePointer());
|
||||
OwnedAttributeValue(const AttributePointer& attribute, void* value);
|
||||
OwnedAttributeValue(const AttributeValue& other);
|
||||
~OwnedAttributeValue();
|
||||
|
||||
OwnedAttributeValue& operator=(const AttributeValue& other);
|
||||
};
|
||||
|
||||
/// Represents a registered attribute.
|
||||
class Attribute : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static const int MERGE_COUNT = 8;
|
||||
|
||||
Attribute(const QString& name);
|
||||
virtual ~Attribute();
|
||||
|
||||
Q_INVOKABLE QString getName() const { return objectName(); }
|
||||
|
||||
void* create() const { return create(getDefaultValue()); }
|
||||
virtual void* create(void* copy) const = 0;
|
||||
virtual void destroy(void* value) const = 0;
|
||||
|
||||
virtual bool read(Bitstream& in, void*& value) const = 0;
|
||||
virtual bool write(Bitstream& out, void* value) const = 0;
|
||||
|
||||
virtual bool equal(void* first, void* second) const = 0;
|
||||
|
||||
/// Merges the value of a parent and its children.
|
||||
/// \return whether or not the children and parent values are all equal
|
||||
virtual bool merge(void*& parent, void* children[]) const = 0;
|
||||
|
||||
virtual void* getDefaultValue() const = 0;
|
||||
|
||||
virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const { return create(); }
|
||||
};
|
||||
|
||||
/// A simple attribute class that stores its values inline.
|
||||
template<class T, int bits = 32> class InlineAttribute : public Attribute {
|
||||
public:
|
||||
|
||||
InlineAttribute(const QString& name, const T& defaultValue = T()) : Attribute(name), _defaultValue(defaultValue) { }
|
||||
|
||||
virtual void* create(void* copy) const { void* value; new (&value) T(*(T*)©); return value; }
|
||||
virtual void destroy(void* value) const { ((T*)&value)->~T(); }
|
||||
|
||||
virtual bool read(Bitstream& in, void*& value) const { value = getDefaultValue(); in.read(&value, bits); return false; }
|
||||
virtual bool write(Bitstream& out, void* value) const { out.write(&value, bits); return false; }
|
||||
|
||||
virtual bool equal(void* first, void* second) const { return decodeInline<T>(first) == decodeInline<T>(second); }
|
||||
|
||||
virtual void* getDefaultValue() const { return encodeInline(_defaultValue); }
|
||||
|
||||
private:
|
||||
|
||||
T _defaultValue;
|
||||
};
|
||||
|
||||
/// Provides merging using the =, ==, += and /= operators.
|
||||
template<class T, int bits = 32> class SimpleInlineAttribute : public InlineAttribute<T, bits> {
|
||||
public:
|
||||
|
||||
SimpleInlineAttribute(const QString& name, T defaultValue = T()) : InlineAttribute<T, bits>(name, defaultValue) { }
|
||||
|
||||
virtual bool merge(void*& parent, void* children[]) const;
|
||||
};
|
||||
|
||||
template<class T, int bits> inline bool SimpleInlineAttribute<T, bits>::merge(void*& parent, void* children[]) const {
|
||||
T& merged = *(T*)&parent;
|
||||
merged = decodeInline<T>(children[0]);
|
||||
bool allChildrenEqual = true;
|
||||
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
|
||||
merged += decodeInline<T>(children[i]);
|
||||
allChildrenEqual &= (decodeInline<T>(children[0]) == decodeInline<T>(children[i]));
|
||||
}
|
||||
merged /= Attribute::MERGE_COUNT;
|
||||
return allChildrenEqual;
|
||||
}
|
||||
|
||||
/// Provides appropriate averaging for RGBA values.
|
||||
class QRgbAttribute : public InlineAttribute<QRgb> {
|
||||
public:
|
||||
|
||||
QRgbAttribute(const QString& name, QRgb defaultValue = QRgb());
|
||||
|
||||
virtual bool merge(void*& parent, void* children[]) const;
|
||||
|
||||
virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const;
|
||||
};
|
||||
|
||||
/// An attribute class that stores pointers to its values.
|
||||
template<class T> class PointerAttribute : public Attribute {
|
||||
public:
|
||||
|
||||
PointerAttribute(const QString& name, T defaultValue = T()) : Attribute(name), _defaultValue(defaultValue) { }
|
||||
|
||||
virtual void* create(void* copy) const { new T(*static_cast<T*>(copy)); }
|
||||
virtual void destroy(void* value) const { delete static_cast<T*>(value); }
|
||||
|
||||
virtual bool read(Bitstream& in, void*& value) const { in >> *static_cast<T*>(value); return true; }
|
||||
virtual bool write(Bitstream& out, void* value) const { out << *static_cast<T*>(value); return true; }
|
||||
|
||||
virtual bool equal(void* first, void* second) const { return *static_cast<T*>(first) == *static_cast<T*>(second); }
|
||||
|
||||
virtual void* getDefaultValue() const { return const_cast<void*>((void*)&_defaultValue); }
|
||||
|
||||
private:
|
||||
|
||||
T _defaultValue;
|
||||
};
|
||||
|
||||
/// Provides merging using the =, ==, += and /= operators.
|
||||
template<class T> class SimplePointerAttribute : public PointerAttribute<T> {
|
||||
public:
|
||||
|
||||
SimplePointerAttribute(const QString& name, T defaultValue = T()) : PointerAttribute<T>(name, defaultValue) { }
|
||||
|
||||
virtual bool merge(void*& parent, void* children[]) const;
|
||||
};
|
||||
|
||||
template<class T> inline bool SimplePointerAttribute<T>::merge(void*& parent, void* children[]) const {
|
||||
T& merged = *static_cast<T*>(parent);
|
||||
merged = *static_cast<T*>(children[0]);
|
||||
bool allChildrenEqual = true;
|
||||
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
|
||||
merged += *static_cast<T*>(children[i]);
|
||||
allChildrenEqual &= (*static_cast<T*>(children[0]) == *static_cast<T*>(children[i]));
|
||||
}
|
||||
merged /= Attribute::MERGE_COUNT;
|
||||
return allChildrenEqual;
|
||||
}
|
||||
|
||||
/// Base class for polymorphic attribute data.
|
||||
class PolymorphicData : public QSharedData {
|
||||
public:
|
||||
|
||||
virtual ~PolymorphicData();
|
||||
|
||||
/// Creates a new clone of this object.
|
||||
virtual PolymorphicData* clone() const = 0;
|
||||
};
|
||||
|
||||
template<> PolymorphicData* QExplicitlySharedDataPointer<PolymorphicData>::clone();
|
||||
|
||||
typedef QExplicitlySharedDataPointer<PolymorphicData> PolymorphicDataPointer;
|
||||
|
||||
/// Provides polymorphic streaming and averaging.
|
||||
class PolymorphicAttribute : public InlineAttribute<PolymorphicDataPointer> {
|
||||
public:
|
||||
|
||||
PolymorphicAttribute(const QString& name, const PolymorphicDataPointer& defaultValue = PolymorphicDataPointer());
|
||||
|
||||
virtual bool merge(void*& parent, void* children[]) const;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__AttributeRegistry__) */
|
81
libraries/metavoxels/src/Bitstream.cpp
Normal file
81
libraries/metavoxels/src/Bitstream.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// Bitstream.cpp
|
||||
// metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/2/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
#include "Bitstream.h"
|
||||
|
||||
Bitstream::Bitstream(QDataStream& underlying)
|
||||
: _underlying(underlying), _byte(0), _position(0) {
|
||||
}
|
||||
|
||||
const int BITS_IN_BYTE = 8;
|
||||
const int LAST_BIT_POSITION = BITS_IN_BYTE - 1;
|
||||
|
||||
Bitstream& Bitstream::write(const void* data, int bits, int offset) {
|
||||
const quint8* source = (const quint8*)data;
|
||||
while (bits > 0) {
|
||||
int bitsToWrite = qMin(BITS_IN_BYTE - _position, qMin(BITS_IN_BYTE - offset, bits));
|
||||
_byte |= ((*source >> offset) & ((1 << bitsToWrite) - 1)) << _position;
|
||||
if ((_position += bitsToWrite) == BITS_IN_BYTE) {
|
||||
flush();
|
||||
}
|
||||
if ((offset += bitsToWrite) == BITS_IN_BYTE) {
|
||||
source++;
|
||||
offset = 0;
|
||||
}
|
||||
bits -= bitsToWrite;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::read(void* data, int bits, int offset) {
|
||||
quint8* dest = (quint8*)data;
|
||||
while (bits > 0) {
|
||||
if (_position == 0) {
|
||||
_underlying >> _byte;
|
||||
}
|
||||
int bitsToRead = qMin(BITS_IN_BYTE - _position, qMin(BITS_IN_BYTE - offset, bits));
|
||||
*dest |= ((_byte >> _position) & ((1 << bitsToRead) - 1)) << offset;
|
||||
_position = (_position + bitsToRead) & LAST_BIT_POSITION;
|
||||
if ((offset += bitsToRead) == BITS_IN_BYTE) {
|
||||
dest++;
|
||||
offset = 0;
|
||||
}
|
||||
bits -= bitsToRead;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Bitstream::flush() {
|
||||
if (_position != 0) {
|
||||
_underlying << _byte;
|
||||
_byte = 0;
|
||||
_position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Bitstream& Bitstream::operator<<(bool value) {
|
||||
if (value) {
|
||||
_byte |= (1 << _position);
|
||||
}
|
||||
if (++_position == BITS_IN_BYTE) {
|
||||
flush();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(bool& value) {
|
||||
if (_position == 0) {
|
||||
_underlying >> _byte;
|
||||
}
|
||||
value = _byte & (1 << _position);
|
||||
_position = (_position + 1) & LAST_BIT_POSITION;
|
||||
return *this;
|
||||
}
|
45
libraries/metavoxels/src/Bitstream.h
Normal file
45
libraries/metavoxels/src/Bitstream.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// Bitstream.h
|
||||
// metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/2/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__Bitstream__
|
||||
#define __interface__Bitstream__
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
class QDataStream;
|
||||
|
||||
/// A stream for bit-aligned data.
|
||||
class Bitstream {
|
||||
public:
|
||||
|
||||
Bitstream(QDataStream& underlying);
|
||||
|
||||
/// Writes a set of bits to the underlying stream.
|
||||
/// \param bits the number of bits to write
|
||||
/// \param offset the offset of the first bit
|
||||
Bitstream& write(const void* data, int bits, int offset = 0);
|
||||
|
||||
/// Reads a set of bits from the underlying stream.
|
||||
/// \param bits the number of bits to read
|
||||
/// \param offset the offset of the first bit
|
||||
Bitstream& read(void* data, int bits, int offset = 0);
|
||||
|
||||
/// Flushes any unwritten bits to the underlying stream.
|
||||
void flush();
|
||||
|
||||
Bitstream& operator<<(bool value);
|
||||
Bitstream& operator>>(bool& value);
|
||||
|
||||
private:
|
||||
|
||||
QDataStream& _underlying;
|
||||
quint8 _byte;
|
||||
int _position;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__Bitstream__) */
|
281
libraries/metavoxels/src/MetavoxelData.cpp
Normal file
281
libraries/metavoxels/src/MetavoxelData.cpp
Normal file
|
@ -0,0 +1,281 @@
|
|||
//
|
||||
// MetavoxelData.cpp
|
||||
// metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/6/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QScriptEngine>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "MetavoxelData.h"
|
||||
|
||||
MetavoxelData::~MetavoxelData() {
|
||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
||||
it.value()->destroy(it.key());
|
||||
delete it.value();
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelData::guide(MetavoxelVisitor& visitor) {
|
||||
// start with the root values/defaults (plus the guide attribute)
|
||||
const float TOP_LEVEL_SIZE = 1.0f;
|
||||
const QVector<AttributePointer>& attributes = visitor.getAttributes();
|
||||
MetavoxelVisitation firstVisitation = { visitor, QVector<MetavoxelNode*>(attributes.size() + 1),
|
||||
{ glm::vec3(), TOP_LEVEL_SIZE, QVector<AttributeValue>(attributes.size() + 1) } };
|
||||
for (int i = 0; i < attributes.size(); i++) {
|
||||
MetavoxelNode* node = _roots.value(attributes[i]);
|
||||
firstVisitation.nodes[i] = node;
|
||||
firstVisitation.info.attributeValues[i] = node ? node->getAttributeValue(attributes[i]) : attributes[i];
|
||||
}
|
||||
AttributePointer guideAttribute = AttributeRegistry::getInstance()->getGuideAttribute();
|
||||
MetavoxelNode* node = _roots.value(guideAttribute);
|
||||
firstVisitation.nodes.last() = node;
|
||||
firstVisitation.info.attributeValues.last() = node ? node->getAttributeValue(guideAttribute) : guideAttribute;
|
||||
static_cast<MetavoxelGuide*>(firstVisitation.info.attributeValues.last().getInlineValue<
|
||||
PolymorphicDataPointer>().data())->guide(firstVisitation);
|
||||
}
|
||||
|
||||
void MetavoxelData::setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue) {
|
||||
MetavoxelNode*& node = _roots[attributeValue.getAttribute()];
|
||||
if (node == NULL) {
|
||||
node = new MetavoxelNode(attributeValue.getAttribute());
|
||||
}
|
||||
if (node->setAttributeValue(path, 0, attributeValue) && attributeValue.isDefault()) {
|
||||
node->destroy(attributeValue.getAttribute());
|
||||
delete node;
|
||||
_roots.remove(attributeValue.getAttribute());
|
||||
}
|
||||
}
|
||||
|
||||
AttributeValue MetavoxelData::getAttributeValue(const MetavoxelPath& path, const AttributePointer& attribute) const {
|
||||
MetavoxelNode* node = _roots.value(attribute);
|
||||
if (node == NULL) {
|
||||
return AttributeValue(attribute);
|
||||
}
|
||||
for (int i = 0, n = path.getSize(); i < n; i++) {
|
||||
MetavoxelNode* child = node->getChild(path[i]);
|
||||
if (child == NULL) {
|
||||
return node->getAttributeValue(attribute);
|
||||
}
|
||||
node = child;
|
||||
}
|
||||
return node->getAttributeValue(attribute);
|
||||
}
|
||||
|
||||
MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) {
|
||||
_attributeValue = attributeValue.copy();
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
_children[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool MetavoxelNode::setAttributeValue(const MetavoxelPath& path, int index, const AttributeValue& attributeValue) {
|
||||
if (index == path.getSize()) {
|
||||
setAttributeValue(attributeValue);
|
||||
return true;
|
||||
}
|
||||
int element = path[index];
|
||||
if (_children[element] == NULL) {
|
||||
AttributeValue ownAttributeValue = getAttributeValue(attributeValue.getAttribute());
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
_children[i] = new MetavoxelNode(ownAttributeValue);
|
||||
}
|
||||
}
|
||||
_children[element]->setAttributeValue(path, index + 1, attributeValue);
|
||||
|
||||
void* childValues[CHILD_COUNT];
|
||||
bool allLeaves = true;
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
childValues[i] = _children[i]->_attributeValue;
|
||||
allLeaves &= _children[i]->isLeaf();
|
||||
}
|
||||
if (attributeValue.getAttribute()->merge(_attributeValue, childValues) && allLeaves) {
|
||||
clearChildren(attributeValue.getAttribute());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MetavoxelNode::setAttributeValue(const AttributeValue& attributeValue) {
|
||||
attributeValue.getAttribute()->destroy(_attributeValue);
|
||||
_attributeValue = attributeValue.copy();
|
||||
clearChildren(attributeValue.getAttribute());
|
||||
}
|
||||
|
||||
AttributeValue MetavoxelNode::getAttributeValue(const AttributePointer& attribute) const {
|
||||
return AttributeValue(attribute, _attributeValue);
|
||||
}
|
||||
|
||||
bool MetavoxelNode::isLeaf() const {
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
if (_children[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MetavoxelNode::destroy(const AttributePointer& attribute) {
|
||||
attribute->destroy(_attributeValue);
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
if (_children[i]) {
|
||||
_children[i]->destroy(attribute);
|
||||
delete _children[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelNode::clearChildren(const AttributePointer& attribute) {
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
if (_children[i]) {
|
||||
_children[i]->destroy(attribute);
|
||||
delete _children[i];
|
||||
_children[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int MetavoxelPath::operator[](int index) const {
|
||||
return _array.at(index * BITS_PER_ELEMENT) | (_array.at(index * BITS_PER_ELEMENT + 1) << 1) |
|
||||
(_array.at(index * BITS_PER_ELEMENT + 2) << 2);
|
||||
}
|
||||
|
||||
MetavoxelPath& MetavoxelPath::operator+=(int element) {
|
||||
int offset = _array.size();
|
||||
_array.resize(offset + BITS_PER_ELEMENT);
|
||||
_array.setBit(offset, element & 0x01);
|
||||
_array.setBit(offset + 1, (element >> 1) & 0x01);
|
||||
_array.setBit(offset + 2, element >> 2);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PolymorphicData* DefaultMetavoxelGuide::clone() const {
|
||||
return new DefaultMetavoxelGuide();
|
||||
}
|
||||
|
||||
const int X_MAXIMUM_FLAG = 1;
|
||||
const int Y_MAXIMUM_FLAG = 2;
|
||||
const int Z_MAXIMUM_FLAG = 4;
|
||||
|
||||
void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
||||
visitation.info.isLeaf = visitation.allNodesLeaves();
|
||||
if (!visitation.visitor.visit(visitation.info) || visitation.info.isLeaf) {
|
||||
return;
|
||||
}
|
||||
MetavoxelVisitation nextVisitation = { visitation.visitor, QVector<MetavoxelNode*>(visitation.nodes.size()),
|
||||
{ glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.nodes.size()) } };
|
||||
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
|
||||
for (int j = 0; j < visitation.nodes.size(); j++) {
|
||||
MetavoxelNode* node = visitation.nodes.at(j);
|
||||
MetavoxelNode* child = node ? node->getChild(i) : NULL;
|
||||
nextVisitation.info.attributeValues[j] = ((nextVisitation.nodes[j] = child)) ?
|
||||
child->getAttributeValue(visitation.info.attributeValues[j].getAttribute()) :
|
||||
visitation.info.attributeValues[j];
|
||||
}
|
||||
nextVisitation.info.minimum = visitation.info.minimum + glm::vec3(
|
||||
(i & X_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f,
|
||||
(i & Y_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f,
|
||||
(i & Z_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f);
|
||||
static_cast<MetavoxelGuide*>(nextVisitation.info.attributeValues.last().getInlineValue<
|
||||
PolymorphicDataPointer>().data())->guide(nextVisitation);
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue ScriptedMetavoxelGuide::getAttributes(QScriptContext* context, QScriptEngine* engine) {
|
||||
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
|
||||
|
||||
const QVector<AttributePointer>& attributes = guide->_visitation->visitor.getAttributes();
|
||||
QScriptValue attributesValue = engine->newArray(attributes.size());
|
||||
for (int i = 0; i < attributes.size(); i++) {
|
||||
attributesValue.setProperty(i, engine->newQObject(attributes.at(i).data(), QScriptEngine::QtOwnership,
|
||||
QScriptEngine::PreferExistingWrapperObject));
|
||||
}
|
||||
|
||||
return attributesValue;
|
||||
}
|
||||
|
||||
QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngine* engine) {
|
||||
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
|
||||
|
||||
// start with the basics, including inherited attribute values
|
||||
QScriptValue infoValue = context->argument(0);
|
||||
QScriptValue minimum = infoValue.property(guide->_minimumHandle);
|
||||
MetavoxelInfo info = {
|
||||
glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()),
|
||||
infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.attributeValues,
|
||||
infoValue.property(guide->_isLeafHandle).toBool() };
|
||||
|
||||
// extract and convert the values provided by the script
|
||||
QScriptValue attributeValues = infoValue.property(guide->_attributeValuesHandle);
|
||||
const QVector<AttributePointer>& attributes = guide->_visitation->visitor.getAttributes();
|
||||
for (int i = 0; i < attributes.size(); i++) {
|
||||
QScriptValue attributeValue = attributeValues.property(i);
|
||||
if (attributeValue.isValid()) {
|
||||
info.attributeValues[i] = AttributeValue(attributes.at(i),
|
||||
attributes.at(i)->createFromScript(attributeValue, engine));
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue result = guide->_visitation->visitor.visit(info);
|
||||
|
||||
// destroy any created values
|
||||
for (int i = 0; i < attributes.size(); i++) {
|
||||
if (attributeValues.property(i).isValid()) {
|
||||
info.attributeValues[i].getAttribute()->destroy(info.attributeValues[i].getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ScriptedMetavoxelGuide::ScriptedMetavoxelGuide(const QScriptValue& guideFunction) :
|
||||
_guideFunction(guideFunction),
|
||||
_minimumHandle(guideFunction.engine()->toStringHandle("minimum")),
|
||||
_sizeHandle(guideFunction.engine()->toStringHandle("size")),
|
||||
_attributeValuesHandle(guideFunction.engine()->toStringHandle("attributeValues")),
|
||||
_isLeafHandle(guideFunction.engine()->toStringHandle("isLeaf")),
|
||||
_getAttributesFunction(guideFunction.engine()->newFunction(getAttributes, 0)),
|
||||
_visitFunction(guideFunction.engine()->newFunction(visit, 1)),
|
||||
_info(guideFunction.engine()->newObject()),
|
||||
_minimum(guideFunction.engine()->newArray(3)) {
|
||||
|
||||
_arguments.append(guideFunction.engine()->newObject());
|
||||
QScriptValue visitor = guideFunction.engine()->newObject();
|
||||
visitor.setProperty("getAttributes", _getAttributesFunction);
|
||||
visitor.setProperty("visit", _visitFunction);
|
||||
_arguments[0].setProperty("visitor", visitor);
|
||||
_arguments[0].setProperty("info", _info);
|
||||
_info.setProperty(_minimumHandle, _minimum);
|
||||
}
|
||||
|
||||
PolymorphicData* ScriptedMetavoxelGuide::clone() const {
|
||||
return new ScriptedMetavoxelGuide(_guideFunction);
|
||||
}
|
||||
|
||||
void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
||||
QScriptValue data = _guideFunction.engine()->newVariant(QVariant::fromValue<void*>(this));
|
||||
_getAttributesFunction.setData(data);
|
||||
_visitFunction.setData(data);
|
||||
_minimum.setProperty(0, visitation.info.minimum.x);
|
||||
_minimum.setProperty(1, visitation.info.minimum.y);
|
||||
_minimum.setProperty(2, visitation.info.minimum.z);
|
||||
_info.setProperty(_sizeHandle, visitation.info.size);
|
||||
_info.setProperty(_isLeafHandle, visitation.info.isLeaf);
|
||||
_visitation = &visitation;
|
||||
_guideFunction.call(QScriptValue(), _arguments);
|
||||
if (_guideFunction.engine()->hasUncaughtException()) {
|
||||
qDebug() << "Script error: " << _guideFunction.engine()->uncaughtException().toString() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool MetavoxelVisitation::allNodesLeaves() const {
|
||||
foreach (MetavoxelNode* node, nodes) {
|
||||
if (node != NULL && !node->isLeaf()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
187
libraries/metavoxels/src/MetavoxelData.h
Normal file
187
libraries/metavoxels/src/MetavoxelData.h
Normal file
|
@ -0,0 +1,187 @@
|
|||
//
|
||||
// MetavoxelData.h
|
||||
// metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/6/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__MetavoxelData__
|
||||
#define __interface__MetavoxelData__
|
||||
|
||||
#include <QBitArray>
|
||||
#include <QHash>
|
||||
#include <QScriptString>
|
||||
#include <QScriptValue>
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "AttributeRegistry.h"
|
||||
|
||||
class QScriptContext;
|
||||
|
||||
class MetavoxelNode;
|
||||
class MetavoxelPath;
|
||||
class MetavoxelVisitation;
|
||||
class MetavoxelVisitor;
|
||||
|
||||
/// The base metavoxel representation shared between server and client.
|
||||
class MetavoxelData {
|
||||
public:
|
||||
|
||||
~MetavoxelData();
|
||||
|
||||
/// Applies the specified visitor to the contained voxels.
|
||||
void guide(MetavoxelVisitor& visitor);
|
||||
|
||||
/// Sets the attribute value corresponding to the specified path.
|
||||
void setAttributeValue(const MetavoxelPath& path, const AttributeValue& attributeValue);
|
||||
|
||||
/// Retrieves the attribute value corresponding to the specified path.
|
||||
AttributeValue getAttributeValue(const MetavoxelPath& path, const AttributePointer& attribute) const;
|
||||
|
||||
private:
|
||||
|
||||
QHash<AttributePointer, MetavoxelNode*> _roots;
|
||||
};
|
||||
|
||||
/// A single node within a metavoxel layer.
|
||||
class MetavoxelNode {
|
||||
public:
|
||||
|
||||
static const int CHILD_COUNT = 8;
|
||||
|
||||
MetavoxelNode(const AttributeValue& attributeValue);
|
||||
|
||||
/// Descends the voxel tree in order to set the value of a node.
|
||||
/// \param path the path to follow
|
||||
/// \param index the position in the path
|
||||
/// \return whether or not the node is entirely equal to the value
|
||||
bool setAttributeValue(const MetavoxelPath& path, int index, const AttributeValue& attributeValue);
|
||||
|
||||
void setAttributeValue(const AttributeValue& attributeValue);
|
||||
|
||||
AttributeValue getAttributeValue(const AttributePointer& attribute) const;
|
||||
|
||||
MetavoxelNode* getChild(int index) const { return _children[index]; }
|
||||
void setChild(int index, MetavoxelNode* child) { _children[index] = child; }
|
||||
|
||||
bool isLeaf() const;
|
||||
|
||||
void destroy(const AttributePointer& attribute);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(MetavoxelNode)
|
||||
|
||||
void clearChildren(const AttributePointer& attribute);
|
||||
|
||||
void* _attributeValue;
|
||||
MetavoxelNode* _children[CHILD_COUNT];
|
||||
};
|
||||
|
||||
/// A path down an octree.
|
||||
class MetavoxelPath {
|
||||
public:
|
||||
|
||||
int getSize() const { return _array.size() / BITS_PER_ELEMENT; }
|
||||
bool isEmpty() const { return _array.isEmpty(); }
|
||||
|
||||
int operator[](int index) const;
|
||||
|
||||
MetavoxelPath& operator+=(int element);
|
||||
|
||||
private:
|
||||
|
||||
static const int BITS_PER_ELEMENT = 3;
|
||||
|
||||
QBitArray _array;
|
||||
};
|
||||
|
||||
/// Contains information about a metavoxel (explicit or procedural).
|
||||
class MetavoxelInfo {
|
||||
public:
|
||||
|
||||
glm::vec3 minimum; ///< the minimum extent of the area covered by the voxel
|
||||
float size; ///< the size of the voxel in all dimensions
|
||||
QVector<AttributeValue> attributeValues;
|
||||
bool isLeaf;
|
||||
};
|
||||
|
||||
/// Interface for visitors to metavoxels.
|
||||
class MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
MetavoxelVisitor(const QVector<AttributePointer>& attributes) : _attributes(attributes) { }
|
||||
|
||||
/// Returns a reference to the list of attributes desired.
|
||||
const QVector<AttributePointer>& getAttributes() const { return _attributes; }
|
||||
|
||||
/// Visits a metavoxel.
|
||||
/// \param info the metavoxel ata
|
||||
/// \param if true, continue descending; if false, stop
|
||||
virtual bool visit(const MetavoxelInfo& info) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
QVector<AttributePointer> _attributes;
|
||||
};
|
||||
|
||||
/// Interface for objects that guide metavoxel visitors.
|
||||
class MetavoxelGuide : public PolymorphicData {
|
||||
public:
|
||||
|
||||
/// Guides the specified visitor to the contained voxels.
|
||||
virtual void guide(MetavoxelVisitation& visitation) = 0;
|
||||
};
|
||||
|
||||
/// Guides visitors through the explicit content of the system.
|
||||
class DefaultMetavoxelGuide : public MetavoxelGuide {
|
||||
public:
|
||||
|
||||
virtual PolymorphicData* clone() const;
|
||||
|
||||
virtual void guide(MetavoxelVisitation& visitation);
|
||||
};
|
||||
|
||||
/// Represents a guide implemented in Javascript.
|
||||
class ScriptedMetavoxelGuide : public MetavoxelGuide {
|
||||
public:
|
||||
|
||||
ScriptedMetavoxelGuide(const QScriptValue& guideFunction);
|
||||
|
||||
virtual PolymorphicData* clone() const;
|
||||
|
||||
virtual void guide(MetavoxelVisitation& visitation);
|
||||
|
||||
private:
|
||||
|
||||
static QScriptValue getAttributes(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue visit(QScriptContext* context, QScriptEngine* engine);
|
||||
|
||||
QScriptValue _guideFunction;
|
||||
QScriptString _minimumHandle;
|
||||
QScriptString _sizeHandle;
|
||||
QScriptString _attributeValuesHandle;
|
||||
QScriptString _isLeafHandle;
|
||||
QScriptValueList _arguments;
|
||||
QScriptValue _getAttributesFunction;
|
||||
QScriptValue _visitFunction;
|
||||
QScriptValue _info;
|
||||
QScriptValue _minimum;
|
||||
|
||||
MetavoxelVisitation* _visitation;
|
||||
};
|
||||
|
||||
/// Contains the state associated with a visit to a metavoxel system.
|
||||
class MetavoxelVisitation {
|
||||
public:
|
||||
|
||||
MetavoxelVisitor& visitor;
|
||||
QVector<MetavoxelNode*> nodes;
|
||||
MetavoxelInfo info;
|
||||
|
||||
bool allNodesLeaves() const;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__MetavoxelData__) */
|
Loading…
Reference in a new issue