├── .gitignore ├── HoloPlayCore ├── VERSION ├── dylib │ ├── Win32 │ │ ├── HoloPlayCore.dll │ │ ├── HoloPlayCore.exp │ │ └── HoloPlayCore.lib │ ├── Win64 │ │ ├── HoloPlayCore.dll │ │ ├── HoloPlayCore.exp │ │ └── HoloPlayCore.lib │ ├── linux │ │ └── libHoloPlayCore.so │ └── macos │ │ ├── libHoloPlayCore.dylib │ │ └── HoloPlayCore.bundle │ │ └── Contents │ │ ├── MacOS │ │ └── libHoloPlayCore.so │ │ └── Info.plist ├── examples │ ├── printshaders.c │ ├── minimal.c │ ├── async.c │ └── HoloPlayInfo.c └── include │ ├── HoloPlayShadersOpen.h │ ├── HoloPlayShaders.h │ ├── HoloPlayCore.h │ └── libHoloPlayCore.h ├── ExampleProject ├── images │ └── output.jpg ├── .gitignore ├── shader │ ├── blit.frag │ ├── blit.vert │ ├── shader.vert │ └── shader.frag ├── src │ ├── glError.hpp │ ├── main.cpp │ ├── glError.cpp │ ├── SampleScene.hpp │ ├── Shader.hpp │ ├── HoloPlayContext.hpp │ ├── Shader.cpp │ ├── SampleScene.cpp │ └── HoloPlayContext.cpp ├── LICENSE ├── CMakeLists.txt └── README.md ├── .gitmodules ├── README.md └── LICENSE.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /HoloPlayCore/VERSION: -------------------------------------------------------------------------------- 1 | 0.2.0 2 | -------------------------------------------------------------------------------- /ExampleProject/images/output.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Looking-Glass/LookingGlassCoreSDK/HEAD/ExampleProject/images/output.jpg -------------------------------------------------------------------------------- /HoloPlayCore/dylib/Win32/HoloPlayCore.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Looking-Glass/LookingGlassCoreSDK/HEAD/HoloPlayCore/dylib/Win32/HoloPlayCore.dll -------------------------------------------------------------------------------- /HoloPlayCore/dylib/Win32/HoloPlayCore.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Looking-Glass/LookingGlassCoreSDK/HEAD/HoloPlayCore/dylib/Win32/HoloPlayCore.exp -------------------------------------------------------------------------------- /HoloPlayCore/dylib/Win32/HoloPlayCore.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Looking-Glass/LookingGlassCoreSDK/HEAD/HoloPlayCore/dylib/Win32/HoloPlayCore.lib -------------------------------------------------------------------------------- /HoloPlayCore/dylib/Win64/HoloPlayCore.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Looking-Glass/LookingGlassCoreSDK/HEAD/HoloPlayCore/dylib/Win64/HoloPlayCore.dll -------------------------------------------------------------------------------- /HoloPlayCore/dylib/Win64/HoloPlayCore.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Looking-Glass/LookingGlassCoreSDK/HEAD/HoloPlayCore/dylib/Win64/HoloPlayCore.exp -------------------------------------------------------------------------------- /HoloPlayCore/dylib/Win64/HoloPlayCore.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Looking-Glass/LookingGlassCoreSDK/HEAD/HoloPlayCore/dylib/Win64/HoloPlayCore.lib -------------------------------------------------------------------------------- /HoloPlayCore/dylib/linux/libHoloPlayCore.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Looking-Glass/LookingGlassCoreSDK/HEAD/HoloPlayCore/dylib/linux/libHoloPlayCore.so -------------------------------------------------------------------------------- /HoloPlayCore/dylib/macos/libHoloPlayCore.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Looking-Glass/LookingGlassCoreSDK/HEAD/HoloPlayCore/dylib/macos/libHoloPlayCore.dylib -------------------------------------------------------------------------------- /ExampleProject/.gitignore: -------------------------------------------------------------------------------- 1 | [Bb]uilds/ 2 | [Bb]uild/ 3 | .vscode 4 | *.swp 5 | 6 | ##### MacOS 7 | # General 8 | .DS_Store 9 | .AppleDouble 10 | .LSOverride 11 | -------------------------------------------------------------------------------- /ExampleProject/shader/blit.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | in vec2 texCoords; 3 | out vec4 fragColor; 4 | uniform sampler2D blitTex; 5 | void main() 6 | { 7 | fragColor = texture(blitTex, texCoords.xy); 8 | } -------------------------------------------------------------------------------- /HoloPlayCore/dylib/macos/HoloPlayCore.bundle/Contents/MacOS/libHoloPlayCore.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Looking-Glass/LookingGlassCoreSDK/HEAD/HoloPlayCore/dylib/macos/HoloPlayCore.bundle/Contents/MacOS/libHoloPlayCore.so -------------------------------------------------------------------------------- /ExampleProject/shader/blit.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | layout (location = 0) 3 | in vec2 vertPos_data; 4 | out vec2 texCoords; 5 | void main() 6 | { 7 | gl_Position = vec4(vertPos_data.xy, 0.0, 1.0); 8 | texCoords = (vertPos_data.xy + 1.0) * 0.5; 9 | } -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ExampleProject/lib/glew"] 2 | path = ExampleProject/lib/glew 3 | url = https://github.com/omniavinco/glew-cmake.git 4 | [submodule "ExampleProject/lib/glm"] 5 | path = ExampleProject/lib/glm 6 | url = https://github.com/g-truc/glm.git 7 | [submodule "ExampleProject/lib/glfw"] 8 | path = ExampleProject/lib/glfw 9 | url = https://github.com/glfw/glfw.git 10 | -------------------------------------------------------------------------------- /HoloPlayCore/examples/printshaders.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "HoloPlayShaders.h" 6 | 7 | int main(int argc, char **argv) 8 | { 9 | printf("========Vertex shader=======\n"); 10 | printf("%s\n", hpc_LightfieldVertShaderGLSL); 11 | printf("=======Fragment shader=======\n"); 12 | printf("%s\n", hpc_LightfieldFragShaderGLSL); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ExampleProject/src/glError.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * glError.hpp 3 | * Contributors: 4 | * * Arthur Sonzogni (author) 5 | * Licence: 6 | * * MIT 7 | */ 8 | 9 | #ifndef OPENGL_CMAKE_SKELETON_GLERROR_HPP 10 | #define OPENGL_CMAKE_SKELETON_GLERROR_HPP 11 | 12 | // Ask Opengl for errors: 13 | // Result is printed on the standard output 14 | // usage : 15 | // glCheckError(__FILE__,__LINE__); 16 | void glCheckError(const char* file, unsigned int line); 17 | 18 | #endif // OPENGL_CMAKE_SKELETON_GLERROR_HPP 19 | -------------------------------------------------------------------------------- /ExampleProject/src/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * main.cpp 3 | * Contributors: 4 | * * Arthur Sonzogni (author), Looking Glass Factory Inc. 5 | * Licence: 6 | * * MIT 7 | */ 8 | 9 | #ifdef WIN32 10 | #pragma warning(disable : 4464 4820 4514 5045 4201 5039 4061 4710 4458 4626 5027 4365 4312) 11 | #endif 12 | 13 | #include "SampleScene.hpp" 14 | 15 | using namespace std; 16 | 17 | #define UNUSED(x) [&x]{}() 18 | 19 | int main(int argc, const char *argv[]) 20 | { 21 | UNUSED(argc); 22 | UNUSED(argv); 23 | 24 | SampleScene sampleScene; 25 | 26 | sampleScene.run(); 27 | 28 | return 0; 29 | } -------------------------------------------------------------------------------- /ExampleProject/shader/shader.vert: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | in vec3 position; 4 | in vec3 normal; 5 | in vec4 color; 6 | 7 | uniform mat4 projection; 8 | uniform mat4 view; 9 | 10 | out vec4 fPosition; 11 | out vec4 fColor; 12 | out vec4 fLightPosition; 13 | out vec3 fNormal; 14 | 15 | void main(void) 16 | { 17 | fPosition = view * vec4(position,1.0); 18 | fLightPosition = view * vec4(0.0,0.0,1.0,1.0); 19 | 20 | fColor = color; 21 | fNormal = vec3(view * vec4(normal,0.0)); 22 | 23 | gl_Position = projection * fPosition; 24 | /*gl_Position.x *= 1000.0f;*/ 25 | /*gl_Position.y = 0.0;*/ 26 | } 27 | -------------------------------------------------------------------------------- /ExampleProject/shader/shader.frag: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | in vec4 fPosition; 4 | in vec4 fColor; 5 | in vec4 fLightPosition; 6 | in vec3 fNormal; 7 | 8 | // output 9 | out vec4 color; 10 | 11 | void main(void) 12 | { 13 | vec3 o =-normalize(fPosition.xyz); 14 | vec3 n = normalize(fNormal); 15 | vec3 r = reflect(o,n); 16 | vec3 l = normalize(fLightPosition.xyz-fPosition.xyz); 17 | 18 | float ambient = 0.1; 19 | float diffus = 0.7*max(0.0,dot(n,l)); 20 | float specular = 0.6*pow(max(0.0,-dot(r,l)),4.0); 21 | 22 | color = fColor * ( ambient + diffus + specular ); 23 | 24 | /*color = vec3(1,0,0);*/ 25 | } 26 | -------------------------------------------------------------------------------- /HoloPlayCore/dylib/macos/HoloPlayCore.bundle/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | libHoloPlayCore.so 9 | CFBundleIdentifier 10 | com.lookingglassfactory.HoloPlayCore 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | HoloPlayCore 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 0.1.1 19 | CFBundleSupportedPlatforms 20 | 21 | MacOSX 22 | 23 | DTCompiler 24 | com.apple.compilers.llvm.clang.1_0 25 | NSHumanReadableCopyright 26 | Copyright © 2020 Looking Glass Factory. All rights reserved. 27 | 28 | 29 | -------------------------------------------------------------------------------- /HoloPlayCore/examples/minimal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char **argv) 8 | { 9 | hpc_client_error errco; 10 | if (!(errco = hpc_InitializeApp("minimal.c", hpc_LICENSE_NONCOMMERCIAL))) 11 | { 12 | char buf[1500]; 13 | size_t d = hpc_GetStateAsJSON(buf, 1500); 14 | // if we haven't allocated enough space for the string, try again 15 | if (d) 16 | { 17 | char *buf2 = (char *)malloc(d); 18 | size_t c = hpc_GetStateAsJSON(buf2, d); 19 | printf("%s\n", buf2); 20 | free(buf2); 21 | } 22 | else 23 | { 24 | printf("%s\n", buf); 25 | } 26 | hpc_GetHoloPlayServiceVersion(buf, 1500); 27 | printf("Version %s\n", buf); 28 | printf("%d devices.\n", hpc_GetNumDevices()); 29 | } 30 | else 31 | { 32 | printf("Error connecting to HoloPlay Service (code %d).\n", errco); 33 | } 34 | hpc_CloseApp(); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /ExampleProject/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Arthur Sonzogni 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ExampleProject/src/glError.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * glError.cpp 3 | * Contributors: 4 | * * Arthur Sonzogni (author) 5 | * Licence: 6 | * * MIT 7 | */ 8 | 9 | #ifdef WIN32 10 | #pragma warning(disable : 4464 4820 4514 5045 4201 5039 4061 4710 4458 4626 5027 4668) 11 | #endif 12 | 13 | #include "glError.hpp" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace std; 20 | 21 | void glCheckError(const char* file, unsigned int line) { 22 | GLenum errorCode = glGetError(); 23 | 24 | while (errorCode != GL_NO_ERROR) { 25 | string fileString(file); 26 | string error = "unknown error"; 27 | 28 | // clang-format off 29 | switch (errorCode) { 30 | case GL_INVALID_ENUM: error = "GL_INVALID_ENUM"; break; 31 | case GL_INVALID_VALUE: error = "GL_INVALID_VALUE"; break; 32 | case GL_INVALID_OPERATION: error = "GL_INVALID_OPERATION"; break; 33 | case GL_STACK_OVERFLOW: error = "GL_STACK_OVERFLOW"; break; 34 | case GL_STACK_UNDERFLOW: error = "GL_STACK_UNDERFLOW"; break; 35 | case GL_OUT_OF_MEMORY: error = "GL_OUT_OF_MEMORY"; break; 36 | } 37 | // clang-format on 38 | 39 | cerr << "OpenglError : file=" << file << " line=" << line 40 | << " error:" << error << endl; 41 | errorCode = glGetError(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /HoloPlayCore/examples/async.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | volatile bool done = false; 8 | 9 | void cb(hpc_obj obj, hpc_client_error clierr, void *context) 10 | { 11 | char buf[1500]; 12 | size_t d = hpc_ObjAsJson(obj, buf, 1500); 13 | printf("%s \nerror: %d\n*context: %d\n", buf, clierr, *(int *)context); 14 | done = true; 15 | } 16 | 17 | int main(int argc, char **argv) 18 | { 19 | printf("start\n"); 20 | 21 | hpc_client_error c = hpc_InitializeApp("async", hpc_LICENSE_NONCOMMERCIAL); 22 | if (c) 23 | { 24 | printf("client error %d\n", c); 25 | } else{ 26 | hpc_obj *info_req = hpc_MakeObject("{\"info\":{}}", 0, NULL); 27 | int d = 123; 28 | hpc_client_error c = hpc_SendCallback(info_req, cb, &d); 29 | if (c) 30 | { 31 | printf("client error %d\n", c); 32 | } 33 | else 34 | { 35 | // wait for a while before exiting, defeating the entire purpose 36 | // of an async request -- oh well 37 | unsigned long i = 0; 38 | while (!done && i < 10000000) 39 | { 40 | i++; 41 | } 42 | printf("done.\n"); 43 | } 44 | hpc_CloseApp(); 45 | } 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /ExampleProject/src/SampleScene.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * SampleScene.hpp 3 | * Contributors: 4 | * * Arthur Sonzogni (author), Looking Glass Factory Inc. 5 | * Licence: 6 | * * MIT 7 | */ 8 | #ifndef OPENGL_CMAKE_SKELETON_MYAPPLICATION 9 | #define OPENGL_CMAKE_SKELETON_MYAPPLICATION 10 | 11 | #include "HoloPlayContext.hpp" 12 | 13 | class SampleScene : public HoloPlayContext 14 | { 15 | public: 16 | SampleScene(); 17 | // control 18 | virtual void mouse_callback(GLFWwindow *window, double xpos, double ypos); 19 | virtual void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); 20 | 21 | protected: 22 | virtual void update(); 23 | virtual void onExit(); 24 | virtual void renderScene(); 25 | virtual glm::mat4 getViewMatrixOfCurrentFrame(); 26 | virtual bool processInput(GLFWwindow *window); 27 | 28 | ShaderProgram *shaderProgram; 29 | 30 | private: 31 | const unsigned int size = 100; 32 | 33 | // VBO/VAO/ibo 34 | GLuint vao, vbo, ibo; 35 | 36 | // camera 37 | glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); 38 | glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); 39 | glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); 40 | bool firstMouse = true; 41 | float yaw = -90.0f; // yaw is initialized to -90.0 degrees since a yaw of 0.0 42 | // results in a direction vector pointing to the right so 43 | // we initially rotate a bit to the left. 44 | float pitch = 0.0f; 45 | float lastX = 800.0f / 2.0; 46 | float lastY = 600.0 / 2.0; 47 | int debug = 0; 48 | }; 49 | 50 | #endif // OPENGL_CMAKE_SKELETON_MYAPPLICATION 51 | -------------------------------------------------------------------------------- /ExampleProject/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Projects Settings 2 | cmake_minimum_required (VERSION 3.1) 3 | project (holoplay-core-example) 4 | 5 | set(HOLOPLAY_CORE_BASE_PATH "${PROJECT_SOURCE_DIR}/../HoloPlayCore") 6 | 7 | # The main executable 8 | add_executable(main 9 | src/HoloPlayContext.hpp 10 | src/HoloPlayContext.cpp 11 | src/SampleScene.hpp 12 | src/SampleScene.cpp 13 | src/glError.hpp 14 | src/glError.cpp 15 | src/main.cpp 16 | src/Shader.hpp 17 | src/Shader.cpp 18 | ) 19 | 20 | set_property(TARGET main PROPERTY CXX_STANDARD 11) 21 | target_compile_options(main PRIVATE -Wall) 22 | 23 | # glfw 24 | add_subdirectory(lib/glfw EXCLUDE_FROM_ALL) 25 | target_link_libraries(main PRIVATE glfw) 26 | 27 | # glew 28 | add_definitions(-DGLEW_STATIC) 29 | add_subdirectory(lib/glew EXCLUDE_FROM_ALL) 30 | target_link_libraries(main PRIVATE libglew_static) 31 | 32 | # glm 33 | add_subdirectory(lib/glm EXCLUDE_FROM_ALL) 34 | target_link_libraries(main PRIVATE glm) 35 | 36 | set(DLL_DIR "linux") 37 | 38 | if(WIN32) 39 | set(DLL_DIR "Win64") 40 | if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") 41 | set(DLL_DIR "Win32") 42 | endif() 43 | set(HOLOPLAY_CORE_DLL_LOCATION "${HOLOPLAY_CORE_BASE_PATH}/dylib/${DLL_DIR}/HoloPlayCore.dll") 44 | add_custom_command(TARGET main POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${HOLOPLAY_CORE_DLL_LOCATION}" $) 45 | endif(WIN32) 46 | 47 | if(APPLE) 48 | set(DLL_DIR "macos") 49 | endif(APPLE) 50 | 51 | # holoplaycore 52 | target_include_directories(main PRIVATE "${HOLOPLAY_CORE_BASE_PATH}/include") 53 | find_library(HOLOPLAY_CORE_LOCATION HoloPlayCore PATHS "${HOLOPLAY_CORE_BASE_PATH}/dylib" PATH_SUFFIXES ${DLL_DIR}) 54 | target_link_libraries(main PRIVATE ${HOLOPLAY_CORE_LOCATION}) 55 | 56 | -------------------------------------------------------------------------------- /HoloPlayCore/include/HoloPlayShadersOpen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | HoloPlayCore 0.1.1 5 | 6 | include/HoloPlayShadersOpen.h 7 | 8 | author: Evan Kahn 9 | contact: evan@lookingglassfactory.com 10 | 11 | If you cannot include HoloPlayShaders.h in your codebase for licensing reasons, 12 | please include this file instead: it refers to the shader strings embedded in 13 | the HoloPlayCore dynamic library, rather than statically linking the shaders 14 | directly from the header file. 15 | 16 | Copyright 2020 Looking Glass Factory 17 | 18 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 19 | and associated documentation files (the "Software"), to deal in the Software without 20 | restriction, including without limitation the rights to use, copy, modify, merge, publish, 21 | distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 22 | Software is furnished to do so, subject to the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included in all copies or 25 | substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 28 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 30 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | #ifndef IMPORT_DECL 35 | #ifdef _WIN32 36 | #ifdef HPC_STATIC 37 | #define IMPORT_DECL 38 | #else 39 | #define IMPORT_DECL __declspec(dllimport) 40 | #endif 41 | #else 42 | #define IMPORT_DECL 43 | #endif 44 | #endif 45 | 46 | #ifdef __cplusplus 47 | extern "C" 48 | { 49 | #endif 50 | IMPORT_DECL const extern char* hpc_LightfieldVertShaderGLSLExported; 51 | IMPORT_DECL const extern char* hpc_LightfieldFragShaderGLSLExported; 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | #define hpc_LightfieldVertShaderGLSL hpc_LightfieldVertShaderGLSLExported 57 | #define hpc_LightfieldFragShaderGLSL hpc_LightfieldFragShaderGLSLExported 58 | -------------------------------------------------------------------------------- /HoloPlayCore/examples/HoloPlayInfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "HoloPlayCore.h" 6 | 7 | int main(int argc, char **argv) 8 | { 9 | hpc_client_error errco = hpc_InitializeApp("HoloPlayInfo.c", hpc_LICENSE_NONCOMMERCIAL); 10 | if (errco) 11 | { 12 | char *errstr; 13 | switch (errco) 14 | { 15 | case hpc_CLIERR_NOSERVICE: 16 | errstr = "HoloPlay Service not running"; 17 | break; 18 | case hpc_CLIERR_SERIALIZEERR: 19 | errstr = "Client message could not be serialized"; 20 | break; 21 | case hpc_CLIERR_VERSIONERR: 22 | errstr = "Incompatible version of HoloPlay Service"; 23 | break; 24 | case hpc_CLIERR_PIPEERROR: 25 | errstr = "Interprocess pipe broken"; 26 | break; 27 | case hpc_CLIERR_SENDTIMEOUT: 28 | errstr = "Interprocess pipe send timeout"; 29 | break; 30 | case hpc_CLIERR_RECVTIMEOUT: 31 | errstr = "Interprocess pipe receive timeout"; 32 | break; 33 | default: 34 | errstr = "Unknown error"; 35 | break; 36 | } 37 | printf("Client access error (code = %d): %s!\n", errco, errstr); 38 | } 39 | else 40 | { 41 | char buf[1000]; 42 | hpc_GetHoloPlayCoreVersion(buf, 1000); 43 | printf("HoloPlay Core version %s.\n", buf); 44 | hpc_GetHoloPlayServiceVersion(buf, 1000); 45 | printf("HoloPlay Service version %s.\n", buf); 46 | int num_displays = hpc_GetNumDevices(); 47 | printf("%d device%s connected.\n", num_displays, (num_displays == 1 ? "" : "s")); 48 | for (int i = 0; i < num_displays; ++i) 49 | { 50 | printf("Device information for display %d:\n", i); 51 | hpc_GetDeviceHDMIName(i, buf, 1000); 52 | printf(" Device name: %s\n", buf); 53 | hpc_GetDeviceType(i, buf, 1000); 54 | printf(" Device type: %s\n", buf); 55 | int b0 = hpc_GetDevicePropertyInt(i, "/buttons/0"); 56 | int b1 = hpc_GetDevicePropertyInt(i, "/buttons/1"); 57 | int b2 = hpc_GetDevicePropertyInt(i, "/buttons/2"); 58 | int b3 = hpc_GetDevicePropertyInt(i, "/buttons/3"); 59 | printf(" Button status: %d %d %d %d", b0, b1, b2, b3); 60 | printf("\nWindow parameters for display %d:\n", i); 61 | printf(" Position: (%d, %d)\n", hpc_GetDevicePropertyWinX(i), hpc_GetDevicePropertyWinY(i)); 62 | printf(" Size: (%d, %d)\n", hpc_GetDevicePropertyScreenW(i), hpc_GetDevicePropertyScreenH(i)); 63 | printf(" Aspect ratio: %f\n", hpc_GetDevicePropertyDisplayAspect(i)); 64 | printf("Shader uniforms for display %d:\n", i); 65 | printf(" pitch: %.9f\n", hpc_GetDevicePropertyPitch(i)); 66 | printf(" tilt: %.9f\n", hpc_GetDevicePropertyTilt(i)); 67 | printf(" center: %.9f\n", hpc_GetDevicePropertyCenter(i)); 68 | printf(" subp: %.9f\n", hpc_GetDevicePropertySubp(i)); 69 | printf(" fringe: %.1f\n", hpc_GetDevicePropertyFringe(i)); 70 | printf(" RI: %d\n BI: %d\n invView: %d\n", hpc_GetDevicePropertyRi(i), hpc_GetDevicePropertyBi(i), hpc_GetDevicePropertyInvView(i)); 71 | } 72 | } 73 | hpc_CloseApp(); 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /ExampleProject/src/Shader.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2017-2020 Looking Glass Factory Inc. 2 | //All rights reserved. 3 | //Unauthorized copying or distribution of this file, and the source code contained herein, is strictly prohibited. 4 | 5 | #ifndef OPENGL_CMAKE_SKELETON_SHADER_HPP 6 | #define OPENGL_CMAKE_SKELETON_SHADER_HPP 7 | 8 | #define GLM_FORCE_RADIANS 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class Shader; 16 | class ShaderProgram; 17 | 18 | // Loads a shader from a file into OpenGL. 19 | class Shader 20 | { 21 | public: 22 | // Load Shader from a file 23 | Shader(const std::string &filename, GLenum type); 24 | Shader(GLenum type, const char *shaderText); 25 | 26 | // provide opengl shader identifiant. 27 | GLuint getHandle() const; 28 | 29 | void checkCompileError(std::string file); 30 | 31 | ~Shader(); 32 | 33 | private: 34 | // opengl program identifiant 35 | GLuint handle; 36 | 37 | friend class ShaderProgram; 38 | }; 39 | 40 | // A shader program is a set of shader (for instance vertex shader + pixel 41 | // shader) defining the rendering pipeline. 42 | // 43 | // This class provide an interface to define the OpenGL uniforms and attributes 44 | // using GLM objects. 45 | class ShaderProgram 46 | { 47 | public: 48 | // constructor 49 | ShaderProgram(std::initializer_list shaderList); 50 | 51 | // bind the program 52 | void use() const; 53 | void unuse() const; 54 | 55 | // provide the opengl identifiant 56 | GLuint getHandle() const; 57 | 58 | // clang-format off 59 | // provide attributes informations. 60 | GLint attribute(const std::string& name); 61 | void setAttribute(const std::string& name, GLint size, GLsizei stride, GLuint offset, GLboolean normalize, GLenum type); 62 | void setAttribute(const std::string& name, GLint size, GLsizei stride, GLuint offset, GLboolean normalize); 63 | void setAttribute(const std::string& name, GLint size, GLsizei stride, GLuint offset, GLenum type); 64 | void setAttribute(const std::string& name, GLint size, GLsizei stride, GLuint offset); 65 | // clang-format on 66 | 67 | // provide uniform location 68 | GLint uniform(const std::string &name); 69 | GLint operator[](const std::string &name); 70 | 71 | // affect uniform 72 | void setUniform(const std::string &name, float x, float y, float z); 73 | void setUniform(const std::string &name, const glm::vec2 &v); 74 | void setUniform(const std::string &name, const glm::vec3 &v); 75 | void setUniform(const std::string &name, const glm::dvec3 &v); 76 | void setUniform(const std::string &name, const glm::vec4 &v); 77 | void setUniform(const std::string &name, const glm::dvec4 &v); 78 | void setUniform(const std::string &name, const glm::dmat4 &m); 79 | void setUniform(const std::string &name, const glm::mat4 &m); 80 | void setUniform(const std::string &name, const glm::mat3 &m); 81 | void setUniform(const std::string &name, float val); 82 | void setUniform(const std::string &name, int val); 83 | 84 | ~ShaderProgram(); 85 | 86 | private: 87 | ShaderProgram(); 88 | 89 | std::map uniforms; 90 | std::map attributes; 91 | 92 | // opengl id 93 | GLuint handle; 94 | 95 | void link(); 96 | }; 97 | 98 | #endif // OPENGL_CMAKE_SKELETON_SHADER_HPP 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Note that this SDK is now out of date.** 2 | 3 | This SDK does not have support for the lastest Looking Glass devices (Looking Glass Go, Looking Glass 16" Spatial Displays, and Looking Glass 32" Spatial Displays). **[Please use our new Bridge SDK instead](https://github.com/Looking-Glass/bridge-sdk-samples).** You can see documentation on our Bridge SDK [here](https://docs.lookingglassfactory.com/core/looking-glass-bridge-sdk) and a migration guide from Looking Glass Core [here](https://docs.lookingglassfactory.com/core/looking-glass-core-migration-guide). 4 | 5 | # Looking Glass Core 6 | 7 | The Looking Glass Core SDK (formerly HoloPlay Core) unlocks the ability to integrate your existing 3D software with Looking Glass displays, making the Looking Glass a holographic second monitor. 8 | 9 | The SDK comes in two different flavors: 10 | 11 | - Native dynamic libraries for Windows, Mac, and Linux (contained in this repository) 12 | - JavaScript for web or Node development, which you can [access here](https://github.com/Looking-Glass/holoplaycore.js) 13 | 14 | ## Prerequisites 15 | 16 | Developers can use any rendering backend (DirectX, OpenGL, Metal, Vulkan) and any windowing library (e.g. GLFW, Qt, SDL). Beyond that, in order to render to the Looking Glass display, your application must be able to: 17 | 18 | - Generate a borderless fullscreen window at a specific position 19 | - Distort the camera's projection matrix 20 | - Render multiple views to a texture 21 | - Apply a shader to the texture 22 | 23 | Also, your end user must have [Looking Glass Bridge](https://lookingglassfactory.com/software/looking-glass-bridge) installed on their machine. 24 | 25 | ## How It Works 26 | 27 | The Looking Glass Core SDK provides your application all the information it needs to draw to the Looking Glass, including window information and calibration. 28 | 29 | #### **Why Window Information is Important** 30 | 31 | Operating systems see connected Looking Glass devices as HDMI monitors. Your application must know how the OS sees the monitor so that it knows where to draw the windows. 32 | 33 | #### **Why Calibration Data is Important** 34 | 35 | Each Looking Glass has its own device-specific calibration, read over USB. Your application must know this calibration data in order to render holograms properly on the Looking Glass. 36 | 37 | #### **All Together** 38 | 39 | Looking Glass Core (the graphics library integrated into your application) gets this information by providing an API endpoint to request information from Looking Glass Bridge (a persistent driver-like service that is installed on the user’s machine). Looking Glass Core uses this information to draw your 3D scene to the Looking Glass. 40 | 41 | ## Guides 42 | 43 | These reference documents cover some of the underlying logic inside the SDK: 44 | 45 | - [Camera](https://docs.lookingglassfactory.com/keyconcepts/camera) 46 | - [Quilt](https://docs.lookingglassfactory.com/keyconcepts/quilts) 47 | 48 | An example OpenGL project is distributed as part of the Looking Glass Core SDK to demonstrate how to move the camera and render to a texture in the appropriate format. 49 | 50 | To learn more about the Looking Glass and how it works, click [here](https://docs.lookingglassfactory.com/keyconcepts/how-it-works). 51 | 52 | ## Questions 53 | 54 | Email us at [support@lookingglassfactory.com](mailto:support@lookingglassfactory.com) if you have any further questions about how you can integrate Looking Glass Core into your software. 55 | 56 | -------------------------------------------------------------------------------- /HoloPlayCore/include/HoloPlayShaders.h: -------------------------------------------------------------------------------- 1 | /* 2 | HoloPlayCore 0.1.1 3 | 4 | include/HoloPlayShaders.h 5 | 6 | author: Evan Kahn 7 | contact: evan@lookingglassfactory.com 8 | 9 | This file contains static string definitions for the lenticular shader 10 | that turns a "quilt" texture containing a multistereo image into Looking Glass 11 | lenticular output. The lenticular shader depends on two sets of uniforms. 12 | 13 | The first set of uniforms (calibration values) varies from device to device, 14 | and must be queried using functions declared in HoloPlayCore.h. The second set 15 | (quilt settings) must be provided by the developer and depends on the desired 16 | resolution of their multiview render. 17 | 18 | By using, copying, or modifying this code in any way, you agree to the terms of 19 | https://github.com/Looking-Glass/HoloPlayCoreSDK/blob/master/LICENSE.txt 20 | 21 | The contents of this file are not open source and should not be merged into 22 | codebases with licenses that conflict with the HoloPlay SDK License. In those 23 | cases, please include HoloPlayShadersOpen.h instead. 24 | */ 25 | 26 | static const char* hpc_LightfieldVertShaderGLSL = "\ 27 | layout (location = 0)\n\ 28 | in vec2 vertPos_data;\n\ 29 | \n\ 30 | out vec2 texCoords;\n\ 31 | \n\ 32 | void main()\n\ 33 | {\n\ 34 | gl_Position = vec4(vertPos_data.xy, 0.0, 1.0);\n\ 35 | texCoords = (vertPos_data.xy + 1.0) * 0.5;\n\ 36 | }"; 37 | static const char* hpc_LightfieldFragShaderGLSL = "\ 38 | in vec2 texCoords;\n\ 39 | out vec4 fragColor;\n\ 40 | \n\ 41 | // Calibration values\n\ 42 | uniform float pitch;\n\ 43 | uniform float tilt;\n\ 44 | uniform float center;\n\ 45 | uniform int invView;\n\ 46 | uniform float subp;\n\ 47 | uniform float displayAspect;\n\ 48 | uniform int ri;\n\ 49 | uniform int bi;\n\ 50 | \n\ 51 | // Quilt settings\n\ 52 | uniform vec3 tile;\n\ 53 | uniform vec2 viewPortion;\n\ 54 | uniform float quiltAspect;\n\ 55 | uniform int overscan;\n\ 56 | uniform int quiltInvert;\n\ 57 | \n\ 58 | uniform int debug;\n\ 59 | \n\ 60 | uniform sampler2D screenTex;\n\ 61 | \n\ 62 | vec2 texArr(vec3 uvz)\n\ 63 | {\n\ 64 | // decide which section to take from based on the z.\n\ 65 | float x = (mod(uvz.z, tile.x) + uvz.x) / tile.x;\n\ 66 | float y = (floor(uvz.z / tile.x) + uvz.y) / tile.y;\n\ 67 | return vec2(x, y) * viewPortion.xy;\n\ 68 | }\n\ 69 | \n\ 70 | // recreate CG clip function (clear pixel if any component is negative)\n\ 71 | void clip(vec3 toclip)\n\ 72 | {\n\ 73 | if (any(lessThan(toclip, vec3(0,0,0)))) discard;\n\ 74 | }\n\ 75 | \n\ 76 | void main()\n\ 77 | {\n\ 78 | if (debug == 1)\n\ 79 | {\n\ 80 | fragColor = texture(screenTex, texCoords.xy);\n\ 81 | }\n\ 82 | else {\n\ 83 | float invert = 1.0;\n\ 84 | if (invView + quiltInvert == 1) invert = -1.0;\n\ 85 | vec3 nuv = vec3(texCoords.xy, 0.0);\n\ 86 | nuv -= 0.5;\n\ 87 | float modx = clamp (step(quiltAspect, displayAspect) * step(float(overscan), 0.5) + step(displayAspect, quiltAspect) * step(0.5, float(overscan)), 0, 1);\n\ 88 | nuv.x = modx * nuv.x * displayAspect / quiltAspect + (1.0-modx) * nuv.x;\n\ 89 | nuv.y = modx * nuv.y + (1.0-modx) * nuv.y * quiltAspect / displayAspect; \n\ 90 | nuv += 0.5;\n\ 91 | clip (nuv);\n\ 92 | clip (1.0-nuv);\n\ 93 | vec4 rgb[3];\n\ 94 | for (int i=0; i < 3; i++)\n\ 95 | {\n\ 96 | nuv.z = (texCoords.x + i * subp + texCoords.y * tilt) * pitch - center;\n\ 97 | nuv.z = mod(nuv.z + ceil(abs(nuv.z)), 1.0);\n\ 98 | nuv.z *= invert;\n\ 99 | nuv.z *= tile.z;\n\ 100 | vec3 coords1 = nuv;\n\ 101 | vec3 coords2 = nuv;\n\ 102 | coords1.y = coords2.y = clamp(nuv.y, 0.005, 0.995);\n\ 103 | coords1.z = floor(nuv.z);\n\ 104 | coords2.z = ceil(nuv.z);\n\ 105 | vec4 col1 = texture(screenTex, texArr(coords1));\n\ 106 | vec4 col2 = texture(screenTex, texArr(coords2));\n\ 107 | rgb[i] = mix(col1, col2, nuv.z - coords1.z);\n\ 108 | }\n\ 109 | fragColor = vec4(rgb[ri].r, rgb[1].g, rgb[bi].b, 1.0);\n\ 110 | }\n\ 111 | }\n\ 112 | "; 113 | -------------------------------------------------------------------------------- /ExampleProject/src/HoloPlayContext.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * HoloPlayContext.hpp 3 | * Contributors: 4 | * * Arthur Sonzogni (author), Looking Glass Factory Inc. 5 | * Licence: 6 | * * MIT 7 | */ 8 | 9 | #ifndef OPENGL_CMAKE_SKELETON_APPLICATION_HPP 10 | #define OPENGL_CMAKE_SKELETON_APPLICATION_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "HoloPlayCore.h" 17 | #include "Shader.hpp" 18 | 19 | struct GLFWwindow; 20 | struct GLFWmonitor; 21 | struct hpc_Uniforms_t; 22 | 23 | class HoloPlayContext 24 | { 25 | public: 26 | HoloPlayContext(bool capture_mouse = true); 27 | virtual ~HoloPlayContext(); 28 | 29 | static HoloPlayContext &getInstance(); 30 | 31 | // get the window id 32 | GLFWwindow *getWindow() const; 33 | 34 | // exit function 35 | void exit(); 36 | 37 | // delta time between frame and time from beginning 38 | float getFrameDeltaTime() const; 39 | float getTime() const; 40 | 41 | // application run 42 | void run(); 43 | 44 | // Window functions 45 | int getWidth(); 46 | int getHeight(); 47 | float getWindowRatio(); 48 | bool windowDimensionChanged(); 49 | 50 | // functions that should be overrieded in the child class 51 | virtual void onExit(); 52 | virtual void update(); // update function that will run every frame 53 | virtual void renderScene(); // render scene here 54 | virtual glm::mat4 55 | getViewMatrixOfCurrentFrame(); // define how view matrix gets updated each 56 | // frame here. projection matrix is not 57 | // changeable because the field of view is 58 | // static according to hardware measurement 59 | virtual bool processInput(GLFWwindow *window); // all key inputs 60 | virtual void mouse_callback(GLFWwindow *window, double xpos, double ypos); 61 | virtual void scroll_callback(GLFWwindow *window, 62 | double xoffset, 63 | double yoffset); 64 | 65 | private: 66 | enum class State 67 | { 68 | Ready, 69 | Run, 70 | Exit 71 | }; 72 | 73 | State state; 74 | 75 | HoloPlayContext &operator=(const HoloPlayContext &) { return *this; } 76 | 77 | GLFWwindow *window; 78 | 79 | // Window dimensions: 80 | int win_w; 81 | int win_h; 82 | int win_x; 83 | int win_y; 84 | 85 | bool windowChanged; 86 | void detectWindowChange(); 87 | 88 | // storing matrix of each view 89 | glm::mat4 projectionMatrix = glm::mat4(1.0); 90 | glm::mat4 viewMatrix = glm::mat4(1.0); 91 | 92 | protected: 93 | HoloPlayContext(const HoloPlayContext &){}; 94 | 95 | std::string title; 96 | int opengl_version_major; 97 | int opengl_version_minor; 98 | std::string opengl_version_header; 99 | 100 | // Time: 101 | float time; 102 | float deltaTime; 103 | 104 | // lkg related: 105 | const int DEV_INDEX = 0; // the index of device we are rendering on, 106 | // default is 0, the first Looking Glass detected 107 | float cameraSize = 5; // size of the holoplay camera, 108 | // changeable without limitation 109 | float viewCone = 40.0; // view cone of hardware, always around 40 110 | 111 | // quilt settings 112 | // more info at 113 | // https://docs.lookingglassfactory.com/HoloPlayCAPI/guides/quilt/ 114 | int qs_width; // Total width of the quilt texture 115 | int qs_height; // Total height of the quilt texture 116 | int qs_rows; // Number of columns in the quilt 117 | int qs_columns; // Number of rows in the quilt 118 | int qs_totalViews; // The total number of views in the quilt. 119 | // Note that this number might be lower than rows * 120 | // columns 121 | // qs_viewWidth & qs_viewHeight could be calculated by given numbers 122 | 123 | // shaders: 124 | ShaderProgram *lightFieldShader = 125 | NULL; // The shader program for drawing light field images to the Looking 126 | // Glass 127 | ShaderProgram *blitShader = 128 | NULL; // The shader program for copying views to the quilt 129 | 130 | // render var 131 | unsigned int 132 | quiltTexture; // The texture object used internally to draw quilt, 133 | // It is bound and drawn by drawLightfield() 134 | unsigned int VAO; // The vertex array object used internally to blit to the 135 | // quilt and screen 136 | unsigned int VBO; // The vertex buffer object used internally to blit to the 137 | // quilt and screen 138 | unsigned int FBO; // The frame buffer object used internally to blit views to 139 | // the quilt 140 | 141 | // example implementation for rendering 45 views 142 | // ==================================================================================== 143 | // set up functions 144 | void initialize(); // calls all the functions necessary to set up the 145 | // HoloPlay Context 146 | void setupQuilt(); // create the quiltTexture, VBO, VAO, and FBO 147 | void setupQuiltSettings( 148 | int preset); // Set up the quilt settings according to the preset passed 149 | // 0: 32 views 150 | // 1: 45 views, normally used one 151 | // 2: 45 views for 8k display 152 | // Feel free to customize if you want 153 | void passQuiltSettingsToShader(); // assign quilt settings to light-field 154 | // shader uniforms 155 | void loadCalibrationIntoShader(); // assign calibration to light-field shader 156 | // uniforms 157 | void loadLightFieldShaders(); // create and compile light-field shader 158 | 159 | // release function 160 | void release(); // Destroys / releases all buffers and objects creating 161 | // during initialize() 162 | 163 | // render functions 164 | void setupVirtualCameraForView( // Changes the view matrix and projection 165 | int currentViewIndex, // accoriding to the view index and the 166 | // currentViewMatrix 167 | glm::mat4 currentViewMatrix); 168 | 169 | void drawLightField(); // Uses the lightfieldShader program, 170 | // binds the quiltTexture, and draws a fullscreen 171 | // quad. Call this after all the views have been 172 | // rendered. 173 | 174 | // holoplay core related helper functions 175 | bool 176 | GetLookingGlassInfo(); // get all the information of all connected looking 177 | // glass retuyrn false if no looking glass detected 178 | GLFWwindow * 179 | openWindowOnLKG(); // open a full-szie window on the looking glass 180 | 181 | // some get functions 182 | unsigned int getQuiltTexture() { return quiltTexture; } 183 | unsigned int getLightfieldShader() { return lightFieldShader->getHandle(); } 184 | glm::mat4 GetProjectionMatrixOfCurrentView() { return projectionMatrix; } 185 | glm::mat4 GetViewMatrixOfCurrentView() { return viewMatrix; } 186 | }; 187 | 188 | #endif /* end of include guard: OPENGL_CMAKE_SKELETON_APPLICATION_HPP */ 189 | -------------------------------------------------------------------------------- /ExampleProject/src/Shader.cpp: -------------------------------------------------------------------------------- 1 | //Copyright 2017-2020 Looking Glass Factory Inc. 2 | //All rights reserved. 3 | //Unauthorized copying or distribution of this file, and the source code contained herein, is strictly prohibited. 4 | 5 | #ifdef WIN32 6 | #pragma warning(disable : 4464 4820 4514 5045 4201 5039 4061 4710 4458 4626 5027 4365 4312) 7 | #endif 8 | 9 | #include "Shader.hpp" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace std; 20 | using namespace glm; 21 | 22 | // ------------------- 23 | // file reading 24 | void getFileContents(const char *filename, vector &buffer) 25 | { 26 | ifstream file(filename, ios_base::binary); 27 | if (file) 28 | { 29 | file.seekg(0, ios_base::end); 30 | streamsize size = file.tellg(); 31 | if (size > 0) 32 | { 33 | file.seekg(0, ios_base::beg); 34 | buffer.resize(static_cast(size)); 35 | file.read(&buffer[0], size); 36 | } 37 | buffer.push_back('\0'); 38 | } 39 | else 40 | { 41 | throw std::invalid_argument(string("The file ") + filename + 42 | " doesn't exists"); 43 | } 44 | } 45 | 46 | Shader::Shader(const std::string &filename, GLenum type) 47 | { 48 | 49 | // file loading 50 | vector fileContent; 51 | getFileContents(filename.c_str(), fileContent); 52 | 53 | // creation 54 | handle = glCreateShader(type); 55 | if (handle == 0) 56 | throw std::runtime_error("[Error] Impossible to create a new Shader"); 57 | 58 | // code source assignation 59 | const char *shaderText(&fileContent[0]); 60 | glShaderSource(handle, 1, (const GLchar **)&shaderText, NULL); 61 | 62 | // compilation 63 | glCompileShader(handle); 64 | 65 | checkCompileError(filename); 66 | } 67 | 68 | Shader::Shader(GLenum type, const char *shaderText) 69 | { 70 | // creation 71 | handle = glCreateShader(type); 72 | if (handle == 0) 73 | throw std::runtime_error("[Error] Impossible to create a new Shader"); 74 | 75 | glShaderSource(handle, 1, &shaderText, NULL); 76 | 77 | // compilation 78 | glCompileShader(handle); 79 | 80 | checkCompileError(""); 81 | } 82 | 83 | GLuint Shader::getHandle() const 84 | { 85 | return handle; 86 | } 87 | 88 | void Shader::checkCompileError(std::string file) 89 | { 90 | // compilation check 91 | GLint compile_status; 92 | glGetShaderiv(handle, GL_COMPILE_STATUS, &compile_status); 93 | if (compile_status != GL_TRUE) 94 | { 95 | GLsizei logsize = 0; 96 | glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &logsize); 97 | 98 | string log; 99 | log.resize(size_t(logsize + 1)); 100 | 101 | glGetShaderInfoLog(handle, logsize, &logsize, &log[0]); 102 | 103 | cout << "[Error] compilation error: " << file << endl; 104 | cout << log << endl; 105 | 106 | exit(EXIT_FAILURE); 107 | } 108 | else 109 | { 110 | cout << "[Shader] Shader " << file << " compiled successfully" << endl; 111 | } 112 | } 113 | 114 | Shader::~Shader() {} 115 | 116 | ShaderProgram::ShaderProgram() 117 | { 118 | handle = glCreateProgram(); 119 | if (!handle) 120 | throw std::runtime_error("Impossible to create a new shader program"); 121 | } 122 | 123 | ShaderProgram::ShaderProgram(std::initializer_list shaderList) 124 | : ShaderProgram() 125 | { 126 | for (auto &s : shaderList) 127 | glAttachShader(handle, s.getHandle()); 128 | 129 | link(); 130 | } 131 | 132 | void ShaderProgram::link() 133 | { 134 | glLinkProgram(handle); 135 | GLint result; 136 | glGetProgramiv(handle, GL_LINK_STATUS, &result); 137 | if (result != GL_TRUE) 138 | { 139 | cout << "[Error] linkage error" << endl; 140 | 141 | GLsizei logsize = 0; 142 | glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &logsize); 143 | 144 | string log; 145 | log.resize(size_t(logsize + 1)); 146 | 147 | glGetProgramInfoLog(handle, logsize, &logsize, &log[0]); 148 | 149 | cout << log << endl; 150 | } 151 | } 152 | 153 | GLint ShaderProgram::uniform(const std::string &name) 154 | { 155 | auto it = uniforms.find(name); 156 | if (it == uniforms.end()) 157 | { 158 | // uniform that is not referenced 159 | GLint r = glGetUniformLocation(handle, name.c_str()); 160 | if (r == GL_INVALID_OPERATION || r < 0) 161 | cout << "[Error] uniform " << name << " doesn't exist in program" << endl; 162 | // add it anyways 163 | uniforms[name] = r; 164 | 165 | return r; 166 | } 167 | else 168 | return it->second; 169 | } 170 | 171 | GLint ShaderProgram::attribute(const std::string &name) 172 | { 173 | GLint attrib = glGetAttribLocation(handle, name.c_str()); 174 | if (attrib == GL_INVALID_OPERATION || attrib < 0) 175 | cout << "[Error] Attribute " << name << " doesn't exist in program" << endl; 176 | 177 | return attrib; 178 | } 179 | 180 | void ShaderProgram::setAttribute(const std::string &name, 181 | GLint size, 182 | GLsizei stride, 183 | GLuint offset, 184 | GLboolean normalize, 185 | GLenum type) 186 | { 187 | GLint loc = attribute(name); 188 | glEnableVertexAttribArray(loc); 189 | glVertexAttribPointer(loc, size, type, normalize, stride, 190 | reinterpret_cast(offset)); 191 | } 192 | 193 | void ShaderProgram::setAttribute(const std::string &name, 194 | GLint size, 195 | GLsizei stride, 196 | GLuint offset, 197 | GLboolean normalize) 198 | { 199 | setAttribute(name, size, stride, offset, normalize, GL_FLOAT); 200 | } 201 | 202 | void ShaderProgram::setAttribute(const std::string &name, 203 | GLint size, 204 | GLsizei stride, 205 | GLuint offset, 206 | GLenum type) 207 | { 208 | setAttribute(name, size, stride, offset, false, type); 209 | } 210 | 211 | void ShaderProgram::setAttribute(const std::string &name, 212 | GLint size, 213 | GLsizei stride, 214 | GLuint offset) 215 | { 216 | setAttribute(name, size, stride, offset, false, GL_FLOAT); 217 | } 218 | 219 | void ShaderProgram::setUniform(const std::string &name, 220 | float x, 221 | float y, 222 | float z) 223 | { 224 | glUniform3f(uniform(name), x, y, z); 225 | } 226 | void ShaderProgram::setUniform(const std::string &name, const vec2 &v) 227 | { 228 | glUniform2fv(uniform(name), 1, value_ptr(v)); 229 | } 230 | 231 | void ShaderProgram::setUniform(const std::string &name, const vec3 &v) 232 | { 233 | glUniform3fv(uniform(name), 1, value_ptr(v)); 234 | } 235 | 236 | void ShaderProgram::setUniform(const std::string &name, const dvec3 &v) 237 | { 238 | glUniform3dv(uniform(name), 1, value_ptr(v)); 239 | } 240 | 241 | void ShaderProgram::setUniform(const std::string &name, const vec4 &v) 242 | { 243 | glUniform4fv(uniform(name), 1, value_ptr(v)); 244 | } 245 | 246 | void ShaderProgram::setUniform(const std::string &name, const dvec4 &v) 247 | { 248 | glUniform4dv(uniform(name), 1, value_ptr(v)); 249 | } 250 | 251 | void ShaderProgram::setUniform(const std::string &name, const dmat4 &m) 252 | { 253 | glUniformMatrix4dv(uniform(name), 1, GL_FALSE, value_ptr(m)); 254 | } 255 | 256 | void ShaderProgram::setUniform(const std::string &name, const mat4 &m) 257 | { 258 | glUniformMatrix4fv(uniform(name), 1, GL_FALSE, value_ptr(m)); 259 | } 260 | 261 | void ShaderProgram::setUniform(const std::string &name, const mat3 &m) 262 | { 263 | glUniformMatrix3fv(uniform(name), 1, GL_FALSE, value_ptr(m)); 264 | } 265 | 266 | void ShaderProgram::setUniform(const std::string &name, float val) 267 | { 268 | glUniform1f(uniform(name), val); 269 | } 270 | 271 | void ShaderProgram::setUniform(const std::string &name, int val) 272 | { 273 | glUniform1i(uniform(name), val); 274 | } 275 | 276 | ShaderProgram::~ShaderProgram() 277 | { 278 | glDeleteProgram(handle); 279 | } 280 | 281 | void ShaderProgram::use() const 282 | { 283 | glUseProgram(handle); 284 | } 285 | void ShaderProgram::unuse() const 286 | { 287 | glUseProgram(0); 288 | } 289 | 290 | GLuint ShaderProgram::getHandle() const 291 | { 292 | return handle; 293 | } 294 | -------------------------------------------------------------------------------- /ExampleProject/src/SampleScene.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * SampleScene.cpp 3 | * Contributors: 4 | * * Arthur Sonzogni (author), Looking Glass Factory Inc. 5 | * Licence: 6 | * * MIT 7 | */ 8 | 9 | #ifdef WIN32 10 | #pragma warning(disable : 4464 4820 4514 5045 4201 5039 4061 4710 4458 4626 5027) 11 | #endif 12 | 13 | #include "SampleScene.hpp" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "glError.hpp" 22 | 23 | #ifdef _DEBUG 24 | static const bool capture_mouse = false; 25 | #else 26 | static const bool capture_mouse = true; 27 | #endif 28 | 29 | struct VertexType 30 | { 31 | glm::vec3 position; 32 | glm::vec3 normal; 33 | glm::vec4 color; 34 | }; 35 | 36 | float heightMap(const glm::vec2 position) 37 | { 38 | return float(2.0 * sin(position.x) * sin(position.y)); 39 | } 40 | 41 | VertexType getHeightMap(const glm::vec2 position) 42 | { 43 | const glm::vec2 dx(1.0, 0.0); 44 | const glm::vec2 dy(0.0, 1.0); 45 | 46 | VertexType v; 47 | float h = heightMap(position); 48 | float hx = 100.f * (heightMap(position + 0.01f * dx) - h); 49 | float hy = 100.f * (heightMap(position + 0.01f * dy) - h); 50 | 51 | v.position = glm::vec3(position, h); 52 | v.normal = glm::normalize(glm::vec3(-hx, -hy, 1.0)); 53 | 54 | float c = float(sin(h * 5.f) * 0.5 + 0.5); 55 | v.color = glm::vec4(c, 1.0 - c, 1.0, 1.0); 56 | return v; 57 | } 58 | 59 | SampleScene::SampleScene() : HoloPlayContext(capture_mouse) 60 | { 61 | glCheckError(__FILE__, __LINE__); 62 | 63 | // creation of the mesh ------------------------------------------------------ 64 | std::vector vertices; 65 | std::vector index; 66 | 67 | for (unsigned int y = 0; y <= size; ++y) 68 | for (unsigned int x = 0; x <= size; ++x) 69 | { 70 | float xx = (float(x) - float(size) / 2.0f) * 0.1f; 71 | float yy = (float(y) - float(size) / 2.0f) * 0.1f; 72 | vertices.push_back(getHeightMap({xx, yy})); 73 | } 74 | 75 | for (unsigned int y = 0; y < size; ++y) 76 | for (unsigned int x = 0; x < size; ++x) 77 | { 78 | index.push_back((x + 0) + (size + 1) * (y + 0)); 79 | index.push_back((x + 1) + (size + 1) * (y + 0)); 80 | index.push_back((x + 1) + (size + 1) * (y + 1)); 81 | 82 | index.push_back((x + 1) + (size + 1) * (y + 1)); 83 | index.push_back((x + 0) + (size + 1) * (y + 1)); 84 | index.push_back((x + 0) + (size + 1) * (y + 0)); 85 | } 86 | 87 | std::cout << "vertices=" << vertices.size() << std::endl; 88 | std::cout << "index=" << index.size() << std::endl; 89 | 90 | // creation of the vertex array buffer---------------------------------------- 91 | 92 | // vbo 93 | glGenBuffers(1, &vbo); 94 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 95 | glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(vertices.size() * sizeof(VertexType)), 96 | vertices.data(), GL_STATIC_DRAW); 97 | glBindBuffer(GL_ARRAY_BUFFER, 0); 98 | 99 | // ibo 100 | glGenBuffers(1, &ibo); 101 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 102 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, GLsizeiptr(index.size() * sizeof(GLuint)), 103 | index.data(), GL_STATIC_DRAW); 104 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 105 | 106 | // vao 107 | glGenVertexArrays(1, &vao); 108 | glBindVertexArray(vao); 109 | 110 | // bind vbo 111 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 112 | 113 | const char *fragmentShaderSource = R"--( 114 | #version 150 115 | 116 | in vec4 fPosition; 117 | in vec4 fColor; 118 | in vec4 fLightPosition; 119 | in vec3 fNormal; 120 | 121 | // output 122 | out vec4 color; 123 | 124 | void main(void) 125 | { 126 | vec3 o =-normalize(fPosition.xyz); 127 | vec3 n = normalize(fNormal); 128 | vec3 r = reflect(o,n); 129 | vec3 l = normalize(fLightPosition.xyz-fPosition.xyz); 130 | 131 | float ambient = 0.1; 132 | float diffus = 0.7*max(0.0,dot(n,l)); 133 | float specular = 0.6*pow(max(0.0,-dot(r,l)),4.0); 134 | 135 | color = vec4(ambient + fColor.xyz * diffus + specular, fColor.w); 136 | } 137 | )--"; 138 | const char *vertexShaderSource = R"--( 139 | #version 150 140 | 141 | in vec3 position; 142 | in vec3 normal; 143 | in vec4 color; 144 | 145 | uniform mat4 projection; 146 | uniform mat4 view; 147 | 148 | out vec4 fPosition; 149 | out vec4 fColor; 150 | out vec4 fLightPosition; 151 | out vec3 fNormal; 152 | 153 | void main(void) 154 | { 155 | fPosition = view * vec4(position,1.0); 156 | fLightPosition = view * vec4(0.0,0.0,1.0,1.0); 157 | 158 | fColor = color; 159 | fNormal = vec3(view * vec4(normal,0.0)); 160 | 161 | gl_Position = projection * fPosition; 162 | /*gl_Position.x *= 1000.0f;*/ 163 | /*gl_Position.y = 0.0;*/ 164 | } 165 | )--"; 166 | Shader vertexShader(GL_VERTEX_SHADER, vertexShaderSource); 167 | Shader fragmentShader(GL_FRAGMENT_SHADER, fragmentShaderSource); 168 | 169 | shaderProgram = new ShaderProgram({vertexShader, fragmentShader}); 170 | 171 | // map vbo to shader attributes 172 | shaderProgram->setAttribute("position", 3, sizeof(VertexType), 173 | offsetof(VertexType, position)); 174 | shaderProgram->setAttribute("normal", 3, sizeof(VertexType), 175 | offsetof(VertexType, normal)); 176 | shaderProgram->setAttribute("color", 4, sizeof(VertexType), 177 | offsetof(VertexType, color)); 178 | 179 | // bind the ibo 180 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 181 | 182 | // vao end 183 | glBindVertexArray(0); 184 | } 185 | 186 | // process input: query GLFW if relevant keys are pressed/released 187 | // if ESC pressed, return false 188 | // --------------------------------------------------------------------------------------------------------- 189 | bool SampleScene::processInput(GLFWwindow *window) 190 | { 191 | if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) 192 | return false; 193 | 194 | int new_debug = 0; 195 | 196 | if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) 197 | new_debug = 1; 198 | 199 | if (debug != new_debug) 200 | { 201 | debug = new_debug; 202 | lightFieldShader->use(); 203 | lightFieldShader->setUniform("debug", debug); 204 | lightFieldShader->unuse(); 205 | } 206 | 207 | // Here add your code to control the camera by keys 208 | float cameraSpeed = 5 * deltaTime; 209 | if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) 210 | cameraPos += cameraSpeed * cameraFront; 211 | if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) 212 | cameraPos -= cameraSpeed * cameraFront; 213 | if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) 214 | cameraPos += 215 | glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; 216 | if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) 217 | cameraPos -= 218 | glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; 219 | 220 | return true; 221 | } 222 | 223 | // glfw: whenever the mouse moves, this callback is called 224 | // ------------------------------------------------------- 225 | void SampleScene::mouse_callback(GLFWwindow*, double xpos, double ypos) 226 | { 227 | if (firstMouse) 228 | { 229 | lastX = float(xpos); 230 | lastY = float(ypos); 231 | firstMouse = false; 232 | } 233 | 234 | float xoffset = float(xpos) - lastX; 235 | float yoffset = 236 | lastY - float(ypos); // reversed since y-coordinates go from bottom to top 237 | 238 | lastX = float(xpos); 239 | lastY = float(ypos); 240 | 241 | float sensitivity = 0.01f; // change this value to your liking 242 | xoffset *= -sensitivity; 243 | yoffset *= -sensitivity; 244 | 245 | yaw += xoffset; 246 | pitch += yoffset; 247 | 248 | // make sure that when pitch is out of bounds, screen doesn't get flipped 249 | if (pitch > 89.0f) 250 | pitch = 89.0f; 251 | if (pitch < -89.0f) 252 | pitch = -89.0f; 253 | 254 | glm::vec3 front; 255 | front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch)); 256 | front.y = sin(glm::radians(pitch)); 257 | front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch)); 258 | cameraFront = glm::normalize(front); 259 | } 260 | 261 | // mouse scroll feed back 262 | void SampleScene::scroll_callback(GLFWwindow*, 263 | double, 264 | double yoffset) 265 | { 266 | // here we implement zoom in and zoom out control 267 | const float MAX_SIZE = 10; // for example 268 | const float MIN_SIZE = 1; // for example 269 | if (cameraSize >= MIN_SIZE && cameraSize <= MAX_SIZE) 270 | cameraSize -= float(yoffset); 271 | if (cameraSize <= MIN_SIZE) 272 | cameraSize = MIN_SIZE; 273 | if (cameraSize >= MAX_SIZE) 274 | cameraSize = MAX_SIZE; 275 | } 276 | 277 | void SampleScene::update() 278 | { 279 | // add your updates for each frame here 280 | } 281 | 282 | void SampleScene::onExit() 283 | { 284 | glDeleteVertexArrays(1, &vao); 285 | glDeleteBuffers(1, &vbo); 286 | glDeleteBuffers(1, &ibo); 287 | delete shaderProgram; 288 | } 289 | 290 | glm::mat4 SampleScene::getViewMatrixOfCurrentFrame() 291 | { 292 | return glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); 293 | } 294 | 295 | void SampleScene::renderScene() 296 | { 297 | glCheckError(__FILE__, __LINE__); 298 | 299 | // clear 300 | glClear(GL_COLOR_BUFFER_BIT); 301 | glClearColor(0.0, 0.0, 0.0, 1.0); 302 | 303 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 304 | glCheckError(__FILE__, __LINE__); 305 | 306 | shaderProgram->use(); 307 | glCheckError(__FILE__, __LINE__); 308 | 309 | // holoplay special camera setup for each view, don't delete 310 | shaderProgram->setUniform("view", GetViewMatrixOfCurrentView()); 311 | shaderProgram->setUniform("projection", GetProjectionMatrixOfCurrentView()); 312 | glCheckError(__FILE__, __LINE__); 313 | 314 | // render your scene here as usual 315 | glBindVertexArray(vao); 316 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 317 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 318 | 319 | glCheckError(__FILE__, __LINE__); 320 | glDrawElements(GL_TRIANGLES, // mode 321 | GLsizei(size * size * 2 * 3), // count 322 | GL_UNSIGNED_INT, // type 323 | NULL // element array buffer offset 324 | ); 325 | 326 | glBindVertexArray(0); 327 | 328 | shaderProgram->unuse(); 329 | } 330 | -------------------------------------------------------------------------------- /HoloPlayCore/include/HoloPlayCore.h: -------------------------------------------------------------------------------- 1 | /* 2 | HoloPlayCore 0.1.1 3 | 4 | Intended for use with HoloPlay Service 1.0.1 and above. 5 | 6 | File: include/HoloPlayCore.h 7 | 8 | Author: Evan Kahn 9 | Contact: evan@lookingglassfactory.com 10 | 11 | This header contains declarations for functions in the HoloPlayCore dynamic library, 12 | which handles communication with the HoloPlay Service runtime. 13 | 14 | A programmer looking to design a custom renderer for Looking Glass devices ought only to 15 | need the functions declared in this header file. They have simple arguments and return types, 16 | and are designed to be easily bound from any programming language and dropped into custom 17 | rendering pipelines. 18 | 19 | Nearly all of them map directly to combinations of functions declared in libHoloPlayCore.h; 20 | they are provided for developer convenience and simple cross-language binding of functions 21 | that might return structs or opaque object pointers. For insight on how these work under the 22 | hood and more direct access to the data they provide, see that file. 23 | 24 | Copyright 2020 Looking Glass Factory 25 | 26 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 27 | and associated documentation files (the "Software"), to deal in the Software without 28 | restriction, including without limitation the rights to use, copy, modify, merge, publish, 29 | distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 30 | Software is furnished to do so, subject to the following conditions: 31 | 32 | The above copyright notice and this permission notice shall be included in all copies or 33 | substantial portions of the Software. 34 | 35 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 36 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 37 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 38 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 39 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 40 | 41 | */ 42 | 43 | 44 | #ifndef IMPORT_DECL 45 | #ifdef _WIN32 46 | #ifdef HPC_STATIC 47 | #define IMPORT_DECL 48 | #else 49 | #define IMPORT_DECL __declspec(dllimport) 50 | #endif 51 | #else 52 | #define IMPORT_DECL 53 | #endif 54 | #endif 55 | 56 | #include "libHoloPlayCore.h" 57 | 58 | #ifdef __cplusplus 59 | extern "C" 60 | { 61 | #endif 62 | 63 | /* 64 | Note on string return functions: 65 | 66 | Any function of the form "size_t hpc_DoThing(..., char* out_buf, size_t out_buf_sz)" copies a 67 | string into a preallocated buffer of size out_buf_sz. The buffer is allocated and owned by 68 | the caller. 69 | 70 | These functions return 0 if out_buf_sz was sufficient, or the actual size of string if 71 | out_buf_sz was too small. 72 | 73 | This makes it much easier to pass strings into managed memory (i.e. for .NET bindings). 74 | Most of the strings returned by these functions are quite small. 75 | */ 76 | 77 | /* 78 | hpc_InitializeApp 79 | 80 | Registers a client app with HoloPlay Service, and updates the global state variable. 81 | If you intend to register an app under a specific name, this *MUST* be the first 82 | function call you make. 83 | 84 | Future versions of HoloPlayService and HoloPlayCore will refuse to return calibration 85 | information unless hpc_InitializeApp has been called first. 86 | 87 | Args: name of application (will be registered by HoloPlay Service) 88 | Application commercial licensing type (see hpc_license_type) 89 | Returns: error code returned from HoloPlay Service request. 90 | */ 91 | IMPORT_DECL hpc_client_error hpc_InitializeApp(const char *app_name, hpc_license_type app_type); 92 | 93 | /* 94 | hpc_RefreshState 95 | 96 | Send a new message to HoloPlayService requesting updated device information; 97 | overwrite the state variable storing that information. hpc_InitializeApp will 98 | initially populate this variable. 99 | Call this function again to update that variable. 100 | 101 | Args: none 102 | Returns: error code returned from HoloPlay Service request. (See libHoloPlayCore.h 103 | for error code definitions.) 104 | */ 105 | 106 | IMPORT_DECL hpc_client_error hpc_RefreshState(void); 107 | 108 | /* 109 | hpc_CloseApp 110 | 111 | Closes connection to HoloPlay Service. This should *always* be called before your 112 | app exits. 113 | 114 | Args: none 115 | Returns: error code returned from HoloPlay Service request. 116 | */ 117 | IMPORT_DECL int hpc_CloseApp(void); 118 | 119 | /* 120 | hpc_GetHoloPlayCoreVersion 121 | 122 | Args: (see note on string return functions) 123 | Returns: current version of HoloPlay Core, as a string 124 | */ 125 | IMPORT_DECL size_t hpc_GetHoloPlayCoreVersion(char *out_buf, size_t out_buf_sz); 126 | 127 | /* 128 | The following are helper functions to query information from the state message, 129 | meaning that they will only return valid information following the invocation 130 | of hpc_InitializeApp(), and only return new information after hpc_RefreshState(). 131 | */ 132 | 133 | /* 134 | hpc_GetStateAsJson 135 | 136 | Args: (see note on string return functions) 137 | Returns: The current state message, serialized into a char buffer as JSON. 138 | 139 | Mostly useful for debugging - custom message queries can be constructed without 140 | an external JSON serializer, using the helper functions in libHoloPlayCore.h. 141 | */ 142 | IMPORT_DECL size_t hpc_GetStateAsJSON(char *out_buf, size_t out_buf_sz); 143 | 144 | /* 145 | hpc_GetHoloPlayServiceVersion 146 | 147 | Args: (see note on string return functions) 148 | Returns: current version of HoloPlay Service, as a string 149 | */ 150 | IMPORT_DECL size_t hpc_GetHoloPlayServiceVersion(char *out_buf, size_t out_buf_sz); 151 | 152 | /* 153 | hpc_GetNumDevices 154 | 155 | Args: none 156 | Returns: number of Looking Glass devices connnected with valid calibrations. 157 | */ 158 | IMPORT_DECL int hpc_GetNumDevices(); 159 | 160 | /* 161 | hpc_GetDeviceHDMIName 162 | 163 | Args: (see note on string return functions) 164 | Returns: Looking Glass device name retrieved from EDID. 165 | */ 166 | IMPORT_DECL size_t hpc_GetDeviceHDMIName(int dev_index, char *out_buf, size_t out_buf_sz); 167 | 168 | /* 169 | hpc_GetDeviceSerial 170 | 171 | Args: (see note on string return functions) 172 | Returns: Serial number of device (same as the one printed on label) 173 | */ 174 | IMPORT_DECL size_t hpc_GetDeviceSerial(int dev_index, char *out_buf, size_t out_buf_sz); 175 | 176 | /* 177 | hpc_GetDeviceType 178 | 179 | Args: (see note on string return functions) 180 | Returns: Device type as string (currently one of "standard", "large", "pro", "8k") 181 | */ 182 | IMPORT_DECL size_t hpc_GetDeviceType(int dev_index, char *out_buf, size_t out_buf_sz); 183 | 184 | /* 185 | hpc_GetDeviceProperty functions 186 | 187 | The following functions query per-device configuration parameters. 188 | They will return 0 if the device or calibration isn't found. 189 | 190 | Args: device index 191 | Returns: varies 192 | 193 | A note on device indexing: 194 | 195 | HoloPlay Service assigns each connected device a persistent index, 196 | starting from 0. When a new device is connected, HoloPlay Service will 197 | assign it the lowest index available. 198 | 199 | In certain situations, there may be no device present at a certain index. 200 | For instance, if two devices are connected, they will receive indices 0, then 1, 201 | respectively. If the device indexed 0 is disconnected, there will be a device 202 | present at index 1 but not at index 0. The next device to be connected will be 203 | assigned index 0. 204 | */ 205 | 206 | /* 207 | hpc_GetDevicePropertyWinX 208 | 209 | Returns: X position of monitor, in window coordinates, reported by OS. 210 | */ 211 | IMPORT_DECL int hpc_GetDevicePropertyWinX(int dev_index); 212 | 213 | /* 214 | hpc_GetDevicePropertyWinY 215 | 216 | Returns: Y position of monitor, in window coordinates, reported by OS. 217 | */ 218 | IMPORT_DECL int hpc_GetDevicePropertyWinY(int dev_index); 219 | 220 | /* 221 | The following functions return values retrieved from the lenticular 222 | calibration file associated with the device and transmitted over USB. 223 | 224 | They should be loaded into the lenticular shader as uniform parameters 225 | of the same name and type. 226 | */ 227 | 228 | /* 229 | hpc_GetDevicePropertyScreenW 230 | 231 | Returns: screen width in pixels 232 | */ 233 | IMPORT_DECL int hpc_GetDevicePropertyScreenW(int dev_index); 234 | 235 | /* 236 | hpc_GetDevicePropertyScreenH 237 | 238 | Returns: screen height in pixels 239 | */ 240 | IMPORT_DECL int hpc_GetDevicePropertyScreenH(int dev_index); 241 | 242 | /* 243 | hpc_GetDevicePropertyInvView 244 | 245 | Returns: whether the lenticular shader should be inverted. (1 or 0) 246 | */ 247 | IMPORT_DECL int hpc_GetDevicePropertyInvView(int dev_index); 248 | 249 | /* 250 | hpc_GetDevicePropertyRi 251 | 252 | Returns: 'red index' of each lenticular subpixel. (0 or 2) 253 | */ 254 | IMPORT_DECL int hpc_GetDevicePropertyRi(int dev_index); 255 | 256 | /* 257 | hpc_GetDevicePropertyBi 258 | 259 | Returns: 'blue index' of each lenticular subpixel. (0 or 2) 260 | */ 261 | IMPORT_DECL int hpc_GetDevicePropertyBi(int dev_index); 262 | 263 | /* 264 | hpc_GetDevicePropertyPitch 265 | 266 | Returns: lenticular lens pitch. 267 | */ 268 | IMPORT_DECL float hpc_GetDevicePropertyPitch(int dev_index); 269 | 270 | /* 271 | hpc_GetDevicePropertyCenter 272 | 273 | Returns: lenticular center offset. 274 | */ 275 | IMPORT_DECL float hpc_GetDevicePropertyCenter(int dev_index); 276 | 277 | /* 278 | hpc_GetDevicePropertyTilt 279 | 280 | Returns: lenticular tilt angle. 281 | */ 282 | IMPORT_DECL float hpc_GetDevicePropertyTilt(int dev_index); 283 | 284 | /* 285 | hpc_GetDevicePropertyAspect 286 | 287 | Returns: display aspect ratio. (Equal to ScreenW/ScreenH) 288 | */ 289 | IMPORT_DECL float hpc_GetDevicePropertyDisplayAspect(int dev_index); 290 | 291 | /* 292 | hpc_GetDevicePropertyFringe 293 | 294 | Returns: display fringe correction uniform. (Currently only 295 | applicable to Large/Pro units.) 296 | */ 297 | IMPORT_DECL float hpc_GetDevicePropertyFringe(int dev_index); 298 | 299 | /* 300 | hpc_GetDevicePropertySubp 301 | 302 | Returns: display subpixel size. 303 | */ 304 | IMPORT_DECL float hpc_GetDevicePropertySubp(int dev_index); 305 | 306 | /* 307 | hpc_GetDevicePropertyQuiltX 308 | 309 | Returns: recommended horizontal quilt texture resolution. 310 | Note: Only works with Holoplay Service 1.2.0 or later; Holoplay Core 0.1.2 or later 311 | */ 312 | IMPORT_DECL int hpc_GetDevicePropertyQuiltX(int dev_index); 313 | 314 | /* 315 | hpc_GetDevicePropertyQuiltY 316 | 317 | Returns: recommended vertical quilt texture resolution. 318 | Note: Only works with Holoplay Service 1.2.0 or later; Holoplay Core 0.1.2 or later 319 | */ 320 | IMPORT_DECL int hpc_GetDevicePropertyQuiltY(int dev_index); 321 | 322 | /* 323 | hpc_GetDevicePropertyTileX 324 | 325 | Returns: recommended horizontal quilt tiling dimension 326 | Note: Only works with Holoplay Service 1.2.0 or later; Holoplay Core 0.1.2 or later 327 | */ 328 | IMPORT_DECL int hpc_GetDevicePropertyTileX(int dev_index); 329 | 330 | /* 331 | hpc_GetDevicePropertyTileY 332 | 333 | Returns: recommended vertical quilt tiling dimension 334 | Note: Only works with Holoplay Service 1.2.0 or later; Holoplay Core 0.1.2 or later 335 | */ 336 | IMPORT_DECL int hpc_GetDevicePropertyTileY(int dev_index); 337 | 338 | /* 339 | hpc_GetDevicePropertyQuiltAspect 340 | 341 | Returns: recommended quilt aspect ratio. 342 | Note: Only works with Holoplay Service 1.2.0 or later; Holoplay Core 0.1.2 or later 343 | */ 344 | IMPORT_DECL float hpc_GetDevicePropertyQuiltAspect(int dev_index); 345 | #ifdef __cplusplus 346 | } 347 | #endif 348 | -------------------------------------------------------------------------------- /HoloPlayCore/include/libHoloPlayCore.h: -------------------------------------------------------------------------------- 1 | /* 2 | HoloPlayCore 0.1.1 3 | 4 | Intended for use with HoloPlay Service 1.0.1 and above. 5 | 6 | File: include/HoloPlayCore.h 7 | 8 | Author: Evan Kahn 9 | Contact: evan@lookingglassfactory.com 10 | 11 | This header contains declarations for functions in the HoloPlayCore dynamic library, 12 | which handles communication with the HoloPlay Service runtime. 13 | 14 | A programmer looking to design a custom renderer for Looking Glass devices may not need to 15 | understand the functions and types declared in this header file. They handle communication 16 | with HoloPlay Service via the NNG interprocess communication library and provide abstractions 17 | for the CBOR-serialized messages returned from it, to provide easy access from both low- and 18 | high- level languages. 19 | 20 | Convenience functions that implement these under the hood are declared in HoloPlayCore.h. 21 | 22 | Copyright 2020 Looking Glass Factory 23 | 24 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 25 | and associated documentation files (the "Software"), to deal in the Software without 26 | restriction, including without limitation the rights to use, copy, modify, merge, publish, 27 | distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 28 | Software is furnished to do so, subject to the following conditions: 29 | 30 | The above copyright notice and this permission notice shall be included in all copies or 31 | substantial portions of the Software. 32 | 33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 34 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 35 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 36 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 37 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 38 | */ 39 | 40 | #ifdef __cplusplus 41 | extern "C" 42 | { 43 | #endif 44 | /* 45 | Note on string return functions: 46 | 47 | Any function of the form "size_t hpc_DoThing(..., char* out_buf, size_t out_buf_sz)" copies a 48 | string into a preallocated buffer of size out_buf_sz. The buffer is allocated and owned by 49 | the caller. 50 | 51 | These functions return 0 if out_buf_sz was sufficient, or the actual size of string if 52 | out_buf_sz was too small. 53 | 54 | This makes it much easier to pass strings into managed memory (i.e. for .NET bindings). 55 | Most of the strings returned by these functions are quite small. 56 | */ 57 | 58 | /* 59 | hpc_client_error 60 | 61 | Enum definition for errors returned from the HoloPlayCore dynamic library. 62 | 63 | This encapsulates potential errors with the connection itself, 64 | as opposed to hpc_service_error, which describes potential error messages 65 | included in a successful reply from HoloPlay Service. 66 | */ 67 | typedef enum _hpc_client_error 68 | { 69 | hpc_CLIERR_NOERROR, // no error, everything ok 70 | hpc_CLIERR_NOSERVICE, // HoloPlay Service not installed or not running 71 | hpc_CLIERR_VERSIONERR, // HoloPlay Service / HoloPlay Core version mismatch 72 | hpc_CLIERR_SERIALIZEERR, // Something wrong with serilization of message data being sent to HoloPlay Service 73 | hpc_CLIERR_DESERIALIZEERR, // Something wrong with serilization of message data being received from HoloPlay Service 74 | hpc_CLIERR_MSGTOOBIG, // Message sent was too large and was rejected 75 | hpc_CLIERR_SENDTIMEOUT, // HoloPlay Service was detected but did not consume message 76 | hpc_CLIERR_RECVTIMEOUT, // HoloPlay Service received message but did not respond 77 | hpc_CLIERR_PIPEERROR, // Some other problem with communication 78 | hpc_CLIERR_APPNOTINITIALIZED // hpc_RefreshState called before hpc_InitializeApp 79 | } hpc_client_error; 80 | 81 | /* 82 | hpc_service_error 83 | 84 | Enum definition for error codes included in HoloPlay Service responses. 85 | 86 | Most error messages from HoloPlay Service concern access to the HoloPlay Service 87 | internal renderer, which is supported but not the primary focus of the current 88 | version of HoloPlay Core. 89 | 90 | Future versions of HoloPlay Service may return error codes not defined by this 91 | spec. 92 | */ 93 | typedef enum _hpc_service_error 94 | { 95 | hpc_ERR_NOERROR, // no error, everything ok 96 | hpc_ERR_BADCBOR, // HoloPlay Service could not deserialize message as sent 97 | hpc_ERR_BADCOMMAND, // Message as parsed is invalid or not allowed 98 | hpc_ERR_NOIMAGE, // HoloPlay Service expected image data in the message but did not receive any 99 | hpc_ERR_LKGNOTFOUND, // Command refers to a Looking Glass that isn't connected 100 | hpc_ERR_NOTINCACHE, // Command requested that HoloPlay Service load a cached quilt image that doesn't exist 101 | hpc_ERR_INITTOOLATE, // App tried to initialize with appid after it had already sent messages 102 | hpc_ERR_NOTALLOWED, // Action requested by command isn't allowed for some other reason 103 | hpc_ERR_INTERNAL1 // Don't worry about this one :) 104 | } hpc_service_error; 105 | 106 | /* 107 | hpc_license_type 108 | 109 | Enum definition for possible types of licenses associated with a HoloPlay Core app. 110 | 111 | Non-commercial apps can't run on Looking Glass devices without an associated commercial license. 112 | */ 113 | typedef enum _hpc_license_type 114 | { 115 | hpc_LICENSE_NONCOMMERCIAL, 116 | hpc_LICENSE_COMMERCIAL 117 | } hpc_license_type; 118 | 119 | /* 120 | hpc_obj 121 | 122 | Opaque pointer type that references an object from the jsoncons::json C++ library 123 | (https://github.com/danielaparker/jsoncons/), a static dependency of HoloPlay Core. 124 | Objects of this type can be sent to and received from HoloPlay Service, and manipulated 125 | without an external deserializer using the other functions declared in this file. 126 | */ 127 | typedef void *hpc_obj; 128 | 129 | /* 130 | hpc_StateMsgInstance 131 | 132 | Args: none 133 | Returns: pointer to the global state variable from HoloPlay Service. Null if no state 134 | message has been requested. For more information on the global state message, see 135 | hpc_InitializeApp and hpc_RefreshState in HoloPlayCore.h. 136 | */ 137 | IMPORT_DECL hpc_obj *hpc_StateMsgInstance(); 138 | 139 | /* 140 | hpc_MakeObject 141 | 142 | Serializes, allocates, and constructs an opaque hpc_obj, which can be sent to HoloPlay Service. 143 | Messages must include a command part, which will be converted from JSON, and an optional 144 | binary field, which can include quilt data to send to the HoloPlay Service internal renderer. 145 | 146 | Args: JSON command string; binary message length; binary start pointer. 147 | Returns: opaque pointer to the created object. Null if cmd is not a valid JSON string. 148 | */ 149 | IMPORT_DECL hpc_obj *hpc_MakeObject(const char *cmd_json, const size_t binlen, const unsigned char *bin); 150 | 151 | /* 152 | hpc_DeleteObject 153 | 154 | Calls the C++ destructor of an hpc_object. 155 | 156 | Args: object to destroy 157 | Returns: none 158 | */ 159 | IMPORT_DECL void hpc_DeleteObject(hpc_obj *obj); 160 | 161 | /* 162 | hpc_ObjQuery functions 163 | 164 | This group of functions returns primitive values queried from opaque hpc_obj items. 165 | 166 | They are just C wrappers for deserialization calls in the C++ jsoncons dependency, 167 | using the jsonpointer query syntax to request values from inside a hierarchy. 168 | More information on jsonpointer can be found here: https://tools.ietf.org/html/rfc6901 169 | 170 | Args: object to query; jsonpointer query string 171 | Returns: query result; 0 if query has failed. 172 | */ 173 | 174 | IMPORT_DECL int hpc_ObjQueryInt(const hpc_obj *obj, const char *query_string); 175 | IMPORT_DECL float hpc_ObjQueryFloat(const hpc_obj *obj, const char *query_string); 176 | 177 | /* 178 | hpc_ObjQueryString 179 | 180 | Args: object to query; jsonpointer query string; return buffer and size (see note on 181 | string return functions). out_buf will be unmodified if query fails. 182 | */ 183 | IMPORT_DECL size_t hpc_ObjQueryString(const hpc_obj *obj, const char *query_string, char *out_buf, size_t out_buf_sz); 184 | 185 | /* 186 | hpc_ObjGetLength 187 | 188 | Args: object to query; jsonpointer query string 189 | Returns: length of JSON subvalue - ONLY if it is an array type. 0 otherwise. 190 | */ 191 | IMPORT_DECL int hpc_ObjGetLength(const hpc_obj *obj, const char *query_string); 192 | 193 | /* 194 | hpc_ObjAsJson 195 | 196 | Args: object to query; jsonpointer query string 197 | Returns: JSON serialized string representation of object (see note on string return 198 | functions). 199 | */ 200 | IMPORT_DECL size_t hpc_ObjAsJson(const hpc_obj *obj, char *out_buf, size_t out_buf_sz); 201 | 202 | /* 203 | hpc_ObjGetErrorCode 204 | 205 | Args: object to query 206 | Returns: HoloPlay Service error message associated with object. (Obviously, this 207 | only makes sense when applied to an hpc_obj returned from a HoloPlay Service response). 208 | */ 209 | IMPORT_DECL hpc_service_error hpc_ObjGetErrorCode(const hpc_obj *message); 210 | 211 | /* 212 | hpc_GetDeviceProperty functions 213 | 214 | This group of functions returns primitive values queried from a specific device 215 | described in the global state object. 216 | 217 | Args: index of device to query 218 | Returns: query result (0 if query has failed). See note on string return functions 219 | for hpc_GetDevicePropertyString. 220 | */ 221 | IMPORT_DECL int hpc_GetDevicePropertyInt(int dev_index, const char *query_string); 222 | IMPORT_DECL float hpc_GetDevicePropertyFloat(int dev_index, const char *query_string); 223 | IMPORT_DECL size_t hpc_GetDevicePropertyString(int dev_index, const char *query_string, char *out_buf, size_t out_buf_sz); 224 | 225 | /* 226 | hpc_Send functions 227 | 228 | This group of functions sends messages to HoloPlay Service and allocates and 229 | retrieves the response. 230 | */ 231 | 232 | /* 233 | hpc_SendCallback 234 | 235 | This function sends an asynchronous message to HoloPlay Service and returns an allocated 236 | response as an argument to the provided callback function. 237 | 238 | Callback functions should be of the form: 239 | void cb(hpc_obj obj, hpc_client_error clierr, void *context) 240 | 241 | Args: request object; callback function name; context pointer 242 | Returns: client error (only if the error occurs with sending the message; errors 243 | incurred in receiving the response will be passed as a parameter into the callback 244 | function). 245 | */ 246 | IMPORT_DECL hpc_client_error hpc_SendCallback(const hpc_obj *request, void (*callback)(hpc_obj, hpc_client_error, void *), void *context); 247 | 248 | /* 249 | hpc_SendBlocking 250 | 251 | This function sends a synchronous message to HoloPlay Service and returns an allocated 252 | response. 253 | 254 | Args: request object; pointer to hpc_obj in which to store the response. The caller 255 | need not allocate memory for the response object. 256 | Returns: client error 257 | */ 258 | IMPORT_DECL hpc_client_error hpc_SendBlocking(const hpc_obj *request, hpc_obj **response); 259 | 260 | /* 261 | hpc_SetupMessagePipe 262 | 263 | Function to set up the connection to HoloPlay Service, without sending any messages. 264 | This will automatically be called when the first message is sent, but it can also be called 265 | earlier. 266 | There are very few reasons to call this directly. 267 | 268 | Args: none 269 | Returns: 0 if successful or 1 if the connection already exists. 270 | */ 271 | IMPORT_DECL int hpc_SetupMessagePipe(); 272 | 273 | /* 274 | hpc_TeardownMessagePipe 275 | 276 | Function to sever the connection to HoloPlay Service. 277 | This is called by hpc_CloseApp, so there is little reason to call it directly. 278 | 279 | Args: none 280 | Returns: 0 if successful or 1 if the connection is already closed. 281 | */ 282 | IMPORT_DECL int hpc_TeardownMessagePipe(); 283 | 284 | #ifdef __cplusplus 285 | } 286 | #endif 287 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Looking Glass Factory Inc. 2 | HOLOPLAY CORE LICENSE AGREEMENT 3 | IMPORTANT-READ CAREFULLY BEFORE USING THE APPLICATION PROGRAMMING INTERFACE: This HoloPlay Core License Agreement (“Agreement”) is a legal agreement between you and/or any company you represent (“Licensee”) and Looking Glass Factory Inc. (“LGF”), for the HoloPlay Core (the “Looking Glass HoloPlay Core”, “HoloPlay Core”, or collectively, “Core”) licensed by LGF. By accepting these terms or by installing, downloading, copying, or otherwise using Core, you agree to be and will be bound by the terms of this Agreement as a condition of your license. If you do not agree to the terms of this Agreement, your use is prohibited, and you may not install or use Core. 4 | 5 | Core is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. Core is licensed (not sold) to you, and its use is subject to the terms of this Agreement. This is NOT a sale contract. 6 | 7 | 1. DEFINITIONS. 8 | 1.1 “HoloPlay Core” or “Core” means LGF technology, which may include object code, software libraries, software tools, sample source code, published specifications and Documentation. Core shall include any future, updated or otherwise modified version(s) thereof furnished by LGF (in its sole discretion) to Licensee. 9 | 10 | 1.2 “Documentation” includes, but is not limited to programmer guides, CDs, manuals, materials, and information appropriate or necessary for use in connection with Core. 11 | 12 | 2. GRANT OF LICENSE. Subject to the terms of this Agreement, LGF hereby grants Licensee a limited, non- exclusive, non-transferable, royalty-free license (without the right to sublicense) to use Core solely for the purpose of Licensee’s development efforts to develop applications to work in conjunction with the LGF products referenced in Core and for which Core was provided. Licensee shall have no right to distribute, license (whether or not through multiple tiers) or otherwise transfer Core to any third party or incorporate Core in any software, product, or technology for use on anything other than LGF products. 13 | 14 | 3. OTHER RIGHTS AND LIMITATIONS. 15 | 3.1 Copies. Licensee may copy Core only as necessary to exercise its rights hereunder; provided, however that Licensee may also make one (1) copy for back-up purposes and any reproduction of Core must be marked with the proprietary notices provided on the original Core. 16 | 17 | 3.2 No Reverse Engineering. Licensee shall have no rights to any source code for any of the software in Core, except for the explicit rights to use the source code as provided to Licensee hereunder. Licensee may not reverse engineer, decompile, modify or disassemble Core or otherwise reduce Core to human-perceivable form in whole or in part, except and only to the extent that such activity is expressly permitted by this Agreement or applicable laws. 18 | 19 | 3.3 Third Party Software. Licensee acknowledges that effective utilization of Core may require the use of a development tool, compiler and other software and technology of third parties (“Third Party Software”). Licensee is solely responsible for procuring such Third Party Software and technology and the necessary licenses for the use thereof. LGF makes no representation or warranty concerning Third Party Software and shall have no obligation or liability with respect to Third Party Software. 20 | 21 | 3.4 No right is granted to Licensee to sublicense its rights hereunder. All rights not expressly granted are reserved by LGF and, except as expressly set forth herein, no license is granted by LGF under this Agreement directly, by implication, estoppel or otherwise, under any patent, copyright, trade secret or trademark or other intellectual property right of LGF. Nothing herein shall be deemed to authorize Licensee to use LGF’s trademarks or trade names in Licensee’s advertising, marketing, promotional, sales or related materials. 22 | 23 | 3.5 Nonassertion By Licensee. Licensee agrees not to assert any patent rights related to Core or applications developed using Core against LGF, LGF’s distributors, LGF customers, or other licensees of Core for making, using, selling, offering for sale, or importing any products or technology developed using Core. 24 | 25 | 3.6 Benchmark Tests. You may not publish the results of any benchmark tests run on Core without written permission from LGF. 26 | 27 | 4. OWNERSHIP. 28 | As between LGF and Licensee, LGF or its licensors shall own and retain all proprietary rights, including all patent, copyright, trade secret, trademark and other intellectual property rights, in and to Core and any corrections, bug fixes, enhancements, updates, improvements, or modifications thereto and Licensee hereby irrevocably transfers, conveys and assigns to LGF all of its right, title, and interest therein. LGF shall have the exclusive right to apply for or register any patents, mask work rights, copyrights, and such other proprietary protections with respect thereto. Licensee acknowledges that the license granted under this Agreement does not provide Licensee with title or ownership to Core, but only a right of limited use under the terms and conditions of this Agreement. 29 | 30 | 5. SUPPORT. 31 | LGF will not provide any support for Core under this Agreement. Nothing herein shall be construed to require LGF to provide support services or updates, upgrades, bug fixes or modifications to Core. 32 | 33 | 6. CONFIDENTIALITY. 34 | 6.1 Core contains valuable proprietary information and trade secrets of LGF and its suppliers that remain the property of LGF. You shall protect the confidentiality of, and avoid disclosure and unauthorized use of, Core. 35 | 36 | 6.2 Licensee shall not disclose, advertise, or publish the terms and conditions of this Agreement without the prior written consent of LGF. Any press release or publication regarding this Agreement is subject to prior review and written approval of LGF. 37 | 38 | 7. HEALTHCARE APPLICATIONS SUITABILITY. 39 | LICENSEE SHALL BE SOLELY RESPONSIBLE FOR ANY PRODUCT USE OR APPLICATION DEVELOPED USING LGF’S CORE THAT MAY FALL UNDER UNITED STATES FOOD AND DRUG ADMINISTRATION REGULATION, OR OTHER SUCH SIMILAR REGULATORY JURISDICTION, INCLUDING ANY AND ALL RESPONSIBILITY FOR COMPLIANCE TO SUCH REGULATION AS MAY BE APPLICABLE. LICENSEE ACKNOWLEDGES THAT LGF PROVIDES THE API AS A GENERAL PURPOSE DEVELOPMENT TOOL TO LICENSEE. 40 | 41 | 8. NO WARRANTY. 42 | Core and Documentation are provided "AS-IS" without any warranty whatsoever. TO THE FULL EXTENT ALLOWED BY LAW, THE FOREGOING WARRANTIES AND REMEDIES ARE EXCLUSIVE AND ARE IN LIEU OF ALL OTHER WARRANTIES, TERMS, OR CONDITIONS, EXPRESS OR IMPLIED, EITHER IN FACT OR BY OPERATION OF LAW, STATUTORY OR OTHERWISE, INCLUDING WARRANTIES, TERMS, OR CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, SATISFACTORY QUALITY, CORRESPONDENCE WITH DESCRIPTION, AND NON-INFRINGEMENT, ALL OF WHICH ARE EXPRESSLY DISCLAIMED. NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED BY YOU FROM LGF OR THROUGH OR FROM CORE SHALL CREATE ANY WARRANTY NOT EXPRESSLY STATED IN THIS AGREEMENT. LGF DOES NOT WARRANT THAT CORE AND DOCUMENTATION ARE SUITABLE FOR LICENSEE'S USE, THAT CORE OR DOCUMENTATION ARE WITHOUT DEFECT OR ERROR, THAT OPERATION WILL BE UNINTERRUPRED, OR THAT DEFECTS WILL BE CORRECTED. FURTHER, LGF MAKES NO WARRANTY REGARDING THE RESULTS OF THE USE OF CORE AND DOCUMENTATION. YOU ACKNOWLEDGE THAT LGF DOES NOT WARRANT THAT CORE WILL BE UNINTERRUPTED, TIMELY, SECURE, ERROR-FREE OR FREE FROM VIRUSES OR OTHER MALICIOUS SOFTWARE, AND NO INFORMATION OR ADVICE OBTAINED BY YOU FROM LGF OR THROUGH YOUR USE OF CORE SHALL CREATE ANY WARRANTY NOT EXPRESSLY STATED IN THIS AGREEMENT. 43 | 44 | 9. LIMITATION OF LIABILITY. 45 | YOUR USE OF CORE IS AT YOUR SOLE RISK. YOU WILL BE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR LOSS OF DATA THAT RESULTS FROM THE DOWNLOAD OR USE OF CORE. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL LGF OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION DAMAGES FOR LOSS OF BUSINESS PROFITS OR REVENUE; BUSINESS INTERRUPTION OR WORK STOPPAGE; COMPUTER FAILURE OR MALFUNCTION; LOSS OF BUSINESS INFORMATION, DATA OR DATA USE; LOSS OF GOODWILL; OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE CORE OR THE PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF LGF OR ITS SUPPLIER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL LGF’S SUPPLIERS BE LIABLE FOR ANY DIRECT DAMAGES WHATSOEVER ARISING OUT OF THE USE OR THE INABILITY TO USE CORE. IN ANY CASE, LGF’S ENTIRE LIABILITY SHALL BE LIMITED TO THE GREATER OF THE AMOUNT ACTUALLY PAID BY YOU FOR CORE OR U.S. $5.00. 46 | 47 | 10. INDEMNITY. 48 | You agree to indemnify and hold harmless LGF and its subsidiaries, affiliates, officers, agents, co-branders, customers, suppliers or other partners, and employees, from any loss, claim or demand, including reasonable attorneys' fees, made by any third party due to or arising out of your use of Core, your connection to Core, or your violation of the Terms. 49 | 50 | 11. DISCLAIMER. 51 | Some countries, states, or provinces do not allow the exclusion or limitation of implied warranties or the limitation of incidental or consequential damages for certain products supplied to consumers, or the limitation of liability for death or personal injury, so the above limitations and exclusions may be limited in their application to you. When the implied warranties are not allowed to be excluded in their entirety due to local law, they will be limited to the duration of the applicable warranty. 52 | 53 | 12. TERM AND TERMINATION. 54 | 12.1 This Agreement will terminate automatically if you fail to comply with any of the terms and conditions of this Agreement and you will be liable to LGF and its suppliers for damages or losses caused by your non-compliance. The waiver by LGF of a specific breach or default shall not constitute the waiver of any subsequent breach or default. 55 | 56 | 12.2 Either party shall have the right to terminate the Agreement, upon thirty (30) days written notice to the other party. 57 | 58 | 12.3 Upon termination of this Agreement, Licensee will immediately cease using Core, and Licensee agrees to destroy all adaptations or copies of Core and Documentation, or return them LGF upon termination of this License. 59 | 60 | 12.4 LGF shall have the right to audit your use of Core in conjunction with this Agreement, and you will provide reasonable assistance for this purpose. 61 | 62 | 12.5 The rights of LGF and your obligations contained in this Agreement survive any expiration or termination of this Agreement. 63 | 64 | 13. MISCELLANEOUS. 65 | 13.1 ASSIGNMENT. Licensee may not assign this Agreement, or any interest or rights granted hereunder to any third party without the prior written consent of LGF. A change of control or reorganization of Licensee pursuant to a merger, sale of assets or stock shall be deemed to be an assignment under this Agreement. This Agreement shall terminate immediately upon occurrence of any prohibited assignment. 66 | 67 | 13.2 EXPORT CONTROLS. You acknowledge that Core may be subject to export restrictions of various countries. You shall fully comply with all applicable export license restrictions and requirements as well as with all laws and regulations relating to the importation of Core, in the United States and in any foreign jurisdiction in which Core is used. Without limiting the foregoing, Core may not be downloaded or otherwise exported or re-exported (i) into (or to a national or resident of) any country to which the U.S. has embargoed goods; (ii) any end user known, or having reason to be known, will utilize them in the design, development or production of nuclear, chemical or biological weapons; or (iii) to anyone on the U.S. Treasury Department's list of Specially Designated Nationals or the U.S. Commerce Department's Table of Denial Orders. By downloading or using Core, you are agreeing to the foregoing and you are representing and warranting that you are not located in, under the control of, or a national or resident of any such country or on any such list. If you obtained Core outside of the United States, you are also agreeing that you will not export or re-export it in violation of the laws of the country in which it was obtained. You further acknowledge that Core may include technical data subject to export and re-export restrictions imposed by US law. 68 | 69 | 13.3 WAIVER. No failure by either party to exercise or enforce any of its rights under this Agreement will act as a waiver of such rights and no waiver of a breach in a particular situation shall be held to be a waiver of any other or subsequent breach. 70 | 71 | 13.4 SEVERABILITY. If any provision of this Agreement is found invalid or unenforceable, that provision will be enforced to the maximum extent possible and the other provisions of this Agreement will remain in force. 72 | 73 | 13.5 Governing Law. This Agreement shall be governed by the laws of the state of New York as such laws are applied to agreements entered into and to be performed entirely within New York between New York residents, and by the laws of the United States, without reference to conflict of laws principles. The United Nations Convention on Contracts for the International Sale of Goods (1980) and the Uniform Computer Information Transactions Act (UCITA) are hereby excluded in their entirety from application to this Agreement. 74 | 75 | 13.6 Entire Agreement. This Agreement represents the complete agreement concerning Core. 76 | 77 | 13.7 Contact. If you have any questions concerning this Agreement, or if you desire to contact LGF for any reason, please contact the LGF at support@lookingglassfactory.com. 78 | 79 | BY INSTALLING, COPYING, OR OTHERWISE USING CORE YOU ACKNOWLEDGE THAT YOU HAVE READ, UNDERSTAND AND AGREE TO BE BOUND BY THE TERMS AND CONDITIONS INDICATED ABOVE. 80 | -------------------------------------------------------------------------------- /ExampleProject/README.md: -------------------------------------------------------------------------------- 1 | HoloPlay Core Example Project 2 | === 3 | This is an example project that shows how to use [Looking Glass Core](https://docs.lookingglassfactory.com/core/core-sdk) to build a crossplatform holographic renderer for a Looking Glass display. It is based on [OpenGL CMake Skeleton](https://github.com/ArthurSonzogni/OpenGL_CMake_Skeleton) by Arthur Sonzogni, and depends on [GLFW](https://github.com/glfw/glfw/), [GLEW](https://github.com/omniavinco/glew-cmake/), and [glm](https://github.com/g-truc/glm). 4 | 5 | # Table of Contents 6 | * [Setup](#setup) 7 | - [Clone with Submodules](#clone-with-submodules) 8 | - [Installing CMake and Dependencies](#installing-cmake-and-dependencies) 9 | - [Build](#build) 10 | - [Linux](#linux) 11 | - [Windows](#windows) 12 | - [macOS](#macos) 13 | - [Run](#run) 14 | * [Rendering Holograms with the Looking Glass](#rendering-holograms-with-the-looking-glass) 15 | * [Introduction](#introduction) 16 | * [Key Steps](#key-steps) 17 | * [Initialization](#initialization--holoplaycontextholoplaycontext) 18 | * [Render Loop](#rendering--holoplaycontextrun) 19 | * [On Exit](#on-exit--holoplaycontextonexit) 20 | * [Set Up Virtual Camera](#set-up-virtual-camera--holoplaycontextsetupvirtualcameraforview) 21 | * [More References](#more-references) 22 | * [Project Structure](#project-structure) 23 | * [Making Use of Looking Glass Core](#making-use-of-looking-glass-core) 24 | * [Setup and Teardown](#setup-and-teardown) 25 | * [Shader related](#shader-related) 26 | * [Monitor Coordinates](#monitor-coordinates) 27 | * [View cone](#view-cone) 28 | * [Debug mode](#debug-mode) 29 | * [Other info](#other-info) 30 | 31 | # Setup 32 | 33 | ## Clone with submodules 34 | 35 | ```bash 36 | git clone --recursive https://github.com/Looking-Glass/LookingGlassCoreSDK.git 37 | ``` 38 | 39 | If you already have the repository and didn't use the `--recursive` option, you can type: 40 | ```bash 41 | git submodule update --init --recursive 42 | ``` 43 | 44 | ### Installing CMake and Dependencies 45 | 46 | Follow [these instructions](https://cmake.org/install/) or use your preferred command-line package manager to download and install the latest version of CMake. 47 | 48 | If using a graphical installer on Windows or macOS, make sure to check "Add CMake to the system PATH". 49 | 50 | [This document](https://cliutils.gitlab.io/modern-cmake/) has more helpful background on what CMake is and how to use it. 51 | 52 | ## Build 53 | 54 | ### Linux 55 | First you will need to install the project dependencies: 56 | ```bash 57 | sudo apt-get install cmake libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev 58 | ``` 59 | Open the directory into a terminal: 60 | ```bash 61 | cd ExampleProject 62 | mkdir build 63 | cd build 64 | cmake .. 65 | cmake --build . 66 | ./main 67 | ``` 68 | 69 | ### Windows 70 | * Open the project with CMake GUI 71 | * Configure (you have several options here depending on whether you wish to use the command line or an IDE for development) 72 | * Generate 73 | * Use IDE or command line to build 74 | * Run the build (normally at `build\Debug\main.exe`) 75 | 76 | Or, open the directory into a terminal: 77 | 78 | ```batchfile 79 | cd ExampleProject 80 | mkdir build 81 | cd build 82 | cmake .. 83 | cmake --build . 84 | Debug\main.exe 85 | ``` 86 | 87 | ### macOS 88 | * Open the project with CMake GUI 89 | * Configure (Xcode or "Unix Makefiles" both work fine) 90 | * Generate 91 | * Use IDE or command line to build 92 | * Run the build (normally at `build/main`) 93 | 94 | Or, open the directory into a terminal: 95 | ```bash 96 | cd ExampleProject 97 | mkdir build 98 | cd build 99 | cmake .. 100 | cmake --build . 101 | ./main 102 | ``` 103 | ## Run 104 | 105 | ### Controls 106 | 107 | - **WASD** or mouse to move the camera 108 | Scroll to zoom in and out 109 | 110 | - Press **SPACE** to show the quilt in debug mode (this displays a 2D quilt image) 111 | 112 | - Press **ESC** to quit 113 | 114 | 115 | ### Preview 116 | 117 | ![output](images/output.jpg) 118 | 119 | ### Troubleshooting 120 | 121 | - If the content shows incorrectly compared to the preview: 122 | 123 | - Verify if the window is full-screen and borderless. Some graphics libraries may create windows with invisible decorations. If your hologram appears 'miscalibrated', you may wish to use a tool like [NirSoft WinLister](https://www.nirsoft.net/utils/winlister.html) (Win32) or [xwininfo](https://linux.die.net/man/1/xwininfo) (Linux) to verify that your window has been opened with the correct properties. 124 | 125 | - If the app aborts or shuts down immediately: 126 | 1. Verify that [Looking Glass Bridge](https://lookingglassfactory.com/software/looking-glass-bridge) is installed and running. 127 | - The Looking Glass Bridge icon should display in the taskbar, if running properly. 128 | - If it is not installed, install it, and if it is not displaying in the taskbar, run it manually. 129 | 2. Right-click on the taskbar icon. This opens a menu that shows information about all your connected Looking Glass displays. Make sure it detects at least one of your devices and its calibration. 130 | - If not, right-click on the icon to restart Looking Glass Bridge until it detects both the device and its calibration. Double check if your Looking Glass is plugged in a USB3.0 port. If you have any problems achieving this, please [email us](https://lookingglassfactory.com/contact) or report the bug in our [forum](https://forum.lookingglassfactory.com/?_ga=2.171851938.388081720.1583171731-2126388208.1558451460) or [Discord server](https://discord.gg/ZW87Y4m). 131 | 132 | # Rendering Holograms with the Looking Glass 133 | 134 | ## Introduction 135 | First, it may be helpful to know how the Looking Glass works. In order to display holograms, the Looking Glass takes **45 discrete views** of a 3D scene and presents them across a view cone roughly 40° wide. 136 | 137 | The simplest way to create these views is to render a 3D scene 45 times per frame, varying the camera position each time, then combine all views into a single texture called a **quilt**. In OpenGL, we save each view with a **framebuffer** and use a **blit shader** to copy it into its designated position in the quilt. 138 | 139 | To show the views simultaneously, we use a **light field shader** to scramble the pixels in the quilt, making it appear as a 3D hologram when viewed through the Looking Glass. 140 | 141 | Each Looking Glass display has a unique set of **calibration** values, which describe its optical properties. These are converted to **uniforms** (values passed from the CPU to the GPU at runtime) for the light field shader. Calibration values are read over USB by **Looking Glass Bridge** and could be accessed via Looking Glass Core. 142 | 143 | For the calibration to apply correctly, the rendering context must be perfectly aligned to the display. Your application can achieve this by creating a fullscreen, undecorated window. In this example we will use the GLFW library to create our window. 144 | 145 | Looking Glass Core provides the source code for the light field shader as well as an interface to access the calibration values and exact window positions for each connected Looking Glass. 146 | 147 | This has been a brief overview of a complex process. For a more in-depth explanation of quilts, light fields, virtual camera setup, and the principles behind Looking Glass technology, please check out [More References](#more-references). 148 | 149 | 150 | ## Scripts 151 | 152 | HoloPlayContext: a class that sets up the context for rendering holograms onto the Looking Glass. 153 | 154 | SampleScene: inherits from HoloPlayContext. Overrides camera update, scene render and control functions in HoloPlayContext. 155 | 156 | Shader class and helper scripts are included. 157 | 158 | 159 | ## Key Steps 160 | 161 | Most key steps are implemented in `HoloPlayContext` and some could be overrided and implemented in `SampleScene`. 162 | 163 | To recap, the key steps to display a hologram are: 164 | 165 | #### Initialization → ``HoloPlayContext::HoloPlayContext()`` 166 | 167 | 1. Open connection to **Looking Glass Bridge**; retrieve window and calibration parameters → ``HoloPlayContext::HoloPlayContext()`` 168 | 2. Open a **full-screen window** on the Looking Glass → ``HoloPlayContext::openWindowOnLKG()`` 169 | 3. Compile **blit shaders** → ``HoloPlayContext::loadBlitShaders()`` 170 | 4. Create and configure **light field** shader: 171 | - Compile light field shader from provided GLSL → ``HoloPlayContext::loadLightFieldShaders()`` 172 | - Request calibration → ``HoloPlayContext::loadLightFieldShaders()`` 173 | - Configure **quilt settings** → ``HoloPlayContext::setupQuiltSettings()`` 174 | - Pass them to the light field shader → ``HoloPlayContext::passQuiltSettingsToShader()`` 175 | 5. Allocate and configure quilt → ``HoloPlayContext::setupQuilt()`` 176 | 6. Allocate and configure **view texture** and **view framebuffer** targets → ``HoloPlayContext::setupViewTextureAndFrameBuffer()`` 177 | 178 | #### Rendering → ``HoloPlayContext::run()`` 179 | 180 | 1. Update scene logic (i.e., physics) → ``HoloPlayContext::update()`` 181 | 2. For each view in the quilt: 182 | 1. Bind view framebuffer to view texture 183 | 2. [Set up virtual camera](#set-up-virtual-camera--holoplaycontextsetupvirtualcameraforview) → ``HoloPlayContext::setupVirtualCameraForView()`` 184 | 3. Render the scene into the view framebuffer → ``HoloPlayContext::renderScene()`` 185 | - This function should be overrided in child class. And in the override function, apply caculated view and projection of current view to the shader program that is used to render in child class → `SampleScene::renderScene()` 186 | 4. Use the blit shader to copy the view texture into the quilt texture → ``HoloPlayContext::copyViewToQuilt()`` 187 | ```c++ 188 | void SampleScene::renderScene() 189 | { 190 | ... 191 | shaderProgram->use(); 192 | // holoplay special camera setup for each view, don't delete 193 | shaderProgram->setUniform("view", GetViewMatrixOfCurrentView()); 194 | shaderProgram->setUniform("projection", GetProjectionMatrixOfCurrentView()); 195 | ... 196 | shaderProgram->unuse(); 197 | } 198 | ``` 199 | 3. Draw the quilt: render the quilt texture to the default framebuffer using the light field shader ``HoloPlayContext::drawLightField()`` 200 | 201 | #### On Exit → ``HoloPlayContext::OnExit()`` 202 | 1. Free the ``HoloPlayContext`` objects created → `HoloPlayContext::release()` 203 | 2. Release the connection to HoloPlay Service → `hpc_closeApp()` 204 | 205 | ## Set Up Virtual Camera → ``HoloPlayContext::setupVirtualCameraForView()`` 206 | 207 | Here's an illustration of the way the camera position changes each frame: 208 | 209 | ![alt text][view-cone] 210 | 211 | [view-cone]:https://2178864959-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWj8g-jOrSs315lrZFz%2Fsync%2F94ff2289db3b8e082f403a3a9330cb79495a3d78.png?generation=1616772665943629&alt=media "camera moves on the red track" 212 | 213 | The projection matrix also shifts between views. Here is an animation showing those changes: 214 | ![alt text][quilt_format2] 215 | 216 | [quilt_format2]:https://2178864959-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MWj8g-jOrSs315lrZFz%2Fsync%2F26fba6f986d557c5b6a6b5e511d6a043dbb1b52f.gif?generation=1616772667694314&alt=media "quilt - top-down view of Looking Glass - single view" 217 | 218 | So we calculate the position and projection offsets and then change the projection matrix: 219 | ```c++ 220 | void HoloPlayContext::setupVirtualCameraForView(int currentViewIndex, 221 | glm::mat4 currentViewMatrix) 222 | { 223 | // The standard model Looking Glass screen is roughly 4.75" vertically. If we 224 | // assume the average viewing distance for a user sitting at their desk is 225 | // about 36", our field of view should be about 14°. There is no correct 226 | // answer, as it all depends on your expected user's distance from the Looking 227 | // Glass, but we've found the most success using this figure. 228 | const float fov = glm::radians(14.0f); 229 | float cameraDistance = -cameraSize / tan(fov / 2.0f); 230 | 231 | // start at -viewCone * 0.5 and go up to viewCone * 0.5 232 | float offsetAngle = 233 | (currentViewIndex / (qs_totalViews - 1.0f) - 0.5f) * 234 | glm::radians(viewCone); 235 | 236 | float offset = 237 | cameraDistance * 238 | tan(offsetAngle); // calculate the offset that the camera should move 239 | 240 | // modify the view matrix (position) 241 | // determine the local direction of the offset using currentViewMatrix and translate 242 | glm::vec3 offsetLocal = glm::vec3(currentViewMatrix * glm::vec4(offset, 0.0f, cameraDistance, 1.0f)); 243 | viewMatrix = glm::translate(currentViewMatrix, offsetLocal); 244 | 245 | float aspectRatio = getWindowRatio(); 246 | 247 | projectionMatrix = glm::perspective(fov, aspectRatio, 0.1f, 100.0f); 248 | // modify the projection matrix, relative to the camera size and aspect ratio 249 | projectionMatrix[2][0] += offset / (cameraSize * aspectRatio); 250 | } 251 | ``` 252 | If you want to further understand how these equations work, check out [Offset](https://docs.lookingglassfactory.com/keyconcepts/camera#offset). 253 | 254 | ## More References 255 | - [How the Looking Glass Works](https://docs.lookingglassfactory.com/keyconcepts/how-it-works) 256 | - More about [Quilts](https://docs.lookingglassfactory.com/keyconcepts/quilts) 257 | - More about [Camera Setup](https://docs.lookingglassfactory.com/keyconcepts/camera) 258 | 259 | 260 | # Project Structure 261 | When starting a new project, you can use this example project as a template. Begin by rendering your own scene in `SampleScene::renderScene`, then change how the camera updates in `SampleScene::GetCurrentViewMatrix` and reimplement control functions for customization. Here is a list of all the virtual functions in the `SampleScene` class: 262 | ```c++ 263 | virtual void update(); // update each frame 264 | virtual void onExit(); // release memory here 265 | virtual void renderScene(); // render scene, will render 45 timers per frame for 45 views 266 | virtual glm::mat4 267 | getViewMatrixOfCurrentFrame(); // define how view matrix gets updated each frame here. 268 | // projection matrix is not changeable because 269 | // the field of view is static according to hardware measurement 270 | virtual bool processInput(GLFWwindow* window); // all key inputs 271 | virtual void mouse_callback(GLFWwindow* window, double xpos, double ypos); 272 | virtual void scroll_callback(GLFWwindow* window, 273 | double xoffset, 274 | double yoffset); 275 | ``` 276 | 277 | If you have an existing 3D app and you want to bring it in the Looking Glass, please refer to how the HoloPlay Context is [initialized](#initialization--holoplaycontextholoplaycontext) and [released](#on-exit--holoplaycontextonexit), [how the camera changes for 45 views](#set-up-virtual-camera--holoplaycontextsetupvirtualcameraforview), and [how to copy views to the quilt](#rendering--holoplaycontextrun) in the example project. Then, build up the same context in your project. We recommend reading the section below for more detailed instructions. 278 | 279 | 280 | # Making Use of HoloPlay Core 281 | ### Setup and Teardown 282 | * Release: `int hpc_CloseApp();` 283 | * Setup: `hpc_client_error hpc_InitializeApp(const char *app_name)` 284 | 285 | ### Shader related 286 | * Shader source code ``hpc_LightfieldVertShaderGLSL`` & ``hpc_LightfieldFragShaderGLSL`` 287 | * Shader Uniforms 288 | ```c++ 289 | void HoloPlayContext::loadCalibrationIntoShader() { 290 | std::cout << "begin assigning calibration uniforms" << std::endl; 291 | lightFieldShader->use(); 292 | lightFieldShader->setUniform("pitch", hpc_GetDevicePropertyPitch(DEV_INDEX)); 293 | lightFieldShader->setUniform("tilt", hpc_GetDevicePropertyTilt(DEV_INDEX)); 294 | lightFieldShader->setUniform("center", hpc_GetDevicePropertyCenter(DEV_INDEX)); 295 | lightFieldShader->setUniform("invView", hpc_GetDevicePropertyInvView(DEV_INDEX)); 296 | lightFieldShader->setUniform("quiltInvert", 0); 297 | lightFieldShader->setUniform("subp", hpc_GetDevicePropertySubp(DEV_INDEX)); 298 | lightFieldShader->setUniform("ri", hpc_GetDevicePropertyRi(DEV_INDEX)); 299 | lightFieldShader->setUniform("bi", hpc_GetDevicePropertyBi(DEV_INDEX)); 300 | lightFieldShader->setUniform("displayAspect",hpc_GetDevicePropertyDisplayAspect(DEV_INDEX)); 301 | lightFieldShader->setUniform("quiltAspect", hpc_GetDevicePropertyDisplayAspect(DEV_INDEX)); 302 | lightFieldShader->unuse(); 303 | } 304 | ``` 305 | ### Monitor Coordinates 306 | ```c++ 307 | GLFWwindow* HoloPlayContext::openWindowOnLKG() { 308 | ... 309 | // get window coordinates 310 | win_w = hpc_GetDevicePropertyScreenW(DEV_INDEX); 311 | win_h = hpc_GetDevicePropertyScreenH(DEV_INDEX); 312 | win_x = hpc_GetDevicePropertyWinX(DEV_INDEX); 313 | win_y = hpc_GetDevicePropertyWinY(DEV_INDEX); 314 | // open the window 315 | auto mWindow = glfwCreateWindow(win_w, win_h, "Looking Glass Output", NULL, NULL); 316 | glfwSetWindowPos(mWindow, win_x, win_y); 317 | return mWindow; 318 | } 319 | ``` 320 | ### View cone 321 | ```c++ 322 | float viewCone = hpc_GetDevicePropertyFloat(i, "/calibration/viewCone/value") 323 | ``` 324 | ### Debug mode 325 | ```c++ 326 | quiltShader->setUniform("debug", 1); // turn off by setting "debug" to 0 327 | ``` 328 | ### Other info 329 | 330 | Check in `HoloPlayContext::GetLookingGlassInfo`: 331 | ```c++ 332 | hpc_GetHoloPlayCoreVersion(buf, 1000); 333 | hpc_GetHoloPlayServiceVersion(buf, 1000); 334 | int num_displays = hpc_GetNumDevices(); 335 | hpc_GetDeviceHDMIName(i, buf, 1000); 336 | hpc_GetDeviceType(i, buf, 1000); 337 | ``` 338 | -------------------------------------------------------------------------------- /ExampleProject/src/HoloPlayContext.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * HoloPlayContext.cpp 3 | * Contributors: 4 | * * Arthur Sonzogni (author), Looking Glass Factory Inc. 5 | * Licence: 6 | * * MIT 7 | */ 8 | 9 | #ifdef WIN32 10 | #pragma warning(disable : 4464 4820 4514 5045 4201 5039 4061 4710) 11 | #endif 12 | 13 | #include "HoloPlayContext.hpp" 14 | #include "HoloPlayShaders.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "Shader.hpp" 24 | #include "glError.hpp" 25 | 26 | using namespace std; 27 | 28 | #define UNUSED(x) [&x]{}() 29 | 30 | HoloPlayContext *currentApplication = NULL; 31 | 32 | HoloPlayContext &HoloPlayContext::getInstance() 33 | { 34 | if (currentApplication) 35 | return *currentApplication; 36 | else 37 | throw std::runtime_error("There is no current Application"); 38 | } 39 | 40 | // Mouse and scroll function wrapper 41 | // ======================================================== 42 | // callback functions must be static 43 | HoloPlayContext &getInstance() 44 | { 45 | if (currentApplication) 46 | return *currentApplication; 47 | else 48 | throw std::runtime_error("There is no current Application"); 49 | } 50 | 51 | // wrapper for getting mouse movement callback 52 | static void external_mouse_callback(GLFWwindow *window, 53 | double xpos, 54 | double ypos) 55 | { 56 | // here we access the instance via the singleton pattern and forward the 57 | // callback to the instance method 58 | getInstance().mouse_callback(window, xpos, ypos); 59 | } 60 | 61 | // wrapper for getting mouse scroll callback 62 | static void external_scroll_callback(GLFWwindow *window, 63 | double xpos, 64 | double ypos) 65 | { 66 | // here we access the instance via the singleton pattern and forward the 67 | // callback to the instance method 68 | getInstance().scroll_callback(window, xpos, ypos); 69 | } 70 | 71 | HoloPlayContext::HoloPlayContext(bool capture_mouse) 72 | : state(State::Ready), 73 | title("Application"), 74 | opengl_version_major(3), 75 | opengl_version_minor(3) 76 | { 77 | currentApplication = this; 78 | 79 | // get device info via holoplay core 80 | if (!GetLookingGlassInfo()) 81 | { 82 | cout << "[Info] HoloplayCore Message Pipe tear down" << endl; 83 | state = State::Exit; 84 | // must tear down the message pipe before shut down the app 85 | hpc_TeardownMessagePipe(); 86 | throw std::runtime_error("Couldn't find looking glass"); 87 | } 88 | // get the viewcone here, which is used as a const 89 | viewCone = hpc_GetDevicePropertyFloat(DEV_INDEX, "/calibration/viewCone/value"); 90 | 91 | cout << "[Info] GLFW initialisation" << endl; 92 | 93 | opengl_version_header = "#version "; 94 | opengl_version_header += to_string(opengl_version_major); 95 | opengl_version_header += to_string(opengl_version_minor); 96 | opengl_version_header += "0 core\n"; 97 | 98 | // initialize the GLFW library 99 | if (!glfwInit()) 100 | { 101 | throw std::runtime_error("Couldn't init GLFW"); 102 | } 103 | 104 | // set opengl version (will also be used for lightfield and blit shaders) 105 | 106 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, opengl_version_major); 107 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, opengl_version_minor); 108 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 109 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 110 | 111 | // create window on the first looking glass device 112 | window = openWindowOnLKG(); 113 | if (!window) 114 | { 115 | glfwTerminate(); 116 | throw std::runtime_error( 117 | "Couldn't create a window on looking glass device"); 118 | } 119 | cout << "[Info] Window opened on lkg" << endl; 120 | glfwMakeContextCurrent(window); 121 | glCheckError(__FILE__, __LINE__); 122 | 123 | // set up the cursor callback 124 | glfwSetCursorPosCallback(window, external_mouse_callback); 125 | glfwSetScrollCallback(window, external_scroll_callback); 126 | 127 | if (capture_mouse) 128 | { 129 | // tell GLFW to capture our mouse 130 | glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); 131 | } 132 | 133 | glCheckError(__FILE__, __LINE__); 134 | 135 | glewExperimental = GL_TRUE; 136 | GLenum err = glewInit(); 137 | glCheckError(__FILE__, __LINE__); 138 | 139 | if (err != GLEW_OK) 140 | { 141 | cout << "terminiated" << endl; 142 | glfwTerminate(); 143 | throw std::runtime_error(string("Could initialize GLEW, error = ") + 144 | (const char *)glewGetErrorString(err)); 145 | } 146 | 147 | // get OpenGL version info 148 | const GLubyte *renderer = glGetString(GL_RENDERER); 149 | const GLubyte *version = glGetString(GL_VERSION); 150 | cout << "Renderer: " << renderer << endl; 151 | cout << "[Info] OpenGL version supported " << version << endl; 152 | 153 | // opengl configuration 154 | glEnable(GL_DEPTH_TEST); // enable depth-testing 155 | glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer" 156 | 157 | // initialize the holoplay context 158 | initialize(); 159 | } 160 | 161 | HoloPlayContext::~HoloPlayContext() 162 | { 163 | } 164 | 165 | void HoloPlayContext::onExit() 166 | { 167 | cout << "[INFO] : on exit" << endl; 168 | } 169 | 170 | void HoloPlayContext::exit() 171 | { 172 | state = State::Exit; 173 | cout << "[Info] Informing Holoplay Core to close app" << endl; 174 | hpc_CloseApp(); 175 | // release all the objects created for setting up the HoloPlay Context 176 | release(); 177 | } 178 | 179 | // main loop 180 | void HoloPlayContext::run() 181 | { 182 | state = State::Run; 183 | 184 | // Make the window's context current 185 | glfwMakeContextCurrent(window); 186 | 187 | time = float(glfwGetTime()); 188 | 189 | while (state == State::Run) 190 | { 191 | // compute new time and delta time 192 | float t = float(glfwGetTime()); 193 | deltaTime = t - time; 194 | time = t; 195 | 196 | // detech window related changes 197 | detectWindowChange(); 198 | glCheckError(__FILE__, __LINE__); 199 | 200 | // press esc to quit 201 | if (!processInput(window)) 202 | { 203 | exit(); 204 | onExit(); 205 | continue; 206 | } 207 | 208 | // decide how camera updates here, override in SampleScene.cpp 209 | glm::mat4 currentViewMatrix = getViewMatrixOfCurrentFrame(); 210 | glCheckError(__FILE__, __LINE__); 211 | 212 | // do the update 213 | update(); 214 | 215 | // clear backbuffer 216 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 217 | glClearColor(0.0, 0.0, 0.0, 1.0); 218 | 219 | // bind quilt texture to frame buffer 220 | glBindFramebuffer(GL_FRAMEBUFFER, FBO); 221 | 222 | // save the viewport for the total quilt 223 | GLint viewport[4]; 224 | glGetIntegerv(GL_VIEWPORT, viewport); 225 | 226 | // get quilt view dimensions 227 | int qs_viewWidth = int(float(qs_width) / float(qs_columns)); 228 | int qs_viewHeight = int(float(qs_height) / float(qs_rows)); 229 | 230 | // render views and copy each view to the quilt 231 | for (int viewIndex = 0; viewIndex < qs_totalViews; viewIndex++) 232 | { 233 | // get the x and y origin for this view 234 | int x = (viewIndex % qs_columns) * qs_viewWidth; 235 | int y = int(float(viewIndex) / float(qs_columns)) * qs_viewHeight; 236 | 237 | // set the viewport to the view to control the projection extent 238 | glViewport(x, y, qs_viewWidth, qs_viewHeight); 239 | 240 | // set the scissor to the view to restrict calls like glClear from making modifications 241 | glEnable(GL_SCISSOR_TEST); 242 | glScissor(x, y, qs_viewWidth, qs_viewHeight); 243 | 244 | // set up the camera rotation and position for current view 245 | setupVirtualCameraForView(viewIndex, currentViewMatrix); 246 | 247 | //render the scene according to the view 248 | renderScene(); 249 | 250 | // reset viewport 251 | glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); 252 | 253 | // restore scissor 254 | glDisable(GL_SCISSOR_TEST); 255 | glScissor(viewport[0], viewport[1], viewport[2], viewport[3]); 256 | } 257 | 258 | // reset framebuffer 259 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 260 | 261 | // draw the light field image 262 | drawLightField(); 263 | 264 | // Swap Front and Back buffers (double buffering) 265 | glfwSwapBuffers(window); 266 | 267 | // Poll and process events 268 | glfwPollEvents(); 269 | } 270 | 271 | glfwTerminate(); 272 | } 273 | 274 | // window coordinates may be changed when the main display is scaled and the 275 | // looking glass display is not, so we make this function here to detect the 276 | // window change and force our window to be full-screen again 277 | void HoloPlayContext::detectWindowChange() 278 | { 279 | int w, h; 280 | int x, y; 281 | glfwGetWindowSize(getWindow(), &w, &h); 282 | glfwGetWindowPos(getWindow(), &x, &y); 283 | 284 | windowChanged = (w != win_w) || (h != win_h) || (x != win_x) || (y != win_y); 285 | if (windowChanged) 286 | { 287 | cout << "[Info] Dimension changed: (" << w << "," << h << ")" << endl; 288 | glfwSetWindowPos(getWindow(), win_x, win_y); 289 | glfwSetWindowSize(getWindow(), win_w, win_h); 290 | cout << "[Info] force window to be full-screen again" << endl; 291 | } 292 | } 293 | 294 | // virtual functions 295 | // ========================================================= 296 | void HoloPlayContext::update() 297 | { 298 | cout << "[INFO] : update" << endl; 299 | // implement update function in the child class 300 | } 301 | 302 | void HoloPlayContext::renderScene() 303 | { 304 | cout << "[INFO] : render scene" << endl; 305 | } 306 | 307 | glm::mat4 HoloPlayContext::getViewMatrixOfCurrentFrame() 308 | { 309 | cout << "[INFO] : update camera" << endl; 310 | return glm::mat4(1.0); 311 | } 312 | 313 | // process all input: query GLFW whether relevant keys are pressed/released this 314 | // frame and react accordingly. return false to close application 315 | // --------------------------------------------------------------------------------------------------------- 316 | bool HoloPlayContext::processInput(GLFWwindow*) 317 | { 318 | cout << "[INFO] : process input" << endl; 319 | return true; 320 | } 321 | 322 | // glfw: whenever the mouse moves, this callback is called 323 | // ------------------------------------------------------- 324 | void HoloPlayContext::mouse_callback(GLFWwindow*, 325 | double xpos, 326 | double ypos) 327 | { 328 | UNUSED(xpos); 329 | UNUSED(ypos); 330 | } 331 | 332 | void HoloPlayContext::scroll_callback(GLFWwindow*, 333 | double xoffset, 334 | double yoffset) 335 | { 336 | UNUSED(xoffset); 337 | UNUSED(yoffset); 338 | } 339 | 340 | // get functions 341 | // ========================================================= 342 | int HoloPlayContext::getWidth() 343 | { 344 | return win_w; 345 | } 346 | 347 | int HoloPlayContext::getHeight() 348 | { 349 | return win_h; 350 | } 351 | 352 | float HoloPlayContext::getWindowRatio() 353 | { 354 | return float(win_w) / float(win_h); 355 | } 356 | 357 | GLFWwindow *HoloPlayContext::getWindow() const 358 | { 359 | return window; 360 | } 361 | 362 | bool HoloPlayContext::windowDimensionChanged() 363 | { 364 | return windowChanged; 365 | } 366 | 367 | float HoloPlayContext::getFrameDeltaTime() const 368 | { 369 | return deltaTime; 370 | } 371 | 372 | float HoloPlayContext::getTime() const 373 | { 374 | return time; 375 | } 376 | 377 | // Sample code for creating HoloPlay context 378 | 379 | // Holoplay Core related functions 380 | // ========================================================= 381 | // Register and initialize the app through HoloPlay Core 382 | // And print information about connected Looking Glass devices 383 | bool HoloPlayContext::GetLookingGlassInfo() 384 | { 385 | hpc_client_error errco = 386 | hpc_InitializeApp("Holoplay Core Example App", hpc_LICENSE_NONCOMMERCIAL); 387 | if (errco) 388 | { 389 | string errstr; 390 | switch (errco) 391 | { 392 | case hpc_CLIERR_NOSERVICE: 393 | errstr = "HoloPlay Service not running"; 394 | break; 395 | case hpc_CLIERR_SERIALIZEERR: 396 | errstr = "Client message could not be serialized"; 397 | break; 398 | case hpc_CLIERR_VERSIONERR: 399 | errstr = "Incompatible version of HoloPlay Service"; 400 | break; 401 | case hpc_CLIERR_PIPEERROR: 402 | errstr = "Interprocess pipe broken"; 403 | break; 404 | case hpc_CLIERR_SENDTIMEOUT: 405 | errstr = "Interprocess pipe send timeout"; 406 | break; 407 | case hpc_CLIERR_RECVTIMEOUT: 408 | errstr = "Interprocess pipe receive timeout"; 409 | break; 410 | default: 411 | errstr = "Unknown error"; 412 | break; 413 | } 414 | cout << "HoloPlay Service access error (code " << errco << "): " << errstr 415 | << "!" << endl; 416 | return false; 417 | } 418 | char buf[1000]; 419 | hpc_GetHoloPlayCoreVersion(buf, 1000); 420 | cout << "HoloPlay Core version " << buf << "." << endl; 421 | hpc_GetHoloPlayServiceVersion(buf, 1000); 422 | cout << "HoloPlay Service version " << buf << "." << endl; 423 | int num_displays = hpc_GetNumDevices(); 424 | cout << num_displays << " devices connected." << endl; 425 | if (num_displays < 1) 426 | { 427 | return false; 428 | } 429 | for (int i = 0; i < num_displays; ++i) 430 | { 431 | cout << "Device information for display " << i << ":" << endl; 432 | hpc_GetDeviceHDMIName(i, buf, 1000); 433 | cout << "\tDevice name: " << buf << endl; 434 | hpc_GetDeviceType(i, buf, 1000); 435 | cout << "\tDevice type: " << buf << endl; 436 | hpc_GetDeviceType(i, buf, 1000); 437 | cout << "\nWindow parameters for display " << i << ":" << endl; 438 | cout << "\tPosition: (" << hpc_GetDevicePropertyWinX(i) << ", " 439 | << hpc_GetDevicePropertyWinY(i) << ")" << endl; 440 | cout << "\tSize: (" << hpc_GetDevicePropertyScreenW(i) << ", " 441 | << hpc_GetDevicePropertyScreenH(i) << ")" << endl; 442 | cout << "\tAspect ratio: " << hpc_GetDevicePropertyDisplayAspect(i) << endl; 443 | cout << "\nShader uniforms for display " << i << ":" << endl; 444 | cout << "\tPitch: " << hpc_GetDevicePropertyPitch(i) << endl; 445 | cout << "\tTilt: " << hpc_GetDevicePropertyTilt(i) << endl; 446 | cout << "\tCenter: " << hpc_GetDevicePropertyCenter(i) << endl; 447 | cout << "\tSubpixel width: " << hpc_GetDevicePropertySubp(i) << endl; 448 | cout << "\tView cone: " 449 | << hpc_GetDevicePropertyFloat(i, "/calibration/viewCone/value") 450 | << endl; 451 | cout << "\tFringe: " << hpc_GetDevicePropertyFringe(i) << endl; 452 | cout << "\tRI: " << hpc_GetDevicePropertyRi(i) 453 | << "\n\tBI: " << hpc_GetDevicePropertyBi(i) 454 | << "\n\tinvView: " << hpc_GetDevicePropertyInvView(i) << endl; 455 | } 456 | 457 | return true; 458 | } 459 | 460 | // setup fuctions 461 | // ========================================================= 462 | void HoloPlayContext::initialize() 463 | { 464 | cout << "[Info] initializing" << endl; 465 | glfwMakeContextCurrent(window); 466 | 467 | loadLightFieldShaders(); 468 | glCheckError(__FILE__, __LINE__); 469 | 470 | loadCalibrationIntoShader(); 471 | glCheckError(__FILE__, __LINE__); 472 | 473 | setupQuiltSettings(1); 474 | passQuiltSettingsToShader(); 475 | glCheckError(__FILE__, __LINE__); 476 | 477 | setupQuilt(); 478 | glCheckError(__FILE__, __LINE__); 479 | } 480 | 481 | // set up the quilt settings 482 | void HoloPlayContext::setupQuiltSettings(int preset) 483 | { 484 | // there are 3 presets: 485 | switch (preset) 486 | { 487 | case 0: // standard 488 | qs_width = 2048; 489 | qs_height = 2048; 490 | qs_columns = 4; 491 | qs_rows = 8; 492 | qs_totalViews = 32; 493 | break; 494 | default: 495 | case 1: // hires 496 | qs_width = 4096; 497 | qs_height = 4096; 498 | qs_columns = 5; 499 | qs_rows = 9; 500 | qs_totalViews = 45; 501 | break; 502 | case 2: // 8k 503 | qs_width = 4096 * 2; 504 | qs_height = 4096 * 2; 505 | qs_columns = 5; 506 | qs_rows = 9; 507 | qs_totalViews = 45; 508 | break; 509 | } 510 | } 511 | // pass quilt values to shader 512 | void HoloPlayContext::passQuiltSettingsToShader() 513 | { 514 | lightFieldShader->use(); 515 | lightFieldShader->setUniform("overscan", 0); 516 | glCheckError(__FILE__, __LINE__); 517 | 518 | lightFieldShader->setUniform("tile", 519 | glm::vec3(qs_columns, qs_rows, qs_totalViews)); 520 | glCheckError(__FILE__, __LINE__); 521 | 522 | int qs_viewWidth = qs_width / qs_columns; 523 | int qs_viewHeight = qs_height / qs_rows; 524 | 525 | lightFieldShader->setUniform( 526 | "viewPortion", glm::vec2(float(qs_viewWidth * qs_columns) / float(qs_width), 527 | float(qs_viewHeight * qs_rows) / float(qs_height))); 528 | glCheckError(__FILE__, __LINE__); 529 | lightFieldShader->unuse(); 530 | } 531 | 532 | void HoloPlayContext::setupQuilt() 533 | { 534 | cout << "setting up quilt texture and framebuffer" << endl; 535 | glGenTextures(1, &quiltTexture); 536 | glBindTexture(GL_TEXTURE_2D, quiltTexture); 537 | 538 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, qs_width, qs_height, 0, GL_RGB, 539 | GL_UNSIGNED_BYTE, NULL); 540 | 541 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 542 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 543 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 544 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 545 | 546 | glBindTexture(GL_TEXTURE_2D, 0); 547 | 548 | // framebuffer 549 | glGenFramebuffers(1, &FBO); 550 | glBindFramebuffer(GL_FRAMEBUFFER, FBO); 551 | 552 | // bind the quilt texture as the color attachment of the framebuffer 553 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 554 | quiltTexture, 0); 555 | 556 | // vbo and vao 557 | glGenVertexArrays(1, &VAO); 558 | glGenBuffers(1, &VBO); 559 | 560 | // set up the vertex array object 561 | glBindVertexArray(VAO); 562 | 563 | // fullscreen quad vertices 564 | const float fsquadVerts[] = { 565 | -1.0f, 566 | -1.0f, 567 | -1.0f, 568 | 1.0f, 569 | 1.0f, 570 | 1.0f, 571 | 1.0f, 572 | 1.0f, 573 | 1.0f, 574 | -1.0f, 575 | -1.0f, 576 | -1.0f, 577 | }; 578 | 579 | // create vbo 580 | glBindBuffer(GL_ARRAY_BUFFER, VBO); 581 | glBufferData(GL_ARRAY_BUFFER, sizeof(fsquadVerts), fsquadVerts, 582 | GL_STATIC_DRAW); 583 | 584 | // setup the attribute pointers 585 | // note: using only 2 floats per vert, not 3 586 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0); 587 | glEnableVertexAttribArray(0); 588 | 589 | // unbind stuff 590 | glBindBuffer(GL_ARRAY_BUFFER, 0); 591 | glBindVertexArray(0); 592 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 593 | } 594 | 595 | void HoloPlayContext::loadLightFieldShaders() 596 | { 597 | cout << "loading quilt shader" << endl; 598 | Shader lightFieldVertexShader( 599 | GL_VERTEX_SHADER, 600 | (opengl_version_header + hpc_LightfieldVertShaderGLSL).c_str()); 601 | Shader lightFieldFragmentShader( 602 | GL_FRAGMENT_SHADER, 603 | (opengl_version_header + hpc_LightfieldFragShaderGLSL).c_str()); 604 | lightFieldShader = 605 | new ShaderProgram({lightFieldVertexShader, lightFieldFragmentShader}); 606 | } 607 | 608 | void HoloPlayContext::loadCalibrationIntoShader() 609 | { 610 | cout << "begin assigning calibration uniforms" << endl; 611 | lightFieldShader->use(); 612 | lightFieldShader->setUniform("pitch", hpc_GetDevicePropertyPitch(DEV_INDEX)); 613 | glCheckError(__FILE__, __LINE__); 614 | 615 | lightFieldShader->setUniform("tilt", hpc_GetDevicePropertyTilt(DEV_INDEX)); 616 | glCheckError(__FILE__, __LINE__); 617 | 618 | lightFieldShader->setUniform("center", 619 | hpc_GetDevicePropertyCenter(DEV_INDEX)); 620 | glCheckError(__FILE__, __LINE__); 621 | 622 | lightFieldShader->setUniform("invView", 623 | hpc_GetDevicePropertyInvView(DEV_INDEX)); 624 | glCheckError(__FILE__, __LINE__); 625 | 626 | lightFieldShader->setUniform("quiltInvert", 0); 627 | glCheckError(__FILE__, __LINE__); 628 | 629 | lightFieldShader->setUniform("subp", hpc_GetDevicePropertySubp(DEV_INDEX)); 630 | glCheckError(__FILE__, __LINE__); 631 | 632 | lightFieldShader->setUniform("ri", hpc_GetDevicePropertyRi(DEV_INDEX)); 633 | glCheckError(__FILE__, __LINE__); 634 | 635 | lightFieldShader->setUniform("bi", hpc_GetDevicePropertyBi(DEV_INDEX)); 636 | glCheckError(__FILE__, __LINE__); 637 | 638 | lightFieldShader->setUniform("displayAspect", 639 | hpc_GetDevicePropertyDisplayAspect(DEV_INDEX)); 640 | glCheckError(__FILE__, __LINE__); 641 | lightFieldShader->setUniform("quiltAspect", 642 | hpc_GetDevicePropertyDisplayAspect(DEV_INDEX)); 643 | glCheckError(__FILE__, __LINE__); 644 | lightFieldShader->unuse(); 645 | glCheckError(__FILE__, __LINE__); 646 | } 647 | 648 | // release function 649 | // ========================================================= 650 | void HoloPlayContext::release() 651 | { 652 | cout << "[Info] HoloPlay Context releasing" << endl; 653 | glDeleteVertexArrays(1, &VAO); 654 | glDeleteBuffers(1, &VBO); 655 | glDeleteFramebuffers(1, &FBO); 656 | glDeleteTextures(1, &quiltTexture); 657 | delete lightFieldShader; 658 | delete blitShader; 659 | } 660 | 661 | // render functions 662 | // ========================================================= 663 | // set up the camera for each view and the shader of the rendering object 664 | void HoloPlayContext::setupVirtualCameraForView(int currentViewIndex, 665 | glm::mat4 currentViewMatrix) 666 | { 667 | // The standard model Looking Glass screen is roughly 4.75" vertically. If we 668 | // assume the average viewing distance for a user sitting at their desk is 669 | // about 36", our field of view should be about 14°. There is no correct 670 | // answer, as it all depends on your expected user's distance from the Looking 671 | // Glass, but we've found the most success using this figure. 672 | const float fov = glm::radians(14.0f); 673 | float cameraDistance = -cameraSize / tan(fov / 2.0f); 674 | 675 | float offsetAngle = 676 | (float(currentViewIndex) / (float(qs_totalViews) - 1.0f) - 0.5f) * 677 | glm::radians( 678 | viewCone); // start at -viewCone * 0.5 and go up to viewCone * 0.5 679 | 680 | float offset = 681 | cameraDistance * 682 | tan(offsetAngle); // calculate the offset that the camera should move 683 | 684 | // modify the view matrix (position) 685 | // determine the local direction of the offset using currentViewMatrix and translate 686 | glm::vec3 offsetLocal = glm::vec3(currentViewMatrix * glm::vec4(offset, 0.0f, cameraDistance, 1.0f)); 687 | viewMatrix = glm::translate(currentViewMatrix, offsetLocal); 688 | 689 | float aspectRatio = getWindowRatio(); 690 | 691 | projectionMatrix = glm::perspective(fov, aspectRatio, 0.1f, 100.0f); 692 | // modify the projection matrix, relative to the camera size and aspect ratio 693 | projectionMatrix[2][0] += offset / (cameraSize * aspectRatio); 694 | } 695 | 696 | void HoloPlayContext::drawLightField() 697 | { 698 | // bind quilt texture 699 | glBindTexture(GL_TEXTURE_2D, quiltTexture); 700 | 701 | // bind vao 702 | glBindVertexArray(VAO); 703 | 704 | // use the shader and draw 705 | lightFieldShader->use(); 706 | glDrawArrays(GL_TRIANGLES, 0, 6); 707 | 708 | // clean up 709 | glBindVertexArray(0); 710 | lightFieldShader->unuse(); 711 | } 712 | 713 | // Other helper functions 714 | // ======================================================================= 715 | // open window at looking glass monitor 716 | GLFWwindow *HoloPlayContext::openWindowOnLKG() 717 | { 718 | // Load GLFW and Create a Window 719 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 720 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); 721 | 722 | // open the window 723 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 724 | glfwWindowHint(GLFW_CENTER_CURSOR, false); 725 | glfwWindowHint(GLFW_DECORATED, false); 726 | glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, true); 727 | 728 | // get the window size / coordinates 729 | win_w = hpc_GetDevicePropertyScreenW(DEV_INDEX); 730 | win_h = hpc_GetDevicePropertyScreenH(DEV_INDEX); 731 | win_x = hpc_GetDevicePropertyWinX(DEV_INDEX); 732 | win_y = hpc_GetDevicePropertyWinY(DEV_INDEX); 733 | cout << "[Info] window opened at (" << win_x << ", " << win_y << "), size: (" 734 | << win_w << ", " << win_h << ")" << endl; 735 | // open the window 736 | auto mWindow = 737 | glfwCreateWindow(win_w, win_h, "Looking Glass Output", NULL, NULL); 738 | 739 | glfwSetWindowPos(mWindow, win_x, win_y); 740 | 741 | return mWindow; 742 | } 743 | --------------------------------------------------------------------------------