mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-26 02:15:08 +02:00
Undo the merge with the broken master checking. What could go wrong?
This commit is contained in:
parent
810c766f77
commit
0f30ec2ccc
41 changed files with 1526 additions and 444 deletions
|
@ -180,6 +180,7 @@ option(GET_TBB "Get Threading Building Blocks library automatically as external
|
||||||
option(GET_LIBOVR "Get LibOVR library automatically as external project" 1)
|
option(GET_LIBOVR "Get LibOVR library automatically as external project" 1)
|
||||||
option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
|
option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
|
||||||
option(GET_VHACD "Get V-HACD library automatically as external project" 1)
|
option(GET_VHACD "Get V-HACD library automatically as external project" 1)
|
||||||
|
option(GET_POLYVOX "Get polyvox library automatically as external project" 1)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
option(GET_GLEW "Get GLEW library automatically as external project" 1)
|
option(GET_GLEW "Get GLEW library automatically as external project" 1)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
# OSXTBBInstallNameChange.cmake
|
# OSXInstallNameChange.cmake
|
||||||
# cmake/externals/tbb
|
# cmake/macros
|
||||||
#
|
#
|
||||||
# Copyright 2015 High Fidelity, Inc.
|
# Copyright 2015 High Fidelity, Inc.
|
||||||
# Created by Stephen Birarda on February 20, 2014
|
# Created by Stephen Birarda on February 20, 2014
|
||||||
|
@ -10,36 +10,33 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# first find the so files in the source dir
|
# first find the so files in the source dir
|
||||||
set(_TBB_LIBRARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib)
|
message("INSTALL_NAME_LIBRARY_DIR ${INSTALL_NAME_LIBRARY_DIR}")
|
||||||
file(GLOB_RECURSE _TBB_LIBRARIES "${_TBB_LIBRARY_DIR}/*.dylib")
|
|
||||||
|
|
||||||
# raise an error if we found none
|
file(GLOB_RECURSE _LIBRARIES "${INSTALL_NAME_LIBRARY_DIR}/*.dylib")
|
||||||
if (NOT _TBB_LIBRARIES)
|
|
||||||
message(FATAL_ERROR "Did not find any TBB libraries")
|
if (NOT _LIBRARIES)
|
||||||
|
message(FATAL_ERROR "OSXInstallNameChange -- no libraries found: ${INSTALL_NAME_LIBRARY_DIR}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# find the install_name_tool command
|
# find the install_name_tool command
|
||||||
find_program(INSTALL_NAME_TOOL_COMMAND NAMES install_name_tool DOC "Path to the install_name_tool command")
|
find_program(INSTALL_NAME_TOOL_COMMAND NAMES install_name_tool DOC "Path to the install_name_tool command")
|
||||||
|
|
||||||
# find the lipo command
|
|
||||||
find_program(LIPO_COMMAND NAMES lipo DOC "Path to the lipo command")
|
|
||||||
|
|
||||||
# enumerate the libraries
|
# enumerate the libraries
|
||||||
foreach(_TBB_LIBRARY ${_TBB_LIBRARIES})
|
foreach(_LIBRARY ${_LIBRARIES})
|
||||||
get_filename_component(_TBB_LIBRARY_FILENAME ${_TBB_LIBRARY} NAME)
|
get_filename_component(_LIBRARY_FILENAME ${_LIBRARY} NAME)
|
||||||
|
|
||||||
set(_INSTALL_NAME_ARGS ${INSTALL_NAME_TOOL_COMMAND} -id ${_TBB_LIBRARY} ${_TBB_LIBRARY_FILENAME})
|
set(_INSTALL_NAME_ARGS ${INSTALL_NAME_TOOL_COMMAND} -id ${_LIBRARY} ${_LIBRARY_FILENAME})
|
||||||
|
|
||||||
message(STATUS "${INSTALL_NAME_COMMAND} ${_INSTALL_NAME_ARGS}")
|
message(STATUS "${INSTALL_NAME_COMMAND} ${_INSTALL_NAME_ARGS}")
|
||||||
|
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND ${INSTALL_NAME_COMMAND} ${_INSTALL_NAME_ARGS}
|
COMMAND ${INSTALL_NAME_COMMAND} ${_INSTALL_NAME_ARGS}
|
||||||
WORKING_DIRECTORY ${_TBB_LIBRARY_DIR}
|
WORKING_DIRECTORY ${INSTALL_NAME_LIBRARY_DIR}
|
||||||
ERROR_VARIABLE _INSTALL_NAME_ERROR
|
ERROR_VARIABLE _INSTALL_NAME_ERROR
|
||||||
)
|
)
|
||||||
|
|
||||||
if (_INSTALL_NAME_ERROR)
|
if (_INSTALL_NAME_ERROR)
|
||||||
message(FATAL_ERROR "There was an error changing install name for ${_TBB_LIBRARY_FILENAME} - ${_INSTALL_NAME_ERROR}")
|
message(FATAL_ERROR "There was an error changing install name for ${_LIBRARY_FILENAME} - ${_INSTALL_NAME_ERROR}")
|
||||||
endif ()
|
endif ()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
57
cmake/externals/polyvox/CMakeLists.txt
vendored
Normal file
57
cmake/externals/polyvox/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
set(EXTERNAL_NAME polyvox)
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
ExternalProject_Add(
|
||||||
|
${EXTERNAL_NAME}
|
||||||
|
URL http://hifi-public.s3.amazonaws.com/dependencies/polyvox-master-2015-5-27.zip
|
||||||
|
URL_MD5 e3dd09a24df4db29ba370e3bea753388
|
||||||
|
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||||
|
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||||
|
LOG_DOWNLOAD 1
|
||||||
|
LOG_CONFIGURE 1
|
||||||
|
LOG_BUILD 1
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
set(INSTALL_NAME_LIBRARY_DIR ${INSTALL_DIR}/lib)
|
||||||
|
message(STATUS "in polyvox INSTALL_NAME_LIBRARY_DIR ${INSTALL_NAME_LIBRARY_DIR}")
|
||||||
|
ExternalProject_Add_Step(
|
||||||
|
${EXTERNAL_NAME}
|
||||||
|
change-install-name
|
||||||
|
COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${INSTALL_NAME_LIBRARY_DIR} -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
|
||||||
|
DEPENDEES install
|
||||||
|
WORKING_DIRECTORY <SOURCE_DIR>
|
||||||
|
LOG 1
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
|
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_CORE_INCLUDE_DIRS ${INSTALL_DIR}/PolyVoxCore/include CACHE FILEPATH
|
||||||
|
"Path to polyvox core include directory")
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_UTIL_INCLUDE_DIRS ${INSTALL_DIR}/PolyVoxUtil/include CACHE FILEPATH
|
||||||
|
"Path to polyvox util include directory")
|
||||||
|
else ()
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_CORE_INCLUDE_DIRS ${INSTALL_DIR}/include/PolyVoxCore CACHE FILEPATH
|
||||||
|
"Path to polyvox core include directory")
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_UTIL_INCLUDE_DIRS ${INSTALL_DIR}/include/PolyVoxUtil CACHE FILEPATH
|
||||||
|
"Path to polyvox util include directory")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_CORE_LIBRARY ${INSTALL_DIR}/PolyVoxCore/lib/PolyVoxCore.lib CACHE FILEPATH "polyvox core library")
|
||||||
|
# set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY ${INSTALL_DIR}/PolyVoxUtil/lib/PolyVoxUtil.lib CACHE FILEPATH "polyvox util library")
|
||||||
|
elseif (APPLE)
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_CORE_LIBRARY ${INSTALL_DIR}/lib/libPolyVoxCore.dylib CACHE FILEPATH "polyvox core library")
|
||||||
|
# set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY ${INSTALL_DIR}/lib/libPolyVoxUtil.dylib CACHE FILEPATH "polyvox util library")
|
||||||
|
else ()
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_CORE_LIBRARY ${INSTALL_DIR}/lib/libPolyVoxCore.so CACHE FILEPATH "polyvox core library")
|
||||||
|
# set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY ${INSTALL_DIR}/lib/libPolyVoxUtil.so CACHE FILEPATH "polyvox util library")
|
||||||
|
endif ()
|
4
cmake/externals/tbb/CMakeLists.txt
vendored
4
cmake/externals/tbb/CMakeLists.txt
vendored
|
@ -66,7 +66,7 @@ if (APPLE)
|
||||||
${EXTERNAL_NAME}
|
${EXTERNAL_NAME}
|
||||||
change-install-name
|
change-install-name
|
||||||
COMMENT "Calling install_name_tool on TBB libraries to fix install name for dylib linking"
|
COMMENT "Calling install_name_tool on TBB libraries to fix install name for dylib linking"
|
||||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/OSXTBBInstallNameChange.cmake
|
COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_TBB_LIB_DIR} -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
|
||||||
DEPENDEES install
|
DEPENDEES install
|
||||||
WORKING_DIRECTORY <SOURCE_DIR>
|
WORKING_DIRECTORY <SOURCE_DIR>
|
||||||
LOG 1
|
LOG 1
|
||||||
|
@ -115,4 +115,4 @@ endif ()
|
||||||
|
|
||||||
if (DEFINED ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE)
|
if (DEFINED ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE)
|
||||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE "List of tbb include directories")
|
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE "List of tbb include directories")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
54
cmake/modules/FindPolyVox.cmake
Normal file
54
cmake/modules/FindPolyVox.cmake
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#
|
||||||
|
# FindPolyvox.cmake
|
||||||
|
#
|
||||||
|
# Try to find the libpolyvox resampling library
|
||||||
|
#
|
||||||
|
# You can provide a LIBPOLYVOX_ROOT_DIR which contains lib and include directories
|
||||||
|
#
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# POLYVOX_FOUND - system found libpolyvox
|
||||||
|
# POLYVOX_INCLUDE_DIRS - the libpolyvox include directory
|
||||||
|
# POLYVOX_LIBRARIES - link to this to use libpolyvox
|
||||||
|
#
|
||||||
|
# Created on 1/22/2015 by Stephen Birarda
|
||||||
|
# Copyright 2015 High Fidelity, Inc.
|
||||||
|
#
|
||||||
|
# Distributed under the Apache License, Version 2.0.
|
||||||
|
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
#
|
||||||
|
|
||||||
|
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||||
|
hifi_library_search_hints("polyvox")
|
||||||
|
|
||||||
|
find_path(POLYVOX_CORE_INCLUDE_DIRS PolyVoxCore/SimpleVolume.h PATH_SUFFIXES include include/PolyVoxCore HINTS ${POLYVOX_SEARCH_DIRS})
|
||||||
|
# find_path(POLYVOX_UTIL_INCLUDE_DIRS PolyVoxUtil/Serialization.h PATH_SUFFIXES include include/PolyVoxUtil HINTS ${POLYVOX_SEARCH_DIRS})
|
||||||
|
|
||||||
|
find_library(POLYVOX_CORE_LIBRARY NAMES PolyVoxCore PATH_SUFFIXES lib HINTS ${POLYVOX_SEARCH_DIRS})
|
||||||
|
# find_library(POLYVOX_UTIL_LIBRARY NAMES PolyVoxUtil PATH_SUFFIXES lib HINTS ${POLYVOX_SEARCH_DIRS})
|
||||||
|
|
||||||
|
|
||||||
|
# if (WIN32)
|
||||||
|
# find_path(POLYVOX_DLL_PATH polyvox.dll PATH_SUFFIXES bin HINTS ${POLYVOX_SEARCH_DIRS})
|
||||||
|
# endif()
|
||||||
|
|
||||||
|
# set(POLYVOX_REQUIREMENTS POLYVOX_CORE_INCLUDE_DIRS POLYVOX_UTIL_INCLUDE_DIRS POLYVOX_CORE_LIBRARY POLYVOX_UTIL_LIBRARY)
|
||||||
|
set(POLYVOX_REQUIREMENTS POLYVOX_CORE_INCLUDE_DIRS POLYVOX_CORE_LIBRARY)
|
||||||
|
# if (WIN32)
|
||||||
|
# list(APPEND POLYVOX_REQUIREMENTS POLYVOX_DLL_PATH)
|
||||||
|
# endif ()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(Polyvox DEFAULT_MSG ${POLYVOX_REQUIREMENTS})
|
||||||
|
|
||||||
|
# if (WIN32)
|
||||||
|
# add_paths_to_fixup_libs(${POLYVOX_DLL_PATH})
|
||||||
|
# endif ()
|
||||||
|
|
||||||
|
# set(POLYVOX_INCLUDE_DIRS ${POLYVOX_CORE_INCLUDE_DIRS} ${POLYVOX_UTIL_INCLUDE_DIRS})
|
||||||
|
# set(POLYVOX_LIBRARIES ${POLYVOX_CORE_LIBRARY} ${POLYVOX_UTIL_LIBRARY})
|
||||||
|
|
||||||
|
set(POLYVOX_INCLUDE_DIRS ${POLYVOX_CORE_INCLUDE_DIRS})
|
||||||
|
set(POLYVOX_LIBRARIES ${POLYVOX_CORE_LIBRARY})
|
||||||
|
|
||||||
|
mark_as_advanced(POLYVOX_INCLUDE_DIRS POLYVOX_LIBRARIES POLYVOX_SEARCH_DIRS)
|
|
@ -0,0 +1,201 @@
|
||||||
|
// blockWorld.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Eric Levin on May 26, 2015
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Creates a floor of tiles and then drops planky blocks at random points above the tile floor
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var TILE_SIZE = 7
|
||||||
|
var GENERATE_INTERVAL = 50;
|
||||||
|
var NUM_ROWS = 10;
|
||||||
|
var angVelRange = 4;
|
||||||
|
|
||||||
|
var floorTiles = [];
|
||||||
|
var blocks = [];
|
||||||
|
var blockSpawner;
|
||||||
|
|
||||||
|
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
|
|
||||||
|
|
||||||
|
var floorPos = Vec3.sum(MyAvatar.position, {
|
||||||
|
x: 0,
|
||||||
|
y: -2,
|
||||||
|
z: 0
|
||||||
|
});
|
||||||
|
var x = floorPos.x;
|
||||||
|
|
||||||
|
var currentRowIndex = 0;
|
||||||
|
var currentColumnIndex = 0;
|
||||||
|
|
||||||
|
var DROP_HEIGHT = floorPos.y + 5;
|
||||||
|
var BLOCK_GRAVITY = {
|
||||||
|
x: 0,
|
||||||
|
y: -9,
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
var BLOCK_SIZE = {
|
||||||
|
x: 0.2,
|
||||||
|
y: 0.1,
|
||||||
|
z: 0.8
|
||||||
|
};
|
||||||
|
|
||||||
|
var bounds = {
|
||||||
|
xMin: floorPos.x,
|
||||||
|
xMax: floorPos.x + (TILE_SIZE * NUM_ROWS) - TILE_SIZE,
|
||||||
|
zMin: floorPos.z,
|
||||||
|
zMax: floorPos.z + (TILE_SIZE * NUM_ROWS) - TILE_SIZE
|
||||||
|
};
|
||||||
|
|
||||||
|
var screenSize = Controller.getViewportDimensions();
|
||||||
|
|
||||||
|
var BUTTON_SIZE = 32;
|
||||||
|
var PADDING = 3;
|
||||||
|
|
||||||
|
var offButton = Overlays.addOverlay("image", {
|
||||||
|
x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING,
|
||||||
|
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||||
|
width: BUTTON_SIZE,
|
||||||
|
height: BUTTON_SIZE,
|
||||||
|
imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",
|
||||||
|
color: {
|
||||||
|
red: 255,
|
||||||
|
green: 255,
|
||||||
|
blue: 255
|
||||||
|
},
|
||||||
|
alpha: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
var deleteButton = Overlays.addOverlay("image", {
|
||||||
|
x: screenSize.x / 2 - BUTTON_SIZE,
|
||||||
|
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||||
|
width: BUTTON_SIZE,
|
||||||
|
height: BUTTON_SIZE,
|
||||||
|
imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png",
|
||||||
|
color: {
|
||||||
|
red: 255,
|
||||||
|
green: 255,
|
||||||
|
blue: 255
|
||||||
|
},
|
||||||
|
alpha: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function generateFloor() {
|
||||||
|
for (var z = floorPos.z; currentColumnIndex < NUM_ROWS; z += TILE_SIZE, currentColumnIndex++) {
|
||||||
|
floorTiles.push(Entities.addEntity({
|
||||||
|
type: 'Box',
|
||||||
|
position: {
|
||||||
|
x: x,
|
||||||
|
y: floorPos.y,
|
||||||
|
z: z
|
||||||
|
},
|
||||||
|
dimensions: {
|
||||||
|
x: TILE_SIZE,
|
||||||
|
y: 2,
|
||||||
|
z: TILE_SIZE
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
red: randFloat(70, 120),
|
||||||
|
green: randFloat(70, 71),
|
||||||
|
blue: randFloat(70, 80)
|
||||||
|
},
|
||||||
|
// collisionsWillMove: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRowIndex++;
|
||||||
|
if (currentRowIndex < NUM_ROWS) {
|
||||||
|
currentColumnIndex = 0;
|
||||||
|
x += TILE_SIZE;
|
||||||
|
Script.setTimeout(generateFloor, GENERATE_INTERVAL);
|
||||||
|
} else {
|
||||||
|
//Once we're done generating floor, drop planky blocks at random points on floor
|
||||||
|
blockSpawner = Script.setInterval(function() {
|
||||||
|
dropBlock();
|
||||||
|
}, GENERATE_INTERVAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dropBlock() {
|
||||||
|
var dropPos = floorPos;
|
||||||
|
dropPos.y = DROP_HEIGHT;
|
||||||
|
dropPos.x = randFloat(bounds.xMin, bounds.xMax);
|
||||||
|
dropPos.z = randFloat(bounds.zMin, bounds.zMax);
|
||||||
|
blocks.push(Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
modelURL: 'http://s3.amazonaws.com/hifi-public/marketplace/hificontent/Games/blocks/block.fbx',
|
||||||
|
shapeType: 'box',
|
||||||
|
position: dropPos,
|
||||||
|
dimensions: BLOCK_SIZE,
|
||||||
|
collisionsWillMove: true,
|
||||||
|
gravity: {
|
||||||
|
x: 0,
|
||||||
|
y: -9,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
velocity: {
|
||||||
|
x: 0,
|
||||||
|
y: .1,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
angularVelocity: {
|
||||||
|
x: randFloat(-angVelRange, angVelRange),
|
||||||
|
y: randFloat(-angVelRange, angVelRange),
|
||||||
|
z: randFloat(-angVelRange, angVelRange),
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||||
|
x: event.x,
|
||||||
|
y: event.y
|
||||||
|
});
|
||||||
|
if (clickedOverlay == offButton) {
|
||||||
|
Script.clearInterval(blockSpawner);
|
||||||
|
}
|
||||||
|
if(clickedOverlay == deleteButton){
|
||||||
|
destroyStuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generateFloor();
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
// for (var i = 0; i < floorTiles.length; i++) {
|
||||||
|
// Entities.deleteEntity(floorTiles[i]);
|
||||||
|
// }
|
||||||
|
// for (var i = 0; i < blocks.length; i++) {
|
||||||
|
// Entities.deleteEntity(blocks[i]);
|
||||||
|
// }
|
||||||
|
Overlays.deleteOverlay(offButton);
|
||||||
|
Overlays.deleteOverlay(deleteButton)
|
||||||
|
Script.clearInterval(blockSpawner);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyStuff() {
|
||||||
|
for (var i = 0; i < floorTiles.length; i++) {
|
||||||
|
Entities.deleteEntity(floorTiles[i]);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < blocks.length; i++) {
|
||||||
|
Entities.deleteEntity(blocks[i]);
|
||||||
|
}
|
||||||
|
Script.clearInterval(blockSpawner);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function randFloat(low, high) {
|
||||||
|
return Math.floor(low + Math.random() * (high - low));
|
||||||
|
}
|
||||||
|
|
||||||
|
function map(value, min1, max1, min2, max2) {
|
||||||
|
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(cleanup);
|
||||||
|
Controller.mousePressEvent.connect(mousePressEvent);
|
|
@ -67,20 +67,6 @@ var pointerButton = Overlays.addOverlay("image", {
|
||||||
|
|
||||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2.0, Quat.getFront(Camera.getOrientation())));
|
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2.0, Quat.getFront(Camera.getOrientation())));
|
||||||
center.y += 0.5;
|
center.y += 0.5;
|
||||||
var whiteBoard = Entities.addEntity({
|
|
||||||
type: "Box",
|
|
||||||
position: center,
|
|
||||||
dimensions: {
|
|
||||||
x: 1,
|
|
||||||
y: 1,
|
|
||||||
z: .001
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
red: 255,
|
|
||||||
green: 255,
|
|
||||||
blue: 255
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function calculateNearLinePosition(targetPosition) {
|
function calculateNearLinePosition(targetPosition) {
|
||||||
var handPosition = MyAvatar.getRightPalmPosition();
|
var handPosition = MyAvatar.getRightPalmPosition();
|
||||||
|
@ -243,7 +229,6 @@ function keyReleaseEvent(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
Entities.deleteEntity(whiteBoard);
|
|
||||||
for (var i = 0; i < strokes.length; i++) {
|
for (var i = 0; i < strokes.length; i++) {
|
||||||
Entities.deleteEntity(strokes[i]);
|
Entities.deleteEntity(strokes[i]);
|
||||||
}
|
}
|
||||||
|
|
43
examples/voxels.js
Normal file
43
examples/voxels.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
var controlHeld = false;
|
||||||
|
|
||||||
|
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
if (!event.isLeftButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
|
||||||
|
// var props = Entities.getEntityProperties(intersection.entityID);
|
||||||
|
if (intersection.intersects) {
|
||||||
|
var ids = Entities.findEntities(intersection.intersection, 10);
|
||||||
|
for (var i = 0; i < ids.length; i++) {
|
||||||
|
var id = ids[i];
|
||||||
|
if (controlHeld) {
|
||||||
|
Entities.setVoxelSphere(id, intersection.intersection, 1.2, 0);
|
||||||
|
} else {
|
||||||
|
Entities.setVoxelSphere(id, intersection.intersection, 1.2, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function keyPressEvent(event) {
|
||||||
|
if (event.text == "CONTROL") {
|
||||||
|
controlHeld = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function keyReleaseEvent(event) {
|
||||||
|
if (event.text == "CONTROL") {
|
||||||
|
controlHeld = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
|
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
|
@ -1948,7 +1948,9 @@ FaceTracker* Application::getSelectedFaceTracker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setActiveFaceTracker() {
|
void Application::setActiveFaceTracker() {
|
||||||
|
#if defined(HAVE_FACESHIFT) || defined(HAVE_DDE)
|
||||||
bool isMuted = Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking);
|
bool isMuted = Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking);
|
||||||
|
#endif
|
||||||
#ifdef HAVE_FACESHIFT
|
#ifdef HAVE_FACESHIFT
|
||||||
auto faceshiftTracker = DependencyManager::get<Faceshift>();
|
auto faceshiftTracker = DependencyManager::get<Faceshift>();
|
||||||
faceshiftTracker->setIsMuted(isMuted);
|
faceshiftTracker->setIsMuted(isMuted);
|
||||||
|
|
|
@ -147,9 +147,9 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE glm::vec3 getNeckPosition() const;
|
Q_INVOKABLE glm::vec3 getNeckPosition() const;
|
||||||
|
|
||||||
Q_INVOKABLE const glm::vec3& getAcceleration() const { return _acceleration; }
|
Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; }
|
||||||
Q_INVOKABLE const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; }
|
||||||
Q_INVOKABLE const glm::vec3& getAngularAcceleration() const { return _angularAcceleration; }
|
Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; }
|
||||||
|
|
||||||
|
|
||||||
/// Scales a world space position vector relative to the avatar position and scale
|
/// Scales a world space position vector relative to the avatar position and scale
|
||||||
|
|
|
@ -123,17 +123,17 @@ glm::quat AvatarMotionState::getObjectRotation() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
const glm::vec3& AvatarMotionState::getObjectLinearVelocity() const {
|
glm::vec3 AvatarMotionState::getObjectLinearVelocity() const {
|
||||||
return _avatar->getVelocity();
|
return _avatar->getVelocity();
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
const glm::vec3& AvatarMotionState::getObjectAngularVelocity() const {
|
glm::vec3 AvatarMotionState::getObjectAngularVelocity() const {
|
||||||
return _avatar->getAngularVelocity();
|
return _avatar->getAngularVelocity();
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
const glm::vec3& AvatarMotionState::getObjectGravity() const {
|
glm::vec3 AvatarMotionState::getObjectGravity() const {
|
||||||
return _avatar->getAcceleration();
|
return _avatar->getAcceleration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,9 @@ public:
|
||||||
|
|
||||||
virtual glm::vec3 getObjectPosition() const;
|
virtual glm::vec3 getObjectPosition() const;
|
||||||
virtual glm::quat getObjectRotation() const;
|
virtual glm::quat getObjectRotation() const;
|
||||||
virtual const glm::vec3& getObjectLinearVelocity() const;
|
virtual glm::vec3 getObjectLinearVelocity() const;
|
||||||
virtual const glm::vec3& getObjectAngularVelocity() const;
|
virtual glm::vec3 getObjectAngularVelocity() const;
|
||||||
virtual const glm::vec3& getObjectGravity() const;
|
virtual glm::vec3 getObjectGravity() const;
|
||||||
|
|
||||||
virtual const QUuid& getObjectID() const;
|
virtual const QUuid& getObjectID() const;
|
||||||
|
|
||||||
|
|
|
@ -356,7 +356,7 @@ void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!Application::getInstance()->isMouseHidden()) {
|
if (!Application::getInstance()->isMouseHidden()) {
|
||||||
renderPointersOculus(myAvatar->getDefaultEyePosition());
|
renderPointersOculus();
|
||||||
}
|
}
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
@ -486,49 +486,40 @@ void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origi
|
||||||
direction = glm::normalize(intersectionWithUi - origin);
|
direction = glm::normalize(intersectionWithUi - origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec2 getPolarCoordinates(const PalmData& palm) {
|
||||||
|
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
|
auto avatarOrientation = myAvatar->getOrientation();
|
||||||
|
auto eyePos = myAvatar->getDefaultEyePosition();
|
||||||
|
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm);
|
||||||
|
// Direction of the tip relative to the eye
|
||||||
|
glm::vec3 tipDirection = tip - eyePos;
|
||||||
|
// orient into avatar space
|
||||||
|
tipDirection = glm::inverse(avatarOrientation) * tipDirection;
|
||||||
|
// Normalize for trig functions
|
||||||
|
tipDirection = glm::normalize(tipDirection);
|
||||||
|
// Convert to polar coordinates
|
||||||
|
glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y));
|
||||||
|
return polar;
|
||||||
|
}
|
||||||
|
|
||||||
//Caculate the click location using one of the sixense controllers. Scale is not applied
|
//Caculate the click location using one of the sixense controllers. Scale is not applied
|
||||||
QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
|
QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
|
||||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
|
||||||
|
|
||||||
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
|
|
||||||
glm::vec3 eyePos = myAvatar->getHead()->getEyePosition();
|
|
||||||
glm::quat invOrientation = glm::inverse(myAvatar->getOrientation());
|
|
||||||
//direction of ray goes towards camera
|
|
||||||
glm::vec3 dir = invOrientation * glm::normalize(qApp->getCamera()->getPosition() - tip);
|
|
||||||
glm::vec3 tipPos = invOrientation * (tip - eyePos);
|
|
||||||
|
|
||||||
QPoint rv;
|
QPoint rv;
|
||||||
auto canvasSize = qApp->getCanvasSize();
|
auto canvasSize = qApp->getCanvasSize();
|
||||||
if (qApp->isHMDMode()) {
|
if (qApp->isHMDMode()) {
|
||||||
float t;
|
float t;
|
||||||
|
glm::vec2 polar = getPolarCoordinates(*palm);
|
||||||
//We back the ray up by dir to ensure that it will not start inside the UI.
|
glm::vec2 point = sphericalToScreen(-polar);
|
||||||
glm::vec3 adjustedPos = tipPos - dir;
|
rv.rx() = point.x;
|
||||||
//Find intersection of crosshair ray.
|
rv.ry() = point.y;
|
||||||
if (raySphereIntersect(dir, adjustedPos, _oculusUIRadius * myAvatar->getScale(), &t)){
|
|
||||||
glm::vec3 collisionPos = adjustedPos + dir * t;
|
|
||||||
//Normalize it in case its not a radius of 1
|
|
||||||
collisionPos = glm::normalize(collisionPos);
|
|
||||||
//If we hit the back hemisphere, mark it as not a collision
|
|
||||||
if (collisionPos.z > 0) {
|
|
||||||
rv.setX(INT_MAX);
|
|
||||||
rv.setY(INT_MAX);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
float u = asin(collisionPos.x) / (_textureFov)+0.5f;
|
|
||||||
float v = 1.0 - (asin(collisionPos.y) / (_textureFov)+0.5f);
|
|
||||||
|
|
||||||
rv.setX(u * canvasSize.x);
|
|
||||||
rv.setY(v * canvasSize.y);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//if they did not click on the overlay, just set the coords to INT_MAX
|
|
||||||
rv.setX(INT_MAX);
|
|
||||||
rv.setY(INT_MAX);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
glm::dmat4 projection;
|
glm::dmat4 projection;
|
||||||
qApp->getProjectionMatrix(&projection);
|
qApp->getProjectionMatrix(&projection);
|
||||||
|
glm::quat invOrientation = glm::inverse(myAvatar->getOrientation());
|
||||||
|
glm::vec3 eyePos = myAvatar->getDefaultEyePosition();
|
||||||
|
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
|
||||||
|
glm::vec3 tipPos = invOrientation * (tip - eyePos);
|
||||||
|
|
||||||
glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0));
|
glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0));
|
||||||
glm::vec3 ndcSpacePos;
|
glm::vec3 ndcSpacePos;
|
||||||
|
@ -729,7 +720,7 @@ void ApplicationOverlay::renderControllerPointers() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) {
|
void ApplicationOverlay::renderPointersOculus() {
|
||||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
|
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
@ -737,16 +728,12 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) {
|
||||||
//Controller Pointers
|
//Controller Pointers
|
||||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
|
for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
|
||||||
|
|
||||||
PalmData& palm = myAvatar->getHand()->getPalms()[i];
|
PalmData& palm = myAvatar->getHand()->getPalms()[i];
|
||||||
if (palm.isActive()) {
|
if (palm.isActive()) {
|
||||||
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm);
|
glm::vec2 polar = getPolarCoordinates(palm);
|
||||||
glm::vec3 tipDirection = glm::normalize(glm::inverse(myAvatar->getOrientation()) * (tip - eyePos));
|
// Convert to quaternion
|
||||||
float pitch = -glm::asin(tipDirection.y);
|
glm::quat orientation = glm::quat(glm::vec3(polar.y, -polar.x, 0.0f));
|
||||||
float yawSign = glm::sign(-tipDirection.x);
|
// Render reticle at location
|
||||||
float yaw = glm::acos(-tipDirection.z) *
|
|
||||||
((yawSign == 0.0f) ? 1.0f : yawSign);
|
|
||||||
glm::quat orientation = glm::quat(glm::vec3(pitch, yaw, 0.0f));
|
|
||||||
renderReticle(orientation, _alpha);
|
renderReticle(orientation, _alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ private:
|
||||||
void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder);
|
void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder);
|
||||||
|
|
||||||
void renderControllerPointers();
|
void renderControllerPointers();
|
||||||
void renderPointersOculus(const glm::vec3& eyePos);
|
void renderPointersOculus();
|
||||||
|
|
||||||
void renderAudioMeter();
|
void renderAudioMeter();
|
||||||
void renderCameraToggle();
|
void renderCameraToggle();
|
||||||
|
|
|
@ -301,7 +301,7 @@ public:
|
||||||
int getReceiveRate() const;
|
int getReceiveRate() const;
|
||||||
|
|
||||||
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
|
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
|
||||||
Q_INVOKABLE const glm::vec3& getVelocity() const { return _velocity; }
|
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
|
||||||
const glm::vec3& getTargetVelocity() const { return _targetVelocity; }
|
const glm::vec3& getTargetVelocity() const { return _targetVelocity; }
|
||||||
|
|
||||||
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; }
|
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; }
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "RenderableWebEntityItem.h"
|
#include "RenderableWebEntityItem.h"
|
||||||
#include "RenderableZoneEntityItem.h"
|
#include "RenderableZoneEntityItem.h"
|
||||||
#include "RenderableLineEntityItem.h"
|
#include "RenderableLineEntityItem.h"
|
||||||
|
#include "RenderablePolyVoxEntityItem.h"
|
||||||
#include "EntitiesRendererLogging.h"
|
#include "EntitiesRendererLogging.h"
|
||||||
|
|
||||||
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
||||||
|
@ -65,6 +66,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory)
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory)
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Line, RenderableLineEntityItem::factory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Line, RenderableLineEntityItem::factory)
|
||||||
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(PolyVox, RenderablePolyVoxEntityItem::factory)
|
||||||
|
|
||||||
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID;
|
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID;
|
||||||
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
|
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
|
||||||
|
|
336
libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
Normal file
336
libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
Normal file
|
@ -0,0 +1,336 @@
|
||||||
|
//
|
||||||
|
// RenderablePolyVoxEntityItem.cpp
|
||||||
|
// libraries/entities-renderer/src/
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 5/19/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
|
||||||
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
#include <glm/gtx/string_cast.hpp>
|
||||||
|
|
||||||
|
#include <gpu/GPUConfig.h>
|
||||||
|
|
||||||
|
#include <DeferredLightingEffect.h>
|
||||||
|
#include <Model.h>
|
||||||
|
#include <PerfStat.h>
|
||||||
|
|
||||||
|
#include <PolyVoxCore/CubicSurfaceExtractorWithNormals.h>
|
||||||
|
#include <PolyVoxCore/MarchingCubesSurfaceExtractor.h>
|
||||||
|
#include <PolyVoxCore/SurfaceMesh.h>
|
||||||
|
#include <PolyVoxCore/SimpleVolume.h>
|
||||||
|
#include <PolyVoxCore/Raycast.h>
|
||||||
|
#include <PolyVoxCore/Material.h>
|
||||||
|
|
||||||
|
#include "model/Geometry.h"
|
||||||
|
#include "gpu/GLBackend.h"
|
||||||
|
#include "EntityTreeRenderer.h"
|
||||||
|
#include "RenderablePolyVoxEntityItem.h"
|
||||||
|
|
||||||
|
|
||||||
|
EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
|
return EntityItemPointer(new RenderablePolyVoxEntityItem(entityID, properties));
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() {
|
||||||
|
delete _volData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
|
||||||
|
|
||||||
|
if (_volData && voxelVolumeSize == _voxelVolumeSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "resetting voxel-space size";
|
||||||
|
|
||||||
|
PolyVoxEntityItem::setVoxelVolumeSize(voxelVolumeSize);
|
||||||
|
|
||||||
|
if (_volData) {
|
||||||
|
delete _volData;
|
||||||
|
}
|
||||||
|
|
||||||
|
PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
|
||||||
|
PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize[0] - 1, // -1 because these corners are inclusive
|
||||||
|
_voxelVolumeSize[1] - 1,
|
||||||
|
_voxelVolumeSize[2] - 1);
|
||||||
|
|
||||||
|
_volData = new PolyVox::SimpleVolume<uint8_t>(PolyVox::Region(lowCorner, highCorner));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
|
||||||
|
if (voxelData == _voxelData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PolyVoxEntityItem::setVoxelData(voxelData);
|
||||||
|
decompressVolumeData();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const {
|
||||||
|
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
|
||||||
|
glm::mat4 scaled = glm::scale(glm::mat4(), scale);
|
||||||
|
glm::mat4 centerToCorner = glm::translate(scaled, _voxelVolumeSize / -2.0f);
|
||||||
|
glm::mat4 rotation = glm::mat4_cast(_rotation);
|
||||||
|
glm::mat4 translation = glm::translate(getCenter());
|
||||||
|
return translation * rotation * centerToCorner;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const {
|
||||||
|
glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix());
|
||||||
|
return worldToModelMatrix;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) {
|
||||||
|
// This three-level for loop iterates over every voxel in the volume
|
||||||
|
for (int z = 0; z < _volData->getDepth(); z++) {
|
||||||
|
for (int y = 0; y < _volData->getHeight(); y++) {
|
||||||
|
for (int x = 0; x < _volData->getWidth(); x++) {
|
||||||
|
// Store our current position as a vector...
|
||||||
|
glm::vec3 pos(x, y, z);
|
||||||
|
// And compute how far the current position is from the center of the volume
|
||||||
|
float fDistToCenter = glm::distance(pos, center);
|
||||||
|
// If the current voxel is less than 'radius' units from the center then we make it solid.
|
||||||
|
if (fDistToCenter <= radius) {
|
||||||
|
_volData->setVoxelAt(x, y, z, toValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compressVolumeData();
|
||||||
|
_needsModelReload = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) {
|
||||||
|
// glm::vec3 centerVoxelCoords = worldToVoxelCoordinates(centerWorldCoords);
|
||||||
|
glm::vec4 centerVoxelCoords = worldToVoxelMatrix() * glm::vec4(centerWorldCoords, 1.0f);
|
||||||
|
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
|
||||||
|
float scaleY = scale[0];
|
||||||
|
float radiusVoxelCoords = radiusWorldCoords / scaleY;
|
||||||
|
setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::getModel() {
|
||||||
|
if (!_volData) {
|
||||||
|
// this will cause the allocation of _volData
|
||||||
|
setVoxelVolumeSize(_voxelVolumeSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A mesh object to hold the result of surface extraction
|
||||||
|
PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> polyVoxMesh;
|
||||||
|
|
||||||
|
switch (_voxelSurfaceStyle) {
|
||||||
|
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: {
|
||||||
|
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||||
|
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||||
|
surfaceExtractor.execute();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PolyVoxEntityItem::SURFACE_CUBIC: {
|
||||||
|
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||||
|
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||||
|
surfaceExtractor.execute();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert PolyVox mesh to a Sam mesh
|
||||||
|
model::Mesh* mesh = new model::Mesh();
|
||||||
|
model::MeshPointer meshPtr(mesh);
|
||||||
|
|
||||||
|
const std::vector<uint32_t>& vecIndices = polyVoxMesh.getIndices();
|
||||||
|
auto indexBuffer = new gpu::Buffer(vecIndices.size() * sizeof(uint32_t), (gpu::Byte*)vecIndices.data());
|
||||||
|
auto indexBufferPtr = gpu::BufferPointer(indexBuffer);
|
||||||
|
mesh->setIndexBuffer(gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW)));
|
||||||
|
|
||||||
|
|
||||||
|
const std::vector<PolyVox::PositionMaterialNormal>& vecVertices = polyVoxMesh.getVertices();
|
||||||
|
auto vertexBuffer = new gpu::Buffer(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal),
|
||||||
|
(gpu::Byte*)vecVertices.data());
|
||||||
|
auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer);
|
||||||
|
mesh->setVertexBuffer(gpu::BufferView(vertexBufferPtr,
|
||||||
|
0,
|
||||||
|
vertexBufferPtr->getSize() - sizeof(float) * 3,
|
||||||
|
sizeof(PolyVox::PositionMaterialNormal),
|
||||||
|
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
|
||||||
|
mesh->addAttribute(gpu::Stream::NORMAL,
|
||||||
|
gpu::BufferView(vertexBufferPtr,
|
||||||
|
sizeof(float) * 3,
|
||||||
|
vertexBufferPtr->getSize() - sizeof(float) * 3,
|
||||||
|
sizeof(PolyVox::PositionMaterialNormal),
|
||||||
|
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
|
||||||
|
|
||||||
|
// auto normalAttrib = mesh->getAttributeBuffer(gpu::Stream::NORMAL);
|
||||||
|
// for (auto normal = normalAttrib.begin<glm::vec3>(); normal != normalAttrib.end<glm::vec3>(); normal++) {
|
||||||
|
// (*normal) = -(*normal);
|
||||||
|
// }
|
||||||
|
|
||||||
|
qDebug() << "---- vecIndices.size() =" << vecIndices.size();
|
||||||
|
qDebug() << "---- vecVertices.size() =" << vecVertices.size();
|
||||||
|
|
||||||
|
_modelGeometry.setMesh(meshPtr);
|
||||||
|
_needsModelReload = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||||
|
PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render");
|
||||||
|
assert(getType() == EntityTypes::PolyVox);
|
||||||
|
|
||||||
|
if (_needsModelReload) {
|
||||||
|
getModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 position = getPosition();
|
||||||
|
glm::vec3 dimensions = getDimensions();
|
||||||
|
glm::vec3 scale = dimensions / _voxelVolumeSize;
|
||||||
|
glm::vec3 center = getCenter();
|
||||||
|
glm::quat rotation = getRotation();
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(position.x, position.y, position.z);
|
||||||
|
glm::vec3 axis = glm::axis(rotation);
|
||||||
|
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||||
|
glm::vec3 positionToCenter = center - position;
|
||||||
|
// make the rendered voxel volume be centered on the entity's position
|
||||||
|
positionToCenter -= _dimensions * glm::vec3(0.5f,0.5f,0.5f);
|
||||||
|
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||||
|
glScalef(scale.x, scale.y, scale.z);
|
||||||
|
|
||||||
|
auto mesh = _modelGeometry.getMesh();
|
||||||
|
gpu::Batch batch;
|
||||||
|
batch.setInputFormat(mesh->getVertexFormat());
|
||||||
|
batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer());
|
||||||
|
batch.setInputBuffer(gpu::Stream::NORMAL,
|
||||||
|
mesh->getVertexBuffer()._buffer,
|
||||||
|
sizeof(float) * 3,
|
||||||
|
mesh->getVertexBuffer()._stride);
|
||||||
|
batch.setIndexBuffer(gpu::UINT32, mesh->getIndexBuffer()._buffer, 0);
|
||||||
|
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
|
||||||
|
gpu::GLBackend::renderBatch(batch);
|
||||||
|
glPopMatrix();
|
||||||
|
RenderableDebugableEntityItem::render(this, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
class RaycastFunctor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RaycastFunctor() : _result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)) { }
|
||||||
|
bool operator()(PolyVox::SimpleVolume<unsigned char>::Sampler& sampler)
|
||||||
|
{
|
||||||
|
if (sampler.getVoxel() == 0) {
|
||||||
|
return true; // keep raycasting
|
||||||
|
}
|
||||||
|
PolyVox::Vector3DInt32 positionIndex = sampler.getPosition();
|
||||||
|
_result = glm::vec4(positionIndex.getX(), positionIndex.getY(), positionIndex.getZ(), 1.0f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glm::vec4 _result;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin,
|
||||||
|
const glm::vec3& direction,
|
||||||
|
bool& keepSearching,
|
||||||
|
OctreeElement*& element,
|
||||||
|
float& distance, BoxFace& face,
|
||||||
|
void** intersectedObject,
|
||||||
|
bool precisionPicking) const
|
||||||
|
{
|
||||||
|
if (_needsModelReload || !precisionPicking) {
|
||||||
|
// just intersect with bounding box
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 wtvMatrix = worldToVoxelMatrix();
|
||||||
|
glm::vec3 farPoint = origin + direction;
|
||||||
|
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
|
||||||
|
glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 1.0f);
|
||||||
|
glm::vec4 directionInVoxel = farInVoxel - originInVoxel;
|
||||||
|
|
||||||
|
PolyVox::Vector3DFloat start(originInVoxel[0], originInVoxel[1], originInVoxel[2]);
|
||||||
|
PolyVox::Vector3DFloat pvDirection(directionInVoxel[0], directionInVoxel[1], directionInVoxel[2]);
|
||||||
|
pvDirection.normalise();
|
||||||
|
|
||||||
|
// the PolyVox ray intersection code requires a near and far point.
|
||||||
|
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
|
||||||
|
float distanceToEntity = glm::distance(origin, _position);
|
||||||
|
float largestDimension = glm::max(_dimensions[0], _dimensions[1], _dimensions[2]);
|
||||||
|
// set ray cast length to long enough to cover all of the voxel space
|
||||||
|
pvDirection *= (distanceToEntity + largestDimension) / glm::min(scale[0], scale[1], scale[2]);
|
||||||
|
|
||||||
|
PolyVox::RaycastResult raycastResult;
|
||||||
|
RaycastFunctor callback;
|
||||||
|
raycastResult = PolyVox::raycastWithDirection(_volData, start, pvDirection, callback);
|
||||||
|
|
||||||
|
if (raycastResult == PolyVox::RaycastResults::Completed) {
|
||||||
|
// the ray completed its path -- nothing was hit.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * callback._result;
|
||||||
|
|
||||||
|
distance = glm::distance(glm::vec3(intersectedWorldPosition), origin);
|
||||||
|
|
||||||
|
face = BoxFace::MIN_X_FACE; // XXX
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// compress the data in _volData and save the results. The compressed form is used during
|
||||||
|
// saves to disk and for transmission over the wire
|
||||||
|
void RenderablePolyVoxEntityItem::compressVolumeData() {
|
||||||
|
int rawSize = _volData->getDepth() * _volData->getHeight() * _volData->getWidth();
|
||||||
|
QByteArray uncompressedData = QByteArray(rawSize, '\0');
|
||||||
|
|
||||||
|
for (int z = 0; z < _volData->getDepth(); z++) {
|
||||||
|
for (int y = 0; y < _volData->getHeight(); y++) {
|
||||||
|
for (int x = 0; x < _volData->getWidth(); x++) {
|
||||||
|
uint8_t uVoxelValue = _volData->getVoxelAt(x, y, z);
|
||||||
|
int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x;
|
||||||
|
uncompressedData[uncompressedIndex] = uVoxelValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray newVoxelData = qCompress(uncompressedData, 9);
|
||||||
|
// HACK -- until we have a way to allow for properties larger than MTU, don't update.
|
||||||
|
if (newVoxelData.length() < 1200) {
|
||||||
|
_voxelData = newVoxelData;
|
||||||
|
qDebug() << "-------------- voxel compresss --------------";
|
||||||
|
qDebug() << "raw-size =" << rawSize << " compressed-size =" << newVoxelData.size();
|
||||||
|
} else {
|
||||||
|
qDebug() << "voxel data too large, reverting change.";
|
||||||
|
// revert
|
||||||
|
decompressVolumeData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// take compressed data and decompreess it into _volData.
|
||||||
|
void RenderablePolyVoxEntityItem::decompressVolumeData() {
|
||||||
|
int rawSize = _volData->getDepth() * _volData->getHeight() * _volData->getWidth();
|
||||||
|
QByteArray uncompressedData = QByteArray(rawSize, '\0');
|
||||||
|
|
||||||
|
uncompressedData = qUncompress(_voxelData);
|
||||||
|
|
||||||
|
for (int z = 0; z < _volData->getDepth(); z++) {
|
||||||
|
for (int y = 0; y < _volData->getHeight(); y++) {
|
||||||
|
for (int x = 0; x < _volData->getWidth(); x++) {
|
||||||
|
int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x;
|
||||||
|
_volData->setVoxelAt(x, y, z, uncompressedData[uncompressedIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_needsModelReload = true;
|
||||||
|
|
||||||
|
qDebug() << "--------------- voxel decompress ---------------";
|
||||||
|
qDebug() << "raw-size =" << rawSize << " compressed-size =" << _voxelData.size();
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
//
|
||||||
|
// RenderablePolyVoxEntityItem.h
|
||||||
|
// libraries/entities-renderer/src/
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 5/19/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_RenderablePolyVoxEntityItem_h
|
||||||
|
#define hifi_RenderablePolyVoxEntityItem_h
|
||||||
|
|
||||||
|
#include <PolyVoxCore/SimpleVolume.h>
|
||||||
|
|
||||||
|
#include "PolyVoxEntityItem.h"
|
||||||
|
#include "RenderableDebugableEntityItem.h"
|
||||||
|
|
||||||
|
class RenderablePolyVoxEntityItem : public PolyVoxEntityItem {
|
||||||
|
public:
|
||||||
|
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
|
RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||||
|
PolyVoxEntityItem(entityItemID, properties) { }
|
||||||
|
|
||||||
|
virtual ~RenderablePolyVoxEntityItem();
|
||||||
|
|
||||||
|
virtual void somethingChangedNotification() {
|
||||||
|
// This gets called from EnityItem::readEntityDataFromBuffer every time a packet describing
|
||||||
|
// this entity comes from the entity-server. It gets called even if nothing has actually changed
|
||||||
|
// (see the comment in EntityItem.cpp). If that gets fixed, this could be used to know if we
|
||||||
|
// need to redo the voxel data.
|
||||||
|
// _needsModelReload = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void render(RenderArgs* args);
|
||||||
|
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||||
|
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||||
|
void** intersectedObject, bool precisionPicking) const;
|
||||||
|
|
||||||
|
void getModel();
|
||||||
|
|
||||||
|
virtual void setVoxelData(QByteArray voxelData);
|
||||||
|
|
||||||
|
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
|
||||||
|
glm::mat4 voxelToWorldMatrix() const;
|
||||||
|
glm::mat4 worldToVoxelMatrix() const;
|
||||||
|
|
||||||
|
// coords are in voxel-volume space
|
||||||
|
virtual void setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue);
|
||||||
|
|
||||||
|
// coords are in world-space
|
||||||
|
virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void compressVolumeData();
|
||||||
|
void decompressVolumeData();
|
||||||
|
|
||||||
|
PolyVox::SimpleVolume<uint8_t>* _volData = nullptr;
|
||||||
|
model::Geometry _modelGeometry;
|
||||||
|
bool _needsModelReload = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // hifi_RenderablePolyVoxEntityItem_h
|
|
@ -7,10 +7,14 @@ add_dependency_external_projects(glm)
|
||||||
find_package(GLM REQUIRED)
|
find_package(GLM REQUIRED)
|
||||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||||
|
|
||||||
add_dependency_external_projects(bullet)
|
add_dependency_external_projects(bullet polyvox)
|
||||||
|
|
||||||
find_package(Bullet REQUIRED)
|
find_package(Bullet REQUIRED)
|
||||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
||||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||||
|
|
||||||
|
find_package(PolyVox REQUIRED)
|
||||||
|
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})
|
||||||
|
|
||||||
link_hifi_libraries(avatars shared octree gpu model fbx networking animation environment)
|
link_hifi_libraries(avatars shared octree gpu model fbx networking animation environment)
|
||||||
|
|
|
@ -183,9 +183,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
||||||
QByteArray encodedPropertyFlags;
|
QByteArray encodedPropertyFlags;
|
||||||
int propertyCount = 0;
|
int propertyCount = 0;
|
||||||
|
|
||||||
successIDFits = packetData->appendValue(encodedID);
|
successIDFits = packetData->appendRawData(encodedID);
|
||||||
if (successIDFits) {
|
if (successIDFits) {
|
||||||
successTypeFits = packetData->appendValue(encodedType);
|
successTypeFits = packetData->appendRawData(encodedType);
|
||||||
}
|
}
|
||||||
if (successTypeFits) {
|
if (successTypeFits) {
|
||||||
successCreatedFits = packetData->appendValue(_created);
|
successCreatedFits = packetData->appendValue(_created);
|
||||||
|
@ -194,17 +194,17 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
||||||
successLastEditedFits = packetData->appendValue(lastEdited);
|
successLastEditedFits = packetData->appendValue(lastEdited);
|
||||||
}
|
}
|
||||||
if (successLastEditedFits) {
|
if (successLastEditedFits) {
|
||||||
successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
|
successLastUpdatedFits = packetData->appendRawData(encodedUpdateDelta);
|
||||||
}
|
}
|
||||||
if (successLastUpdatedFits) {
|
if (successLastUpdatedFits) {
|
||||||
successLastSimulatedFits = packetData->appendValue(encodedSimulatedDelta);
|
successLastSimulatedFits = packetData->appendRawData(encodedSimulatedDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (successLastSimulatedFits) {
|
if (successLastSimulatedFits) {
|
||||||
propertyFlagsOffset = packetData->getUncompressedByteOffset();
|
propertyFlagsOffset = packetData->getUncompressedByteOffset();
|
||||||
encodedPropertyFlags = propertyFlags;
|
encodedPropertyFlags = propertyFlags;
|
||||||
oldPropertyFlagsLength = encodedPropertyFlags.length();
|
oldPropertyFlagsLength = encodedPropertyFlags.length();
|
||||||
successPropertyFlagsFits = packetData->appendValue(encodedPropertyFlags);
|
successPropertyFlagsFits = packetData->appendRawData(encodedPropertyFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool headerFits = successIDFits && successTypeFits && successCreatedFits && successLastEditedFits
|
bool headerFits = successIDFits && successTypeFits && successCreatedFits && successLastEditedFits
|
||||||
|
@ -318,15 +318,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this bitstream indicates that this node is the simulation owner, ignore any physics-related updates.
|
|
||||||
glm::vec3 savePosition = _position;
|
|
||||||
glm::quat saveRotation = _rotation;
|
|
||||||
// glm::vec3 saveVelocity = _velocity;
|
|
||||||
// glm::vec3 saveAngularVelocity = _angularVelocity;
|
|
||||||
// glm::vec3 saveGravity = _gravity;
|
|
||||||
// glm::vec3 saveAcceleration = _acceleration;
|
|
||||||
|
|
||||||
|
|
||||||
// Header bytes
|
// Header bytes
|
||||||
// object ID [16 bytes]
|
// object ID [16 bytes]
|
||||||
// ByteCountCoded(type code) [~1 byte]
|
// ByteCountCoded(type code) [~1 byte]
|
||||||
|
@ -337,299 +328,308 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
const int MINIMUM_HEADER_BYTES = 27;
|
const int MINIMUM_HEADER_BYTES = 27;
|
||||||
|
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
if (bytesLeftToRead >= MINIMUM_HEADER_BYTES) {
|
if (bytesLeftToRead < MINIMUM_HEADER_BYTES) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int originalLength = bytesLeftToRead;
|
// if this bitstream indicates that this node is the simulation owner, ignore any physics-related updates.
|
||||||
QByteArray originalDataBuffer((const char*)data, originalLength);
|
glm::vec3 savePosition = _position;
|
||||||
|
glm::quat saveRotation = _rotation;
|
||||||
|
glm::vec3 saveVelocity = _velocity;
|
||||||
|
glm::vec3 saveAngularVelocity = _angularVelocity;
|
||||||
|
|
||||||
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
|
int originalLength = bytesLeftToRead;
|
||||||
|
QByteArray originalDataBuffer((const char*)data, originalLength);
|
||||||
|
|
||||||
const unsigned char* dataAt = data;
|
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
|
||||||
|
|
||||||
// id
|
const unsigned char* dataAt = data;
|
||||||
QByteArray encodedID = originalDataBuffer.mid(bytesRead, NUM_BYTES_RFC4122_UUID); // maximum possible size
|
|
||||||
_id = QUuid::fromRfc4122(encodedID);
|
|
||||||
dataAt += encodedID.size();
|
|
||||||
bytesRead += encodedID.size();
|
|
||||||
|
|
||||||
// type
|
|
||||||
QByteArray encodedType = originalDataBuffer.mid(bytesRead); // maximum possible size
|
|
||||||
ByteCountCoded<quint32> typeCoder = encodedType;
|
|
||||||
encodedType = typeCoder; // determine true length
|
|
||||||
dataAt += encodedType.size();
|
|
||||||
bytesRead += encodedType.size();
|
|
||||||
quint32 type = typeCoder;
|
|
||||||
_type = (EntityTypes::EntityType)type;
|
|
||||||
|
|
||||||
bool overwriteLocalData = true; // assume the new content overwrites our local data
|
// id
|
||||||
|
QByteArray encodedID = originalDataBuffer.mid(bytesRead, NUM_BYTES_RFC4122_UUID); // maximum possible size
|
||||||
|
_id = QUuid::fromRfc4122(encodedID);
|
||||||
|
dataAt += encodedID.size();
|
||||||
|
bytesRead += encodedID.size();
|
||||||
|
|
||||||
|
// type
|
||||||
|
QByteArray encodedType = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||||
|
ByteCountCoded<quint32> typeCoder = encodedType;
|
||||||
|
encodedType = typeCoder; // determine true length
|
||||||
|
dataAt += encodedType.size();
|
||||||
|
bytesRead += encodedType.size();
|
||||||
|
quint32 type = typeCoder;
|
||||||
|
_type = (EntityTypes::EntityType)type;
|
||||||
|
|
||||||
// _created
|
bool overwriteLocalData = true; // assume the new content overwrites our local data
|
||||||
quint64 createdFromBuffer = 0;
|
|
||||||
memcpy(&createdFromBuffer, dataAt, sizeof(createdFromBuffer));
|
|
||||||
dataAt += sizeof(createdFromBuffer);
|
|
||||||
bytesRead += sizeof(createdFromBuffer);
|
|
||||||
|
|
||||||
quint64 now = usecTimestampNow();
|
// _created
|
||||||
if (_created == UNKNOWN_CREATED_TIME) {
|
quint64 createdFromBuffer = 0;
|
||||||
// we don't yet have a _created timestamp, so we accept this one
|
memcpy(&createdFromBuffer, dataAt, sizeof(createdFromBuffer));
|
||||||
createdFromBuffer -= clockSkew;
|
dataAt += sizeof(createdFromBuffer);
|
||||||
if (createdFromBuffer > now || createdFromBuffer == UNKNOWN_CREATED_TIME) {
|
bytesRead += sizeof(createdFromBuffer);
|
||||||
createdFromBuffer = now;
|
|
||||||
}
|
quint64 now = usecTimestampNow();
|
||||||
_created = createdFromBuffer;
|
if (_created == UNKNOWN_CREATED_TIME) {
|
||||||
|
// we don't yet have a _created timestamp, so we accept this one
|
||||||
|
createdFromBuffer -= clockSkew;
|
||||||
|
if (createdFromBuffer > now || createdFromBuffer == UNKNOWN_CREATED_TIME) {
|
||||||
|
createdFromBuffer = now;
|
||||||
}
|
}
|
||||||
|
_created = createdFromBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
quint64 lastEdited = getLastEdited();
|
||||||
|
float editedAgo = getEditedAgo();
|
||||||
|
QString agoAsString = formatSecondsElapsed(editedAgo);
|
||||||
|
QString ageAsString = formatSecondsElapsed(getAge());
|
||||||
|
qCDebug(entities) << "------------------------------------------";
|
||||||
|
qCDebug(entities) << "Loading entity " << getEntityItemID() << " from buffer...";
|
||||||
|
qCDebug(entities) << "------------------------------------------";
|
||||||
|
debugDump();
|
||||||
|
qCDebug(entities) << "------------------------------------------";
|
||||||
|
qCDebug(entities) << " _created =" << _created;
|
||||||
|
qCDebug(entities) << " age=" << getAge() << "seconds - " << ageAsString;
|
||||||
|
qCDebug(entities) << " lastEdited =" << lastEdited;
|
||||||
|
qCDebug(entities) << " ago=" << editedAgo << "seconds - " << agoAsString;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
quint64 lastEditedFromBuffer = 0;
|
||||||
|
quint64 lastEditedFromBufferAdjusted = 0;
|
||||||
|
|
||||||
|
// TODO: we could make this encoded as a delta from _created
|
||||||
|
// _lastEdited
|
||||||
|
memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer));
|
||||||
|
dataAt += sizeof(lastEditedFromBuffer);
|
||||||
|
bytesRead += sizeof(lastEditedFromBuffer);
|
||||||
|
lastEditedFromBufferAdjusted = lastEditedFromBuffer - clockSkew;
|
||||||
|
if (lastEditedFromBufferAdjusted > now) {
|
||||||
|
lastEditedFromBufferAdjusted = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fromSameServerEdit = (lastEditedFromBuffer == _lastEditedFromRemoteInRemoteTime);
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
qCDebug(entities) << "data from server **************** ";
|
||||||
|
qCDebug(entities) << " entityItemID:" << getEntityItemID();
|
||||||
|
qCDebug(entities) << " now:" << now;
|
||||||
|
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||||
|
qCDebug(entities) << " lastEditedFromBuffer:" << debugTime(lastEditedFromBuffer, now);
|
||||||
|
qCDebug(entities) << " clockSkew:" << debugTimeOnly(clockSkew);
|
||||||
|
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
|
||||||
|
qCDebug(entities) << " _lastEditedFromRemote:" << debugTime(_lastEditedFromRemote, now);
|
||||||
|
qCDebug(entities) << " _lastEditedFromRemoteInRemoteTime:" << debugTime(_lastEditedFromRemoteInRemoteTime, now);
|
||||||
|
qCDebug(entities) << " fromSameServerEdit:" << fromSameServerEdit;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool ignoreServerPacket = false; // assume we'll use this server packet
|
||||||
|
|
||||||
|
// If this packet is from the same server edit as the last packet we accepted from the server
|
||||||
|
// we probably want to use it.
|
||||||
|
if (fromSameServerEdit) {
|
||||||
|
// If this is from the same sever packet, then check against any local changes since we got
|
||||||
|
// the most recent packet from this server time
|
||||||
|
if (_lastEdited > _lastEditedFromRemote) {
|
||||||
|
ignoreServerPacket = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If this isn't from the same sever packet, then honor our skew adjusted times...
|
||||||
|
// If we've changed our local tree more recently than the new data from this packet
|
||||||
|
// then we will not be changing our values, instead we just read and skip the data
|
||||||
|
if (_lastEdited > lastEditedFromBufferAdjusted) {
|
||||||
|
ignoreServerPacket = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoreServerPacket) {
|
||||||
|
overwriteLocalData = false;
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
quint64 lastEdited = getLastEdited();
|
qCDebug(entities) << "IGNORING old data from server!!! ****************";
|
||||||
float editedAgo = getEditedAgo();
|
|
||||||
QString agoAsString = formatSecondsElapsed(editedAgo);
|
|
||||||
QString ageAsString = formatSecondsElapsed(getAge());
|
|
||||||
qCDebug(entities) << "------------------------------------------";
|
|
||||||
qCDebug(entities) << "Loading entity " << getEntityItemID() << " from buffer...";
|
|
||||||
qCDebug(entities) << "------------------------------------------";
|
|
||||||
debugDump();
|
debugDump();
|
||||||
qCDebug(entities) << "------------------------------------------";
|
|
||||||
qCDebug(entities) << " _created =" << _created;
|
|
||||||
qCDebug(entities) << " age=" << getAge() << "seconds - " << ageAsString;
|
|
||||||
qCDebug(entities) << " lastEdited =" << lastEdited;
|
|
||||||
qCDebug(entities) << " ago=" << editedAgo << "seconds - " << agoAsString;
|
|
||||||
#endif
|
#endif
|
||||||
|
} else {
|
||||||
quint64 lastEditedFromBuffer = 0;
|
|
||||||
quint64 lastEditedFromBufferAdjusted = 0;
|
|
||||||
|
|
||||||
// TODO: we could make this encoded as a delta from _created
|
|
||||||
// _lastEdited
|
|
||||||
memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer));
|
|
||||||
dataAt += sizeof(lastEditedFromBuffer);
|
|
||||||
bytesRead += sizeof(lastEditedFromBuffer);
|
|
||||||
lastEditedFromBufferAdjusted = lastEditedFromBuffer - clockSkew;
|
|
||||||
if (lastEditedFromBufferAdjusted > now) {
|
|
||||||
lastEditedFromBufferAdjusted = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fromSameServerEdit = (lastEditedFromBuffer == _lastEditedFromRemoteInRemoteTime);
|
|
||||||
|
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
qCDebug(entities) << "data from server **************** ";
|
qCDebug(entities) << "USING NEW data from server!!! ****************";
|
||||||
qCDebug(entities) << " entityItemID:" << getEntityItemID();
|
debugDump();
|
||||||
qCDebug(entities) << " now:" << now;
|
|
||||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
|
||||||
qCDebug(entities) << " lastEditedFromBuffer:" << debugTime(lastEditedFromBuffer, now);
|
|
||||||
qCDebug(entities) << " clockSkew:" << debugTimeOnly(clockSkew);
|
|
||||||
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
|
|
||||||
qCDebug(entities) << " _lastEditedFromRemote:" << debugTime(_lastEditedFromRemote, now);
|
|
||||||
qCDebug(entities) << " _lastEditedFromRemoteInRemoteTime:" << debugTime(_lastEditedFromRemoteInRemoteTime, now);
|
|
||||||
qCDebug(entities) << " fromSameServerEdit:" << fromSameServerEdit;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool ignoreServerPacket = false; // assume we'll use this server packet
|
// don't allow _lastEdited to be in the future
|
||||||
|
_lastEdited = lastEditedFromBufferAdjusted;
|
||||||
// If this packet is from the same server edit as the last packet we accepted from the server
|
_lastEditedFromRemote = now;
|
||||||
// we probably want to use it.
|
_lastEditedFromRemoteInRemoteTime = lastEditedFromBuffer;
|
||||||
if (fromSameServerEdit) {
|
|
||||||
// If this is from the same sever packet, then check against any local changes since we got
|
|
||||||
// the most recent packet from this server time
|
|
||||||
if (_lastEdited > _lastEditedFromRemote) {
|
|
||||||
ignoreServerPacket = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If this isn't from the same sever packet, then honor our skew adjusted times...
|
|
||||||
// If we've changed our local tree more recently than the new data from this packet
|
|
||||||
// then we will not be changing our values, instead we just read and skip the data
|
|
||||||
if (_lastEdited > lastEditedFromBufferAdjusted) {
|
|
||||||
ignoreServerPacket = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ignoreServerPacket) {
|
// TODO: only send this notification if something ACTUALLY changed (hint, we haven't yet parsed
|
||||||
overwriteLocalData = false;
|
// the properties out of the bitstream (see below))
|
||||||
#ifdef WANT_DEBUG
|
somethingChangedNotification(); // notify derived classes that something has changed
|
||||||
qCDebug(entities) << "IGNORING old data from server!!! ****************";
|
}
|
||||||
debugDump();
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
|
|
||||||
#ifdef WANT_DEBUG
|
// last updated is stored as ByteCountCoded delta from lastEdited
|
||||||
qCDebug(entities) << "USING NEW data from server!!! ****************";
|
QByteArray encodedUpdateDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||||
debugDump();
|
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
|
||||||
#endif
|
quint64 updateDelta = updateDeltaCoder;
|
||||||
|
if (overwriteLocalData) {
|
||||||
// don't allow _lastEdited to be in the future
|
_lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that
|
||||||
_lastEdited = lastEditedFromBufferAdjusted;
|
#ifdef WANT_DEBUG
|
||||||
_lastEditedFromRemote = now;
|
qCDebug(entities) << " _lastUpdated:" << debugTime(_lastUpdated, now);
|
||||||
_lastEditedFromRemoteInRemoteTime = lastEditedFromBuffer;
|
qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now);
|
||||||
|
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
|
||||||
// TODO: only send this notification if something ACTUALLY changed (hint, we haven't yet parsed
|
#endif
|
||||||
// the properties out of the bitstream (see below))
|
}
|
||||||
somethingChangedNotification(); // notify derived classes that something has changed
|
encodedUpdateDelta = updateDeltaCoder; // determine true length
|
||||||
}
|
dataAt += encodedUpdateDelta.size();
|
||||||
|
bytesRead += encodedUpdateDelta.size();
|
||||||
// last updated is stored as ByteCountCoded delta from lastEdited
|
|
||||||
QByteArray encodedUpdateDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
|
// Newer bitstreams will have a last simulated and a last updated value
|
||||||
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
|
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) {
|
||||||
quint64 updateDelta = updateDeltaCoder;
|
// last simulated is stored as ByteCountCoded delta from lastEdited
|
||||||
|
QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||||
|
ByteCountCoded<quint64> simulatedDeltaCoder = encodedSimulatedDelta;
|
||||||
|
quint64 simulatedDelta = simulatedDeltaCoder;
|
||||||
if (overwriteLocalData) {
|
if (overwriteLocalData) {
|
||||||
_lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that
|
_lastSimulated = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
qCDebug(entities) << " _lastUpdated:" << debugTime(_lastUpdated, now);
|
qCDebug(entities) << " _lastSimulated:" << debugTime(_lastSimulated, now);
|
||||||
qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now);
|
qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now);
|
||||||
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
|
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
encodedUpdateDelta = updateDeltaCoder; // determine true length
|
encodedSimulatedDelta = simulatedDeltaCoder; // determine true length
|
||||||
dataAt += encodedUpdateDelta.size();
|
dataAt += encodedSimulatedDelta.size();
|
||||||
bytesRead += encodedUpdateDelta.size();
|
bytesRead += encodedSimulatedDelta.size();
|
||||||
|
}
|
||||||
// Newer bitstreams will have a last simulated and a last updated value
|
|
||||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) {
|
#ifdef WANT_DEBUG
|
||||||
// last simulated is stored as ByteCountCoded delta from lastEdited
|
if (overwriteLocalData) {
|
||||||
QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
|
qCDebug(entities) << "EntityItem::readEntityDataFromBuffer()... changed entity:" << getEntityItemID();
|
||||||
ByteCountCoded<quint64> simulatedDeltaCoder = encodedSimulatedDelta;
|
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||||
quint64 simulatedDelta = simulatedDeltaCoder;
|
qCDebug(entities) << " getLastSimulated:" << debugTime(getLastSimulated(), now);
|
||||||
|
qCDebug(entities) << " getLastUpdated:" << debugTime(getLastUpdated(), now);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Property Flags
|
||||||
|
QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||||
|
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
|
||||||
|
dataAt += propertyFlags.getEncodedLength();
|
||||||
|
bytesRead += propertyFlags.getEncodedLength();
|
||||||
|
bool useMeters = (args.bitstreamVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS);
|
||||||
|
if (useMeters) {
|
||||||
|
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
|
||||||
|
} else {
|
||||||
|
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionInDomainUnits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS
|
||||||
|
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) {
|
||||||
|
if (propertyFlags.getHasProperty(PROP_RADIUS)) {
|
||||||
|
float fromBuffer;
|
||||||
|
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer));
|
||||||
|
dataAt += sizeof(fromBuffer);
|
||||||
|
bytesRead += sizeof(fromBuffer);
|
||||||
if (overwriteLocalData) {
|
if (overwriteLocalData) {
|
||||||
_lastSimulated = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that
|
setRadius(fromBuffer);
|
||||||
#ifdef WANT_DEBUG
|
|
||||||
qCDebug(entities) << " _lastSimulated:" << debugTime(_lastSimulated, now);
|
|
||||||
qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now);
|
|
||||||
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
encodedSimulatedDelta = simulatedDeltaCoder; // determine true length
|
|
||||||
dataAt += encodedSimulatedDelta.size();
|
|
||||||
bytesRead += encodedSimulatedDelta.size();
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
#ifdef WANT_DEBUG
|
|
||||||
if (overwriteLocalData) {
|
|
||||||
qCDebug(entities) << "EntityItem::readEntityDataFromBuffer()... changed entity:" << getEntityItemID();
|
|
||||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
|
||||||
qCDebug(entities) << " getLastSimulated:" << debugTime(getLastSimulated(), now);
|
|
||||||
qCDebug(entities) << " getLastUpdated:" << debugTime(getLastUpdated(), now);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Property Flags
|
|
||||||
QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size
|
|
||||||
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
|
|
||||||
dataAt += propertyFlags.getEncodedLength();
|
|
||||||
bytesRead += propertyFlags.getEncodedLength();
|
|
||||||
bool useMeters = (args.bitstreamVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS);
|
|
||||||
if (useMeters) {
|
if (useMeters) {
|
||||||
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
|
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
|
||||||
} else {
|
} else {
|
||||||
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionInDomainUnits);
|
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensionsInDomainUnits);
|
||||||
}
|
|
||||||
|
|
||||||
// Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS
|
|
||||||
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) {
|
|
||||||
if (propertyFlags.getHasProperty(PROP_RADIUS)) {
|
|
||||||
float fromBuffer;
|
|
||||||
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer));
|
|
||||||
dataAt += sizeof(fromBuffer);
|
|
||||||
bytesRead += sizeof(fromBuffer);
|
|
||||||
if (overwriteLocalData) {
|
|
||||||
setRadius(fromBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (useMeters) {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
|
|
||||||
} else {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensionsInDomainUnits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity);
|
|
||||||
if (useMeters) {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity);
|
|
||||||
} else {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocityInDomainUnits);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravityInDomainUnits);
|
|
||||||
}
|
|
||||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration);
|
|
||||||
}
|
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
|
|
||||||
if (useMeters) {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
|
|
||||||
} else {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees);
|
|
||||||
}
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData);
|
|
||||||
|
|
||||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_SIMULATOR_ID, QUuid, updateSimulatorID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
|
||||||
}
|
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
|
|
||||||
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
|
||||||
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
|
|
||||||
|
|
||||||
////////////////////////////////////
|
|
||||||
// WARNING: Do not add stream content here after the subclass. Always add it before the subclass
|
|
||||||
//
|
|
||||||
// NOTE: we had a bad version of the stream that we added stream data after the subclass. We can attempt to recover
|
|
||||||
// by doing this parsing here... but it's not likely going to fully recover the content.
|
|
||||||
//
|
|
||||||
// TODO: Remove this conde once we've sufficiently migrated content past this damaged version
|
|
||||||
if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES))) {
|
|
||||||
// NOTE: This code is attempting to "repair" the old data we just got from the server to make it more
|
|
||||||
// closely match where the entities should be if they'd stepped forward in time to "now". The server
|
|
||||||
// is sending us data with a known "last simulated" time. That time is likely in the past, and therefore
|
|
||||||
// this "new" data is actually slightly out of date. We calculate the time we need to skip forward and
|
|
||||||
// use our simulation helper routine to get a best estimate of where the entity should be.
|
|
||||||
const float MIN_TIME_SKIP = 0.0f;
|
|
||||||
const float MAX_TIME_SKIP = 1.0f; // in seconds
|
|
||||||
float skipTimeForward = glm::clamp((float)(now - _lastSimulated) / (float)(USECS_PER_SECOND),
|
|
||||||
MIN_TIME_SKIP, MAX_TIME_SKIP);
|
|
||||||
if (skipTimeForward > 0.0f) {
|
|
||||||
#ifdef WANT_DEBUG
|
|
||||||
qCDebug(entities) << "skipTimeForward:" << skipTimeForward;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// we want to extrapolate the motion forward to compensate for packet travel time, but
|
|
||||||
// we don't want the side effect of flag setting.
|
|
||||||
simulateKinematicMotion(skipTimeForward, false);
|
|
||||||
}
|
|
||||||
_lastSimulated = now;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity);
|
||||||
|
if (useMeters) {
|
||||||
|
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity);
|
||||||
|
} else {
|
||||||
|
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocityInDomainUnits);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravityInDomainUnits);
|
||||||
|
}
|
||||||
|
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
|
||||||
|
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration);
|
||||||
|
}
|
||||||
|
|
||||||
|
READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
|
||||||
|
if (useMeters) {
|
||||||
|
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
|
||||||
|
} else {
|
||||||
|
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees);
|
||||||
|
}
|
||||||
|
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData);
|
||||||
|
|
||||||
|
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
|
||||||
|
// we always accept the server's notion of simulatorID, so we fake overwriteLocalData as true
|
||||||
|
// before we try to READ_ENTITY_PROPERTY it
|
||||||
|
bool temp = overwriteLocalData;
|
||||||
|
overwriteLocalData = true;
|
||||||
|
READ_ENTITY_PROPERTY(PROP_SIMULATOR_ID, QUuid, updateSimulatorID);
|
||||||
|
overwriteLocalData = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) {
|
||||||
|
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
||||||
|
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
|
||||||
|
|
||||||
|
////////////////////////////////////
|
||||||
|
// WARNING: Do not add stream content here after the subclass. Always add it before the subclass
|
||||||
|
//
|
||||||
|
// NOTE: we had a bad version of the stream that we added stream data after the subclass. We can attempt to recover
|
||||||
|
// by doing this parsing here... but it's not likely going to fully recover the content.
|
||||||
|
//
|
||||||
|
// TODO: Remove this conde once we've sufficiently migrated content past this damaged version
|
||||||
|
if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) {
|
||||||
|
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES))) {
|
||||||
|
// NOTE: This code is attempting to "repair" the old data we just got from the server to make it more
|
||||||
|
// closely match where the entities should be if they'd stepped forward in time to "now". The server
|
||||||
|
// is sending us data with a known "last simulated" time. That time is likely in the past, and therefore
|
||||||
|
// this "new" data is actually slightly out of date. We calculate the time we need to skip forward and
|
||||||
|
// use our simulation helper routine to get a best estimate of where the entity should be.
|
||||||
|
const float MIN_TIME_SKIP = 0.0f;
|
||||||
|
const float MAX_TIME_SKIP = 1.0f; // in seconds
|
||||||
|
float skipTimeForward = glm::clamp((float)(now - _lastSimulated) / (float)(USECS_PER_SECOND),
|
||||||
|
MIN_TIME_SKIP, MAX_TIME_SKIP);
|
||||||
|
if (skipTimeForward > 0.0f) {
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
qCDebug(entities) << "skipTimeForward:" << skipTimeForward;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// we want to extrapolate the motion forward to compensate for packet travel time, but
|
||||||
|
// we don't want the side effect of flag setting.
|
||||||
|
simulateKinematicMotion(skipTimeForward, false);
|
||||||
|
}
|
||||||
|
_lastSimulated = now;
|
||||||
|
}
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
const QUuid& myNodeID = nodeList->getSessionUUID();
|
const QUuid& myNodeID = nodeList->getSessionUUID();
|
||||||
if (_simulatorID == myNodeID && !_simulatorID.isNull()) {
|
if (overwriteLocalData && _simulatorID == myNodeID && !_simulatorID.isNull()) {
|
||||||
// the packet that produced this bitstream originally came from physics simulations performed by
|
// we own the simulation, so we keep our transform+velocities and remove any related dirty flags
|
||||||
// this node, so our version has to be newer than what the packet contained.
|
// rather than accept the values in the packet
|
||||||
_position = savePosition;
|
_position = savePosition;
|
||||||
_rotation = saveRotation;
|
_rotation = saveRotation;
|
||||||
// _velocity = saveVelocity;
|
_velocity = saveVelocity;
|
||||||
// _angularVelocity = saveAngularVelocity;
|
_angularVelocity = saveAngularVelocity;
|
||||||
// _gravity = saveGravity;
|
_dirtyFlags &= ~(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES);
|
||||||
// _acceleration = saveAcceleration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
|
@ -652,6 +652,7 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
|
||||||
// lastEdited
|
// lastEdited
|
||||||
quint64 lastEditedInLocalTime;
|
quint64 lastEditedInLocalTime;
|
||||||
memcpy(&lastEditedInLocalTime, dataAt, sizeof(lastEditedInLocalTime));
|
memcpy(&lastEditedInLocalTime, dataAt, sizeof(lastEditedInLocalTime));
|
||||||
|
assert(lastEditedInLocalTime > 0);
|
||||||
quint64 lastEditedInServerTime = lastEditedInLocalTime + clockSkew;
|
quint64 lastEditedInServerTime = lastEditedInLocalTime + clockSkew;
|
||||||
memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime));
|
memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime));
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
|
@ -948,40 +949,25 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName);
|
||||||
|
|
||||||
if (somethingChanged) {
|
if (somethingChanged) {
|
||||||
somethingChangedNotification(); // notify derived classes that something has changed
|
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
int elapsed = now - getLastEdited();
|
int elapsed = now - getLastEdited();
|
||||||
qCDebug(entities) << "EntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
|
qCDebug(entities) << "EntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
|
||||||
"now=" << now << " getLastEdited()=" << getLastEdited();
|
"now=" << now << " getLastEdited()=" << getLastEdited();
|
||||||
#endif
|
#endif
|
||||||
if (_created != UNKNOWN_CREATED_TIME) {
|
setLastEdited(now);
|
||||||
setLastEdited(now);
|
somethingChangedNotification(); // notify derived classes that something has changed
|
||||||
|
if (_created == UNKNOWN_CREATED_TIME) {
|
||||||
|
_created = now;
|
||||||
}
|
}
|
||||||
if (getDirtyFlags() & (EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES)) {
|
if (getDirtyFlags() & (EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES)) {
|
||||||
// TODO: Andrew & Brad to discuss. Is this correct? Maybe it is. Need to think through all cases.
|
// anything that sets the transform or velocity must update _lastSimulated which is used
|
||||||
|
// for kinematic extrapolation (e.g. we want to extrapolate forward from this moment
|
||||||
|
// when position and/or velocity was changed).
|
||||||
_lastSimulated = now;
|
_lastSimulated = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// timestamps
|
|
||||||
quint64 timestamp = properties.getCreated();
|
|
||||||
if (_created == UNKNOWN_CREATED_TIME && timestamp != UNKNOWN_CREATED_TIME) {
|
|
||||||
quint64 now = usecTimestampNow();
|
|
||||||
if (timestamp > now) {
|
|
||||||
timestamp = now;
|
|
||||||
}
|
|
||||||
_created = timestamp;
|
|
||||||
|
|
||||||
timestamp = properties.getLastEdited();
|
|
||||||
if (timestamp > now) {
|
|
||||||
timestamp = now;
|
|
||||||
} else if (timestamp < _created) {
|
|
||||||
timestamp = _created;
|
|
||||||
}
|
|
||||||
_lastEdited = timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return somethingChanged;
|
return somethingChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "ParticleEffectEntityItem.h"
|
#include "ParticleEffectEntityItem.h"
|
||||||
#include "TextEntityItem.h"
|
#include "TextEntityItem.h"
|
||||||
#include "ZoneEntityItem.h"
|
#include "ZoneEntityItem.h"
|
||||||
|
#include "PolyVoxEntityItem.h"
|
||||||
|
|
||||||
AtmospherePropertyGroup EntityItemProperties::_staticAtmosphere;
|
AtmospherePropertyGroup EntityItemProperties::_staticAtmosphere;
|
||||||
SkyboxPropertyGroup EntityItemProperties::_staticSkybox;
|
SkyboxPropertyGroup EntityItemProperties::_staticSkybox;
|
||||||
|
@ -87,10 +88,14 @@ CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR),
|
||||||
CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY),
|
CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY),
|
||||||
CONSTRUCT_PROPERTY(keyLightAmbientIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY),
|
CONSTRUCT_PROPERTY(keyLightAmbientIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY),
|
||||||
CONSTRUCT_PROPERTY(keyLightDirection, ZoneEntityItem::DEFAULT_KEYLIGHT_DIRECTION),
|
CONSTRUCT_PROPERTY(keyLightDirection, ZoneEntityItem::DEFAULT_KEYLIGHT_DIRECTION),
|
||||||
|
CONSTRUCT_PROPERTY(voxelVolumeSize, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE),
|
||||||
|
CONSTRUCT_PROPERTY(voxelData, PolyVoxEntityItem::DEFAULT_VOXEL_DATA),
|
||||||
|
CONSTRUCT_PROPERTY(voxelSurfaceStyle, PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE),
|
||||||
CONSTRUCT_PROPERTY(name, ENTITY_ITEM_DEFAULT_NAME),
|
CONSTRUCT_PROPERTY(name, ENTITY_ITEM_DEFAULT_NAME),
|
||||||
CONSTRUCT_PROPERTY(backgroundMode, BACKGROUND_MODE_INHERIT),
|
CONSTRUCT_PROPERTY(backgroundMode, BACKGROUND_MODE_INHERIT),
|
||||||
CONSTRUCT_PROPERTY(sourceUrl, ""),
|
CONSTRUCT_PROPERTY(sourceUrl, ""),
|
||||||
|
|
||||||
|
|
||||||
_id(UNKNOWN_ENTITY_ID),
|
_id(UNKNOWN_ENTITY_ID),
|
||||||
_idSet(false),
|
_idSet(false),
|
||||||
_lastEdited(0),
|
_lastEdited(0),
|
||||||
|
@ -336,6 +341,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||||
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_DIRECTION, keyLightDirection);
|
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_DIRECTION, keyLightDirection);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode);
|
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl);
|
CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_VOXEL_DATA, voxelData);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle);
|
||||||
|
|
||||||
changedProperties += _stage.getChangedProperties();
|
changedProperties += _stage.getChangedProperties();
|
||||||
changedProperties += _atmosphere.getChangedProperties();
|
changedProperties += _atmosphere.getChangedProperties();
|
||||||
|
@ -418,6 +426,10 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString());
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString());
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl);
|
||||||
|
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelVolumeSize);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelData);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelSurfaceStyle);
|
||||||
|
|
||||||
// Sitting properties support
|
// Sitting properties support
|
||||||
if (!skipDefaults) {
|
if (!skipDefaults) {
|
||||||
|
@ -523,7 +535,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightDirection, glmVec3, setKeyLightDirection);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightDirection, glmVec3, setKeyLightDirection);
|
||||||
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(backgroundMode, BackgroundMode);
|
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(backgroundMode, BackgroundMode);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
|
||||||
|
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelSurfaceStyle, uint16_t, setVoxelSurfaceStyle);
|
||||||
|
|
||||||
_stage.copyFromScriptValue(object, _defaultSettings);
|
_stage.copyFromScriptValue(object, _defaultSettings);
|
||||||
_atmosphere.copyFromScriptValue(object, _defaultSettings);
|
_atmosphere.copyFromScriptValue(object, _defaultSettings);
|
||||||
_skybox.copyFromScriptValue(object, _defaultSettings);
|
_skybox.copyFromScriptValue(object, _defaultSettings);
|
||||||
|
@ -619,23 +635,23 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
||||||
quint64 lastEdited = properties.getLastEdited();
|
quint64 lastEdited = properties.getLastEdited();
|
||||||
bool successLastEditedFits = packetData->appendValue(lastEdited);
|
bool successLastEditedFits = packetData->appendValue(lastEdited);
|
||||||
|
|
||||||
bool successIDFits = packetData->appendValue(encodedID);
|
bool successIDFits = packetData->appendRawData(encodedID);
|
||||||
if (successIDFits) {
|
if (successIDFits) {
|
||||||
successIDFits = packetData->appendValue(encodedToken);
|
successIDFits = packetData->appendRawData(encodedToken);
|
||||||
}
|
}
|
||||||
bool successTypeFits = packetData->appendValue(encodedType);
|
bool successTypeFits = packetData->appendRawData(encodedType);
|
||||||
|
|
||||||
// NOTE: We intentionally do not send "created" times in edit messages. This is because:
|
// NOTE: We intentionally do not send "created" times in edit messages. This is because:
|
||||||
// 1) if the edit is to an existing entity, the created time can not be changed
|
// 1) if the edit is to an existing entity, the created time can not be changed
|
||||||
// 2) if the edit is to a new entity, the created time is the last edited time
|
// 2) if the edit is to a new entity, the created time is the last edited time
|
||||||
|
|
||||||
// TODO: Should we get rid of this in this in edit packets, since this has to always be 0?
|
// TODO: Should we get rid of this in this in edit packets, since this has to always be 0?
|
||||||
bool successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
|
bool successLastUpdatedFits = packetData->appendRawData(encodedUpdateDelta);
|
||||||
|
|
||||||
int propertyFlagsOffset = packetData->getUncompressedByteOffset();
|
int propertyFlagsOffset = packetData->getUncompressedByteOffset();
|
||||||
QByteArray encodedPropertyFlags = propertyFlags;
|
QByteArray encodedPropertyFlags = propertyFlags;
|
||||||
int oldPropertyFlagsLength = encodedPropertyFlags.length();
|
int oldPropertyFlagsLength = encodedPropertyFlags.length();
|
||||||
bool successPropertyFlagsFits = packetData->appendValue(encodedPropertyFlags);
|
bool successPropertyFlagsFits = packetData->appendRawData(encodedPropertyFlags);
|
||||||
int propertyCount = 0;
|
int propertyCount = 0;
|
||||||
|
|
||||||
bool headerFits = successIDFits && successTypeFits && successLastEditedFits
|
bool headerFits = successIDFits && successTypeFits && successLastEditedFits
|
||||||
|
@ -740,6 +756,12 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
||||||
_staticSkybox.setProperties(properties);
|
_staticSkybox.setProperties(properties);
|
||||||
_staticSkybox.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
|
_staticSkybox.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (properties.getType() == EntityTypes::PolyVox) {
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, properties.getVoxelVolumeSize());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_VOXEL_DATA, properties.getVoxelData());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, properties.getVoxelSurfaceStyle());
|
||||||
|
}
|
||||||
|
|
||||||
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
|
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
|
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
|
||||||
|
@ -974,11 +996,17 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
||||||
properties.getAtmosphere().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
|
properties.getAtmosphere().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
|
||||||
properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
|
properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (properties.getType() == EntityTypes::PolyVox) {
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_VOLUME_SIZE, glm::vec3, setVoxelVolumeSize);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_DATA, QByteArray, setVoxelData);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle);
|
||||||
|
}
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,6 +1107,10 @@ void EntityItemProperties::markAllChanged() {
|
||||||
_skybox.markAllChanged();
|
_skybox.markAllChanged();
|
||||||
|
|
||||||
_sourceUrlChanged = true;
|
_sourceUrlChanged = true;
|
||||||
|
|
||||||
|
_voxelVolumeSizeChanged = true;
|
||||||
|
_voxelDataChanged = true;
|
||||||
|
_voxelSurfaceStyleChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The maximum bounding cube for the entity, independent of it's rotation.
|
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||||
|
|
|
@ -54,6 +54,7 @@ class EntityItemProperties {
|
||||||
friend class ZoneEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class ZoneEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||||
friend class WebEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class WebEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||||
friend class LineEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class LineEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||||
|
friend class PolyVoxEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||||
public:
|
public:
|
||||||
EntityItemProperties();
|
EntityItemProperties();
|
||||||
virtual ~EntityItemProperties();
|
virtual ~EntityItemProperties();
|
||||||
|
@ -135,6 +136,9 @@ public:
|
||||||
DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
|
DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
|
||||||
DEFINE_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float);
|
DEFINE_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float);
|
||||||
DEFINE_PROPERTY_REF(PROP_KEYLIGHT_DIRECTION, KeyLightDirection, keyLightDirection, glm::vec3);
|
DEFINE_PROPERTY_REF(PROP_KEYLIGHT_DIRECTION, KeyLightDirection, keyLightDirection, glm::vec3);
|
||||||
|
DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3);
|
||||||
|
DEFINE_PROPERTY_REF(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray);
|
||||||
|
DEFINE_PROPERTY_REF(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t);
|
||||||
DEFINE_PROPERTY_REF(PROP_NAME, Name, name, QString);
|
DEFINE_PROPERTY_REF(PROP_NAME, Name, name, QString);
|
||||||
DEFINE_PROPERTY_REF_ENUM(PROP_BACKGROUND_MODE, BackgroundMode, backgroundMode, BackgroundMode);
|
DEFINE_PROPERTY_REF_ENUM(PROP_BACKGROUND_MODE, BackgroundMode, backgroundMode, BackgroundMode);
|
||||||
DEFINE_PROPERTY_GROUP(Stage, stage, StagePropertyGroup);
|
DEFINE_PROPERTY_GROUP(Stage, stage, StagePropertyGroup);
|
||||||
|
@ -189,6 +193,8 @@ public:
|
||||||
|
|
||||||
QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); }
|
QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); }
|
||||||
|
|
||||||
|
void setVoxelDataDirty() { _voxelDataChanged = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUuid _id;
|
QUuid _id;
|
||||||
bool _idSet;
|
bool _idSet;
|
||||||
|
@ -219,7 +225,6 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP
|
||||||
inline void EntityItemProperties::setPosition(const glm::vec3& value)
|
inline void EntityItemProperties::setPosition(const glm::vec3& value)
|
||||||
{ _position = glm::clamp(value, 0.0f, (float)TREE_SCALE); _positionChanged = true; }
|
{ _position = glm::clamp(value, 0.0f, (float)TREE_SCALE); _positionChanged = true; }
|
||||||
|
|
||||||
|
|
||||||
inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
||||||
debug << "EntityItemProperties[" << "\n";
|
debug << "EntityItemProperties[" << "\n";
|
||||||
|
|
||||||
|
@ -281,6 +286,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, "");
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, "");
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, "");
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, "");
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, "");
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, "");
|
||||||
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, "");
|
||||||
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelData, voxelData, "");
|
||||||
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelSurfaceStyle, voxelSurfaceStyle, "");
|
||||||
|
|
||||||
properties.getStage().debugDump();
|
properties.getStage().debugDump();
|
||||||
properties.getAtmosphere().debugDump();
|
properties.getAtmosphere().debugDump();
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#define READ_ENTITY_PROPERTY(P,T,S) \
|
#define READ_ENTITY_PROPERTY(P,T,S) \
|
||||||
if (propertyFlags.getHasProperty(P)) { \
|
if (propertyFlags.getHasProperty(P)) { \
|
||||||
T fromBuffer; \
|
T fromBuffer; \
|
||||||
int bytes = OctreePacketData::uppackDataFromBytes(dataAt, fromBuffer); \
|
int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); \
|
||||||
dataAt += bytes; \
|
dataAt += bytes; \
|
||||||
bytesRead += bytes; \
|
bytesRead += bytes; \
|
||||||
if (overwriteLocalData) { \
|
if (overwriteLocalData) { \
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
#define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \
|
#define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \
|
||||||
if (propertyFlags.getHasProperty(P)) { \
|
if (propertyFlags.getHasProperty(P)) { \
|
||||||
T fromBuffer; \
|
T fromBuffer; \
|
||||||
int bytes = OctreePacketData::uppackDataFromBytes(dataAt, fromBuffer); \
|
int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); \
|
||||||
dataAt += bytes; \
|
dataAt += bytes; \
|
||||||
processedBytes += bytes; \
|
processedBytes += bytes; \
|
||||||
properties.O(fromBuffer); \
|
properties.O(fromBuffer); \
|
||||||
|
@ -91,10 +91,18 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScri
|
||||||
inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); }
|
inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); }
|
||||||
inline QScriptValue convertScriptValue(QScriptEngine* e, quint32 v) { return QScriptValue(v); }
|
inline QScriptValue convertScriptValue(QScriptEngine* e, quint32 v) { return QScriptValue(v); }
|
||||||
inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { return QScriptValue(v); }
|
inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { return QScriptValue(v); }
|
||||||
|
|
||||||
inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { return xColorToScriptValue(e, v); }
|
inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { return xColorToScriptValue(e, v); }
|
||||||
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); }
|
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); }
|
||||||
inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; }
|
inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; }
|
||||||
|
|
||||||
|
inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
|
||||||
|
QByteArray b64 = v.toBase64();
|
||||||
|
return QScriptValue(QString(b64));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
|
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
|
||||||
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
|
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
|
||||||
QScriptValue groupProperties = properties.property(#g); \
|
QScriptValue groupProperties = properties.property(#g); \
|
||||||
|
@ -129,6 +137,16 @@ inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { re
|
||||||
inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }
|
inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }
|
||||||
inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); }
|
inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); }
|
||||||
inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
|
inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
|
||||||
|
|
||||||
|
|
||||||
|
inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||||
|
isValid = true;
|
||||||
|
QString b64 = v.toVariant().toString().trimmed();
|
||||||
|
return QByteArray::fromBase64(b64.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||||
isValid = false; /// assume it can't be converted
|
isValid = false; /// assume it can't be converted
|
||||||
QScriptValue x = v.property("x");
|
QScriptValue x = v.property("x");
|
||||||
|
|
|
@ -110,6 +110,10 @@ enum EntityPropertyList {
|
||||||
PROP_RESTITUTION,
|
PROP_RESTITUTION,
|
||||||
PROP_FRICTION,
|
PROP_FRICTION,
|
||||||
|
|
||||||
|
PROP_VOXEL_VOLUME_SIZE,
|
||||||
|
PROP_VOXEL_DATA,
|
||||||
|
PROP_VOXEL_SURFACE_STYLE,
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// ATTENTION: add new properties ABOVE this line
|
// ATTENTION: add new properties ABOVE this line
|
||||||
PROP_AFTER_LAST_ITEM,
|
PROP_AFTER_LAST_ITEM,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "ModelEntityItem.h"
|
#include "ModelEntityItem.h"
|
||||||
#include "ZoneEntityItem.h"
|
#include "ZoneEntityItem.h"
|
||||||
#include "EntitiesLogging.h"
|
#include "EntitiesLogging.h"
|
||||||
|
#include "PolyVoxEntityItem.h"
|
||||||
|
|
||||||
|
|
||||||
EntityScriptingInterface::EntityScriptingInterface() :
|
EntityScriptingInterface::EntityScriptingInterface() :
|
||||||
|
@ -382,3 +383,40 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra
|
||||||
vec3FromScriptValue(intersection, value.intersection);
|
vec3FromScriptValue(intersection, value.intersection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
|
||||||
|
if (!_entityTree) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
|
||||||
|
if (!entity) {
|
||||||
|
qCDebug(entities) << "EntityScriptingInterface::setVoxelSphere no entity with ID" << entityID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityTypes::EntityType entityType = entity->getType();
|
||||||
|
if (entityType != EntityTypes::PolyVox) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
|
||||||
|
PolyVoxEntityItem* polyVoxEntity = static_cast<PolyVoxEntityItem*>(entity.get());
|
||||||
|
_entityTree->lockForWrite();
|
||||||
|
polyVoxEntity->setSphere(center, radius, value);
|
||||||
|
entity->setLastEdited(now);
|
||||||
|
entity->setLastBroadcast(now);
|
||||||
|
_entityTree->unlock();
|
||||||
|
|
||||||
|
_entityTree->lockForRead();
|
||||||
|
EntityItemProperties properties = entity->getProperties();
|
||||||
|
_entityTree->unlock();
|
||||||
|
|
||||||
|
properties.setVoxelDataDirty();
|
||||||
|
properties.setLastEdited(now);
|
||||||
|
|
||||||
|
queueEntityMessage(PacketTypeEntityEdit, entityID, properties);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -117,6 +117,8 @@ public slots:
|
||||||
Q_INVOKABLE void setSendPhysicsUpdates(bool value);
|
Q_INVOKABLE void setSendPhysicsUpdates(bool value);
|
||||||
Q_INVOKABLE bool getSendPhysicsUpdates() const;
|
Q_INVOKABLE bool getSendPhysicsUpdates() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value);
|
||||||
|
|
||||||
Q_INVOKABLE void dumpTree() const;
|
Q_INVOKABLE void dumpTree() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "WebEntityItem.h"
|
#include "WebEntityItem.h"
|
||||||
#include "ZoneEntityItem.h"
|
#include "ZoneEntityItem.h"
|
||||||
#include "LineEntityItem.h"
|
#include "LineEntityItem.h"
|
||||||
|
#include "PolyVoxEntityItem.h"
|
||||||
|
|
||||||
QMap<EntityTypes::EntityType, QString> EntityTypes::_typeToNameMap;
|
QMap<EntityTypes::EntityType, QString> EntityTypes::_typeToNameMap;
|
||||||
QMap<QString, EntityTypes::EntityType> EntityTypes::_nameToTypeMap;
|
QMap<QString, EntityTypes::EntityType> EntityTypes::_nameToTypeMap;
|
||||||
|
@ -45,6 +46,7 @@ REGISTER_ENTITY_TYPE(Text)
|
||||||
REGISTER_ENTITY_TYPE(ParticleEffect)
|
REGISTER_ENTITY_TYPE(ParticleEffect)
|
||||||
REGISTER_ENTITY_TYPE(Zone)
|
REGISTER_ENTITY_TYPE(Zone)
|
||||||
REGISTER_ENTITY_TYPE(Line)
|
REGISTER_ENTITY_TYPE(Line)
|
||||||
|
REGISTER_ENTITY_TYPE(PolyVox)
|
||||||
|
|
||||||
const QString& EntityTypes::getEntityTypeName(EntityType entityType) {
|
const QString& EntityTypes::getEntityTypeName(EntityType entityType) {
|
||||||
QMap<EntityType, QString>::iterator matchedTypeName = _typeToNameMap.find(entityType);
|
QMap<EntityType, QString>::iterator matchedTypeName = _typeToNameMap.find(entityType);
|
||||||
|
|
|
@ -45,7 +45,8 @@ public:
|
||||||
Zone,
|
Zone,
|
||||||
Web,
|
Web,
|
||||||
Line,
|
Line,
|
||||||
LAST = Line
|
PolyVox,
|
||||||
|
LAST = PolyVox
|
||||||
} EntityType;
|
} EntityType;
|
||||||
|
|
||||||
static const QString& getEntityTypeName(EntityType entityType);
|
static const QString& getEntityTypeName(EntityType entityType);
|
||||||
|
|
117
libraries/entities/src/PolyVoxEntityItem.cpp
Normal file
117
libraries/entities/src/PolyVoxEntityItem.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
//
|
||||||
|
// PolyVoxEntityItem.cpp
|
||||||
|
// libraries/entities/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 5/11/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <ByteCountCoding.h>
|
||||||
|
|
||||||
|
#include "PolyVoxEntityItem.h"
|
||||||
|
#include "EntityTree.h"
|
||||||
|
#include "EntitiesLogging.h"
|
||||||
|
#include "EntityTreeElement.h"
|
||||||
|
|
||||||
|
|
||||||
|
const glm::vec3 PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE = glm::vec3(32, 32, 32);
|
||||||
|
const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(qCompress(QByteArray(0), 9));
|
||||||
|
const PolyVoxEntityItem::PolyVoxSurfaceStyle PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE =
|
||||||
|
PolyVoxEntityItem::SURFACE_MARCHING_CUBES;
|
||||||
|
|
||||||
|
EntityItemPointer PolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
|
return EntityItemPointer(new PolyVoxEntityItem(entityID, properties));
|
||||||
|
}
|
||||||
|
|
||||||
|
PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||||
|
EntityItem(entityItemID),
|
||||||
|
_voxelVolumeSize(PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE),
|
||||||
|
_voxelData(PolyVoxEntityItem::DEFAULT_VOXEL_DATA),
|
||||||
|
_voxelSurfaceStyle(PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE)
|
||||||
|
{
|
||||||
|
_type = EntityTypes::PolyVox;
|
||||||
|
_created = properties.getCreated();
|
||||||
|
setProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityItemProperties PolyVoxEntityItem::getProperties() const {
|
||||||
|
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelData, getVoxelData);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelSurfaceStyle, getVoxelSurfaceStyle);
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PolyVoxEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
|
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelVolumeSize, setVoxelVolumeSize);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelData, setVoxelData);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelSurfaceStyle, setVoxelSurfaceStyle);
|
||||||
|
|
||||||
|
if (somethingChanged) {
|
||||||
|
bool wantDebug = false;
|
||||||
|
if (wantDebug) {
|
||||||
|
uint64_t now = usecTimestampNow();
|
||||||
|
int elapsed = now - getLastEdited();
|
||||||
|
qCDebug(entities) << "PolyVoxEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
|
||||||
|
"now=" << now << " getLastEdited()=" << getLastEdited();
|
||||||
|
}
|
||||||
|
setLastEdited(properties._lastEdited);
|
||||||
|
}
|
||||||
|
return somethingChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PolyVoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
|
ReadBitstreamToTreeParams& args,
|
||||||
|
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
|
||||||
|
|
||||||
|
int bytesRead = 0;
|
||||||
|
const unsigned char* dataAt = data;
|
||||||
|
|
||||||
|
READ_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, glm::vec3, setVoxelVolumeSize);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_VOXEL_DATA, QByteArray, setVoxelData);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle);
|
||||||
|
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||||
|
EntityPropertyFlags PolyVoxEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
|
||||||
|
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||||
|
requestedProperties += PROP_VOXEL_VOLUME_SIZE;
|
||||||
|
requestedProperties += PROP_VOXEL_DATA;
|
||||||
|
requestedProperties += PROP_VOXEL_SURFACE_STYLE;
|
||||||
|
return requestedProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||||
|
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
|
||||||
|
EntityPropertyFlags& requestedProperties,
|
||||||
|
EntityPropertyFlags& propertyFlags,
|
||||||
|
EntityPropertyFlags& propertiesDidntFit,
|
||||||
|
int& propertyCount,
|
||||||
|
OctreeElement::AppendState& appendState) const {
|
||||||
|
bool successPropertyFits = true;
|
||||||
|
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, getVoxelVolumeSize());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_VOXEL_DATA, getVoxelData());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, (uint16_t) getVoxelSurfaceStyle());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PolyVoxEntityItem::debugDump() const {
|
||||||
|
quint64 now = usecTimestampNow();
|
||||||
|
qCDebug(entities) << " POLYVOX EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||||
|
qCDebug(entities) << " position:" << debugTreeVector(_position);
|
||||||
|
qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions);
|
||||||
|
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||||
|
}
|
||||||
|
|
98
libraries/entities/src/PolyVoxEntityItem.h
Normal file
98
libraries/entities/src/PolyVoxEntityItem.h
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
//
|
||||||
|
// PolyVoxEntityItem.h
|
||||||
|
// libraries/entities/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 5/11/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_PolyVoxEntityItem_h
|
||||||
|
#define hifi_PolyVoxEntityItem_h
|
||||||
|
|
||||||
|
#include "EntityItem.h"
|
||||||
|
|
||||||
|
class PolyVoxEntityItem : public EntityItem {
|
||||||
|
public:
|
||||||
|
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
|
PolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
|
ALLOW_INSTANTIATION // This class can be instantiated
|
||||||
|
|
||||||
|
// methods for getting/setting all properties of an entity
|
||||||
|
virtual EntityItemProperties getProperties() const;
|
||||||
|
virtual bool setProperties(const EntityItemProperties& properties);
|
||||||
|
|
||||||
|
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||||
|
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
|
||||||
|
|
||||||
|
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||||
|
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
|
||||||
|
EntityPropertyFlags& requestedProperties,
|
||||||
|
EntityPropertyFlags& propertyFlags,
|
||||||
|
EntityPropertyFlags& propertiesDidntFit,
|
||||||
|
int& propertyCount,
|
||||||
|
OctreeElement::AppendState& appendState) const;
|
||||||
|
|
||||||
|
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
|
ReadBitstreamToTreeParams& args,
|
||||||
|
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||||
|
|
||||||
|
const rgbColor& getColor() const { return _color; }
|
||||||
|
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||||
|
|
||||||
|
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
|
||||||
|
void setXColor(const xColor& value) {
|
||||||
|
_color[RED_INDEX] = value.red;
|
||||||
|
_color[GREEN_INDEX] = value.green;
|
||||||
|
_color[BLUE_INDEX] = value.blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ShapeType getShapeType() const { return SHAPE_TYPE_POLYVOX; }
|
||||||
|
|
||||||
|
// never have a ray intersection pick a PolyVoxEntityItem.
|
||||||
|
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||||
|
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||||
|
void** intersectedObject, bool precisionPicking) const { return false; }
|
||||||
|
|
||||||
|
virtual void debugDump() const;
|
||||||
|
|
||||||
|
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { _voxelVolumeSize = voxelVolumeSize; }
|
||||||
|
virtual const glm::vec3& getVoxelVolumeSize() const { return _voxelVolumeSize; }
|
||||||
|
|
||||||
|
virtual void setVoxelData(QByteArray voxelData) { _voxelData = voxelData; }
|
||||||
|
virtual const QByteArray& getVoxelData() const { return _voxelData; }
|
||||||
|
|
||||||
|
enum PolyVoxSurfaceStyle {
|
||||||
|
SURFACE_MARCHING_CUBES,
|
||||||
|
SURFACE_CUBIC
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; }
|
||||||
|
virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) {
|
||||||
|
_voxelSurfaceStyle = (PolyVoxSurfaceStyle) voxelSurfaceStyle;
|
||||||
|
}
|
||||||
|
virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; }
|
||||||
|
|
||||||
|
static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE;
|
||||||
|
static const QByteArray DEFAULT_VOXEL_DATA;
|
||||||
|
static const PolyVoxSurfaceStyle DEFAULT_VOXEL_SURFACE_STYLE;
|
||||||
|
|
||||||
|
// coords are in voxel-volume space
|
||||||
|
virtual void setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) {}
|
||||||
|
|
||||||
|
// coords are in world-space
|
||||||
|
virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
rgbColor _color;
|
||||||
|
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
|
||||||
|
QByteArray _voxelData;
|
||||||
|
PolyVoxSurfaceStyle _voxelSurfaceStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_PolyVoxEntityItem_h
|
|
@ -228,13 +228,14 @@ public:
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Iterator(T* ptr = NULL) { _ptr = ptr; }
|
Iterator(T* ptr = NULL, int stride = sizeof(T)): _ptr(ptr), _stride(stride) { }
|
||||||
Iterator(const Iterator<T>& iterator) = default;
|
Iterator(const Iterator<T>& iterator) = default;
|
||||||
~Iterator() {}
|
~Iterator() {}
|
||||||
|
|
||||||
Iterator<T>& operator=(const Iterator<T>& iterator) = default;
|
Iterator<T>& operator=(const Iterator<T>& iterator) = default;
|
||||||
Iterator<T>& operator=(T* ptr) {
|
Iterator<T>& operator=(T* ptr) {
|
||||||
_ptr = ptr;
|
_ptr = ptr;
|
||||||
|
// stride is left unchanged
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,42 +250,48 @@ public:
|
||||||
bool operator==(const Iterator<T>& iterator) const { return (_ptr == iterator.getConstPtr()); }
|
bool operator==(const Iterator<T>& iterator) const { return (_ptr == iterator.getConstPtr()); }
|
||||||
bool operator!=(const Iterator<T>& iterator) const { return (_ptr != iterator.getConstPtr()); }
|
bool operator!=(const Iterator<T>& iterator) const { return (_ptr != iterator.getConstPtr()); }
|
||||||
|
|
||||||
|
void movePtr(const Index& movement) {
|
||||||
|
auto byteptr = ((Byte*)_ptr);
|
||||||
|
byteptr += _stride * movement;
|
||||||
|
_ptr = (T*)byteptr;
|
||||||
|
}
|
||||||
|
|
||||||
Iterator<T>& operator+=(const Index& movement) {
|
Iterator<T>& operator+=(const Index& movement) {
|
||||||
_ptr += movement;
|
movePtr(movement);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
Iterator<T>& operator-=(const Index& movement) {
|
Iterator<T>& operator-=(const Index& movement) {
|
||||||
_ptr -= movement;
|
movePtr(-movement);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
Iterator<T>& operator++() {
|
Iterator<T>& operator++() {
|
||||||
++_ptr;
|
movePtr(1);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
Iterator<T>& operator--() {
|
Iterator<T>& operator--() {
|
||||||
--_ptr;
|
movePtr(-1);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
Iterator<T> operator++(Index) {
|
Iterator<T> operator++(Index) {
|
||||||
auto temp(*this);
|
auto temp(*this);
|
||||||
++_ptr;
|
movePtr(1);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
Iterator<T> operator--(Index) {
|
Iterator<T> operator--(Index) {
|
||||||
auto temp(*this);
|
auto temp(*this);
|
||||||
--_ptr;
|
movePtr(-1);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
Iterator<T> operator+(const Index& movement) {
|
Iterator<T> operator+(const Index& movement) {
|
||||||
auto oldPtr = _ptr;
|
auto oldPtr = _ptr;
|
||||||
_ptr += movement;
|
movePtr(movement);
|
||||||
auto temp(*this);
|
auto temp(*this);
|
||||||
_ptr = oldPtr;
|
_ptr = oldPtr;
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
Iterator<T> operator-(const Index& movement) {
|
Iterator<T> operator-(const Index& movement) {
|
||||||
auto oldPtr = _ptr;
|
auto oldPtr = _ptr;
|
||||||
_ptr -= movement;
|
movePtr(-movement);
|
||||||
auto temp(*this);
|
auto temp(*this);
|
||||||
_ptr = oldPtr;
|
_ptr = oldPtr;
|
||||||
return temp;
|
return temp;
|
||||||
|
@ -302,16 +309,17 @@ public:
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
T* _ptr;
|
T* _ptr;
|
||||||
|
int _stride;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> Iterator<T> begin() { return Iterator<T>(&edit<T>(0)); }
|
template <typename T> Iterator<T> begin() { return Iterator<T>(&edit<T>(0), _stride); }
|
||||||
template <typename T> Iterator<T> end() { return Iterator<T>(&edit<T>(getNum<T>())); }
|
template <typename T> Iterator<T> end() { return Iterator<T>(&edit<T>(getNum<T>()), _stride); }
|
||||||
template <typename T> Iterator<const T> cbegin() const { return Iterator<const T>(&get<T>(0)); }
|
template <typename T> Iterator<const T> cbegin() const { return Iterator<const T>(&get<T>(0), _stride); }
|
||||||
template <typename T> Iterator<const T> cend() const { return Iterator<const T>(&get<T>(getNum<T>())); }
|
template <typename T> Iterator<const T> cend() const { return Iterator<const T>(&get<T>(getNum<T>()), _stride); }
|
||||||
|
|
||||||
// the number of elements of the specified type fitting in the view size
|
// the number of elements of the specified type fitting in the view size
|
||||||
template <typename T> Index getNum() const {
|
template <typename T> Index getNum() const {
|
||||||
return Index(_size / sizeof(T));
|
return Index(_size / _stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> const T& get() const {
|
template <typename T> const T& get() const {
|
||||||
|
@ -347,7 +355,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> const T& get(const Index index) const {
|
template <typename T> const T& get(const Index index) const {
|
||||||
Resource::Size elementOffset = index * sizeof(T) + _offset;
|
Resource::Size elementOffset = index * _stride + _offset;
|
||||||
#if _DEBUG
|
#if _DEBUG
|
||||||
if (!_buffer) {
|
if (!_buffer) {
|
||||||
qDebug() << "Accessing null gpu::buffer!";
|
qDebug() << "Accessing null gpu::buffer!";
|
||||||
|
@ -363,7 +371,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> T& edit(const Index index) const {
|
template <typename T> T& edit(const Index index) const {
|
||||||
Resource::Size elementOffset = index * sizeof(T) + _offset;
|
Resource::Size elementOffset = index * _stride + _offset;
|
||||||
#if _DEBUG
|
#if _DEBUG
|
||||||
if (!_buffer) {
|
if (!_buffer) {
|
||||||
qDebug() << "Accessing null gpu::buffer!";
|
qDebug() << "Accessing null gpu::buffer!";
|
||||||
|
|
|
@ -42,6 +42,15 @@ void Mesh::addAttribute(Slot slot, const BufferView& buffer) {
|
||||||
evalVertexFormat();
|
evalVertexFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BufferView Mesh::getAttributeBuffer(int attrib) const {
|
||||||
|
auto attribBuffer = _attributeBuffers.find(attrib);
|
||||||
|
if (attribBuffer != _attributeBuffers.end()) {
|
||||||
|
return attribBuffer->second;
|
||||||
|
} else {
|
||||||
|
return BufferView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Mesh::evalVertexFormat() {
|
void Mesh::evalVertexFormat() {
|
||||||
auto vf = new VertexFormat();
|
auto vf = new VertexFormat();
|
||||||
int channelNum = 0;
|
int channelNum = 0;
|
||||||
|
|
|
@ -52,6 +52,7 @@ public:
|
||||||
// Attribute Buffers
|
// Attribute Buffers
|
||||||
int getNumAttributes() const { return _attributeBuffers.size(); }
|
int getNumAttributes() const { return _attributeBuffers.size(); }
|
||||||
void addAttribute(Slot slot, const BufferView& buffer);
|
void addAttribute(Slot slot, const BufferView& buffer);
|
||||||
|
const BufferView getAttributeBuffer(int attrib) const;
|
||||||
|
|
||||||
// Stream format
|
// Stream format
|
||||||
const gpu::Stream::FormatPointer getVertexFormat() const { return _vertexFormat; }
|
const gpu::Stream::FormatPointer getVertexFormat() const { return _vertexFormat; }
|
||||||
|
|
|
@ -107,7 +107,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
||||||
} else {
|
} else {
|
||||||
// skybox has no cubemap, just clear the color buffer
|
// skybox has no cubemap, just clear the color buffer
|
||||||
auto color = skybox.getColor();
|
auto color = skybox.getColor();
|
||||||
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(skybox.getColor(),1.0f), 0.f, 0);
|
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 1.0f), 0.f, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -426,7 +426,12 @@ bool OctreePacketData::appendValue(const QUuid& uuid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OctreePacketData::appendValue(const QByteArray& bytes) {
|
bool OctreePacketData::appendValue(const QByteArray& bytes) {
|
||||||
bool success = appendRawData((const unsigned char*)bytes.constData(), bytes.size());
|
// TODO: make this a ByteCountCoded leading byte
|
||||||
|
uint16_t length = bytes.size();
|
||||||
|
bool success = appendValue(length);
|
||||||
|
if (success) {
|
||||||
|
success = appendRawData((const unsigned char*)bytes.constData(), bytes.size());
|
||||||
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,6 +456,12 @@ bool OctreePacketData::appendRawData(const unsigned char* data, int length) {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool OctreePacketData::appendRawData(QByteArray data) {
|
||||||
|
return appendRawData((unsigned char *)data.data(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
quint64 OctreePacketData::_compressContentTime = 0;
|
quint64 OctreePacketData::_compressContentTime = 0;
|
||||||
quint64 OctreePacketData::_compressContentCalls = 0;
|
quint64 OctreePacketData::_compressContentCalls = 0;
|
||||||
|
|
||||||
|
@ -545,7 +556,7 @@ void OctreePacketData::debugContent() {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int OctreePacketData::uppackDataFromBytes(const unsigned char* dataBytes, QString& result) {
|
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QString& result) {
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
memcpy(&length, dataBytes, sizeof(length));
|
memcpy(&length, dataBytes, sizeof(length));
|
||||||
dataBytes += sizeof(length);
|
dataBytes += sizeof(length);
|
||||||
|
@ -554,7 +565,7 @@ int OctreePacketData::uppackDataFromBytes(const unsigned char* dataBytes, QStrin
|
||||||
return sizeof(length) + length;
|
return sizeof(length) + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int OctreePacketData::uppackDataFromBytes(const unsigned char* dataBytes, QUuid& result) {
|
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result) {
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
memcpy(&length, dataBytes, sizeof(length));
|
memcpy(&length, dataBytes, sizeof(length));
|
||||||
dataBytes += sizeof(length);
|
dataBytes += sizeof(length);
|
||||||
|
@ -567,9 +578,18 @@ int OctreePacketData::uppackDataFromBytes(const unsigned char* dataBytes, QUuid&
|
||||||
return sizeof(length) + length;
|
return sizeof(length) + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int OctreePacketData::uppackDataFromBytes(const unsigned char* dataBytes, xColor& result) {
|
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, xColor& result) {
|
||||||
result.red = dataBytes[RED_INDEX];
|
result.red = dataBytes[RED_INDEX];
|
||||||
result.green = dataBytes[GREEN_INDEX];
|
result.green = dataBytes[GREEN_INDEX];
|
||||||
result.blue = dataBytes[BLUE_INDEX];
|
result.blue = dataBytes[BLUE_INDEX];
|
||||||
return sizeof(rgbColor);
|
return sizeof(rgbColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result) {
|
||||||
|
uint16_t length;
|
||||||
|
memcpy(&length, dataBytes, sizeof(length));
|
||||||
|
dataBytes += sizeof(length);
|
||||||
|
QByteArray value((const char*)dataBytes, length);
|
||||||
|
result = value;
|
||||||
|
return sizeof(length) + length;
|
||||||
|
}
|
||||||
|
|
|
@ -183,6 +183,7 @@ public:
|
||||||
|
|
||||||
/// appends raw bytes, might fail if byte would cause packet to be too large
|
/// appends raw bytes, might fail if byte would cause packet to be too large
|
||||||
bool appendRawData(const unsigned char* data, int length);
|
bool appendRawData(const unsigned char* data, int length);
|
||||||
|
bool appendRawData(QByteArray data);
|
||||||
|
|
||||||
/// returns a byte offset from beginning of the uncompressed stream based on offset from end.
|
/// returns a byte offset from beginning of the uncompressed stream based on offset from end.
|
||||||
/// Positive offsetFromEnd returns that many bytes before the end of uncompressed stream
|
/// Positive offsetFromEnd returns that many bytes before the end of uncompressed stream
|
||||||
|
@ -226,20 +227,21 @@ public:
|
||||||
static quint64 getTotalBytesOfBitMasks() { return _totalBytesOfBitMasks; } /// total bytes of bitmasks
|
static quint64 getTotalBytesOfBitMasks() { return _totalBytesOfBitMasks; } /// total bytes of bitmasks
|
||||||
static quint64 getTotalBytesOfColor() { return _totalBytesOfColor; } /// total bytes of color
|
static quint64 getTotalBytesOfColor() { return _totalBytesOfColor; } /// total bytes of color
|
||||||
|
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, uint32_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, uint32_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, uint16_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, uint16_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, uint8_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, uint8_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, rgbColor& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, rgbColor& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, BackgroundMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, BackgroundMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, QString& result);
|
static int unpackDataFromBytes(const unsigned char* dataBytes, QString& result);
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, QUuid& result);
|
static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result);
|
||||||
static int uppackDataFromBytes(const unsigned char* dataBytes, xColor& result);
|
static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result);
|
||||||
|
static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// appends raw bytes, might fail if byte would cause packet to be too large
|
/// appends raw bytes, might fail if byte would cause packet to be too large
|
||||||
|
|
|
@ -132,7 +132,6 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
|
||||||
uint32_t thisStep = ObjectMotionState::getWorldSimulationStep();
|
uint32_t thisStep = ObjectMotionState::getWorldSimulationStep();
|
||||||
float dt = (thisStep - _lastKinematicStep) * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
float dt = (thisStep - _lastKinematicStep) * PHYSICS_ENGINE_FIXED_SUBSTEP;
|
||||||
_entity->simulateKinematicMotion(dt);
|
_entity->simulateKinematicMotion(dt);
|
||||||
_entity->setLastSimulated(usecTimestampNow());
|
|
||||||
|
|
||||||
// bypass const-ness so we can remember the step
|
// bypass const-ness so we can remember the step
|
||||||
const_cast<EntityMotionState*>(this)->_lastKinematicStep = thisStep;
|
const_cast<EntityMotionState*>(this)->_lastKinematicStep = thisStep;
|
||||||
|
@ -401,13 +400,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
|
||||||
properties.setAcceleration(_serverAcceleration);
|
properties.setAcceleration(_serverAcceleration);
|
||||||
properties.setAngularVelocity(_serverAngularVelocity);
|
properties.setAngularVelocity(_serverAngularVelocity);
|
||||||
|
|
||||||
// we only update lastEdited when we're sending new physics data
|
// set the LastEdited of the properties but NOT the entity itself
|
||||||
quint64 lastSimulated = _entity->getLastSimulated();
|
quint64 now = usecTimestampNow();
|
||||||
_entity->setLastEdited(lastSimulated);
|
properties.setLastEdited(now);
|
||||||
properties.setLastEdited(lastSimulated);
|
|
||||||
|
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
quint64 now = usecTimestampNow();
|
quint64 lastSimulated = _entity->getLastSimulated();
|
||||||
qCDebug(physics) << "EntityMotionState::sendUpdate()";
|
qCDebug(physics) << "EntityMotionState::sendUpdate()";
|
||||||
qCDebug(physics) << " EntityItemId:" << _entity->getEntityItemID()
|
qCDebug(physics) << " EntityItemId:" << _entity->getEntityItemID()
|
||||||
<< "---------------------------------------------";
|
<< "---------------------------------------------";
|
||||||
|
|
|
@ -61,9 +61,9 @@ public:
|
||||||
|
|
||||||
virtual glm::vec3 getObjectPosition() const { return _entity->getPosition() - ObjectMotionState::getWorldOffset(); }
|
virtual glm::vec3 getObjectPosition() const { return _entity->getPosition() - ObjectMotionState::getWorldOffset(); }
|
||||||
virtual glm::quat getObjectRotation() const { return _entity->getRotation(); }
|
virtual glm::quat getObjectRotation() const { return _entity->getRotation(); }
|
||||||
virtual const glm::vec3& getObjectLinearVelocity() const { return _entity->getVelocity(); }
|
virtual glm::vec3 getObjectLinearVelocity() const { return _entity->getVelocity(); }
|
||||||
virtual const glm::vec3& getObjectAngularVelocity() const { return _entity->getAngularVelocity(); }
|
virtual glm::vec3 getObjectAngularVelocity() const { return _entity->getAngularVelocity(); }
|
||||||
virtual const glm::vec3& getObjectGravity() const { return _entity->getGravity(); }
|
virtual glm::vec3 getObjectGravity() const { return _entity->getGravity(); }
|
||||||
|
|
||||||
virtual const QUuid& getObjectID() const { return _entity->getID(); }
|
virtual const QUuid& getObjectID() const { return _entity->getID(); }
|
||||||
|
|
||||||
|
|
|
@ -112,9 +112,9 @@ public:
|
||||||
|
|
||||||
virtual glm::vec3 getObjectPosition() const = 0;
|
virtual glm::vec3 getObjectPosition() const = 0;
|
||||||
virtual glm::quat getObjectRotation() const = 0;
|
virtual glm::quat getObjectRotation() const = 0;
|
||||||
virtual const glm::vec3& getObjectLinearVelocity() const = 0;
|
virtual glm::vec3 getObjectLinearVelocity() const = 0;
|
||||||
virtual const glm::vec3& getObjectAngularVelocity() const = 0;
|
virtual glm::vec3 getObjectAngularVelocity() const = 0;
|
||||||
virtual const glm::vec3& getObjectGravity() const = 0;
|
virtual glm::vec3 getObjectGravity() const = 0;
|
||||||
|
|
||||||
virtual const QUuid& getObjectID() const = 0;
|
virtual const QUuid& getObjectID() const = 0;
|
||||||
|
|
||||||
|
|
|
@ -93,16 +93,16 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeferredLightingEffect::bindSimpleProgram() {
|
void DeferredLightingEffect::bindSimpleProgram() {
|
||||||
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(true, true, true);
|
// DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(true, true, true);
|
||||||
_simpleProgram.bind();
|
_simpleProgram.bind();
|
||||||
_simpleProgram.setUniformValue(_glowIntensityLocation, DependencyManager::get<GlowEffect>()->getIntensity());
|
_simpleProgram.setUniformValue(_glowIntensityLocation, DependencyManager::get<GlowEffect>()->getIntensity());
|
||||||
glDisable(GL_BLEND);
|
// glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeferredLightingEffect::releaseSimpleProgram() {
|
void DeferredLightingEffect::releaseSimpleProgram() {
|
||||||
glEnable(GL_BLEND);
|
// glEnable(GL_BLEND);
|
||||||
_simpleProgram.release();
|
_simpleProgram.release();
|
||||||
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(true, false, false);
|
// DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(true, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeferredLightingEffect::renderSolidSphere(float radius, int slices, int stacks, const glm::vec4& color) {
|
void DeferredLightingEffect::renderSolidSphere(float radius, int slices, int stacks, const glm::vec4& color) {
|
||||||
|
|
|
@ -35,7 +35,8 @@ enum ShapeType {
|
||||||
SHAPE_TYPE_CYLINDER_X,
|
SHAPE_TYPE_CYLINDER_X,
|
||||||
SHAPE_TYPE_CYLINDER_Y,
|
SHAPE_TYPE_CYLINDER_Y,
|
||||||
SHAPE_TYPE_CYLINDER_Z,
|
SHAPE_TYPE_CYLINDER_Z,
|
||||||
SHAPE_TYPE_LINE
|
SHAPE_TYPE_LINE,
|
||||||
|
SHAPE_TYPE_POLYVOX
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShapeInfo {
|
class ShapeInfo {
|
||||||
|
|
Loading…
Reference in a new issue