mirror of
https://github.com/lubosz/overte.git
synced 2025-04-27 21:15:27 +02:00
resolve conflicts and merge with upstream master
This commit is contained in:
commit
c7a5f3c86c
158 changed files with 4394 additions and 1865 deletions
BUILD.mdBUILD_LINUX.mdBUILD_OSX.mdBUILD_WIN.mdCMakeLists.txt
assignment-client
cmake
macros
IncludeDependencyIncludes.cmakeLinkHifiLibraries.cmakeLinkSharedDependencies.cmakeSetupHifiLibrary.cmakeSetupHifiProject.cmake
modules
domain-server
examples
ice-server
interface
CMakeLists.txt
src
libraries
animation
audio
avatars
embedded-webserver
entities-renderer
entities
CMakeLists.txt
src
BoxEntityItem.cppBoxEntityItem.hEntityCollisionSystem.cppEntityItem.cppEntityItem.hEntityItemProperties.cppEntityItemProperties.hEntityItemPropertiesMacros.hEntityTree.cppEntityTreeElement.cppEntityTypes.cppLightEntityItem.cppLightEntityItem.hModelEntityItem.cppModelEntityItem.hSphereEntityItem.cppSphereEntityItem.hTextEntityItem.cppTextEntityItem.h
fbx
gpu
235
BUILD.md
235
BUILD.md
|
@ -1,33 +1,29 @@
|
|||
Dependencies
|
||||
===
|
||||
###Dependencies
|
||||
|
||||
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.12.2
|
||||
* [Qt](http://qt-project.org/downloads) ~> 5.2.0
|
||||
* [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.2
|
||||
* [Qt](http://qt-project.org/downloads) ~> 5.3.0
|
||||
* [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4
|
||||
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g
|
||||
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
|
||||
* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
|
||||
|
||||
#####Linux only
|
||||
* [freeglut](http://freeglut.sourceforge.net/) ~> 2.8.0
|
||||
* [zLib](http://www.zlib.net/) ~> 1.2.8
|
||||
### OS Specific Build Guides
|
||||
* [BUILD_OSX.md](BUILD_OSX.md) - additional instructions for OS X.
|
||||
* [BUILD_LINUX.md](BUILD_LINUX.md) - additional instructions for Linux.
|
||||
* [BUILD_WIN.md](BUILD_WIN.md) - additional instructions for Windows.
|
||||
|
||||
#####Windows only
|
||||
* [GLEW](http://glew.sourceforge.net/) ~> 1.10.0
|
||||
* [freeglut MSVC](http://www.transmissionzero.co.uk/software/freeglut-devel/) ~> 2.8.1
|
||||
* [zLib](http://www.zlib.net/) ~> 1.2.8
|
||||
|
||||
CMake
|
||||
===
|
||||
###CMake
|
||||
Hifi uses CMake to generate build files and project files for your platform.
|
||||
|
||||
####Qt
|
||||
In order for CMake to find the Qt5 find modules, you will need to set an ENV variable pointing to your Qt installation.
|
||||
|
||||
For example, a Qt5 5.2.0 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||
For example, a Qt5 5.3.2 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||
|
||||
The path it needs to be set to will depend on where and how Qt5 was installed. e.g.
|
||||
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.2.0/clang_64/lib/cmake/
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.2.1/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.3.2/clang_64/lib/cmake/
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.3.2/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
||||
|
||||
####Generating build files
|
||||
|
@ -42,7 +38,7 @@ Any variables that need to be set for CMake to find dependencies can be set as E
|
|||
|
||||
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
|
||||
|
||||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.2.1/lib/cmake
|
||||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.3.2/lib/cmake
|
||||
|
||||
####Finding Dependencies
|
||||
You can point our [Cmake find modules](cmake/modules/) to the correct version of dependencies by setting one of the three following variables to the location of the correct version of the dependency.
|
||||
|
@ -53,206 +49,7 @@ In the examples below the variable $NAME would be replaced by the name of the de
|
|||
* $NAME_ROOT_DIR - set this variable in your ENV
|
||||
* HIFI_LIB_DIR - set this variable in your ENV to your High Fidelity lib folder, should contain a folder '$name'
|
||||
|
||||
UNIX
|
||||
===
|
||||
In general, as long as external dependencies are placed in OS standard locations, CMake will successfully find them during its run. When possible, you may choose to install depencies from your package manager of choice, or from source.
|
||||
|
||||
####Linux
|
||||
Should you choose not to install Qt5 via a package manager that handles dependencies for you, you may be missing some Qt5 dependencies. On Ubuntu, for example, the following additional packages are required:
|
||||
|
||||
libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-dev
|
||||
|
||||
####OS X
|
||||
#####Package Managers
|
||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all hifi dependencies very simple.
|
||||
|
||||
brew tap highfidelity/homebrew-formulas
|
||||
brew install cmake glm openssl
|
||||
brew install highfidelity/formulas/qt5
|
||||
brew link qt5 --force
|
||||
|
||||
We have a [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) that you can use/tap to install some of the dependencies. In the code block above qt5 is installed from a formula in this repository.
|
||||
|
||||
*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.2.0 stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.*
|
||||
|
||||
#####Xcode
|
||||
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
||||
|
||||
cmake .. -GXcode
|
||||
|
||||
After running cmake, you will have the make files or Xcode project file necessary to build all of the components. Open the hifi.xcodeproj file, choose ALL_BUILD from the Product > Scheme menu (or target drop down), and click Run.
|
||||
|
||||
If the build completes successfully, you will have built targets for all components located in the `build/${target_name}/Debug` directories.
|
||||
|
||||
Windows
|
||||
===
|
||||
####Visual Studio
|
||||
|
||||
Currently building on Windows has been tested using the following compilers:
|
||||
* Visual Studio C++ 2010 Express
|
||||
* Visual Studio 2013
|
||||
|
||||
(If anyone can test using Visual Studio 2013 Express then please update this document)
|
||||
|
||||
#####Windows SDK 7.1
|
||||
|
||||
If using Visual Studio 2010, or using Visual Studio 2013 but building as a Visual Studio 2010 project, you need [Microsoft Windows SDK for Windows 7 and .NET Framework 4](http://www.microsoft.com/en-us/download/details.aspx?id=8279).
|
||||
|
||||
NOTE: If using Visual Studio C++ 2010 Express, you need to follow a specific install order. See below before installing the Windows SDK.
|
||||
|
||||
######Windows SDK 8.1
|
||||
|
||||
If using Visual Studio 2013 and building as a Visual Studio 2013 project you need the Windows 8 SDK which you should already have as part of installing Visual Studio 2013. You should be able to see it at `C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86`.
|
||||
|
||||
#####Visual Studio C++ 2010 Express
|
||||
|
||||
Visual Studio C++ 2010 Express can be downloaded [here](http://www.visualstudio.com/en-us/downloads#d-2010-express).
|
||||
|
||||
The following patches/service packs are also required:
|
||||
* [VS2010 SP1](http://www.microsoft.com/en-us/download/details.aspx?id=23691)
|
||||
* [VS2010 SP1 Compiler Update](http://www.microsoft.com/en-us/download/details.aspx?id=4422)
|
||||
|
||||
IMPORTANT: Use the following install order:
|
||||
Visual Studio C++ 2010 Express
|
||||
Windows SDK 7.1
|
||||
VS2010 SP1
|
||||
VS2010 SP1 Compiler Update
|
||||
|
||||
If you get an error while installing the VS2010 SP1 Compiler update saying that you don't have the Windows SDK installed, then uninstall all of the above and start again in the correct order.
|
||||
|
||||
Some of the build instructions will ask you to start a Visual Studio Command Prompt. You should have a shortcut in your Start menu called "Open Visual Studio Command Prompt (2010)" which will do so.
|
||||
|
||||
#####Visual Studio 2013
|
||||
|
||||
You can use the Community or Professional editions of Visual Studio 2013.
|
||||
|
||||
You can start a Visual Studio 2013 command prompt using the shortcut provided in the Visual Studio Tools folder installed as part of Visual Studio 2013.
|
||||
|
||||
Or you can start a regular command prompt and then run:
|
||||
|
||||
"%VS120COMNTOOLS%\vsvars32.bat"
|
||||
|
||||
If you experience issues building interface on Visual Studio 2013, try generating the build files with Visual Studio 2010 instead. To do so, download Visual Studio 2010 and run `cmake .. -G "Visual Studio 10"` (Assuming running from %HIFI_DIR%\build).
|
||||
|
||||
####Qt
|
||||
You can use the online installer or the offline installer. If you use the offline installer, be sure to select the "OpenGL" version.
|
||||
|
||||
NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit version of libraries for interface.exe to run. The 32-bit version of the static library is the one linked by our CMake find modules.
|
||||
|
||||
* Download the online installer [here](http://qt-project.org/downloads)
|
||||
* When it asks you to select components, ONLY select the following:
|
||||
* Qt > Qt 5.2.0 > **msvc2010 32-bit OpenGL**
|
||||
|
||||
* Download the offline installer [here](http://download.qt-project.org/official_releases/qt/5.2/5.2.0/qt-windows-opensource-5.2.0-msvc2010_opengl-x86-offline.exe)
|
||||
|
||||
Once Qt is installed, you need to manually configure the following:
|
||||
* Make sure the Qt runtime DLLs are loadable. You must do this before you attempt to build because some tools for the build depend on Qt. E.g., add to the PATH: `Qt\5.2.0\msvc2010_opengl\bin\`.
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.2.0\msvc2010_opengl` directory.
|
||||
|
||||
If building as a Visual Studio 2013 project, download and configure the msvc2013 version of Qt instead.
|
||||
|
||||
####External Libraries
|
||||
|
||||
CMake will need to know where the headers and libraries for required external dependencies are.
|
||||
|
||||
The recommended route for CMake to find the external dependencies is to place all of the dependencies in one folder and set one ENV variable - HIFI_LIB_DIR. That ENV variable should point to a directory with the following structure:
|
||||
|
||||
root_lib_dir
|
||||
-> freeglut
|
||||
-> bin
|
||||
-> include
|
||||
-> lib
|
||||
-> glew
|
||||
-> bin
|
||||
-> include
|
||||
-> lib
|
||||
-> glm
|
||||
-> glm
|
||||
-> glm.hpp
|
||||
-> openssl
|
||||
-> bin
|
||||
-> include
|
||||
-> lib
|
||||
-> zlib
|
||||
-> include
|
||||
-> lib
|
||||
-> test
|
||||
|
||||
For many of the external libraries where precompiled binaries are readily available you should be able to simply copy the extracted folder that you get from the download links provided at the top of the guide. Otherwise you may need to build from source and install the built product to this directory. The `root_lib_dir` in the above example can be wherever you choose on your system - as long as the environment variable HIFI_LIB_DIR is set to it. From here on, whenever you see %HIFI_LIB_DIR% you should substitute the directory that you chose.
|
||||
|
||||
As with the Qt libraries, you will need to make sure that directories containing DLL'S are in your path. Where possible, you can use static builds of the external dependencies to avoid this requirement.
|
||||
|
||||
#### OpenSSL
|
||||
|
||||
QT will use OpenSSL if it's available, but it doesn't install it, so you must install it separately.
|
||||
|
||||
Your system may already have several versions of the OpenSSL DLL's (ssleay32.dll, libeay32.dll) lying around, but they may be the wrong version. If these DLL's are in the PATH then QT will try to use them, and if they're the wrong version then you will see the following errors in the console:
|
||||
|
||||
QSslSocket: cannot resolve TLSv1_1_client_method
|
||||
QSslSocket: cannot resolve TLSv1_2_client_method
|
||||
QSslSocket: cannot resolve TLSv1_1_server_method
|
||||
QSslSocket: cannot resolve TLSv1_2_server_method
|
||||
QSslSocket: cannot resolve SSL_select_next_proto
|
||||
QSslSocket: cannot resolve SSL_CTX_set_next_proto_select_cb
|
||||
QSslSocket: cannot resolve SSL_get0_next_proto_negotiated
|
||||
|
||||
To prevent these problems, install OpenSSL yourself. Download the following binary packages [from this website](http://slproweb.com/products/Win32OpenSSL.html):
|
||||
* Visual C++ 2008 Redistributables
|
||||
* Win32 OpenSSL v1.0.1h
|
||||
|
||||
Install OpenSSL into the Windows system directory, to make sure that QT uses the version that you've just installed, and not some other version.
|
||||
|
||||
#### Zlib
|
||||
|
||||
Download the compiled DLL from the [zlib website](http://www.zlib.net/). Extract to %HIFI_LIB_DIR%\zlib.
|
||||
|
||||
Add the following environment variables (remember to substitute your own directory for %HIFI_LIB_DIR%):
|
||||
|
||||
ZLIB_LIBRARY=%HIFI_LIB_DIR%\zlib\lib\zdll.lib
|
||||
ZLIB_INCLUDE_DIR=%HIFI_LIB_DIR%\zlib\include
|
||||
|
||||
Add to the PATH: `%HIFI_LIB_DIR%\zlib`
|
||||
|
||||
Important! This should be added at the beginning of the path, not the end. That's because your
|
||||
system likely has many copies of zlib1.dll, and you want High Fidelity to use the correct version. If High Fidelity picks up the wrong zlib1.dll then it might be unable to use it, and that would cause it to fail to start, showing only the cryptic error "The application was unable to start correctly: 0xc0000022".
|
||||
|
||||
#### freeglut
|
||||
|
||||
Download the binary package: `freeglut-MSVC-2.8.1-1.mp.zip`. Extract to %HIFI_LIB_DIR%\freeglut.
|
||||
|
||||
Add to the PATH: `%HIFI_LIB_DIR%\freeglut\bin`
|
||||
|
||||
#### GLEW
|
||||
|
||||
Download the binary package: `glew-1.10.0-win32.zip`. Extract to %HIFI_LIB_DIR%\glew (you'll need to rename the default directory name).
|
||||
|
||||
Add to the PATH: `%HIFI_LIB_DIR%\glew\bin\Release\Win32`
|
||||
|
||||
#### GLM
|
||||
|
||||
This package contains only headers, so there's nothing to add to the PATH.
|
||||
|
||||
Be careful with glm. For the folder other libraries would normally call 'include', the folder containing the headers, glm opts to use 'glm'. You will have a glm folder nested inside the top-level glm folder.
|
||||
|
||||
#### Build High Fidelity using Visual Studio
|
||||
Follow the same build steps from the CMake section, but pass a different generator to CMake.
|
||||
|
||||
cmake .. -DZLIB_LIBRARY=%ZLIB_LIBRARY% -DZLIB_INCLUDE_DIR=%ZLIB_INCLUDE_DIR% -G "Visual Studio 10"
|
||||
|
||||
If you're using Visual Studio 2013 then pass "Visual Studio 12" instead of "Visual Studio 10" (yes, 12, not 13).
|
||||
|
||||
Open %HIFI_DIR%\build\hifi.sln and compile.
|
||||
|
||||
####Running Interface
|
||||
If you need to debug Interface, you can run interface from within Visual Studio (see the section below). You can also run Interface by launching it from command line or File Explorer from %HIFI_DIR%\build\interface\Debug\interface.exe
|
||||
|
||||
####Debugging Interface
|
||||
* In the Solution Explorer, right click interface and click Set as StartUp Project
|
||||
* Set the "Working Directory" for the Interface debugging sessions to the Debug output directory so that your application can load resources. Do this: right click interface and click Properties, choose Debugging from Configuration Properties, set Working Directory to .\Debug
|
||||
* Now you can run and debug interface through Visual Studio
|
||||
|
||||
Optional Components
|
||||
===
|
||||
###Optional Components
|
||||
|
||||
####QXmpp
|
||||
|
||||
|
@ -260,7 +57,7 @@ You can find QXmpp [here](https://github.com/qxmpp-project/qxmpp). The inclusion
|
|||
|
||||
OS X users who tap our [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) can install QXmpp via homebrew - `brew install highfidelity/formulas/qxmpp`.
|
||||
|
||||
#### Devices
|
||||
####Devices
|
||||
|
||||
You can support external input/output devices such as Leap Motion, Faceplus, Faceshift, PrioVR, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
|
||||
|
|
12
BUILD_LINUX.md
Normal file
12
BUILD_LINUX.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file.
|
||||
|
||||
###Linux Specific Dependencies
|
||||
* [freeglut](http://freeglut.sourceforge.net/) ~> 2.8.0
|
||||
* [zLib](http://www.zlib.net/) ~> 1.2.8
|
||||
|
||||
In general, as long as external dependencies are placed in OS standard locations, CMake will successfully find them during its run. When possible, you may choose to install depencies from your package manager of choice, or from source.
|
||||
|
||||
###Qt5 Dependencies
|
||||
Should you choose not to install Qt5 via a package manager that handles dependencies for you, you may be missing some Qt5 dependencies. On Ubuntu, for example, the following additional packages are required:
|
||||
|
||||
libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-dev
|
22
BUILD_OSX.md
Normal file
22
BUILD_OSX.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
|
||||
|
||||
###Homebrew
|
||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all hifi dependencies very simple.
|
||||
|
||||
brew tap highfidelity/homebrew-formulas
|
||||
brew install cmake glm openssl tbb
|
||||
brew install highfidelity/formulas/qt5
|
||||
brew link qt5 --force
|
||||
|
||||
We have a [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) that you can use/tap to install some of the dependencies. In the code block above qt5 is installed from a formula in this repository.
|
||||
|
||||
*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.3.x stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.*
|
||||
|
||||
###Xcode
|
||||
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
||||
|
||||
cmake .. -GXcode
|
||||
|
||||
After running cmake, you will have the make files or Xcode project file necessary to build all of the components. Open the hifi.xcodeproj file, choose ALL_BUILD from the Product > Scheme menu (or target drop down), and click Run.
|
||||
|
||||
If the build completes successfully, you will have built targets for all components located in the `build/${target_name}/Debug` directories.
|
149
BUILD_WIN.md
Normal file
149
BUILD_WIN.md
Normal file
|
@ -0,0 +1,149 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Windows specific instructions are found in this file.
|
||||
|
||||
###Windows Dependencies
|
||||
* [GLEW](http://glew.sourceforge.net/) ~> 1.10.0
|
||||
* [freeglut MSVC](http://www.transmissionzero.co.uk/software/freeglut-devel/) ~> 2.8.1
|
||||
* [zLib](http://www.zlib.net/) ~> 1.2.8
|
||||
|
||||
###Visual Studio
|
||||
|
||||
Currently building on Windows has been tested using the following compilers:
|
||||
* Visual Studio 2013
|
||||
|
||||
(If anyone can test using Visual Studio 2013 Express then please update this document)
|
||||
|
||||
####Visual Studio 2013
|
||||
|
||||
You can use the Community or Professional editions of Visual Studio 2013.
|
||||
|
||||
You can start a Visual Studio 2013 command prompt using the shortcut provided in the Visual Studio Tools folder installed as part of Visual Studio 2013.
|
||||
|
||||
Or you can start a regular command prompt and then run:
|
||||
|
||||
"%VS120COMNTOOLS%\vsvars32.bat"
|
||||
|
||||
#####Windows SDK 8.1
|
||||
|
||||
If using Visual Studio 2013 and building as a Visual Studio 2013 project you need the Windows 8 SDK which you should already have as part of installing Visual Studio 2013. You should be able to see it at `C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86`.
|
||||
|
||||
###Qt
|
||||
You can use the online installer or the offline installer. If you use the offline installer, be sure to select the "OpenGL" version.
|
||||
|
||||
NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit version of libraries for interface.exe to run. The 32-bit version of the static library is the one linked by our CMake find modules.
|
||||
|
||||
* Download the online installer [here](http://qt-project.org/downloads)
|
||||
* When it asks you to select components, ONLY select the following:
|
||||
* Qt > Qt 5.3.2 > **msvc2013 32-bit OpenGL**
|
||||
|
||||
* Download the offline installer [here](http://download.qt-project.org/official_releases/qt/5.3/5.3.2/qt-opensource-windows-x86-msvc2013_opengl-5.3.2.exe)
|
||||
|
||||
Once Qt is installed, you need to manually configure the following:
|
||||
* Make sure the Qt runtime DLLs are loadable. You must do this before you attempt to build because some tools for the build depend on Qt. E.g., add to the PATH: `Qt\5.3.2\msvc2013_opengl\bin\`.
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.3.2\msvc2013_opengl` directory.
|
||||
|
||||
###External Libraries
|
||||
|
||||
CMake will need to know where the headers and libraries for required external dependencies are.
|
||||
|
||||
The recommended route for CMake to find the external dependencies is to place all of the dependencies in one folder and set one ENV variable - HIFI_LIB_DIR. That ENV variable should point to a directory with the following structure:
|
||||
|
||||
root_lib_dir
|
||||
-> freeglut
|
||||
-> bin
|
||||
-> include
|
||||
-> lib
|
||||
-> glew
|
||||
-> bin
|
||||
-> include
|
||||
-> lib
|
||||
-> glm
|
||||
-> glm
|
||||
-> glm.hpp
|
||||
-> openssl
|
||||
-> bin
|
||||
-> include
|
||||
-> lib
|
||||
-> tbb
|
||||
-> include
|
||||
-> lib
|
||||
-> zlib
|
||||
-> include
|
||||
-> lib
|
||||
-> test
|
||||
|
||||
For many of the external libraries where precompiled binaries are readily available you should be able to simply copy the extracted folder that you get from the download links provided at the top of the guide. Otherwise you may need to build from source and install the built product to this directory. The `root_lib_dir` in the above example can be wherever you choose on your system - as long as the environment variable HIFI_LIB_DIR is set to it. From here on, whenever you see %HIFI_LIB_DIR% you should substitute the directory that you chose.
|
||||
|
||||
As with the Qt libraries, you will need to make sure that directories containing DLL'S are in your path. Where possible, you can use static builds of the external dependencies to avoid this requirement.
|
||||
|
||||
###OpenSSL
|
||||
|
||||
QT will use OpenSSL if it's available, but it doesn't install it, so you must install it separately.
|
||||
|
||||
Your system may already have several versions of the OpenSSL DLL's (ssleay32.dll, libeay32.dll) lying around, but they may be the wrong version. If these DLL's are in the PATH then QT will try to use them, and if they're the wrong version then you will see the following errors in the console:
|
||||
|
||||
QSslSocket: cannot resolve TLSv1_1_client_method
|
||||
QSslSocket: cannot resolve TLSv1_2_client_method
|
||||
QSslSocket: cannot resolve TLSv1_1_server_method
|
||||
QSslSocket: cannot resolve TLSv1_2_server_method
|
||||
QSslSocket: cannot resolve SSL_select_next_proto
|
||||
QSslSocket: cannot resolve SSL_CTX_set_next_proto_select_cb
|
||||
QSslSocket: cannot resolve SSL_get0_next_proto_negotiated
|
||||
|
||||
To prevent these problems, install OpenSSL yourself. Download the following binary packages [from this website](http://slproweb.com/products/Win32OpenSSL.html):
|
||||
* Visual C++ 2008 Redistributables
|
||||
* Win32 OpenSSL v1.0.1h
|
||||
|
||||
Install OpenSSL into the Windows system directory, to make sure that QT uses the version that you've just installed, and not some other version.
|
||||
|
||||
###Intel Threading Building Blocks (TBB)
|
||||
|
||||
Download the zip from the [TBB website](https://www.threadingbuildingblocks.org/).
|
||||
|
||||
We recommend you extract it to %HIFI_LIB_DIR%\tbb. This will help our FindTBB cmake module find what it needs. You can place it wherever you like on your machine if you specify TBB_ROOT_DIR as an environment variable or a variable passed when cmake is run.
|
||||
|
||||
###Zlib
|
||||
|
||||
Download the compiled DLL from the [zlib website](http://www.zlib.net/). Extract to %HIFI_LIB_DIR%\zlib.
|
||||
|
||||
Add the following environment variables (remember to substitute your own directory for %HIFI_LIB_DIR%):
|
||||
|
||||
ZLIB_LIBRARY=%HIFI_LIB_DIR%\zlib\lib\zdll.lib
|
||||
ZLIB_INCLUDE_DIR=%HIFI_LIB_DIR%\zlib\include
|
||||
|
||||
Add to the PATH: `%HIFI_LIB_DIR%\zlib`
|
||||
|
||||
Important! This should be added at the beginning of the path, not the end. That's because your
|
||||
system likely has many copies of zlib1.dll, and you want High Fidelity to use the correct version. If High Fidelity picks up the wrong zlib1.dll then it might be unable to use it, and that would cause it to fail to start, showing only the cryptic error "The application was unable to start correctly: 0xc0000022".
|
||||
|
||||
###freeglut
|
||||
|
||||
Download the binary package: `freeglut-MSVC-2.8.1-1.mp.zip`. Extract to %HIFI_LIB_DIR%\freeglut.
|
||||
|
||||
Add to the PATH: `%HIFI_LIB_DIR%\freeglut\bin`
|
||||
|
||||
###GLEW
|
||||
|
||||
Download the binary package: `glew-1.10.0-win32.zip`. Extract to %HIFI_LIB_DIR%\glew (you'll need to rename the default directory name).
|
||||
|
||||
Add to the PATH: `%HIFI_LIB_DIR%\glew\bin\Release\Win32`
|
||||
|
||||
###GLM
|
||||
|
||||
This package contains only headers, so there's nothing to add to the PATH.
|
||||
|
||||
Be careful with glm. For the folder other libraries would normally call 'include', the folder containing the headers, glm opts to use 'glm'. You will have a glm folder nested inside the top-level glm folder.
|
||||
|
||||
###Build High Fidelity using Visual Studio
|
||||
Follow the same build steps from the CMake section, but pass a different generator to CMake.
|
||||
|
||||
cmake .. -DZLIB_LIBRARY=%ZLIB_LIBRARY% -DZLIB_INCLUDE_DIR=%ZLIB_INCLUDE_DIR% -G "Visual Studio 12"
|
||||
|
||||
Open %HIFI_DIR%\build\hifi.sln and compile.
|
||||
|
||||
###Running Interface
|
||||
If you need to debug Interface, you can run interface from within Visual Studio (see the section below). You can also run Interface by launching it from command line or File Explorer from %HIFI_DIR%\build\interface\Debug\interface.exe
|
||||
|
||||
###Debugging Interface
|
||||
* In the Solution Explorer, right click interface and click Set as StartUp Project
|
||||
* Set the "Working Directory" for the Interface debugging sessions to the Debug output directory so that your application can load resources. Do this: right click interface and click Properties, choose Debugging from Configuration Properties, set Working Directory to .\Debug
|
||||
* Now you can run and debug interface through Visual Studio
|
|
@ -12,6 +12,10 @@ if (POLICY CMP0043)
|
|||
cmake_policy(SET CMP0043 OLD)
|
||||
endif ()
|
||||
|
||||
if (POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 OLD)
|
||||
endif ()
|
||||
|
||||
project(hifi)
|
||||
add_definitions(-DGLM_FORCE_RADIANS)
|
||||
|
||||
|
@ -34,6 +38,24 @@ elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-strict-aliasing")
|
||||
endif(WIN32)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
||||
|
||||
if (COMPILER_SUPPORTS_CXX11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
elseif(COMPILER_SUPPORTS_CXX0X)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
else()
|
||||
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++0x")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --stdlib=libc++")
|
||||
endif ()
|
||||
|
||||
if (NOT QT_CMAKE_PREFIX_PATH)
|
||||
set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH})
|
||||
endif ()
|
||||
|
|
|
@ -6,13 +6,13 @@ include_glm()
|
|||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
audio avatars octree voxels fbx entities metavoxels
|
||||
audio avatars octree voxels gpu model fbx entities metavoxels
|
||||
networking animation shared script-engine embedded-webserver
|
||||
physics
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${CMAKE_DL_LIBS})
|
||||
target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})
|
||||
endif (UNIX)
|
||||
|
||||
link_shared_dependencies()
|
||||
include_dependency_includes()
|
||||
|
|
|
@ -441,12 +441,13 @@ int AudioMixer::prepareMixForListeningNode(Node* node) {
|
|||
|
||||
// loop through all other nodes that have sufficient audio to mix
|
||||
int streamsMixed = 0;
|
||||
foreach (const SharedNodePointer& otherNode, NodeList::getInstance()->getNodeHash()) {
|
||||
|
||||
NodeList::getInstance()->eachNode([&](const SharedNodePointer& otherNode){
|
||||
if (otherNode->getLinkedData()) {
|
||||
AudioMixerClientData* otherNodeClientData = (AudioMixerClientData*) otherNode->getLinkedData();
|
||||
|
||||
|
||||
// enumerate the ARBs attached to the otherNode and add all that should be added to mix
|
||||
|
||||
|
||||
const QHash<QUuid, PositionalAudioStream*>& otherNodeAudioStreams = otherNodeClientData->getAudioStreams();
|
||||
QHash<QUuid, PositionalAudioStream*>::ConstIterator i;
|
||||
for (i = otherNodeAudioStreams.constBegin(); i != otherNodeAudioStreams.constEnd(); i++) {
|
||||
|
@ -456,14 +457,15 @@ int AudioMixer::prepareMixForListeningNode(Node* node) {
|
|||
if (otherNodeStream->getType() == PositionalAudioStream::Microphone) {
|
||||
streamUUID = otherNode->getUUID();
|
||||
}
|
||||
|
||||
|
||||
if (*otherNode != *node || otherNodeStream->shouldLoopbackForNode()) {
|
||||
streamsMixed += addStreamToMixForListeningNodeWithStream(listenerNodeData, streamUUID,
|
||||
otherNodeStream, nodeAudioStream);
|
||||
streamsMixed += addStreamToMixForListeningNodeWithStream(listenerNodeData, streamUUID,
|
||||
otherNodeStream, nodeAudioStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return streamsMixed;
|
||||
}
|
||||
|
||||
|
@ -541,12 +543,11 @@ void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const Hif
|
|||
QByteArray packet = receivedPacket;
|
||||
populatePacketHeader(packet, PacketTypeMuteEnvironment);
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) {
|
||||
nodeList->writeDatagram(packet, packet.size(), node);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
|
@ -609,8 +610,9 @@ void AudioMixer::sendStatsPacket() {
|
|||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
int clientNumber = 0;
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
|
||||
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
// if we're too large, send the packet
|
||||
if (sizeOfStats > TOO_BIG_FOR_MTU) {
|
||||
nodeList->sendStatsToDomainServer(statsObject2);
|
||||
|
@ -628,7 +630,7 @@ void AudioMixer::sendStatsPacket() {
|
|||
somethingToSend = true;
|
||||
sizeOfStats += property.size() + value.size();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (somethingToSend) {
|
||||
nodeList->sendStatsToDomainServer(statsObject2);
|
||||
|
@ -766,7 +768,8 @@ void AudioMixer::run() {
|
|||
_lastPerSecondCallbackTime = now;
|
||||
}
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
|
||||
if (node->getLinkedData()) {
|
||||
AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData();
|
||||
|
||||
|
@ -833,7 +836,7 @@ void AudioMixer::run() {
|
|||
++_sumListeners;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
++_numStatFrames;
|
||||
|
||||
|
@ -891,7 +894,7 @@ void AudioMixer::perSecondActions() {
|
|||
_timeSpentPerHashMatchCallStats.getWindowSum() / WINDOW_LENGTH_USECS * 100.0,
|
||||
_timeSpentPerHashMatchCallStats.getCurrentIntervalSum() / USECS_PER_SECOND * 100.0);
|
||||
|
||||
foreach(const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
NodeList::getInstance()->eachNode([](const SharedNodePointer& node) {
|
||||
if (node->getLinkedData()) {
|
||||
AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData();
|
||||
|
||||
|
@ -901,7 +904,7 @@ void AudioMixer::perSecondActions() {
|
|||
nodeData->printUpstreamDownstreamStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_datagramsReadPerCallStats.currentIntervalComplete();
|
||||
|
|
|
@ -122,7 +122,7 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
AvatarMixerClientData* nodeData = NULL;
|
||||
AvatarMixerClientData* otherNodeData = NULL;
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
if (node->getLinkedData() && node->getType() == NodeType::Agent && node->getActiveSocket()
|
||||
&& (nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData()))->getMutex().tryLock()) {
|
||||
++_sumListeners;
|
||||
|
@ -135,7 +135,7 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
|
||||
// this is an AGENT we have received head data from
|
||||
// send back a packet with other active node data to this node
|
||||
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
|
||||
nodeList->eachNode([&](const SharedNodePointer& otherNode) {
|
||||
if (otherNode->getLinkedData() && otherNode->getUUID() != node->getUUID()
|
||||
&& (otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData()))->getMutex().tryLock()) {
|
||||
|
||||
|
@ -203,13 +203,13 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
|
||||
otherNodeData->getMutex().unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
nodeList->writeDatagram(mixedAvatarByteArray, node);
|
||||
|
||||
nodeData->getMutex().unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_lastFrameTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
|
|
|
@ -131,15 +131,17 @@ void EntityServer::pruneDeletedEntities() {
|
|||
if (tree->hasAnyDeletedEntities()) {
|
||||
|
||||
quint64 earliestLastDeletedEntitiesSent = usecTimestampNow() + 1; // in the future
|
||||
foreach (const SharedNodePointer& otherNode, NodeList::getInstance()->getNodeHash()) {
|
||||
if (otherNode->getLinkedData()) {
|
||||
EntityNodeData* nodeData = static_cast<EntityNodeData*>(otherNode->getLinkedData());
|
||||
|
||||
NodeList::getInstance()->eachNode([&earliestLastDeletedEntitiesSent](const SharedNodePointer& node) {
|
||||
if (node->getLinkedData()) {
|
||||
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
||||
quint64 nodeLastDeletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
||||
if (nodeLastDeletedEntitiesSentAt < earliestLastDeletedEntitiesSent) {
|
||||
earliestLastDeletedEntitiesSent = nodeLastDeletedEntitiesSentAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tree->forgetEntitiesDeletedBefore(earliestLastDeletedEntitiesSent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -261,7 +261,7 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
|
|||
continue;
|
||||
}
|
||||
|
||||
const SharedNodePointer& destinationNode = NodeList::getInstance()->getNodeHash().value(nodeUUID);
|
||||
const SharedNodePointer& destinationNode = NodeList::getInstance()->nodeWithUUID(nodeUUID);
|
||||
|
||||
// retrieve sequence number stats of node, prune its missing set
|
||||
SequenceNumberStats& sequenceNumberStats = nodeStats.getIncomingEditSequenceNumberStats();
|
||||
|
|
|
@ -1222,13 +1222,16 @@ void OctreeServer::aboutToFinish() {
|
|||
qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish...";
|
||||
qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down...";
|
||||
_octreeInboundPacketProcessor->shuttingDown();
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
|
||||
NodeList::getInstance()->eachNode([this](const SharedNodePointer& node) {
|
||||
qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node;
|
||||
forceNodeShutdown(node);
|
||||
}
|
||||
});
|
||||
|
||||
if (_persistThread) {
|
||||
_persistThread->aboutToFinish();
|
||||
}
|
||||
|
||||
qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish...";
|
||||
}
|
||||
|
||||
|
|
22
cmake/macros/IncludeDependencyIncludes.cmake
Normal file
22
cmake/macros/IncludeDependencyIncludes.cmake
Normal file
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# IncludeDependencyIncludes.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on August 8, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(INCLUDE_DEPENDENCY_INCLUDES)
|
||||
if (${TARGET_NAME}_DEPENDENCY_INCLUDES)
|
||||
list(REMOVE_DUPLICATES ${TARGET_NAME}_DEPENDENCY_INCLUDES)
|
||||
|
||||
# include those in our own target
|
||||
include_directories(SYSTEM ${${TARGET_NAME}_DEPENDENCY_INCLUDES})
|
||||
endif ()
|
||||
|
||||
# set the property on this target so it can be retreived by targets linking to us
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_INCLUDES "${${TARGET_NAME}_DEPENDENCY_INCLUDES}")
|
||||
endmacro(INCLUDE_DEPENDENCY_INCLUDES)
|
|
@ -25,10 +25,9 @@ macro(LINK_HIFI_LIBRARIES)
|
|||
# link the actual library - it is static so don't bubble it up
|
||||
target_link_libraries(${TARGET_NAME} ${HIFI_LIBRARY})
|
||||
|
||||
# ask the library what its dynamic dependencies are and link them
|
||||
get_target_property(LINKED_TARGET_DEPENDENCY_LIBRARIES ${HIFI_LIBRARY} DEPENDENCY_LIBRARIES)
|
||||
list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${LINKED_TARGET_DEPENDENCY_LIBRARIES})
|
||||
|
||||
# ask the library what its include dependencies are and link them
|
||||
get_target_property(LINKED_TARGET_DEPENDENCY_INCLUDES ${HIFI_LIBRARY} DEPENDENCY_INCLUDES)
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_INCLUDES ${LINKED_TARGET_DEPENDENCY_INCLUDES})
|
||||
endforeach()
|
||||
|
||||
endmacro(LINK_HIFI_LIBRARIES)
|
|
@ -1,25 +0,0 @@
|
|||
#
|
||||
# LinkSharedDependencies.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on August 8, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(LINK_SHARED_DEPENDENCIES)
|
||||
if (${TARGET_NAME}_LIBRARIES_TO_LINK)
|
||||
list(REMOVE_DUPLICATES ${TARGET_NAME}_LIBRARIES_TO_LINK)
|
||||
|
||||
# link these libraries to our target
|
||||
target_link_libraries(${TARGET_NAME} ${${TARGET_NAME}_LIBRARIES_TO_LINK})
|
||||
endif ()
|
||||
|
||||
# we've already linked our Qt modules, but we need to bubble them up to parents
|
||||
list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${${TARGET}_QT_MODULES_TO_LINK}")
|
||||
|
||||
# set the property on this target so it can be retreived by targets linking to us
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${${TARGET}_LIBRARIES_TO_LINK}")
|
||||
endmacro(LINK_SHARED_DEPENDENCIES)
|
|
@ -18,16 +18,14 @@ macro(SETUP_HIFI_LIBRARY)
|
|||
# create a library and set the property so it can be referenced later
|
||||
add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOMTC_SRC})
|
||||
|
||||
set(QT_MODULES_TO_LINK ${ARGN})
|
||||
list(APPEND QT_MODULES_TO_LINK Core)
|
||||
set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN})
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
|
||||
|
||||
find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK} REQUIRED)
|
||||
|
||||
foreach(QT_MODULE ${QT_MODULES_TO_LINK})
|
||||
get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION)
|
||||
|
||||
# add the actual path to the Qt module to our LIBRARIES_TO_LINK variable
|
||||
# find these Qt modules and link them to our own target
|
||||
find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED)
|
||||
|
||||
foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES})
|
||||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
||||
list(APPEND ${TARGET_NAME}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION})
|
||||
endforeach()
|
||||
|
||||
endmacro(SETUP_HIFI_LIBRARY)
|
|
@ -25,17 +25,13 @@ macro(SETUP_HIFI_PROJECT)
|
|||
# add the executable, include additional optional sources
|
||||
add_executable(${TARGET_NAME} ${TARGET_SRCS} "${AUTOMTC_SRC}")
|
||||
|
||||
set(QT_MODULES_TO_LINK ${ARGN})
|
||||
list(APPEND QT_MODULES_TO_LINK Core)
|
||||
set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN})
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
|
||||
|
||||
find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK} REQUIRED)
|
||||
|
||||
foreach(QT_MODULE ${QT_MODULES_TO_LINK})
|
||||
# find these Qt modules and link them to our own target
|
||||
find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED)
|
||||
|
||||
foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES})
|
||||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
||||
|
||||
# add the actual path to the Qt module to our LIBRARIES_TO_LINK variable
|
||||
get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION)
|
||||
list(APPEND ${TARGET_NAME}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION})
|
||||
endforeach()
|
||||
|
||||
endmacro()
|
|
@ -1,47 +0,0 @@
|
|||
#
|
||||
# FindGLUT.cmake
|
||||
#
|
||||
# Try to find GLUT library and include path.
|
||||
# Once done this will define
|
||||
#
|
||||
# GLUT_FOUND
|
||||
# GLUT_INCLUDE_DIRS
|
||||
# GLUT_LIBRARIES
|
||||
#
|
||||
# Created on 2/6/2014 by Stephen Birarda
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
#
|
||||
# Adapted from FindGLUT.cmake available in tlorach's OpenGLText Repository
|
||||
# https://raw.github.com/tlorach/OpenGLText/master/cmake/FindGLUT.cmake
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("freeglut")
|
||||
|
||||
if (WIN32)
|
||||
set(GLUT_HINT_DIRS "${FREEGLUT_SEARCH_DIRS} ${OPENGL_INCLUDE_DIR}")
|
||||
|
||||
find_path(GLUT_INCLUDE_DIRS GL/glut.h PATH_SUFFIXES include HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
find_library(GLUT_LIBRARY freeglut PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
else ()
|
||||
find_path(GLUT_INCLUDE_DIRS GL/glut.h PATH_SUFFIXES include HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
find_library(GLUT_LIBRARY glut PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
set(GLUT_LIBRARIES "${GLUT_LIBRARY}" "${XMU_LIBRARY}" "${XI_LIBRARY}")
|
||||
|
||||
if (UNIX)
|
||||
find_library(XI_LIBRARY Xi PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
find_library(XMU_LIBRARY Xmu PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
|
||||
|
||||
find_package_handle_standard_args(GLUT DEFAULT_MSG GLUT_INCLUDE_DIRS GLUT_LIBRARIES XI_LIBRARY XMU_LIBRARY)
|
||||
else ()
|
||||
find_package_handle_standard_args(GLUT DEFAULT_MSG GLUT_INCLUDE_DIRS GLUT_LIBRARIES)
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(GLUT_INCLUDE_DIRS GLUT_LIBRARIES GLUT_LIBRARY XI_LIBRARY XMU_LIBRARY FREEGLUT_SEARCH_DIRS)
|
75
cmake/modules/FindTBB.cmake
Normal file
75
cmake/modules/FindTBB.cmake
Normal file
|
@ -0,0 +1,75 @@
|
|||
#
|
||||
# FindTBB.cmake
|
||||
#
|
||||
# Try to find the Intel Threading Building Blocks library
|
||||
#
|
||||
# You can provide a TBB_ROOT_DIR which contains lib and include directories
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# TBB_FOUND - system was able to find TBB
|
||||
# TBB_INCLUDE_DIRS - the TBB include directory
|
||||
# TBB_LIBRARIES - link this to use TBB
|
||||
#
|
||||
# Created on 12/14/2014 by Stephen Birarda
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("tbb")
|
||||
|
||||
find_path(TBB_INCLUDE_DIRS tbb/tbb.h PATH_SUFFIXES include HINTS ${TBB_SEARCH_DIRS})
|
||||
|
||||
set(_TBB_LIB_NAME "tbb")
|
||||
set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
|
||||
|
||||
if (APPLE)
|
||||
set(_TBB_LIB_DIR "lib/libc++")
|
||||
elseif (UNIX)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_TBB_ARCH_DIR "intel64")
|
||||
else()
|
||||
set(_TBB_ARCH_DIR "ia32")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE GCC_VERSION
|
||||
)
|
||||
|
||||
if (GCC_VERSION VERSION_GREATER 4.4 OR GCC_VERSION VERSION_EQUAL 4.4)
|
||||
set(_TBB_LIB_DIR "lib/${_TBB_ARCH_DIR}/gcc4.4")
|
||||
elseif (GCC_VERSION VERSION_GREATER 4.1 OR GCC_VERSION VERSION_EQUAL 4.1)
|
||||
set(_TBB_LIB_DIR "lib/${_TBB_ARCH_DIR}/gcc4.1")
|
||||
else ()
|
||||
message(FATAL_ERROR "Could not find a compatible version of Threading Building Blocks library for your compiler.")
|
||||
endif ()
|
||||
|
||||
elseif (WIN32)
|
||||
if (CMAKE_CL_64)
|
||||
set(_TBB_ARCH_DIR "intel64")
|
||||
else()
|
||||
set(_TBB_ARCH_DIR "ia32")
|
||||
endif()
|
||||
|
||||
set(_TBB_LIB_DIR "lib/${_TBB_ARCH_DIR}/vc12")
|
||||
endif ()
|
||||
|
||||
find_library(TBB_LIBRARY_DEBUG NAMES ${_TBB_LIB_NAME}_debug PATH_SUFFIXES ${_TBB_LIB_DIR} HINTS ${TBB_SEARCH_DIRS})
|
||||
find_library(TBB_LIBRARY_RELEASE NAMES ${_TBB_LIB_NAME} PATH_SUFFIXES ${_TBB_LIB_DIR} HINTS ${TBB_SEARCH_DIRS})
|
||||
|
||||
find_library(TBB_MALLOC_LIBRARY_DEBUG NAMES ${_TBB_LIB_MALLOC_NAME}_debug PATH_SUFFIXES ${_TBB_LIB_DIR} HINTS ${TBB_SEARCH_DIRS})
|
||||
find_library(TBB_MALLOC_LIBRARY_RELEASE NAMES ${_TBB_LIB_MALLOC_NAME} PATH_SUFFIXES ${_TBB_LIB_DIR} HINTS ${TBB_SEARCH_DIRS})
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
select_library_configurations(TBB)
|
||||
select_library_configurations(TBB_MALLOC)
|
||||
|
||||
find_package_handle_standard_args(TBB DEFAULT_MSG TBB_LIBRARY TBB_MALLOC_LIBRARY TBB_INCLUDE_DIRS)
|
||||
|
||||
set(TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY})
|
|
@ -32,9 +32,10 @@ if (APPLE)
|
|||
find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS})
|
||||
find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib HINTS ${VISAGE_SEARCH_DIRS})
|
||||
|
||||
find_library(AppKit AppKit)
|
||||
find_library(QuartzCore QuartzCore)
|
||||
find_library(CoreVideo CoreVideo)
|
||||
find_library(QTKit QTKit)
|
||||
find_library(IOKit IOKit)
|
||||
|
||||
elseif (WIN32)
|
||||
find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS})
|
||||
find_path(VISAGE_OPENCV_INCLUDE_DIR opencv/cv.h PATH_SUFFIXES dependencies/OpenCV/include HINTS ${VISAGE_SEARCH_DIRS})
|
||||
|
@ -49,19 +50,19 @@ include(FindPackageHandleStandardArgs)
|
|||
|
||||
list(APPEND VISAGE_ARGS_LIST VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR
|
||||
VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR
|
||||
VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY)
|
||||
VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY)
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND VISAGE_ARGS_LIST QuartzCore AppKit QTKit)
|
||||
list(APPEND VISAGE_ARGS_LIST CoreVideo QTKit IOKit)
|
||||
endif ()
|
||||
|
||||
find_package_handle_standard_args(Visage DEFAULT_MSG ${VISAGE_ARGS_LIST})
|
||||
|
||||
set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR}" "${VISAGE_OPENCV2_INCLUDE_DIR}" "${VISAGE_BASE_INCLUDE_DIR}")
|
||||
set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}")
|
||||
set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}")
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND VISAGE_LIBRARIES ${QuartzCore} ${AppKit} ${QTKit})
|
||||
list(APPEND VISAGE_LIBRARIES "${CoreVideo}" "${QTKit}" "${IOKit}")
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES)
|
||||
|
|
|
@ -50,6 +50,6 @@ endif ()
|
|||
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
||||
|
||||
# append OpenSSL to our list of libraries to link
|
||||
list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${OPENSSL_LIBRARIES}")
|
||||
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})
|
||||
|
||||
link_shared_dependencies()
|
||||
include_dependency_includes()
|
|
@ -1,131 +1,3 @@
|
|||
// Add your JavaScript for assignment below this line
|
||||
|
||||
// The following is an example of Conway's Game of Life (http://en.wikipedia.org/wiki/Conway's_Game_of_Life)
|
||||
|
||||
var NUMBER_OF_CELLS_EACH_DIMENSION = 64;
|
||||
var NUMBER_OF_CELLS = NUMBER_OF_CELLS_EACH_DIMENSION * NUMBER_OF_CELLS_EACH_DIMENSION;
|
||||
|
||||
var currentCells = [];
|
||||
var nextCells = [];
|
||||
|
||||
var METER_LENGTH = 1;
|
||||
var cellScale = (NUMBER_OF_CELLS_EACH_DIMENSION * METER_LENGTH) / NUMBER_OF_CELLS_EACH_DIMENSION;
|
||||
|
||||
// randomly populate the cell start values
|
||||
for (var i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) {
|
||||
// create the array to hold this row
|
||||
currentCells[i] = [];
|
||||
|
||||
// create the array to hold this row in the nextCells array
|
||||
nextCells[i] = [];
|
||||
|
||||
for (var j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) {
|
||||
currentCells[i][j] = Math.floor(Math.random() * 2);
|
||||
|
||||
// put the same value in the nextCells array for first board draw
|
||||
nextCells[i][j] = currentCells[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
function isNeighbourAlive(i, j) {
|
||||
if (i < 0 || i >= NUMBER_OF_CELLS_EACH_DIMENSION
|
||||
|| i < 0 || j >= NUMBER_OF_CELLS_EACH_DIMENSION) {
|
||||
return 0;
|
||||
} else {
|
||||
return currentCells[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
function updateCells() {
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
|
||||
for (i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) {
|
||||
for (j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) {
|
||||
// figure out the number of live neighbours for the i-j cell
|
||||
var liveNeighbours =
|
||||
isNeighbourAlive(i + 1, j - 1) + isNeighbourAlive(i + 1, j) + isNeighbourAlive(i + 1, j + 1) +
|
||||
isNeighbourAlive(i, j - 1) + isNeighbourAlive(i, j + 1) +
|
||||
isNeighbourAlive(i - 1, j - 1) + isNeighbourAlive(i - 1, j) + isNeighbourAlive(i - 1, j + 1);
|
||||
|
||||
if (currentCells[i][j]) {
|
||||
// live cell
|
||||
|
||||
if (liveNeighbours < 2) {
|
||||
// rule #1 - under-population - this cell will die
|
||||
// mark it zero to mark the change
|
||||
nextCells[i][j] = 0;
|
||||
} else if (liveNeighbours < 4) {
|
||||
// rule #2 - this cell lives
|
||||
// mark it -1 to mark no change
|
||||
nextCells[i][j] = -1;
|
||||
} else {
|
||||
// rule #3 - overcrowding - this cell dies
|
||||
// mark it zero to mark the change
|
||||
nextCells[i][j] = 0;
|
||||
}
|
||||
} else {
|
||||
// dead cell
|
||||
if (liveNeighbours == 3) {
|
||||
// rule #4 - reproduction - this cell revives
|
||||
// mark it one to mark the change
|
||||
nextCells[i][j] = 1;
|
||||
} else {
|
||||
// this cell stays dead
|
||||
// mark it -1 for no change
|
||||
nextCells[i][j] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.random() < 0.001) {
|
||||
// Random mutation to keep things interesting in there.
|
||||
nextCells[i][j] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) {
|
||||
for (j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) {
|
||||
if (nextCells[i][j] != -1) {
|
||||
// there has been a change to this cell, change the value in the currentCells array
|
||||
currentCells[i][j] = nextCells[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sendNextCells() {
|
||||
for (var i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) {
|
||||
for (var j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) {
|
||||
if (nextCells[i][j] != -1) {
|
||||
// there has been a change to the state of this cell, send it
|
||||
|
||||
// find the x and y position for this voxel, z = 0
|
||||
var x = j * cellScale;
|
||||
var y = i * cellScale;
|
||||
|
||||
// queue a packet to add a voxel for the new cell
|
||||
var color = (nextCells[i][j] == 1) ? 255 : 1;
|
||||
Voxels.setVoxel(x, y, 0, cellScale, color, color, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sentFirstBoard = false;
|
||||
|
||||
function step(deltaTime) {
|
||||
if (sentFirstBoard) {
|
||||
// we've already sent the first full board, perform a step in time
|
||||
updateCells();
|
||||
} else {
|
||||
// this will be our first board send
|
||||
sentFirstBoard = true;
|
||||
}
|
||||
|
||||
sendNextCells();
|
||||
}
|
||||
|
||||
|
||||
Script.update.connect(step);
|
||||
Voxels.setPacketsPerSecond(200);
|
||||
// Here you can put a script that will be run by an assignment-client (AC)
|
||||
// For examples, please go to http://public.highfidelity.io/scripts
|
||||
// The directory named acScripts contains assignment-client specific scripts you can try.
|
||||
|
|
|
@ -549,7 +549,9 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
|||
for (Assignment::Type defaultedType = Assignment::AudioMixerType;
|
||||
defaultedType != Assignment::AllTypes;
|
||||
defaultedType = static_cast<Assignment::Type>(static_cast<int>(defaultedType) + 1)) {
|
||||
if (!excludedTypes.contains(defaultedType) && defaultedType != Assignment::AgentType) {
|
||||
if (!excludedTypes.contains(defaultedType)
|
||||
&& defaultedType != Assignment::UNUSED
|
||||
&& defaultedType != Assignment::AgentType) {
|
||||
// type has not been set from a command line or config file config, use the default
|
||||
// by clearing whatever exists and writing a single default assignment with no payload
|
||||
Assignment* newAssignment = new Assignment(Assignment::CreateCommand, (Assignment::Type) defaultedType);
|
||||
|
@ -857,49 +859,48 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
|||
|
||||
if (nodeData->isAuthenticated()) {
|
||||
// if this authenticated node has any interest types, send back those nodes as well
|
||||
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& otherNode){
|
||||
// reset our nodeByteArray and nodeDataStream
|
||||
QByteArray nodeByteArray;
|
||||
QDataStream nodeDataStream(&nodeByteArray, QIODevice::Append);
|
||||
|
||||
|
||||
if (otherNode->getUUID() != node->getUUID() && nodeInterestList.contains(otherNode->getType())) {
|
||||
|
||||
|
||||
// don't send avatar nodes to other avatars, that will come from avatar mixer
|
||||
nodeDataStream << *otherNode.data();
|
||||
|
||||
|
||||
// pack the secret that these two nodes will use to communicate with each other
|
||||
QUuid secretUUID = nodeData->getSessionSecretHash().value(otherNode->getUUID());
|
||||
if (secretUUID.isNull()) {
|
||||
// generate a new secret UUID these two nodes can use
|
||||
secretUUID = QUuid::createUuid();
|
||||
|
||||
|
||||
// set that on the current Node's sessionSecretHash
|
||||
nodeData->getSessionSecretHash().insert(otherNode->getUUID(), secretUUID);
|
||||
|
||||
|
||||
// set it on the other Node's sessionSecretHash
|
||||
reinterpret_cast<DomainServerNodeData*>(otherNode->getLinkedData())
|
||||
->getSessionSecretHash().insert(node->getUUID(), secretUUID);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
nodeDataStream << secretUUID;
|
||||
|
||||
|
||||
if (broadcastPacket.size() + nodeByteArray.size() > dataMTU) {
|
||||
// we need to break here and start a new packet
|
||||
// so send the current one
|
||||
|
||||
|
||||
nodeList->writeDatagram(broadcastPacket, node, senderSockAddr);
|
||||
|
||||
|
||||
// reset the broadcastPacket structure
|
||||
broadcastPacket.resize(numBroadcastPacketLeadBytes);
|
||||
broadcastDataStream.device()->seek(numBroadcastPacketLeadBytes);
|
||||
}
|
||||
|
||||
|
||||
// append the nodeByteArray to the current state of broadcastDataStream
|
||||
broadcastPacket.append(nodeByteArray);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// always write the last broadcastPacket
|
||||
|
@ -996,14 +997,14 @@ void DomainServer::readAvailableDatagrams() {
|
|||
|
||||
void DomainServer::setupPendingAssignmentCredits() {
|
||||
// enumerate the NodeList to find the assigned nodes
|
||||
foreach (const SharedNodePointer& node, LimitedNodeList::getInstance()->getNodeHash()) {
|
||||
NodeList::getInstance()->eachNode([&](const SharedNodePointer& node){
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||
|
||||
|
||||
if (!nodeData->getAssignmentUUID().isNull() && !nodeData->getWalletUUID().isNull()) {
|
||||
// check if we have a non-finalized transaction for this node to add this amount to
|
||||
TransactionHash::iterator i = _pendingAssignmentCredits.find(nodeData->getWalletUUID());
|
||||
WalletTransaction* existingTransaction = NULL;
|
||||
|
||||
|
||||
while (i != _pendingAssignmentCredits.end() && i.key() == nodeData->getWalletUUID()) {
|
||||
if (!i.value()->isFinalized()) {
|
||||
existingTransaction = i.value();
|
||||
|
@ -1012,16 +1013,16 @@ void DomainServer::setupPendingAssignmentCredits() {
|
|||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
qint64 elapsedMsecsSinceLastPayment = nodeData->getPaymentIntervalTimer().elapsed();
|
||||
nodeData->getPaymentIntervalTimer().restart();
|
||||
|
||||
|
||||
const float CREDITS_PER_HOUR = 0.10f;
|
||||
const float CREDITS_PER_MSEC = CREDITS_PER_HOUR / (60 * 60 * 1000);
|
||||
const int SATOSHIS_PER_MSEC = CREDITS_PER_MSEC * SATOSHIS_PER_CREDIT;
|
||||
|
||||
|
||||
float pendingCredits = elapsedMsecsSinceLastPayment * SATOSHIS_PER_MSEC;
|
||||
|
||||
|
||||
if (existingTransaction) {
|
||||
existingTransaction->incrementAmount(pendingCredits);
|
||||
} else {
|
||||
|
@ -1030,7 +1031,7 @@ void DomainServer::setupPendingAssignmentCredits() {
|
|||
_pendingAssignmentCredits.insert(nodeData->getWalletUUID(), freshTransaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DomainServer::sendPendingTransactionsToServer() {
|
||||
|
@ -1155,11 +1156,12 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
|
|||
|
||||
// add the number of currently connected agent users
|
||||
int numConnectedAuthedUsers = 0;
|
||||
foreach(const SharedNodePointer& node, LimitedNodeList::getInstance()->getNodeHash()) {
|
||||
|
||||
NodeList::getInstance()->eachNode([&numConnectedAuthedUsers](const SharedNodePointer& node){
|
||||
if (node->getLinkedData() && !static_cast<DomainServerNodeData*>(node->getLinkedData())->getUsername().isEmpty()) {
|
||||
++numConnectedAuthedUsers;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const QString DOMAIN_HEARTBEAT_KEY = "heartbeat";
|
||||
const QString HEARTBEAT_NUM_USERS_KEY = "num_users";
|
||||
|
@ -1277,8 +1279,9 @@ void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiS
|
|||
parseNodeDataFromByteArray(packetStream, throwawayNodeType, nodePublicAddress, nodeLocalAddress,
|
||||
senderSockAddr);
|
||||
|
||||
SharedNodePointer checkInNode = nodeList->updateSocketsForNode(nodeUUID,
|
||||
nodePublicAddress, nodeLocalAddress);
|
||||
SharedNodePointer checkInNode = nodeList->nodeWithUUID(nodeUUID);
|
||||
checkInNode->setPublicSocket(nodePublicAddress);
|
||||
checkInNode->setLocalSocket(nodeLocalAddress);
|
||||
|
||||
// update last receive to now
|
||||
quint64 timeNow = usecTimestampNow();
|
||||
|
@ -1470,15 +1473,15 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
QJsonObject assignedNodesJSON;
|
||||
|
||||
// enumerate the NodeList to find the assigned nodes
|
||||
foreach (const SharedNodePointer& node, LimitedNodeList::getInstance()->getNodeHash()) {
|
||||
NodeList::getInstance()->eachNode([this, &assignedNodesJSON](const SharedNodePointer& node){
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||
|
||||
|
||||
if (!nodeData->getAssignmentUUID().isNull()) {
|
||||
// add the node using the UUID as the key
|
||||
QString uuidString = uuidStringWithoutCurlyBraces(nodeData->getAssignmentUUID());
|
||||
assignedNodesJSON[uuidString] = jsonObjectForNode(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
assignmentJSON["fulfilled"] = assignedNodesJSON;
|
||||
|
||||
|
@ -1532,12 +1535,10 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
QJsonArray nodesJSONArray;
|
||||
|
||||
// enumerate the NodeList to find the assigned nodes
|
||||
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
LimitedNodeList::getInstance()->eachNode([this, &nodesJSONArray](const SharedNodePointer& node){
|
||||
// add the node using the UUID as the key
|
||||
nodesJSONArray.append(jsonObjectForNode(node));
|
||||
}
|
||||
});
|
||||
|
||||
rootJSON["nodes"] = nodesJSONArray;
|
||||
|
||||
|
@ -2065,16 +2066,9 @@ void DomainServer::addStaticAssignmentsToQueue() {
|
|||
QHash<QUuid, SharedAssignmentPointer>::iterator staticAssignment = staticHashCopy.begin();
|
||||
while (staticAssignment != staticHashCopy.end()) {
|
||||
// add any of the un-matched static assignments to the queue
|
||||
bool foundMatchingAssignment = false;
|
||||
|
||||
|
||||
// enumerate the nodes and check if there is one with an attached assignment with matching UUID
|
||||
foreach (const SharedNodePointer& node, LimitedNodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getUUID() == staticAssignment->data()->getUUID()) {
|
||||
foundMatchingAssignment = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundMatchingAssignment) {
|
||||
if (!NodeList::getInstance()->nodeWithUUID(staticAssignment->data()->getUUID())) {
|
||||
// this assignment has not been fulfilled - reset the UUID and add it to the assignment queue
|
||||
refreshStaticAssignmentAndAddToQueue(*staticAssignment);
|
||||
}
|
||||
|
|
|
@ -15,3 +15,4 @@ Script.load("hydraMove.js");
|
|||
Script.load("headMove.js");
|
||||
Script.load("inspect.js");
|
||||
Script.load("lobby.js");
|
||||
Script.load("notifications.js");
|
||||
|
|
|
@ -13,34 +13,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function(){
|
||||
this.oldColor = {};
|
||||
this.oldColorKnown = false;
|
||||
this.storeOldColor = function(entityID) {
|
||||
var oldProperties = Entities.getEntityProperties(entityID);
|
||||
this.oldColor = oldProperties.color;
|
||||
this.oldColorKnown = true;
|
||||
print("storing old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue);
|
||||
};
|
||||
|
||||
this.preload = function(entityID) {
|
||||
print("preload");
|
||||
this.storeOldColor(entityID);
|
||||
};
|
||||
|
||||
this.hoverEnterEntity = function(entityID, mouseEvent) {
|
||||
print("hoverEnterEntity");
|
||||
if (!this.oldColorKnown) {
|
||||
this.storeOldColor(entityID);
|
||||
}
|
||||
Entities.editEntity(entityID, { color: { red: 0, green: 255, blue: 255} });
|
||||
};
|
||||
this.hoverLeaveEntity = function(entityID, mouseEvent) {
|
||||
print("hoverLeaveEntity");
|
||||
if (this.oldColorKnown) {
|
||||
print("leave restoring old color... this.oldColor="
|
||||
+ this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue);
|
||||
Entities.editEntity(entityID, { color: this.oldColor });
|
||||
}
|
||||
};
|
||||
})
|
||||
(function() {
|
||||
Script.include("changeColorOnHoverClass.js");
|
||||
return new ChangeColorOnHover();
|
||||
})
|
||||
|
|
55
examples/entityScripts/changeColorOnHoverClass.js
Normal file
55
examples/entityScripts/changeColorOnHoverClass.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// changeColorOnHover.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 11/1/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example of an entity script which when assigned to a non-model entity like a box or sphere, will
|
||||
// change the color of the entity when you hover over it. This script uses the JavaScript prototype/class functionality
|
||||
// to construct an object that has methods for hoverEnterEntity and hoverLeaveEntity;
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
ChangeColorOnHover = function(){
|
||||
this.oldColor = {};
|
||||
this.oldColorKnown = false;
|
||||
};
|
||||
|
||||
ChangeColorOnHover.prototype = {
|
||||
|
||||
storeOldColor: function(entityID) {
|
||||
var oldProperties = Entities.getEntityProperties(entityID);
|
||||
this.oldColor = oldProperties.color;
|
||||
this.oldColorKnown = true;
|
||||
print("storing old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue);
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
print("preload");
|
||||
this.storeOldColor(entityID);
|
||||
},
|
||||
|
||||
hoverEnterEntity: function(entityID, mouseEvent) {
|
||||
print("hoverEnterEntity");
|
||||
if (!this.oldColorKnown) {
|
||||
this.storeOldColor(entityID);
|
||||
}
|
||||
Entities.editEntity(entityID, { color: { red: 0, green: 255, blue: 255} });
|
||||
},
|
||||
|
||||
|
||||
hoverLeaveEntity: function(entityID, mouseEvent) {
|
||||
print("hoverLeaveEntity");
|
||||
if (this.oldColorKnown) {
|
||||
print("leave restoring old color... this.oldColor="
|
||||
+ this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue);
|
||||
Entities.editEntity(entityID, { color: this.oldColor });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -27,10 +27,12 @@
|
|||
};
|
||||
|
||||
this.enterEntity = function(entityID) {
|
||||
print("enterEntity("+entityID.id+")");
|
||||
playSound();
|
||||
};
|
||||
|
||||
this.leaveEntity = function(entityID) {
|
||||
print("leaveEntity("+entityID.id+")");
|
||||
playSound();
|
||||
};
|
||||
})
|
||||
|
|
|
@ -5,19 +5,89 @@
|
|||
// Created by Clément Brisset on 7/18/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// If using Hydra controllers, pulling the triggers makes laser pointers emanate from the respective hands.
|
||||
// If using a Leap Motion or similar to control your avatar's hands and fingers, pointing with your index fingers makes
|
||||
// laser pointers emanate from the respective index fingers.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var LEFT = 0;
|
||||
var RIGHT = 1;
|
||||
var LEFT_HAND_FLAG = 1;
|
||||
var RIGHT_HAND_FLAG = 2;
|
||||
var laserPointer = (function () {
|
||||
|
||||
function update() {
|
||||
var state = ((Controller.getTriggerValue(LEFT) > 0.9) ? LEFT_HAND_FLAG : 0) +
|
||||
((Controller.getTriggerValue(RIGHT) > 0.9) ? RIGHT_HAND_FLAG : 0);
|
||||
MyAvatar.setHandState(state);
|
||||
}
|
||||
var NUM_FINGERs = 4, // Excluding thumb
|
||||
fingers = [
|
||||
[ "LeftHandIndex", "LeftHandMiddle", "LeftHandRing", "LeftHandPinky" ],
|
||||
[ "RightHandIndex", "RightHandMiddle", "RightHandRing", "RightHandPinky" ]
|
||||
];
|
||||
|
||||
Script.update.connect(update);
|
||||
function isHandPointing(hand) {
|
||||
var MINIMUM_TRIGGER_PULL = 0.9;
|
||||
return Controller.getTriggerValue(hand) > MINIMUM_TRIGGER_PULL;
|
||||
}
|
||||
|
||||
function isFingerPointing(hand) {
|
||||
// Index finger is pointing if final two bones of middle, ring, and pinky fingers are > 90 degrees w.r.t. index finger
|
||||
|
||||
var pointing,
|
||||
indexDirection,
|
||||
otherDirection,
|
||||
f;
|
||||
|
||||
pointing = true;
|
||||
|
||||
indexDirection = Vec3.subtract(
|
||||
MyAvatar.getJointPosition(fingers[hand][0] + "4"),
|
||||
MyAvatar.getJointPosition(fingers[hand][0] + "2")
|
||||
);
|
||||
|
||||
for (f = 1; f < NUM_FINGERs; f += 1) {
|
||||
otherDirection = Vec3.subtract(
|
||||
MyAvatar.getJointPosition(fingers[hand][f] + "4"),
|
||||
MyAvatar.getJointPosition(fingers[hand][f] + "2")
|
||||
);
|
||||
pointing = pointing && Vec3.dot(indexDirection, otherDirection) < 0;
|
||||
}
|
||||
|
||||
return pointing;
|
||||
}
|
||||
|
||||
function update() {
|
||||
var LEFT_HAND = 0,
|
||||
RIGHT_HAND = 1,
|
||||
LEFT_HAND_POINTING_FLAG = 1,
|
||||
RIGHT_HAND_POINTING_FLAG = 2,
|
||||
FINGER_POINTING_FLAG = 4,
|
||||
handState;
|
||||
|
||||
handState = 0;
|
||||
|
||||
if (isHandPointing(LEFT_HAND)) {
|
||||
handState += LEFT_HAND_POINTING_FLAG;
|
||||
}
|
||||
if (isHandPointing(RIGHT_HAND)) {
|
||||
handState += RIGHT_HAND_POINTING_FLAG;
|
||||
}
|
||||
|
||||
if (handState === 0) {
|
||||
if (isFingerPointing(LEFT_HAND)) {
|
||||
handState += LEFT_HAND_POINTING_FLAG;
|
||||
}
|
||||
if (isFingerPointing(RIGHT_HAND)) {
|
||||
handState += RIGHT_HAND_POINTING_FLAG;
|
||||
}
|
||||
if (handState !== 0) {
|
||||
handState += FINGER_POINTING_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
MyAvatar.setHandState(handState);
|
||||
}
|
||||
|
||||
return {
|
||||
update: update
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
Script.update.connect(laserPointer.update);
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
var SETTING_GRID_VISIBLE = 'gridVisible';
|
||||
var SETTING_GRID_SNAP_TO_GRID = 'gridSnapToGrid';
|
||||
var SETTING_GRID_MINOR_WIDTH= 'gridMinorWidth';
|
||||
var SETTING_GRID_MAJOR_EVERY = 'gridMajorEvery';
|
||||
var SETTING_GRID_COLOR = 'gridColor';
|
||||
|
||||
Grid = function(opts) {
|
||||
var that = {};
|
||||
|
||||
|
@ -18,6 +12,9 @@ Grid = function(opts) {
|
|||
|
||||
var worldSize = 16384;
|
||||
|
||||
var minorGridWidth = 0.5;
|
||||
var majorGridWidth = 1.5;
|
||||
|
||||
var snapToGrid = false;
|
||||
|
||||
var gridOverlay = Overlays.addOverlay("grid", {
|
||||
|
@ -26,7 +23,7 @@ Grid = function(opts) {
|
|||
color: { red: 0, green: 0, blue: 128 },
|
||||
alpha: 1.0,
|
||||
rotation: Quat.fromPitchYawRollDegrees(90, 0, 0),
|
||||
minorGridSpacing: 0.1,
|
||||
minorGridWidth: 0.1,
|
||||
majorGridEvery: 2,
|
||||
});
|
||||
|
||||
|
@ -43,37 +40,16 @@ Grid = function(opts) {
|
|||
that.getSnapToGrid = function() { return snapToGrid; };
|
||||
|
||||
that.setEnabled = function(enabled) {
|
||||
if (that.enabled != enabled) {
|
||||
that.enabled = enabled;
|
||||
|
||||
if (enabled) {
|
||||
if (selectionManager.hasSelection()) {
|
||||
that.setPosition(selectionManager.getBottomPosition());
|
||||
} else {
|
||||
that.setPosition(MyAvatar.position);
|
||||
}
|
||||
}
|
||||
|
||||
updateGrid();
|
||||
}
|
||||
that.enabled = enabled;
|
||||
updateGrid();
|
||||
}
|
||||
|
||||
that.setVisible = function(visible, noUpdate) {
|
||||
if (visible != that.visible) {
|
||||
that.visible = visible;
|
||||
updateGrid();
|
||||
that.visible = visible;
|
||||
updateGrid();
|
||||
|
||||
if (visible) {
|
||||
if (selectionManager.hasSelection()) {
|
||||
that.setPosition(selectionManager.getBottomPosition());
|
||||
} else {
|
||||
that.setPosition(MyAvatar.position);
|
||||
}
|
||||
}
|
||||
|
||||
if (!noUpdate) {
|
||||
that.emitUpdate();
|
||||
}
|
||||
if (!noUpdate) {
|
||||
that.emitUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,43 +181,15 @@ Grid = function(opts) {
|
|||
}
|
||||
|
||||
function cleanup() {
|
||||
saveSettings();
|
||||
|
||||
Overlays.deleteOverlay(gridOverlay);
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
that.setVisible(Settings.getValue(SETTING_GRID_VISIBLE) == "true", true);
|
||||
snapToGrid = Settings.getValue(SETTING_GRID_SNAP_TO_GRID) == "true";
|
||||
minorGridSpacing = parseFloat(Settings.getValue(SETTING_GRID_MINOR_WIDTH), 10);
|
||||
majorGridEvery = parseInt(Settings.getValue(SETTING_GRID_MAJOR_EVERY), 10);
|
||||
try {
|
||||
var newColor = JSON.parse(Settings.getValue(SETTING_GRID_COLOR));
|
||||
if (newColor.red !== undefined && newColor.green !== undefined && newColor.blue !== undefined) {
|
||||
gridColor.red = newColor.red;
|
||||
gridColor.green = newColor.green;
|
||||
gridColor.blue = newColor.blue;
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
updateGrid();
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
Settings.setValue(SETTING_GRID_VISIBLE, that.visible);
|
||||
Settings.setValue(SETTING_GRID_SNAP_TO_GRID, snapToGrid);
|
||||
Settings.setValue(SETTING_GRID_MINOR_WIDTH, minorGridSpacing);
|
||||
Settings.setValue(SETTING_GRID_MAJOR_EVERY, majorGridEvery);
|
||||
Settings.setValue(SETTING_GRID_COLOR, JSON.stringify(gridColor));
|
||||
}
|
||||
|
||||
that.addListener = function(callback) {
|
||||
that.onUpdate = callback;
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
||||
loadSettings();
|
||||
updateGrid();
|
||||
|
||||
that.onUpdate = null;
|
||||
|
||||
|
|
|
@ -274,19 +274,11 @@ modelUploader = (function () {
|
|||
}
|
||||
}
|
||||
|
||||
if (view.string(0, 18) === "Kaydara FBX Binary") {
|
||||
previousNodeFilename = "";
|
||||
|
||||
index = 27;
|
||||
while (index < view.byteLength - 39 && !EOF) {
|
||||
parseBinaryFBX();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
readTextFBX();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function readModel() {
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
//
|
||||
// notifications.js
|
||||
// notifications.js
|
||||
// Version 0.801
|
||||
// Created by Adrian
|
||||
//
|
||||
// Adrian McCarlie 8-10-14
|
||||
// This script demonstrates on-screen overlay type notifications.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
// This script demonstrates notifications created via a number of ways, such as:
|
||||
// Simple key press alerts, which only depend on a key being pressed,
|
||||
// dummy examples of this are "q", "w", "e", "r", and "SPACEBAR".
|
||||
// actual working examples are "a" for left turn, "d" for right turn and Ctrl/s for snapshot.
|
||||
|
||||
// System generated alerts such as users joining and leaving and chat messages which mention this user.
|
||||
// System generated alerts which originate with a user interface event such as Window Resize, and Mic Mute/Unmute.
|
||||
// Mic Mute/Unmute may appear to be a key press alert, but it actually gets the call from the system as mic is muted and unmuted,
|
||||
// so the mic mute/unmute will also trigger the notification by clicking the Mic Mute button at the top of the screen.
|
||||
// This script generates notifications created via a number of ways, such as:
|
||||
// keystroke:
|
||||
//
|
||||
// "q" returns number of users currently online (for debug purposes)
|
||||
|
||||
// CTRL/s for snapshot.
|
||||
// CTRL/m for mic mute and unmute.
|
||||
|
||||
// System generated notifications:
|
||||
// Displays users online at startup.
|
||||
// If Screen is resized.
|
||||
// Triggers notification if @MyUserName is mentioned in chat.
|
||||
// Announces existing user logging out.
|
||||
// Announces new user logging in.
|
||||
// If mic is muted for any reason.
|
||||
//
|
||||
// To add a new System notification type:
|
||||
//
|
||||
// 1. Set the Event Connector at the bottom of the script.
|
||||
|
@ -45,22 +52,23 @@
|
|||
// 2. Declare a text string.
|
||||
// 3. Call createNotifications(text) parsing the text.
|
||||
// example:
|
||||
// if (key.text == "a") {
|
||||
// var noteString = "Turning to the Left";
|
||||
// createNotification(noteString);
|
||||
// }
|
||||
// if (key.text == "q") { //queries number of users online
|
||||
// var numUsers = GlobalServices.onlineUsers.length;
|
||||
// var welcome = "There are " + numUsers + " users online now.";
|
||||
// createNotification(welcome);
|
||||
// }
|
||||
|
||||
|
||||
var width = 340.0; //width of notification overlay
|
||||
var height = 40.0; // height of a single line notification overlay
|
||||
var windowDimensions = Controller.getViewportDimensions(); // get the size of the interface window
|
||||
var overlayLocationX = (windowDimensions.x - (width + 60.0));// positions window 60px from the right of the interface window
|
||||
var overlayLocationX = (windowDimensions.x - (width + 20.0));// positions window 20px from the right of the interface window
|
||||
var buttonLocationX = overlayLocationX + (width - 28.0);
|
||||
var locationY = 20.0; // position down from top of interface window
|
||||
var topMargin = 13.0;
|
||||
var leftMargin = 10.0;
|
||||
var textColor = { red: 228, green: 228, blue: 228}; // text color
|
||||
var backColor = { red: 38, green: 38, blue: 38}; // background color
|
||||
var backColor = { red: 2, green: 2, blue: 2}; // background color was 38,38,38
|
||||
var backgroundAlpha = 0;
|
||||
var fontSize = 12.0;
|
||||
var persistTime = 10.0; // time in seconds before notification fades
|
||||
|
@ -115,7 +123,6 @@ function createNotification(text) {
|
|||
color: textColor,
|
||||
backgroundColor: backColor,
|
||||
alpha: backgroundAlpha,
|
||||
backgroundAlpha: backgroundAlpha,
|
||||
topMargin: topMargin,
|
||||
leftMargin: leftMargin,
|
||||
font: {size: fontSize},
|
||||
|
@ -125,8 +132,8 @@ function createNotification(text) {
|
|||
var buttonProperties = {
|
||||
x: buttonLocationX,
|
||||
y: bLevel,
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
subImage: { x: 0, y: 0, width: 10, height: 10 },
|
||||
imageURL: "http://hifi-public.s3.amazonaws.com/images/close-small-light.svg",
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
|
@ -161,7 +168,7 @@ function fadeIn(noticeIn, buttonIn) {
|
|||
pauseTimer = Script.setInterval(function() {
|
||||
q++;
|
||||
qFade = q / 10.0;
|
||||
Overlays.editOverlay(noticeIn, {alpha: qFade, backgroundAlpha: qFade});
|
||||
Overlays.editOverlay(noticeIn, {alpha: qFade});
|
||||
Overlays.editOverlay(buttonIn, {alpha: qFade});
|
||||
if (q >= 9.0) {
|
||||
Script.clearInterval(pauseTimer);
|
||||
|
@ -203,41 +210,18 @@ function keyPressEvent(key) {
|
|||
if (key.key == 16777249) {
|
||||
ctrlIsPressed = true;
|
||||
}
|
||||
if (key.text == "a") {
|
||||
var noteString = "Turning to the Left";
|
||||
createNotification(noteString);
|
||||
}
|
||||
if (key.text == "d") {
|
||||
var noteString = "Turning to the Right";
|
||||
createNotification(noteString);
|
||||
}
|
||||
if (key.text == "q") { //queries number of users online
|
||||
var numUsers = GlobalServices.onlineUsers.length;
|
||||
var welcome = "There are " + numUsers + " users online now.";
|
||||
createNotification(welcome);
|
||||
}
|
||||
|
||||
if (key.text == "s") {
|
||||
if (ctrlIsPressed == true){
|
||||
var noteString = "You have taken a snapshot";
|
||||
var noteString = "Snapshot taken.";
|
||||
createNotification(noteString);
|
||||
}
|
||||
}
|
||||
if (key.text == "q") {
|
||||
var noteString = "Enable Scripted Motor control is now on.";
|
||||
wordWrap(noteString);
|
||||
}
|
||||
if (key.text == "w") {
|
||||
var noteString = "This notification spans 2 lines. The overlay will resize to fit new lines.";
|
||||
var noteString = "editVoxels.js stopped, editModels.js stopped, selectAudioDevice.js stopped.";
|
||||
wordWrap(noteString);
|
||||
}
|
||||
if (key.text == "e") {
|
||||
var noteString = "This is an example of a multiple line notification. This notification will span 3 lines."
|
||||
wordWrap(noteString);
|
||||
}
|
||||
if (key.text == "r") {
|
||||
var noteString = "This is a very long line of text that we are going to use in this example to divide it into rows of maximum 43 chars and see how many lines we use.";
|
||||
wordWrap(noteString);
|
||||
}
|
||||
if (key.text == "SPACE") {
|
||||
var noteString = "You have pressed the Spacebar, This is an example of a multiple line notification. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam.";
|
||||
wordWrap(noteString);
|
||||
}
|
||||
}
|
||||
|
||||
// formats string to add newline every 43 chars
|
||||
|
@ -275,18 +259,14 @@ function checkSize(){
|
|||
|
||||
// Triggers notification if a user logs on or off
|
||||
function onOnlineUsersChanged(users) {
|
||||
var joiners = [];
|
||||
var leavers = [];
|
||||
for (user in users) {
|
||||
if (last_users.indexOf(users[user]) == -1.0) {
|
||||
joiners.push(users[user]);
|
||||
createNotification(users[user] + " Has joined");
|
||||
if (last_users.indexOf(users[user]) == -1.0) {
|
||||
createNotification(users[user] + " has joined");
|
||||
}
|
||||
}
|
||||
for (user in last_users) {
|
||||
if (users.indexOf(last_users[user]) == -1.0) {
|
||||
leavers.push(last_users[user]);
|
||||
createNotification(last_users[user] + " Has left");
|
||||
createNotification(last_users[user] + " has left");
|
||||
}
|
||||
}
|
||||
last_users = users;
|
||||
|
@ -303,8 +283,8 @@ function onIncomingMessage(user, message) {
|
|||
}
|
||||
// Triggers mic mute notification
|
||||
function onMuteStateChanged() {
|
||||
var muteState = AudioDevice.getMuted() ? "Muted" : "Unmuted";
|
||||
var muteString = "Microphone is set to " + muteState;
|
||||
var muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
||||
var muteString = "Microphone is now " + muteState;
|
||||
createNotification(muteString);
|
||||
}
|
||||
|
||||
|
@ -345,7 +325,7 @@ function fadeOut(noticeOut, buttonOut, arraysOut) {
|
|||
pauseTimer = Script.setInterval(function() {
|
||||
r--;
|
||||
rFade = r / 10.0;
|
||||
Overlays.editOverlay(noticeOut, {alpha: rFade, backgroundAlpha: rFade});
|
||||
Overlays.editOverlay(noticeOut, {alpha: rFade});
|
||||
Overlays.editOverlay(buttonOut, {alpha: rFade});
|
||||
if (r < 0) {
|
||||
dismiss(noticeOut, buttonOut, arraysOut);
|
||||
|
@ -368,10 +348,17 @@ function dismiss(firstNoteOut, firstButOut, firstOut) {
|
|||
myAlpha.splice(firstOut,1);
|
||||
}
|
||||
|
||||
onMuteStateChanged();
|
||||
// This is meant to show users online at startup but currently shows 0 users.
|
||||
function onConnected() {
|
||||
var numUsers = GlobalServices.onlineUsers.length;
|
||||
var welcome = "Welcome! There are " + numUsers + " users online now.";
|
||||
createNotification(welcome);
|
||||
}
|
||||
|
||||
AudioDevice.muteToggled.connect(onMuteStateChanged);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
GlobalServices.connected.connect(onConnected);
|
||||
GlobalServices.onlineUsersChanged.connect(onOnlineUsersChanged);
|
||||
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
|
|
|
@ -6,4 +6,4 @@ setup_hifi_project(Network)
|
|||
# link the shared hifi libraries
|
||||
link_hifi_libraries(networking shared)
|
||||
|
||||
link_shared_dependencies()
|
||||
include_dependency_includes()
|
|
@ -2,7 +2,7 @@ set(TARGET_NAME interface)
|
|||
project(${TARGET_NAME})
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb")
|
||||
set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb")
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
|
||||
|
@ -25,15 +25,15 @@ else ()
|
|||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
set(GL_HEADERS "#include <GLUT/glut.h>\n#include <OpenGL/glext.h>")
|
||||
set(GL_HEADERS "#include <OpenGL/glext.h>")
|
||||
elseif (UNIX)
|
||||
# include the right GL headers for UNIX
|
||||
set(GL_HEADERS "#include <GL/gl.h>\n#include <GL/glut.h>\n#include <GL/glext.h>")
|
||||
set(GL_HEADERS "#include <GL/gl.h>\n#include <GL/glext.h>")
|
||||
elseif (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
|
||||
|
||||
set(GL_HEADERS "#include <windowshacks.h>\n#include <GL/glew.h>\n#include <GL/glut.h>\n#include <GL/wglew.h>")
|
||||
set(GL_HEADERS "#include <windowshacks.h>\n#include <GL/glew.h>\n#include <GL/wglew.h>")
|
||||
endif ()
|
||||
|
||||
# set up the external glm library
|
||||
|
@ -107,7 +107,7 @@ endif()
|
|||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_libraries(shared octree voxels gpu fbx metavoxels networking entities avatars audio animation script-engine physics
|
||||
link_hifi_libraries(shared octree voxels gpu model fbx metavoxels networking entities avatars audio animation script-engine physics
|
||||
render-utils entities-renderer)
|
||||
|
||||
# find any optional and required libraries
|
||||
|
@ -157,7 +157,6 @@ if (VISAGE_FOUND AND NOT DISABLE_VISAGE AND APPLE)
|
|||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment")
|
||||
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 ()
|
||||
|
||||
|
@ -195,11 +194,10 @@ if (APPLE)
|
|||
# link in required OS X frameworks and include the right GL headers
|
||||
find_library(CoreAudio CoreAudio)
|
||||
find_library(CoreFoundation CoreFoundation)
|
||||
find_library(GLUT GLUT)
|
||||
find_library(OpenGL OpenGL)
|
||||
find_library(AppKit AppKit)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${CoreAudio} ${CoreFoundation} ${GLUT} ${OpenGL} ${AppKit})
|
||||
target_link_libraries(${TARGET_NAME} ${CoreAudio} ${CoreFoundation} ${OpenGL} ${AppKit})
|
||||
|
||||
# install command for OS X bundle
|
||||
INSTALL(TARGETS ${TARGET_NAME}
|
||||
|
@ -215,15 +213,12 @@ else (APPLE)
|
|||
)
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GLUT REQUIRED)
|
||||
|
||||
include_directories(SYSTEM "${GLUT_INCLUDE_DIRS}")
|
||||
|
||||
if (${OPENGL_INCLUDE_DIR})
|
||||
include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}" "${GLUT_LIBRARIES}")
|
||||
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
|
||||
|
||||
# link target to external libraries
|
||||
if (WIN32)
|
||||
|
@ -233,7 +228,7 @@ else (APPLE)
|
|||
# we're using static GLEW, so define GLEW_STATIC
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" "${NSIGHT_LIBRARIES}" wsock32.lib opengl32.lib)
|
||||
target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" "${NSIGHT_LIBRARIES}" wsock32.lib opengl32.lib Winmm.lib)
|
||||
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
find_package(NSIGHT)
|
||||
|
@ -247,4 +242,4 @@ else (APPLE)
|
|||
endif (APPLE)
|
||||
|
||||
# link any dependencies bubbled up from our linked dependencies
|
||||
link_shared_dependencies()
|
||||
include_dependency_includes()
|
||||
|
|
|
@ -132,7 +132,7 @@ static QTimer* idleTimer = NULL;
|
|||
const QString CHECK_VERSION_URL = "https://highfidelity.io/latestVersion.xml";
|
||||
const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";
|
||||
|
||||
const QString DEFAULT_SCRIPTS_JS_URL = "http://public.highfidelity.io/scripts/defaultScripts.js";
|
||||
const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js";
|
||||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message);
|
||||
|
@ -309,15 +309,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
AddressManager::SharedPointer addressManager = DependencyManager::get<AddressManager>();
|
||||
|
||||
// use our MyAvatar position and quat for address manager path
|
||||
addressManager->setPositionGetter(getPositionForPath);
|
||||
addressManager->setOrientationGetter(getOrientationForPath);
|
||||
|
||||
// handle domain change signals from AddressManager
|
||||
connect(addressManager.data(), &AddressManager::possibleDomainChangeRequiredToHostname,
|
||||
this, &Application::changeDomainHostname);
|
||||
|
||||
connect(addressManager.data(), &AddressManager::possibleDomainChangeRequiredViaICEForID,
|
||||
&domainHandler, &DomainHandler::setIceServerHostnameAndID);
|
||||
addressManager.setPositionGetter(getPositionForPath);
|
||||
addressManager.setOrientationGetter(getOrientationForPath);
|
||||
|
||||
_settings = new QSettings(this);
|
||||
_numChangedSettings = 0;
|
||||
|
@ -541,8 +534,6 @@ void Application::initializeGL() {
|
|||
} else {
|
||||
isInitialized = true;
|
||||
}
|
||||
int argc = 0;
|
||||
glutInit(&argc, 0);
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
@ -1439,7 +1430,7 @@ void Application::dropEvent(QDropEvent *event) {
|
|||
SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath);
|
||||
if (snapshotData) {
|
||||
if (!snapshotData->getDomain().isEmpty()) {
|
||||
changeDomainHostname(snapshotData->getDomain());
|
||||
NodeList::getInstance()->getDomainHandler().setHostnameAndPort(snapshotData->getDomain());
|
||||
}
|
||||
|
||||
_myAvatar->setPosition(snapshotData->getLocation());
|
||||
|
@ -2454,72 +2445,73 @@ int Application::sendNackPackets() {
|
|||
char packet[MAX_PACKET_SIZE];
|
||||
|
||||
// iterates thru all nodes in NodeList
|
||||
foreach(const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
|
||||
if (node->getActiveSocket() &&
|
||||
( node->getType() == NodeType::VoxelServer
|
||||
|| node->getType() == NodeType::EntityServer)
|
||||
) {
|
||||
|
||||
if (node->getActiveSocket()
|
||||
&& (node->getType() == NodeType::VoxelServer || node->getType() == NodeType::EntityServer)) {
|
||||
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
|
||||
|
||||
// if there are octree packets from this node that are waiting to be processed,
|
||||
// don't send a NACK since the missing packets may be among those waiting packets.
|
||||
if (_octreeProcessor.hasPacketsToProcessFrom(nodeUUID)) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
_octreeSceneStatsLock.lockForRead();
|
||||
|
||||
|
||||
// retreive octree scene stats of this node
|
||||
if (_octreeServerSceneStats.find(nodeUUID) == _octreeServerSceneStats.end()) {
|
||||
_octreeSceneStatsLock.unlock();
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// get sequence number stats of node, prune its missing set, and make a copy of the missing set
|
||||
SequenceNumberStats& sequenceNumberStats = _octreeServerSceneStats[nodeUUID].getIncomingOctreeSequenceNumberStats();
|
||||
sequenceNumberStats.pruneMissingSet();
|
||||
const QSet<OCTREE_PACKET_SEQUENCE> missingSequenceNumbers = sequenceNumberStats.getMissingSet();
|
||||
|
||||
|
||||
_octreeSceneStatsLock.unlock();
|
||||
|
||||
|
||||
// construct nack packet(s) for this node
|
||||
int numSequenceNumbersAvailable = missingSequenceNumbers.size();
|
||||
QSet<OCTREE_PACKET_SEQUENCE>::const_iterator missingSequenceNumbersIterator = missingSequenceNumbers.constBegin();
|
||||
while (numSequenceNumbersAvailable > 0) {
|
||||
|
||||
|
||||
char* dataAt = packet;
|
||||
int bytesRemaining = MAX_PACKET_SIZE;
|
||||
|
||||
|
||||
// pack header
|
||||
int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack);
|
||||
dataAt += numBytesPacketHeader;
|
||||
bytesRemaining -= numBytesPacketHeader;
|
||||
|
||||
|
||||
// calculate and pack the number of sequence numbers
|
||||
int numSequenceNumbersRoomFor = (bytesRemaining - sizeof(uint16_t)) / sizeof(OCTREE_PACKET_SEQUENCE);
|
||||
uint16_t numSequenceNumbers = min(numSequenceNumbersAvailable, numSequenceNumbersRoomFor);
|
||||
uint16_t* numSequenceNumbersAt = (uint16_t*)dataAt;
|
||||
*numSequenceNumbersAt = numSequenceNumbers;
|
||||
dataAt += sizeof(uint16_t);
|
||||
|
||||
|
||||
// pack sequence numbers
|
||||
for (int i = 0; i < numSequenceNumbers; i++) {
|
||||
OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt;
|
||||
*sequenceNumberAt = *missingSequenceNumbersIterator;
|
||||
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
|
||||
|
||||
|
||||
missingSequenceNumbersIterator++;
|
||||
}
|
||||
numSequenceNumbersAvailable -= numSequenceNumbers;
|
||||
|
||||
|
||||
// send it
|
||||
NodeList::getInstance()->writeUnverifiedDatagram(packet, dataAt - packet, node);
|
||||
nodeList->writeUnverifiedDatagram(packet, dataAt - packet, node);
|
||||
packetsSent++;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return packetsSent;
|
||||
}
|
||||
|
||||
|
@ -2552,7 +2544,9 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
int inViewServers = 0;
|
||||
int unknownJurisdictionServers = 0;
|
||||
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
// only send to the NodeTypes that are serverType
|
||||
if (node->getActiveSocket() && node->getType() == serverType) {
|
||||
totalServers++;
|
||||
|
@ -2583,7 +2577,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (wantExtraDebugging) {
|
||||
qDebug("Servers: total %d, in view %d, unknown jurisdiction %d",
|
||||
|
@ -2609,20 +2603,18 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
if (wantExtraDebugging) {
|
||||
qDebug("perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer);
|
||||
}
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
// only send to the NodeTypes that are serverType
|
||||
if (node->getActiveSocket() && node->getType() == serverType) {
|
||||
|
||||
|
||||
|
||||
|
||||
// get the server bounds for this server
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
|
||||
|
||||
bool inView = false;
|
||||
bool unknownView = false;
|
||||
|
||||
|
||||
// if we haven't heard from this voxel server, go ahead and send it a query, so we
|
||||
// can get the jurisdiction...
|
||||
if (jurisdictions.find(nodeUUID) == jurisdictions.end()) {
|
||||
|
@ -2632,15 +2624,15 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
}
|
||||
} else {
|
||||
const JurisdictionMap& map = (jurisdictions)[nodeUUID];
|
||||
|
||||
|
||||
unsigned char* rootCode = map.getRootOctalCode();
|
||||
|
||||
|
||||
if (rootCode) {
|
||||
VoxelPositionSize rootDetails;
|
||||
voxelDetailsForCode(rootCode, rootDetails);
|
||||
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
|
||||
serverBounds.scale(TREE_SCALE);
|
||||
|
||||
|
||||
ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds);
|
||||
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
|
||||
inView = true;
|
||||
|
@ -2653,15 +2645,15 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (inView) {
|
||||
_octreeQuery.setMaxOctreePacketsPerSecond(perServerPPS);
|
||||
} else if (unknownView) {
|
||||
if (wantExtraDebugging) {
|
||||
qDebug() << "no known jurisdiction for node " << *node << ", give it budget of "
|
||||
<< perUnknownServer << " to send us jurisdiction.";
|
||||
<< perUnknownServer << " to send us jurisdiction.";
|
||||
}
|
||||
|
||||
|
||||
// set the query's position/orientation to be degenerate in a manner that will get the scene quickly
|
||||
// If there's only one server, then don't do this, and just let the normal voxel query pass through
|
||||
// as expected... this way, we will actually get a valid scene if there is one to be seen
|
||||
|
@ -2685,22 +2677,22 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
}
|
||||
// set up the packet for sending...
|
||||
unsigned char* endOfQueryPacket = queryPacket;
|
||||
|
||||
|
||||
// insert packet type/version and node UUID
|
||||
endOfQueryPacket += populatePacketHeader(reinterpret_cast<char*>(endOfQueryPacket), packetType);
|
||||
|
||||
|
||||
// encode the query data...
|
||||
endOfQueryPacket += _octreeQuery.getBroadcastData(endOfQueryPacket);
|
||||
|
||||
|
||||
int packetLength = endOfQueryPacket - queryPacket;
|
||||
|
||||
|
||||
// make sure we still have an active socket
|
||||
nodeList->writeUnverifiedDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
|
||||
|
||||
|
||||
// Feed number of bytes to corresponding channel of the bandwidth meter
|
||||
_bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool Application::isHMDMode() const {
|
||||
|
@ -3565,7 +3557,7 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) {
|
|||
glPushMatrix();
|
||||
glColor4f(1, 1, 0, 1);
|
||||
glTranslatef(position.x, position.y, position.z); // where we actually want it!
|
||||
glutWireSphere(keyholeRadius, 20, 20);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(keyholeRadius, 20, 20, false);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
@ -3624,16 +3616,6 @@ void Application::setMenuShortcutsEnabled(bool enabled) {
|
|||
setShortcutsEnabled(_window->menuBar(), enabled);
|
||||
}
|
||||
|
||||
void Application::uploadModel(ModelType modelType) {
|
||||
ModelUploader* uploader = new ModelUploader(modelType);
|
||||
QThread* thread = new QThread();
|
||||
thread->connect(uploader, SIGNAL(destroyed()), SLOT(quit()));
|
||||
thread->connect(thread, SIGNAL(finished()), SLOT(deleteLater()));
|
||||
uploader->connect(thread, SIGNAL(started()), SLOT(send()));
|
||||
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void Application::updateWindowTitle(){
|
||||
|
||||
QString buildVersion = " (build " + applicationVersion() + ")";
|
||||
|
@ -3689,19 +3671,6 @@ void Application::updateLocationInServer() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::changeDomainHostname(const QString &newDomainHostname) {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
if (!nodeList->getDomainHandler().isCurrentHostname(newDomainHostname)) {
|
||||
// tell the MyAvatar object to send a kill packet so that it dissapears from its old avatar mixer immediately
|
||||
_myAvatar->sendKillAvatar();
|
||||
|
||||
// call the domain hostname change as a queued connection on the nodelist
|
||||
QMetaObject::invokeMethod(&NodeList::getInstance()->getDomainHandler(), "setHostname",
|
||||
Q_ARG(const QString&, newDomainHostname));
|
||||
}
|
||||
}
|
||||
|
||||
void Application::clearDomainOctreeDetails() {
|
||||
qDebug() << "Clearing domain octree details...";
|
||||
// reset the environment so that we don't erroneously end up with multiple
|
||||
|
@ -4202,15 +4171,19 @@ void Application::toggleRunningScriptsWidget() {
|
|||
}
|
||||
|
||||
void Application::uploadHead() {
|
||||
uploadModel(HEAD_MODEL);
|
||||
ModelUploader::uploadHead();
|
||||
}
|
||||
|
||||
void Application::uploadSkeleton() {
|
||||
uploadModel(SKELETON_MODEL);
|
||||
ModelUploader::uploadSkeleton();
|
||||
}
|
||||
|
||||
void Application::uploadAttachment() {
|
||||
uploadModel(ATTACHMENT_MODEL);
|
||||
ModelUploader::uploadAttachment();
|
||||
}
|
||||
|
||||
void Application::uploadEntity() {
|
||||
ModelUploader::uploadEntity();
|
||||
}
|
||||
|
||||
void Application::openUrl(const QUrl& url) {
|
||||
|
|
|
@ -334,7 +334,6 @@ signals:
|
|||
void importDone();
|
||||
|
||||
public slots:
|
||||
void changeDomainHostname(const QString& newDomainHostname);
|
||||
void domainChanged(const QString& domainHostname);
|
||||
void updateWindowTitle();
|
||||
void updateLocationInServer();
|
||||
|
@ -374,6 +373,7 @@ public slots:
|
|||
void uploadHead();
|
||||
void uploadSkeleton();
|
||||
void uploadAttachment();
|
||||
void uploadEntity();
|
||||
|
||||
void openUrl(const QUrl& url);
|
||||
|
||||
|
@ -459,8 +459,6 @@ private:
|
|||
|
||||
void setMenuShortcutsEnabled(bool enabled);
|
||||
|
||||
void uploadModel(ModelType modelType);
|
||||
|
||||
static void attachNewHeadToNode(Node *newNode);
|
||||
static void* networkReceive(void* args); // network receive thread
|
||||
|
||||
|
|
|
@ -10,11 +10,14 @@
|
|||
//
|
||||
// Creates single flexible verlet-integrated strands that can be used for hair/fur/grass
|
||||
|
||||
#include "Hair.h"
|
||||
#include <gpu/GPUConfig.h>
|
||||
|
||||
#include "Util.h"
|
||||
#include "world.h"
|
||||
|
||||
#include "Hair.h"
|
||||
|
||||
|
||||
const float HAIR_DAMPING = 0.99f;
|
||||
const float CONSTRAINT_RELAXATION = 10.0f;
|
||||
const float HAIR_ACCELERATION_COUPLING = 0.045f;
|
||||
|
|
|
@ -185,10 +185,14 @@ Menu::Menu() :
|
|||
SLOT(toggleAddressBar()));
|
||||
|
||||
addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model");
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0, Application::getInstance(), SLOT(uploadHead()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadSkeleton, 0, Application::getInstance(), SLOT(uploadSkeleton()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0,
|
||||
Application::getInstance(), SLOT(uploadHead()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadSkeleton, 0,
|
||||
Application::getInstance(), SLOT(uploadSkeleton()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadAttachment, 0,
|
||||
Application::getInstance(), SLOT(uploadAttachment()));
|
||||
Application::getInstance(), SLOT(uploadAttachment()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadEntity, 0,
|
||||
Application::getInstance(), SLOT(uploadEntity()));
|
||||
addDisabledActionAndSeparator(fileMenu, "Settings");
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsImport, 0, this, SLOT(importSettings()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsExport, 0, this, SLOT(exportSettings()));
|
||||
|
|
|
@ -477,6 +477,7 @@ namespace MenuOption {
|
|||
const QString TransmitterDrive = "Transmitter Drive";
|
||||
const QString TurnWithHead = "Turn using Head";
|
||||
const QString UploadAttachment = "Upload Attachment Model";
|
||||
const QString UploadEntity = "Upload Entity Model";
|
||||
const QString UploadHead = "Upload Head Model";
|
||||
const QString UploadSkeleton = "Upload Skeleton Model";
|
||||
const QString UserInterface = "User Interface";
|
||||
|
|
|
@ -496,7 +496,7 @@ void MetavoxelSystem::render() {
|
|||
}
|
||||
|
||||
void MetavoxelSystem::refreshVoxelData() {
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
NodeList::getInstance()->eachNode([](const SharedNodePointer& node){
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
|
||||
|
@ -504,7 +504,7 @@ void MetavoxelSystem::refreshVoxelData() {
|
|||
QMetaObject::invokeMethod(client, "refreshVoxelData");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class RayVoxelIntersectionVisitor : public RayIntersectionVisitor {
|
||||
|
@ -819,7 +819,7 @@ MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) {
|
|||
}
|
||||
|
||||
void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor, bool render) {
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
NodeList::getInstance()->eachNode([&visitor, &render](const SharedNodePointer& node){
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
|
||||
|
@ -833,7 +833,7 @@ void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor, bool render) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void MetavoxelSystem::loadSplatProgram(const char* type, ProgramObject& program, SplatLocations& locations) {
|
||||
|
|
|
@ -55,7 +55,8 @@ static const QString MODEL_URL = "/api/v1/models";
|
|||
|
||||
static const QString SETTING_NAME = "LastModelUploadLocation";
|
||||
|
||||
static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB
|
||||
static const int BYTES_PER_MEGABYTES = 1024 * 1024;
|
||||
static const unsigned long MAX_SIZE = 50 * 1024 * BYTES_PER_MEGABYTES; // 50 GB (Virtually remove limit)
|
||||
static const int MAX_TEXTURE_SIZE = 1024;
|
||||
static const int TIMEOUT = 1000;
|
||||
static const int MAX_CHECK = 30;
|
||||
|
@ -63,6 +64,32 @@ static const int MAX_CHECK = 30;
|
|||
static const int QCOMPRESS_HEADER_POSITION = 0;
|
||||
static const int QCOMPRESS_HEADER_SIZE = 4;
|
||||
|
||||
void ModelUploader::uploadModel(ModelType modelType) {
|
||||
ModelUploader* uploader = new ModelUploader(modelType);
|
||||
QThread* thread = new QThread();
|
||||
thread->connect(uploader, SIGNAL(destroyed()), SLOT(quit()));
|
||||
thread->connect(thread, SIGNAL(finished()), SLOT(deleteLater()));
|
||||
uploader->connect(thread, SIGNAL(started()), SLOT(send()));
|
||||
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void ModelUploader::uploadHead() {
|
||||
uploadModel(HEAD_MODEL);
|
||||
}
|
||||
|
||||
void ModelUploader::uploadSkeleton() {
|
||||
uploadModel(SKELETON_MODEL);
|
||||
}
|
||||
|
||||
void ModelUploader::uploadAttachment() {
|
||||
uploadModel(ATTACHMENT_MODEL);
|
||||
}
|
||||
|
||||
void ModelUploader::uploadEntity() {
|
||||
uploadModel(ENTITY_MODEL);
|
||||
}
|
||||
|
||||
ModelUploader::ModelUploader(ModelType modelType) :
|
||||
_lodCount(-1),
|
||||
_texturesCount(-1),
|
||||
|
@ -148,6 +175,91 @@ bool ModelUploader::zip() {
|
|||
FBXGeometry geometry = readFBX(fbxContents, QVariantHash());
|
||||
|
||||
// make sure we have some basic mappings
|
||||
populateBasicMapping(mapping, filename, geometry);
|
||||
|
||||
// open the dialog to configure the rest
|
||||
ModelPropertiesDialog properties(_modelType, mapping, basePath, geometry);
|
||||
if (properties.exec() == QDialog::Rejected) {
|
||||
return false;
|
||||
}
|
||||
mapping = properties.getMapping();
|
||||
|
||||
QByteArray nameField = mapping.value(NAME_FIELD).toByteArray();
|
||||
QString urlBase;
|
||||
if (!nameField.isEmpty()) {
|
||||
QHttpPart textPart;
|
||||
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"model_name\"");
|
||||
textPart.setBody(nameField);
|
||||
_dataMultiPart->append(textPart);
|
||||
urlBase = S3_URL + "/models/" + MODEL_TYPE_NAMES[_modelType] + "/" + nameField;
|
||||
_url = urlBase + ".fst";
|
||||
|
||||
} else {
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::zip()"),
|
||||
QString("Model name is missing in the .fst file."),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("Model name is missing in the .fst file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray texdirField = mapping.value(TEXDIR_FIELD).toByteArray();
|
||||
QString texDir;
|
||||
_textureBase = urlBase + "/textures/";
|
||||
if (!texdirField.isEmpty()) {
|
||||
texDir = basePath + "/" + texdirField;
|
||||
QFileInfo texInfo(texDir);
|
||||
if (!texInfo.exists() || !texInfo.isDir()) {
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::zip()"),
|
||||
QString("Texture directory could not be found."),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("Texture directory could not be found.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QVariantHash lodField = mapping.value(LOD_FIELD).toHash();
|
||||
for (QVariantHash::const_iterator it = lodField.constBegin(); it != lodField.constEnd(); it++) {
|
||||
QFileInfo lod(basePath + "/" + it.key());
|
||||
if (!lod.exists() || !lod.isFile()) { // Check existence
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::zip()"),
|
||||
QString("LOD file %1 could not be found.").arg(lod.fileName()),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("FBX file %1 could not be found.").arg(lod.fileName());
|
||||
}
|
||||
// Compress and copy
|
||||
if (!addPart(lod.filePath(), QString("lod%1").arg(++_lodCount))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Write out, compress and copy the fst
|
||||
if (!addPart(*fst, writeMapping(mapping), QString("fst"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compress and copy the fbx
|
||||
if (!addPart(fbx, fbxContents, "fbx")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addTextures(texDir, geometry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QHttpPart textPart;
|
||||
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;"
|
||||
" name=\"model_category\"");
|
||||
textPart.setBody(MODEL_TYPE_NAMES[_modelType]);
|
||||
_dataMultiPart->append(textPart);
|
||||
|
||||
_readyToSend = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModelUploader::populateBasicMapping(QVariantHash& mapping, QString filename, FBXGeometry geometry) {
|
||||
if (!mapping.contains(NAME_FIELD)) {
|
||||
mapping.insert(NAME_FIELD, QFileInfo(filename).baseName());
|
||||
}
|
||||
|
@ -162,11 +274,11 @@ bool ModelUploader::zip() {
|
|||
QVariantHash joints = mapping.value(JOINT_FIELD).toHash();
|
||||
if (!joints.contains("jointEyeLeft")) {
|
||||
joints.insert("jointEyeLeft", geometry.jointIndices.contains("jointEyeLeft") ? "jointEyeLeft" :
|
||||
(geometry.jointIndices.contains("EyeLeft") ? "EyeLeft" : "LeftEye"));
|
||||
(geometry.jointIndices.contains("EyeLeft") ? "EyeLeft" : "LeftEye"));
|
||||
}
|
||||
if (!joints.contains("jointEyeRight")) {
|
||||
joints.insert("jointEyeRight", geometry.jointIndices.contains("jointEyeRight") ? "jointEyeRight" :
|
||||
geometry.jointIndices.contains("EyeRight") ? "EyeRight" : "RightEye");
|
||||
geometry.jointIndices.contains("EyeRight") ? "EyeRight" : "RightEye");
|
||||
}
|
||||
if (!joints.contains("jointNeck")) {
|
||||
joints.insert("jointNeck", geometry.jointIndices.contains("jointNeck") ? "jointNeck" : "Neck");
|
||||
|
@ -250,87 +362,6 @@ bool ModelUploader::zip() {
|
|||
blendshapes.insertMulti("Sneer", QVariantList() << "Squint_Right" << 0.5);
|
||||
mapping.insert(BLENDSHAPE_FIELD, blendshapes);
|
||||
}
|
||||
|
||||
// open the dialog to configure the rest
|
||||
ModelPropertiesDialog properties(_modelType, mapping, basePath, geometry);
|
||||
if (properties.exec() == QDialog::Rejected) {
|
||||
return false;
|
||||
}
|
||||
mapping = properties.getMapping();
|
||||
|
||||
QByteArray nameField = mapping.value(NAME_FIELD).toByteArray();
|
||||
QString urlBase;
|
||||
if (!nameField.isEmpty()) {
|
||||
QHttpPart textPart;
|
||||
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"model_name\"");
|
||||
textPart.setBody(nameField);
|
||||
_dataMultiPart->append(textPart);
|
||||
urlBase = S3_URL + "/models/" + MODEL_TYPE_NAMES[_modelType] + "/" + nameField;
|
||||
_url = urlBase + ".fst";
|
||||
|
||||
} else {
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::zip()"),
|
||||
QString("Model name is missing in the .fst file."),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("Model name is missing in the .fst file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray texdirField = mapping.value(TEXDIR_FIELD).toByteArray();
|
||||
QString texDir;
|
||||
_textureBase = urlBase + "/textures/";
|
||||
if (!texdirField.isEmpty()) {
|
||||
texDir = basePath + "/" + texdirField;
|
||||
QFileInfo texInfo(texDir);
|
||||
if (!texInfo.exists() || !texInfo.isDir()) {
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::zip()"),
|
||||
QString("Texture directory could not be found."),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("Texture directory could not be found.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QVariantHash lodField = mapping.value(LOD_FIELD).toHash();
|
||||
for (QVariantHash::const_iterator it = lodField.constBegin(); it != lodField.constEnd(); it++) {
|
||||
QFileInfo lod(basePath + "/" + it.key());
|
||||
if (!lod.exists() || !lod.isFile()) { // Check existence
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::zip()"),
|
||||
QString("LOD file %1 could not be found.").arg(lod.fileName()),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("FBX file %1 could not be found.").arg(lod.fileName());
|
||||
}
|
||||
// Compress and copy
|
||||
if (!addPart(lod.filePath(), QString("lod%1").arg(++_lodCount))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Write out, compress and copy the fst
|
||||
if (!addPart(*fst, writeMapping(mapping), QString("fst"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compress and copy the fbx
|
||||
if (!addPart(fbx, fbxContents, "fbx")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addTextures(texDir, geometry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QHttpPart textPart;
|
||||
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;"
|
||||
" name=\"model_category\"");
|
||||
textPart.setBody(MODEL_TYPE_NAMES[_modelType]);
|
||||
_dataMultiPart->append(textPart);
|
||||
|
||||
_readyToSend = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModelUploader::send() {
|
||||
|
@ -590,9 +621,9 @@ bool ModelUploader::addPart(const QFile& file, const QByteArray& contents, const
|
|||
if (_totalSize > MAX_SIZE) {
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::zip()"),
|
||||
QString("Model too big, over %1 Bytes.").arg(MAX_SIZE),
|
||||
QString("Model too big, over %1 MB.").arg(MAX_SIZE / BYTES_PER_MEGABYTES),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("Model too big, over %1 Bytes.").arg(MAX_SIZE);
|
||||
qDebug() << "[Warning] " << QString("Model too big, over %1 MB.").arg(MAX_SIZE / BYTES_PER_MEGABYTES);
|
||||
return false;
|
||||
}
|
||||
qDebug() << "Current model size: " << _totalSize;
|
||||
|
@ -613,8 +644,8 @@ ModelPropertiesDialog::ModelPropertiesDialog(ModelType modelType, const QVariant
|
|||
_modelType(modelType),
|
||||
_originalMapping(originalMapping),
|
||||
_basePath(basePath),
|
||||
_geometry(geometry) {
|
||||
|
||||
_geometry(geometry)
|
||||
{
|
||||
setWindowTitle("Set Model Properties");
|
||||
|
||||
QFormLayout* form = new QFormLayout();
|
||||
|
@ -629,33 +660,35 @@ ModelPropertiesDialog::ModelPropertiesDialog(ModelType modelType, const QVariant
|
|||
_scale->setMaximum(FLT_MAX);
|
||||
_scale->setSingleStep(0.01);
|
||||
|
||||
if (_modelType == ATTACHMENT_MODEL) {
|
||||
QHBoxLayout* translation = new QHBoxLayout();
|
||||
form->addRow("Translation:", translation);
|
||||
translation->addWidget(_translationX = createTranslationBox());
|
||||
translation->addWidget(_translationY = createTranslationBox());
|
||||
translation->addWidget(_translationZ = createTranslationBox());
|
||||
form->addRow("Pivot About Center:", _pivotAboutCenter = new QCheckBox());
|
||||
form->addRow("Pivot Joint:", _pivotJoint = createJointBox());
|
||||
connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint()));
|
||||
_pivotAboutCenter->setChecked(true);
|
||||
|
||||
} else {
|
||||
form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox());
|
||||
form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox());
|
||||
form->addRow("Neck Joint:", _neckJoint = createJointBox());
|
||||
}
|
||||
if (_modelType == SKELETON_MODEL) {
|
||||
form->addRow("Root Joint:", _rootJoint = createJointBox());
|
||||
form->addRow("Lean Joint:", _leanJoint = createJointBox());
|
||||
form->addRow("Head Joint:", _headJoint = createJointBox());
|
||||
form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox());
|
||||
form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox());
|
||||
|
||||
form->addRow("Free Joints:", _freeJoints = new QVBoxLayout());
|
||||
QPushButton* newFreeJoint = new QPushButton("New Free Joint");
|
||||
_freeJoints->addWidget(newFreeJoint);
|
||||
connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint()));
|
||||
if (_modelType != ENTITY_MODEL) {
|
||||
if (_modelType == ATTACHMENT_MODEL) {
|
||||
QHBoxLayout* translation = new QHBoxLayout();
|
||||
form->addRow("Translation:", translation);
|
||||
translation->addWidget(_translationX = createTranslationBox());
|
||||
translation->addWidget(_translationY = createTranslationBox());
|
||||
translation->addWidget(_translationZ = createTranslationBox());
|
||||
form->addRow("Pivot About Center:", _pivotAboutCenter = new QCheckBox());
|
||||
form->addRow("Pivot Joint:", _pivotJoint = createJointBox());
|
||||
connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint()));
|
||||
_pivotAboutCenter->setChecked(true);
|
||||
|
||||
} else {
|
||||
form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox());
|
||||
form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox());
|
||||
form->addRow("Neck Joint:", _neckJoint = createJointBox());
|
||||
}
|
||||
if (_modelType == SKELETON_MODEL) {
|
||||
form->addRow("Root Joint:", _rootJoint = createJointBox());
|
||||
form->addRow("Lean Joint:", _leanJoint = createJointBox());
|
||||
form->addRow("Head Joint:", _headJoint = createJointBox());
|
||||
form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox());
|
||||
form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox());
|
||||
|
||||
form->addRow("Free Joints:", _freeJoints = new QVBoxLayout());
|
||||
QPushButton* newFreeJoint = new QPushButton("New Free Joint");
|
||||
_freeJoints->addWidget(newFreeJoint);
|
||||
connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint()));
|
||||
}
|
||||
}
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok |
|
||||
|
@ -683,38 +716,40 @@ QVariantHash ModelPropertiesDialog::getMapping() const {
|
|||
}
|
||||
mapping.insert(JOINT_INDEX_FIELD, jointIndices);
|
||||
|
||||
QVariantHash joints = mapping.value(JOINT_FIELD).toHash();
|
||||
if (_modelType == ATTACHMENT_MODEL) {
|
||||
glm::vec3 pivot;
|
||||
if (_pivotAboutCenter->isChecked()) {
|
||||
pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f;
|
||||
|
||||
} else if (_pivotJoint->currentIndex() != 0) {
|
||||
pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform);
|
||||
if (_modelType != ENTITY_MODEL) {
|
||||
QVariantHash joints = mapping.value(JOINT_FIELD).toHash();
|
||||
if (_modelType == ATTACHMENT_MODEL) {
|
||||
glm::vec3 pivot;
|
||||
if (_pivotAboutCenter->isChecked()) {
|
||||
pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f;
|
||||
|
||||
} else if (_pivotJoint->currentIndex() != 0) {
|
||||
pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform);
|
||||
}
|
||||
mapping.insert(TRANSLATION_X_FIELD, -pivot.x * _scale->value() + _translationX->value());
|
||||
mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * _scale->value() + _translationY->value());
|
||||
mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * _scale->value() + _translationZ->value());
|
||||
|
||||
} else {
|
||||
insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText());
|
||||
insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText());
|
||||
insertJointMapping(joints, "jointNeck", _neckJoint->currentText());
|
||||
}
|
||||
mapping.insert(TRANSLATION_X_FIELD, -pivot.x * _scale->value() + _translationX->value());
|
||||
mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * _scale->value() + _translationY->value());
|
||||
mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * _scale->value() + _translationZ->value());
|
||||
|
||||
} else {
|
||||
insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText());
|
||||
insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText());
|
||||
insertJointMapping(joints, "jointNeck", _neckJoint->currentText());
|
||||
}
|
||||
if (_modelType == SKELETON_MODEL) {
|
||||
insertJointMapping(joints, "jointRoot", _rootJoint->currentText());
|
||||
insertJointMapping(joints, "jointLean", _leanJoint->currentText());
|
||||
insertJointMapping(joints, "jointHead", _headJoint->currentText());
|
||||
insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText());
|
||||
insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText());
|
||||
|
||||
mapping.remove(FREE_JOINT_FIELD);
|
||||
for (int i = 0; i < _freeJoints->count() - 1; i++) {
|
||||
QComboBox* box = static_cast<QComboBox*>(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget());
|
||||
mapping.insertMulti(FREE_JOINT_FIELD, box->currentText());
|
||||
if (_modelType == SKELETON_MODEL) {
|
||||
insertJointMapping(joints, "jointRoot", _rootJoint->currentText());
|
||||
insertJointMapping(joints, "jointLean", _leanJoint->currentText());
|
||||
insertJointMapping(joints, "jointHead", _headJoint->currentText());
|
||||
insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText());
|
||||
insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText());
|
||||
|
||||
mapping.remove(FREE_JOINT_FIELD);
|
||||
for (int i = 0; i < _freeJoints->count() - 1; i++) {
|
||||
QComboBox* box = static_cast<QComboBox*>(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget());
|
||||
mapping.insertMulti(FREE_JOINT_FIELD, box->currentText());
|
||||
}
|
||||
}
|
||||
mapping.insert(JOINT_FIELD, joints);
|
||||
}
|
||||
mapping.insert(JOINT_FIELD, joints);
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
@ -729,32 +764,35 @@ void ModelPropertiesDialog::reset() {
|
|||
_scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble());
|
||||
|
||||
QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash();
|
||||
if (_modelType == ATTACHMENT_MODEL) {
|
||||
_translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble());
|
||||
_translationY->setValue(_originalMapping.value(TRANSLATION_Y_FIELD).toDouble());
|
||||
_translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble());
|
||||
_pivotAboutCenter->setChecked(true);
|
||||
_pivotJoint->setCurrentIndex(0);
|
||||
|
||||
} else {
|
||||
setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString());
|
||||
setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString());
|
||||
setJointText(_neckJoint, jointHash.value("jointNeck").toString());
|
||||
}
|
||||
if (_modelType == SKELETON_MODEL) {
|
||||
setJointText(_rootJoint, jointHash.value("jointRoot").toString());
|
||||
setJointText(_leanJoint, jointHash.value("jointLean").toString());
|
||||
setJointText(_headJoint, jointHash.value("jointHead").toString());
|
||||
setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString());
|
||||
setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString());
|
||||
|
||||
while (_freeJoints->count() > 1) {
|
||||
delete _freeJoints->itemAt(0)->widget();
|
||||
|
||||
if (_modelType != ENTITY_MODEL) {
|
||||
if (_modelType == ATTACHMENT_MODEL) {
|
||||
_translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble());
|
||||
_translationY->setValue(_originalMapping.value(TRANSLATION_Y_FIELD).toDouble());
|
||||
_translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble());
|
||||
_pivotAboutCenter->setChecked(true);
|
||||
_pivotJoint->setCurrentIndex(0);
|
||||
|
||||
} else {
|
||||
setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString());
|
||||
setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString());
|
||||
setJointText(_neckJoint, jointHash.value("jointNeck").toString());
|
||||
}
|
||||
foreach (const QVariant& joint, _originalMapping.values(FREE_JOINT_FIELD)) {
|
||||
QString jointName = joint.toString();
|
||||
if (_geometry.jointIndices.contains(jointName)) {
|
||||
createNewFreeJoint(jointName);
|
||||
if (_modelType == SKELETON_MODEL) {
|
||||
setJointText(_rootJoint, jointHash.value("jointRoot").toString());
|
||||
setJointText(_leanJoint, jointHash.value("jointLean").toString());
|
||||
setJointText(_headJoint, jointHash.value("jointHead").toString());
|
||||
setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString());
|
||||
setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString());
|
||||
|
||||
while (_freeJoints->count() > 1) {
|
||||
delete _freeJoints->itemAt(0)->widget();
|
||||
}
|
||||
foreach (const QVariant& joint, _originalMapping.values(FREE_JOINT_FIELD)) {
|
||||
QString jointName = joint.toString();
|
||||
if (_geometry.jointIndices.contains(jointName)) {
|
||||
createNewFreeJoint(jointName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,13 +33,15 @@ class ModelUploader : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModelUploader(ModelType type);
|
||||
~ModelUploader();
|
||||
static void uploadModel(ModelType modelType);
|
||||
|
||||
public slots:
|
||||
void send();
|
||||
static void uploadHead();
|
||||
static void uploadSkeleton();
|
||||
static void uploadAttachment();
|
||||
static void uploadEntity();
|
||||
|
||||
private slots:
|
||||
void send();
|
||||
void checkJSON(QNetworkReply& requestReply);
|
||||
void uploadUpdate(qint64 bytesSent, qint64 bytesTotal);
|
||||
void uploadSuccess(QNetworkReply& requestReply);
|
||||
|
@ -48,12 +50,21 @@ private slots:
|
|||
void processCheck();
|
||||
|
||||
private:
|
||||
ModelUploader(ModelType type);
|
||||
~ModelUploader();
|
||||
|
||||
void populateBasicMapping(QVariantHash& mapping, QString filename, FBXGeometry geometry);
|
||||
bool zip();
|
||||
bool addTextures(const QString& texdir, const FBXGeometry& geometry);
|
||||
bool addPart(const QString& path, const QString& name, bool isTexture = false);
|
||||
bool addPart(const QFile& file, const QByteArray& contents, const QString& name, bool isTexture = false);
|
||||
|
||||
QString _url;
|
||||
QString _textureBase;
|
||||
QSet<QByteArray> _textureFilenames;
|
||||
int _lodCount;
|
||||
int _texturesCount;
|
||||
int _totalSize;
|
||||
unsigned long _totalSize;
|
||||
ModelType _modelType;
|
||||
bool _readyToSend;
|
||||
|
||||
|
@ -64,12 +75,6 @@ private:
|
|||
|
||||
QDialog* _progressDialog;
|
||||
QProgressBar* _progressBar;
|
||||
|
||||
|
||||
bool zip();
|
||||
bool addTextures(const QString& texdir, const FBXGeometry& geometry);
|
||||
bool addPart(const QString& path, const QString& name, bool isTexture = false);
|
||||
bool addPart(const QFile& file, const QByteArray& contents, const QString& name, bool isTexture = false);
|
||||
};
|
||||
|
||||
/// A dialog that allows customization of various model properties.
|
||||
|
|
|
@ -33,12 +33,6 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
// no clue which versions are affected...
|
||||
#define WORKAROUND_BROKEN_GLUT_STROKES
|
||||
// see http://www.opengl.org/resources/libraries/glut/spec3/node78.html
|
||||
|
||||
|
||||
|
||||
void renderWorldBox() {
|
||||
// Show edge of world
|
||||
float red[] = {1, 0, 0};
|
||||
|
|
|
@ -282,43 +282,64 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
// render pointing lasers
|
||||
glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f);
|
||||
float laserLength = 50.0f;
|
||||
if (_handState == HAND_STATE_LEFT_POINTING ||
|
||||
_handState == HAND_STATE_BOTH_POINTING) {
|
||||
int leftIndex = _skeletonModel.getLeftHandJointIndex();
|
||||
glm::vec3 leftPosition;
|
||||
glm::quat leftRotation;
|
||||
_skeletonModel.getJointPositionInWorldFrame(leftIndex, leftPosition);
|
||||
_skeletonModel.getJointRotationInWorldFrame(leftIndex, leftRotation);
|
||||
glPushMatrix(); {
|
||||
glTranslatef(leftPosition.x, leftPosition.y, leftPosition.z);
|
||||
float angle = glm::degrees(glm::angle(leftRotation));
|
||||
glm::vec3 axis = glm::axis(leftRotation);
|
||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(laserColor.x, laserColor.y, laserColor.z);
|
||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex3f(0.0f, laserLength, 0.0f);
|
||||
glEnd();
|
||||
} glPopMatrix();
|
||||
glm::vec3 position;
|
||||
glm::quat rotation;
|
||||
bool havePosition, haveRotation;
|
||||
|
||||
if (_handState & LEFT_HAND_POINTING_FLAG) {
|
||||
|
||||
if (_handState & IS_FINGER_POINTING_FLAG) {
|
||||
int leftIndexTip = getJointIndex("LeftHandIndex4");
|
||||
int leftIndexTipJoint = getJointIndex("LeftHandIndex3");
|
||||
havePosition = _skeletonModel.getJointPositionInWorldFrame(leftIndexTip, position);
|
||||
haveRotation = _skeletonModel.getJointRotationInWorldFrame(leftIndexTipJoint, rotation);
|
||||
} else {
|
||||
int leftHand = _skeletonModel.getLeftHandJointIndex();
|
||||
havePosition = _skeletonModel.getJointPositionInWorldFrame(leftHand, position);
|
||||
haveRotation = _skeletonModel.getJointRotationInWorldFrame(leftHand, rotation);
|
||||
}
|
||||
|
||||
if (havePosition && haveRotation) {
|
||||
glPushMatrix(); {
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
float angle = glm::degrees(glm::angle(rotation));
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(laserColor.x, laserColor.y, laserColor.z);
|
||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex3f(0.0f, laserLength, 0.0f);
|
||||
glEnd();
|
||||
} glPopMatrix();
|
||||
}
|
||||
}
|
||||
if (_handState == HAND_STATE_RIGHT_POINTING ||
|
||||
_handState == HAND_STATE_BOTH_POINTING) {
|
||||
int rightIndex = _skeletonModel.getRightHandJointIndex();
|
||||
glm::vec3 rightPosition;
|
||||
glm::quat rightRotation;
|
||||
_skeletonModel.getJointPositionInWorldFrame(rightIndex, rightPosition);
|
||||
_skeletonModel.getJointRotationInWorldFrame(rightIndex, rightRotation);
|
||||
glPushMatrix(); {
|
||||
glTranslatef(rightPosition.x, rightPosition.y, rightPosition.z);
|
||||
float angle = glm::degrees(glm::angle(rightRotation));
|
||||
glm::vec3 axis = glm::axis(rightRotation);
|
||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(laserColor.x, laserColor.y, laserColor.z);
|
||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex3f(0.0f, laserLength, 0.0f);
|
||||
glEnd();
|
||||
} glPopMatrix();
|
||||
|
||||
if (_handState & RIGHT_HAND_POINTING_FLAG) {
|
||||
|
||||
if (_handState & IS_FINGER_POINTING_FLAG) {
|
||||
int rightIndexTip = getJointIndex("RightHandIndex4");
|
||||
int rightIndexTipJoint = getJointIndex("RightHandIndex3");
|
||||
havePosition = _skeletonModel.getJointPositionInWorldFrame(rightIndexTip, position);
|
||||
haveRotation = _skeletonModel.getJointRotationInWorldFrame(rightIndexTipJoint, rotation);
|
||||
} else {
|
||||
int rightHand = _skeletonModel.getRightHandJointIndex();
|
||||
havePosition = _skeletonModel.getJointPositionInWorldFrame(rightHand, position);
|
||||
haveRotation = _skeletonModel.getJointRotationInWorldFrame(rightHand, rotation);
|
||||
}
|
||||
|
||||
if (havePosition && haveRotation) {
|
||||
glPushMatrix(); {
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
float angle = glm::degrees(glm::angle(rotation));
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(laserColor.x, laserColor.y, laserColor.z);
|
||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex3f(0.0f, laserLength, 0.0f);
|
||||
glEnd();
|
||||
} glPopMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -648,6 +669,49 @@ glm::vec3 Avatar::getDisplayNamePosition() {
|
|||
return namePosition;
|
||||
}
|
||||
|
||||
float Avatar::calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD) {
|
||||
|
||||
// We need to compute the scale factor such as the text remains with fixed size respect to window coordinates
|
||||
// We project a unit vector and check the difference in screen coordinates, to check which is the
|
||||
// correction scale needed
|
||||
// save the matrices for later scale correction factor
|
||||
// The up vector must be relative to the rotation current rotation matrix:
|
||||
// we set the identity
|
||||
glm::vec3 testPoint0 = textPosition;
|
||||
glm::vec3 testPoint1 = textPosition + (Application::getInstance()->getCamera()->getRotation() * IDENTITY_UP);
|
||||
|
||||
double textWindowHeight;
|
||||
|
||||
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
|
||||
float windowSizeX = glCanvas->getDeviceWidth();
|
||||
float windowSizeY = glCanvas->getDeviceHeight();
|
||||
|
||||
glm::dmat4 modelViewMatrix;
|
||||
glm::dmat4 projectionMatrix;
|
||||
Application::getInstance()->getModelViewMatrix(&modelViewMatrix);
|
||||
Application::getInstance()->getProjectionMatrix(&projectionMatrix);
|
||||
|
||||
glm::dvec4 p0 = modelViewMatrix * glm::dvec4(testPoint0, 1.0);
|
||||
p0 = projectionMatrix * p0;
|
||||
glm::dvec2 result0 = glm::vec2(windowSizeX * (p0.x / p0.w + 1.0f) * 0.5f, windowSizeY * (p0.y / p0.w + 1.0f) * 0.5f);
|
||||
|
||||
glm::dvec4 p1 = modelViewMatrix * glm::dvec4(testPoint1, 1.0);
|
||||
p1 = projectionMatrix * p1;
|
||||
glm::vec2 result1 = glm::vec2(windowSizeX * (p1.x / p1.w + 1.0f) * 0.5f, windowSizeY * (p1.y / p1.w + 1.0f) * 0.5f);
|
||||
textWindowHeight = abs(result1.y - result0.y);
|
||||
|
||||
// need to scale to compensate for the font resolution due to the device
|
||||
float scaleFactor = QApplication::desktop()->windowHandle()->devicePixelRatio() *
|
||||
((textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f);
|
||||
if (inHMD) {
|
||||
const float HMDMODE_NAME_SCALE = 0.65f;
|
||||
scaleFactor *= HMDMODE_NAME_SCALE;
|
||||
} else {
|
||||
scaleFactor *= Application::getInstance()->getRenderResolutionScale();
|
||||
}
|
||||
return scaleFactor;
|
||||
}
|
||||
|
||||
void Avatar::renderDisplayName() {
|
||||
|
||||
if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) {
|
||||
|
@ -679,78 +743,39 @@ void Avatar::renderDisplayName() {
|
|||
frontAxis = glm::normalize(glm::vec3(frontAxis.z, 0.0f, -frontAxis.x));
|
||||
float angle = acos(frontAxis.x) * ((frontAxis.z < 0) ? 1.0f : -1.0f);
|
||||
glRotatef(glm::degrees(angle), 0.0f, 1.0f, 0.0f);
|
||||
|
||||
// We need to compute the scale factor such as the text remains with fixed size respect to window coordinates
|
||||
// We project a unit vector and check the difference in screen coordinates, to check which is the
|
||||
// correction scale needed
|
||||
// save the matrices for later scale correction factor
|
||||
glm::dmat4 modelViewMatrix;
|
||||
glm::dmat4 projectionMatrix;
|
||||
GLint viewportMatrix[4];
|
||||
Application::getInstance()->getModelViewMatrix(&modelViewMatrix);
|
||||
Application::getInstance()->getProjectionMatrix(&projectionMatrix);
|
||||
glGetIntegerv(GL_VIEWPORT, viewportMatrix);
|
||||
GLdouble result0[3], result1[3];
|
||||
|
||||
// The up vector must be relative to the rotation current rotation matrix:
|
||||
// we set the identity
|
||||
glm::dvec3 testPoint0 = glm::dvec3(textPosition);
|
||||
glm::dvec3 testPoint1 = glm::dvec3(textPosition) + glm::dvec3(Application::getInstance()->getCamera()->getRotation() * IDENTITY_UP);
|
||||
|
||||
bool success;
|
||||
success = gluProject(testPoint0.x, testPoint0.y, testPoint0.z,
|
||||
(GLdouble*)&modelViewMatrix, (GLdouble*)&projectionMatrix, viewportMatrix,
|
||||
&result0[0], &result0[1], &result0[2]);
|
||||
success = success &&
|
||||
gluProject(testPoint1.x, testPoint1.y, testPoint1.z,
|
||||
(GLdouble*)&modelViewMatrix, (GLdouble*)&projectionMatrix, viewportMatrix,
|
||||
&result1[0], &result1[1], &result1[2]);
|
||||
float scaleFactor = calculateDisplayNameScaleFactor(textPosition, inHMD);
|
||||
glScalef(scaleFactor, scaleFactor, 1.0);
|
||||
|
||||
glScalef(1.0f, -1.0f, 1.0f); // TextRenderer::draw paints the text upside down in y axis
|
||||
|
||||
if (success) {
|
||||
double textWindowHeight = abs(result1[1] - result0[1]);
|
||||
// need to scale to compensate for the font resolution due to the device
|
||||
float scaleFactor = QApplication::desktop()->windowHandle()->devicePixelRatio() *
|
||||
((textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f);
|
||||
if (inHMD) {
|
||||
const float HMDMODE_NAME_SCALE = 0.65f;
|
||||
scaleFactor *= HMDMODE_NAME_SCALE;
|
||||
} else {
|
||||
scaleFactor *= Application::getInstance()->getRenderResolutionScale();
|
||||
}
|
||||
glScalef(scaleFactor, scaleFactor, 1.0);
|
||||
|
||||
glScalef(1.0f, -1.0f, 1.0f); // TextRenderer::draw paints the text upside down in y axis
|
||||
int text_x = -_displayNameBoundingRect.width() / 2;
|
||||
int text_y = -_displayNameBoundingRect.height() / 2;
|
||||
|
||||
int text_x = -_displayNameBoundingRect.width() / 2;
|
||||
int text_y = -_displayNameBoundingRect.height() / 2;
|
||||
// draw a gray background
|
||||
int left = text_x + _displayNameBoundingRect.x();
|
||||
int right = left + _displayNameBoundingRect.width();
|
||||
int bottom = text_y + _displayNameBoundingRect.y();
|
||||
int top = bottom + _displayNameBoundingRect.height();
|
||||
const int border = 8;
|
||||
bottom -= border;
|
||||
left -= border;
|
||||
top += border;
|
||||
right += border;
|
||||
|
||||
// draw a gray background
|
||||
int left = text_x + _displayNameBoundingRect.x();
|
||||
int right = left + _displayNameBoundingRect.width();
|
||||
int bottom = text_y + _displayNameBoundingRect.y();
|
||||
int top = bottom + _displayNameBoundingRect.height();
|
||||
const int border = 8;
|
||||
bottom -= border;
|
||||
left -= border;
|
||||
top += border;
|
||||
right += border;
|
||||
// We are drawing coplanar textures with depth: need the polygon offset
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.0f, 1.0f);
|
||||
|
||||
// We are drawing coplanar textures with depth: need the polygon offset
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.0f, 1.0f);
|
||||
|
||||
glColor4f(0.2f, 0.2f, 0.2f, _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA);
|
||||
renderBevelCornersRect(left, bottom, right - left, top - bottom, 3);
|
||||
|
||||
glColor4f(0.93f, 0.93f, 0.93f, _displayNameAlpha);
|
||||
QByteArray ba = _displayName.toLocal8Bit();
|
||||
const char* text = ba.data();
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
textRenderer(DISPLAYNAME)->draw(text_x, text_y, text);
|
||||
|
||||
|
||||
}
|
||||
glColor4f(0.2f, 0.2f, 0.2f, _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA);
|
||||
renderBevelCornersRect(left, bottom, right - left, top - bottom, 3);
|
||||
|
||||
glColor4f(0.93f, 0.93f, 0.93f, _displayNameAlpha);
|
||||
QByteArray ba = _displayName.toLocal8Bit();
|
||||
const char* text = ba.data();
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
textRenderer(DISPLAYNAME)->draw(text_x, text_y, text);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
|
|
|
@ -230,6 +230,7 @@ protected:
|
|||
float getPelvisFloatingHeight() const;
|
||||
glm::vec3 getDisplayNamePosition();
|
||||
|
||||
float calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD);
|
||||
void renderDisplayName();
|
||||
virtual void renderBody(RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
|
||||
virtual bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const;
|
||||
|
|
|
@ -153,7 +153,7 @@ void Hand::renderHandTargets(bool isMine) {
|
|||
|
||||
const float collisionRadius = 0.05f;
|
||||
glColor4f(0.5f,0.5f,0.5f, alpha);
|
||||
glutWireSphere(collisionRadius, 10.0f, 10.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(collisionRadius, 10, 10, false);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,6 @@
|
|||
|
||||
class ModelItemID;
|
||||
|
||||
enum AvatarHandState
|
||||
{
|
||||
HAND_STATE_NULL = 0,
|
||||
HAND_STATE_LEFT_POINTING,
|
||||
HAND_STATE_RIGHT_POINTING,
|
||||
HAND_STATE_BOTH_POINTING,
|
||||
NUM_HAND_STATES
|
||||
};
|
||||
|
||||
class MyAvatar : public Avatar {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally)
|
||||
|
|
|
@ -582,7 +582,7 @@ void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) {
|
|||
|
||||
glLoadIdentity();
|
||||
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
|
||||
gluOrtho2D(0, glCanvas->getDeviceWidth(), 0, glCanvas->getDeviceHeight());
|
||||
glOrtho(0, glCanvas->getDeviceWidth(), 0, glCanvas->getDeviceHeight(), -1.0, 1.0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
|||
|
||||
glPushMatrix(); {
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0, glCanvas->width(), glCanvas->height(), 0);
|
||||
glOrtho(0, glCanvas->width(), glCanvas->height(), 0, -1.0, 1.0);
|
||||
|
||||
renderAudioMeter();
|
||||
|
||||
|
@ -227,7 +227,7 @@ void ApplicationOverlay::displayOverlayTexture() {
|
|||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix(); {
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight(), 0);
|
||||
glOrtho(0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight(), 0, -1.0, 1.0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <QVBoxLayout>
|
||||
|
||||
#include <AttributeRegistry.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <MetavoxelMessages.h>
|
||||
#include <MetavoxelUtil.h>
|
||||
#include <PathUtils.h>
|
||||
|
@ -492,12 +493,11 @@ void BoxTool::render() {
|
|||
glColor4f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS, BOX_ALPHA);
|
||||
}
|
||||
glEnable(GL_CULL_FACE);
|
||||
glutSolidCube(1.0);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f);
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
glColor3f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS);
|
||||
glutWireCube(1.0);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderWireCube(1.0f);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,16 +12,19 @@
|
|||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QFileInfo>
|
||||
#include <QHeaderView>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QThread>
|
||||
#include <QUrl>
|
||||
#include <qurlquery.h>
|
||||
#include <QUrlQuery>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#include <NetworkAccessManager.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include "ModelsBrowser.h"
|
||||
|
||||
const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "attachments" };
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <GeometryCache.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
@ -49,59 +51,59 @@ void NodeBounds::draw() {
|
|||
float selectedScale = 0;
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
NodeType_t nodeType = node->getType();
|
||||
|
||||
|
||||
if (nodeType == NodeType::VoxelServer && _showVoxelNodes) {
|
||||
serverJurisdictions = &voxelServerJurisdictions;
|
||||
} else if (nodeType == NodeType::EntityServer && _showEntityNodes) {
|
||||
serverJurisdictions = &entityServerJurisdictions;
|
||||
} else {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
serverJurisdictions->lockForRead();
|
||||
if (serverJurisdictions->find(nodeUUID) != serverJurisdictions->end()) {
|
||||
const JurisdictionMap& map = (*serverJurisdictions)[nodeUUID];
|
||||
|
||||
|
||||
unsigned char* rootCode = map.getRootOctalCode();
|
||||
|
||||
|
||||
if (rootCode) {
|
||||
VoxelPositionSize rootDetails;
|
||||
voxelDetailsForCode(rootCode, rootDetails);
|
||||
serverJurisdictions->unlock();
|
||||
glm::vec3 location(rootDetails.x, rootDetails.y, rootDetails.z);
|
||||
location *= (float)TREE_SCALE;
|
||||
|
||||
|
||||
AACube serverBounds(location, rootDetails.s * TREE_SCALE);
|
||||
|
||||
|
||||
glm::vec3 center = serverBounds.getVertex(BOTTOM_RIGHT_NEAR)
|
||||
+ ((serverBounds.getVertex(TOP_LEFT_FAR) - serverBounds.getVertex(BOTTOM_RIGHT_NEAR)) / 2.0f);
|
||||
|
||||
+ ((serverBounds.getVertex(TOP_LEFT_FAR) - serverBounds.getVertex(BOTTOM_RIGHT_NEAR)) / 2.0f);
|
||||
|
||||
const float VOXEL_NODE_SCALE = 1.00f;
|
||||
const float ENTITY_NODE_SCALE = 0.99f;
|
||||
|
||||
|
||||
float scaleFactor = rootDetails.s * TREE_SCALE;
|
||||
|
||||
|
||||
// Scale by 0.92 - 1.00 depending on the scale of the node. This allows smaller nodes to scale in
|
||||
// a bit and not overlap larger nodes.
|
||||
scaleFactor *= 0.92 + (rootDetails.s * 0.08);
|
||||
|
||||
|
||||
// Scale different node types slightly differently because it's common for them to overlap.
|
||||
if (nodeType == NodeType::VoxelServer) {
|
||||
scaleFactor *= VOXEL_NODE_SCALE;
|
||||
} else if (nodeType == NodeType::EntityServer) {
|
||||
scaleFactor *= ENTITY_NODE_SCALE;
|
||||
}
|
||||
|
||||
|
||||
float red, green, blue;
|
||||
getColorForNodeType(nodeType, red, green, blue);
|
||||
drawNodeBorder(center, scaleFactor, red, green, blue);
|
||||
|
||||
|
||||
float distance;
|
||||
BoxFace face;
|
||||
|
||||
bool inside = serverBounds.contains(pickRay.origin);
|
||||
bool colliding = serverBounds.findRayIntersection(pickRay.origin, pickRay.direction, distance, face);
|
||||
|
||||
|
@ -120,7 +122,7 @@ void NodeBounds::draw() {
|
|||
} else {
|
||||
serverJurisdictions->unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (selectedNode) {
|
||||
glPushMatrix();
|
||||
|
@ -132,7 +134,7 @@ void NodeBounds::draw() {
|
|||
getColorForNodeType(selectedNode->getType(), red, green, blue);
|
||||
|
||||
glColor4f(red, green, blue, 0.2f);
|
||||
glutSolidCube(1.0);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
|
|
|
@ -248,8 +248,8 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
|
|||
QLocale locale(QLocale::English);
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
|
||||
// only send to the NodeTypes that are NodeType_t_VOXEL_SERVER
|
||||
if (node->getType() == serverType) {
|
||||
serverCount++;
|
||||
|
@ -420,7 +420,7 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
|
|||
serverDetails << linkDetails.str();
|
||||
_labels[_voxelServerLables[serverCount - 1]]->setText(serverDetails.str().c_str());
|
||||
} // is VOXEL_SERVER
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void OctreeStatsDialog::reject() {
|
||||
|
|
|
@ -128,7 +128,7 @@ void RearMirrorTools::displayIcon(QRect bounds, QRect iconBounds, GLuint texture
|
|||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
gluOrtho2D(bounds.left(), bounds.right(), bounds.bottom(), bounds.top());
|
||||
glOrtho(bounds.left(), bounds.right(), bounds.bottom(), bounds.top(), -1.0, 1.0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
|
|
@ -328,8 +328,8 @@ void Stats::display(
|
|||
// Now handle voxel servers, since there could be more than one, we average their ping times
|
||||
unsigned long totalPingVoxel = 0;
|
||||
int voxelServerCount = 0;
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
|
||||
nodeList->eachNode([&totalPingVoxel, &pingVoxelMax, &voxelServerCount](const SharedNodePointer& node){
|
||||
// TODO: this should also support entities
|
||||
if (node->getType() == NodeType::VoxelServer) {
|
||||
totalPingVoxel += node->getPingMs();
|
||||
|
@ -338,7 +338,7 @@ void Stats::display(
|
|||
pingVoxelMax = node->getPingMs();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (voxelServerCount) {
|
||||
pingVoxel = totalPingVoxel/voxelServerCount;
|
||||
|
|
|
@ -100,26 +100,31 @@ void ImageOverlay::render(RenderArgs* args) {
|
|||
float w = fromImage.width() / imageWidth; // ?? is this what we want? not sure
|
||||
float h = fromImage.height() / imageHeight;
|
||||
|
||||
int left = _bounds.left();
|
||||
int right = _bounds.right() + 1;
|
||||
int top = _bounds.top();
|
||||
int bottom = _bounds.bottom() + 1;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
if (_renderImage) {
|
||||
glTexCoord2f(x, 1.0f - y);
|
||||
}
|
||||
glVertex2f(_bounds.left(), _bounds.top());
|
||||
glVertex2f(left, top);
|
||||
|
||||
if (_renderImage) {
|
||||
glTexCoord2f(x + w, 1.0f - y);
|
||||
}
|
||||
glVertex2f(_bounds.right(), _bounds.top());
|
||||
glVertex2f(right, top);
|
||||
|
||||
if (_renderImage) {
|
||||
glTexCoord2f(x + w, 1.0f - (y + h));
|
||||
}
|
||||
glVertex2f(_bounds.right(), _bounds.bottom());
|
||||
glVertex2f(right, bottom);
|
||||
|
||||
if (_renderImage) {
|
||||
glTexCoord2f(x, 1.0f - (y + h));
|
||||
}
|
||||
glVertex2f(_bounds.left(), _bounds.bottom());
|
||||
glVertex2f(left, bottom);
|
||||
glEnd();
|
||||
|
||||
if (_renderImage) {
|
||||
|
|
|
@ -62,11 +62,7 @@ void Sphere3DOverlay::render(RenderArgs* args) {
|
|||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
if (_isSolid) {
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(1.0f, SLICES, SLICES);
|
||||
} else {
|
||||
glutWireSphere(1.0f, SLICES, SLICES);
|
||||
}
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(1.0f, SLICES, SLICES, _isSolid);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
|
||||
|
|
|
@ -70,11 +70,16 @@ void TextOverlay::render(RenderArgs* args) {
|
|||
glColor4f(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR,
|
||||
getBackgroundAlpha());
|
||||
|
||||
int left = _bounds.left();
|
||||
int right = _bounds.right() + 1;
|
||||
int top = _bounds.top();
|
||||
int bottom = _bounds.bottom() + 1;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(_bounds.left(), _bounds.top());
|
||||
glVertex2f(_bounds.right(), _bounds.top());
|
||||
glVertex2f(_bounds.right(), _bounds.bottom());
|
||||
glVertex2f(_bounds.left(), _bounds.bottom());
|
||||
glVertex2f(left, top);
|
||||
glVertex2f(right, top);
|
||||
glVertex2f(right, bottom);
|
||||
glVertex2f(left, bottom);
|
||||
glEnd();
|
||||
|
||||
// Same font properties as textSize()
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <GlowEffect.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <VoxelConstants.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
@ -47,7 +48,7 @@ void VoxelFade::render() {
|
|||
voxelDetails.y + voxelDetails.s * 0.5f,
|
||||
voxelDetails.z + voxelDetails.s * 0.5f);
|
||||
glLineWidth(1.0f);
|
||||
glutSolidCube(voxelDetails.s);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(voxelDetails.s);
|
||||
glLineWidth(1.0f);
|
||||
glPopMatrix();
|
||||
glEnable(GL_LIGHTING);
|
||||
|
|
|
@ -3,7 +3,7 @@ set(TARGET_NAME animation)
|
|||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network Script)
|
||||
|
||||
link_hifi_libraries(shared fbx)
|
||||
link_hifi_libraries(shared gpu model fbx)
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
# call macro to include our dependency includes and bubble them up via a property on our target
|
||||
include_dependency_includes()
|
|
@ -7,5 +7,5 @@ include_glm()
|
|||
|
||||
link_hifi_libraries(networking shared)
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
# call macro to include our dependency includes and bubble them up via a property on our target
|
||||
include_dependency_includes()
|
|
@ -5,8 +5,7 @@ setup_hifi_library(Network Script)
|
|||
|
||||
include_glm()
|
||||
|
||||
link_hifi_libraries(shared octree voxels networking physics)
|
||||
include_hifi_library_headers(fbx)
|
||||
link_hifi_libraries(audio shared octree voxels networking physics gpu model fbx)
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
# call macro to include our dependency includes and bubble them up via a property on our target
|
||||
include_dependency_includes()
|
||||
|
|
|
@ -188,7 +188,11 @@ QByteArray AvatarData::toByteArray() {
|
|||
// key state
|
||||
setSemiNibbleAt(bitItems,KEY_STATE_START_BIT,_keyState);
|
||||
// hand state
|
||||
setSemiNibbleAt(bitItems,HAND_STATE_START_BIT,_handState);
|
||||
bool isFingerPointing = _handState & IS_FINGER_POINTING_FLAG;
|
||||
setSemiNibbleAt(bitItems, HAND_STATE_START_BIT, _handState & ~IS_FINGER_POINTING_FLAG);
|
||||
if (isFingerPointing) {
|
||||
setAtBit(bitItems, HAND_STATE_FINGER_POINTING_BIT);
|
||||
}
|
||||
// faceshift state
|
||||
if (_headData->_isFaceshiftConnected) {
|
||||
setAtBit(bitItems, IS_FACESHIFT_CONNECTED);
|
||||
|
@ -439,8 +443,16 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
|||
|
||||
// key state, stored as a semi-nibble in the bitItems
|
||||
_keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT);
|
||||
// hand state, stored as a semi-nibble in the bitItems
|
||||
_handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT);
|
||||
|
||||
// hand state, stored as a semi-nibble plus a bit in the bitItems
|
||||
// we store the hand state as well as other items in a shared bitset. The hand state is an octal, but is split
|
||||
// into two sections to maintain backward compatibility. The bits are ordered as such (0-7 left to right).
|
||||
// +---+-----+-----+--+
|
||||
// |x,x|H0,H1|x,x,x|H2|
|
||||
// +---+-----+-----+--+
|
||||
// Hand state - H0,H1,H2 is found in the 3rd, 4th, and 8th bits
|
||||
_handState = getSemiNibbleAt(bitItems, HAND_STATE_START_BIT)
|
||||
+ (oneAtBit(bitItems, HAND_STATE_FINGER_POINTING_BIT) ? IS_FINGER_POINTING_FLAG : 0);
|
||||
|
||||
_headData->_isFaceshiftConnected = oneAtBit(bitItems, IS_FACESHIFT_CONNECTED);
|
||||
_isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED);
|
||||
|
|
|
@ -76,12 +76,28 @@ const quint32 AVATAR_MOTION_SCRIPTABLE_BITS =
|
|||
AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
|
||||
|
||||
|
||||
// First bitset
|
||||
// Bitset of state flags - we store the key state, hand state, faceshift, chat circling, and existance of
|
||||
// referential data in this bit set. The hand state is an octal, but is split into two sections to maintain
|
||||
// backward compatibility. The bits are ordered as such (0-7 left to right).
|
||||
// +-----+-----+-+-+-+--+
|
||||
// |K0,K1|H0,H1|F|C|R|H2|
|
||||
// +-----+-----+-+-+-+--+
|
||||
// Key state - K0,K1 is found in the 1st and 2nd bits
|
||||
// Hand state - H0,H1,H2 is found in the 3rd, 4th, and 8th bits
|
||||
// Faceshift - F is found in the 5th bit
|
||||
// Chat Circling - C is found in the 6th bit
|
||||
// Referential Data - R is found in the 7th bit
|
||||
const int KEY_STATE_START_BIT = 0; // 1st and 2nd bits
|
||||
const int HAND_STATE_START_BIT = 2; // 3rd and 4th bits
|
||||
const int IS_FACESHIFT_CONNECTED = 4; // 5th bit
|
||||
const int IS_CHAT_CIRCLING_ENABLED = 5; // 6th bit
|
||||
const int HAS_REFERENTIAL = 6; // 7th bit
|
||||
const int HAND_STATE_FINGER_POINTING_BIT = 7; // 8th bit
|
||||
|
||||
const char HAND_STATE_NULL = 0;
|
||||
const char LEFT_HAND_POINTING_FLAG = 1;
|
||||
const char RIGHT_HAND_POINTING_FLAG = 2;
|
||||
const char IS_FINGER_POINTING_FLAG = 4;
|
||||
|
||||
static const float MAX_AVATAR_SCALE = 1000.0f;
|
||||
static const float MIN_AVATAR_SCALE = .005f;
|
||||
|
|
|
@ -3,5 +3,5 @@ set(TARGET_NAME embedded-webserver)
|
|||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Network)
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
# call macro to include our dependency includes and bubble them up via a property on our target
|
||||
include_dependency_includes()
|
|
@ -5,33 +5,7 @@ setup_hifi_library(Widgets OpenGL Network Script)
|
|||
|
||||
include_glm()
|
||||
|
||||
link_hifi_libraries(shared gpu)
|
||||
if (APPLE)
|
||||
# link in required OS X frameworks and include the right GL headers
|
||||
find_library(OpenGL OpenGL)
|
||||
link_hifi_libraries(shared gpu script-engine render-utils)
|
||||
|
||||
#target_link_libraries(${TARGET_NAME} ${OpenGL})
|
||||
|
||||
else (APPLE)
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
if (${OPENGL_INCLUDE_DIR})
|
||||
include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
|
||||
endif ()
|
||||
|
||||
# link target to external libraries
|
||||
if (WIN32)
|
||||
find_package(GLEW REQUIRED)
|
||||
include_directories(${GLEW_INCLUDE_DIRS})
|
||||
|
||||
find_package(GLUT REQUIRED)
|
||||
include_directories(SYSTEM "${GLUT_INCLUDE_DIRS}")
|
||||
|
||||
# we're using static GLEW, so define GLEW_STATIC
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}")
|
||||
endif()
|
||||
endif (APPLE)
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
# call macro to include our dependency includes and bubble them up via a property on our target
|
||||
include_dependency_includes()
|
||||
|
|
|
@ -62,6 +62,7 @@ EntityTreeRenderer::~EntityTreeRenderer() {
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::clear() {
|
||||
leaveAllEntities();
|
||||
foreach (const EntityItemID& entityID, _entityScripts.keys()) {
|
||||
checkAndCallUnload(entityID);
|
||||
}
|
||||
|
@ -82,8 +83,7 @@ void EntityTreeRenderer::init() {
|
|||
|
||||
// make sure our "last avatar position" is something other than our current position, so that on our
|
||||
// first chance, we'll check for enter/leave entity events.
|
||||
glm::vec3 avatarPosition = _viewState->getAvatarPosition();
|
||||
_lastAvatarPosition = avatarPosition + glm::vec3(1.0f, 1.0f, 1.0f);
|
||||
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3(1.0f, 1.0f, 1.0f);
|
||||
|
||||
connect(entityTree, &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity);
|
||||
connect(entityTree, &EntityTree::addingEntity, this, &EntityTreeRenderer::checkAndCallPreload);
|
||||
|
@ -97,13 +97,15 @@ QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItem
|
|||
}
|
||||
|
||||
|
||||
QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorText) {
|
||||
QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorText, bool& isURL) {
|
||||
QUrl url(scriptMaybeURLorText);
|
||||
|
||||
// If the url is not valid, this must be script text...
|
||||
if (!url.isValid()) {
|
||||
isURL = false;
|
||||
return scriptMaybeURLorText;
|
||||
}
|
||||
isURL = true;
|
||||
|
||||
QString scriptContents; // assume empty
|
||||
|
||||
|
@ -173,7 +175,8 @@ QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) {
|
|||
return QScriptValue(); // no script
|
||||
}
|
||||
|
||||
QString scriptContents = loadScriptContents(entityScript);
|
||||
bool isURL = false; // loadScriptContents() will tell us if this is a URL or just text.
|
||||
QString scriptContents = loadScriptContents(entityScript, isURL);
|
||||
|
||||
QScriptSyntaxCheckResult syntaxCheck = QScriptEngine::checkSyntax(scriptContents);
|
||||
if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
|
||||
|
@ -184,6 +187,9 @@ QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) {
|
|||
return QScriptValue(); // invalid script
|
||||
}
|
||||
|
||||
if (isURL) {
|
||||
_entitiesScriptEngine->setParentURL(entity->getScript());
|
||||
}
|
||||
QScriptValue entityScriptConstructor = _entitiesScriptEngine->evaluate(scriptContents);
|
||||
|
||||
if (!entityScriptConstructor.isFunction()) {
|
||||
|
@ -197,6 +203,10 @@ QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) {
|
|||
EntityScriptDetails newDetails = { entityScript, entityScriptObject };
|
||||
_entityScripts[entityID] = newDetails;
|
||||
|
||||
if (isURL) {
|
||||
_entitiesScriptEngine->setParentURL("");
|
||||
}
|
||||
|
||||
return entityScriptObject; // newly constructed
|
||||
}
|
||||
|
||||
|
@ -287,6 +297,27 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::leaveAllEntities() {
|
||||
if (_tree) {
|
||||
_tree->lockForWrite(); // so that our scripts can do edits if they want
|
||||
|
||||
// for all of our previous containing entities, if they are no longer containing then send them a leave event
|
||||
foreach(const EntityItemID& entityID, _currentEntitiesInside) {
|
||||
emit leaveEntity(entityID);
|
||||
QScriptValueList entityArgs = createEntityArgs(entityID);
|
||||
QScriptValue entityScript = loadEntityScript(entityID);
|
||||
if (entityScript.property("leaveEntity").isValid()) {
|
||||
entityScript.property("leaveEntity").call(entityScript, entityArgs);
|
||||
}
|
||||
}
|
||||
_currentEntitiesInside.clear();
|
||||
|
||||
// make sure our "last avatar position" is something other than our current position, so that on our
|
||||
// first chance, we'll check for enter/leave entity events.
|
||||
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3(1.0f, 1.0f, 1.0f);
|
||||
_tree->unlock();
|
||||
}
|
||||
}
|
||||
void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) {
|
||||
if (_tree) {
|
||||
Model::startScene(renderSide);
|
||||
|
|
|
@ -129,6 +129,7 @@ private:
|
|||
|
||||
QScriptValueList createEntityArgs(const EntityItemID& entityID);
|
||||
void checkEnterLeaveEntities();
|
||||
void leaveAllEntities();
|
||||
glm::vec3 _lastAvatarPosition;
|
||||
QVector<EntityItemID> _currentEntitiesInside;
|
||||
|
||||
|
@ -138,7 +139,7 @@ private:
|
|||
QScriptValue loadEntityScript(EntityItem* entity);
|
||||
QScriptValue loadEntityScript(const EntityItemID& entityItemID);
|
||||
QScriptValue getPreviouslyLoadedEntityScript(const EntityItemID& entityItemID);
|
||||
QString loadScriptContents(const QString& scriptMaybeURLorText);
|
||||
QString loadScriptContents(const QString& scriptMaybeURLorText, bool& isURL);
|
||||
QScriptValueList createMouseEventArgs(const EntityItemID& entityID, QMouseEvent* event, unsigned int deviceID);
|
||||
QScriptValueList createMouseEventArgs(const EntityItemID& entityID, const MouseEvent& mouseEvent);
|
||||
|
||||
|
|
|
@ -28,79 +28,23 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
|
|||
glm::vec3 position = getPositionInMeters();
|
||||
glm::vec3 center = getCenter() * (float)TREE_SCALE;
|
||||
glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE;
|
||||
glm::vec3 halfDimensions = dimensions / 2.0f;
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
const bool useGlutCube = true;
|
||||
const float MAX_COLOR = 255.0f;
|
||||
|
||||
if (useGlutCube) {
|
||||
glColor4f(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR,
|
||||
getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha());
|
||||
glColor4f(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR,
|
||||
getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha());
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(1.0f);
|
||||
glPopMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(1.0f);
|
||||
glPopMatrix();
|
||||
} else {
|
||||
static GLfloat vertices[] = { 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0,v1,v2,v3 (front)
|
||||
1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0,v3,v4,v5 (right)
|
||||
1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0,v5,v6,v1 (top)
|
||||
-1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1, 1, // v1,v6,v7,v2 (left)
|
||||
-1,-1,-1, 1,-1,-1, 1,-1, 1, -1,-1, 1, // v7,v4,v3,v2 (bottom)
|
||||
1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 }; // v4,v7,v6,v5 (back)
|
||||
glPopMatrix();
|
||||
|
||||
// normal array
|
||||
static GLfloat normals[] = { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0,v1,v2,v3 (front)
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0,v3,v4,v5 (right)
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0,v5,v6,v1 (top)
|
||||
-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1,v6,v7,v2 (left)
|
||||
0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7,v4,v3,v2 (bottom)
|
||||
0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1 }; // v4,v7,v6,v5 (back)
|
||||
|
||||
// index array of vertex array for glDrawElements() & glDrawRangeElement()
|
||||
static GLubyte indices[] = { 0, 1, 2, 2, 3, 0, // front
|
||||
4, 5, 6, 6, 7, 4, // right
|
||||
8, 9,10, 10,11, 8, // top
|
||||
12,13,14, 14,15,12, // left
|
||||
16,17,18, 18,19,16, // bottom
|
||||
20,21,22, 22,23,20 }; // back
|
||||
|
||||
|
||||
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glNormalPointer(GL_FLOAT, 0, normals);
|
||||
glVertexPointer(3, GL_FLOAT, 0, vertices);
|
||||
|
||||
glColor4f(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR,
|
||||
getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha());
|
||||
|
||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
// we need to do half the size because the geometry in the VBOs are from -1,-1,-1 to 1,1,1
|
||||
glScalef(halfDimensions.x, halfDimensions.y, halfDimensions.z);
|
||||
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
|
||||
DependencyManager::get<DeferredLightingEffect>()->releaseSimpleProgram();
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -34,9 +34,9 @@ RenderableModelEntityItem::~RenderableModelEntityItem() {
|
|||
}
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
QString oldModelURL = getModelURL();
|
||||
bool somethingChanged = ModelEntityItem::setProperties(properties, forceCopy);
|
||||
bool somethingChanged = ModelEntityItem::setProperties(properties);
|
||||
if (somethingChanged && oldModelURL != getModelURL()) {
|
||||
_needsModelReload = true;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public:
|
|||
virtual ~RenderableModelEntityItem();
|
||||
|
||||
virtual EntityItemProperties getProperties() const;
|
||||
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy);
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||
|
|
|
@ -5,7 +5,7 @@ setup_hifi_library(Network Script)
|
|||
|
||||
include_glm()
|
||||
|
||||
link_hifi_libraries(shared octree fbx networking animation physics)
|
||||
link_hifi_libraries(avatars shared octree gpu model fbx networking animation physics)
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
# call macro to include our dependency includes and bubble them up via a property on our target
|
||||
include_dependency_includes()
|
||||
|
|
|
@ -29,7 +29,7 @@ BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemP
|
|||
{
|
||||
_type = EntityTypes::Box;
|
||||
_created = properties.getCreated();
|
||||
setProperties(properties, true);
|
||||
setProperties(properties);
|
||||
}
|
||||
|
||||
EntityItemProperties BoxEntityItem::getProperties() const {
|
||||
|
@ -44,9 +44,9 @@ EntityItemProperties BoxEntityItem::getProperties() const {
|
|||
return properties;
|
||||
}
|
||||
|
||||
bool BoxEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
bool BoxEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = false;
|
||||
somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
|
||||
somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties() const;
|
||||
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
|
||||
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
|
||||
|
|
|
@ -141,6 +141,13 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) {
|
|||
penetration = collision->_penetration;
|
||||
entityB = static_cast<EntityItem*>(collision->_extraData);
|
||||
|
||||
// The collision _extraData should be a valid entity, but if for some reason
|
||||
// it's NULL then continue with a warning.
|
||||
if (!entityB) {
|
||||
qDebug() << "UNEXPECTED - we have a collision with missing _extraData. Something went wrong down below!";
|
||||
continue; // skip this loop pass if the entity is NULL
|
||||
}
|
||||
|
||||
// don't collide entities with unknown IDs,
|
||||
if (!entityB->isKnownID()) {
|
||||
continue; // skip this loop pass if the entity has an unknown ID
|
||||
|
|
|
@ -53,14 +53,13 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
|
|||
_creatorTokenID = entityItemID.creatorTokenID;
|
||||
|
||||
// init values with defaults before calling setProperties
|
||||
//uint64_t now = usecTimestampNow();
|
||||
quint64 now = usecTimestampNow();
|
||||
_lastSimulated = now;
|
||||
_lastUpdated = now;
|
||||
_lastEdited = 0;
|
||||
_lastEditedFromRemote = 0;
|
||||
_lastEditedFromRemoteInRemoteTime = 0;
|
||||
|
||||
_lastSimulated = 0;
|
||||
_lastUpdated = 0;
|
||||
_created = 0; // TODO: when do we actually want to make this "now"
|
||||
_created = UNKNOWN_CREATED_TIME;
|
||||
_changedOnServer = 0;
|
||||
|
||||
_position = glm::vec3(0,0,0);
|
||||
|
@ -86,12 +85,13 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
|
|||
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID) {
|
||||
_type = EntityTypes::Unknown;
|
||||
quint64 now = usecTimestampNow();
|
||||
_lastSimulated = now;
|
||||
_lastUpdated = now;
|
||||
_lastEdited = 0;
|
||||
_lastEditedFromRemote = 0;
|
||||
_lastEditedFromRemoteInRemoteTime = 0;
|
||||
_lastSimulated = 0;
|
||||
_lastUpdated = 0;
|
||||
_created = 0;
|
||||
_created = UNKNOWN_CREATED_TIME;
|
||||
_dirtyFlags = 0;
|
||||
_changedOnServer = 0;
|
||||
initFromEntityItemID(entityItemID);
|
||||
|
@ -99,16 +99,17 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) {
|
|||
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) {
|
||||
_type = EntityTypes::Unknown;
|
||||
quint64 now = usecTimestampNow();
|
||||
_lastSimulated = now;
|
||||
_lastUpdated = now;
|
||||
_lastEdited = 0;
|
||||
_lastEditedFromRemote = 0;
|
||||
_lastEditedFromRemoteInRemoteTime = 0;
|
||||
_lastSimulated = 0;
|
||||
_lastUpdated = 0;
|
||||
_created = properties.getCreated();
|
||||
_created = UNKNOWN_CREATED_TIME;
|
||||
_dirtyFlags = 0;
|
||||
_changedOnServer = 0;
|
||||
initFromEntityItemID(entityItemID);
|
||||
setProperties(properties, true); // force copy
|
||||
setProperties(properties);
|
||||
}
|
||||
|
||||
EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
|
||||
|
@ -365,9 +366,16 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
memcpy(&createdFromBuffer, dataAt, sizeof(createdFromBuffer));
|
||||
dataAt += sizeof(createdFromBuffer);
|
||||
bytesRead += sizeof(createdFromBuffer);
|
||||
createdFromBuffer -= clockSkew;
|
||||
|
||||
_created = createdFromBuffer; // TODO: do we ever want to discard this???
|
||||
|
||||
quint64 now = usecTimestampNow();
|
||||
if (_created == UNKNOWN_CREATED_TIME) {
|
||||
// we don't yet have a _created timestamp, so we accept this one
|
||||
createdFromBuffer -= clockSkew;
|
||||
if (createdFromBuffer > now || createdFromBuffer == UNKNOWN_CREATED_TIME) {
|
||||
createdFromBuffer = now;
|
||||
}
|
||||
_created = createdFromBuffer;
|
||||
}
|
||||
|
||||
if (wantDebug) {
|
||||
quint64 lastEdited = getLastEdited();
|
||||
|
@ -381,7 +389,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
qDebug() << " ago=" << editedAgo << "seconds - " << agoAsString;
|
||||
}
|
||||
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 lastEditedFromBuffer = 0;
|
||||
quint64 lastEditedFromBufferAdjusted = 0;
|
||||
|
||||
|
@ -391,6 +398,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
dataAt += sizeof(lastEditedFromBuffer);
|
||||
bytesRead += sizeof(lastEditedFromBuffer);
|
||||
lastEditedFromBufferAdjusted = lastEditedFromBuffer - clockSkew;
|
||||
if (lastEditedFromBufferAdjusted > now) {
|
||||
lastEditedFromBufferAdjusted = now;
|
||||
}
|
||||
|
||||
bool fromSameServerEdit = (lastEditedFromBuffer == _lastEditedFromRemoteInRemoteTime);
|
||||
|
||||
|
@ -439,10 +449,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
qDebug() << "USING NEW data from server!!! ****************";
|
||||
}
|
||||
|
||||
// don't allow _lastEdited to be in the future
|
||||
_lastEdited = lastEditedFromBufferAdjusted;
|
||||
_lastEditedFromRemote = now;
|
||||
_lastEditedFromRemoteInRemoteTime = lastEditedFromBuffer;
|
||||
|
||||
// TODO: only send this notification if something ACTUALLY changed (hint, we haven't yet parsed
|
||||
// the properties out of the bitstream (see below))
|
||||
somethingChangedNotification(); // notify derived classes that something has changed
|
||||
}
|
||||
|
||||
|
@ -451,7 +464,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
|
||||
quint64 updateDelta = updateDeltaCoder;
|
||||
if (overwriteLocalData) {
|
||||
_lastSimulated = _lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited
|
||||
_lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that
|
||||
if (wantDebug) {
|
||||
qDebug() << "_lastUpdated =" << _lastUpdated;
|
||||
qDebug() << "_lastEdited=" << _lastEdited;
|
||||
|
@ -523,6 +536,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
|
||||
|
||||
recalculateCollisionShape();
|
||||
if (overwriteLocalData && (getDirtyFlags() & EntityItem::DIRTY_POSITION)) {
|
||||
_lastSimulated = now;
|
||||
}
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
@ -576,7 +592,7 @@ void EntityItem::simulate(const quint64& now) {
|
|||
float timeElapsed = (float)(now - _lastSimulated) / (float)(USECS_PER_SECOND);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << "********** EntityItem::update()";
|
||||
qDebug() << "********** EntityItem::simulate()";
|
||||
qDebug() << " entity ID=" << getEntityItemID();
|
||||
qDebug() << " now=" << now;
|
||||
qDebug() << " _lastSimulated=" << _lastSimulated;
|
||||
|
@ -612,10 +628,8 @@ void EntityItem::simulate(const quint64& now) {
|
|||
}
|
||||
}
|
||||
|
||||
_lastSimulated = now;
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " ********** EntityItem::update() .... SETTING _lastSimulated=" << _lastSimulated;
|
||||
qDebug() << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated;
|
||||
}
|
||||
|
||||
if (hasAngularVelocity()) {
|
||||
|
@ -651,7 +665,7 @@ void EntityItem::simulate(const quint64& now) {
|
|||
glm::vec3 newPosition = position + (velocity * timeElapsed);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " EntityItem::update()....";
|
||||
qDebug() << " EntityItem::simulate()....";
|
||||
qDebug() << " timeElapsed:" << timeElapsed;
|
||||
qDebug() << " old AACube:" << getMaximumAACube();
|
||||
qDebug() << " old position:" << position;
|
||||
|
@ -677,15 +691,15 @@ void EntityItem::simulate(const quint64& now) {
|
|||
}
|
||||
|
||||
// handle gravity....
|
||||
if (hasGravity() && !isRestingOnSurface()) {
|
||||
velocity += getGravity() * timeElapsed;
|
||||
}
|
||||
|
||||
// handle resting on surface case, this is definitely a bit of a hack, and it only works on the
|
||||
// "ground" plane of the domain, but for now it
|
||||
if (hasGravity() && isRestingOnSurface()) {
|
||||
velocity.y = 0.0f;
|
||||
position.y = getDistanceToBottomOfEntity();
|
||||
if (hasGravity()) {
|
||||
// handle resting on surface case, this is definitely a bit of a hack, and it only works on the
|
||||
// "ground" plane of the domain, but for now it what we've got
|
||||
if (isRestingOnSurface()) {
|
||||
velocity.y = 0.0f;
|
||||
position.y = getDistanceToBottomOfEntity();
|
||||
} else {
|
||||
velocity += getGravity() * timeElapsed;
|
||||
}
|
||||
}
|
||||
|
||||
// handle damping for velocity
|
||||
|
@ -721,6 +735,8 @@ void EntityItem::simulate(const quint64& now) {
|
|||
qDebug() << " old getAABox:" << getAABox();
|
||||
}
|
||||
}
|
||||
|
||||
_lastSimulated = now;
|
||||
}
|
||||
|
||||
bool EntityItem::isMoving() const {
|
||||
|
@ -768,18 +784,9 @@ EntityItemProperties EntityItem::getProperties() const {
|
|||
return properties;
|
||||
}
|
||||
|
||||
bool EntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = false;
|
||||
|
||||
// handle the setting of created timestamps for the basic new entity case
|
||||
if (forceCopy) {
|
||||
if (properties.getCreated() == UNKNOWN_CREATED_TIME) {
|
||||
_created = usecTimestampNow();
|
||||
} else if (properties.getCreated() != USE_EXISTING_CREATED_TIME) {
|
||||
_created = properties.getCreated();
|
||||
}
|
||||
}
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePositionInMeters); // this will call recalculate collision shape if needed
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensionsInMeters); // NOTE: radius is obsolete
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation);
|
||||
|
@ -803,18 +810,49 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc
|
|||
if (somethingChanged) {
|
||||
somethingChangedNotification(); // notify derived classes that something has changed
|
||||
bool wantDebug = false;
|
||||
uint64_t now = usecTimestampNow();
|
||||
if (wantDebug) {
|
||||
uint64_t now = usecTimestampNow();
|
||||
int elapsed = now - getLastEdited();
|
||||
qDebug() << "EntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
|
||||
"now=" << now << " getLastEdited()=" << getLastEdited();
|
||||
}
|
||||
setLastEdited(properties._lastEdited);
|
||||
if (_created != UNKNOWN_CREATED_TIME) {
|
||||
setLastEdited(now);
|
||||
}
|
||||
if (getDirtyFlags() & EntityItem::DIRTY_POSITION) {
|
||||
_lastSimulated = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// timestamps
|
||||
quint64 timestamp = properties.getCreated();
|
||||
if (_created == UNKNOWN_CREATED_TIME && timestamp != UNKNOWN_CREATED_TIME) {
|
||||
quint64 now = usecTimestampNow();
|
||||
if (timestamp > now) {
|
||||
timestamp = now;
|
||||
}
|
||||
_created = timestamp;
|
||||
|
||||
timestamp = properties.getLastEdited();
|
||||
if (timestamp > now) {
|
||||
timestamp = now;
|
||||
} else if (timestamp < _created) {
|
||||
timestamp = _created;
|
||||
}
|
||||
_lastEdited = timestamp;
|
||||
}
|
||||
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
void EntityItem::recordCreationTime() {
|
||||
assert(_created == UNKNOWN_CREATED_TIME);
|
||||
_created = usecTimestampNow();
|
||||
_lastEdited = _created;
|
||||
_lastUpdated = _created;
|
||||
_lastSimulated = _created;
|
||||
}
|
||||
|
||||
|
||||
// TODO: is this really correct? how do we use size, does it need to handle rotation?
|
||||
float EntityItem::getSize() const {
|
||||
|
|
|
@ -74,18 +74,19 @@ public:
|
|||
virtual EntityItemProperties getProperties() const;
|
||||
|
||||
/// returns true if something changed
|
||||
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
|
||||
/// Override this in your derived class if you'd like to be informed when something about the state of the entity
|
||||
/// has changed. This will be called with properties change or when new data is loaded from a stream
|
||||
virtual void somethingChangedNotification() { }
|
||||
|
||||
void recordCreationTime(); // set _created to 'now'
|
||||
quint64 getLastSimulated() const { return _lastSimulated; } /// Last simulated time of this entity universal usecs
|
||||
|
||||
/// Last edited time of this entity universal usecs
|
||||
quint64 getLastEdited() const { return _lastEdited; }
|
||||
void setLastEdited(quint64 lastEdited)
|
||||
{ _lastEdited = _lastSimulated = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); }
|
||||
{ _lastEdited = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); }
|
||||
float getEditedAgo() const /// Elapsed seconds since this entity was last edited
|
||||
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
|
||||
|
||||
|
@ -120,9 +121,6 @@ public:
|
|||
|
||||
static int expectedBytes();
|
||||
|
||||
static bool encodeEntityEditMessageDetails(PacketType command, EntityItemID id, const EntityItemProperties& details,
|
||||
unsigned char* bufferOut, int sizeIn, int& sizeOut);
|
||||
|
||||
static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew);
|
||||
|
||||
// perform update
|
||||
|
|
|
@ -156,6 +156,17 @@ void EntityItemProperties::debugDump() const {
|
|||
props.debugDumpBits();
|
||||
}
|
||||
|
||||
void EntityItemProperties::setCreated(quint64 usecTime) {
|
||||
_created = usecTime;
|
||||
if (_lastEdited < _created) {
|
||||
_lastEdited = _created;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItemProperties::setLastEdited(quint64 usecTime) {
|
||||
_lastEdited = usecTime > _created ? usecTime : _created;
|
||||
}
|
||||
|
||||
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||
EntityPropertyFlags changedProperties;
|
||||
|
||||
|
@ -652,9 +663,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
entityID.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
|
||||
entityID.isKnownID = true;
|
||||
valid = true;
|
||||
|
||||
// created time is lastEdited time
|
||||
properties.setCreated(USE_EXISTING_CREATED_TIME);
|
||||
}
|
||||
|
||||
// Entity Type...
|
||||
|
|
|
@ -95,9 +95,7 @@ enum EntityPropertyList {
|
|||
|
||||
typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
|
||||
|
||||
const quint64 UNKNOWN_CREATED_TIME = (quint64)(-1);
|
||||
const quint64 USE_EXISTING_CREATED_TIME = (quint64)(-2);
|
||||
|
||||
const quint64 UNKNOWN_CREATED_TIME = 0;
|
||||
|
||||
/// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an
|
||||
/// entity and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete
|
||||
|
@ -134,7 +132,7 @@ public:
|
|||
AABox getAABoxInMeters() const;
|
||||
|
||||
void debugDump() const;
|
||||
void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; }
|
||||
void setLastEdited(quint64 usecTime);
|
||||
|
||||
DEFINE_PROPERTY(PROP_VISIBLE, Visible, visible, bool);
|
||||
DEFINE_PROPERTY_REF_WITH_SETTER(PROP_POSITION, Position, position, glm::vec3);
|
||||
|
@ -180,7 +178,7 @@ public:
|
|||
|
||||
float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
|
||||
quint64 getCreated() const { return _created; }
|
||||
void setCreated(quint64 usecTime) { _created = usecTime; }
|
||||
void setCreated(quint64 usecTime);
|
||||
bool hasCreatedTime() const { return (_created != UNKNOWN_CREATED_TIME); }
|
||||
|
||||
bool containsBoundsProperties() const { return (_positionChanged || _dimensionsChanged); }
|
||||
|
|
|
@ -137,13 +137,13 @@
|
|||
}
|
||||
|
||||
#define SET_ENTITY_PROPERTY_FROM_PROPERTIES(P,M) \
|
||||
if (properties._##P##Changed || forceCopy) { \
|
||||
if (properties._##P##Changed) { \
|
||||
M(properties._##P); \
|
||||
somethingChanged = true; \
|
||||
}
|
||||
|
||||
#define SET_ENTITY_PROPERTY_FROM_PROPERTIES_GETTER(C,G,S) \
|
||||
if (properties.C() || forceCopy) { \
|
||||
if (properties.C()) { \
|
||||
S(properties.G()); \
|
||||
somethingChanged = true; \
|
||||
}
|
||||
|
|
|
@ -164,9 +164,17 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem
|
|||
|
||||
// NOTE: This method is used in the client and the server tree. In the client, it's possible to create EntityItems
|
||||
// that do not yet have known IDs. In the server tree however we don't want to have entities without known IDs.
|
||||
if (getIsServer() && !entityID.isKnownID) {
|
||||
qDebug() << "UNEXPECTED!!! ----- EntityTree::addEntity()... (getIsSever() && !entityID.isKnownID)";
|
||||
return result;
|
||||
bool recordCreationTime = false;
|
||||
if (!entityID.isKnownID) {
|
||||
if (getIsServer()) {
|
||||
qDebug() << "UNEXPECTED!!! ----- EntityTree::addEntity()... (getIsSever() && !entityID.isKnownID)";
|
||||
return result;
|
||||
}
|
||||
if (properties.getCreated() == UNKNOWN_CREATED_TIME) {
|
||||
// the entity's creation time was not specified in properties, which means this is a NEW entity
|
||||
// and we must record its creation time
|
||||
recordCreationTime = true;
|
||||
}
|
||||
}
|
||||
|
||||
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
|
||||
|
@ -182,6 +190,9 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem
|
|||
result = EntityTypes::constructEntityItem(type, entityID, properties);
|
||||
|
||||
if (result) {
|
||||
if (recordCreationTime) {
|
||||
result->recordCreationTime();
|
||||
}
|
||||
// Recurse the tree and store the entity in the correct tree element
|
||||
AddEntityOperator theOperator(this, result);
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
|
|
|
@ -585,8 +585,12 @@ bool EntityTreeElement::findShapeCollisions(const Shape* shape, CollisionList& c
|
|||
if (shape != otherCollisionShape && !ignoreForCollisions) {
|
||||
if (ShapeCollider::collideShapes(shape, otherCollisionShape, collisions)) {
|
||||
CollisionInfo* lastCollision = collisions.getLastCollision();
|
||||
lastCollision->_extraData = entity;
|
||||
atLeastOneCollision = true;
|
||||
if (lastCollision) {
|
||||
lastCollision->_extraData = entity;
|
||||
atLeastOneCollision = true;
|
||||
} else {
|
||||
qDebug() << "UNEXPECTED - ShapeCollider::collideShapes() returned true, but no lastCollision.";
|
||||
}
|
||||
}
|
||||
}
|
||||
++entityItr;
|
||||
|
|
|
@ -71,22 +71,13 @@ bool EntityTypes::registerEntityType(EntityType entityType, const char* name, En
|
|||
|
||||
EntityItem* EntityTypes::constructEntityItem(EntityType entityType, const EntityItemID& entityID,
|
||||
const EntityItemProperties& properties) {
|
||||
|
||||
EntityItem* newEntityItem = NULL;
|
||||
EntityTypeFactory factory = NULL;
|
||||
if (entityType >= 0 && entityType <= LAST) {
|
||||
factory = _factories[entityType];
|
||||
}
|
||||
if (factory) {
|
||||
// NOTE: if someone attempts to create an entity with properties that do not include a proper "created" time
|
||||
// then set the created time to now
|
||||
if (!properties.hasCreatedTime()) {
|
||||
EntityItemProperties mutableProperties = properties;
|
||||
mutableProperties.setCreated(usecTimestampNow());
|
||||
newEntityItem = factory(entityID, mutableProperties);
|
||||
} else {
|
||||
newEntityItem = factory(entityID, properties);
|
||||
}
|
||||
newEntityItem = factory(entityID, properties);
|
||||
}
|
||||
return newEntityItem;
|
||||
}
|
||||
|
@ -129,8 +120,6 @@ EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int byte
|
|||
|
||||
EntityItemID tempEntityID(actualID);
|
||||
EntityItemProperties tempProperties;
|
||||
tempProperties.setCreated(usecTimestampNow()); // this is temporary...
|
||||
|
||||
return constructEntityItem(entityType, tempEntityID, tempProperties);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityI
|
|||
_exponent = 0.0f;
|
||||
_cutoff = PI;
|
||||
|
||||
setProperties(properties, true);
|
||||
setProperties(properties);
|
||||
|
||||
// a light is not collide-able so we make it's shape be a tiny sphere at origin
|
||||
_emptyShape.setTranslation(glm::vec3(0.0f, 0.0f, 0.0f));
|
||||
|
@ -71,8 +71,8 @@ EntityItemProperties LightEntityItem::getProperties() const {
|
|||
return properties;
|
||||
}
|
||||
|
||||
bool LightEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
bool somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
|
||||
bool LightEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(diffuseColor, setDiffuseColor);
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties() const;
|
||||
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
|
||||
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityI
|
|||
EntityItem(entityItemID, properties)
|
||||
{
|
||||
_type = EntityTypes::Model;
|
||||
setProperties(properties, true);
|
||||
setProperties(properties);
|
||||
_lastAnimated = usecTimestampNow();
|
||||
_jointMappingCompleted = false;
|
||||
_color[0] = _color[1] = _color[2] = 0;
|
||||
|
@ -55,9 +55,9 @@ EntityItemProperties ModelEntityItem::getProperties() const {
|
|||
return properties;
|
||||
}
|
||||
|
||||
bool ModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = false;
|
||||
somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
|
||||
somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL);
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties() const;
|
||||
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
|
||||
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
|
||||
|
|
|
@ -31,7 +31,7 @@ SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID, const Entit
|
|||
EntityItem(entityItemID, properties)
|
||||
{
|
||||
_type = EntityTypes::Sphere;
|
||||
setProperties(properties, true);
|
||||
setProperties(properties);
|
||||
}
|
||||
|
||||
EntityItemProperties SphereEntityItem::getProperties() const {
|
||||
|
@ -40,8 +40,8 @@ EntityItemProperties SphereEntityItem::getProperties() const {
|
|||
return properties;
|
||||
}
|
||||
|
||||
bool SphereEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
bool somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
|
||||
bool SphereEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties() const;
|
||||
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
|
||||
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID, const EntityIte
|
|||
{
|
||||
_type = EntityTypes::Text;
|
||||
_created = properties.getCreated();
|
||||
setProperties(properties, true);
|
||||
setProperties(properties);
|
||||
}
|
||||
|
||||
void TextEntityItem::setDimensions(const glm::vec3& value) {
|
||||
|
@ -57,9 +57,9 @@ EntityItemProperties TextEntityItem::getProperties() const {
|
|||
return properties;
|
||||
}
|
||||
|
||||
bool TextEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||
bool TextEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = false;
|
||||
somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
|
||||
somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(text, setText);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineHeight, setLineHeight);
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties() const;
|
||||
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
|
||||
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
|
||||
|
|
|
@ -5,11 +5,11 @@ setup_hifi_library()
|
|||
|
||||
include_glm()
|
||||
|
||||
link_hifi_libraries(shared networking octree voxels)
|
||||
link_hifi_libraries(shared gpu model networking octree voxels)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")
|
||||
list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}")
|
||||
target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
# call macro to include our dependency includes and bubble them up via a property on our target
|
||||
include_dependency_includes()
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
class QIODevice;
|
||||
#include <model/Geometry.h>
|
||||
#include <model/Material.h>
|
||||
|
||||
class QIODevice;
|
||||
class FBXNode;
|
||||
|
||||
typedef QList<FBXNode> FBXNodeList;
|
||||
|
@ -131,6 +133,7 @@ public:
|
|||
FBXTexture emissiveTexture;
|
||||
|
||||
QString materialID;
|
||||
model::MaterialPointer _material;
|
||||
};
|
||||
|
||||
/// A single mesh (with optional blendshapes) extracted from an FBX document.
|
||||
|
@ -159,6 +162,8 @@ public:
|
|||
|
||||
bool hasSpecularTexture() const;
|
||||
bool hasEmissiveTexture() const;
|
||||
|
||||
model::Mesh _mesh;
|
||||
};
|
||||
|
||||
/// A single animation frame extracted from an FBX document.
|
||||
|
|
|
@ -6,13 +6,32 @@ setup_hifi_library()
|
|||
include_glm()
|
||||
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
if (APPLE)
|
||||
# link in required OS X frameworks and include the right GL headers
|
||||
find_library(OpenGL OpenGL)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${OpenGL})
|
||||
|
||||
else (APPLE)
|
||||
elseif (WIN32)
|
||||
find_package(GLEW REQUIRED)
|
||||
include_directories(${GLEW_INCLUDE_DIRS})
|
||||
|
||||
# we're using static GLEW, so define GLEW_STATIC
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} opengl32.lib)
|
||||
|
||||
# need to bubble up the GLEW_INCLUDE_DIRS
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_INCLUDES "${GLEW_INCLUDE_DIRS}")
|
||||
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
find_package(NSIGHT)
|
||||
if (NSIGHT_FOUND)
|
||||
include_directories(${NSIGHT_INCLUDE_DIRS})
|
||||
add_definitions(-DNSIGHT_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
|
||||
endif ()
|
||||
else ()
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
if (${OPENGL_INCLUDE_DIR})
|
||||
|
@ -21,26 +40,9 @@ else (APPLE)
|
|||
|
||||
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
|
||||
|
||||
# link target to external libraries
|
||||
if (WIN32)
|
||||
find_package(GLEW REQUIRED)
|
||||
include_directories(${GLEW_INCLUDE_DIRS})
|
||||
|
||||
# we're using static GLEW, so define GLEW_STATIC
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" "${NSIGHT_LIBRARIES}" opengl32.lib)
|
||||
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
find_package(NSIGHT)
|
||||
if (NSIGHT_FOUND)
|
||||
include_directories(${NSIGHT_INCLUDE_DIRS})
|
||||
add_definitions(-DNSIGHT_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
|
||||
endif ()
|
||||
|
||||
endif()
|
||||
# need to bubble up the OPENGL_INCLUDE_DIR
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_INCLUDES "${OPENGL_INCLUDE_DIR}")
|
||||
endif (APPLE)
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
# call macro to include our dependency includes and bubble them up via a property on our target
|
||||
include_dependency_includes()
|
||||
|
|
|
@ -107,6 +107,19 @@ void Batch::setInputFormat(const Stream::FormatPointer& format) {
|
|||
_params.push_back(_streamFormats.cache(format));
|
||||
}
|
||||
|
||||
void Batch::setInputBuffer(Slot channel, const BufferPointer& buffer, Offset offset, Offset stride) {
|
||||
ADD_COMMAND(setInputBuffer);
|
||||
|
||||
_params.push_back(stride);
|
||||
_params.push_back(offset);
|
||||
_params.push_back(_buffers.cache(buffer));
|
||||
_params.push_back(channel);
|
||||
}
|
||||
|
||||
void Batch::setInputBuffer(Slot channel, const BufferView& view) {
|
||||
setInputBuffer(channel, view._buffer, view._offset, Offset(view._stride));
|
||||
}
|
||||
|
||||
void Batch::setInputStream(Slot startChannel, const BufferStream& stream) {
|
||||
if (stream.getNumBuffers()) {
|
||||
const Buffers& buffers = stream.getBuffers();
|
||||
|
@ -118,15 +131,6 @@ void Batch::setInputStream(Slot startChannel, const BufferStream& stream) {
|
|||
}
|
||||
}
|
||||
|
||||
void Batch::setInputBuffer(Slot channel, const BufferPointer& buffer, Offset offset, Offset stride) {
|
||||
ADD_COMMAND(setInputBuffer);
|
||||
|
||||
_params.push_back(stride);
|
||||
_params.push_back(offset);
|
||||
_params.push_back(_buffers.cache(buffer));
|
||||
_params.push_back(channel);
|
||||
}
|
||||
|
||||
void Batch::setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset) {
|
||||
ADD_COMMAND(setIndexBuffer);
|
||||
|
||||
|
@ -153,3 +157,17 @@ void Batch::setProjectionTransform(const Transform& proj) {
|
|||
_params.push_back(_transforms.cache(proj));
|
||||
}
|
||||
|
||||
void Batch::setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size) {
|
||||
ADD_COMMAND(setUniformBuffer);
|
||||
|
||||
_params.push_back(size);
|
||||
_params.push_back(offset);
|
||||
_params.push_back(_buffers.cache(buffer));
|
||||
_params.push_back(slot);
|
||||
}
|
||||
|
||||
void Batch::setUniformBuffer(uint32 slot, const BufferView& view) {
|
||||
setUniformBuffer(slot, view._buffer, view._offset, view._size);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -72,8 +72,9 @@ public:
|
|||
// IndexBuffer
|
||||
void setInputFormat(const Stream::FormatPointer& format);
|
||||
|
||||
void setInputStream(Slot startChannel, const BufferStream& stream); // not a command, just unroll into a loop of setInputBuffer
|
||||
void setInputBuffer(Slot channel, const BufferPointer& buffer, Offset offset, Offset stride);
|
||||
void setInputBuffer(Slot channel, const BufferView& buffer); // not a command, just a shortcut from a BufferView
|
||||
void setInputStream(Slot startChannel, const BufferStream& stream); // not a command, just unroll into a loop of setInputBuffer
|
||||
|
||||
void setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset);
|
||||
|
||||
|
@ -87,6 +88,9 @@ public:
|
|||
void setViewTransform(const Transform& view);
|
||||
void setProjectionTransform(const Transform& proj);
|
||||
|
||||
// Shader Stage
|
||||
void setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size);
|
||||
void setUniformBuffer(uint32 slot, const BufferView& view); // not a command, just a shortcut from a BufferView
|
||||
|
||||
// TODO: As long as we have gl calls explicitely issued from interface
|
||||
// code, we need to be able to record and batch these calls. THe long
|
||||
|
@ -117,6 +121,7 @@ public:
|
|||
void _glUseProgram(GLuint program);
|
||||
void _glUniform1f(GLint location, GLfloat v0);
|
||||
void _glUniform2f(GLint location, GLfloat v0, GLfloat v1);
|
||||
void _glUniform4fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void _glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
|
||||
void _glMatrixMode(GLenum mode);
|
||||
|
@ -161,6 +166,8 @@ public:
|
|||
COMMAND_setViewTransform,
|
||||
COMMAND_setProjectionTransform,
|
||||
|
||||
COMMAND_setUniformBuffer,
|
||||
|
||||
// TODO: As long as we have gl calls explicitely issued from interface
|
||||
// code, we need to be able to record and batch these calls. THe long
|
||||
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
||||
|
@ -187,6 +194,7 @@ public:
|
|||
COMMAND_glUseProgram,
|
||||
COMMAND_glUniform1f,
|
||||
COMMAND_glUniform2f,
|
||||
COMMAND_glUniform4fv,
|
||||
COMMAND_glUniformMatrix4fv,
|
||||
|
||||
COMMAND_glMatrixMode,
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#define hifi_gpu_Context_h
|
||||
|
||||
#include <assert.h>
|
||||
#include "GPUConfig.h"
|
||||
|
||||
#include "Resource.h"
|
||||
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#define hifi_gpu_Format_h
|
||||
|
||||
#include <assert.h>
|
||||
#include "GPUConfig.h"
|
||||
|
||||
|
||||
namespace gpu {
|
||||
|
||||
|
@ -94,7 +92,8 @@ static const int DIMENSION_COUNT[NUM_DIMENSIONS] = {
|
|||
// Semantic of an Element
|
||||
// Provide information on how to use the element
|
||||
enum Semantic {
|
||||
RGB = 0,
|
||||
RAW = 0, // used as RAW memory
|
||||
RGB,
|
||||
RGBA,
|
||||
XYZ,
|
||||
XYZW,
|
||||
|
@ -104,6 +103,8 @@ enum Semantic {
|
|||
DIR_XYZ,
|
||||
UV,
|
||||
R8,
|
||||
INDEX, //used by index buffer of a mesh
|
||||
PART, // used by part buffer of a mesh
|
||||
|
||||
NUM_SEMANTICS,
|
||||
};
|
||||
|
@ -119,7 +120,7 @@ public:
|
|||
_type(type)
|
||||
{}
|
||||
Element() :
|
||||
_semantic(R8),
|
||||
_semantic(RAW),
|
||||
_dimension(SCALAR),
|
||||
_type(INT8)
|
||||
{}
|
||||
|
|
|
@ -31,6 +31,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::GLBackend::do_setViewTransform),
|
||||
(&::gpu::GLBackend::do_setProjectionTransform),
|
||||
|
||||
(&::gpu::GLBackend::do_setUniformBuffer),
|
||||
|
||||
(&::gpu::GLBackend::do_glEnable),
|
||||
(&::gpu::GLBackend::do_glDisable),
|
||||
|
||||
|
@ -54,6 +56,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::GLBackend::do_glUseProgram),
|
||||
(&::gpu::GLBackend::do_glUniform1f),
|
||||
(&::gpu::GLBackend::do_glUniform2f),
|
||||
(&::gpu::GLBackend::do_glUniform4fv),
|
||||
(&::gpu::GLBackend::do_glUniformMatrix4fv),
|
||||
|
||||
(&::gpu::GLBackend::do_glMatrixMode),
|
||||
|
@ -483,6 +486,25 @@ void GLBackend::updateTransform() {
|
|||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 3]._uint;
|
||||
BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
|
||||
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
|
||||
#if defined(Q_OS_MAC)
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
#else
|
||||
GLuint bo = getBufferID(*uniformBuffer);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize);
|
||||
|
||||
// glUniformBufferEXT(_shader._program, slot, bo);
|
||||
|
||||
//glBindBufferBase(GL_UNIFORM_BUFFER, slot, bo);
|
||||
#endif
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
// TODO: As long as we have gl calls explicitely issued from interface
|
||||
// code, we need to be able to record and batch these calls. THe long
|
||||
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
||||
|
@ -672,7 +694,10 @@ void Batch::_glUseProgram(GLuint program) {
|
|||
DO_IT_NOW(_glUseProgram, 1);
|
||||
}
|
||||
void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) {
|
||||
glUseProgram(batch._params[paramOffset]._uint);
|
||||
|
||||
_shader._program = batch._params[paramOffset]._uint;
|
||||
glUseProgram(_shader._program);
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
@ -708,6 +733,25 @@ void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) {
|
|||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void Batch::_glUniform4fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
ADD_COMMAND_GL(glUniform4fv);
|
||||
|
||||
const int VEC4_SIZE = 4 * sizeof(float);
|
||||
_params.push_back(cacheData(count * VEC4_SIZE, value));
|
||||
_params.push_back(count);
|
||||
_params.push_back(location);
|
||||
|
||||
DO_IT_NOW(_glUniform4fv, 3);
|
||||
}
|
||||
void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) {
|
||||
glUniform4fv(
|
||||
batch._params[paramOffset + 2]._int,
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint));
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void Batch::_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
ADD_COMMAND_GL(glUniformMatrix4fv);
|
||||
|
||||
|
|
|
@ -122,6 +122,19 @@ protected:
|
|||
_lastMode(GL_TEXTURE) {}
|
||||
} _transform;
|
||||
|
||||
// Shader Stage
|
||||
void do_setUniformBuffer(Batch& batch, uint32 paramOffset);
|
||||
|
||||
void updateShader();
|
||||
struct ShaderStageState {
|
||||
|
||||
GLuint _program;
|
||||
|
||||
ShaderStageState() :
|
||||
_program(0) {}
|
||||
} _shader;
|
||||
|
||||
|
||||
// TODO: As long as we have gl calls explicitely issued from interface
|
||||
// code, we need to be able to record and batch these calls. THe long
|
||||
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
||||
|
@ -148,6 +161,7 @@ protected:
|
|||
void do_glUseProgram(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform1f(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform2f(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform4fv(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset);
|
||||
|
||||
void do_glMatrixMode(Batch& batch, uint32 paramOffset);
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// GPUConfig.h
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/17/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef gpu__GLUTConfig__
|
||||
#define gpu__GLUTConfig__
|
||||
|
||||
// TODO: remove these once we migrate away from GLUT calls
|
||||
#if defined(__APPLE__)
|
||||
#include <GLUT/glut.h>
|
||||
#elif defined(WIN32)
|
||||
#include <GL/glut.h>
|
||||
#else
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
|
||||
#endif // gpu__GLUTConfig__
|
|
@ -67,6 +67,26 @@ Resource::Sysmem::Sysmem(Size size, const Byte* bytes) :
|
|||
}
|
||||
}
|
||||
|
||||
Resource::Sysmem::Sysmem(const Sysmem& sysmem) :
|
||||
_stamp(0),
|
||||
_size(0),
|
||||
_data(NULL)
|
||||
{
|
||||
if (sysmem.getSize() > 0) {
|
||||
_size = allocateMemory(&_data, sysmem.getSize());
|
||||
if (_size >= sysmem.getSize()) {
|
||||
if (sysmem.readData()) {
|
||||
memcpy(_data, sysmem.readData(), sysmem.getSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Resource::Sysmem& Resource::Sysmem::operator=(const Sysmem& sysmem) {
|
||||
setData(sysmem.getSize(), sysmem.readData());
|
||||
return (*this);
|
||||
}
|
||||
|
||||
Resource::Sysmem::~Sysmem() {
|
||||
deallocateMemory( _data, _size );
|
||||
_data = NULL;
|
||||
|
@ -75,7 +95,7 @@ Resource::Sysmem::~Sysmem() {
|
|||
|
||||
Resource::Size Resource::Sysmem::allocate(Size size) {
|
||||
if (size != _size) {
|
||||
Byte* newData = 0;
|
||||
Byte* newData = NULL;
|
||||
Size newSize = 0;
|
||||
if (size > 0) {
|
||||
Size allocated = allocateMemory(&newData, size);
|
||||
|
@ -96,7 +116,7 @@ Resource::Size Resource::Sysmem::allocate(Size size) {
|
|||
|
||||
Resource::Size Resource::Sysmem::resize(Size size) {
|
||||
if (size != _size) {
|
||||
Byte* newData = 0;
|
||||
Byte* newData = NULL;
|
||||
Size newSize = 0;
|
||||
if (size > 0) {
|
||||
Size allocated = allocateMemory(&newData, size);
|
||||
|
@ -152,19 +172,35 @@ Resource::Size Resource::Sysmem::append(Size size, const Byte* bytes) {
|
|||
|
||||
Buffer::Buffer() :
|
||||
Resource(),
|
||||
_sysmem(NULL),
|
||||
_sysmem(new Sysmem()),
|
||||
_gpuObject(NULL) {
|
||||
_sysmem = new Sysmem();
|
||||
}
|
||||
|
||||
Buffer::Buffer(Size size, const Byte* bytes) :
|
||||
Resource(),
|
||||
_sysmem(new Sysmem(size, bytes)),
|
||||
_gpuObject(NULL) {
|
||||
}
|
||||
|
||||
Buffer::Buffer(const Buffer& buf) :
|
||||
Resource(),
|
||||
_sysmem(new Sysmem(buf.getSysmem())),
|
||||
_gpuObject(NULL) {
|
||||
}
|
||||
|
||||
Buffer& Buffer::operator=(const Buffer& buf) {
|
||||
(*_sysmem) = buf.getSysmem();
|
||||
return (*this);
|
||||
}
|
||||
|
||||
Buffer::~Buffer() {
|
||||
if (_sysmem) {
|
||||
delete _sysmem;
|
||||
_sysmem = 0;
|
||||
_sysmem = NULL;
|
||||
}
|
||||
if (_gpuObject) {
|
||||
delete _gpuObject;
|
||||
_gpuObject = 0;
|
||||
_gpuObject = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue