mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 08:04:01 +02:00
Merge pull request #1627 from ey6es/metavoxels
Basic metavoxel editing interface (doesn't actually perform any edits yet).
This commit is contained in:
commit
6120416cbb
16 changed files with 955 additions and 250 deletions
|
@ -35,11 +35,11 @@ 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;
|
||||
info.inputValues[normalIndex] = 0x007F00;
|
||||
|
||||
} else {
|
||||
var scale = 127.0 / length;
|
||||
info.attributeValues[normalIndex] =
|
||||
info.inputValues[normalIndex] =
|
||||
(Math.floor(vector[0] * scale) & 0xFF) << 16 |
|
||||
(Math.floor(vector[1] * scale) & 0xFF) << 8 |
|
||||
Math.floor(vector[2] * scale) & 0xFF;
|
||||
|
@ -61,7 +61,7 @@ function guide(minimum, size, depth) {
|
|||
maximum[2] <= sphereCenter[2] - sphereRadius) {
|
||||
info.isLeaf = true;
|
||||
if (colorIndex != -1) {
|
||||
info.attributeValues[colorIndex] = 0x0;
|
||||
info.inputValues[colorIndex] = 0x0;
|
||||
}
|
||||
visitor.visit(info);
|
||||
return;
|
||||
|
@ -110,7 +110,7 @@ function guide(minimum, size, depth) {
|
|||
if (inside == 8) {
|
||||
info.isLeaf = true;
|
||||
if (colorIndex != -1) {
|
||||
info.attributeValues[colorIndex] = sphereColor;
|
||||
info.inputValues[colorIndex] = sphereColor;
|
||||
}
|
||||
setNormal(vector);
|
||||
visitor.visit(info);
|
||||
|
@ -122,13 +122,13 @@ function guide(minimum, size, depth) {
|
|||
info.isLeaf = true;
|
||||
if (inside >= 3) {
|
||||
if (colorIndex != -1) {
|
||||
info.attributeValues[colorIndex] = sphereColor;
|
||||
info.inputValues[colorIndex] = sphereColor;
|
||||
}
|
||||
setNormal(vector);
|
||||
|
||||
} else {
|
||||
if (colorIndex != -1) {
|
||||
info.attributeValues[colorIndex] = 0x0;
|
||||
info.inputValues[colorIndex] = 0x0;
|
||||
}
|
||||
}
|
||||
visitor.visit(info);
|
||||
|
@ -152,11 +152,11 @@ function guide(minimum, size, depth) {
|
|||
}
|
||||
|
||||
(function(visitation) {
|
||||
var attributes = visitation.visitor.getAttributes();
|
||||
colorIndex = strictIndexOf(attributes, AttributeRegistry.colorAttribute);
|
||||
normalIndex = strictIndexOf(attributes, AttributeRegistry.normalAttribute);
|
||||
var inputs = visitation.visitor.getInputs();
|
||||
colorIndex = strictIndexOf(inputs, AttributeRegistry.colorAttribute);
|
||||
normalIndex = strictIndexOf(inputs, AttributeRegistry.normalAttribute);
|
||||
visitor = visitation.visitor;
|
||||
info = { attributeValues: new Array(attributes.length) };
|
||||
info = { inputValues: new Array(inputs.length) };
|
||||
|
||||
// have the sphere orbit the center and pulse in size
|
||||
var time = new Date().getTime();
|
||||
|
|
15
interface/resources/shaders/grid.frag
Normal file
15
interface/resources/shaders/grid.frag
Normal file
|
@ -0,0 +1,15 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// grid.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 1/21/14.
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
void main(void) {
|
||||
// use the standard exponential fog calculation
|
||||
const float FOG_DENSITY = 0.5;
|
||||
gl_FragColor = vec4(gl_Color.rgb, exp(-FOG_DENSITY / gl_FragCoord.w));
|
||||
}
|
|
@ -1152,13 +1152,12 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
|||
_seenMouseMove = true;
|
||||
}
|
||||
|
||||
int deltaX = event->x() - _mouseX;
|
||||
int deltaY = event->y() - _mouseY;
|
||||
_mouseX = event->x();
|
||||
_mouseY = event->y();
|
||||
|
||||
if (activeWindow() == _window) {
|
||||
int deltaX = event->x() - _mouseX;
|
||||
int deltaY = event->y() - _mouseY;
|
||||
|
||||
_mouseX = event->x();
|
||||
_mouseY = event->y();
|
||||
|
||||
// orbit behavior
|
||||
if (_mousePressed && !Menu::getInstance()->isVoxelModeActionChecked()) {
|
||||
if (_lookatTargetAvatar) {
|
||||
|
@ -1849,25 +1848,23 @@ const float HEAD_SPHERE_RADIUS = 0.07f;
|
|||
|
||||
static QUuid DEFAULT_NODE_ID_REF;
|
||||
|
||||
void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||
glm::vec3& eyePosition) {
|
||||
void Application::updateLookatTargetAvatar(glm::vec3& eyePosition) {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()");
|
||||
|
||||
if (!_mousePressed) {
|
||||
_lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF);
|
||||
_lookatTargetAvatar = findLookatTargetAvatar(eyePosition, DEFAULT_NODE_ID_REF);
|
||||
}
|
||||
}
|
||||
|
||||
Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||
glm::vec3& eyePosition, QUuid& nodeUUID = DEFAULT_NODE_ID_REF) {
|
||||
Avatar* Application::findLookatTargetAvatar(glm::vec3& eyePosition, QUuid& nodeUUID = DEFAULT_NODE_ID_REF) {
|
||||
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
|
||||
Avatar* avatar = (Avatar*)node->getLinkedData();
|
||||
float distance;
|
||||
|
||||
if (avatar->findRayIntersection(mouseRayOrigin, mouseRayDirection, distance)) {
|
||||
if (avatar->findRayIntersection(_mouseRayOrigin, _mouseRayDirection, distance)) {
|
||||
// rescale to compensate for head embiggening
|
||||
eyePosition = (avatar->getHead().calculateAverageEyePosition() - avatar->getHead().getScalePivot()) *
|
||||
(avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot();
|
||||
|
@ -1918,7 +1915,7 @@ void Application::renderHighlightVoxel(VoxelDetail voxel) {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection) {
|
||||
void Application::updateAvatars(float deltaTime) {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateAvatars()");
|
||||
|
||||
|
@ -1930,7 +1927,7 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::
|
|||
avatar->init();
|
||||
}
|
||||
avatar->simulate(deltaTime, NULL);
|
||||
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
|
||||
avatar->setMouseRay(_mouseRayOrigin, _mouseRayDirection);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1953,28 +1950,28 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::
|
|||
}
|
||||
}
|
||||
|
||||
void Application::updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection) {
|
||||
void Application::updateMouseRay() {
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMouseRay()");
|
||||
|
||||
_viewFrustum.computePickRay(_mouseX / (float)_glWidget->width(), _mouseY / (float)_glWidget->height(),
|
||||
mouseRayOrigin, mouseRayDirection);
|
||||
_mouseRayOrigin, _mouseRayDirection);
|
||||
|
||||
// adjust for mirroring
|
||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
glm::vec3 mouseRayOffset = mouseRayOrigin - _viewFrustum.getPosition();
|
||||
mouseRayOrigin -= 2.0f * (_viewFrustum.getDirection() * glm::dot(_viewFrustum.getDirection(), mouseRayOffset) +
|
||||
glm::vec3 mouseRayOffset = _mouseRayOrigin - _viewFrustum.getPosition();
|
||||
_mouseRayOrigin -= 2.0f * (_viewFrustum.getDirection() * glm::dot(_viewFrustum.getDirection(), mouseRayOffset) +
|
||||
_viewFrustum.getRight() * glm::dot(_viewFrustum.getRight(), mouseRayOffset));
|
||||
mouseRayDirection -= 2.0f * (_viewFrustum.getDirection() * glm::dot(_viewFrustum.getDirection(), mouseRayDirection) +
|
||||
_viewFrustum.getRight() * glm::dot(_viewFrustum.getRight(), mouseRayDirection));
|
||||
_mouseRayDirection -= 2.0f * (_viewFrustum.getDirection() * glm::dot(_viewFrustum.getDirection(), _mouseRayDirection) +
|
||||
_viewFrustum.getRight() * glm::dot(_viewFrustum.getRight(), _mouseRayDirection));
|
||||
}
|
||||
|
||||
// tell my avatar if the mouse is being pressed...
|
||||
_myAvatar.setMousePressed(_mousePressed);
|
||||
|
||||
// tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position
|
||||
_myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection);
|
||||
_myAvatar.setMouseRay(_mouseRayOrigin, _mouseRayDirection);
|
||||
}
|
||||
|
||||
void Application::updateFaceshift() {
|
||||
|
@ -1991,8 +1988,7 @@ void Application::updateFaceshift() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin,
|
||||
glm::vec3& lookAtRayDirection) {
|
||||
void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot) {
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()");
|
||||
|
@ -2009,7 +2005,7 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3&
|
|||
|
||||
} else {
|
||||
// just look in direction of the mouse ray
|
||||
lookAtSpot = lookAtRayOrigin + lookAtRayDirection * FAR_AWAY_STARE;
|
||||
lookAtSpot = _mouseRayOrigin + _mouseRayDirection * FAR_AWAY_STARE;
|
||||
}
|
||||
if (_faceshift.isActive()) {
|
||||
// deflect using Faceshift gaze data
|
||||
|
@ -2023,8 +2019,7 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3&
|
|||
_myAvatar.getHead().setLookAtPosition(lookAtSpot);
|
||||
}
|
||||
|
||||
void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||
float& distance, BoxFace& face) {
|
||||
void Application::updateHoverVoxels(float deltaTime, float& distance, BoxFace& face) {
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels()");
|
||||
|
@ -2055,7 +2050,7 @@ void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin,
|
|||
if (!(_voxels.treeIsBusy() || _mousePressed)) {
|
||||
{
|
||||
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
|
||||
_isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face);
|
||||
_isHoverVoxel = _voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _hoverVoxel, distance, face);
|
||||
}
|
||||
if (MAKE_SOUND_ON_VOXEL_HOVER && _isHoverVoxel &&
|
||||
glm::vec4(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s) != oldVoxel) {
|
||||
|
@ -2071,8 +2066,7 @@ void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin,
|
|||
}
|
||||
}
|
||||
|
||||
void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||
float& distance, BoxFace& face) {
|
||||
void Application::updateMouseVoxels(float deltaTime, float& distance, BoxFace& face) {
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMouseVoxels()");
|
||||
|
@ -2084,7 +2078,7 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin,
|
|||
fabs(_myAvatar.getVelocity().y) +
|
||||
fabs(_myAvatar.getVelocity().z)) / 3 < MAX_AVATAR_EDIT_VELOCITY) {
|
||||
|
||||
if (_voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _mouseVoxel, distance, face)) {
|
||||
if (_voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _mouseVoxel, distance, face)) {
|
||||
if (distance < MAX_VOXEL_EDIT_DISTANCE) {
|
||||
// set the voxel scale to that of the first moused-over voxel
|
||||
if (!wasInitialized) {
|
||||
|
@ -2104,7 +2098,7 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin,
|
|||
glm::vec3 faceVector = getFaceVector(face);
|
||||
if (_mouseVoxelScale < _mouseVoxel.s) {
|
||||
// find the closest contained voxel
|
||||
glm::vec3 pt = (mouseRayOrigin + mouseRayDirection * distance) / (float)TREE_SCALE -
|
||||
glm::vec3 pt = (_mouseRayOrigin + _mouseRayDirection * distance) / (float)TREE_SCALE -
|
||||
faceVector * (_mouseVoxelScale * 0.5f);
|
||||
_mouseVoxel.x = _mouseVoxelScale * floorf(pt.x / _mouseVoxelScale);
|
||||
_mouseVoxel.y = _mouseVoxelScale * floorf(pt.y / _mouseVoxelScale);
|
||||
|
@ -2125,7 +2119,7 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin,
|
|||
|| Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode)) {
|
||||
// place the voxel a fixed distance away
|
||||
float worldMouseVoxelScale = _mouseVoxelScale * TREE_SCALE;
|
||||
glm::vec3 pt = mouseRayOrigin + mouseRayDirection * (2.0f + worldMouseVoxelScale * 0.5f);
|
||||
glm::vec3 pt = _mouseRayOrigin + _mouseRayDirection * (2.0f + worldMouseVoxelScale * 0.5f);
|
||||
_mouseVoxel.x = _mouseVoxelScale * floorf(pt.x / worldMouseVoxelScale);
|
||||
_mouseVoxel.y = _mouseVoxelScale * floorf(pt.y / worldMouseVoxelScale);
|
||||
_mouseVoxel.z = _mouseVoxelScale * floorf(pt.z / worldMouseVoxelScale);
|
||||
|
@ -2359,29 +2353,28 @@ void Application::update(float deltaTime) {
|
|||
PerformanceWarning warn(showWarnings, "Application::update()");
|
||||
|
||||
// check what's under the mouse and update the mouse voxel
|
||||
glm::vec3 mouseRayOrigin, mouseRayDirection;
|
||||
updateMouseRay(deltaTime, mouseRayOrigin, mouseRayDirection);
|
||||
updateMouseRay();
|
||||
|
||||
// Set where I am looking based on my mouse ray (so that other people can see)
|
||||
glm::vec3 lookAtSpot;
|
||||
|
||||
updateFaceshift();
|
||||
updateLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot);
|
||||
updateMyAvatarLookAtPosition(lookAtSpot, mouseRayOrigin, mouseRayDirection);
|
||||
updateLookatTargetAvatar(lookAtSpot);
|
||||
updateMyAvatarLookAtPosition(lookAtSpot);
|
||||
|
||||
// Find the voxel we are hovering over, and respond if clicked
|
||||
float distance;
|
||||
BoxFace face;
|
||||
|
||||
updateHoverVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // clicking on voxels and making sounds
|
||||
updateMouseVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // UI/UX related to voxels
|
||||
updateHoverVoxels(deltaTime, distance, face); // clicking on voxels and making sounds
|
||||
updateMouseVoxels(deltaTime, distance, face); // UI/UX related to voxels
|
||||
updateHandAndTouch(deltaTime); // Update state for touch sensors
|
||||
updateLeap(deltaTime); // Leap finger-sensing device
|
||||
updateSixense(deltaTime); // Razer Hydra controllers
|
||||
updateSerialDevices(deltaTime); // Read serial port interface devices
|
||||
updateAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
|
||||
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||
updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); //loop through all the other avatars and simulate them...
|
||||
updateAvatars(deltaTime); //loop through all the other avatars and simulate them...
|
||||
updateMyAvatarSimulation(deltaTime); // Simulate myself
|
||||
updateParticles(deltaTime); // Simulate particle cloud movements
|
||||
updateMetavoxels(deltaTime); // update metavoxels
|
||||
|
@ -3030,6 +3023,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
// give external parties a change to hook in
|
||||
emit renderingInWorldInterface();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -147,10 +147,13 @@ public:
|
|||
ViewFrustum* getViewFrustum() { return &_viewFrustum; }
|
||||
VoxelSystem* getVoxels() { return &_voxels; }
|
||||
ParticleTreeRenderer* getParticles() { return &_particles; }
|
||||
MetavoxelSystem* getMetavoxels() { return &_metavoxels; }
|
||||
VoxelSystem* getSharedVoxelSystem() { return &_sharedVoxelSystem; }
|
||||
VoxelTree* getClipboard() { return &_clipboard; }
|
||||
Environment* getEnvironment() { return &_environment; }
|
||||
bool isMouseHidden() const { return _mouseHidden; }
|
||||
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
||||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||
Faceshift* getFaceshift() { return &_faceshift; }
|
||||
SixenseManager* getSixenseManager() { return &_sixenseManager; }
|
||||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||
|
@ -203,6 +206,11 @@ public:
|
|||
|
||||
void skipVersion(QString latestVersion);
|
||||
|
||||
signals:
|
||||
|
||||
/// Fired when we're rendering in-world interface elements; allows external parties to hook in.
|
||||
void renderingInWorldInterface();
|
||||
|
||||
public slots:
|
||||
void domainChanged(const QString& domainHostname);
|
||||
void nodeKilled(SharedNodePointer node);
|
||||
|
@ -266,15 +274,12 @@ private:
|
|||
void update(float deltaTime);
|
||||
|
||||
// Various helper functions called during update()
|
||||
void updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection);
|
||||
void updateMouseRay();
|
||||
void updateFaceshift();
|
||||
void updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection);
|
||||
void updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||
float& distance, BoxFace& face);
|
||||
void updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||
float& distance, BoxFace& face);
|
||||
void updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||
glm::vec3& eyePosition);
|
||||
void updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot);
|
||||
void updateHoverVoxels(float deltaTime, float& distance, BoxFace& face);
|
||||
void updateMouseVoxels(float deltaTime, float& distance, BoxFace& face);
|
||||
void updateLookatTargetAvatar(glm::vec3& eyePosition);
|
||||
void updateHandAndTouch(float deltaTime);
|
||||
void updateLeap(float deltaTime);
|
||||
void updateSixense(float deltaTime);
|
||||
|
@ -289,15 +294,14 @@ private:
|
|||
void updateAudio(float deltaTime);
|
||||
void updateCursor(float deltaTime);
|
||||
|
||||
Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||
glm::vec3& eyePosition, QUuid &nodeUUID);
|
||||
Avatar* findLookatTargetAvatar(glm::vec3& eyePosition, QUuid &nodeUUID);
|
||||
bool isLookingAtMyAvatar(Avatar* avatar);
|
||||
|
||||
void renderLookatIndicator(glm::vec3 pointOfInterest);
|
||||
void renderHighlightVoxel(VoxelDetail voxel);
|
||||
|
||||
void updateAvatar(float deltaTime);
|
||||
void updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection);
|
||||
void updateAvatars(float deltaTime);
|
||||
void queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, NodeToJurisdictionMap& jurisdictions);
|
||||
void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
|
||||
|
||||
|
@ -402,6 +406,9 @@ private:
|
|||
bool _mouseHidden;
|
||||
bool _seenMouseMove;
|
||||
|
||||
glm::vec3 _mouseRayOrigin;
|
||||
glm::vec3 _mouseRayDirection;
|
||||
|
||||
float _touchAvgX;
|
||||
float _touchAvgY;
|
||||
float _lastTouchAvgX;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "Menu.h"
|
||||
#include "Util.h"
|
||||
#include "InfoView.h"
|
||||
#include "ui/MetavoxelEditor.h"
|
||||
|
||||
Menu* Menu::_instance = NULL;
|
||||
|
||||
|
@ -220,6 +221,8 @@ Menu::Menu() :
|
|||
SLOT(increaseVoxelSize()));
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::ResetSwatchColors, 0, this, SLOT(resetSwatchColors()));
|
||||
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0, this, SLOT(showMetavoxelEditor()));
|
||||
|
||||
|
||||
QMenu* viewMenu = addMenu("View");
|
||||
|
||||
|
@ -1010,6 +1013,13 @@ void Menu::bandwidthDetails() {
|
|||
_bandwidthDialog->raise();
|
||||
}
|
||||
|
||||
void Menu::showMetavoxelEditor() {
|
||||
if (!_MetavoxelEditor) {
|
||||
_MetavoxelEditor = new MetavoxelEditor();
|
||||
}
|
||||
_MetavoxelEditor->raise();
|
||||
}
|
||||
|
||||
void Menu::audioMuteToggled() {
|
||||
QAction *muteAction = _actionHash.value(MenuOption::MuteAudio);
|
||||
muteAction->setChecked(Application::getInstance()->getAudio()->getMuted());
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <QMenuBar>
|
||||
#include <QHash>
|
||||
#include <QKeySequence>
|
||||
#include <QPointer>
|
||||
|
||||
#include <AbstractMenuInterface.h>
|
||||
|
||||
|
@ -36,8 +37,9 @@ struct ViewFrustumOffset {
|
|||
class QSettings;
|
||||
|
||||
class BandwidthDialog;
|
||||
class VoxelStatsDialog;
|
||||
class LodToolsDialog;
|
||||
class MetavoxelEditor;
|
||||
class VoxelStatsDialog;
|
||||
|
||||
class Menu : public QMenuBar, public AbstractMenuInterface {
|
||||
Q_OBJECT
|
||||
|
@ -107,6 +109,7 @@ private slots:
|
|||
void chooseVoxelPaintColor();
|
||||
void runTests();
|
||||
void resetSwatchColors();
|
||||
void showMetavoxelEditor();
|
||||
void audioMuteToggled();
|
||||
|
||||
private:
|
||||
|
@ -140,6 +143,7 @@ private:
|
|||
FrustumDrawMode _frustumDrawMode;
|
||||
ViewFrustumOffset _viewFrustumOffset;
|
||||
QActionGroup* _voxelModeActionsGroup;
|
||||
QPointer<MetavoxelEditor> _MetavoxelEditor;
|
||||
VoxelStatsDialog* _voxelStatsDialog;
|
||||
LodToolsDialog* _lodToolsDialog;
|
||||
int _maxVoxels;
|
||||
|
@ -219,6 +223,7 @@ namespace MenuOption {
|
|||
const QString Login = "Login";
|
||||
const QString LookAtIndicator = "Look-at Indicator";
|
||||
const QString LookAtVectors = "Look-at Vectors";
|
||||
const QString MetavoxelEditor = "Metavoxel Editor...";
|
||||
const QString Metavoxels = "Metavoxels";
|
||||
const QString Mirror = "Mirror";
|
||||
const QString MoveWithLean = "Move with Lean";
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QtDebug>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
@ -40,14 +38,6 @@ void MetavoxelSystem::init() {
|
|||
connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
|
||||
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer)));
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -156,16 +146,17 @@ void MetavoxelSystem::receivedData(const QByteArray& data, const HifiSockAddr& s
|
|||
MetavoxelSystem::PointVisitor::PointVisitor(QVector<Point>& points) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() <<
|
||||
AttributeRegistry::getInstance()->getColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getNormalAttribute()),
|
||||
AttributeRegistry::getInstance()->getNormalAttribute(),
|
||||
QVector<AttributePointer>()),
|
||||
_points(points) {
|
||||
}
|
||||
|
||||
bool MetavoxelSystem::PointVisitor::visit(const MetavoxelInfo& info) {
|
||||
bool MetavoxelSystem::PointVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.isLeaf) {
|
||||
return true;
|
||||
}
|
||||
QRgb color = info.attributeValues.at(0).getInlineValue<QRgb>();
|
||||
QRgb normal = info.attributeValues.at(1).getInlineValue<QRgb>();
|
||||
QRgb color = info.inputValues.at(0).getInlineValue<QRgb>();
|
||||
QRgb normal = info.inputValues.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),
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include <QList>
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QScriptEngine>
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -30,18 +29,23 @@ class MetavoxelSystem : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelSystem();
|
||||
|
||||
void init();
|
||||
|
||||
MetavoxelData& getData() { return _data; }
|
||||
|
||||
void processData(const QByteArray& data, const HifiSockAddr& sender);
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
public slots:
|
||||
|
||||
void nodeAdded(SharedNodePointer node);
|
||||
void nodeKilled(SharedNodePointer node);
|
||||
|
||||
private:
|
||||
|
||||
Q_INVOKABLE void addClient(const QUuid& uuid, const HifiSockAddr& address);
|
||||
|
@ -58,7 +62,7 @@ private:
|
|||
class PointVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
PointVisitor(QVector<Point>& points);
|
||||
virtual bool visit(const MetavoxelInfo& info);
|
||||
virtual bool visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
QVector<Point>& _points;
|
||||
|
@ -67,7 +71,6 @@ private:
|
|||
static ProgramObject _program;
|
||||
static int _pointScaleLocation;
|
||||
|
||||
QScriptEngine _scriptEngine;
|
||||
MetavoxelData _data;
|
||||
QVector<Point> _points;
|
||||
PointVisitor _pointVisitor;
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
|
||||
#include <cmath>
|
||||
|
||||
// include this before QOpenGLBuffer, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QOpenGLBuffer>
|
||||
|
||||
#include "Application.h"
|
||||
#include "GeometryCache.h"
|
||||
|
@ -241,6 +245,50 @@ void GeometryCache::renderHalfCylinder(int slices, int stacks) {
|
|||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void GeometryCache::renderGrid(int xDivisions, int yDivisions) {
|
||||
QOpenGLBuffer& buffer = _gridBuffers[IntPair(xDivisions, yDivisions)];
|
||||
int vertices = (xDivisions + 1 + yDivisions + 1) * 2;
|
||||
if (!buffer.isCreated()) {
|
||||
GLfloat* vertexData = new GLfloat[vertices * 2];
|
||||
GLfloat* vertex = vertexData;
|
||||
for (int i = 0; i <= xDivisions; i++) {
|
||||
float x = (float)i / xDivisions;
|
||||
|
||||
*(vertex++) = x;
|
||||
*(vertex++) = 0.0f;
|
||||
|
||||
*(vertex++) = x;
|
||||
*(vertex++) = 1.0f;
|
||||
}
|
||||
for (int i = 0; i <= yDivisions; i++) {
|
||||
float y = (float)i / yDivisions;
|
||||
|
||||
*(vertex++) = 0.0f;
|
||||
*(vertex++) = y;
|
||||
|
||||
*(vertex++) = 1.0f;
|
||||
*(vertex++) = y;
|
||||
}
|
||||
buffer.create();
|
||||
buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
buffer.bind();
|
||||
buffer.allocate(vertexData, vertices * 2 * sizeof(GLfloat));
|
||||
delete[] vertexData;
|
||||
|
||||
} else {
|
||||
buffer.bind();
|
||||
}
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glVertexPointer(2, GL_FLOAT, 0, 0);
|
||||
|
||||
glDrawArrays(GL_LINES, 0, vertices);
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
buffer.release();
|
||||
}
|
||||
|
||||
QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url) {
|
||||
QSharedPointer<NetworkGeometry> geometry = _networkGeometry.value(url);
|
||||
if (geometry.isNull()) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "InterfaceConfig.h"
|
||||
|
||||
class QNetworkReply;
|
||||
class QOpenGLBuffer;
|
||||
|
||||
class NetworkGeometry;
|
||||
class NetworkMesh;
|
||||
|
@ -33,6 +34,7 @@ public:
|
|||
void renderHemisphere(int slices, int stacks);
|
||||
void renderSquare(int xDivisions, int yDivisions);
|
||||
void renderHalfCylinder(int slices, int stacks);
|
||||
void renderGrid(int xDivisions, int yDivisions);
|
||||
|
||||
/// Loads geometry from the specified URL.
|
||||
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url);
|
||||
|
@ -45,6 +47,7 @@ private:
|
|||
QHash<IntPair, VerticesIndices> _hemisphereVBOs;
|
||||
QHash<IntPair, VerticesIndices> _squareVBOs;
|
||||
QHash<IntPair, VerticesIndices> _halfCylinderVBOs;
|
||||
QHash<IntPair, QOpenGLBuffer> _gridBuffers;
|
||||
|
||||
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
|
||||
};
|
||||
|
|
405
interface/src/ui/MetavoxelEditor.cpp
Normal file
405
interface/src/ui/MetavoxelEditor.cpp
Normal file
|
@ -0,0 +1,405 @@
|
|||
//
|
||||
// MetavoxelEditor.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 1/21/14.
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QMetaProperty>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <AttributeRegistry.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MetavoxelEditor.h"
|
||||
|
||||
enum GridPlane {
|
||||
GRID_PLANE_XY, GRID_PLANE_XZ, GRID_PLANE_YZ
|
||||
};
|
||||
|
||||
const glm::vec2 INVALID_VECTOR(FLT_MAX, FLT_MAX);
|
||||
|
||||
MetavoxelEditor::MetavoxelEditor() :
|
||||
QDialog(Application::getInstance()->getGLWidget()) {
|
||||
|
||||
setWindowTitle("Metavoxel Editor");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QVBoxLayout* topLayout = new QVBoxLayout();
|
||||
setLayout(topLayout);
|
||||
|
||||
QGroupBox* attributeGroup = new QGroupBox();
|
||||
attributeGroup->setTitle("Attributes");
|
||||
topLayout->addWidget(attributeGroup);
|
||||
|
||||
QVBoxLayout* attributeLayout = new QVBoxLayout();
|
||||
attributeGroup->setLayout(attributeLayout);
|
||||
|
||||
attributeLayout->addWidget(_attributes = new QListWidget());
|
||||
connect(_attributes, SIGNAL(itemSelectionChanged()), SLOT(updateValueEditor()));
|
||||
|
||||
QPushButton* newAttribute = new QPushButton("New...");
|
||||
attributeLayout->addWidget(newAttribute);
|
||||
connect(newAttribute, SIGNAL(clicked()), SLOT(createNewAttribute()));
|
||||
|
||||
QFormLayout* formLayout = new QFormLayout();
|
||||
topLayout->addLayout(formLayout);
|
||||
|
||||
formLayout->addRow("Grid Plane:", _gridPlane = new QComboBox());
|
||||
_gridPlane->addItem("X/Y");
|
||||
_gridPlane->addItem("X/Z");
|
||||
_gridPlane->addItem("Y/Z");
|
||||
_gridPlane->setCurrentIndex(GRID_PLANE_XZ);
|
||||
|
||||
formLayout->addRow("Grid Spacing:", _gridSpacing = new QDoubleSpinBox());
|
||||
_gridSpacing->setValue(0.1);
|
||||
_gridSpacing->setMaximum(FLT_MAX);
|
||||
_gridSpacing->setSingleStep(0.01);
|
||||
connect(_gridSpacing, SIGNAL(valueChanged(double)), SLOT(updateGridPosition()));
|
||||
|
||||
formLayout->addRow("Grid Position:", _gridPosition = new QDoubleSpinBox());
|
||||
_gridPosition->setSingleStep(0.1);
|
||||
_gridPosition->setMinimum(-FLT_MAX);
|
||||
_gridPosition->setMaximum(FLT_MAX);
|
||||
|
||||
_value = new QGroupBox();
|
||||
_value->setTitle("Value");
|
||||
topLayout->addWidget(_value);
|
||||
|
||||
QVBoxLayout* valueLayout = new QVBoxLayout();
|
||||
_value->setLayout(valueLayout);
|
||||
|
||||
updateAttributes();
|
||||
|
||||
connect(Application::getInstance(), SIGNAL(renderingInWorldInterface()), SLOT(render()));
|
||||
|
||||
Application::getInstance()->getGLWidget()->installEventFilter(this);
|
||||
|
||||
resetState();
|
||||
|
||||
show();
|
||||
|
||||
if (_gridProgram.isLinked()) {
|
||||
return;
|
||||
}
|
||||
switchToResourcesParentIfRequired();
|
||||
_gridProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/grid.frag");
|
||||
_gridProgram.link();
|
||||
}
|
||||
|
||||
bool MetavoxelEditor::eventFilter(QObject* watched, QEvent* event) {
|
||||
switch (_state) {
|
||||
case HOVERING_STATE:
|
||||
if (event->type() == QEvent::MouseButtonPress && _startPosition != INVALID_VECTOR) {
|
||||
_state = DRAGGING_STATE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case DRAGGING_STATE:
|
||||
if (event->type() == QEvent::MouseButtonRelease) {
|
||||
_state = RAISING_STATE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case RAISING_STATE:
|
||||
if (event->type() == QEvent::MouseButtonPress) {
|
||||
if (_height != 0) {
|
||||
// find the start and end corners in X/Y
|
||||
float base = _gridPosition->value();
|
||||
float top = base + _height;
|
||||
glm::quat rotation = getGridRotation();
|
||||
glm::vec3 start = rotation * glm::vec3(glm::min(_startPosition, _endPosition), glm::min(base, top));
|
||||
float spacing = _gridSpacing->value();
|
||||
glm::vec3 end = rotation * glm::vec3(glm::max(_startPosition, _endPosition) +
|
||||
glm::vec2(spacing, spacing), glm::max(base, top));
|
||||
|
||||
// find the minimum and maximum extents after rotation
|
||||
applyValue(glm::min(start, end), glm::max(start, end));
|
||||
}
|
||||
resetState();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MetavoxelEditor::updateValueEditor() {
|
||||
QString selected = getSelectedAttribute();
|
||||
if (selected.isNull()) {
|
||||
_value->setVisible(false);
|
||||
return;
|
||||
}
|
||||
_value->setVisible(true);
|
||||
|
||||
if (!_value->layout()->isEmpty()) {
|
||||
delete _value->layout()->takeAt(0);
|
||||
}
|
||||
|
||||
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(selected);
|
||||
QWidget* editor = attribute->createEditor();
|
||||
if (editor) {
|
||||
_value->layout()->addWidget(editor);
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelEditor::createNewAttribute() {
|
||||
QDialog dialog(this);
|
||||
dialog.setWindowTitle("New Attribute");
|
||||
|
||||
QVBoxLayout layout;
|
||||
dialog.setLayout(&layout);
|
||||
|
||||
QFormLayout form;
|
||||
layout.addLayout(&form);
|
||||
|
||||
QLineEdit name;
|
||||
form.addRow("Name:", &name);
|
||||
|
||||
QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
dialog.connect(&buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||
dialog.connect(&buttons, SIGNAL(rejected()), SLOT(reject()));
|
||||
|
||||
layout.addWidget(&buttons);
|
||||
|
||||
if (!dialog.exec()) {
|
||||
return;
|
||||
}
|
||||
QString nameText = name.text().trimmed();
|
||||
AttributeRegistry::getInstance()->registerAttribute(new QRgbAttribute(nameText));
|
||||
|
||||
updateAttributes(nameText);
|
||||
}
|
||||
|
||||
void MetavoxelEditor::updateGridPosition() {
|
||||
// make sure our grid position matches our grid spacing
|
||||
double step = _gridSpacing->value();
|
||||
if (step > 0.0) {
|
||||
_gridPosition->setSingleStep(step);
|
||||
_gridPosition->setValue(step * floor(_gridPosition->value() / step));
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelEditor::render() {
|
||||
QString selected = getSelectedAttribute();
|
||||
if (selected.isNull()) {
|
||||
resetState();
|
||||
return;
|
||||
}
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glm::quat rotation = getGridRotation();
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
|
||||
glm::quat inverseRotation = glm::inverse(rotation);
|
||||
glm::vec3 rayOrigin = inverseRotation * Application::getInstance()->getMouseRayOrigin();
|
||||
glm::vec3 rayDirection = inverseRotation * Application::getInstance()->getMouseRayDirection();
|
||||
float spacing = _gridSpacing->value();
|
||||
float position = _gridPosition->value();
|
||||
if (_state == RAISING_STATE) {
|
||||
// find the plane at the mouse position, orthogonal to the plane, facing the eye position
|
||||
glLineWidth(4.0f);
|
||||
glm::vec3 eyePosition = inverseRotation * Application::getInstance()->getViewFrustum()->getOffsetPosition();
|
||||
glm::vec3 mousePoint = glm::vec3(_mousePosition, position);
|
||||
glm::vec3 right = glm::cross(glm::vec3(0.0f, 0.0f, 1.0f), eyePosition - mousePoint);
|
||||
glm::vec3 normal = glm::cross(right, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
float divisor = glm::dot(normal, rayDirection);
|
||||
if (fabs(divisor) > EPSILON) {
|
||||
float distance = (glm::dot(normal, mousePoint) - glm::dot(normal, rayOrigin)) / divisor;
|
||||
float projection = rayOrigin.z + distance * rayDirection.z;
|
||||
_height = spacing * roundf(projection / spacing) - position;
|
||||
}
|
||||
} else if (fabs(rayDirection.z) > EPSILON) {
|
||||
// find the intersection of the rotated mouse ray with the plane
|
||||
float distance = (position - rayOrigin.z) / rayDirection.z;
|
||||
_mousePosition = glm::vec2(rayOrigin + rayDirection * distance);
|
||||
glm::vec2 snappedPosition = spacing * glm::floor(_mousePosition / spacing);
|
||||
|
||||
if (_state == HOVERING_STATE) {
|
||||
_startPosition = _endPosition = snappedPosition;
|
||||
glLineWidth(2.0f);
|
||||
|
||||
} else if (_state == DRAGGING_STATE) {
|
||||
_endPosition = snappedPosition;
|
||||
glLineWidth(4.0f);
|
||||
}
|
||||
} else {
|
||||
// cancel any operation in progress
|
||||
resetState();
|
||||
}
|
||||
|
||||
const float GRID_BRIGHTNESS = 0.5f;
|
||||
if (_startPosition != INVALID_VECTOR) {
|
||||
glm::vec2 minimum = glm::min(_startPosition, _endPosition);
|
||||
glm::vec2 maximum = glm::max(_startPosition, _endPosition);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(minimum.x, minimum.y, position);
|
||||
glScalef(maximum.x + spacing - minimum.x, maximum.y + spacing - minimum.y, _height);
|
||||
|
||||
glTranslatef(0.5f, 0.5f, 0.5f);
|
||||
if (_state != HOVERING_STATE) {
|
||||
const float BOX_ALPHA = 0.25f;
|
||||
QColor color = getValue().value<QColor>();
|
||||
if (color.isValid()) {
|
||||
glColor4f(color.redF(), color.greenF(), color.blueF(), BOX_ALPHA);
|
||||
} else {
|
||||
glColor4f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS, BOX_ALPHA);
|
||||
}
|
||||
glEnable(GL_CULL_FACE);
|
||||
glutSolidCube(1.0);
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
glutWireCube(1.0);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glLineWidth(1.0f);
|
||||
|
||||
// center the grid around the camera position on the plane
|
||||
glm::vec3 rotated = inverseRotation * Application::getInstance()->getCamera()->getPosition();
|
||||
const int GRID_DIVISIONS = 300;
|
||||
glTranslatef(spacing * (floorf(rotated.x / spacing) - GRID_DIVISIONS / 2),
|
||||
spacing * (floorf(rotated.y / spacing) - GRID_DIVISIONS / 2), position);
|
||||
|
||||
float scale = GRID_DIVISIONS * spacing;
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
_gridProgram.bind();
|
||||
|
||||
glColor3f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS);
|
||||
Application::getInstance()->getGeometryCache()->renderGrid(GRID_DIVISIONS, GRID_DIVISIONS);
|
||||
|
||||
_gridProgram.release();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
void MetavoxelEditor::updateAttributes(const QString& select) {
|
||||
// remember the selection in order to preserve it
|
||||
QString selected = select.isNull() ? getSelectedAttribute() : select;
|
||||
_attributes->clear();
|
||||
|
||||
// sort the names for consistent ordering
|
||||
QList<QString> names = AttributeRegistry::getInstance()->getAttributes().keys();
|
||||
qSort(names);
|
||||
|
||||
foreach (const QString& name, names) {
|
||||
QListWidgetItem* item = new QListWidgetItem(name);
|
||||
_attributes->addItem(item);
|
||||
if (name == selected || selected.isNull()) {
|
||||
item->setSelected(true);
|
||||
selected = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString MetavoxelEditor::getSelectedAttribute() const {
|
||||
QList<QListWidgetItem*> selectedItems = _attributes->selectedItems();
|
||||
return selectedItems.isEmpty() ? QString() : selectedItems.first()->text();
|
||||
}
|
||||
|
||||
glm::quat MetavoxelEditor::getGridRotation() const {
|
||||
// for simplicity, we handle the other two planes by rotating them onto X/Y and performing computation there
|
||||
switch (_gridPlane->currentIndex()) {
|
||||
case GRID_PLANE_XY:
|
||||
return glm::quat();
|
||||
|
||||
case GRID_PLANE_XZ:
|
||||
return glm::angleAxis(-90.0f, 1.0f, 0.0f, 0.0f);
|
||||
|
||||
case GRID_PLANE_YZ:
|
||||
return glm::angleAxis(90.0f, 0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelEditor::resetState() {
|
||||
_state = HOVERING_STATE;
|
||||
_startPosition = INVALID_VECTOR;
|
||||
_height = 0.0f;
|
||||
}
|
||||
|
||||
class Applier : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
Applier(const glm::vec3& minimum, const glm::vec3& maximum, float granularity, const AttributeValue& value);
|
||||
|
||||
virtual bool visit(MetavoxelInfo& info);
|
||||
|
||||
protected:
|
||||
|
||||
glm::vec3 _minimum;
|
||||
glm::vec3 _maximum;
|
||||
float _granularity;
|
||||
AttributeValue _value;
|
||||
};
|
||||
|
||||
Applier::Applier(const glm::vec3& minimum, const glm::vec3& maximum, float granularity, const AttributeValue& value) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << value.getAttribute()),
|
||||
_minimum(minimum),
|
||||
_maximum(maximum),
|
||||
_granularity(granularity),
|
||||
_value(value) {
|
||||
}
|
||||
|
||||
bool Applier::visit(MetavoxelInfo& info) {
|
||||
// find the intersection between volume and voxel
|
||||
glm::vec3 minimum = glm::max(info.minimum, _minimum);
|
||||
glm::vec3 maximum = glm::min(info.minimum + glm::vec3(info.size, info.size, info.size), _maximum);
|
||||
glm::vec3 size = maximum - minimum;
|
||||
if (size.x <= 0.0f || size.y <= 0.0f || size.z <= 0.0f) {
|
||||
return false; // disjoint
|
||||
}
|
||||
float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size);
|
||||
if (volume >= 1.0f) {
|
||||
info.outputValues[0] = _value;
|
||||
return false; // entirely contained
|
||||
}
|
||||
if (info.size <= _granularity) {
|
||||
if (volume > 0.5f) {
|
||||
info.outputValues[0] = _value;
|
||||
}
|
||||
return false; // reached granularity limit; take best guess
|
||||
}
|
||||
return true; // subdivide
|
||||
}
|
||||
|
||||
void MetavoxelEditor::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) {
|
||||
AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(getSelectedAttribute());
|
||||
if (!attribute) {
|
||||
return;
|
||||
}
|
||||
OwnedAttributeValue value(attribute, attribute->createFromVariant(getValue()));
|
||||
|
||||
Applier applier(minimum, maximum, _gridSpacing->value(), value);
|
||||
Application::getInstance()->getMetavoxels()->getData().guide(applier);
|
||||
}
|
||||
|
||||
QVariant MetavoxelEditor::getValue() const {
|
||||
if (_value->layout()->isEmpty()) {
|
||||
return QVariant();
|
||||
}
|
||||
QWidget* editor = _value->layout()->itemAt(0)->widget();
|
||||
return editor->metaObject()->userProperty().read(editor);
|
||||
}
|
||||
|
||||
ProgramObject MetavoxelEditor::_gridProgram;
|
67
interface/src/ui/MetavoxelEditor.h
Normal file
67
interface/src/ui/MetavoxelEditor.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// MetavoxelEditor.h
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 1/21/14.
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__MetavoxelEditor__
|
||||
#define __interface__MetavoxelEditor__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "renderer/ProgramObject.h"
|
||||
|
||||
class QComboBox;
|
||||
class QDoubleSpinBox;
|
||||
class QGroupBox;
|
||||
class QListWidget;
|
||||
|
||||
/// Allows editing metavoxels.
|
||||
class MetavoxelEditor : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelEditor();
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
private slots:
|
||||
|
||||
void updateValueEditor();
|
||||
void createNewAttribute();
|
||||
void updateGridPosition();
|
||||
|
||||
void render();
|
||||
|
||||
private:
|
||||
|
||||
void updateAttributes(const QString& select = QString());
|
||||
QString getSelectedAttribute() const;
|
||||
glm::quat getGridRotation() const;
|
||||
void resetState();
|
||||
void applyValue(const glm::vec3& minimum, const glm::vec3& maximum);
|
||||
QVariant getValue() const;
|
||||
|
||||
QListWidget* _attributes;
|
||||
QComboBox* _gridPlane;
|
||||
QDoubleSpinBox* _gridSpacing;
|
||||
QDoubleSpinBox* _gridPosition;
|
||||
QGroupBox* _value;
|
||||
|
||||
enum State { HOVERING_STATE, DRAGGING_STATE, RAISING_STATE };
|
||||
|
||||
State _state;
|
||||
|
||||
glm::vec2 _mousePosition; ///< the position of the mouse in rotated space
|
||||
|
||||
glm::vec2 _startPosition; ///< the first corner of the selection base
|
||||
glm::vec2 _endPosition; ///< the second corner of the selection base
|
||||
float _height; ///< the selection height
|
||||
|
||||
static ProgramObject _gridProgram;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__MetavoxelEditor__) */
|
|
@ -6,7 +6,10 @@
|
|||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QColorDialog>
|
||||
#include <QPushButton>
|
||||
#include <QScriptEngine>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "AttributeRegistry.h"
|
||||
#include "MetavoxelData.h"
|
||||
|
@ -69,12 +72,12 @@ 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, value) {
|
||||
}
|
||||
|
||||
OwnedAttributeValue::OwnedAttributeValue(const AttributePointer& attribute, void* value) :
|
||||
AttributeValue(attribute, attribute ? attribute->create(value) : NULL) {
|
||||
OwnedAttributeValue::OwnedAttributeValue(const AttributePointer& attribute) :
|
||||
AttributeValue(attribute, attribute ? attribute->create() : NULL) {
|
||||
}
|
||||
|
||||
OwnedAttributeValue::OwnedAttributeValue(const AttributeValue& other) :
|
||||
|
@ -92,7 +95,7 @@ OwnedAttributeValue& OwnedAttributeValue::operator=(const AttributeValue& other)
|
|||
_attribute->destroy(_value);
|
||||
}
|
||||
if ((_attribute = other.getAttribute())) {
|
||||
_value = _attribute->create(other.getValue());
|
||||
_value = other.copy();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -132,6 +135,41 @@ void* QRgbAttribute::createFromScript(const QScriptValue& value, QScriptEngine*
|
|||
return encodeInline((QRgb)value.toUInt32());
|
||||
}
|
||||
|
||||
void* QRgbAttribute::createFromVariant(const QVariant& value) const {
|
||||
switch (value.userType()) {
|
||||
case QMetaType::QColor:
|
||||
return encodeInline(value.value<QColor>().rgba());
|
||||
|
||||
default:
|
||||
return encodeInline((QRgb)value.toUInt());
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* QRgbAttribute::createEditor(QWidget* parent) const {
|
||||
QRgbEditor* editor = new QRgbEditor(parent);
|
||||
editor->setColor(QColor::fromRgba(_defaultValue));
|
||||
return editor;
|
||||
}
|
||||
|
||||
QRgbEditor::QRgbEditor(QWidget* parent) : QWidget(parent) {
|
||||
setLayout(new QVBoxLayout());
|
||||
layout()->addWidget(_button = new QPushButton());
|
||||
connect(_button, SIGNAL(clicked()), SLOT(selectColor()));
|
||||
}
|
||||
|
||||
void QRgbEditor::setColor(const QColor& color) {
|
||||
QString name = (_color = color).name();
|
||||
_button->setStyleSheet(QString("background: %1; color: %2").arg(name, QColor::fromRgb(~color.rgb()).name()));
|
||||
_button->setText(name);
|
||||
}
|
||||
|
||||
void QRgbEditor::selectColor() {
|
||||
QColor color = QColorDialog::getColor(_color, this, QString(), QColorDialog::ShowAlphaChannel);
|
||||
if (color.isValid()) {
|
||||
setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
PolymorphicData::~PolymorphicData() {
|
||||
}
|
||||
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
#include <QSharedData>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
#include "Bitstream.h"
|
||||
|
||||
class QPushButton;
|
||||
class QScriptContext;
|
||||
class QScriptEngine;
|
||||
class QScriptValue;
|
||||
|
@ -52,6 +54,9 @@ public:
|
|||
/// Retrieves an attribute by name.
|
||||
AttributePointer getAttribute(const QString& name) const { return _attributes.value(name); }
|
||||
|
||||
/// Returns a reference to the attribute hash.
|
||||
const QHash<QString, AttributePointer>& getAttributes() const { return _attributes; }
|
||||
|
||||
/// Returns a reference to the standard PolymorphicDataPointer "guide" attribute.
|
||||
const AttributePointer& getGuideAttribute() const { return _guideAttribute; }
|
||||
|
||||
|
@ -113,11 +118,19 @@ protected:
|
|||
class OwnedAttributeValue : public AttributeValue {
|
||||
public:
|
||||
|
||||
OwnedAttributeValue(const AttributePointer& attribute = AttributePointer());
|
||||
/// Assumes ownership of the specified value. It will be destroyed when this is destroyed or reassigned.
|
||||
OwnedAttributeValue(const AttributePointer& attribute, void* value);
|
||||
|
||||
/// Creates an owned attribute with a copy of the specified attribute's default value.
|
||||
OwnedAttributeValue(const AttributePointer& attribute = AttributePointer());
|
||||
|
||||
/// Creates an owned attribute with a copy of the specified other value.
|
||||
OwnedAttributeValue(const AttributeValue& other);
|
||||
|
||||
/// Destroys the current value, if any.
|
||||
~OwnedAttributeValue();
|
||||
|
||||
/// Destroys the current value, if any, and copies the specified other value.
|
||||
OwnedAttributeValue& operator=(const AttributeValue& other);
|
||||
};
|
||||
|
||||
|
@ -153,6 +166,12 @@ public:
|
|||
virtual void* getDefaultValue() const = 0;
|
||||
|
||||
virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const { return create(); }
|
||||
|
||||
virtual void* createFromVariant(const QVariant& value) const { return create(); }
|
||||
|
||||
/// Creates a widget to use to edit values of this attribute, or returns NULL if the attribute isn't editable.
|
||||
/// The widget should have a single "user" property that will be used to get/set the value.
|
||||
virtual QWidget* createEditor(QWidget* parent = NULL) const { return NULL; }
|
||||
};
|
||||
|
||||
/// A simple attribute class that stores its values inline.
|
||||
|
@ -222,6 +241,33 @@ public:
|
|||
virtual bool merge(void*& parent, void* children[]) const;
|
||||
|
||||
virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const;
|
||||
|
||||
virtual void* createFromVariant(const QVariant& value) const;
|
||||
|
||||
virtual QWidget* createEditor(QWidget* parent = NULL) const;
|
||||
};
|
||||
|
||||
/// Editor for RGBA values.
|
||||
class QRgbEditor : public QWidget {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor color MEMBER _color WRITE setColor USER true)
|
||||
|
||||
public:
|
||||
|
||||
QRgbEditor(QWidget* parent);
|
||||
|
||||
public slots:
|
||||
|
||||
void setColor(const QColor& color);
|
||||
|
||||
private slots:
|
||||
|
||||
void selectColor();
|
||||
|
||||
private:
|
||||
|
||||
QPushButton* _button;
|
||||
QColor _color;
|
||||
};
|
||||
|
||||
/// An attribute class that stores pointers to its values.
|
||||
|
|
|
@ -32,46 +32,36 @@ MetavoxelData& MetavoxelData::operator=(const MetavoxelData& other) {
|
|||
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];
|
||||
const QVector<AttributePointer>& inputs = visitor.getInputs();
|
||||
const QVector<AttributePointer>& outputs = visitor.getOutputs();
|
||||
MetavoxelVisitation firstVisitation = { this, NULL, visitor, QVector<MetavoxelNode*>(inputs.size() + 1),
|
||||
QVector<MetavoxelNode*>(outputs.size()), { glm::vec3(), TOP_LEVEL_SIZE,
|
||||
QVector<AttributeValue>(inputs.size() + 1), QVector<AttributeValue>(outputs.size()) } };
|
||||
for (int i = 0; i < inputs.size(); i++) {
|
||||
MetavoxelNode* node = _roots.value(inputs.at(i));
|
||||
firstVisitation.inputNodes[i] = node;
|
||||
firstVisitation.info.inputValues[i] = node ? node->getAttributeValue(inputs[i]) : inputs[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<
|
||||
firstVisitation.inputNodes.last() = node;
|
||||
firstVisitation.info.inputValues.last() = node ? node->getAttributeValue(guideAttribute) : guideAttribute;
|
||||
for (int i = 0; i < outputs.size(); i++) {
|
||||
MetavoxelNode* node = _roots.value(outputs.at(i));
|
||||
firstVisitation.outputNodes[i] = node;
|
||||
}
|
||||
static_cast<MetavoxelGuide*>(firstVisitation.info.inputValues.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->decrementReferenceCount(attributeValue.getAttribute());
|
||||
_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);
|
||||
for (int i = 0; i < outputs.size(); i++) {
|
||||
AttributeValue& value = firstVisitation.info.outputValues[i];
|
||||
if (value.getAttribute()) {
|
||||
MetavoxelNode* node = firstVisitation.outputNodes.at(i);
|
||||
if (node->isLeaf() && value.isDefault()) {
|
||||
node->decrementReferenceCount(value.getAttribute());
|
||||
_roots.remove(value.getAttribute());
|
||||
}
|
||||
}
|
||||
node = child;
|
||||
}
|
||||
return node->getAttributeValue(attribute);
|
||||
}
|
||||
|
||||
void MetavoxelData::read(Bitstream& in) {
|
||||
|
@ -80,7 +70,7 @@ void MetavoxelData::read(Bitstream& in) {
|
|||
_roots.clear();
|
||||
|
||||
// read in the new roots, reusing old ones where appropriate
|
||||
qint32 rootCount;
|
||||
int rootCount;
|
||||
in >> rootCount;
|
||||
for (int i = 0; i < rootCount; i++) {
|
||||
AttributePointer attribute;
|
||||
|
@ -100,7 +90,7 @@ void MetavoxelData::read(Bitstream& in) {
|
|||
}
|
||||
|
||||
void MetavoxelData::write(Bitstream& out) const {
|
||||
out << (qint32)_roots.size();
|
||||
out << _roots.size();
|
||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
||||
out.getAttributeStreamer() << it.key();
|
||||
it.value()->write(it.key(), out);
|
||||
|
@ -108,9 +98,70 @@ void MetavoxelData::write(Bitstream& out) const {
|
|||
}
|
||||
|
||||
void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) {
|
||||
int changedCount;
|
||||
in >> changedCount;
|
||||
for (int i = 0; i < changedCount; i++) {
|
||||
AttributePointer attribute;
|
||||
in.getAttributeStreamer() >> attribute;
|
||||
MetavoxelNode*& root = _roots[attribute];
|
||||
if (!root) {
|
||||
root = new MetavoxelNode(attribute);
|
||||
}
|
||||
MetavoxelNode* referenceRoot = reference._roots.value(attribute);
|
||||
if (referenceRoot) {
|
||||
root->readDelta(attribute, *referenceRoot, in);
|
||||
|
||||
} else {
|
||||
root->read(attribute, in);
|
||||
}
|
||||
}
|
||||
|
||||
int removedCount;
|
||||
in >> removedCount;
|
||||
for (int i = 0; i < removedCount; i++) {
|
||||
AttributePointer attribute;
|
||||
in.getAttributeStreamer() >> attribute;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) const {
|
||||
// count the number of roots added/changed, then write
|
||||
int changedCount = 0;
|
||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
||||
MetavoxelNode* referenceRoot = reference._roots.value(it.key());
|
||||
if (it.value() != referenceRoot) {
|
||||
changedCount++;
|
||||
}
|
||||
}
|
||||
out << changedCount;
|
||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
|
||||
MetavoxelNode* referenceRoot = reference._roots.value(it.key());
|
||||
if (it.value() != referenceRoot) {
|
||||
out.getAttributeStreamer() << it.key();
|
||||
if (referenceRoot) {
|
||||
it.value()->writeDelta(it.key(), *referenceRoot, out);
|
||||
} else {
|
||||
it.value()->write(it.key(), out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// same with nodes removed
|
||||
int removedCount = 0;
|
||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = reference._roots.constBegin();
|
||||
it != reference._roots.constEnd(); it++) {
|
||||
if (!_roots.contains(it.key())) {
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
out << removedCount;
|
||||
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = reference._roots.constBegin();
|
||||
it != reference._roots.constEnd(); it++) {
|
||||
if (!_roots.contains(it.key())) {
|
||||
out.getAttributeStreamer() << it.key();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelData::incrementRootReferenceCounts() {
|
||||
|
@ -128,10 +179,11 @@ void MetavoxelData::decrementRootReferenceCounts() {
|
|||
void writeDelta(const MetavoxelDataPointer& data, const MetavoxelDataPointer& reference, Bitstream& out) {
|
||||
if (data == reference) {
|
||||
out << false;
|
||||
return;
|
||||
|
||||
} else {
|
||||
out << true;
|
||||
data->writeDelta(*reference, out);
|
||||
}
|
||||
out << true;
|
||||
data->writeDelta(*reference, out);
|
||||
}
|
||||
|
||||
void readDelta(MetavoxelDataPointer& data, const MetavoxelDataPointer& reference, Bitstream& in) {
|
||||
|
@ -140,6 +192,9 @@ void readDelta(MetavoxelDataPointer& data, const MetavoxelDataPointer& reference
|
|||
if (changed) {
|
||||
data.detach();
|
||||
data->readDelta(*reference, in);
|
||||
|
||||
} else {
|
||||
data = reference;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,34 +205,6 @@ MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) : _referenceC
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -188,6 +215,18 @@ AttributeValue MetavoxelNode::getAttributeValue(const AttributePointer& attribut
|
|||
return AttributeValue(attribute, _attributeValue);
|
||||
}
|
||||
|
||||
void MetavoxelNode::mergeChildren(const AttributePointer& attribute) {
|
||||
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 (attribute->merge(_attributeValue, childValues) && allLeaves) {
|
||||
clearChildren(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
bool MetavoxelNode::isLeaf() const {
|
||||
for (int i = 0; i < CHILD_COUNT; i++) {
|
||||
if (_children[i]) {
|
||||
|
@ -229,11 +268,6 @@ void MetavoxelNode::write(const AttributePointer& attribute, Bitstream& out) con
|
|||
}
|
||||
|
||||
void MetavoxelNode::readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in) {
|
||||
bool different;
|
||||
in >> different;
|
||||
if (!different) {
|
||||
return;
|
||||
}
|
||||
bool leaf;
|
||||
in >> leaf;
|
||||
attribute->readDelta(in, _attributeValue, reference._attributeValue, leaf);
|
||||
|
@ -254,11 +288,6 @@ void MetavoxelNode::readDelta(const AttributePointer& attribute, const Metavoxel
|
|||
}
|
||||
|
||||
void MetavoxelNode::writeDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& out) const {
|
||||
if (this == &reference) {
|
||||
out << false;
|
||||
return;
|
||||
}
|
||||
out << true;
|
||||
bool leaf = isLeaf();
|
||||
out << leaf;
|
||||
attribute->writeDelta(out, _attributeValue, reference._attributeValue, leaf);
|
||||
|
@ -300,18 +329,9 @@ void MetavoxelNode::clearChildren(const AttributePointer& attribute) {
|
|||
}
|
||||
}
|
||||
|
||||
int MetavoxelPath::operator[](int index) const {
|
||||
return (int)_array.at(index * BITS_PER_ELEMENT) | ((int)_array.at(index * BITS_PER_ELEMENT + 1) << 1) |
|
||||
((int)_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;
|
||||
MetavoxelVisitor::MetavoxelVisitor(const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs) :
|
||||
_inputs(inputs),
|
||||
_outputs(outputs) {
|
||||
}
|
||||
|
||||
PolymorphicData* DefaultMetavoxelGuide::clone() const {
|
||||
|
@ -323,42 +343,84 @@ 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) {
|
||||
visitation.info.isLeaf = visitation.allInputNodesLeaves();
|
||||
bool keepGoing = visitation.visitor.visit(visitation.info);
|
||||
for (int i = 0; i < visitation.outputNodes.size(); i++) {
|
||||
AttributeValue& value = visitation.info.outputValues[i];
|
||||
if (value.getAttribute()) {
|
||||
MetavoxelNode*& node = visitation.outputNodes[i];
|
||||
if (!node) {
|
||||
node = visitation.createOutputNode(i);
|
||||
}
|
||||
node->setAttributeValue(value);
|
||||
}
|
||||
}
|
||||
if (!keepGoing) {
|
||||
return;
|
||||
}
|
||||
MetavoxelVisitation nextVisitation = { visitation.visitor, QVector<MetavoxelNode*>(visitation.nodes.size()),
|
||||
{ glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.nodes.size()) } };
|
||||
MetavoxelVisitation nextVisitation = { visitation.data, &visitation, visitation.visitor,
|
||||
QVector<MetavoxelNode*>(visitation.inputNodes.size()), QVector<MetavoxelNode*>(visitation.outputNodes.size()),
|
||||
{ glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.inputNodes.size()),
|
||||
QVector<AttributeValue>(visitation.outputNodes.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);
|
||||
for (int j = 0; j < visitation.inputNodes.size(); j++) {
|
||||
MetavoxelNode* node = visitation.inputNodes.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.inputValues[j] = ((nextVisitation.inputNodes[j] = child)) ?
|
||||
child->getAttributeValue(visitation.info.inputValues[j].getAttribute()) :
|
||||
visitation.info.inputValues[j];
|
||||
}
|
||||
for (int j = 0; j < visitation.outputNodes.size(); j++) {
|
||||
MetavoxelNode* node = visitation.outputNodes.at(j);
|
||||
MetavoxelNode* child = node ? node->getChild(i) : NULL;
|
||||
nextVisitation.outputNodes[j] = child;
|
||||
}
|
||||
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<
|
||||
nextVisitation.childIndex = i;
|
||||
static_cast<MetavoxelGuide*>(nextVisitation.info.inputValues.last().getInlineValue<
|
||||
PolymorphicDataPointer>().data())->guide(nextVisitation);
|
||||
for (int j = 0; j < nextVisitation.outputNodes.size(); j++) {
|
||||
AttributeValue& value = nextVisitation.info.outputValues[j];
|
||||
if (value.getAttribute()) {
|
||||
visitation.info.outputValues[j] = value;
|
||||
value = AttributeValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < visitation.outputNodes.size(); i++) {
|
||||
AttributeValue& value = visitation.info.outputValues[i];
|
||||
if (value.getAttribute()) {
|
||||
MetavoxelNode* node = visitation.outputNodes.at(i);
|
||||
node->mergeChildren(value.getAttribute());
|
||||
value = node->getAttributeValue(value.getAttribute());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue ScriptedMetavoxelGuide::getAttributes(QScriptContext* context, QScriptEngine* engine) {
|
||||
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
|
||||
static QScriptValue getAttributes(QScriptEngine* engine, ScriptedMetavoxelGuide* guide,
|
||||
const QVector<AttributePointer>& attributes) {
|
||||
|
||||
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::getInputs(QScriptContext* context, QScriptEngine* engine) {
|
||||
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
|
||||
return getAttributes(engine, guide, guide->_visitation->visitor.getInputs());
|
||||
}
|
||||
|
||||
QScriptValue ScriptedMetavoxelGuide::getOutputs(QScriptContext* context, QScriptEngine* engine) {
|
||||
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
|
||||
return getAttributes(engine, guide, guide->_visitation->visitor.getOutputs());
|
||||
}
|
||||
|
||||
QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngine* engine) {
|
||||
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
|
||||
|
||||
|
@ -367,26 +429,26 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin
|
|||
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() };
|
||||
infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.inputValues,
|
||||
guide->_visitation->info.outputValues, 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);
|
||||
QScriptValue inputValues = infoValue.property(guide->_inputValuesHandle);
|
||||
const QVector<AttributePointer>& inputs = guide->_visitation->visitor.getInputs();
|
||||
for (int i = 0; i < inputs.size(); i++) {
|
||||
QScriptValue attributeValue = inputValues.property(i);
|
||||
if (attributeValue.isValid()) {
|
||||
info.attributeValues[i] = AttributeValue(attributes.at(i),
|
||||
attributes.at(i)->createFromScript(attributeValue, engine));
|
||||
info.inputValues[i] = AttributeValue(inputs.at(i),
|
||||
inputs.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());
|
||||
for (int i = 0; i < inputs.size(); i++) {
|
||||
if (inputValues.property(i).isValid()) {
|
||||
info.inputValues[i].getAttribute()->destroy(info.inputValues[i].getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,16 +459,19 @@ ScriptedMetavoxelGuide::ScriptedMetavoxelGuide(const QScriptValue& guideFunction
|
|||
_guideFunction(guideFunction),
|
||||
_minimumHandle(guideFunction.engine()->toStringHandle("minimum")),
|
||||
_sizeHandle(guideFunction.engine()->toStringHandle("size")),
|
||||
_attributeValuesHandle(guideFunction.engine()->toStringHandle("attributeValues")),
|
||||
_inputValuesHandle(guideFunction.engine()->toStringHandle("inputValues")),
|
||||
_outputValuesHandle(guideFunction.engine()->toStringHandle("outputValues")),
|
||||
_isLeafHandle(guideFunction.engine()->toStringHandle("isLeaf")),
|
||||
_getAttributesFunction(guideFunction.engine()->newFunction(getAttributes, 0)),
|
||||
_getInputsFunction(guideFunction.engine()->newFunction(getInputs, 0)),
|
||||
_getOutputsFunction(guideFunction.engine()->newFunction(getOutputs, 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("getInputs", _getInputsFunction);
|
||||
visitor.setProperty("getOutputs", _getOutputsFunction);
|
||||
visitor.setProperty("visit", _visitFunction);
|
||||
_arguments[0].setProperty("visitor", visitor);
|
||||
_arguments[0].setProperty("info", _info);
|
||||
|
@ -419,7 +484,7 @@ PolymorphicData* ScriptedMetavoxelGuide::clone() const {
|
|||
|
||||
void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
||||
QScriptValue data = _guideFunction.engine()->newVariant(QVariant::fromValue<void*>(this));
|
||||
_getAttributesFunction.setData(data);
|
||||
_getInputsFunction.setData(data);
|
||||
_visitFunction.setData(data);
|
||||
_minimum.setProperty(0, visitation.info.minimum.x);
|
||||
_minimum.setProperty(1, visitation.info.minimum.y);
|
||||
|
@ -433,11 +498,29 @@ void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
|
|||
}
|
||||
}
|
||||
|
||||
bool MetavoxelVisitation::allNodesLeaves() const {
|
||||
foreach (MetavoxelNode* node, nodes) {
|
||||
bool MetavoxelVisitation::allInputNodesLeaves() const {
|
||||
foreach (MetavoxelNode* node, inputNodes) {
|
||||
if (node != NULL && !node->isLeaf()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
MetavoxelNode* MetavoxelVisitation::createOutputNode(int index) {
|
||||
const AttributePointer& attribute = visitor.getOutputs().at(index);
|
||||
if (previous) {
|
||||
MetavoxelNode*& parent = previous->outputNodes[index];
|
||||
if (!parent) {
|
||||
parent = previous->createOutputNode(index);
|
||||
}
|
||||
AttributeValue value = parent->getAttributeValue(attribute);
|
||||
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
|
||||
parent->_children[i] = new MetavoxelNode(value);
|
||||
}
|
||||
return parent->_children[childIndex];
|
||||
|
||||
} else {
|
||||
return data->_roots[attribute] = new MetavoxelNode(attribute);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
class QScriptContext;
|
||||
|
||||
class MetavoxelNode;
|
||||
class MetavoxelPath;
|
||||
class MetavoxelVisitation;
|
||||
class MetavoxelVisitor;
|
||||
|
||||
|
@ -41,12 +40,6 @@ public:
|
|||
/// 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;
|
||||
|
||||
void read(Bitstream& in);
|
||||
void write(Bitstream& out) const;
|
||||
|
||||
|
@ -54,6 +47,8 @@ public:
|
|||
void writeDelta(const MetavoxelData& reference, Bitstream& out) const;
|
||||
|
||||
private:
|
||||
|
||||
friend class MetavoxelVisitation;
|
||||
|
||||
void incrementRootReferenceCounts();
|
||||
void decrementRootReferenceCounts();
|
||||
|
@ -74,17 +69,13 @@ 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;
|
||||
|
||||
void mergeChildren(const AttributePointer& attribute);
|
||||
|
||||
MetavoxelNode* getChild(int index) const { return _children[index]; }
|
||||
void setChild(int index, MetavoxelNode* child) { _children[index] = child; }
|
||||
|
||||
|
@ -108,6 +99,8 @@ public:
|
|||
private:
|
||||
Q_DISABLE_COPY(MetavoxelNode)
|
||||
|
||||
friend class MetavoxelVisitation;
|
||||
|
||||
void clearChildren(const AttributePointer& attribute);
|
||||
|
||||
int _referenceCount;
|
||||
|
@ -115,31 +108,14 @@ private:
|
|||
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;
|
||||
QVector<AttributeValue> inputValues;
|
||||
QVector<AttributeValue> outputValues;
|
||||
bool isLeaf;
|
||||
};
|
||||
|
||||
|
@ -147,19 +123,23 @@ public:
|
|||
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; }
|
||||
MetavoxelVisitor(const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs);
|
||||
|
||||
/// Returns a reference to the list of input attributes desired.
|
||||
const QVector<AttributePointer>& getInputs() const { return _inputs; }
|
||||
|
||||
/// Returns a reference to the list of output attributes provided.
|
||||
const QVector<AttributePointer>& getOutputs() const { return _outputs; }
|
||||
|
||||
/// Visits a metavoxel.
|
||||
/// \param info the metavoxel ata
|
||||
/// \param if true, continue descending; if false, stop
|
||||
virtual bool visit(const MetavoxelInfo& info) = 0;
|
||||
/// \param info the metavoxel data
|
||||
/// \return if true, continue descending; if false, stop
|
||||
virtual bool visit(MetavoxelInfo& info) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
QVector<AttributePointer> _attributes;
|
||||
QVector<AttributePointer> _inputs;
|
||||
QVector<AttributePointer> _outputs;
|
||||
};
|
||||
|
||||
/// Interface for objects that guide metavoxel visitors.
|
||||
|
@ -191,16 +171,19 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
static QScriptValue getAttributes(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue getInputs(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue getOutputs(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue visit(QScriptContext* context, QScriptEngine* engine);
|
||||
|
||||
QScriptValue _guideFunction;
|
||||
QScriptString _minimumHandle;
|
||||
QScriptString _sizeHandle;
|
||||
QScriptString _attributeValuesHandle;
|
||||
QScriptString _inputValuesHandle;
|
||||
QScriptString _outputValuesHandle;
|
||||
QScriptString _isLeafHandle;
|
||||
QScriptValueList _arguments;
|
||||
QScriptValue _getAttributesFunction;
|
||||
QScriptValue _getInputsFunction;
|
||||
QScriptValue _getOutputsFunction;
|
||||
QScriptValue _visitFunction;
|
||||
QScriptValue _info;
|
||||
QScriptValue _minimum;
|
||||
|
@ -212,11 +195,16 @@ private:
|
|||
class MetavoxelVisitation {
|
||||
public:
|
||||
|
||||
MetavoxelData* data;
|
||||
MetavoxelVisitation* previous;
|
||||
MetavoxelVisitor& visitor;
|
||||
QVector<MetavoxelNode*> nodes;
|
||||
QVector<MetavoxelNode*> inputNodes;
|
||||
QVector<MetavoxelNode*> outputNodes;
|
||||
MetavoxelInfo info;
|
||||
int childIndex;
|
||||
|
||||
bool allNodesLeaves() const;
|
||||
bool allInputNodesLeaves() const;
|
||||
MetavoxelNode* createOutputNode(int index);
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__MetavoxelData__) */
|
||||
|
|
Loading…
Reference in a new issue