mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-14 09:06:32 +02:00
adding Matt's SvoViewer
This commit is contained in:
parent
bde7152246
commit
45b5f54bc5
24 changed files with 3224 additions and 0 deletions
|
@ -39,3 +39,4 @@ add_subdirectory(domain-server)
|
|||
add_subdirectory(interface)
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(voxel-edit)
|
||||
add_subdirectory(SvoViewer)
|
||||
|
|
250
SvoViewer/CMakeLists.txt
Normal file
250
SvoViewer/CMakeLists.txt
Normal file
|
@ -0,0 +1,250 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(ROOT_DIR ..)
|
||||
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||
|
||||
set(TARGET_NAME SvoViewer)
|
||||
project(${TARGET_NAME})
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
|
||||
|
||||
if (APPLE)
|
||||
set(GL_HEADERS "#include <GLUT/glut.h>\n#include <OpenGL/glext.h>")
|
||||
endif (APPLE)
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
# include the right GL headers for UNIX
|
||||
set(GL_HEADERS "#include <GL/gl.h>\n#include <GL/glut.h>\n#include <GL/glext.h>")
|
||||
endif (UNIX AND NOT APPLE)
|
||||
|
||||
if (WIN32)
|
||||
|
||||
add_definitions( -D_USE_MATH_DEFINES ) # apparently needed to get M_PI and other defines from cmath/math.h
|
||||
add_definitions( -DWINDOWS_LEAN_AND_MEAN ) # needed to make sure windows doesn't go to crazy with its defines
|
||||
|
||||
# windows build needs an external glut, we're using freeglut
|
||||
set(GLUT_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external/freeglut)
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${GLUT_ROOT_PATH})
|
||||
|
||||
# windows build needs glew (opengl extention wrangler) this will handle providing access to OpenGL methods after 1.1
|
||||
# which are not accessible on windows without glew or some other dynamic linking mechanism
|
||||
set(GLEW_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external/glew)
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${GLEW_ROOT_PATH})
|
||||
include_directories(SYSTEM ${GLEW_ROOT_PATH}/include ${GLUT_ROOT_PATH}/include)
|
||||
|
||||
#set(GL_HEADERS "#define GLEW_STATIC\n#define FREEGLUT_STATIC\n#define FREEGLUT_LIB_PRAGMAS 0\n#include <GL/glew.h>\n#include <GL/wglew.h>\n#include <GL/freeglut_std.h>\n#include <GL/freeglut_ext.h>")
|
||||
set(GL_HEADERS "#define GLEW_STATIC\n#include <windowshacks.h>\n#include <GL/glew.h>\n#include <GL/glut.h>")
|
||||
|
||||
endif (WIN32)
|
||||
|
||||
# set up the external glm library
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
# create the ${TARGET_NAME}Config.h file based on GL_HEADERS above
|
||||
configure_file(${TARGET_NAME}Config.h.in ${PROJECT_BINARY_DIR}/includes/${TARGET_NAME}Config.h)
|
||||
configure_file(${TARGET_NAME}Version.h.in ${PROJECT_BINARY_DIR}/includes/${TARGET_NAME}Version.h)
|
||||
|
||||
# grab the implementation and header files from src dirs
|
||||
file(GLOB APPLICATION_SRCS src/*.c src/*.cpp src/*.h)
|
||||
foreach(SUBDIR avatar devices renderer ui starfield)
|
||||
file(GLOB_RECURSE SUBDIR_SRCS src/${SUBDIR}/*.cpp src/${SUBDIR}/*.c src/${SUBDIR}/*.h)
|
||||
set(APPLICATION_SRCS ${APPLICATION_SRCS} ${SUBDIR_SRCS})
|
||||
endforeach(SUBDIR)
|
||||
|
||||
foreach(EXTERNAL_SOURCE_SUBDIR ${EXTERNAL_SOURCE_SUBDIRS})
|
||||
file(GLOB_RECURSE SUBDIR_SRCS external/${EXTERNAL_SOURCE_SUBDIR}/src/*.cpp external/${EXTERNAL_SOURCE_SUBDIR}/src/*.c external/${EXTERNAL_SOURCE_SUBDIR}/src/*.h)
|
||||
set(APPLICATION_SRCS ${APPLICATION_SRCS} ${SUBDIR_SRCS})
|
||||
endforeach(EXTERNAL_SOURCE_SUBDIR)
|
||||
|
||||
find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Gui REQUIRED)
|
||||
find_package(Qt5Multimedia REQUIRED)
|
||||
find_package(Qt5Network REQUIRED)
|
||||
find_package(Qt5OpenGL REQUIRED)
|
||||
find_package(Qt5Svg REQUIRED)
|
||||
find_package(Qt5WebKit REQUIRED)
|
||||
find_package(Qt5WebKitWidgets REQUIRED)
|
||||
find_package(Qt5Xml REQUIRED)
|
||||
|
||||
# grab the ui files in resources/ui
|
||||
file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
|
||||
# have qt5 wrap them and generate the appropriate header files
|
||||
qt5_wrap_ui(QT_UI_HEADERS ${QT_UI_FILES})
|
||||
|
||||
# add them to the application source files
|
||||
set(APPLICATION_SRCS ${APPLICATION_SRCS} ${QT_UI_HEADERS})
|
||||
|
||||
if (APPLE)
|
||||
|
||||
# configure CMake to use a custom Info.plist
|
||||
SET_TARGET_PROPERTIES( ${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in )
|
||||
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME SvoViewer)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER io.highfidelity.${TARGET_NAME})
|
||||
|
||||
# set how the icon shows up in the Info.plist file
|
||||
SET(MACOSX_BUNDLE_ICON_FILE ${TARGET_NAME}.icns)
|
||||
|
||||
# set where in the bundle to put the resources file
|
||||
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/${TARGET_NAME}.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
SET(APPLICATION_SRCS ${APPLICATION_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${TARGET_NAME}.icns)
|
||||
|
||||
# grab the directories in resources and put them in the right spot in Resources
|
||||
file(GLOB RESOURCE_SUBDIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/resources ${CMAKE_CURRENT_SOURCE_DIR}/resources/*)
|
||||
foreach(DIR ${RESOURCE_SUBDIRS})
|
||||
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources/${DIR})
|
||||
FILE(GLOB DIR_CONTENTS resources/${DIR}/*)
|
||||
SET_SOURCE_FILES_PROPERTIES(${DIR_CONTENTS} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/${DIR})
|
||||
|
||||
SET(APPLICATION_SRCS ${APPLICATION_SRCS} ${DIR_CONTENTS})
|
||||
endif()
|
||||
endforeach()
|
||||
endif (APPLE)
|
||||
|
||||
# create the executable, make it a bundle on OS X
|
||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${APPLICATION_SRCS})
|
||||
|
||||
# link in the hifi shared library
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(metavoxels ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(script-engine ${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
# find required libraries
|
||||
find_package(Faceshift)
|
||||
find_package(GLM REQUIRED)
|
||||
find_package(LibOVR)
|
||||
find_package(Sixense)
|
||||
find_package(Visage)
|
||||
find_package(ZLIB)
|
||||
|
||||
# include the Sixense library for Razer Hydra if available
|
||||
if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE)
|
||||
add_definitions(-DHAVE_SIXENSE)
|
||||
include_directories(SYSTEM ${SIXENSE_INCLUDE_DIRS})
|
||||
if (APPLE OR UNIX)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${SIXENSE_INCLUDE_DIRS}")
|
||||
endif (APPLE OR UNIX)
|
||||
target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES})
|
||||
endif (SIXENSE_FOUND AND NOT DISABLE_SIXENSE)
|
||||
|
||||
# likewise with Visage library for webcam feature tracking
|
||||
if (VISAGE_FOUND AND NOT DISABLE_VISAGE)
|
||||
add_definitions(-DHAVE_VISAGE -DVISAGE_STATIC)
|
||||
include_directories(SYSTEM ${VISAGE_INCLUDE_DIRS})
|
||||
if (APPLE)
|
||||
add_definitions(-DMAC_OS_X)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment -isystem ${VISAGE_INCLUDE_DIRS}")
|
||||
find_library(AVFoundation AVFoundation)
|
||||
find_library(CoreMedia CoreMedia)
|
||||
find_library(NEW_STD_LIBRARY libc++.dylib /usr/lib/)
|
||||
target_link_libraries(${TARGET_NAME} ${AVFoundation} ${CoreMedia} ${NEW_STD_LIBRARY})
|
||||
endif (APPLE)
|
||||
target_link_libraries(${TARGET_NAME} ${VISAGE_LIBRARIES})
|
||||
endif (VISAGE_FOUND AND NOT DISABLE_VISAGE)
|
||||
|
||||
# and with LibOVR for Oculus Rift
|
||||
if (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
||||
add_definitions(-DHAVE_LIBOVR)
|
||||
include_directories(SYSTEM ${LIBOVR_INCLUDE_DIRS})
|
||||
if (APPLE OR UNIX)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${LIBOVR_INCLUDE_DIRS}")
|
||||
endif (APPLE OR UNIX)
|
||||
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
|
||||
endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
|
||||
|
||||
qt5_use_modules(${TARGET_NAME} Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets Xml UiTools)
|
||||
|
||||
# include headers for interface
|
||||
include_directories(
|
||||
${PROJECT_SOURCE_DIR}/src
|
||||
${PROJECT_BINARY_DIR}/includes
|
||||
)
|
||||
|
||||
# include external library headers
|
||||
# use system flag so warnings are supressed
|
||||
include_directories(
|
||||
SYSTEM
|
||||
${FACESHIFT_INCLUDE_DIRS}
|
||||
${GLM_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
${FACESHIFT_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
# link in required OS X frameworks and include the right GL headers
|
||||
find_library(AppKit AppKit)
|
||||
find_library(CoreAudio CoreAudio)
|
||||
find_library(CoreServices CoreServices)
|
||||
find_library(Carbon Carbon)
|
||||
find_library(Foundation Foundation)
|
||||
find_library(GLUT GLUT)
|
||||
find_library(OpenGL OpenGL)
|
||||
find_library(IOKit IOKit)
|
||||
find_library(QTKit QTKit)
|
||||
find_library(QuartzCore QuartzCore)
|
||||
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
${AppKit}
|
||||
${CoreAudio}
|
||||
${CoreServices}
|
||||
${Carbon}
|
||||
${Foundation}
|
||||
${GLUT}
|
||||
${OpenGL}
|
||||
${IOKit}
|
||||
${QTKit}
|
||||
${QuartzCore}
|
||||
)
|
||||
else (APPLE)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GLUT REQUIRED)
|
||||
include_directories(${GLUT_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR})
|
||||
target_link_libraries(${TARGET_NAME} ${OPENGL_LIBRARY})
|
||||
endif (APPLE)
|
||||
|
||||
# link target to external libraries
|
||||
if (WIN32)
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/glew/lib/Release/Win32/glew32s.lib
|
||||
${GLUT_ROOT_PATH}/lib/freeglut.lib
|
||||
|
||||
wsock32.lib
|
||||
opengl32.lib
|
||||
)
|
||||
else (WIN32)
|
||||
# link required libraries on UNIX
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${GLUT_LIBRARY}
|
||||
)
|
||||
endif (UNIX AND NOT APPLE)
|
||||
endif (WIN32)
|
||||
|
||||
# install command for OS X bundle
|
||||
INSTALL(TARGETS ${TARGET_NAME}
|
||||
BUNDLE DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/install COMPONENT Runtime
|
||||
RUNTIME DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/install COMPONENT Runtime
|
||||
)
|
||||
|
BIN
SvoViewer/SvoViewer.icns
Normal file
BIN
SvoViewer/SvoViewer.icns
Normal file
Binary file not shown.
14
SvoViewer/SvoViewerConfig.h.in
Normal file
14
SvoViewer/SvoViewerConfig.h.in
Normal file
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// SvoViewerConfig.h
|
||||
// SvoViewer
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc.. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __SvoViewerConfig__
|
||||
#define __SvoViewerConfig__
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES 1
|
||||
@GL_HEADERS@
|
||||
|
||||
#endif
|
8
SvoViewer/SvoViewerVersion.h.in
Normal file
8
SvoViewer/SvoViewerVersion.h.in
Normal file
|
@ -0,0 +1,8 @@
|
|||
//
|
||||
// SvoViewerVersion.h
|
||||
// Declaration of version and build data
|
||||
//
|
||||
// Copyright (c) 2014 High Fidelity, Inc.. All rights reserved.
|
||||
//
|
||||
|
||||
const QString BUILD_VERSION = "@BUILD_SEQ@";
|
187
SvoViewer/src/AABoundingVolume.h
Normal file
187
SvoViewer/src/AABoundingVolume.h
Normal file
|
@ -0,0 +1,187 @@
|
|||
//
|
||||
// AABoundingVolume.h - Axis Aligned Bounding Volumes
|
||||
// hifi
|
||||
//
|
||||
|
||||
#ifndef _AABOUNDING_VOLUME_
|
||||
#define _AABOUNDING_VOLUME_
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
|
||||
|
||||
// A simple axis aligned bounding volume.
|
||||
#define AABF_NUM_DIMS 3
|
||||
#define AABF_LOW 0
|
||||
#define AABF_HIGH 1
|
||||
//Todo:: make this a template.
|
||||
class AABoundingVolume
|
||||
{
|
||||
public:
|
||||
AABoundingVolume() : _isSingleDirectionSet(false), _numPointsInSet(0) { memset(_bounds,0,sizeof(_bounds)); }
|
||||
~AABoundingVolume(){}
|
||||
|
||||
void AddToSet(const glm::vec3 newPt)
|
||||
{
|
||||
if (_numPointsInSet == 0)
|
||||
{
|
||||
for (int i = 0; i < AABF_NUM_DIMS; i++)
|
||||
{
|
||||
_bounds[i][AABF_LOW] = _bounds[i][AABF_HIGH] = newPt[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < AABF_NUM_DIMS; i++)
|
||||
{
|
||||
if (newPt[i] < _bounds[i][AABF_LOW]) _bounds[i][AABF_LOW] = newPt[i];
|
||||
if (newPt[i] > _bounds[i][AABF_HIGH]) _bounds[i][AABF_HIGH] = newPt[i];
|
||||
}
|
||||
}
|
||||
_numPointsInSet++;
|
||||
}
|
||||
|
||||
float getBound(const int dim, const int lohi) { return _bounds[dim][lohi]; }
|
||||
glm::vec3 getCorner(const BoxVertex i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case BOTTOM_LEFT_NEAR:
|
||||
return glm::vec3(_bounds[0][AABF_LOW], _bounds[1][AABF_LOW], _bounds[2][AABF_HIGH]);
|
||||
break;
|
||||
case BOTTOM_RIGHT_NEAR:
|
||||
return glm::vec3(_bounds[0][AABF_HIGH], _bounds[1][AABF_LOW], _bounds[2][AABF_HIGH]);
|
||||
break;
|
||||
case TOP_RIGHT_NEAR:
|
||||
return glm::vec3(_bounds[0][AABF_HIGH], _bounds[1][AABF_HIGH], _bounds[2][AABF_HIGH]);
|
||||
break;
|
||||
case TOP_LEFT_NEAR:
|
||||
return glm::vec3(_bounds[0][AABF_LOW], _bounds[1][AABF_HIGH], _bounds[2][AABF_HIGH]);
|
||||
break;
|
||||
case BOTTOM_LEFT_FAR:
|
||||
return glm::vec3(_bounds[0][AABF_LOW], _bounds[1][AABF_LOW], _bounds[2][AABF_LOW]);
|
||||
break;
|
||||
case BOTTOM_RIGHT_FAR:
|
||||
return glm::vec3(_bounds[0][AABF_HIGH], _bounds[1][AABF_LOW], _bounds[2][AABF_LOW]);
|
||||
break;
|
||||
case TOP_RIGHT_FAR:
|
||||
return glm::vec3(_bounds[0][AABF_HIGH], _bounds[1][AABF_HIGH], _bounds[2][AABF_LOW]);
|
||||
break;
|
||||
case TOP_LEFT_FAR:
|
||||
return glm::vec3(_bounds[0][AABF_LOW], _bounds[1][AABF_HIGH], _bounds[2][AABF_LOW]);
|
||||
break;
|
||||
default :
|
||||
assert(0 && "Requested invalid bounding volume vertex!");
|
||||
}
|
||||
return glm::vec3(-1.0, -1.0, -1.0);
|
||||
}
|
||||
|
||||
void setIsSingleDirection(const bool enable, const glm::vec3 normal)
|
||||
{
|
||||
if (enable) _singleDirectionNormal = normal;
|
||||
_isSingleDirectionSet = true;
|
||||
}
|
||||
|
||||
int within(const float loc, int dim)
|
||||
{
|
||||
if (loc < _bounds[dim][AABF_LOW]) return -1;
|
||||
if (loc > _bounds[dim][AABF_HIGH]) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool isSingleDirectionSet(){ return _isSingleDirectionSet; }
|
||||
glm::vec3 getSingleDirectionNormal(){ return _singleDirectionNormal; }
|
||||
|
||||
AABoundingVolume& operator= (const AABoundingVolume& val) {
|
||||
|
||||
if (this !=&val)
|
||||
|
||||
{
|
||||
|
||||
memcpy(_bounds, &val._bounds, sizeof(AABoundingVolume));
|
||||
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
float _bounds[AABF_NUM_DIMS][2]; // Bounds for each dimension. NOTE:: Not a vector so don't store it that way!
|
||||
int _numPointsInSet;
|
||||
bool _isSingleDirectionSet;
|
||||
glm::vec3 _singleDirectionNormal;
|
||||
};
|
||||
|
||||
#define AABF2D_NUM_DIMS 2
|
||||
#define UNDEFINED_RANGE_VAL 99999.0
|
||||
class AA2DBoundingVolume
|
||||
{
|
||||
public:
|
||||
AA2DBoundingVolume() : _numPointsInSet(0) {}
|
||||
~AA2DBoundingVolume(){}
|
||||
|
||||
void AddToSet(const float newPt[2])
|
||||
{
|
||||
if (_numPointsInSet == 0)
|
||||
{
|
||||
for (int i = 0; i < AABF2D_NUM_DIMS; i++)
|
||||
{
|
||||
_bounds[i][AABF_LOW] = _bounds[i][AABF_HIGH] = newPt[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < AABF2D_NUM_DIMS; i++)
|
||||
{
|
||||
if (newPt[i] < _bounds[i][AABF_LOW]) _bounds[i][AABF_LOW] = newPt[i];
|
||||
if (newPt[i] > _bounds[i][AABF_HIGH]) _bounds[i][AABF_HIGH] = newPt[i];
|
||||
}
|
||||
}
|
||||
_numPointsInSet++;
|
||||
}
|
||||
|
||||
// return true if its in range.
|
||||
bool clipToRegion(const float lowx, const float lowy, const float highx, const float highy)
|
||||
{
|
||||
assert(highx > lowx && highy > lowy);
|
||||
bool inRange = true;
|
||||
if (_bounds[0][AABF_LOW] > highx || _bounds[0][AABF_HIGH] < lowx)
|
||||
{
|
||||
_bounds[0][AABF_LOW] = _bounds[0][AABF_HIGH] = UNDEFINED_RANGE_VAL;
|
||||
inRange=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_bounds[0][AABF_LOW] < lowx) _bounds[0][AABF_LOW] = lowx;
|
||||
if (_bounds[0][AABF_HIGH] > highx) _bounds[0][AABF_HIGH] = highx;
|
||||
}
|
||||
if (_bounds[1][AABF_LOW] > highy || _bounds[1][AABF_HIGH] < lowy)
|
||||
{
|
||||
_bounds[1][AABF_LOW] = _bounds[1][AABF_HIGH] = UNDEFINED_RANGE_VAL;
|
||||
inRange=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_bounds[1][AABF_LOW] < lowy) _bounds[1][AABF_LOW] = lowy;
|
||||
if (_bounds[1][AABF_HIGH] > highy) _bounds[1][AABF_HIGH] = highy;
|
||||
}
|
||||
return inRange;
|
||||
}
|
||||
|
||||
float getHeight()
|
||||
{
|
||||
if (_bounds[1][AABF_HIGH] == UNDEFINED_RANGE_VAL || _bounds[1][AABF_LOW] == UNDEFINED_RANGE_VAL) return 0;
|
||||
return _bounds[1][AABF_HIGH] - _bounds[1][AABF_LOW];
|
||||
}
|
||||
float getWidth()
|
||||
{
|
||||
if (_bounds[0][AABF_HIGH] == UNDEFINED_RANGE_VAL || _bounds[0][AABF_LOW] == UNDEFINED_RANGE_VAL) return 0;
|
||||
return _bounds[0][AABF_HIGH] - _bounds[0][AABF_LOW];
|
||||
}
|
||||
|
||||
protected:
|
||||
float _bounds[AABF2D_NUM_DIMS][2];
|
||||
int _numPointsInSet;
|
||||
};
|
||||
|
||||
#endif
|
251
SvoViewer/src/Camera.cpp
Executable file
251
SvoViewer/src/Camera.cpp
Executable file
|
@ -0,0 +1,251 @@
|
|||
//
|
||||
// Camera.cpp
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <VoxelConstants.h>
|
||||
#include <EventTypes.h>
|
||||
|
||||
#include "Camera.h"
|
||||
#include "Menu.h"
|
||||
#include "Util.h"
|
||||
|
||||
const float CAMERA_FIRST_PERSON_MODE_UP_SHIFT = 0.0f;
|
||||
const float CAMERA_FIRST_PERSON_MODE_DISTANCE = 0.0f;
|
||||
const float CAMERA_FIRST_PERSON_MODE_TIGHTNESS = 100.0f;
|
||||
|
||||
const float CAMERA_INDEPENDENT_MODE_UP_SHIFT = 0.0f;
|
||||
const float CAMERA_INDEPENDENT_MODE_DISTANCE = 0.0f;
|
||||
const float CAMERA_INDEPENDENT_MODE_TIGHTNESS = 100.0f;
|
||||
|
||||
const float CAMERA_THIRD_PERSON_MODE_UP_SHIFT = -0.2f;
|
||||
const float CAMERA_THIRD_PERSON_MODE_DISTANCE = 1.5f;
|
||||
const float CAMERA_THIRD_PERSON_MODE_TIGHTNESS = 8.0f;
|
||||
|
||||
const float CAMERA_MIRROR_MODE_UP_SHIFT = 0.0f;
|
||||
const float CAMERA_MIRROR_MODE_DISTANCE = 0.17f;
|
||||
const float CAMERA_MIRROR_MODE_TIGHTNESS = 100.0f;
|
||||
|
||||
|
||||
Camera::Camera() :
|
||||
_needsToInitialize(true),
|
||||
_mode(CAMERA_MODE_THIRD_PERSON),
|
||||
_prevMode(CAMERA_MODE_THIRD_PERSON),
|
||||
_frustumNeedsReshape(true),
|
||||
_position(0.0f, 0.0f, 0.0f),
|
||||
_idealPosition(0.0f, 0.0f, 0.0f),
|
||||
_targetPosition(0.0f, 0.0f, 0.0f),
|
||||
_fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||
_aspectRatio(16.f/9.f),
|
||||
_nearClip(0.08f), // default
|
||||
_farClip(50.0f * TREE_SCALE), // default
|
||||
_upShift(0.0f),
|
||||
_distance(0.0f),
|
||||
_tightness(10.0f), // default
|
||||
_previousUpShift(0.0f),
|
||||
_previousDistance(0.0f),
|
||||
_previousTightness(0.0f),
|
||||
_newUpShift(0.0f),
|
||||
_newDistance(0.0f),
|
||||
_newTightness(0.0f),
|
||||
_modeShift(1.0f),
|
||||
_linearModeShift(0.0f),
|
||||
_modeShiftPeriod(1.0f),
|
||||
_scale(1.0f),
|
||||
_lookingAt(0.0f, 0.0f, 0.0f),
|
||||
_isKeepLookingAt(false)
|
||||
{
|
||||
}
|
||||
|
||||
void Camera::update(float deltaTime) {
|
||||
|
||||
if (_mode != CAMERA_MODE_NULL) {
|
||||
// use iterative forces to push the camera towards the target position and angle
|
||||
updateFollowMode(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
// use iterative forces to keep the camera at the desired position and angle
|
||||
void Camera::updateFollowMode(float deltaTime) {
|
||||
if (_linearModeShift < 1.0f) {
|
||||
_linearModeShift += deltaTime / _modeShiftPeriod;
|
||||
if (_needsToInitialize || _linearModeShift > 1.0f) {
|
||||
_linearModeShift = 1.0f;
|
||||
_modeShift = 1.0f;
|
||||
_upShift = _newUpShift;
|
||||
_distance = _newDistance;
|
||||
_tightness = _newTightness;
|
||||
} else {
|
||||
_modeShift = ONE_HALF - ONE_HALF * cosf(_linearModeShift * PIE );
|
||||
_upShift = _previousUpShift * (1.0f - _modeShift) + _newUpShift * _modeShift;
|
||||
_distance = _previousDistance * (1.0f - _modeShift) + _newDistance * _modeShift;
|
||||
_tightness = _previousTightness * (1.0f - _modeShift) + _newTightness * _modeShift;
|
||||
}
|
||||
}
|
||||
|
||||
// derive t from tightness
|
||||
float t = _tightness * _modeShift * deltaTime;
|
||||
if (t > 1.0) {
|
||||
t = 1.0;
|
||||
}
|
||||
|
||||
// handle keepLookingAt
|
||||
if (_isKeepLookingAt) {
|
||||
lookAt(_lookingAt);
|
||||
}
|
||||
|
||||
// Update position and rotation, setting directly if tightness is 0.0
|
||||
if (_needsToInitialize || (_tightness == 0.0f)) {
|
||||
_rotation = _targetRotation;
|
||||
_idealPosition = _targetPosition + _scale * (_rotation * glm::vec3(0.0f, _upShift, _distance));
|
||||
_position = _idealPosition;
|
||||
_needsToInitialize = false;
|
||||
} else {
|
||||
// pull rotation towards ideal
|
||||
_rotation = safeMix(_rotation, _targetRotation, t);
|
||||
_idealPosition = _targetPosition + _scale * (_rotation * glm::vec3(0.0f, _upShift, _distance));
|
||||
_position += (_idealPosition - _position) * t;
|
||||
}
|
||||
}
|
||||
|
||||
float Camera::getFarClip() const {
|
||||
return (_scale * _farClip < std::numeric_limits<int16_t>::max())
|
||||
? _scale * _farClip
|
||||
: std::numeric_limits<int16_t>::max() - 1;
|
||||
}
|
||||
|
||||
void Camera::setModeShiftPeriod (float period) {
|
||||
const float MIN_PERIOD = 0.001f;
|
||||
const float MAX_PERIOD = 3.0f;
|
||||
_modeShiftPeriod = glm::clamp(period, MIN_PERIOD, MAX_PERIOD);
|
||||
}
|
||||
|
||||
void Camera::setMode(CameraMode m) {
|
||||
|
||||
_prevMode = _mode;
|
||||
_mode = m;
|
||||
_modeShift = 0.0;
|
||||
_linearModeShift = 0.0;
|
||||
|
||||
_previousUpShift = _upShift;
|
||||
_previousDistance = _distance;
|
||||
_previousTightness = _tightness;
|
||||
|
||||
if (_mode == CAMERA_MODE_THIRD_PERSON) {
|
||||
_newUpShift = CAMERA_THIRD_PERSON_MODE_UP_SHIFT;
|
||||
_newDistance = CAMERA_THIRD_PERSON_MODE_DISTANCE;
|
||||
_newTightness = CAMERA_THIRD_PERSON_MODE_TIGHTNESS;
|
||||
} else if (_mode == CAMERA_MODE_FIRST_PERSON) {
|
||||
_newUpShift = CAMERA_FIRST_PERSON_MODE_UP_SHIFT;
|
||||
_newDistance = CAMERA_FIRST_PERSON_MODE_DISTANCE;
|
||||
_newTightness = CAMERA_FIRST_PERSON_MODE_TIGHTNESS;
|
||||
} else if (_mode == CAMERA_MODE_MIRROR) {
|
||||
_newUpShift = CAMERA_MIRROR_MODE_UP_SHIFT;
|
||||
_newDistance = CAMERA_MIRROR_MODE_DISTANCE;
|
||||
_newTightness = CAMERA_MIRROR_MODE_TIGHTNESS;
|
||||
} else if (_mode == CAMERA_MODE_INDEPENDENT) {
|
||||
_newUpShift = CAMERA_INDEPENDENT_MODE_UP_SHIFT;
|
||||
_newDistance = CAMERA_INDEPENDENT_MODE_DISTANCE;
|
||||
_newTightness = CAMERA_INDEPENDENT_MODE_TIGHTNESS;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::setTargetPosition(const glm::vec3& t) {
|
||||
_targetPosition = t;
|
||||
|
||||
// handle keepLookingAt
|
||||
if (_isKeepLookingAt) {
|
||||
lookAt(_lookingAt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Camera::setTargetRotation( const glm::quat& targetRotation ) {
|
||||
_targetRotation = targetRotation;
|
||||
}
|
||||
|
||||
void Camera::setFieldOfView(float f) {
|
||||
_fieldOfView = f;
|
||||
_frustumNeedsReshape = true;
|
||||
}
|
||||
|
||||
void Camera::setAspectRatio(float a) {
|
||||
_aspectRatio = a;
|
||||
_frustumNeedsReshape = true;
|
||||
}
|
||||
|
||||
void Camera::setNearClip(float n) {
|
||||
_nearClip = n;
|
||||
_frustumNeedsReshape = true;
|
||||
}
|
||||
|
||||
void Camera::setFarClip(float f) {
|
||||
_farClip = f;
|
||||
_frustumNeedsReshape = true;
|
||||
}
|
||||
|
||||
void Camera::setEyeOffsetPosition(const glm::vec3& p) {
|
||||
_eyeOffsetPosition = p;
|
||||
_frustumNeedsReshape = true;
|
||||
}
|
||||
|
||||
void Camera::setEyeOffsetOrientation(const glm::quat& o) {
|
||||
_eyeOffsetOrientation = o;
|
||||
_frustumNeedsReshape = true;
|
||||
}
|
||||
|
||||
void Camera::setScale(float s) {
|
||||
_scale = s;
|
||||
_needsToInitialize = true;
|
||||
_frustumNeedsReshape = true;
|
||||
}
|
||||
|
||||
void Camera::initialize() {
|
||||
_needsToInitialize = true;
|
||||
_modeShift = 0.0;
|
||||
}
|
||||
|
||||
// call to find out if the view frustum needs to be reshaped
|
||||
bool Camera::getFrustumNeedsReshape() const {
|
||||
return _frustumNeedsReshape;
|
||||
}
|
||||
|
||||
// call this when deciding whether to render the head or not
|
||||
CameraMode Camera::getInterpolatedMode() const {
|
||||
const float SHIFT_THRESHOLD_INTO_FIRST_PERSON = 0.7f;
|
||||
const float SHIFT_THRESHOLD_OUT_OF_FIRST_PERSON = 0.6f;
|
||||
if ((_mode == CAMERA_MODE_FIRST_PERSON && _linearModeShift < SHIFT_THRESHOLD_INTO_FIRST_PERSON) ||
|
||||
(_prevMode == CAMERA_MODE_FIRST_PERSON && _linearModeShift < SHIFT_THRESHOLD_OUT_OF_FIRST_PERSON)) {
|
||||
return _prevMode;
|
||||
}
|
||||
return _mode;
|
||||
}
|
||||
|
||||
// call this after reshaping the view frustum
|
||||
void Camera::setFrustumWasReshaped() {
|
||||
_frustumNeedsReshape = false;
|
||||
}
|
||||
|
||||
void Camera::lookAt(const glm::vec3& lookAt) {
|
||||
glm::vec3 up = IDENTITY_UP;
|
||||
glm::mat4 lookAtMatrix = glm::lookAt(_targetPosition, lookAt, up);
|
||||
glm::quat rotation = glm::quat_cast(lookAtMatrix);
|
||||
rotation.w = -rotation.w; // Rosedale approved
|
||||
setTargetRotation(rotation);
|
||||
}
|
||||
|
||||
void Camera::keepLookingAt(const glm::vec3& point) {
|
||||
lookAt(point);
|
||||
_isKeepLookingAt = true;
|
||||
_lookingAt = point;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
119
SvoViewer/src/Camera.h
Executable file
119
SvoViewer/src/Camera.h
Executable file
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// Camera.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__camera__
|
||||
#define __interface__camera__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
//const float DEFAULT_FIELD_OF_VIEW_DEGREES = 90.0f;
|
||||
|
||||
enum CameraMode
|
||||
{
|
||||
CAMERA_MODE_NULL = -1,
|
||||
CAMERA_MODE_THIRD_PERSON,
|
||||
CAMERA_MODE_FIRST_PERSON,
|
||||
CAMERA_MODE_MIRROR,
|
||||
CAMERA_MODE_INDEPENDENT,
|
||||
NUM_CAMERA_MODES
|
||||
};
|
||||
|
||||
class Camera {
|
||||
|
||||
public:
|
||||
Camera();
|
||||
|
||||
void initialize(); // instantly put the camera at the ideal position and rotation.
|
||||
|
||||
void update( float deltaTime );
|
||||
|
||||
void setUpShift(float u) { _upShift = u; }
|
||||
void setDistance(float d) { _distance = d; }
|
||||
void setPosition(const glm::vec3& p) { _position = p; }
|
||||
void setTargetPosition(const glm::vec3& t);
|
||||
void setTightness(float t) { _tightness = t; }
|
||||
void setTargetRotation(const glm::quat& rotation);
|
||||
|
||||
void setMode(CameraMode m);
|
||||
void setModeShiftPeriod(float r);
|
||||
void setFieldOfView(float f);
|
||||
void setAspectRatio(float a);
|
||||
void setNearClip(float n);
|
||||
void setFarClip(float f);
|
||||
void setEyeOffsetPosition(const glm::vec3& p);
|
||||
void setEyeOffsetOrientation(const glm::quat& o);
|
||||
void setScale(const float s);
|
||||
|
||||
const glm::vec3& getPosition() const { return _position; }
|
||||
const glm::quat& getRotation() const { return _rotation; }
|
||||
CameraMode getMode() const { return _mode; }
|
||||
const glm::vec3& getTargetPosition() const { return _targetPosition; }
|
||||
const glm::quat& getTargetRotation() const { return _targetRotation; }
|
||||
float getFieldOfView() const { return _fieldOfView; }
|
||||
float getAspectRatio() const { return _aspectRatio; }
|
||||
float getNearClip() const { return _scale * _nearClip; }
|
||||
float getFarClip() const;
|
||||
const glm::vec3& getEyeOffsetPosition() const { return _eyeOffsetPosition; }
|
||||
const glm::quat& getEyeOffsetOrientation() const { return _eyeOffsetOrientation; }
|
||||
float getScale() const { return _scale; }
|
||||
|
||||
CameraMode getInterpolatedMode() const;
|
||||
|
||||
bool getFrustumNeedsReshape() const; // call to find out if the view frustum needs to be reshaped
|
||||
void setFrustumWasReshaped(); // call this after reshaping the view frustum.
|
||||
|
||||
// These only work on independent cameras
|
||||
/// one time change to what the camera is looking at
|
||||
void lookAt(const glm::vec3& value);
|
||||
|
||||
/// fix what the camera is looking at, and keep the camera looking at this even if position changes
|
||||
void keepLookingAt(const glm::vec3& value);
|
||||
|
||||
/// stops the keep looking at feature, doesn't change what's being looked at, but will stop camera from
|
||||
/// continuing to update it's orientation to keep looking at the item
|
||||
void stopLooking() { _isKeepLookingAt = false; }
|
||||
|
||||
private:
|
||||
|
||||
bool _needsToInitialize;
|
||||
CameraMode _mode;
|
||||
CameraMode _prevMode;
|
||||
bool _frustumNeedsReshape;
|
||||
glm::vec3 _position;
|
||||
glm::vec3 _idealPosition;
|
||||
glm::vec3 _targetPosition;
|
||||
float _fieldOfView;
|
||||
float _aspectRatio;
|
||||
float _nearClip;
|
||||
float _farClip;
|
||||
glm::vec3 _eyeOffsetPosition;
|
||||
glm::quat _eyeOffsetOrientation;
|
||||
glm::quat _rotation;
|
||||
glm::quat _targetRotation;
|
||||
float _upShift;
|
||||
float _distance;
|
||||
float _tightness;
|
||||
float _previousUpShift;
|
||||
float _previousDistance;
|
||||
float _previousTightness;
|
||||
float _newUpShift;
|
||||
float _newDistance;
|
||||
float _newTightness;
|
||||
float _modeShift;
|
||||
float _linearModeShift;
|
||||
float _modeShiftPeriod;
|
||||
float _scale;
|
||||
|
||||
glm::vec3 _lookingAt;
|
||||
bool _isKeepLookingAt;
|
||||
|
||||
void updateFollowMode(float deltaTime);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
87
SvoViewer/src/GLCanvas.cpp
Executable file
87
SvoViewer/src/GLCanvas.cpp
Executable file
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// GLCanvas.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 8/14/13.
|
||||
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "SvoViewer.h"
|
||||
|
||||
#include "GLCanvas.h"
|
||||
#include <QMimeData>
|
||||
#include <QUrl>
|
||||
|
||||
GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)) {
|
||||
}
|
||||
|
||||
void GLCanvas::initializeGL() {
|
||||
SvoViewer::getInstance()->initializeGL();
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
|
||||
void GLCanvas::paintGL() {
|
||||
SvoViewer::getInstance()->paintGL();
|
||||
}
|
||||
|
||||
void GLCanvas::resizeGL(int width, int height) {
|
||||
SvoViewer::getInstance()->resizeGL(width, height);
|
||||
}
|
||||
|
||||
void GLCanvas::keyPressEvent(QKeyEvent* event) {
|
||||
SvoViewer::getInstance()->keyPressEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::keyReleaseEvent(QKeyEvent* event) {
|
||||
SvoViewer::getInstance()->keyReleaseEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::mouseMoveEvent(QMouseEvent* event) {
|
||||
SvoViewer::getInstance()->mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::mousePressEvent(QMouseEvent* event) {
|
||||
SvoViewer::getInstance()->mousePressEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::mouseReleaseEvent(QMouseEvent* event) {
|
||||
SvoViewer::getInstance()->mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
int updateTime = 0;
|
||||
bool GLCanvas::event(QEvent* event) {
|
||||
/* switch (event->type()) {
|
||||
case QEvent::TouchBegin:
|
||||
SvoViewer::getInstance()->touchBeginEvent(static_cast<QTouchEvent*>(event));
|
||||
event->accept();
|
||||
return true;
|
||||
case QEvent::TouchEnd:
|
||||
SvoViewer::getInstance()->touchEndEvent(static_cast<QTouchEvent*>(event));
|
||||
return true;
|
||||
case QEvent::TouchUpdate:
|
||||
SvoViewer::getInstance()->touchUpdateEvent(static_cast<QTouchEvent*>(event));
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}*/
|
||||
return QGLWidget::event(event);
|
||||
}
|
||||
|
||||
void GLCanvas::wheelEvent(QWheelEvent* event) {
|
||||
//SvoViewer::getInstance()->wheelEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::dragEnterEvent(QDragEnterEvent* event) {
|
||||
/*const QMimeData *mimeData = event->mimeData();
|
||||
foreach (QUrl url, mimeData->urls()) {
|
||||
if (url.url().toLower().endsWith(SNAPSHOT_EXTENSION)) {
|
||||
event->acceptProposedAction();
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void GLCanvas::dropEvent(QDropEvent* event) {
|
||||
//SvoViewer::getInstance()->dropEvent(event);
|
||||
}
|
39
SvoViewer/src/GLCanvas.h
Normal file
39
SvoViewer/src/GLCanvas.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// GLCanvas.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 8/14/13.
|
||||
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__GLCanvas__
|
||||
#define __hifi__GLCanvas__
|
||||
|
||||
#include <QGLWidget>
|
||||
|
||||
/// customized canvas that simply forwards requests/events to the singleton application
|
||||
class GLCanvas : public QGLWidget {
|
||||
public:
|
||||
GLCanvas();
|
||||
protected:
|
||||
|
||||
virtual void initializeGL();
|
||||
virtual void paintGL();
|
||||
virtual void resizeGL(int width, int height);
|
||||
|
||||
virtual void keyPressEvent(QKeyEvent* event);
|
||||
virtual void keyReleaseEvent(QKeyEvent* event);
|
||||
|
||||
virtual void mouseMoveEvent(QMouseEvent* event);
|
||||
virtual void mousePressEvent(QMouseEvent* event);
|
||||
virtual void mouseReleaseEvent(QMouseEvent* event);
|
||||
|
||||
virtual bool event(QEvent* event);
|
||||
|
||||
virtual void wheelEvent(QWheelEvent* event);
|
||||
|
||||
virtual void dragEnterEvent(QDragEnterEvent *event);
|
||||
virtual void dropEvent(QDropEvent* event);
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__GLCanvas__) */
|
20
SvoViewer/src/ProgramObject.cpp
Executable file
20
SvoViewer/src/ProgramObject.cpp
Executable file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// ProgramObject.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/7/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
|
||||
#include "ProgramObject.h"
|
||||
|
||||
ProgramObject::ProgramObject(QObject* parent) : QGLShaderProgram(parent) {
|
||||
}
|
||||
|
||||
void ProgramObject::setUniform(int location, const glm::vec3& value) {
|
||||
setUniformValue(location, value.x, value.y, value.z);
|
||||
}
|
||||
|
||||
void ProgramObject::setUniform(const char* name, const glm::vec3& value) {
|
||||
setUniformValue(name, value.x, value.y, value.z);
|
||||
}
|
||||
|
25
SvoViewer/src/ProgramObject.h
Executable file
25
SvoViewer/src/ProgramObject.h
Executable file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// ProgramObject.h
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/7/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__ProgramObject__
|
||||
#define __interface__ProgramObject__
|
||||
|
||||
#include <QGLShaderProgram>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class ProgramObject : public QGLShaderProgram {
|
||||
public:
|
||||
|
||||
ProgramObject(QObject* parent = 0);
|
||||
|
||||
void setUniform(int location, const glm::vec3& value);
|
||||
void setUniform(const char* name, const glm::vec3& value);
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__ProgramObject__) */
|
744
SvoViewer/src/Render.cpp
Executable file
744
SvoViewer/src/Render.cpp
Executable file
|
@ -0,0 +1,744 @@
|
|||
#include "svoviewer.h"
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Some GL helper functions
|
||||
|
||||
GLubyte SvoViewer::SetupGlVBO(GLuint * id, int sizeInBytes, GLenum target, GLenum usage, void * dataUp )
|
||||
{
|
||||
glGenBuffers(1, id);
|
||||
glBindBuffer(target, *id);
|
||||
glBufferData(target, sizeInBytes, dataUp, usage);
|
||||
return PrintGLErrorCode();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Include all the render methods here.
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Points system
|
||||
|
||||
bool SvoViewer::FindNumLeaves(OctreeElement* node, void* extraData)
|
||||
{
|
||||
VoxelTreeElement* voxel = (VoxelTreeElement*)node;
|
||||
FindNumLeavesData* args = (FindNumLeavesData*)extraData;
|
||||
if (node->isLeaf()) args->numLeaves++;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct PointRenderAssembleData
|
||||
{
|
||||
glm::vec3 * buffer;
|
||||
unsigned char* colorBuffer;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
bool SvoViewer::PointRenderAssemblePerVoxel(OctreeElement* node, void* extraData)
|
||||
{
|
||||
VoxelTreeElement* voxel = (VoxelTreeElement*)node;
|
||||
PointRenderAssembleData* args = (PointRenderAssembleData*)extraData;
|
||||
if (!node->isLeaf()) return true;
|
||||
AABox box = voxel->getAABox();
|
||||
glm::vec3 center = box.calcCenter();
|
||||
center += glm::vec3(0, -.05, 0);
|
||||
center *= 100.0;
|
||||
args->buffer[args->count] = center;
|
||||
int cCount = args->count * 3;
|
||||
args->colorBuffer[cCount] = voxel->getTrueColor()[0];
|
||||
args->colorBuffer[cCount+1] = voxel->getTrueColor()[1];
|
||||
args->colorBuffer[cCount+2] = voxel->getTrueColor()[2];
|
||||
args->count++;
|
||||
return true; // keep going!
|
||||
}
|
||||
|
||||
void SvoViewer::InitializePointRenderSystem()
|
||||
{
|
||||
DebugPrint("Initializing point render system!\n");
|
||||
quint64 fstart = usecTimestampNow();
|
||||
_renderFlags.voxelRenderDirty = true;
|
||||
_renderFlags.voxelOptRenderDirty = true;
|
||||
|
||||
glGenBuffers(1, &_pointVtxBuffer);
|
||||
glBindBuffer( GL_ARRAY_BUFFER, _pointVtxBuffer);
|
||||
|
||||
// Assemble the buffer data.
|
||||
PointRenderAssembleData args;
|
||||
args.buffer = _pointVertices = new glm::vec3[_nodeCount];
|
||||
args.colorBuffer = _pointColors = new unsigned char[_nodeCount*3];
|
||||
assert(args.buffer != NULL);
|
||||
args.count = 0;
|
||||
_systemTree.recurseTreeWithOperation(&PointRenderAssemblePerVoxel, &args);
|
||||
|
||||
assert(args.count < _nodeCount);
|
||||
_pointVerticesCount = args.count;
|
||||
|
||||
// create the data store.
|
||||
int size = _nodeCount * sizeof(glm::vec3);
|
||||
glBindBuffer( GL_ARRAY_BUFFER, _pointVtxBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, _nodeCount * 3, args.buffer, GL_STATIC_DRAW);
|
||||
//glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
|
||||
//glBindBuffer(GL_ARRAY_BUFFER, _pointColorBuffer);
|
||||
//glBufferData(GL_ARRAY_BUFFER, size, args.colorBuffer, GL_STATIC_DRAW);
|
||||
//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
|
||||
_renderFlags.ptRenderDirty = false;
|
||||
_ptRenderInitialized = true;
|
||||
float elapsed = (float)(usecTimestampNow() - fstart) / 1000.f;
|
||||
DebugPrint("Point render intialization took %f time for %d nodes\n", elapsed, _nodeCount);
|
||||
}
|
||||
|
||||
void SvoViewer::RenderTreeSystemAsPoints()
|
||||
{
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
//glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glColor3f(.5, 0, 0);
|
||||
glPointSize(1.0f);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableVertexAttribArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _pointVtxBuffer);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glVertexPointer(3, GL_FLOAT, 0, _pointVertices);
|
||||
|
||||
// Removed for testing.
|
||||
/*glEnableClientState(GL_COLOR_ARRAY);
|
||||
//glEnableVertexAttribArray(1);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _pointColorBuffer);*/
|
||||
//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
//glColorPointer(3, GL_UNSIGNED_BYTE, 0, _pointColors);
|
||||
|
||||
glDrawArrays(GL_POINTS, 0, _pointVerticesCount);
|
||||
}
|
||||
|
||||
void SvoViewer::StopUsingPointRenderSystem()
|
||||
{
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
const GLchar * simpleVtxShaderSrc =
|
||||
"uniform mat4 viewMatrix;\n\
|
||||
uniform mat4 projectionMatrix;\n\
|
||||
uniform mat4 modelMatrix;\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
vec4 world_pos = modelMatrix * gl_Vertex;\n\
|
||||
vec4 view_pos = viewMatrix * world_pos;\n\
|
||||
gl_Position = projectionMatrix * view_pos;\n\
|
||||
gl_FrontColor = gl_Color;\n\
|
||||
}\n";
|
||||
int simpleVtxShaderLen = strlen(simpleVtxShaderSrc);
|
||||
|
||||
const GLchar * simpleGeomShaderSrc =
|
||||
"#version 330 compatibility\n\
|
||||
layout(triangles) in;\n\
|
||||
layout(triangle_strip, max_vertices=3) out;\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
for(int i=0; i<3; i++)\n\
|
||||
{\n\
|
||||
gl_Position = gl_in[i].gl_Position;\n\
|
||||
EmitVertex();\n\
|
||||
}\n\
|
||||
EndPrimitive();\n\
|
||||
}";
|
||||
int simpleGeomShaderLen = strlen(simpleGeomShaderSrc);
|
||||
|
||||
const GLchar * simpleFragShaderSrc =
|
||||
"void main()\n\
|
||||
{\n\
|
||||
gl_FragColor = gl_Color;\n\
|
||||
}\n";
|
||||
int simpleFragShaderLen = strlen(simpleFragShaderSrc);
|
||||
|
||||
struct VoxelRenderAssembleData
|
||||
{
|
||||
glm::vec3 * buffer;
|
||||
unsigned char* colorBuffer;
|
||||
GLuint** idxBuffs;
|
||||
unsigned int leafCount;
|
||||
unsigned int lastBufferSegmentStart;
|
||||
GLuint vtxID;
|
||||
GLuint colorID;
|
||||
GLuint* idxIds;
|
||||
|
||||
};
|
||||
|
||||
bool SvoViewer::VoxelRenderAssemblePerVoxel(OctreeElement* node, void* extraData)
|
||||
{
|
||||
VoxelTreeElement* voxel = (VoxelTreeElement*)node;
|
||||
VoxelRenderAssembleData* args = (VoxelRenderAssembleData*)extraData;
|
||||
if (!node->isLeaf()) return true;
|
||||
|
||||
AABox box = voxel->getAABox();
|
||||
int totalNodesProcessedSinceLastFlush = args->leafCount - args->lastBufferSegmentStart;
|
||||
// ack, one of these components is flags, not alpha
|
||||
int cCount = totalNodesProcessedSinceLastFlush * 4; // Place it relative to the current segment.
|
||||
unsigned char col[4] = {voxel->getTrueColor()[0], voxel->getTrueColor()[1], voxel->getTrueColor()[2], 1};
|
||||
for(int i = 0; i < GLOBAL_NORMALS_VERTICES_PER_VOXEL; i++)
|
||||
memcpy(&args->colorBuffer[cCount+i*4], col, sizeof(col));
|
||||
|
||||
int vCount = totalNodesProcessedSinceLastFlush * GLOBAL_NORMALS_VERTICES_PER_VOXEL; // num vertices we've added so far.
|
||||
{
|
||||
int idxCount = totalNodesProcessedSinceLastFlush * INDICES_PER_FACE; // same for every cube face.
|
||||
// Indices follow a static pattern.
|
||||
for (int i = 0; i < NUM_CUBE_FACES; i++)
|
||||
{
|
||||
GLuint* idxBuff = args->idxBuffs[i];
|
||||
for (int j = 0; j < INDICES_PER_FACE; j++)
|
||||
{
|
||||
idxBuff[idxCount+j] = SvoViewerNames::cubeFaceIndices[i][j] + vCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Grab vtx positions according to setup from indices layout above.
|
||||
//center += glm::vec3(0, -.05, 0);
|
||||
float scale = 100.0;
|
||||
for ( int i = 0; i < GLOBAL_NORMALS_VERTICES_PER_VOXEL; i++)
|
||||
{
|
||||
args->buffer[vCount] = box.getVertex((BoxVertex)i); // i corresponds to BOTTOM_LEFT_NEAR,BOTTOM_RIGHT_NEAR,...
|
||||
args->buffer[vCount++] *= scale;
|
||||
}
|
||||
|
||||
args->leafCount++;
|
||||
totalNodesProcessedSinceLastFlush++;
|
||||
|
||||
if (totalNodesProcessedSinceLastFlush >= REASONABLY_LARGE_BUFFER) // Flush data to GL once we have assembled enough of it.
|
||||
{
|
||||
//DebugPrint("committing!\n");
|
||||
PrintGLErrorCode();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, args->vtxID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, args->lastBufferSegmentStart * sizeof(glm::vec3) * GLOBAL_NORMALS_VERTICES_PER_VOXEL,
|
||||
totalNodesProcessedSinceLastFlush * sizeof(glm::vec3) * GLOBAL_NORMALS_VERTICES_PER_VOXEL, args->buffer);
|
||||
PrintGLErrorCode();
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, args->colorID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, args->lastBufferSegmentStart * sizeof(GLubyte) * 4 * GLOBAL_NORMALS_VERTICES_PER_VOXEL,
|
||||
totalNodesProcessedSinceLastFlush * sizeof(GLubyte) * 4 * GLOBAL_NORMALS_VERTICES_PER_VOXEL, args->colorBuffer);
|
||||
PrintGLErrorCode();
|
||||
|
||||
for (int i = 0; i < NUM_CUBE_FACES; i++)
|
||||
{
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, args->idxIds[i]);
|
||||
GLuint* idxBuff = args->idxBuffs[i];
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, args->lastBufferSegmentStart * sizeof(GLuint) * INDICES_PER_FACE,
|
||||
totalNodesProcessedSinceLastFlush * sizeof(GLuint) * INDICES_PER_FACE, idxBuff); // Rework.
|
||||
PrintGLErrorCode();
|
||||
}
|
||||
glFlush();
|
||||
PrintGLErrorCode();
|
||||
args->lastBufferSegmentStart = args->leafCount;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SvoViewer::InitializeVoxelRenderSystem()
|
||||
{
|
||||
DebugPrint("Initializing voxel render system.\n");
|
||||
|
||||
FindNumLeavesData data;
|
||||
data.numLeaves = 0;
|
||||
_systemTree.recurseTreeWithOperation(&FindNumLeaves, &data);
|
||||
_leafCount = data.numLeaves;
|
||||
|
||||
glGenBuffers(NUM_CUBE_FACES, _vboIndicesIds);
|
||||
for (int i = 0; i < NUM_CUBE_FACES; i++)
|
||||
{
|
||||
_vboIndices[i] = new GLuint[REASONABLY_LARGE_BUFFER * INDICES_PER_FACE];
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesIds[i]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, INDICES_PER_FACE * sizeof(GLuint) * _nodeCount,
|
||||
NULL, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
glGenBuffers(1, &_vboVerticesID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glBufferData(GL_ARRAY_BUFFER, GLOBAL_NORMALS_VERTICES_PER_VOXEL * sizeof(glm::vec3) * _nodeCount, NULL, GL_STATIC_DRAW);
|
||||
PrintGLErrorCode();
|
||||
|
||||
glGenBuffers(1, &_vboColorsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glBufferData(GL_ARRAY_BUFFER, GLOBAL_NORMALS_VERTICES_PER_VOXEL * sizeof(GLubyte) * 4 * _nodeCount, NULL, GL_STATIC_DRAW);
|
||||
PrintGLErrorCode();
|
||||
|
||||
//int numVertices = GLOBAL_NORMALS_VERTICES_PER_VOXEL * _nodeCount;
|
||||
// Working set test = dead after about 1.5gb! I.e... don't try to allocate this here.
|
||||
// This will tell you about what you have to play with. On my system, it died consistently after 1.3-1.5gb.
|
||||
//glm::vec3* memPtrs[20];
|
||||
//int i;
|
||||
//for (i = 0; i < 20; i++)
|
||||
//{
|
||||
// memPtrs[i] = new glm::vec3[numVertices / 20];
|
||||
//}
|
||||
//
|
||||
//for (i = 0; i < 20; i++)
|
||||
// delete [] memPtrs[i];
|
||||
#define PAD 32
|
||||
_readVerticesArray = new glm::vec3[GLOBAL_NORMALS_VERTICES_PER_VOXEL * REASONABLY_LARGE_BUFFER + PAD];
|
||||
_readColorsArray = new GLubyte[(GLOBAL_NORMALS_VERTICES_PER_VOXEL * REASONABLY_LARGE_BUFFER * 4) + PAD];
|
||||
|
||||
// Assemble the buffer data.
|
||||
VoxelRenderAssembleData args;
|
||||
args.buffer = _readVerticesArray;
|
||||
args.colorBuffer = _readColorsArray;
|
||||
assert(args.buffer != NULL && args.colorBuffer != NULL);
|
||||
args.leafCount = 0;
|
||||
args.lastBufferSegmentStart = 0;
|
||||
args.idxIds = _vboIndicesIds;
|
||||
args.idxBuffs = _vboIndices;
|
||||
args.vtxID = _vboVerticesID;
|
||||
args.colorID = _vboColorsID;
|
||||
_systemTree.recurseTreeWithOperation(&VoxelRenderAssemblePerVoxel, &args);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), 0);
|
||||
glEnableVertexAttribArray(0);
|
||||
//glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(unsigned char) * 4, 0);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
// Set up the shaders.
|
||||
_vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
_geometryShader = glCreateShader(GL_GEOMETRY_SHADER);
|
||||
_pixelShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
glShaderSource(_vertexShader, 1, &simpleVtxShaderSrc, &simpleVtxShaderLen);
|
||||
glShaderSource(_geometryShader, 1, &simpleGeomShaderSrc, &simpleGeomShaderLen);
|
||||
glShaderSource(_pixelShader, 1, &simpleFragShaderSrc, &simpleFragShaderLen);
|
||||
|
||||
GLchar shaderLog[1000];
|
||||
GLsizei shaderLogLength;
|
||||
GLint compiled;
|
||||
glCompileShaderARB(&_vertexShader);
|
||||
glGetShaderInfoLog(_vertexShader, 1000, &shaderLogLength, shaderLog);
|
||||
if (shaderLog[0] != 0) DebugPrint("Shaderlog v :\n %s\n", shaderLog);
|
||||
glCompileShaderARB(&_geometryShader);
|
||||
glGetShaderInfoLog(_geometryShader, 1000, &shaderLogLength, shaderLog);
|
||||
if (shaderLog[0] != 0) DebugPrint("Shaderlog g :\n %s\n", shaderLog);
|
||||
glCompileShaderARB(&_pixelShader);
|
||||
glGetShaderInfoLog(_pixelShader, 51000, &shaderLogLength, shaderLog);
|
||||
if (shaderLog[0] != 0) DebugPrint("Shaderlog p :\n %s\n", shaderLog);
|
||||
|
||||
_linkProgram = glCreateProgram();
|
||||
glAttachShader(_linkProgram, _vertexShader);
|
||||
glAttachShader(_linkProgram, _geometryShader);
|
||||
glAttachShader(_linkProgram, _pixelShader);
|
||||
glLinkProgram(_linkProgram);
|
||||
GLint linked;
|
||||
glGetProgramiv(_linkProgram, GL_LINK_STATUS, &linked);
|
||||
if (!linked) DebugPrint("Linking failed! %d\n", linked);
|
||||
|
||||
|
||||
_voxelOptRenderInitialized = true;
|
||||
}
|
||||
|
||||
void SvoViewer::RenderTreeSystemAsVoxels()
|
||||
{
|
||||
if (!_voxelOptRenderInitialized) return; // What the??
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
// for performance, enable backface culling
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
// disable specular lighting for ground and voxels
|
||||
glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR);
|
||||
|
||||
setupWorldLight();
|
||||
|
||||
glNormal3f(0,1.0f,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesIds[CUBE_TOP]);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _leafCount - 1,
|
||||
INDICES_PER_FACE * _leafCount, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(0,-1.0f,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesIds[CUBE_BOTTOM]);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _leafCount - 1,
|
||||
INDICES_PER_FACE * _leafCount, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(-1.0f,0,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesIds[CUBE_LEFT]);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _leafCount - 1,
|
||||
INDICES_PER_FACE * _leafCount, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(1.0f,0,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesIds[CUBE_RIGHT]);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _leafCount - 1,
|
||||
INDICES_PER_FACE * _leafCount, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(0,0,-1.0f);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesIds[CUBE_FRONT]);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _leafCount - 1,
|
||||
INDICES_PER_FACE * _leafCount, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(0,0,1.0f);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesIds[CUBE_BACK]);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _leafCount - 1,
|
||||
INDICES_PER_FACE * _leafCount, GL_UNSIGNED_INT, 0);
|
||||
|
||||
//glDisable(GL_CULL_FACE);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void SvoViewer::StopUsingVoxelRenderSystem()
|
||||
{
|
||||
if (!_voxelOptRenderInitialized) return;
|
||||
//for (int i = 0; i < NUM_CUBE_FACES; i++) delete [] _vboIndices[i];
|
||||
//delete [] _readVerticesArray;
|
||||
//delete [] _readColorsArray;
|
||||
|
||||
glDeleteBuffers(1, &_vboVerticesID);
|
||||
glDeleteBuffers(1, &_vboColorsID);
|
||||
glDeleteBuffers(NUM_CUBE_FACES, _vboIndicesIds);
|
||||
_voxelOptRenderInitialized = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// NOTE - the voxel tree data structure doesn't currently have neighbor information encoded in any convenient searchable
|
||||
// way. So here I'm using a HUGE hack to compute repeated faces in the data structure. I 1) compute the barycentric coordinates
|
||||
// of every triangle for every leaf face. 2) Compute the center point for the triangle. (edit: I removed the barycentric part after some testing),
|
||||
// 3) That center point becomes a ID for that tri.
|
||||
// 4) If that ID is added more than once, discard this triangle, as it must be an internal. External triangles will only be added once.
|
||||
// SUBNOTE - I have NO idea how the tree traversal is actually happening as I haven't looked into its usage pattern. If traversal order was intelligent,
|
||||
// static and the pattern was predetermined, traversal could actually generate a mostly sorted list automatically. Because that isn't guaranteed
|
||||
// here, its uglier.
|
||||
|
||||
|
||||
// The
|
||||
bool SvoViewer::TrackVisibleFaces(OctreeElement* node, void* extraData)
|
||||
{
|
||||
VoxelTreeElement* voxel = (VoxelTreeElement*)node;
|
||||
VisibleFacesData* args = (VisibleFacesData*)extraData;
|
||||
if (!node->isLeaf()) return true;
|
||||
|
||||
AABox box = voxel->getAABox();
|
||||
glm::vec3 p0, p1, p2, p3, hackCenterVal;
|
||||
glm::vec3 cubeVerts[GLOBAL_NORMALS_VERTICES_PER_VOXEL];
|
||||
|
||||
for (int i = 0; i < GLOBAL_NORMALS_VERTICES_PER_VOXEL; i++) // Cache as aabox reconstructs with every call.
|
||||
cubeVerts[i] = box.getVertex((BoxVertex)i);
|
||||
|
||||
for (int i = 0; i < NUM_CUBE_FACES; i++)
|
||||
{
|
||||
p0 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][0]];
|
||||
p1 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][1]];
|
||||
p2 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][2]];
|
||||
p3 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][3]];
|
||||
hackCenterVal = computeQuickAndDirtyQuadCenter(p0, p1, p2, p3);
|
||||
args->ptList[args->count] += hackCenterVal;
|
||||
args->count++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do a binary search on the vector list.
|
||||
int SvoViewer::binVecSearch(glm::vec3 searchVal, glm::vec3* list, int count, int * found)
|
||||
{
|
||||
int key = count / 2;
|
||||
int lowerbound = 0;
|
||||
int upperbound = count-1;
|
||||
int lastkey = -1;
|
||||
while (lastkey != key)
|
||||
{
|
||||
lastkey = key;
|
||||
int ret = ptCloseEnough(&searchVal, &list[key]);
|
||||
if (ret == 0) { *found = 1; return key; }
|
||||
if (lowerbound == key || upperbound == key) { *found = 0; return key;} // closest we can get!
|
||||
if (ret < 0)
|
||||
{
|
||||
upperbound = key;
|
||||
if (key == lowerbound+1) key = lowerbound;
|
||||
else key = ((upperbound - lowerbound) / 2) + lowerbound;
|
||||
}
|
||||
else if (ret > 0)
|
||||
{
|
||||
lowerbound = key;
|
||||
if (key == upperbound-1) key = upperbound;
|
||||
else key = ((upperbound - lowerbound) /2) + lowerbound;
|
||||
}
|
||||
}
|
||||
*found = 0;
|
||||
return key;
|
||||
}
|
||||
|
||||
struct VoxelOptRenderAssembleData
|
||||
{
|
||||
Vertex* vtxBuffer;
|
||||
GLuint* idxBuffer;
|
||||
int vtxCount;
|
||||
int idxCount;
|
||||
AABoundingVolume bounds;
|
||||
int faceCenterCount;
|
||||
glm::vec3 * faceCenterList;
|
||||
int discardedCount;
|
||||
int elemCount;
|
||||
};
|
||||
|
||||
bool SvoViewer::VoxelOptRenderAssemblePerVoxel(OctreeElement* node, void* extraData)
|
||||
{
|
||||
VoxelTreeElement* voxel = (VoxelTreeElement*)node;
|
||||
VoxelOptRenderAssembleData* args = (VoxelOptRenderAssembleData*)extraData;
|
||||
if (!node->isLeaf()) return true;
|
||||
|
||||
AABox box = voxel->getAABox();
|
||||
|
||||
glm::vec3 p0, p1, p2, p3, hackCenterVal;
|
||||
glm::vec3 cubeVerts[GLOBAL_NORMALS_VERTICES_PER_VOXEL];
|
||||
for (int i = 0; i < GLOBAL_NORMALS_VERTICES_PER_VOXEL; i++) // Cache, as aabox reconstructs with every call.
|
||||
cubeVerts[i] = box.getVertex((BoxVertex)i);
|
||||
|
||||
bool doAddFace[NUM_CUBE_FACES] = {true, false, true, true, true, true}; // Cull bottom faces by default.
|
||||
|
||||
// Accumulate all the faces that need to be added.
|
||||
for (int i = 0; i < NUM_CUBE_FACES; i++)
|
||||
{
|
||||
p0 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][0]];
|
||||
p1 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][1]];
|
||||
p2 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][2]];
|
||||
p3 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][3]];
|
||||
hackCenterVal = computeQuickAndDirtyQuadCenter(p0, p1, p2, p3);
|
||||
// Search for this in the face center list
|
||||
//glm::vec3 * foundVal = (glm::vec3*)bsearch(&hackCenterVal, args->faceCenterList, args->faceCenterCount, sizeof(glm::vec3), ptCompFunc);
|
||||
int foundBVS = 0;
|
||||
int idxIntoList = binVecSearch(hackCenterVal, args->faceCenterList, args->faceCenterCount, &foundBVS);
|
||||
if (foundBVS == 0) { assert(0); continue; } // What the?
|
||||
//if (foundVal == NULL) { assert(0); continue; } // What the?
|
||||
//unsigned int idxIntoList = (foundVal - args->faceCenterList) / sizeof(glm::vec3);
|
||||
assert(idxIntoList <= args->faceCenterCount-1);
|
||||
// Now check face center list values that are immmediately adjacent to this value. If they're equal, don't add this face as
|
||||
// another leaf voxel must contain this triangle too.
|
||||
bool foundMatch = false;
|
||||
if (idxIntoList != 0)
|
||||
{
|
||||
if (ptCloseEnough(&hackCenterVal, &args->faceCenterList[idxIntoList-1]) == 0) foundMatch = true;
|
||||
}
|
||||
if (idxIntoList != args->faceCenterCount-1 && foundMatch == false)
|
||||
{
|
||||
if (ptCloseEnough(&hackCenterVal, &args->faceCenterList[idxIntoList+1]) == 0) foundMatch = true;
|
||||
}
|
||||
if (foundMatch)
|
||||
{
|
||||
doAddFace[i] = false; // Remove.
|
||||
args->discardedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
#define VTX_NOT_USED 255
|
||||
unsigned char vtxToAddMap[GLOBAL_NORMALS_VERTICES_PER_VOXEL]; // Map from vertex to actual position in the new vtx list.
|
||||
memset(vtxToAddMap, VTX_NOT_USED, sizeof(vtxToAddMap));
|
||||
|
||||
// Figure out what vertices to add. NOTE - QUICK and dirty. easy opt - precalulate bit pattern for every face and just & it.
|
||||
bool useVtx[GLOBAL_NORMALS_VERTICES_PER_VOXEL];
|
||||
memset(useVtx, 0, sizeof(useVtx));
|
||||
for ( int face = 0; face < NUM_CUBE_FACES; face++) // Vertex add order.
|
||||
{
|
||||
if (doAddFace[face])
|
||||
{
|
||||
for (int vOrder = 0; vOrder < 4; vOrder++)
|
||||
{
|
||||
useVtx[SvoViewerNames::cubeFaceVtxs[face][vOrder]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned char vtxAddedCount = 0;
|
||||
int baseVtxCount = args->vtxCount;
|
||||
for (int i = 0; i < GLOBAL_NORMALS_VERTICES_PER_VOXEL; i++)
|
||||
{
|
||||
if (useVtx[i])
|
||||
{
|
||||
vtxToAddMap[i] = vtxAddedCount;
|
||||
vtxAddedCount++;
|
||||
|
||||
args->vtxBuffer[args->vtxCount].position = cubeVerts[i];
|
||||
args->vtxBuffer[args->vtxCount].position *= 100;
|
||||
args->vtxBuffer[args->vtxCount].position.x -= 25;
|
||||
args->vtxBuffer[args->vtxCount].position.y -= 4;
|
||||
args->vtxBuffer[args->vtxCount].color[0] = voxel->getTrueColor()[0];
|
||||
args->vtxBuffer[args->vtxCount].color[1] = voxel->getTrueColor()[1];
|
||||
args->vtxBuffer[args->vtxCount].color[2] = voxel->getTrueColor()[2];
|
||||
args->vtxBuffer[args->vtxCount].color[3] = 1;
|
||||
args->bounds.AddToSet(args->vtxBuffer[args->vtxCount].position);
|
||||
args->vtxCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble the index lists.
|
||||
for ( int face = 0; face < NUM_CUBE_FACES; face++)
|
||||
{
|
||||
if (doAddFace[face])
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
// index is : current vtx + offset in map table
|
||||
args->idxBuffer[args->idxCount] = baseVtxCount + vtxToAddMap[ SvoViewerNames::cubeFaceIndices[face][i] ];
|
||||
args->idxCount++;
|
||||
args->elemCount += 2; // Add 2 elements per face
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SvoViewer::InitializeVoxelOptRenderSystem()
|
||||
{
|
||||
if (_voxelOptRenderInitialized) return;
|
||||
_numSegments = 0;
|
||||
_totalPossibleElems = 0;
|
||||
memset(_numChildNodeLeaves, 0, sizeof(_numChildNodeLeaves));
|
||||
memset(_segmentNodeReferences, 0, sizeof(_segmentNodeReferences));
|
||||
memset(_segmentBoundingVolumes, 0, sizeof(_segmentBoundingVolumes));
|
||||
|
||||
// Set up the segments. Find the number of leaves at each subtree.
|
||||
OctreeElement * rootNode = _systemTree.getRoot();
|
||||
OctreeElement* node0fromRoot = rootNode->getChildAtIndex(0); // ALL the interesting data for our test SVO is in this node! HACK!!
|
||||
int rootNumChildren = rootNode->getChildCount();
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++)
|
||||
{
|
||||
OctreeElement* childNode1stOrder = node0fromRoot->getChildAtIndex(i);
|
||||
if (childNode1stOrder == NULL) continue;
|
||||
// Grab 2nd order nodes for better separation. At some point, this would need to be done intelligently.
|
||||
for (int j = 0; j < NUMBER_OF_CHILDREN; j++)
|
||||
{
|
||||
OctreeElement* childNode2ndOrder = childNode1stOrder->getChildAtIndex(j);
|
||||
if (childNode2ndOrder == NULL) continue;
|
||||
|
||||
int num2ndOrderChildren = childNode2ndOrder->getChildCount();
|
||||
// Figure out how populated this child is.
|
||||
FindNumLeavesData data;
|
||||
data.numLeaves = 0;
|
||||
_systemTree.recurseNodeWithOperation(childNode2ndOrder, &FindNumLeaves, &data, 0);
|
||||
|
||||
// Some of these nodes have a single leaf. Ignore for the moment. We really only want the big segments in this test. Add this back in at some point.
|
||||
if (data.numLeaves > 1)
|
||||
{
|
||||
_numChildNodeLeaves[_numSegments] = data.numLeaves;
|
||||
_segmentNodeReferences[_numSegments] = childNode2ndOrder;
|
||||
_totalPossibleElems += data.numLeaves * NUM_CUBE_FACES * 2;
|
||||
_numSegments++;
|
||||
DebugPrint("child node %d %d has %d leaves and %d children itself\n", i, j, data.numLeaves, childNode2ndOrder->getChildCount());
|
||||
if (_numSegments >= MAX_NUM_OCTREE_PARTITIONS ) { DebugPrint("Out of segment space??? What the?\n"); break; }
|
||||
}
|
||||
}
|
||||
if (_numSegments >= MAX_NUM_OCTREE_PARTITIONS ) { DebugPrint("Out of segment space??? What the?\n"); break; }
|
||||
}
|
||||
|
||||
|
||||
// Set up the VBO's. Once for every partition we stored.
|
||||
for (int i = 0; i < _numSegments; i++)
|
||||
{
|
||||
// compute the visible set of this segment first.
|
||||
glm::vec3* faceCenters = new glm::vec3[NUM_CUBE_FACES *_numChildNodeLeaves[i]];
|
||||
VisibleFacesData visFaceData;
|
||||
visFaceData.ptList = faceCenters;
|
||||
visFaceData.count = 0;
|
||||
_systemTree.recurseNodeWithOperation(_segmentNodeReferences[i], &TrackVisibleFaces, &visFaceData, 0);
|
||||
// Now there's a list of all the face centers. Sort it.
|
||||
qsort(faceCenters, visFaceData.count, sizeof(glm::vec3), ptCompFunc);
|
||||
DebugPrint("Creating VBO's. Sorted neighbor list %d\n", i);
|
||||
|
||||
_readVertexStructs = new Vertex[GLOBAL_NORMALS_VERTICES_PER_VOXEL * _numChildNodeLeaves[i]];
|
||||
_readIndicesArray = new GLuint[NUM_CUBE_FACES * 2 * 3 * _numChildNodeLeaves[i]];
|
||||
|
||||
VoxelOptRenderAssembleData args;
|
||||
args.vtxBuffer = _readVertexStructs;
|
||||
args.idxBuffer = _readIndicesArray;
|
||||
args.vtxCount = 0;
|
||||
args.idxCount = 0;
|
||||
args.faceCenterCount = visFaceData.count;
|
||||
args.faceCenterList = visFaceData.ptList;
|
||||
args.discardedCount = 0;
|
||||
args.elemCount = 0;
|
||||
_systemTree.recurseNodeWithOperation(_segmentNodeReferences[i], &VoxelOptRenderAssemblePerVoxel, &args, 0);
|
||||
_segmentBoundingVolumes[i] = args.bounds;
|
||||
_segmentElemCount[i] = args.elemCount;
|
||||
|
||||
SetupGlVBO(&_vboOVerticesIds[i], args.vtxCount * sizeof(Vertex), GL_ARRAY_BUFFER, GL_STATIC_DRAW, _readVertexStructs);
|
||||
SetupGlVBO(&_vboOIndicesIds[i], args.idxCount * sizeof(GLuint), GL_ARRAY_BUFFER, GL_STATIC_DRAW, _readIndicesArray);
|
||||
|
||||
DebugPrint("Partition %d, vertices %d, indices %d, discarded %d\n", i, args.vtxCount, args.idxCount, args.discardedCount);
|
||||
|
||||
delete [] _readVertexStructs;
|
||||
delete [] _readIndicesArray;
|
||||
delete [] faceCenters;
|
||||
}
|
||||
|
||||
_voxelOptRenderInitialized = true;
|
||||
}
|
||||
|
||||
void SvoViewer::RenderTreeSystemAsOptVoxels()
|
||||
{
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
// disable specular lighting for ground and voxels
|
||||
glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR);
|
||||
|
||||
setupWorldLight();
|
||||
_numElemsDrawn = 0;
|
||||
for (int i = 0; i < _numSegments; i++)
|
||||
{
|
||||
if (_displayOnlyPartition == i || _displayOnlyPartition == NO_PARTITION )
|
||||
{
|
||||
if (isVisibleBV(&_segmentBoundingVolumes[i], &_myCamera, &_viewFrustum)) // Add aggressive LOD check here.
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboOVerticesIds[i]);
|
||||
glVertexAttribPointer(ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex,position));
|
||||
glEnableVertexAttribArray(ATTRIB_POSITION);
|
||||
|
||||
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex,color));
|
||||
glEnableVertexAttribArray(ATTRIB_COLOR);
|
||||
|
||||
//glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex,position));
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex,color));
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboOIndicesIds[i]);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, _segmentElemCount[i], GL_UNSIGNED_INT, NULL);
|
||||
_numElemsDrawn += _segmentElemCount[i];
|
||||
|
||||
/*glColor3f(.8f, 0.0f, 0.0f);
|
||||
glBegin(GL_POINTS);
|
||||
for (int j = 0; j < GLOBAL_NORMALS_VERTICES_PER_VOXEL; j++)
|
||||
{
|
||||
glm::vec3 pt = _segmentBoundingVolumes[i].getCorner((BoxVertex)j);
|
||||
glVertex3f(pt.x, pt.y, pt.z);
|
||||
}
|
||||
glEnd();*/
|
||||
}
|
||||
}
|
||||
}
|
||||
glDisableVertexAttribArray(ATTRIB_POSITION);
|
||||
glDisableVertexAttribArray(ATTRIB_COLOR);
|
||||
}
|
||||
|
||||
|
||||
void SvoViewer::StopUsingVoxelOptRenderSystem()
|
||||
{
|
||||
glDisableVertexAttribArray(ATTRIB_POSITION);
|
||||
glDisableVertexAttribArray(ATTRIB_COLOR);
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
|
0
SvoViewer/src/Render.h
Executable file
0
SvoViewer/src/Render.h
Executable file
375
SvoViewer/src/Render2.cpp
Executable file
375
SvoViewer/src/Render2.cpp
Executable file
|
@ -0,0 +1,375 @@
|
|||
#include "svoviewer.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Helper functions
|
||||
|
||||
inline glm::vec3 SvoViewer::computeQuickAndDirtyQuadCenter(glm::vec3 p0, glm::vec3 p1, glm::vec3 p2, glm::vec3 p3)
|
||||
{
|
||||
glm::vec3 avg = p0 + p1 + p2 + p3;
|
||||
avg /= 4.0f;
|
||||
return avg;
|
||||
}
|
||||
|
||||
// Precision dependent hack. After debugging - change this to a magnitude function.
|
||||
// simple version for clarity/debugging.
|
||||
int SvoViewer::ptCompFunc(const void * a, const void * b)
|
||||
{
|
||||
if ((*(glm::vec3*)a).x < (*(glm::vec3*)b).x) return -1;
|
||||
else if ((*(glm::vec3*)a).x > (*(glm::vec3*)b).x) return 1;
|
||||
|
||||
if ((*(glm::vec3*)a).y < (*(glm::vec3*)b).y) return -1;
|
||||
else if ((*(glm::vec3*)a).y > (*(glm::vec3*)b).y) return 1;
|
||||
|
||||
if ((*(glm::vec3*)a).z < (*(glm::vec3*)b).z) return -1;
|
||||
else if ((*(glm::vec3*)a).z > (*(glm::vec3*)b).z) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//#define PRECISION_ERR .00000001
|
||||
#define PRECISION_ERR .00001
|
||||
// aggressive mode
|
||||
//(0.00097656250 /2) // Space of smallest voxel should define our error bounds here. Test this if time allows.
|
||||
int SvoViewer::ptCloseEnough(const void * a, const void * b)
|
||||
{
|
||||
glm::vec3 diffVec = (*(glm::vec3*)a) - (*(glm::vec3*)b);
|
||||
if (fabs(diffVec.x) < PRECISION_ERR && fabs(diffVec.y) < PRECISION_ERR && fabs(diffVec.z) < PRECISION_ERR) return 0;
|
||||
//float len = diffVec.length();
|
||||
//if (len < PRECISION_ERR) return 0;
|
||||
if ((*(glm::vec3*)a).x < (*(glm::vec3*)b).x) return -1;
|
||||
else if ((*(glm::vec3*)a).x > (*(glm::vec3*)b).x) return 1;
|
||||
if ((*(glm::vec3*)a).y < (*(glm::vec3*)b).y) return -1;
|
||||
else if ((*(glm::vec3*)a).y > (*(glm::vec3*)b).y) return 1;
|
||||
if ((*(glm::vec3*)a).z < (*(glm::vec3*)b).z) return -1;
|
||||
else if ((*(glm::vec3*)a).z > (*(glm::vec3*)b).z) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return parameterized intersection in t.
|
||||
bool SvoViewer::parameterizedRayPlaneIntersection(const glm::vec3 origin, const glm::vec3 direction, const glm::vec3 planePt, const glm::vec3 planeNormal, float *t)
|
||||
{
|
||||
float denom = glm::dot(direction, planeNormal);
|
||||
if (denom < PRECISION_ERR) return false;
|
||||
|
||||
glm::vec3 p010 = planePt - origin;
|
||||
*t = glm::dot(p010, planeNormal) / denom;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// 2nd stab at optimizing this. Cull back faces more aggressively.
|
||||
|
||||
|
||||
struct VoxelOpt2RenderAssembleData
|
||||
{
|
||||
Vertex* vtxBuffer;
|
||||
VoxelDimIdxSet* idxSet;
|
||||
int vtxCount;
|
||||
int faceCenterCount;
|
||||
glm::vec3 * faceCenterList;
|
||||
int discardedCount;
|
||||
};
|
||||
|
||||
bool SvoViewer::VoxelOpt2RenderAssemblePerVoxel(OctreeElement* node, void* extraData)
|
||||
{
|
||||
VoxelTreeElement* voxel = (VoxelTreeElement*)node;
|
||||
VoxelOpt2RenderAssembleData* args = (VoxelOpt2RenderAssembleData*)extraData;
|
||||
if (!node->isLeaf()) return true;
|
||||
|
||||
AABox box = voxel->getAABox();
|
||||
|
||||
glm::vec3 p0, p1, p2, p3, hackCenterVal;
|
||||
glm::vec3 cubeVerts[GLOBAL_NORMALS_VERTICES_PER_VOXEL];
|
||||
for (int i = 0; i < GLOBAL_NORMALS_VERTICES_PER_VOXEL; i++) // Cache, as aabox reconstructs with every call.
|
||||
cubeVerts[i] = box.getVertex((BoxVertex)i);
|
||||
|
||||
bool doAddFace[NUM_CUBE_FACES] = {true, false, true, true, true, true}; // Cull bottom faces by default.
|
||||
|
||||
// Accumulate all the faces that need to be added.
|
||||
for (int i = 0; i < NUM_CUBE_FACES; i++)
|
||||
{
|
||||
p0 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][0]];
|
||||
p1 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][1]];
|
||||
p2 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][2]];
|
||||
p3 = cubeVerts[SvoViewerNames::cubeFaceVtxs[i][3]];
|
||||
hackCenterVal = computeQuickAndDirtyQuadCenter(p0, p1, p2, p3);
|
||||
// Search for this in the face center list
|
||||
//glm::vec3 * foundVal = (glm::vec3*)bsearch(&hackCenterVal, args->faceCenterList, args->faceCenterCount, sizeof(glm::vec3), ptCompFunc);
|
||||
// BSEARCH FAILING! What the? wrote my own index approximate version.
|
||||
int foundBVS = 0;
|
||||
int idxIntoList = binVecSearch(hackCenterVal, args->faceCenterList, args->faceCenterCount, &foundBVS);
|
||||
if (foundBVS == 0) { assert(0); continue; } // What the?
|
||||
assert(idxIntoList <= args->faceCenterCount-1);
|
||||
// Now check face center list values that are immmediately adjacent to this value. If they're equal, don't add this face as
|
||||
// another leaf voxel must contain this triangle too.
|
||||
bool foundMatch = false;
|
||||
if (idxIntoList != 0)
|
||||
{
|
||||
if (ptCloseEnough(&hackCenterVal, &args->faceCenterList[idxIntoList-1]) == 0) foundMatch = true;
|
||||
}
|
||||
if (idxIntoList != args->faceCenterCount-1 && foundMatch == false)
|
||||
{
|
||||
if (ptCloseEnough(&hackCenterVal, &args->faceCenterList[idxIntoList+1]) == 0) foundMatch = true;
|
||||
}
|
||||
if (foundMatch)
|
||||
{
|
||||
doAddFace[i] = false; // Remove.
|
||||
args->discardedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
#define VTX_NOT_USED 255
|
||||
unsigned char vtxToAddMap[GLOBAL_NORMALS_VERTICES_PER_VOXEL]; // Map from vertex to actual position in the new vtx list.
|
||||
memset(vtxToAddMap, VTX_NOT_USED, sizeof(vtxToAddMap));
|
||||
|
||||
// Figure out what vertices to add. NOTE - QUICK and dirty. easy opt - precalulate bit pattern for every face and just & it.
|
||||
bool useVtx[GLOBAL_NORMALS_VERTICES_PER_VOXEL];
|
||||
memset(useVtx, 0, sizeof(useVtx));
|
||||
for ( int face = 0; face < NUM_CUBE_FACES; face++) // Vertex add order.
|
||||
{
|
||||
if (doAddFace[face])
|
||||
{
|
||||
for (int vOrder = 0; vOrder < 4; vOrder++)
|
||||
{
|
||||
useVtx[SvoViewerNames::cubeFaceVtxs[face][vOrder]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned char vtxAddedCount = 0;
|
||||
int baseVtxCount = args->vtxCount;
|
||||
for (int i = 0; i < GLOBAL_NORMALS_VERTICES_PER_VOXEL; i++)
|
||||
{
|
||||
if (useVtx[i])
|
||||
{
|
||||
vtxToAddMap[i] = vtxAddedCount;
|
||||
vtxAddedCount++;
|
||||
|
||||
args->vtxBuffer[args->vtxCount].position = cubeVerts[i];
|
||||
args->vtxBuffer[args->vtxCount].position *= 100;
|
||||
args->vtxBuffer[args->vtxCount].position.x -= 25;
|
||||
args->vtxBuffer[args->vtxCount].position.y -= 4;
|
||||
args->vtxBuffer[args->vtxCount].color[0] = voxel->getTrueColor()[0];
|
||||
args->vtxBuffer[args->vtxCount].color[1] = voxel->getTrueColor()[1];
|
||||
args->vtxBuffer[args->vtxCount].color[2] = voxel->getTrueColor()[2];
|
||||
args->vtxBuffer[args->vtxCount].color[3] = 1;
|
||||
cubeVerts[i] = args->vtxBuffer[args->vtxCount].position;
|
||||
args->vtxCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble the index lists.
|
||||
for ( int face = 0; face < NUM_CUBE_FACES; face++)
|
||||
{
|
||||
if (doAddFace[face])
|
||||
{
|
||||
for (int i = 0; i < 6; i++) // 2 * 3 triangles.
|
||||
{
|
||||
args->idxSet->idxBuff[face][args->idxSet->idxCount[face]] = baseVtxCount + vtxToAddMap[ SvoViewerNames::cubeFaceIndices[face][i] ];
|
||||
args->idxSet->idxCount[face]++;
|
||||
}
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
args->idxSet->bounds[face].AddToSet( cubeVerts[SvoViewerNames::cubeFaceVtxs[face][i]] );
|
||||
}
|
||||
args->idxSet->elemCount[face] += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SvoViewer::InitializeVoxelOpt2RenderSystem()
|
||||
{
|
||||
quint64 startInit = usecTimestampNow();
|
||||
if (_voxelOptRenderInitialized) return;
|
||||
_numSegments = 0;
|
||||
_totalPossibleElems = 0;
|
||||
memset(_numChildNodeLeaves, 0, sizeof(_numChildNodeLeaves));
|
||||
memset(_segmentNodeReferences, 0, sizeof(_segmentNodeReferences));
|
||||
|
||||
// Set up the segments. Find the number of leaves at each subtree.
|
||||
OctreeElement * rootNode = _systemTree.getRoot();
|
||||
OctreeElement* node0fromRoot = rootNode->getChildAtIndex(0); // ALL the interesting data for our test SVO is in this node! HACK!!
|
||||
int rootNumChildren = rootNode->getChildCount();
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++)
|
||||
{
|
||||
OctreeElement* childNode1stOrder = node0fromRoot->getChildAtIndex(i);
|
||||
if (childNode1stOrder == NULL) continue;
|
||||
// Grab 2nd order nodes for better separation. At some point, this would need to be done intelligently.
|
||||
for (int j = 0; j < NUMBER_OF_CHILDREN; j++)
|
||||
{
|
||||
OctreeElement* childNode2ndOrder = childNode1stOrder->getChildAtIndex(j);
|
||||
if (childNode2ndOrder == NULL) continue;
|
||||
|
||||
int num2ndOrderChildren = childNode2ndOrder->getChildCount();
|
||||
// Figure out how populated this child is.
|
||||
FindNumLeavesData data;
|
||||
data.numLeaves = 0;
|
||||
_systemTree.recurseNodeWithOperation(childNode2ndOrder, &FindNumLeaves, &data, 0);
|
||||
|
||||
// Some of these nodes have a single leaf. Ignore for the moment. We really only want the big segments in this test. Add this back in at some point.
|
||||
if (data.numLeaves > 1)
|
||||
{
|
||||
_numChildNodeLeaves[_numSegments] = data.numLeaves;
|
||||
_segmentNodeReferences[_numSegments] = childNode2ndOrder;
|
||||
_totalPossibleElems += data.numLeaves * NUM_CUBE_FACES * 2;
|
||||
_numSegments++;
|
||||
DebugPrint("child node %d %d has %d leaves and %d children itself\n", i, j, data.numLeaves, childNode2ndOrder->getChildCount());
|
||||
if (_numSegments >= MAX_NUM_OCTREE_PARTITIONS ) { DebugPrint("Out of segment space??? What the?\n"); break; }
|
||||
}
|
||||
}
|
||||
if (_numSegments >= MAX_NUM_OCTREE_PARTITIONS ) { DebugPrint("Out of segment space??? What the?\n"); break; }
|
||||
}
|
||||
|
||||
|
||||
// Set up the VBO's. Once for every partition we stored.
|
||||
for (int i = 0; i < _numSegments; i++)
|
||||
{
|
||||
// compute the visible set of this segment first.
|
||||
glm::vec3* faceCenters = new glm::vec3[NUM_CUBE_FACES *_numChildNodeLeaves[i]];
|
||||
VisibleFacesData visFaceData;
|
||||
visFaceData.ptList = faceCenters;
|
||||
visFaceData.count = 0;
|
||||
_systemTree.recurseNodeWithOperation(_segmentNodeReferences[i], &TrackVisibleFaces, &visFaceData, 0);
|
||||
// Now there's a list of all the face centers. Sort it.
|
||||
qsort(faceCenters, visFaceData.count, sizeof(glm::vec3), ptCompFunc);
|
||||
DebugPrint("Creating VBO's. Sorted neighbor list %d\n", i);
|
||||
|
||||
_readVertexStructs = new Vertex[GLOBAL_NORMALS_VERTICES_PER_VOXEL * _numChildNodeLeaves[i]];
|
||||
memset(&_segmentIdxBuffers[i], 0, sizeof(VoxelDimIdxSet)); // Don't do it this way if we ever use a vtable for AABoundingVolumes!
|
||||
for (int k = 0; k < NUM_CUBE_FACES; k++)
|
||||
{
|
||||
_segmentIdxBuffers[i].idxBuff[k] = new GLuint[2 * 3 * _numChildNodeLeaves[i]];
|
||||
assert(_segmentIdxBuffers[i].idxBuff[k] != NULL);
|
||||
}
|
||||
|
||||
VoxelOpt2RenderAssembleData args;
|
||||
args.vtxBuffer = _readVertexStructs;
|
||||
args.vtxCount = 0;
|
||||
args.faceCenterCount = visFaceData.count;
|
||||
args.faceCenterList = visFaceData.ptList;
|
||||
args.discardedCount = 0;
|
||||
args.idxSet = &_segmentIdxBuffers[i];
|
||||
_systemTree.recurseNodeWithOperation(_segmentNodeReferences[i], &VoxelOpt2RenderAssemblePerVoxel, &args, 0);
|
||||
|
||||
SetupGlVBO(&_vboOVerticesIds[i], args.vtxCount * sizeof(Vertex), GL_ARRAY_BUFFER, GL_STATIC_DRAW, _readVertexStructs);
|
||||
unsigned int idxCount = 0;
|
||||
for (int k = 0; k < NUM_CUBE_FACES; k++)
|
||||
{
|
||||
SetupGlVBO(&_segmentIdxBuffers[i].idxIds[k], _segmentIdxBuffers[i].idxCount[k] * sizeof(GLuint),
|
||||
GL_ARRAY_BUFFER, GL_STATIC_DRAW, _segmentIdxBuffers[i].idxBuff[k]);
|
||||
idxCount += _segmentIdxBuffers[i].idxCount[k];
|
||||
_segmentIdxBuffers[i].bounds[k].setIsSingleDirection(true, SvoViewerNames::faceNormals[k]);
|
||||
}
|
||||
|
||||
DebugPrint("Partition %d, vertices %d, indices %d, discarded %d\n", i, args.vtxCount, idxCount, args.discardedCount);
|
||||
|
||||
delete [] _readVertexStructs;
|
||||
//delete [] _readIndicesArray;
|
||||
delete [] faceCenters;
|
||||
for (int k = 0; k < NUM_CUBE_FACES; k++) if (_segmentIdxBuffers[i].idxBuff[k] != NULL) delete [] _segmentIdxBuffers[i].idxBuff[k];
|
||||
}
|
||||
|
||||
_voxelOptRenderInitialized = true;
|
||||
|
||||
UpdateOpt2BVFaceVisibility();
|
||||
|
||||
quint64 endInit = usecTimestampNow();
|
||||
quint64 elapsed = endInit - startInit;
|
||||
qDebug() << "init elapsed:" << ((float)elapsed / (float)1000000.0f) << "seconds";
|
||||
|
||||
}
|
||||
|
||||
void SvoViewer::RenderTreeSystemAsOpt2Voxels()
|
||||
{
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
// disable specular lighting for ground and voxels
|
||||
glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR);
|
||||
|
||||
setupWorldLight();
|
||||
_numElemsDrawn = 0;
|
||||
for (int i = 0; i < _numSegments; i++)
|
||||
{
|
||||
if (_displayOnlyPartition == i || _displayOnlyPartition == NO_PARTITION )
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboOVerticesIds[i]);
|
||||
glVertexAttribPointer(ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex,position));
|
||||
glEnableVertexAttribArray(ATTRIB_POSITION);
|
||||
|
||||
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex,color));
|
||||
glEnableVertexAttribArray(ATTRIB_COLOR);
|
||||
|
||||
//glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex,position));
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex,color));
|
||||
|
||||
for (int j = 0; j < NUM_CUBE_FACES; j++)
|
||||
{
|
||||
// Add aggressive LOD check here.
|
||||
if (_segmentIdxBuffers[i].visibleFace[j] || _useBoundingVolumes != true)
|
||||
{
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _segmentIdxBuffers[i].idxIds[j]);//_vboOIndicesIds[i]);
|
||||
glDrawElements(GL_TRIANGLES, _segmentIdxBuffers[i].elemCount[j]*3, GL_UNSIGNED_INT, NULL);
|
||||
_numElemsDrawn += _segmentIdxBuffers[i].elemCount[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
glDisableVertexAttribArray(ATTRIB_POSITION);
|
||||
glDisableVertexAttribArray(ATTRIB_COLOR);
|
||||
}
|
||||
|
||||
// special rules for single direction bv sets. Basically, we intersect a lookat ray from the camera with two opposite faces and discard
|
||||
// the entire set of the face that is further away as it must be back facing.
|
||||
void SvoViewer::UpdateOpt2BVFaceVisibility()
|
||||
{
|
||||
if (_currentShaderModel != RENDER_OPT_CULLED_POLYS || _voxelOptRenderInitialized != true ) return;
|
||||
|
||||
float faceParamVals[NUM_CUBE_FACES];
|
||||
glm::vec3 pos = _myCamera.getPosition();
|
||||
|
||||
for (int i = 0; i < _numSegments; i++)
|
||||
{
|
||||
VoxelDimIdxSet* setPtr = &_segmentIdxBuffers[i];
|
||||
// Fast cull check.
|
||||
setPtr->visibleFace[0] = (_segmentIdxBuffers[i].bounds[0].within(pos.y, 1) >= 0) ? true : false;
|
||||
setPtr->visibleFace[1] = (_segmentIdxBuffers[i].bounds[1].within(pos.y, 1) <= 0) ? true : false;
|
||||
setPtr->visibleFace[2] = (_segmentIdxBuffers[i].bounds[2].within(pos.x, 0) >= 0) ? true : false;
|
||||
setPtr->visibleFace[3] = (_segmentIdxBuffers[i].bounds[3].within(pos.x, 0) <= 0) ? true : false;
|
||||
setPtr->visibleFace[4] = (_segmentIdxBuffers[i].bounds[4].within(pos.z, 2) <= 0) ? true : false;
|
||||
setPtr->visibleFace[5] = (_segmentIdxBuffers[i].bounds[5].within(pos.z, 2) >= 0) ? true : false;
|
||||
|
||||
// Make sure its actually on the screen.
|
||||
/*for (int j = 0; j < NUM_CUBE_FACES; j++)
|
||||
{
|
||||
if (setPtr->visibleFace[j])
|
||||
{
|
||||
if (visibleAngleSubtended(&_segmentIdxBuffers[i].bounds[j], &_myCamera, &_viewFrustum) <= 0)
|
||||
setPtr->visibleFace[j] = false;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
/*
|
||||
for (int j = 0; j < NUM_CUBE_FACES; j++)
|
||||
{
|
||||
setPtr->visibleFace[i] = true;
|
||||
AABoundingVolume* volume = &_segmentIdxBuffers[i].bounds[j];
|
||||
glm::vec3 randomPlaneVtx = volume->getCorner((BoxVertex)SvoViewerNames::cubeFaceIndices[j][0]);
|
||||
glm::vec3 raydir = randomPlaneVtx - pos;
|
||||
rayder /= glm::length(raydir);
|
||||
if (glm::dot(target, raydir) < 1) raydir *= -1;
|
||||
if (!parameterizedRayPlaneIntersection(pos, raydir, randomPlaneVtx, SvoViewerNames::faceNormals[j], &faceParamVals[j]))
|
||||
faceParamVals[j] = -1;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void SvoViewer::StopUsingVoxelOpt2RenderSystem()
|
||||
{
|
||||
glDisableVertexAttribArray(ATTRIB_POSITION);
|
||||
glDisableVertexAttribArray(ATTRIB_COLOR);
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
BIN
SvoViewer/src/SvoViewer.ico
Executable file
BIN
SvoViewer/src/SvoViewer.ico
Executable file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
2
SvoViewer/src/SvoViewer.rc
Executable file
2
SvoViewer/src/SvoViewer.rc
Executable file
|
@ -0,0 +1,2 @@
|
|||
IDI_ICON1 ICON DISCARDABLE "SvoViewer.ico"
|
||||
|
67
SvoViewer/src/globals.cpp
Executable file
67
SvoViewer/src/globals.cpp
Executable file
|
@ -0,0 +1,67 @@
|
|||
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
const GLfloat WHITE_SPECULAR_COLOR[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
const GLfloat NO_SPECULAR_COLOR[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
namespace SvoViewerNames // avoid conflicts with voxelSystem namespace objects
|
||||
{
|
||||
float identityVerticesGlobalNormals[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 };
|
||||
|
||||
float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, //0-7
|
||||
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, //8-15
|
||||
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 }; // 16-23
|
||||
|
||||
GLfloat identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1,
|
||||
0,0,+1, 0,0,+1, 0,0,+1, 0,0,+1,
|
||||
0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0,
|
||||
0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0,
|
||||
-1,0,0, +1,0,0, +1,0,0, -1,0,0,
|
||||
-1,0,0, +1,0,0, +1,0,0, -1,0,0 };
|
||||
|
||||
GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z-
|
||||
8,9,13, 8,13,12, // Y-
|
||||
16,23,19, 16,20,23, // X-
|
||||
17,18,22, 17,22,21, // X+
|
||||
10,11,15, 10,15,14, // Y+
|
||||
4,5,6, 4,6,7 }; // Z+
|
||||
|
||||
GLubyte identityIndicesTop[] = { 2, 3, 7, 2, 7, 6 };
|
||||
GLubyte identityIndicesBottom[] = { 0, 1, 5, 0, 5, 4 };
|
||||
GLubyte identityIndicesLeft[] = { 0, 7, 3, 0, 4, 7 };
|
||||
GLubyte identityIndicesRight[] = { 1, 2, 6, 1, 6, 5 };
|
||||
GLubyte identityIndicesFront[] = { 0, 2, 1, 0, 3, 2 };
|
||||
GLubyte identityIndicesBack[] = { 4, 5, 6, 4, 6, 7 };
|
||||
|
||||
GLubyte cubeFaceIndices[][2*3] =
|
||||
{
|
||||
{ 2, 3, 7, 2, 7, 6 },
|
||||
{ 0, 1, 5, 0, 5, 4 },
|
||||
{ 0, 7, 3, 0, 4, 7 },
|
||||
{ 1, 2, 6, 1, 6, 5 },
|
||||
{ 0, 2, 1, 0, 3, 2 },
|
||||
{ 4, 5, 6, 4, 6, 7 }
|
||||
};
|
||||
|
||||
GLubyte cubeFaceVtxs[6][4] =
|
||||
{
|
||||
{ 2, 3, 6, 7 },
|
||||
{ 0, 1, 4, 5 },
|
||||
{ 0, 3, 4, 7 },
|
||||
{ 1, 2, 5, 6 },
|
||||
{ 0, 1, 2, 3 },
|
||||
{ 4, 5, 6, 7 }
|
||||
};
|
||||
|
||||
glm::vec3 faceNormals[6] =
|
||||
{
|
||||
glm::vec3(0.0, 1.0, 0.0),
|
||||
glm::vec3(0.0, -1.0, 0.0),
|
||||
glm::vec3(-1.0, 0.0, 0.0),
|
||||
glm::vec3(1.0, 0.0, 0.0),
|
||||
glm::vec3(0.0, 0.0, 1.0),
|
||||
glm::vec3(0.0, 0.0, -1.0)
|
||||
};
|
||||
|
||||
} // SvoViewerNames
|
33
SvoViewer/src/globals.h
Executable file
33
SvoViewer/src/globals.h
Executable file
|
@ -0,0 +1,33 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "SvoViewerConfig.h"
|
||||
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QDesktopWidget>
|
||||
#include <QOpenGLFramebufferObject>
|
||||
//#include <GLCanvas>
|
||||
|
||||
//#include "ui_svoviewer.h"
|
||||
#include <ViewFrustum.h>
|
||||
#include <VoxelTree.h>
|
||||
#include <SharedUtil.h>
|
||||
//#include <VoxelShader.h>
|
||||
//#include <VoxelSystem.h>
|
||||
//#include <PointShader.h>
|
||||
#include <OctreeRenderer.h>
|
||||
|
||||
#include "Camera.h"
|
||||
|
||||
|
||||
extern const GLfloat WHITE_SPECULAR_COLOR[];
|
||||
extern const GLfloat NO_SPECULAR_COLOR[];
|
||||
|
||||
namespace SvoViewerNames // avoid conflicts with voxelSystem namespace objects
|
||||
{
|
||||
extern GLubyte cubeFaceIndices[][2*3];
|
||||
|
||||
extern GLubyte cubeFaceVtxs[6][4];
|
||||
|
||||
extern glm::vec3 faceNormals[6];
|
||||
}
|
8
SvoViewer/src/main.cpp
Executable file
8
SvoViewer/src/main.cpp
Executable file
|
@ -0,0 +1,8 @@
|
|||
#include "svoviewer.h"
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
SvoViewer svoV(argc, argv);
|
||||
return svoV.exec();
|
||||
}
|
644
SvoViewer/src/svoviewer.cpp
Executable file
644
SvoViewer/src/svoviewer.cpp
Executable file
|
@ -0,0 +1,644 @@
|
|||
#include "svoviewer.h"
|
||||
#include "GLCanvas.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <QDesktopWidget>
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <qtimer.h>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
|
||||
|
||||
const int IDLE_SIMULATE_MSECS = 1; // How often should call simulate and other stuff
|
||||
// in the idle loop? (60 FPS is default)
|
||||
// Empirically, I found 5 to be about 60fps
|
||||
|
||||
static QTimer* idleTimer = NULL;
|
||||
const ViewFrustumOffset DEFAULT_FRUSTUM_OFFSET = {-135.0f, 0.0f, 0.0f, 25.0f, 0.0f};
|
||||
SvoViewer * _globalSvoViewerObj; // Hack :: var to store global pointer since this wasn't designed to work with the interface nodelist.
|
||||
|
||||
SvoViewer::SvoViewer(int& argc, char** argv, QWidget *parent)
|
||||
: QApplication(argc, argv),
|
||||
_window(new QMainWindow(desktop())),
|
||||
_glWidget(new GLCanvas()),
|
||||
_width(1280),
|
||||
_height(720),
|
||||
_pixelCount(1280*720),
|
||||
_frameCount(0),
|
||||
_leafCount(0),
|
||||
_nodeCount(0),
|
||||
_fps(0.0),
|
||||
_lastTimeFpsUpdated(0),
|
||||
_lastTimeFrameUpdated(0),
|
||||
_ptRenderInitialized(false),
|
||||
_voxelRenderInitialized(false),
|
||||
_voxelOptRenderInitialized(false),
|
||||
_voxelOpt2RenderInitialized(false),
|
||||
_vertexShader(0),
|
||||
_pixelShader(0),
|
||||
_geometryShader(0),
|
||||
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM),
|
||||
_voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
|
||||
_boundaryLevelAdjust(0),
|
||||
_viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET),
|
||||
_fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||
_useVoxelTextures(false),
|
||||
_pointVertices(NULL),
|
||||
_pointVerticesCount(0),
|
||||
//_vboShaderData(NULL),
|
||||
_mousePressed(false),
|
||||
_pitch(0),
|
||||
_yaw(0),
|
||||
_roll(0),
|
||||
_numSegments(0),
|
||||
_displayOnlyPartition(NO_PARTITION),
|
||||
_totalPossibleElems(0),
|
||||
_numElemsDrawn(0),
|
||||
_useBoundingVolumes(true)
|
||||
{
|
||||
gettimeofday(&_applicationStartupTime, NULL);
|
||||
_appStartTickCount = usecTimestampNow();
|
||||
|
||||
_globalSvoViewerObj = this;
|
||||
|
||||
//ui.setupUi(this);
|
||||
_window->setWindowTitle("SvoViewer");
|
||||
_window->resize(1280,720);
|
||||
|
||||
_window->setCentralWidget(_glWidget);
|
||||
|
||||
DebugPrint("Window initialized\n");
|
||||
|
||||
_window->setVisible(true);
|
||||
_glWidget->setFocusPolicy(Qt::StrongFocus);
|
||||
_glWidget->setFocus();
|
||||
_glWidget->setMouseTracking(true);
|
||||
|
||||
|
||||
_currentShaderModel = RENDER_OPT_CULLED_POLYS; //RENDER_OPT_POLYS;// RENDER_CLASSIC_POLYS; //RENDER_POINTS;//
|
||||
memset(&_renderFlags, 0, sizeof(_renderFlags));
|
||||
_renderFlags.useShadows = false;
|
||||
|
||||
// Load the scene.
|
||||
|
||||
// We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so...
|
||||
float voxelSize = 0.5f / TREE_SCALE;
|
||||
|
||||
DebugPrint("Reading SVO file\n");
|
||||
|
||||
//H:\highfidelity\hifi-19509\build\interface\resources\voxels1A.svo
|
||||
const int MAX_PATH = 1024;
|
||||
char svoFileToRead[MAX_PATH] = "./voxels10.svo"; //"H:\\highfidelity\\hifi-19509\\build\\interface\\resources\\voxels10.svo"
|
||||
if (argc > 1) strcpy(svoFileToRead, argv[1]); // Command line is arg 0 by default.
|
||||
|
||||
//DebugPrint("Sizeof Octree element is %d\n", sizeof(OctreeElement));
|
||||
|
||||
quint64 readStart = usecTimestampNow();
|
||||
bool readSucceeded = _systemTree.readFromSVOFile(svoFileToRead);
|
||||
DebugPrint("Done reading SVO file : %f seconds : ", (float)(usecTimestampNow() - readStart) / 1000.0f);
|
||||
readSucceeded ? DebugPrint("Succeeded\n") : DebugPrint("Failed\n");
|
||||
|
||||
// this should exist... we just loaded it...
|
||||
if (_systemTree.getVoxelAt(voxelSize, 0, voxelSize, voxelSize)) {
|
||||
DebugPrint("corner point voxelSize, 0, voxelSize exists...\n");
|
||||
} else {
|
||||
DebugPrint("corner point voxelSize, 0, voxelSize does not exists...\n");
|
||||
}
|
||||
|
||||
_nodeCount = _systemTree.getOctreeElementsCount();
|
||||
DebugPrint("Nodes after loading file: %ld nodes\n", _nodeCount);
|
||||
|
||||
// Initialize the display model we're using.
|
||||
switch(_currentShaderModel)
|
||||
{
|
||||
case RENDER_NONE:
|
||||
break;
|
||||
case RENDER_POINTS:
|
||||
_renderFlags.useVoxelShader = false;
|
||||
_renderFlags.usePtShader = true;
|
||||
if (!_ptRenderInitialized) InitializePointRenderSystem();
|
||||
break;
|
||||
case RENDER_CLASSIC_POLYS:
|
||||
_renderFlags.useVoxelShader = true;
|
||||
_renderFlags.usePtShader = false;
|
||||
if (!_voxelRenderInitialized) InitializeVoxelRenderSystem();
|
||||
break;
|
||||
case RENDER_OPT_POLYS:
|
||||
_renderFlags.useVoxelShader = true;
|
||||
_renderFlags.usePtShader = false;
|
||||
if (!_voxelOptRenderInitialized) InitializeVoxelOptRenderSystem();
|
||||
break;
|
||||
case RENDER_OPT_CULLED_POLYS:
|
||||
_renderFlags.useVoxelShader = true;
|
||||
_renderFlags.usePtShader = false;
|
||||
if (!_voxelOpt2RenderInitialized) InitializeVoxelOpt2RenderSystem();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SvoViewer::~SvoViewer()
|
||||
{
|
||||
//glDeleteBuffers(_pointVtxBuffer); // TODO :: add comprehensive cleanup!!
|
||||
//glDeleteBuffers(1, _pointVtxBuffer);
|
||||
//glDeleteBuffers(1, _pointColorBuffer);
|
||||
|
||||
if (_pointVertices) delete [] _pointVertices;
|
||||
if (_pointColors) delete [] _pointColors;
|
||||
//if (_vboShaderData) delete [] _vboShaderData;
|
||||
|
||||
StopUsingVoxelRenderSystem();
|
||||
}
|
||||
|
||||
void SvoViewer::init() {
|
||||
//_voxelShader.init();
|
||||
//_pointShader.init();
|
||||
_mouseX = _glWidget->width() / 2;
|
||||
_mouseY = _glWidget->height() / 2;
|
||||
QCursor::setPos(_mouseX, _mouseY);
|
||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
||||
_myCamera.setPosition(glm::vec3(0.0f, 0.0f, -5.0f));
|
||||
_myCamera.setNearClip(0.01f);
|
||||
//_myCamera.setFarClip(500.0f * TREE_SCALE);
|
||||
_myCamera.setFarClip(TREE_SCALE);
|
||||
_myCamera.setFieldOfView(_fieldOfView);
|
||||
_myCamera.lookAt(glm::vec3(0.0f,0.0f,0.0f));
|
||||
_myCamera.setAspectRatio((float)_width / (float) _height);
|
||||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
}
|
||||
|
||||
void SvoViewer::initializeGL()
|
||||
{
|
||||
int argc = 0;
|
||||
glutInit(&argc, 0);
|
||||
init();
|
||||
#ifdef WIN32
|
||||
GLenum err = glewInit();
|
||||
if (GLEW_OK != err) {
|
||||
/* Problem: glewInit failed, something is seriously wrong. */
|
||||
DebugPrint("Error: %s\n", glewGetErrorString(err));
|
||||
}
|
||||
DebugPrint("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
|
||||
#endif
|
||||
glViewport(0, 0, _width, _height);
|
||||
glGetIntegerv(GL_VIEWPORT, _viewport);
|
||||
//glEnable(GL_BLEND);
|
||||
//glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
//glEnable(GL_LIGHTING);
|
||||
//glEnable(GL_LIGHT0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
//// call our idle function whenever we can
|
||||
idleTimer = new QTimer(this);
|
||||
connect(idleTimer, SIGNAL(timeout()), SLOT(idle()));
|
||||
idleTimer->start(0);
|
||||
//_idleLoopStdev.reset();
|
||||
_lastTimeFpsUpdated = _lastTimeFpsUpdated = usecTimestampNow();
|
||||
float startupTime = (float)(_lastTimeFpsUpdated - _appStartTickCount) / 1000.0;
|
||||
DebugPrint("Startup time: %4.2f seconds.", startupTime);
|
||||
//// update before the first render
|
||||
updateProjectionMatrix(_myCamera, true);
|
||||
update(0.0f);
|
||||
|
||||
UpdateOpt2BVFaceVisibility();
|
||||
}
|
||||
|
||||
void SvoViewer::idle() {
|
||||
quint64 tc = usecTimestampNow();
|
||||
// Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran
|
||||
quint64 elapsed = tc - _lastTimeFrameUpdated;
|
||||
//if (elapsed >= IDLE_SIMULATE_MSECS)
|
||||
{
|
||||
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
||||
update(glm::clamp((float)elapsed / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS));
|
||||
_glWidget->updateGL();
|
||||
// After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
|
||||
idleTimer->start(2);
|
||||
_lastTimeFrameUpdated = tc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SvoViewer::paintGL()
|
||||
{
|
||||
glClearColor( 0.f, 0.f, .3f, 0.f );
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
|
||||
glViewport(0, 0, _width, _height);
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
glm::vec3 pos = _myCamera.getPosition();
|
||||
glm::vec3 target = _myCamera.getTargetPosition();
|
||||
updateProjectionMatrix(_myCamera, true);
|
||||
|
||||
// save matrix
|
||||
glGetDoublev(GL_PROJECTION_MATRIX, _projectionMatrix);
|
||||
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
gluLookAt(pos.x, pos.y, pos.z, target.x, target.y, target.z, 0, 1, 0);
|
||||
|
||||
glGetDoublev(GL_MODELVIEW_MATRIX, _modelviewMatrix);
|
||||
|
||||
//glFrontFace(GL_CW);
|
||||
|
||||
glPointSize(5.0);
|
||||
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
glBegin(GL_POINTS);
|
||||
glVertex3f(0,0,0);
|
||||
glVertex3f(1,0,0);
|
||||
glVertex3f(-1,0,0);
|
||||
glVertex3f(0,1,0);
|
||||
glVertex3f(0,-1,0);
|
||||
glVertex3f(0,0,1);
|
||||
glVertex3f(0,0,-1);
|
||||
glEnd();
|
||||
|
||||
switch(_currentShaderModel)
|
||||
{
|
||||
case RENDER_NONE:
|
||||
// Nothing to do!
|
||||
break;
|
||||
case RENDER_POINTS:
|
||||
RenderTreeSystemAsPoints();
|
||||
break;
|
||||
case RENDER_CLASSIC_POLYS:
|
||||
RenderTreeSystemAsVoxels();
|
||||
break;
|
||||
case RENDER_OPT_POLYS:
|
||||
RenderTreeSystemAsOptVoxels();
|
||||
break;
|
||||
case RENDER_OPT_CULLED_POLYS:
|
||||
RenderTreeSystemAsOpt2Voxels();
|
||||
break;
|
||||
}
|
||||
|
||||
_frameCount++;
|
||||
|
||||
// Print out some statistics.
|
||||
|
||||
// Update every x seconds for more stability
|
||||
quint64 tc = usecTimestampNow();
|
||||
quint64 interval = tc - _lastTimeFpsUpdated;
|
||||
#define FPS_UPDATE_TIME_INTERVAL 2
|
||||
if (interval > 1000 * FPS_UPDATE_TIME_INTERVAL)
|
||||
{
|
||||
int numFrames = _frameCount - _lastTrackedFrameCount;
|
||||
_fps = (float)numFrames / (float)(FPS_UPDATE_TIME_INTERVAL);
|
||||
_lastTrackedFrameCount = _frameCount;
|
||||
_lastTimeFpsUpdated = tc;
|
||||
}
|
||||
PrintToScreen((_width / 3) * 2, 10, "FPS is : %f", _fps );
|
||||
PrintToScreen(10, 10, "Camera Pos : %f %f %f", pos.x, pos.y, pos.z);
|
||||
PrintToScreen(10, 30, "Drawing %d of %d (%% %f) total elements", _numElemsDrawn, _totalPossibleElems, ((float)_numElemsDrawn / (float)_totalPossibleElems) * 100.0);
|
||||
}
|
||||
|
||||
#define TEMP_STRING_BUFFER_MAX 1024
|
||||
#define SHADOW_OFFSET 2
|
||||
void SvoViewer::PrintToScreen(const int width, const int height, const char* szFormat, ...)
|
||||
{
|
||||
char szBuff[TEMP_STRING_BUFFER_MAX];
|
||||
assert(strlen(szFormat) < TEMP_STRING_BUFFER_MAX); // > max_path. Use this only for small messages.
|
||||
va_list arg;
|
||||
va_start(arg, szFormat);
|
||||
vsnprintf(szBuff, sizeof(szBuff), szFormat, arg);
|
||||
va_end(arg);
|
||||
// Passed in via char for convenience - convert to unsigned for glutBitmapString
|
||||
unsigned char szUBuff[TEMP_STRING_BUFFER_MAX];
|
||||
memset(szUBuff, 0, sizeof(szUBuff));
|
||||
int len = strlen(szBuff);
|
||||
for (int i = 0; i < len; i++) szUBuff[i] = (unsigned char)szBuff[i];
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(0, _width, 0, _height, 0, 1);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
glColor3f(.8f, .8f, .8f); // Matt:: reverse ordering once depth enabled.
|
||||
glRasterPos2i(width, height);
|
||||
//glutBitmapString(GLUT_BITMAP_HELVETICA_18, szUBuff);
|
||||
|
||||
glColor3f(0.0f, 0.0f, 0.0f);
|
||||
glRasterPos2i(width - SHADOW_OFFSET, height - SHADOW_OFFSET );
|
||||
//glutBitmapString(GLUT_BITMAP_HELVETICA_18, szUBuff);
|
||||
|
||||
//glEnable(GL_LIGHTING);
|
||||
glPopMatrix();
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glPopMatrix();
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void SvoViewer::update(float deltaTime){
|
||||
}
|
||||
|
||||
void SvoViewer::resizeGL(int width, int height)
|
||||
{
|
||||
|
||||
glViewport(0, 0, width, height); // shouldn't this account for the menu???
|
||||
glGetIntegerv(GL_VIEWPORT, _viewport);
|
||||
_pixelCount = width * height;
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
updateProjectionMatrix(_myCamera, true);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void SvoViewer::updateProjectionMatrix(Camera& camera, bool updateViewFrustum)
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
float left, right, bottom, top, nearVal, farVal;
|
||||
glm::vec4 nearClipPlane, farClipPlane;
|
||||
|
||||
// Tell our viewFrustum about this change, using the application camera
|
||||
if (updateViewFrustum) {
|
||||
loadViewFrustum(camera, _viewFrustum);
|
||||
computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
||||
} else {
|
||||
ViewFrustum tempViewFrustum;
|
||||
loadViewFrustum(camera, tempViewFrustum);
|
||||
tempViewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
||||
}
|
||||
glFrustum(left, right, bottom, top, nearVal, farVal);
|
||||
|
||||
// save matrix
|
||||
//glGetDoublev(GL_PROJECTION_MATRIX, _projectionMatrix);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// loadViewFrustum()
|
||||
//
|
||||
// Description: this will load the view frustum bounds for EITHER the head
|
||||
// or the "myCamera".
|
||||
//
|
||||
void SvoViewer::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum)
|
||||
{
|
||||
// We will use these below, from either the camera or head vectors calculated above
|
||||
glm::vec3 position(camera.getPosition());
|
||||
float fov = camera.getFieldOfView();
|
||||
float nearClip = camera.getNearClip();
|
||||
float farClip = camera.getFarClip();
|
||||
float aspectRatio = camera.getAspectRatio();
|
||||
|
||||
glm::quat rotation = camera.getRotation();
|
||||
|
||||
// Set the viewFrustum up with the correct position and orientation of the camera
|
||||
viewFrustum.setPosition(position);
|
||||
viewFrustum.setOrientation(rotation);
|
||||
|
||||
// Also make sure it's got the correct lens details from the camera
|
||||
viewFrustum.setAspectRatio(aspectRatio);
|
||||
viewFrustum.setFieldOfView(fov);
|
||||
viewFrustum.setNearClip(nearClip);
|
||||
viewFrustum.setFarClip(farClip);
|
||||
viewFrustum.setEyeOffsetPosition(camera.getEyeOffsetPosition());
|
||||
viewFrustum.setEyeOffsetOrientation(camera.getEyeOffsetOrientation());
|
||||
|
||||
// Ask the ViewFrustum class to calculate our corners
|
||||
viewFrustum.calculate();
|
||||
}
|
||||
|
||||
void SvoViewer::computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
|
||||
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const
|
||||
{
|
||||
|
||||
_viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
||||
}
|
||||
|
||||
void SvoViewer::updateCamera(float deltaTime)
|
||||
{
|
||||
/*if (Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) {
|
||||
float xSign = _myCamera.getMode() == CAMERA_MODE_MIRROR ? 1.0f : -1.0f;
|
||||
if (_faceshift.isActive()) {
|
||||
const float EYE_OFFSET_SCALE = 0.025f;
|
||||
glm::vec3 position = _faceshift.getHeadTranslation() * EYE_OFFSET_SCALE;
|
||||
_myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z));
|
||||
updateProjectionMatrix();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void SvoViewer::setupWorldLight()
|
||||
{
|
||||
// Setup 3D lights (after the camera transform, so that they are positioned in world space)
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
|
||||
|
||||
//glm::vec3 sunDirection = getSunDirection();
|
||||
GLfloat light_position0[] = {10.0, 10.0, -20.0, 0.0};//{ sunDirection.x, sunDirection.y, sunDirection.z, 0.0 };
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
|
||||
GLfloat ambient_color[] = { 0.7f, 0.7f, 0.8f };
|
||||
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_color);
|
||||
GLfloat diffuse_color[] = { 0.8f, 0.7f, 0.7f };
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_color);
|
||||
|
||||
glLightfv(GL_LIGHT0, GL_SPECULAR, WHITE_SPECULAR_COLOR);
|
||||
glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE_SPECULAR_COLOR);
|
||||
glMateriali(GL_FRONT, GL_SHININESS, 96);
|
||||
}
|
||||
|
||||
inline glm::vec3 MAD(glm::vec3 v1, float mult, glm::vec3 v2)
|
||||
{
|
||||
return glm::vec3(v1.x * mult + v2.x, v1.y * mult + v2.y, v1.z * mult + v2.z);
|
||||
}
|
||||
|
||||
void SvoViewer::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
int keyval = event->key();
|
||||
|
||||
glm::vec3 lookAt = glm::normalize(_myCamera.getTargetPosition() - _myCamera.getPosition());
|
||||
glm::vec3 up = glm::vec3(0.0,1.0f,0.0f);
|
||||
glm::vec3 right = glm::cross(lookAt, up);
|
||||
glm::vec3 rotY;
|
||||
switch (keyval)
|
||||
{
|
||||
case Qt::Key_W:
|
||||
_myCamera.setPosition( MAD(lookAt, .2, _myCamera.getPosition()) );
|
||||
_myCamera.setTargetPosition( MAD(lookAt, .2, _myCamera.getTargetPosition()) );
|
||||
break;
|
||||
case Qt::Key_S:
|
||||
_myCamera.setPosition( MAD(lookAt, -.2, _myCamera.getPosition()) );
|
||||
_myCamera.setTargetPosition( MAD(lookAt, -.2, _myCamera.getTargetPosition()) );
|
||||
break;
|
||||
case Qt::Key_A:
|
||||
_myCamera.setPosition( MAD(right, -.2, _myCamera.getPosition()) );
|
||||
_myCamera.setTargetPosition( MAD(right, -.2, _myCamera.getTargetPosition()) );
|
||||
break;
|
||||
case Qt::Key_D:
|
||||
_myCamera.setPosition( MAD(right, .2, _myCamera.getPosition()) );
|
||||
_myCamera.setTargetPosition( MAD(right, .2, _myCamera.getTargetPosition()) );
|
||||
break;
|
||||
case Qt::Key_R:
|
||||
_myCamera.setPosition( MAD(up, .2, _myCamera.getPosition()) );
|
||||
_myCamera.setTargetPosition( MAD(up, .2, _myCamera.getTargetPosition()) );
|
||||
break;
|
||||
case Qt::Key_F:
|
||||
_myCamera.setPosition( MAD(up, -.2, _myCamera.getPosition()) );
|
||||
_myCamera.setTargetPosition( MAD(up, -.2, _myCamera.getTargetPosition()) );
|
||||
break;
|
||||
case Qt::Key_Q: // rotate left
|
||||
_yaw += 10;
|
||||
_myCamera.setTargetRotation(glm::quat(glm::radians(glm::vec3(_pitch, _yaw, _roll))));
|
||||
break;
|
||||
case Qt::Key_E: // rotate right
|
||||
_yaw -= 10;
|
||||
_myCamera.setTargetRotation(glm::quat(glm::radians(glm::vec3(_pitch, _yaw, _roll))));
|
||||
break;
|
||||
case Qt::Key_B: // rotate right
|
||||
_useBoundingVolumes ^= 1;
|
||||
break;
|
||||
default:
|
||||
if (keyval >= Qt::Key_0 && keyval <= Qt::Key_9)
|
||||
{
|
||||
int newPartitionToDisplay = keyval - Qt::Key_0;
|
||||
if (_displayOnlyPartition == newPartitionToDisplay) _displayOnlyPartition = NO_PARTITION;
|
||||
else _displayOnlyPartition = newPartitionToDisplay;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
UpdateOpt2BVFaceVisibility();
|
||||
}
|
||||
|
||||
|
||||
void SvoViewer::keyReleaseEvent(QKeyEvent* event) {}
|
||||
|
||||
void SvoViewer::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
int deltaX = event->x() - _mouseX;
|
||||
int deltaY = event->y() - _mouseY;
|
||||
_mouseX = event->x();
|
||||
_mouseY = event->y();
|
||||
|
||||
|
||||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
}
|
||||
|
||||
void SvoViewer::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
_mouseX = event->x();
|
||||
_mouseY = event->y();
|
||||
_mouseDragStartedX = _mouseX;
|
||||
_mouseDragStartedY = _mouseY;
|
||||
_mousePressed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SvoViewer::mouseReleaseEvent(QMouseEvent* event) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SvoViewer::updateMouseRay()
|
||||
{
|
||||
// if the mouse pointer isn't visible, act like it's at the center of the screen
|
||||
float x = 0.5f, y = 0.5f;
|
||||
if (!_mouseHidden) {
|
||||
x = _mouseX / (float)_glWidget->width();
|
||||
y = _mouseY / (float)_glWidget->height();
|
||||
}
|
||||
_viewFrustum.computePickRay(x, y, _mouseRayOrigin, _mouseRayDirection);
|
||||
|
||||
// adjust for mirroring
|
||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
glm::vec3 mouseRayOffset = _mouseRayOrigin - _viewFrustum.getPosition();
|
||||
_mouseRayOrigin -= 2.0f * (_viewFrustum.getDirection() * glm::dot(_viewFrustum.getDirection(), mouseRayOffset) +
|
||||
_viewFrustum.getRight() * glm::dot(_viewFrustum.getRight(), mouseRayOffset));
|
||||
_mouseRayDirection -= 2.0f * (_viewFrustum.getDirection() * glm::dot(_viewFrustum.getDirection(), _mouseRayDirection) +
|
||||
_viewFrustum.getRight() * glm::dot(_viewFrustum.getRight(), _mouseRayDirection));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Stub for the full function.
|
||||
bool SvoViewer::isVisibleBV(AABoundingVolume * volume, Camera * camera, ViewFrustum * frustum)
|
||||
{
|
||||
//if (pos.z >= volume->getBound(2,AABF_HIGH)) return false;
|
||||
// Project all the points into screen space.
|
||||
AA2DBoundingVolume twoDBounds;
|
||||
float xvals[2] = {9999.0, -1.0};
|
||||
float yvals[2] = {9999.0, -1.0};
|
||||
//project all bv points into screen space.
|
||||
GLdouble scr[3];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
glm::vec3 pt = volume->getCorner((BoxVertex)i);
|
||||
gluProject((GLdouble)pt.x, (GLdouble)pt.y, (GLdouble)pt.z, _modelviewMatrix, _projectionMatrix, _viewport, &scr[0], &scr[1], &scr[2]);
|
||||
if (scr[2] > 0 && scr[2] < 1)
|
||||
{
|
||||
float tPt[2] = {(float)scr[0], (float)scr[1]};
|
||||
twoDBounds.AddToSet(tPt);
|
||||
}
|
||||
}
|
||||
bool inVisibleSpace = twoDBounds.clipToRegion(0, 0, _width, _height);
|
||||
return inVisibleSpace;
|
||||
}
|
||||
|
||||
float SvoViewer::visibleAngleSubtended(AABoundingVolume * volume, Camera * camera, ViewFrustum * frustum)
|
||||
{
|
||||
AA2DBoundingVolume twoDBounds;
|
||||
float xvals[2] = {9999.0, -1.0};
|
||||
float yvals[2] = {9999.0, -1.0};
|
||||
//project all bv points into screen space.
|
||||
GLdouble scr[3];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
glm::vec3 pt = volume->getCorner((BoxVertex)i);
|
||||
gluProject((GLdouble)pt.x, (GLdouble)pt.y, (GLdouble)pt.z, _modelviewMatrix, _projectionMatrix, _viewport, &scr[0], &scr[1], &scr[2]);
|
||||
if (scr[2] > 0 && scr[2] < 1)
|
||||
{
|
||||
float tPt[2] = {(float)scr[0], (float)scr[1]};
|
||||
twoDBounds.AddToSet(tPt);
|
||||
}
|
||||
}
|
||||
twoDBounds.clipToRegion(0, 0, _width, _height);
|
||||
float area = twoDBounds.getWidth() * twoDBounds.getHeight();
|
||||
if (area < 1) return 0.0;
|
||||
return area / (float)_pixelCount;
|
||||
}
|
||||
|
||||
void SvoViewer::DebugPrint(const char* szFormat, ...)
|
||||
{
|
||||
/**
|
||||
char szBuff[TEMP_STRING_BUFFER_MAX];
|
||||
assert(strlen(szFormat) < TEMP_STRING_BUFFER_MAX); // > max_path. Use this only for small messages.
|
||||
va_list arg;
|
||||
va_start(arg, szFormat);
|
||||
vsnprintf(szBuff, sizeof(szBuff), TEMP_STRING_BUFFER_MAX-100, szFormat, arg);
|
||||
va_end(arg);
|
||||
**/
|
||||
|
||||
qDebug(szFormat);
|
||||
}
|
||||
|
||||
GLubyte SvoViewer::PrintGLErrorCode()
|
||||
{
|
||||
GLubyte err = glGetError();
|
||||
if( err != GL_NO_ERROR ) //DebugPrint("GL Error! : %x\n", err);
|
||||
DebugPrint("Error! : %u, %s\n", (unsigned int)err, gluErrorString(err));
|
||||
return err;
|
||||
}
|
317
SvoViewer/src/svoviewer.h
Executable file
317
SvoViewer/src/svoviewer.h
Executable file
|
@ -0,0 +1,317 @@
|
|||
#ifndef SVOVIEWER_H
|
||||
#define SVOVIEWER_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QApplication>
|
||||
#include <QGLWidget>
|
||||
|
||||
/***
|
||||
#define GL_GLEXT_PROTOTYPES 1
|
||||
#define GLEW_STATIC
|
||||
#include <windowshacks.h>
|
||||
***/
|
||||
#include "globals.h"
|
||||
#include "AABoundingVolume.h"
|
||||
|
||||
|
||||
|
||||
enum SVOViewerShaderModel
|
||||
{
|
||||
RENDER_NONE,
|
||||
RENDER_POINTS,
|
||||
RENDER_CLASSIC_POLYS,
|
||||
RENDER_OPT_POLYS,
|
||||
RENDER_OPT_CULLED_POLYS,
|
||||
};
|
||||
|
||||
enum CubeOrdering
|
||||
{
|
||||
CUBE_TOP,
|
||||
CUBE_BOTTOM,
|
||||
CUBE_LEFT,
|
||||
CUBE_RIGHT,
|
||||
CUBE_FRONT,
|
||||
CUBE_BACK,
|
||||
NUM_CUBE_FACES
|
||||
};
|
||||
|
||||
struct ViewFrustumOffset {
|
||||
float yaw;
|
||||
float pitch;
|
||||
float roll;
|
||||
float distance;
|
||||
float up;
|
||||
};
|
||||
|
||||
struct RenderFlags
|
||||
{
|
||||
bool ptRenderDirty : 1;
|
||||
bool voxelRenderDirty : 1;
|
||||
bool voxelOptRenderDirty : 1;
|
||||
bool usePtShader : 1;
|
||||
bool useVoxelShader : 1;
|
||||
bool useVoxelOptShader : 1;
|
||||
bool useShadows : 1;
|
||||
};
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
glm::vec3 position;
|
||||
unsigned char color[4];
|
||||
};
|
||||
|
||||
enum VtxAttributes
|
||||
{
|
||||
ATTRIB_POSITION,
|
||||
ATTRIB_COLOR,
|
||||
ATTRIB_TEXTURE
|
||||
};
|
||||
|
||||
struct VoxelDimIdxSet
|
||||
{
|
||||
GLuint idxIds[NUM_CUBE_FACES]; // Id for each voxel face
|
||||
GLuint idxCount[NUM_CUBE_FACES]; // count for each voxel face.
|
||||
GLuint* idxBuff[NUM_CUBE_FACES]; // actual index buffers for each voxel face
|
||||
GLuint elemCount[NUM_CUBE_FACES];
|
||||
AABoundingVolume bounds[NUM_CUBE_FACES]; // Super efficient bounding set here.
|
||||
bool visibleFace[NUM_CUBE_FACES];
|
||||
};
|
||||
|
||||
struct VisibleFacesData
|
||||
{
|
||||
int count;
|
||||
glm::vec3 * ptList;
|
||||
};
|
||||
|
||||
struct FindNumLeavesData
|
||||
{
|
||||
int numLeaves;
|
||||
};
|
||||
|
||||
//#define MAX_VOXELS 4000000
|
||||
#define MAX_VOXELS 8000000
|
||||
#define REASONABLY_LARGE_BUFFER 10000
|
||||
|
||||
#define MAX_NUM_OCTREE_PARTITIONS 20
|
||||
#define MAX_NUM_VBO_ALLOWED MAX_NUM_OCTREE_PARTITIONS * NUM_CUBE_FACES
|
||||
#define NO_PARTITION -1
|
||||
|
||||
class VoxelOptRenderer : public OctreeRenderer {
|
||||
};
|
||||
|
||||
class SvoViewer : public QApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static SvoViewer* getInstance() { return static_cast<SvoViewer*>(QCoreApplication::instance()); }
|
||||
|
||||
SvoViewer(int& argc, char** argv, QWidget *parent = 0);
|
||||
~SvoViewer();
|
||||
|
||||
|
||||
void initializeGL();
|
||||
void paintGL();
|
||||
void resizeGL(int width, int height);
|
||||
void init();
|
||||
void update(float deltaTime);
|
||||
void updateMouseRay();
|
||||
void updateProjectionMatrix(Camera& camera, bool updateViewFrustum);
|
||||
void updateCamera(float deltaTime);
|
||||
void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
|
||||
ViewFrustum* getViewFrustum() { return &_viewFrustum; }
|
||||
void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const ;
|
||||
void setupWorldLight();
|
||||
glm::vec2 getViewportDimensions() const{ return glm::vec2(_width,_height); }
|
||||
|
||||
// User Tweakable LOD Items
|
||||
void autoAdjustLOD(float currentFPS);
|
||||
void setVoxelSizeScale(float sizeScale);
|
||||
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
||||
void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
||||
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
||||
|
||||
bool getIsPointShader(){ return _renderFlags.usePtShader; }
|
||||
void setIsPointShader(const bool b){ _renderFlags.usePtShader = b; }
|
||||
bool getIsVoxelShader(){ return _renderFlags.useVoxelShader; }
|
||||
void setIsVoxelShader(const bool b){ _renderFlags.useVoxelShader = b; }
|
||||
bool getIsVoxelOptShader(){ return _renderFlags.useVoxelOptShader; }
|
||||
void setIsVoxelOptShader(const bool b){ _renderFlags.useVoxelOptShader = b; }
|
||||
void setUseVoxelTextures(const bool b){_useVoxelTextures = b; }
|
||||
bool getUseVoxelTextures(){ return _useVoxelTextures; }
|
||||
void setUseShadows(const bool b){ _renderFlags.useShadows = b; }
|
||||
bool getUseShadows(){ return _renderFlags.useShadows; }
|
||||
|
||||
//VoxelShader* getVoxelShader(){ return &_voxelShader; }
|
||||
//PointShader* getPointShader(){ return &_pointShader; }
|
||||
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
void keyReleaseEvent(QKeyEvent* event);
|
||||
|
||||
void mouseMoveEvent(QMouseEvent* event);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void mouseReleaseEvent(QMouseEvent* event);
|
||||
|
||||
void PrintToScreen(const int width, const int height, const char* szFormat, ...);
|
||||
static void DebugPrint(const char* szFormat, ...); // utility function.
|
||||
static GLubyte PrintGLErrorCode();
|
||||
|
||||
// Some helper functions.
|
||||
GLubyte SetupGlVBO(GLuint * id, int sizeInBytes, GLenum target, GLenum usage, void * dataUp );
|
||||
static glm::vec3 computeQuickAndDirtyQuadCenter(glm::vec3 p0, glm::vec3 p1, glm::vec3 p2, glm::vec3 p3);
|
||||
bool isVisibleBV(AABoundingVolume * volume, Camera * camera, ViewFrustum * frustum);
|
||||
float visibleAngleSubtended(AABoundingVolume * volume, Camera * camera, ViewFrustum * frustum);
|
||||
static int ptCompFunc(const void * a, const void * b);
|
||||
static int ptCloseEnough(const void * a, const void * b);
|
||||
static int binVecSearch(glm::vec3 searchVal, glm::vec3* list, int count, int * found);
|
||||
bool parameterizedRayPlaneIntersection(const glm::vec3 origin, const glm::vec3 direction, const glm::vec3 planePt, const glm::vec3 planeNormal, float *t);
|
||||
|
||||
protected:
|
||||
void InitializePointRenderSystem();
|
||||
void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]);
|
||||
void InitializeVoxelRenderSystem();
|
||||
void InitializeVoxelOptRenderSystem();
|
||||
void InitializeVoxelOpt2RenderSystem();
|
||||
void StopUsingPointRenderSystem();
|
||||
void StopUsingVoxelRenderSystem();
|
||||
void StopUsingVoxelOptRenderSystem();
|
||||
void StopUsingVoxelOpt2RenderSystem();
|
||||
void UpdateOpt2BVFaceVisibility();
|
||||
|
||||
|
||||
void RenderTreeSystemAsPoints();
|
||||
void RenderTreeSystemAsVoxels();
|
||||
void RenderTreeSystemAsOptVoxels();
|
||||
void RenderTreeSystemAsOpt2Voxels();
|
||||
|
||||
// Tree traversal functions.
|
||||
static bool PointRenderAssemblePerVoxel(OctreeElement* node, void* extraData);
|
||||
static bool VoxelRenderAssemblePerVoxel(OctreeElement* node, void* extraData);
|
||||
static bool VoxelOptRenderAssemblePerVoxel(OctreeElement* node, void* extraData);
|
||||
static bool VoxelOpt2RenderAssemblePerVoxel(OctreeElement* node, void* extraData);
|
||||
static bool FindNumLeaves(OctreeElement* node, void* extraData);
|
||||
static bool TrackVisibleFaces(OctreeElement* node, void* extraData);
|
||||
|
||||
|
||||
private slots:
|
||||
void idle();
|
||||
|
||||
private:
|
||||
//Ui::SvoViewerClass ui;
|
||||
|
||||
QMainWindow* _window;
|
||||
int _width;
|
||||
int _height;
|
||||
int _pixelCount;
|
||||
QGLWidget* _glWidget;
|
||||
|
||||
//VoxelSystem _voxels;
|
||||
VoxelTree _systemTree;
|
||||
unsigned long _nodeCount;
|
||||
unsigned int _leafCount;
|
||||
|
||||
ViewFrustum _viewFrustum;
|
||||
Camera _myCamera; // My view onto the world
|
||||
float _pitch, _yaw, _roll;
|
||||
|
||||
int _mouseX;
|
||||
int _mouseY;
|
||||
int _mouseDragStartedX;
|
||||
int _mouseDragStartedY;
|
||||
bool _mousePressed;
|
||||
quint64 _lastMouseMove;
|
||||
bool _mouseHidden;
|
||||
bool _seenMouseMove;
|
||||
|
||||
glm::vec3 _mouseRayOrigin;
|
||||
glm::vec3 _mouseRayDirection;
|
||||
|
||||
glm::mat4 _untranslatedViewMatrix;
|
||||
glm::vec3 _viewMatrixTranslation;
|
||||
GLdouble _projectionMatrix[16];
|
||||
GLdouble _modelviewMatrix[16];
|
||||
GLint _viewport[4];
|
||||
|
||||
SVOViewerShaderModel _currentShaderModel;
|
||||
//VoxelShader _voxelShader;
|
||||
//PointShader _pointShader;
|
||||
|
||||
// Display options
|
||||
int _displayOnlyPartition;
|
||||
|
||||
// Frame Rate Measurement
|
||||
int _frameCount;
|
||||
int _lastTrackedFrameCount;
|
||||
float _fps;
|
||||
timeval _applicationStartupTime;
|
||||
quint64 _appStartTickCount;
|
||||
quint64 _lastTimeFpsUpdated;
|
||||
quint64 _lastTimeFrameUpdated;
|
||||
|
||||
// Render variables.
|
||||
bool _ptRenderInitialized;
|
||||
bool _voxelRenderInitialized;
|
||||
bool _voxelOptRenderInitialized;
|
||||
bool _voxelOpt2RenderInitialized;
|
||||
|
||||
GLuint _vertexShader;
|
||||
GLuint _pixelShader;
|
||||
GLuint _geometryShader;
|
||||
GLuint _linkProgram;
|
||||
|
||||
// Vars for RENDER_POINTS
|
||||
GLuint _pointVtxBuffer;
|
||||
GLuint _pointColorBuffer;
|
||||
glm::vec3* _pointVertices;
|
||||
unsigned char* _pointColors;
|
||||
int _pointVerticesCount;
|
||||
|
||||
// Vars for RENDER_CLASSIC_POLYS
|
||||
GLuint _vboVerticesID;
|
||||
GLuint _vboColorsID;
|
||||
GLuint _vboIndicesIds[NUM_CUBE_FACES];
|
||||
GLuint* _vboIndices[NUM_CUBE_FACES];
|
||||
//VoxelShaderVBOData* _vboShaderData; // may not need.
|
||||
glm::vec3* _readVerticesArray;
|
||||
unsigned char* _readColorsArray;
|
||||
GLuint* _readIndicesArray;
|
||||
|
||||
|
||||
// Vars for RENDER_OPT_POLYS
|
||||
// Allow for primitive first level sorting at the moment.
|
||||
GLuint _vboOVerticesIds[MAX_NUM_VBO_ALLOWED];
|
||||
glm::vec3* _vboOVertices[MAX_NUM_VBO_ALLOWED];
|
||||
GLuint _vboOIndicesIds[MAX_NUM_VBO_ALLOWED];
|
||||
GLuint* _vboOIndices[MAX_NUM_VBO_ALLOWED];
|
||||
GLuint _numChildNodeLeaves[MAX_NUM_VBO_ALLOWED];
|
||||
OctreeElement * _segmentNodeReferences[MAX_NUM_OCTREE_PARTITIONS];
|
||||
AABoundingVolume _segmentBoundingVolumes[MAX_NUM_OCTREE_PARTITIONS];
|
||||
int _segmentElemCount[MAX_NUM_OCTREE_PARTITIONS];
|
||||
unsigned int _numSegments;
|
||||
Vertex * _readVertexStructs;
|
||||
|
||||
// Vars for RENDER_OPT_CULLED_POLYS
|
||||
// Use vtx vars from opt_polys version.
|
||||
VoxelDimIdxSet _segmentIdxBuffers[MAX_NUM_OCTREE_PARTITIONS];
|
||||
bool _useBoundingVolumes;
|
||||
|
||||
|
||||
int _numElemsDrawn;
|
||||
int _totalPossibleElems;
|
||||
|
||||
RenderFlags _renderFlags;
|
||||
|
||||
ViewFrustumOffset _viewFrustumOffset;
|
||||
int _maxVoxels;
|
||||
float _voxelSizeScale;
|
||||
int _boundaryLevelAdjust;
|
||||
float _fieldOfView; /// in Degrees
|
||||
bool _useVoxelTextures;
|
||||
|
||||
};
|
||||
|
||||
//Extern hack since this wasn't built with global linking to old project in mind.
|
||||
extern SvoViewer * _globalSvoViewerObj;
|
||||
|
||||
#endif // SVOVIEWER_H
|
4
SvoViewer/src/svoviewer.qrc
Executable file
4
SvoViewer/src/svoviewer.qrc
Executable file
|
@ -0,0 +1,4 @@
|
|||
<RCC>
|
||||
<qresource prefix="SvoViewer">
|
||||
</qresource>
|
||||
</RCC>
|
29
SvoViewer/src/svoviewer.ui
Executable file
29
SvoViewer/src/svoviewer.ui
Executable file
|
@ -0,0 +1,29 @@
|
|||
<UI version="4.0" >
|
||||
<class>SvoViewerClass</class>
|
||||
<widget class="QMainWindow" name="SvoViewerClass" >
|
||||
<property name="objectName" >
|
||||
<string notr="true">SvoViewerClass</string>
|
||||
</property>
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>SvoViewer</string>
|
||||
</property>
|
||||
<widget class="QMenuBar" name="menuBar" />
|
||||
<widget class="QToolBar" name="mainToolBar" />
|
||||
<widget class="QWidget" name="centralWidget" />
|
||||
<widget class="QStatusBar" name="statusBar" />
|
||||
</widget>
|
||||
<layoutDefault spacing="6" margin="11" />
|
||||
<pixmapfunction></pixmapfunction>
|
||||
<resources>
|
||||
<include location="svoviewer.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</UI>
|
Loading…
Reference in a new issue