diff --git a/CMakeLists.txt b/CMakeLists.txt index 5625b8f..a17f013 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required(VERSION 3.1.0) project(osvrUnityRenderingPlugin) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + #----------------------------------------------------------------------------- # Local CMake Modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") @@ -17,15 +20,24 @@ find_package(osvr REQUIRED) # Add one of these libraries for each vendor that we've got a driver # for and add a No driver that tells that it is unavailable when we # don't find the driver library. -find_package(OpenGL REQUIRED) -find_package(GLEW REQUIRED) -find_package(Boost REQUIRED) +find_package(OpenGL) +find_package(OpenGLES2 REQUIRED) +find_package(GLEW) +find_package(Boost) find_package(osvrRenderManager REQUIRED) -find_package(JsonCpp REQUIRED) +find_package(JsonCpp) +find_package(SDL2) set (osvrUnityRenderingPlugin_SOURCES OsvrRenderingPlugin.h OsvrRenderingPlugin.cpp + OsvrUnityRenderer.h + OsvrAndroidRenderer.cpp + OsvrAndroidRenderer.h + OsvrD3DRenderer.cpp + OsvrD3DRenderer.h + OsvrOpenGLRenderer.cpp + OsvrOpenGLRenderer.h PluginConfig.h UnityRendererType.h ) @@ -34,21 +46,37 @@ if(WIN32) # list(APPEND osvrUnityRenderingPlugin_SOURCES OsvrRenderingPlugin.def) endif() -add_library(osvrUnityRenderingPlugin MODULE ${osvrUnityRenderingPlugin_SOURCES}) +set(EXTRA_ANDROID_LINKER_FLAGS "") + +if(ANDROID) + add_library(osvrUnityRenderingPlugin SHARED ${osvrUnityRenderingPlugin_SOURCES}) + set(EXTRA_ANDROID_LINKER_FLAGS "log -z global") +else() + add_library(osvrUnityRenderingPlugin MODULE ${osvrUnityRenderingPlugin_SOURCES}) +endif() + #set_target_properties(osvrUnityRenderingPlugin PROPERTIES LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/OsvrRenderingPlugin.def") -target_link_libraries(osvrUnityRenderingPlugin osvr::osvrClientKit) -target_link_libraries(osvrUnityRenderingPlugin osvrRenderManager::osvrRenderManager) +#target_link_libraries(osvrUnityRenderingPlugin osvr::osvrClientKit) +#target_link_libraries(osvrUnityRenderingPlugin osvrRenderManager::osvrRenderManager) target_include_directories(osvrUnityRenderingPlugin PRIVATE ${Boost_INCLUDE_DIRS}) # target_link_libraries(osvrUnityRenderingPlugin ${Boost_LIBRARIES}) if (OPENGL_FOUND AND GLEW_FOUND) target_include_directories(osvrUnityRenderingPlugin PRIVATE ${OPENGL_INCLUDE_DIRS}) - target_link_libraries(osvrUnityRenderingPlugin ${OPENGL_LIBRARY} GLEW::GLEW JsonCpp::JsonCpp) + target_link_libraries(osvrUnityRenderingPlugin ${OPENGL_LIBRARY} GLEW::GLEW JsonCpp::JsonCpp SDL2::SDL2 osvr::osvrClientKit osvrRenderManager::osvrRenderManager) # Handle static glew. if(GLEW_LIBRARY MATCHES ".*s.lib") target_compile_definitions(osvrUnityRenderingPlugin PRIVATE GLEW_STATIC) endif() endif() +if (OPENGL_FOUND) + target_include_directories(osvrUnityRenderingPlugin PRIVATE ${OPENGL_INCLUDE_DIRS}) + target_link_libraries(osvrUnityRenderingPlugin ${OPENGL_LIBRARY} JsonCpp::JsonCpp osvr::osvrClientKit osvrRenderManager::osvrRenderManager) +endif() +if(OPENGLES2_FOUND) + target_include_directories(osvrUnityRenderingPlugin PRIVATE ${OPENGLES2_INCLUDE_DIR}) + target_link_libraries(osvrUnityRenderingPlugin PRIVATE ${OPENGLES2_LIBRARIES} JsonCpp::JsonCpp osvr::osvrClientKit osvrRenderManager::osvrRenderManager android ${EXTRA_ANDROID_LINKER_FLAGS}) +endif() # Install docs, license, sample config install(TARGETS diff --git a/OsvrAndroidRenderer.cpp b/OsvrAndroidRenderer.cpp new file mode 100644 index 0000000..1e6ab67 --- /dev/null +++ b/OsvrAndroidRenderer.cpp @@ -0,0 +1,1040 @@ +/** @file +@brief Header +@date 2017 +@author +Sensics, Inc. + +*/ + +// Copyright 2017 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "OsvrAndroidRenderer.h" + +static GLuint gvPositionHandle; +static GLuint gvColorHandle; +static GLuint gvTexCoordinateHandle; +static GLuint guTextureUniformId; +static GLuint gvProjectionUniformId; +static GLuint gvViewUniformId; +static GLuint gvModelUniformId; +static GLuint gFrameBuffer; +static GLuint gTextureID; +static GLuint gLeftEyeTextureID; +static GLuint gLeftEyeTextureIDBuffer2; +static GLuint gRightEyeTextureID; +static GLuint gRightEyeTextureIDBuffer2; +static GLuint gProgram; + +typedef struct OSVR_RenderTargetInfoOpenGL { + GLuint colorBufferName; + GLuint depthBufferName; + GLuint frameBufferName; + GLuint renderBufferName; // @todo - do we need this? +} OSVR_RenderTargetInfoOpenGL; +OSVR_ClientInterface gCamera = NULL; +OSVR_ClientInterface gHead = NULL; +static int gReportNumber = 0; +OSVR_ImageBufferElement *gLastFrame = nullptr; +static GLuint gLastFrameWidth = 0; +static GLuint gLastFrameHeight = 0; +static GLubyte *gTextureBuffer = nullptr; + +static bool gGraphicsInitializedOnce = false; // if setupGraphics has been called at least once +static bool gOSVRInitialized = false; +static bool gRenderManagerInitialized = false; +static int gWidth = 0; +static int gHeight = 0; +static bool contextSet = false; + +OSVR_GraphicsLibraryOpenGL gGraphicsLibrary = { 0 }; +OSVR_RenderParams gRenderParams = { 0 }; + +// std::vector buffers; +// std::vector gRenderTargets; +struct FrameInfoOpenGL { + // Set up the vector of textures to render to and any framebuffer + // we need to group them. + std::vector renderBuffers; + FrameInfoOpenGL() : renderBuffers(2) + { + } + +}; +std::vector frameInfoOGL; + +const char gVertexShader[] = +"uniform mat4 model;\n" +"uniform mat4 view;\n" +"uniform mat4 projection;\n" +"attribute vec4 vPosition;\n" +"attribute vec4 vColor;\n" +"attribute vec2 vTexCoordinate;\n" +"varying vec2 texCoordinate;\n" +"varying vec4 fragmentColor;\n" +"void main() {\n" +" gl_Position = projection * view * model * vPosition;\n" +" fragmentColor = vColor;\n" +" texCoordinate = vTexCoordinate;\n" +"}\n"; + +const char gFragmentShader[] = +"precision mediump float;\n" +"uniform sampler2D uTexture;\n" +"varying vec2 texCoordinate;\n" +"varying vec4 fragmentColor;\n" +"void main()\n" +"{\n" +" gl_FragColor = fragmentColor * texture2D(uTexture, texCoordinate);\n" +//" gl_FragColor = texture2D(uTexture, texCoordinate);\n" +"}\n"; + +OsvrAndroidRenderer::OsvrAndroidRenderer() : OsvrUnityRenderer() +{ + +} + +OSVR_ReturnCode OsvrAndroidRenderer::CreateRenderBuffers() +{ + if (!setupRenderTextures(gRenderManager)) { + return OSVR_RETURN_FAILURE; + } + else + return OSVR_RETURN_SUCCESS; +} + +OSVR_ReturnCode OsvrAndroidRenderer::CreateRenderManager(OSVR_ClientContext context) +{ + //s_clientContext = context; + if (setupOSVR()) { + if (setupGraphics(gWidth, gHeight)) { + if (setupRenderManager()) { + return OSVR_RETURN_SUCCESS; + } + else + return 3; + } + else + return 2; + } + else + return 1; + + return OSVR_RETURN_SUCCESS; +} + +OSVR_ReturnCode OsvrAndroidRenderer::SetOsvrClientContext(OSVR_ClientContext context) +{ + s_clientContext = context; + return OSVR_RETURN_SUCCESS; +} + +void OsvrAndroidRenderer::SetColorBuffer(void *texturePtr, std::uint8_t eye, std::uint8_t buffer) +{ +#if UNITY_ANDROID + if (eye == 0) { + if (buffer == 0) + { + gLeftEyeTextureID = (GLuint)texturePtr; + } + else + { + gLeftEyeTextureIDBuffer2 = (GLuint)texturePtr; + } + } + else { + if (buffer == 0) + { + gRightEyeTextureID = (GLuint)texturePtr; + } + else + { + gRightEyeTextureIDBuffer2 = (GLuint)texturePtr; + } + } +#endif +} + +#if UNITY_ANDROID +inline osvr::renderkit::OSVR_ProjectionMatrix +ConvertProjectionMatrix(::OSVR_ProjectionMatrix matrix) { + osvr::renderkit::OSVR_ProjectionMatrix ret = { 0 }; + ret.bottom = matrix.bottom; + ret.top = matrix.top; + ret.left = matrix.left; + ret.right = matrix.right; + ret.nearClip = matrix.nearClip; + ret.farClip = matrix.farClip; + return ret; +} + +static void checkReturnCode(OSVR_ReturnCode returnCode, const char *msg) { + if (returnCode != OSVR_RETURN_SUCCESS) { + // LOGI("[OSVR] OSVR method returned a failure: %s", msg); + throw std::runtime_error(msg); + } +} +// RAII wrapper around the RenderManager collection APIs for OpenGL +class RenderInfoCollectionOpenGL { +private: + OSVR_RenderManager mRenderManager = nullptr; + OSVR_RenderInfoCollection mRenderInfoCollection = nullptr; + OSVR_RenderParams mRenderParams = { 0 }; + +public: + RenderInfoCollectionOpenGL(OSVR_RenderManager renderManager, + OSVR_RenderParams renderParams) + : mRenderManager(renderManager), mRenderParams(renderParams) { + OSVR_ReturnCode rc; + rc = osvrRenderManagerGetRenderInfoCollection( + mRenderManager, mRenderParams, &mRenderInfoCollection); + checkReturnCode( + rc, "osvrRenderManagerGetRenderInfoCollection call failed."); + } + + OSVR_RenderInfoCount getNumRenderInfo() { + OSVR_RenderInfoCount ret; + OSVR_ReturnCode rc; + rc = osvrRenderManagerGetNumRenderInfoInCollection( + mRenderInfoCollection, &ret); + checkReturnCode( + rc, "osvrRenderManagerGetNumRenderInfoInCollection call failed."); + return ret; + } + + OSVR_RenderInfoOpenGL getRenderInfo(OSVR_RenderInfoCount index) { + if (index < 0 || index >= getNumRenderInfo()) { + const static char *err = "getRenderInfo called with invalid index"; + // LOGE(err); + throw std::runtime_error(err); + } + OSVR_RenderInfoOpenGL ret; + OSVR_ReturnCode rc; + rc = osvrRenderManagerGetRenderInfoFromCollectionOpenGL( + mRenderInfoCollection, index, &ret); + checkReturnCode( + rc, + "osvrRenderManagerGetRenderInfoFromCollectionOpenGL call failed."); + return ret; + } + + ~RenderInfoCollectionOpenGL() { + if (mRenderInfoCollection) { + osvrRenderManagerReleaseRenderInfoCollection(mRenderInfoCollection); + } + } +}; + +static void checkGlError(const char *op) { + std::stringstream ss; + for (GLint error = glGetError(); error; error = glGetError()) { + // gluErrorString without glu + std::string errorString; + switch (error) { + case GL_NO_ERROR: + errorString = "GL_NO_ERROR"; + break; + case GL_INVALID_ENUM: + errorString = "GL_INVALID_ENUM"; + break; + case GL_INVALID_VALUE: + errorString = "GL_INVALID_VALUE"; + break; + case GL_INVALID_OPERATION: + errorString = "GL_INVALID_OPERATION"; + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + errorString = "GL_INVALID_FRAMEBUFFER_OPERATION"; + break; + case GL_OUT_OF_MEMORY: + errorString = "GL_OUT_OF_MEMORY"; + break; + default: + errorString = "(unknown error)"; + break; + } + // LOGI("after %s() glError (%s)\n", op, errorString.c_str()); + } +} + +class PassThroughOpenGLContextImpl { + OSVR_OpenGLToolkitFunctions toolkit; + int mWidth; + int mHeight; + + static void createImpl(void *data) {} + static void destroyImpl(void *data) { + delete ((PassThroughOpenGLContextImpl *)data); + } + static OSVR_CBool addOpenGLContextImpl(void *data, + const OSVR_OpenGLContextParams *p) { + return ((PassThroughOpenGLContextImpl *)data)->addOpenGLContext(p); + } + static OSVR_CBool removeOpenGLContextsImpl(void *data) { + return ((PassThroughOpenGLContextImpl *)data)->removeOpenGLContexts(); + } + static OSVR_CBool makeCurrentImpl(void *data, size_t display) { + return ((PassThroughOpenGLContextImpl *)data)->makeCurrent(display); + } + static OSVR_CBool swapBuffersImpl(void *data, size_t display) { + return ((PassThroughOpenGLContextImpl *)data)->swapBuffers(display); + } + static OSVR_CBool setVerticalSyncImpl(void *data, OSVR_CBool verticalSync) { + return ((PassThroughOpenGLContextImpl *)data) + ->setVerticalSync(verticalSync); + } + static OSVR_CBool handleEventsImpl(void *data) { + return ((PassThroughOpenGLContextImpl *)data)->handleEvents(); + } + static OSVR_CBool getDisplayFrameBufferImpl(void *data, size_t display, + GLuint *displayFrameBufferOut) { + return ((PassThroughOpenGLContextImpl *)data) + ->getDisplayFrameBuffer(display, displayFrameBufferOut); + } + static OSVR_CBool getDisplaySizeOverrideImpl(void *data, size_t display, + int *width, int *height) { + return ((PassThroughOpenGLContextImpl *)data) + ->getDisplaySizeOverride(display, width, height); + } + +public: + PassThroughOpenGLContextImpl() { + memset(&toolkit, 0, sizeof(toolkit)); + toolkit.size = sizeof(toolkit); + toolkit.data = this; + + toolkit.create = createImpl; + toolkit.destroy = destroyImpl; + toolkit.addOpenGLContext = addOpenGLContextImpl; + toolkit.removeOpenGLContexts = removeOpenGLContextsImpl; + toolkit.makeCurrent = makeCurrentImpl; + toolkit.swapBuffers = swapBuffersImpl; + toolkit.setVerticalSync = setVerticalSyncImpl; + toolkit.handleEvents = handleEventsImpl; + toolkit.getDisplaySizeOverride = getDisplaySizeOverrideImpl; + toolkit.getDisplayFrameBuffer = getDisplayFrameBufferImpl; + } + + ~PassThroughOpenGLContextImpl() {} + + const OSVR_OpenGLToolkitFunctions *getToolkit() const { return &toolkit; } + + bool addOpenGLContext(const OSVR_OpenGLContextParams *p) { return true; } + + bool removeOpenGLContexts() { return true; } + + bool makeCurrent(size_t display) { return true; } + + bool swapBuffers(size_t display) { return true; } + + bool setVerticalSync(bool verticalSync) { return true; } + + bool handleEvents() { return true; } + bool getDisplayFrameBuffer(size_t display, GLuint *displayFrameBufferOut) { + *displayFrameBufferOut = gFrameBuffer; + return true; + } + + bool getDisplaySizeOverride(size_t display, int *width, int *height) { + *width = gWidth; + *height = gHeight; + return false; + } +}; + +static GLuint loadShader(GLenum shaderType, const char *pSource) { + GLuint shader = glCreateShader(shaderType); + if (shader) { + glShaderSource(shader, 1, &pSource, NULL); + glCompileShader(shader); + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char *buf = (char *)malloc(infoLen); + if (buf) { + glGetShaderInfoLog(shader, infoLen, NULL, buf); + // LOGE("Could not compile shader %d:\n%s\n", + // shaderType, buf); + free(buf); + } + glDeleteShader(shader); + shader = 0; + } + } + } + return shader; +} + +static GLuint createProgram(const char *pVertexSource, + const char *pFragmentSource) { + GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); + if (!vertexShader) { + return 0; + } + + GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); + if (!pixelShader) { + return 0; + } + + GLuint program = glCreateProgram(); + if (program) { + glAttachShader(program, vertexShader); + checkGlError("glAttachShader"); + + glAttachShader(program, pixelShader); + checkGlError("glAttachShader"); + + glBindAttribLocation(program, 0, "vPosition"); + glBindAttribLocation(program, 1, "vColor"); + glBindAttribLocation(program, 2, "vTexCoordinate"); + + glLinkProgram(program); + GLint linkStatus = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) { + GLint bufLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) { + char *buf = (char *)malloc(bufLength); + if (buf) { + glGetProgramInfoLog(program, bufLength, NULL, buf); + // LOGE("Could not link program:\n%s\n", buf); + free(buf); + } + } + glDeleteProgram(program); + program = 0; + } + } + return program; +} + +static GLuint createTexture(GLuint width, GLuint height) { + GLuint ret; + glGenTextures(1, &ret); + checkGlError("glGenTextures"); + + glBindTexture(GL_TEXTURE_2D, ret); + checkGlError("glBindTexture"); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + // // DEBUG CODE - should be passing null here, but then texture is + // always black. + GLubyte *dummyBuffer = new GLubyte[width * height * 4]; + for (GLuint i = 0; i < width * height * 4; i++) { + dummyBuffer[i] = (i % 4 ? 100 : 255); + } + + // This dummy texture successfully makes it into the texture and renders, + // but subsequent + // calls to glTexSubImage2D don't appear to do anything. + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, dummyBuffer); + checkGlError("glTexImage2D"); + delete[] dummyBuffer; + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + checkGlError("glTexParameteri"); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + checkGlError("glTexParameteri"); + return ret; +} + +static void updateTexture(GLuint width, GLuint height, GLubyte *data) { + + glBindTexture(GL_TEXTURE_2D, gTextureID); + checkGlError("glBindTexture"); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + // @todo use glTexSubImage2D to be faster here, but add check to make sure + // height/width are the same. + // glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, + // GL_UNSIGNED_BYTE, data); + // checkGlError("glTexSubImage2D"); + //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, + //GL_UNSIGNED_BYTE, data); + //checkGlError("glTexImage2D"); +} + +static void imagingCallback(void *userdata, const OSVR_TimeValue *timestamp, + const OSVR_ImagingReport *report) { + + OSVR_ClientContext *ctx = (OSVR_ClientContext *)userdata; + + gReportNumber++; + GLuint width = report->state.metadata.width; + GLuint height = report->state.metadata.height; + gLastFrameWidth = width; + gLastFrameHeight = height; + GLuint size = width * height * 4; + + gLastFrame = report->state.data; +} +#if SUPPORT_OPENGL +inline GLuint GetEyeTextureOpenGL(int eye, int buffer = 0) { + if (buffer == 0) + { + return (eye == 0) ? gLeftEyeTextureID : gRightEyeTextureID; + + } + else + { + return (eye == 0) ? gLeftEyeTextureIDBuffer2 : gRightEyeTextureIDBuffer2; + + } +} +#endif +#endif + +bool OsvrAndroidRenderer::setupRenderTextures(OSVR_RenderManager renderManager) { +#if UNITY_ANDROID + try { + OSVR_ReturnCode rc; + rc = osvrRenderManagerGetDefaultRenderParams(&gRenderParams); + checkReturnCode(rc, + "osvrRenderManagerGetDefaultRenderParams call failed."); + + gRenderParams.farClipDistanceMeters = 100000.0f; + gRenderParams.nearClipDistanceMeters = 0.00001f; + RenderInfoCollectionOpenGL renderInfo(renderManager, gRenderParams); + + OSVR_RenderManagerRegisterBufferState state; + rc = osvrRenderManagerStartRegisterRenderBuffers(&state); + checkReturnCode( + rc, "osvrRenderManagerStartRegisterRenderBuffers call failed."); + + for (int j = 0; j < numBuffers; j++){ + FrameInfoOpenGL* f = new FrameInfoOpenGL(); + f->renderBuffers.clear(); + for (OSVR_RenderInfoCount i = 0; i < renderInfo.getNumRenderInfo(); + i++) { + OSVR_RenderInfoOpenGL currentRenderInfo = + renderInfo.getRenderInfo(i); + + // Determine the appropriate size for the frame buffer to be used + // for + // all eyes when placed horizontally size by side. + int width = static_cast(currentRenderInfo.viewport.width); + int height = static_cast(currentRenderInfo.viewport.height); + + GLuint frameBufferName = 0; + glGenFramebuffers(1, &frameBufferName); + glBindFramebuffer(GL_FRAMEBUFFER, frameBufferName); + + GLuint renderBufferName = 0; + glGenRenderbuffers(1, &renderBufferName); + + GLuint colorBufferName = GetEyeTextureOpenGL(i, j); + rc = osvrRenderManagerCreateColorBufferOpenGL( + width, height, GL_RGBA, &colorBufferName); + checkReturnCode( + rc, "osvrRenderManagerCreateColorBufferOpenGL call failed."); + + // bind it to our framebuffer + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, colorBufferName, 0); + + // The depth buffer + GLuint depthBuffer; + rc = osvrRenderManagerCreateDepthBufferOpenGL(width, height, + &depthBuffer); + checkReturnCode( + rc, "osvrRenderManagerCreateDepthBufferOpenGL call failed."); + + glGenRenderbuffers(1, &depthBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, + height); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depthBuffer); + + glBindRenderbuffer(GL_RENDERBUFFER, renderBufferName); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, + height); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, colorBufferName, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, renderBufferName); + + // unbind the framebuffer + glBindTexture(GL_TEXTURE_2D, 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, gFrameBuffer); + + OSVR_RenderBufferOpenGL buffer = { 0 }; + buffer.colorBufferName = colorBufferName; + buffer.depthStencilBufferName = depthBuffer; + rc = osvrRenderManagerRegisterRenderBufferOpenGL(state, buffer); + checkReturnCode( + rc, "osvrRenderManagerRegisterRenderBufferOpenGL call failed."); + + OSVR_RenderTargetInfoOpenGL renderTarget = { 0 }; + renderTarget.frameBufferName = frameBufferName; + renderTarget.renderBufferName = renderBufferName; + renderTarget.colorBufferName = colorBufferName; + renderTarget.depthBufferName = depthBuffer; + f->renderBuffers.push_back(renderTarget); + //gRenderTargets.push_back(renderTarget); + } + frameInfoOGL.push_back(f); + } + rc = osvrRenderManagerFinishRegisterRenderBuffers(renderManager, state, + true); + checkReturnCode( + rc, "osvrRenderManagerFinishRegisterRenderBuffers call failed."); + } + catch (...) { + // LOGE("Error durring render target creation."); + return false; + } + return true; +#endif + return true; +} + +bool OsvrAndroidRenderer::setupOSVR() { + if (gOSVRInitialized) { + return true; + } + OSVR_ReturnCode rc = 0; + try { + // On Android, the current working directory is added to the default + // plugin search path. + // it also helps the server find its configuration and display files. + // boost::filesystem::current_path("/data/data/com.osvr.android.gles2sample/files"); + // auto workingDirectory = boost::filesystem::current_path(); + // //LOGI("[OSVR] Current working directory: %s", + // workingDirectory.string().c_str()); + + // auto-start the server + osvrClientAttemptServerAutoStart(); + + if (!s_clientContext) { + // LOGI("[OSVR] Creating ClientContext..."); + s_clientContext = + osvrClientInit("com.osvr.android.examples.OSVROpenGL", 0); + if (!s_clientContext) { + // LOGI("[OSVR] could not create client context"); + return false; + } + + // temporary workaround to DisplayConfig issue, + // display sometimes fails waiting for the tree from the server. + // LOGI("[OSVR] Calling update a few times..."); + for (int i = 0; i < 10000; i++) { + rc = osvrClientUpdate(s_clientContext); + if (rc != OSVR_RETURN_SUCCESS) { + // LOGI("[OSVR] Error while updating client context."); + return false; + } + } + + rc = osvrClientCheckStatus(s_clientContext); + if (rc != OSVR_RETURN_SUCCESS) { + // LOGI("[OSVR] Client context reported bad status."); + return false; + } + else { + // LOGI("[OSVR] Client context reported good status."); + } + + // if (OSVR_RETURN_SUCCESS != + // osvrClientGetInterface(s_clientContext, + // "/camera", &gCamera)) { + // //LOGI("Error, could not get the camera + // interface at /camera."); + // return false; + // } + // + // // Register the imaging callback. + // if (OSVR_RETURN_SUCCESS != + // osvrRegisterImagingCallback(gCamera, + // &imagingCallback, &s_clientContext)) { + // //LOGI("Error, could not register image + // callback."); + // return false; + // } + } + + gOSVRInitialized = true; + return true; + } + catch (const std::runtime_error &ex) { + // LOGI("[OSVR] OSVR initialization failed: %s", ex.what()); + return false; + } +} + +// Idempotent call to setup render manager +bool OsvrAndroidRenderer::setupRenderManager() { +#if UNITY_ANDROID + if (!gOSVRInitialized || !gGraphicsInitializedOnce) { + return false; + } + if (gRenderManagerInitialized) { + return true; + } + try { + PassThroughOpenGLContextImpl *glContextImpl = + new PassThroughOpenGLContextImpl(); + gGraphicsLibrary.toolkit = glContextImpl->getToolkit(); + + if (OSVR_RETURN_SUCCESS != + osvrCreateRenderManagerOpenGL(s_clientContext, "OpenGL", + gGraphicsLibrary, &gRenderManager, + &gRenderManagerOGL)) { + std::cerr << "Could not create the RenderManager" << std::endl; + return false; + } + + // Open the display and make sure this worked + OSVR_OpenResultsOpenGL openResults; + if (OSVR_RETURN_SUCCESS != osvrRenderManagerOpenDisplayOpenGL( + gRenderManagerOGL, &openResults) || + (openResults.status == OSVR_OPEN_STATUS_FAILURE)) { + std::cerr << "Could not open display" << std::endl; + osvrDestroyRenderManager(gRenderManager); + gRenderManager = gRenderManagerOGL = nullptr; + return false; + } + + gRenderManagerInitialized = true; + return true; + } + catch (const std::runtime_error &ex) { + // LOGI("[OSVR] RenderManager initialization failed: %s", ex.what()); + return false; + } +#endif + return false; +} + +bool OsvrAndroidRenderer::setupGraphics(int width, int height) { +#if UNITY_ANDROID + // initializeGLES2Ext(); + GLint frameBuffer; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &frameBuffer); + gFrameBuffer = (GLuint)frameBuffer; + // LOGI("Window GL_FRAMEBUFFER_BINDING: %d", gFrameBuffer); + + // LOGI("setupGraphics(%d, %d)", width, height); + // gWidth = width; + // gHeight = height; + + // bool osvrSetupSuccess = setupOSVR(); + + gProgram = createProgram(gVertexShader, gFragmentShader); + if (!gProgram) { + // LOGE("Could not create program."); + osvrJniWrapperClass = jniEnvironment->FindClass( + "org/osvr/osvrunityjni/OsvrJNIWrapper"); // try to find the class + if (osvrJniWrapperClass == nullptr) { + return false; + } + else { // if class found, continue + + jmethodID androidDebugLogMethodID = jniEnvironment->GetStaticMethodID( + osvrJniWrapperClass, "logMsg", + "(Ljava/lang/String;)V"); // find method + std::string stringy = + "[OSVR-Unity-Android] Could not create program."; + jstring jstr2 = jniEnvironment->NewStringUTF(stringy.c_str()); + jniEnvironment->CallStaticVoidMethod(osvrJniWrapperClass, androidDebugLogMethodID, + jstr2); + } + return false; + } + /*gvPositionHandle = glGetAttribLocation(gProgram, "vPosition"); + checkGlError("glGetAttribLocation"); + // LOGI("glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle); + + gvColorHandle = glGetAttribLocation(gProgram, "vColor"); + checkGlError("glGetAttribLocation"); + // LOGI("glGetAttribLocation(\"vColor\") = %d\n", gvColorHandle); + + gvTexCoordinateHandle = glGetAttribLocation(gProgram, "vTexCoordinate"); + checkGlError("glGetAttribLocation"); + // LOGI("glGetAttribLocation(\"vTexCoordinate\") = %d\n", + // gvTexCoordinateHandle); + + gvProjectionUniformId = glGetUniformLocation(gProgram, "projection"); + gvViewUniformId = glGetUniformLocation(gProgram, "view"); + gvModelUniformId = glGetUniformLocation(gProgram, "model"); + guTextureUniformId = glGetUniformLocation(gProgram, "uTexture"); + + glViewport(0, 0, width, height); + checkGlError("glViewport"); + + glDisable(GL_CULL_FACE); + + // @todo can we resize the texture after it has been created? + // if not, we may have to delete the dummy one and create a new one after + // the first imaging report. + // LOGI("Creating texture... here we go!"); + + gTextureID = createTexture(width, height);*/ + + // return osvrSetupSuccess; + gGraphicsInitializedOnce = true; +#endif + return true; +} + +OSVR_Pose3 OsvrAndroidRenderer::GetEyePose(std::uint8_t eye) +{ + OSVR_RenderInfoOpenGL currentRenderInfo; +#if UNITY_ANDROID + OSVR_RenderParams renderParams; + OSVR_ReturnCode rc = osvrRenderManagerGetDefaultRenderParams(&renderParams); + checkReturnCode(rc, "osvrRenderManagerGetDefaultRenderParams call failed."); + RenderInfoCollectionOpenGL renderInfoCollection(gRenderManager, + renderParams); + currentRenderInfo = renderInfoCollection.getRenderInfo(eye); +#endif + return currentRenderInfo.pose; +} + +OSVR_ProjectionMatrix OsvrAndroidRenderer::GetProjectionMatrix(std::uint8_t eye) +{ + OSVR_ProjectionMatrix proj; + +#if UNITY_ANDROID + + OSVR_RenderParams renderParams; + OSVR_ReturnCode rc = osvrRenderManagerGetDefaultRenderParams(&renderParams); + checkReturnCode(rc, "osvrRenderManagerGetDefaultRenderParams call failed."); + RenderInfoCollectionOpenGL renderInfoCollection(gRenderManager, + renderParams); + OSVR_RenderInfoOpenGL currentRenderInfo = + renderInfoCollection.getRenderInfo(eye); + proj.left = currentRenderInfo.projection.left; + proj.right = currentRenderInfo.projection.right; + proj.top = currentRenderInfo.projection.top; + proj.bottom = currentRenderInfo.projection.bottom; + proj.nearClip = currentRenderInfo.projection.nearClip; + proj.farClip = currentRenderInfo.projection.farClip; +#endif + return proj; +} + +OSVR_ViewportDescription OsvrAndroidRenderer::GetViewport(std::uint8_t eye) +{ + OSVR_ViewportDescription viewDesc; + +#if UNITY_ANDROID + OSVR_RenderParams renderParams; + OSVR_ReturnCode rc = osvrRenderManagerGetDefaultRenderParams(&renderParams); + checkReturnCode(rc, "osvrRenderManagerGetDefaultRenderParams call failed."); + RenderInfoCollectionOpenGL renderInfoCollection(gRenderManager, + renderParams); + OSVR_RenderInfoOpenGL currentRenderInfo = + renderInfoCollection.getRenderInfo(eye); + viewDesc.width = currentRenderInfo.viewport.width; + viewDesc.height = currentRenderInfo.viewport.height; + viewDesc.left = currentRenderInfo.viewport.left; + viewDesc.lower = currentRenderInfo.viewport.lower; +#endif + return viewDesc; +} + +void OsvrAndroidRenderer::OnRenderEvent() +{ +#if UNITY_ANDROID + if (!gOSVRInitialized) { + // @todo implement some logging/error handling? + return; + } + + // this call is idempotent, so we can make it every frame. + // have to ensure render manager is setup from the rendering thread with + // a current GLES context, so this is a lazy setup call + if (!setupRenderManager()) { + // @todo implement some logging/error handling? + return; + } + + OSVR_ReturnCode rc; + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + checkGlError("glClearColor"); + glViewport(0, 0, gWidth, gHeight); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + checkGlError("glClear"); + + if (gRenderManager && s_clientContext) { + //osvrClientUpdate(s_clientContext); + /*if (gLastFrame != nullptr) { + updateTexture(gLastFrameWidth, gLastFrameHeight, gLastFrame); + osvrClientFreeImage(s_clientContext, gLastFrame); + gLastFrame = nullptr; + }*/ + + OSVR_RenderParams renderParams; + rc = osvrRenderManagerGetDefaultRenderParams(&renderParams); + checkReturnCode(rc, + "osvrRenderManagerGetDefaultRenderParams call failed."); + + RenderInfoCollectionOpenGL renderInfoCollection(gRenderManager, + renderParams); + + // Get the present started + OSVR_RenderManagerPresentState presentState; + rc = osvrRenderManagerStartPresentRenderBuffers(&presentState); + checkReturnCode( + rc, "osvrRenderManagerStartPresentRenderBuffers call failed."); + + int frame = iterations % numBuffers; + + for (OSVR_RenderInfoCount renderInfoCount = 0; + renderInfoCount < renderInfoCollection.getNumRenderInfo(); + renderInfoCount++) { + + // get the current render info + OSVR_RenderInfoOpenGL currentRenderInfo = + renderInfoCollection.getRenderInfo(renderInfoCount); + // Set color and depth buffers for the frame buffer + OSVR_RenderTargetInfoOpenGL renderTargetInfo = frameInfoOGL[frame]->renderBuffers[renderInfoCount]; + //gRenderTargets[renderInfoCount]; + + // present this render target (deferred until the finish call below) + OSVR_ViewportDescription normalizedViewport = { 0 }; + normalizedViewport.left = 0.0f; + normalizedViewport.lower = 0.0f; + normalizedViewport.width = 1.0f; + normalizedViewport.height = 1.0f; + OSVR_RenderBufferOpenGL buffer = { 0 }; + buffer.colorBufferName = GetEyeTextureOpenGL(renderInfoCount, frame); + buffer.depthStencilBufferName = renderTargetInfo.depthBufferName; + + rc = osvrRenderManagerPresentRenderBufferOpenGL( + presentState, buffer, currentRenderInfo, normalizedViewport); + checkReturnCode( + rc, "osvrRenderManagerPresentRenderBufferOpenGL call failed."); + } + + iterations++; + // actually kick off the present + rc = osvrRenderManagerFinishPresentRenderBuffers( + gRenderManager, presentState, renderParams, false); + checkReturnCode( + rc, "osvrRenderManagerFinishPresentRenderBuffers call failed."); + } +#endif +} + +void OsvrAndroidRenderer::OnInitializeGraphicsDeviceEvent() +{/* +#if UNITY_ANDROID + osvrJniWrapperClass = jniEnvironment->FindClass( + OSVR_JNI_CLASS_PATH); // try to find the class + if (osvrJniWrapperClass == nullptr) { + return; + } + else { // if osvrJniWrapperClass found, continue + + // get the Android logger method ID + androidDebugLogMethodID = jniEnvironment->GetStaticMethodID( + osvrJniWrapperClass, OSVR_JNI_LOG_METHOD_NAME, + "(Ljava/lang/String;)V"); // find method + // get the method ID for setting the GL context + jmethodID setGlContextId = jniEnvironment->GetStaticMethodID( + osvrJniWrapperClass, "setUnityMainContext", + "()J"); // find method + if (setGlContextId == nullptr) + return; + else { + jlong currentEglContextHandle = + jniEnvironment->CallStaticLongMethod( + osvrJniWrapperClass, setGlContextId); // call method + // example code for logging the context ID + /*long myLongValue = (long)currentEglContextHandle; + std::string stringy = "[OSVR-Unity-Android] setCurrentContext with handle : " + std::to_string(myLongValue); + jstring jstr2 = jniEnvironment->NewStringUTF(stringy.c_str()); + jniEnvironment->CallStaticVoidMethod(osvrJniWrapperClass, + androidDebugLogMethodID, jstr2);*/ + + /* + contextSet = true; + } + // get the display width and height via JNI + jmethodID getWidthMID = jniEnvironment->GetStaticMethodID( + osvrJniWrapperClass, "getDisplayWidth", "()I"); // find method + jmethodID getHeightMID = jniEnvironment->GetStaticMethodID( + osvrJniWrapperClass, "getDisplayHeight", "()I"); // find method + if (getWidthMID == nullptr || getHeightMID == nullptr) + return; + else { + jint displayWidth = jniEnvironment->CallStaticIntMethod( + osvrJniWrapperClass, getWidthMID); // call method + jint displayHeight = jniEnvironment->CallStaticIntMethod( + osvrJniWrapperClass, getHeightMID); // call method + gWidth = (int)displayWidth; + gHeight = (int)displayHeight; + } + } +#endif + */ +} + + +void OsvrAndroidRenderer::SetFarClipDistance(double distance) +{ + s_farClipDistance = distance; + +} + +void OsvrAndroidRenderer::SetIPD(double ipdMeters) +{ + s_ipd = ipdMeters; + +} + +void OsvrAndroidRenderer::SetNearClipDistance(double distance) +{ + s_nearClipDistance = distance; +} +void OsvrAndroidRenderer::ShutdownRenderManager() +{ + + if (gRenderManager) { + osvrDestroyRenderManager(gRenderManager); + gRenderManager = gRenderManagerOGL = nullptr; + } + + // is this needed? Maybe not. the display config manages the lifetime. + if (s_clientContext != nullptr) { + //osvrClientShutdown(s_clientContext); + s_clientContext = nullptr; + } + + osvrClientReleaseAutoStartedServer(); + contextSet = false; +} + +void OsvrAndroidRenderer::UpdateRenderInfo() +{ +} + + + + diff --git a/OsvrAndroidRenderer.h b/OsvrAndroidRenderer.h new file mode 100644 index 0000000..a2fb7e2 --- /dev/null +++ b/OsvrAndroidRenderer.h @@ -0,0 +1,73 @@ +/** @file +@brief Header +@date 2017 +@author +Sensics, Inc. + +*/ + +// Copyright 2017 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "OsvrUnityRenderer.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "OsvrRenderingPlugin.h" +class OsvrAndroidRenderer : public OsvrUnityRenderer{ +public: + OsvrAndroidRenderer(); + ~OsvrAndroidRenderer(); + virtual OSVR_ReturnCode CreateRenderBuffers(); + virtual OSVR_ReturnCode CreateRenderManager(OSVR_ClientContext context); + virtual OSVR_ReturnCode SetOsvrClientContext(OSVR_ClientContext context); + virtual OSVR_Pose3 GetEyePose(std::uint8_t eye); + virtual OSVR_ProjectionMatrix GetProjectionMatrix(std::uint8_t eye); + virtual OSVR_ViewportDescription GetViewport(std::uint8_t eye); + virtual void OnRenderEvent(); + virtual void OnInitializeGraphicsDeviceEvent(); + virtual void SetFarClipDistance(double distance); + virtual void SetIPD(double ipdMeters); + virtual void SetNearClipDistance(double distance); + virtual void ShutdownRenderManager(); + virtual void UpdateRenderInfo(); + virtual void SetColorBuffer(void *texturePtr, std::uint8_t eye, std::uint8_t buffer); + + + + //@todo keep refactoring into generic base class +protected: + bool setupOSVR(); + bool setupRenderManager(); + bool setupGraphics(int width, int height); + bool setupRenderTextures(OSVR_RenderManager renderManager); + OSVR_RenderManager gRenderManager = nullptr; + OSVR_RenderManagerOpenGL gRenderManagerOGL = nullptr; + +}; \ No newline at end of file diff --git a/OsvrD3DRenderer.cpp b/OsvrD3DRenderer.cpp new file mode 100644 index 0000000..348e107 --- /dev/null +++ b/OsvrD3DRenderer.cpp @@ -0,0 +1,490 @@ +#include "OsvrRenderingPlugin.h" +#if SUPPORT_D3D11 +#include "OsvrUnityRenderer.h" +#include "OsvrD3DRenderer.h" + + +OsvrD3DRenderer::OsvrD3DRenderer() : OsvrUnityRenderer() +{ + +} +void OsvrD3DRenderer::SetColorBuffer(void *texturePtr, std::uint8_t eye, std::uint8_t buffer) +{ + if (eye == 0) { + if (buffer == 0) + { + s_leftEyeTexturePtr = texturePtr; + } + else + { + s_leftEyeTexturePtrBuffer2 = texturePtr; + } + } + else { + if (buffer == 0) + { + s_rightEyeTexturePtr = texturePtr; + } + else + { + s_rightEyeTexturePtrBuffer2 = texturePtr; + } + } +} + +#if UNITY_WIN +void OsvrD3DRenderer::UpdateRenderInfo() +{ + if (s_render == nullptr) + { + return; + } + // Do a call to get the information we need to construct our + // color and depth render-to-texture buffers. + OSVR_RenderParams renderParams; + osvrRenderManagerGetDefaultRenderParams(&renderParams); + + if ((OSVR_RETURN_SUCCESS != osvrRenderManagerGetNumRenderInfo( + s_render, renderParams, &numRenderInfo))) { + DebugLog("[OSVR Rendering Plugin] Could not get context number of render infos."); + ShutdownRenderManager(); + return; + } + + s_renderInfo.clear(); + for (OSVR_RenderInfoCount i = 0; i < numRenderInfo; i++) { + OSVR_RenderInfoD3D11 info; + if ((OSVR_RETURN_SUCCESS != osvrRenderManagerGetRenderInfoD3D11( + s_renderD3D, i, renderParams, &info))) { + DebugLog("[OSVR Rendering Plugin] Could not get render info."); + ShutdownRenderManager(); + return; + } + s_renderInfo.push_back(info); + } + if (numRenderInfo > 0) + { + s_lastRenderInfo = s_renderInfo; + } +} +#endif // UNITY_WIN +OSVR_ReturnCode OsvrD3DRenderer::ConstructBuffersD3D11(int eye, int buffer, FrameInfoD3D11* fInfo) +{ + //DebugLog("[OSVR Rendering Plugin] ConstructBuffersD3D11"); + HRESULT hr; + // The color buffer for this eye. We need to put this into + // a generic structure for the Present function, but we only need + // to fill in the Direct3D portion. + // Note that this texture format must be RGBA and unsigned byte, + // so that we can present it to Direct3D for DirectMode. + ID3D11Texture2D *D3DTexture = reinterpret_cast(GetEyeTexture(eye, buffer)); + unsigned width = static_cast(s_renderInfo[eye].viewport.width); + unsigned height = static_cast(s_renderInfo[eye].viewport.height); + + D3DTexture->GetDesc(&s_textureDesc); + + // Fill in the resource view for your render texture buffer here + D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc = {}; + // This must match what was created in the texture to be rendered + /// @todo Figure this out by introspection on the texture? + // renderTargetViewDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + /// @todo Interesting - change this line to DXGI_FORMAT_R8G8B8A8_UNORM_SRGB + /// and not only do you not get direct mode, you get multicolored static on + /// the display. + renderTargetViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + renderTargetViewDesc.Texture2D.MipSlice = 0; + + // Create the render target view. + ID3D11RenderTargetView *renderTargetView = + nullptr; //< Pointer to our render target view + hr = s_renderInfo[eye].library.device->CreateRenderTargetView( + D3DTexture, &renderTargetViewDesc, &renderTargetView); + if (FAILED(hr)) { + DebugLog("[OSVR Rendering Plugin] Could not create render target for eye"); + return OSVR_RETURN_FAILURE; + } + + // Push the filled-in RenderBuffer onto the stack. + OSVR_RenderBufferD3D11 rbD3D; + rbD3D.colorBuffer = D3DTexture; + rbD3D.colorBufferView = renderTargetView; + fInfo->renderBuffers.push_back(rbD3D); + + IDXGIKeyedMutex* keyedMutex = nullptr; + hr = D3DTexture->QueryInterface( + __uuidof(IDXGIKeyedMutex), (LPVOID*)&keyedMutex); + if (FAILED(hr) || keyedMutex == nullptr) { + DebugLog("[OSVR Rendering Plugin] Could not mutex pointer"); + return OSVR_RETURN_FAILURE; + } + fInfo->keyedMutex = keyedMutex; + + //================================================================== + // Create a depth buffer + + // Make the depth/stencil texture. + D3D11_TEXTURE2D_DESC textureDescription = { 0 }; + textureDescription.SampleDesc.Count = 1; + textureDescription.SampleDesc.Quality = 0; + textureDescription.Usage = D3D11_USAGE_DEFAULT; + textureDescription.BindFlags = D3D11_BIND_DEPTH_STENCIL; + textureDescription.Width = width; + textureDescription.Height = height; + textureDescription.MipLevels = 1; + textureDescription.ArraySize = 1; + textureDescription.CPUAccessFlags = 0; + textureDescription.MiscFlags = 0; + /// @todo Make this a parameter + textureDescription.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + ID3D11Texture2D* depthStencilBuffer; + hr = s_libraryD3D.device->CreateTexture2D( + &textureDescription, NULL, &depthStencilBuffer); + if (FAILED(hr)) { + DebugLog("[OSVR Rendering Plugin] Could not create depth/stencil texture"); + return OSVR_RETURN_FAILURE; + } + fInfo->depthStencilTexture = depthStencilBuffer; + + // Create the depth/stencil view description + D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDescription; + memset(&depthStencilViewDescription, 0, sizeof(depthStencilViewDescription)); + depthStencilViewDescription.Format = textureDescription.Format; + depthStencilViewDescription.ViewDimension = + D3D11_DSV_DIMENSION_TEXTURE2D; + depthStencilViewDescription.Texture2D.MipSlice = 0; + + ID3D11DepthStencilView* depthStencilView; + hr = s_libraryD3D.device->CreateDepthStencilView( + depthStencilBuffer, + &depthStencilViewDescription, + &depthStencilView); + if (FAILED(hr)) { + DebugLog("[OSVR Rendering Plugin] Could not create depth/stencil view"); + return OSVR_RETURN_FAILURE; + } + fInfo->depthStencilView = depthStencilView; + + return OSVR_RETURN_SUCCESS; +} + +OSVR_ReturnCode OsvrD3DRenderer::CreateRenderBuffers() +{ + for (int i = 0; i < numBuffers; i++) + { + FrameInfoD3D11* f = new FrameInfoD3D11(); + f->renderBuffers.clear(); + for (int j = 0; j < numRenderInfo; j++) + { + ConstructBuffersD3D11(i, j, f); + } + frameInfo.push_back(f); + } + + // Register our constructed buffers so that we can use them for + // presentation. + OSVR_RenderManagerRegisterBufferState registerBufferState; + if ((OSVR_RETURN_SUCCESS != osvrRenderManagerStartRegisterRenderBuffers( + ®isterBufferState))) { + DebugLog("[OSVR Rendering Plugin] Could not start registering render buffers"); + ShutdownRenderManager(); + return OSVR_RETURN_FAILURE; + } + for (size_t i = 0; i < frameInfo.size(); i++) { + for (int j = 0; j < numRenderInfo; j++) + { + if ((OSVR_RETURN_SUCCESS != osvrRenderManagerRegisterRenderBufferD3D11( + registerBufferState, frameInfo[i]->renderBuffers[j]))) { + DebugLog("[OSVR Rendering Plugin] Could not register render buffer "); + ShutdownRenderManager(); + return OSVR_RETURN_FAILURE; + } + } + + } + if ((OSVR_RETURN_SUCCESS != osvrRenderManagerFinishRegisterRenderBuffers( + s_render, registerBufferState, false))) { + DebugLog("[OSVR Rendering Plugin] Could not finish registering render buffers"); + ShutdownRenderManager(); + return OSVR_RETURN_FAILURE; + } +} + +OSVR_ReturnCode OsvrD3DRenderer::CreateRenderManager(OSVR_ClientContext context) +{ + if (s_render != nullptr) { + if (osvrRenderManagerGetDoingOkay(s_render)) { + DebugLog("[OSVR Rendering Plugin] RenderManager already created " + "and doing OK - will just return success without trying " + "to re-initialize."); + return OSVR_RETURN_SUCCESS; + } + + DebugLog("[OSVR Rendering Plugin] RenderManager already created, " + "but not doing OK. Will shut down before creating again."); + ShutdownRenderManager(); + return OSVR_RETURN_SUCCESS; + } + if (s_clientContext != nullptr) { + DebugLog( + "[OSVR Rendering Plugin] Client context already set! Replacing..."); + } + s_clientContext = context; + + if (!s_deviceType) { + // @todo pass the platform from Unity + // This is a patch to workaround a bug in Unity where the renderer type + // is not being set on Windows x86 builds. Until the OpenGL path is + // working, it's safe to assume we're using D3D11, but we'd rather get + // the platform from Unity than assume it's D3D11. + + s_deviceType = kUnityGfxRendererD3D11; + } + + bool setLibraryFromOpenDisplayReturn = false; + /// @todo We should always have a legit value in + /// s_deviceType.getDeviceTypeEnum() at this point, right? + switch (s_deviceType.getDeviceTypeEnum()) { + + case OSVRSupportedRenderers::D3D11: + if (OSVR_RETURN_SUCCESS != + osvrCreateRenderManagerD3D11(context, "Direct3D11", s_libraryD3D, + &s_render, &s_renderD3D)) { + DebugLog("[OSVR Rendering Plugin] Could not create RenderManagerD3D"); + return OSVR_RETURN_FAILURE; + } + break; + } + + if (s_render == nullptr) { + DebugLog("[OSVR Rendering Plugin] Could not create RenderManagerD3D"); + ShutdownRenderManager(); + return OSVR_RETURN_FAILURE; + } + + // Open the display and make sure this worked. + OSVR_OpenResultsD3D11 openResults; + if ((OSVR_RETURN_SUCCESS != + osvrRenderManagerOpenDisplayD3D11(s_renderD3D, &openResults)) || + (openResults.status == OSVR_OPEN_STATUS_FAILURE)) { + //DebugLog("[OSVR Rendering Plugin] Could not open display"); + ShutdownRenderManager(); + return OSVR_RETURN_FAILURE; + } + if (openResults.library.device == nullptr) { + DebugLog("[OSVR Rendering Plugin] Could not get device when opening display"); + + ShutdownRenderManager(); + return OSVR_RETURN_FAILURE; + } + if (openResults.library.context == nullptr) { + DebugLog("[OSVR Rendering Plugin] Could not get context when opening display"); + + ShutdownRenderManager(); + return OSVR_RETURN_FAILURE; + } + + // create a new set of RenderParams for passing to GetRenderInfo() + osvrRenderManagerGetDefaultRenderParams(&s_renderParams); + + UpdateRenderInfo(); + + DebugLog("[OSVR Rendering Plugin] Created RenderManager Successfully"); + return OSVR_RETURN_SUCCESS; +} + +OSVR_ReturnCode OsvrD3DRenderer::SetOsvrClientContext(OSVR_ClientContext context) +{ + s_clientContext = context; + return OSVR_RETURN_SUCCESS; +} + +OSVR_Pose3 OsvrD3DRenderer::GetEyePose(std::uint8_t eye) +{ + OSVR_Pose3 pose; + osvrPose3SetIdentity(&pose); + if (numRenderInfo > 0 && eye <= numRenderInfo - 1 && s_render != nullptr) { + pose = s_lastRenderInfo[eye].pose; + lastGoodPose = pose; + } + else { + std::string errorLog = "[OSVR Rendering Plugin] Error in GetEyePose, " + "returning default values. Eye = " + + std::to_string(int(eye)); + DebugLog(errorLog.c_str()); + pose = lastGoodPose; + } + return pose; +} + +OSVR_ProjectionMatrix OsvrD3DRenderer::GetProjectionMatrix(std::uint8_t eye) +{ + OSVR_ProjectionMatrix pm; + if (numRenderInfo > 0 && eye <= numRenderInfo - 1) { + pm = s_lastRenderInfo[eye].projection; + lastGoodProjMatrix = pm; + } + else { + std::string errorLog = "[OSVR Rendering Plugin] Error in " + "GetProjectionMatrix, returning default values. " + "Eye = " + + std::to_string(int(eye)); + DebugLog(errorLog.c_str()); + pm = lastGoodProjMatrix; + } + return pm; +} + +OSVR_ViewportDescription OsvrD3DRenderer::GetViewport(std::uint8_t eye) +{ + OSVR_ViewportDescription viewportDescription; + if (numRenderInfo > 0 && eye <= numRenderInfo - 1) { + viewportDescription = s_lastRenderInfo[eye].viewport; + + // cache the viewport width and height + // patches issue where sometimes empty viewport is returned + //@todo fix the real cause of why this method bugs out occasionally on + //some machines, more often on others + if (viewportWidth == 0 && s_lastRenderInfo[eye].viewport.width != 0) { + viewportWidth = s_lastRenderInfo[eye].viewport.width; + } + if (viewportHeight == 0 && s_lastRenderInfo[eye].viewport.height != 0) { + viewportHeight = s_lastRenderInfo[eye].viewport.height; + } + lastGoodViewportDescription = viewportDescription; + } + else { + // we shouldn't be here unless we hit a bug, in which case, we avoid + // error by returning cached viewport values + std::string errorLog = "[OSVR Rendering Plugin] Error in GetViewport, " + "returning cached values. Eye = " + + std::to_string(int(eye)); + DebugLog(errorLog.c_str()); + viewportDescription.left = 0; + viewportDescription.lower = 0; + viewportDescription.width = viewportWidth; + viewportDescription.height = viewportHeight; + lastGoodViewportDescription = viewportDescription; + } + return viewportDescription; +} + +void* OsvrD3DRenderer::GetEyeTexture(int eye, int buffer) +{ + if (buffer == 0) + { + return (eye == 0 ? s_leftEyeTexturePtr + : s_rightEyeTexturePtr); + } + else + { + return (eye == 0 ? s_leftEyeTexturePtrBuffer2 + : s_rightEyeTexturePtrBuffer2); + } +} + +void OsvrD3DRenderer::OnRenderEvent() +{ + int frame = iterations % numBuffers; + + const auto n = static_cast(numRenderInfo); + // Render into each buffer using the specified information. + for (int i = 0; i < n; ++i) { + + auto context = s_renderInfo[i].library.context; + // Set up to render to the textures for this eye + context->OMSetRenderTargets(1, &frameInfo[frame]->renderBuffers[i].colorBufferView, NULL); + + // copy the updated RenderTexture from Unity to RenderManager colorBuffer + frameInfo[frame]->renderBuffers[i].colorBuffer = reinterpret_cast(GetEyeTexture(i, frame)); + } + // Send the rendered results to the screen + OSVR_RenderManagerPresentState presentState; + if ((OSVR_RETURN_SUCCESS != + osvrRenderManagerStartPresentRenderBuffers(&presentState))) { + DebugLog("[OSVR Rendering Plugin] Could not start presenting render buffers."); + ShutdownRenderManager(); + } + // create normalized cropping viewports for side-by-side rendering to a single render target + std::vector NVCPs; + double fraction = 1.0 / s_renderInfo.size(); + for (size_t i = 0; i < s_renderInfo.size(); i++) { + OSVR_ViewportDescription v; + v.left = fraction * i; + v.lower = 0.0; + v.width = fraction; + v.height = 1; + NVCPs.push_back(v); + } + OSVR_ViewportDescription fullView; + fullView.left = fullView.lower = 0; + fullView.width = fullView.height = 1; + for (size_t i = 0; i < numRenderInfo; i++) { + if ((OSVR_RETURN_SUCCESS != + osvrRenderManagerPresentRenderBufferD3D11( + presentState, frameInfo[frame]->renderBuffers[i], s_renderInfo[i], + fullView))) { + DebugLog("[OSVR Rendering Plugin] Could not present render buffer "); + ShutdownRenderManager(); + } + } + + if ((OSVR_RETURN_SUCCESS != + osvrRenderManagerFinishPresentRenderBuffers( + s_render, presentState, s_renderParams, true))) { + DebugLog("[OSVR Rendering Plugin] Could not finish presenting render buffers"); + ShutdownRenderManager(); + } + + iterations++; +} + +void OsvrD3DRenderer::OnInitializeGraphicsDeviceEvent() +{ + IUnityGraphicsD3D11 *d3d11 = + s_UnityInterfaces->Get(); + + // Put the device and context into a structure to let RenderManager + // know to use this one rather than creating its own. + s_libraryD3D.device = d3d11->GetDevice(); + ID3D11DeviceContext *ctx = nullptr; + s_libraryD3D.device->GetImmediateContext(&ctx); + s_libraryD3D.context = ctx; +} + + +void OsvrD3DRenderer::SetFarClipDistance(double distance) +{ + s_farClipDistance = distance; + +} + +void OsvrD3DRenderer::SetIPD(double ipdMeters) +{ + s_ipd = ipdMeters; + +} + +void OsvrD3DRenderer::SetNearClipDistance(double distance) +{ + s_nearClipDistance = distance; +} +void OsvrD3DRenderer::ShutdownRenderManager() +{ + DebugLog("[OSVR Rendering Plugin] Shutting down RenderManagerD3D."); + if (s_render != nullptr) { + osvrDestroyRenderManager(s_render); + s_render = nullptr; + s_leftEyeTexturePtr = nullptr; + s_leftEyeTexturePtrBuffer2 = nullptr; + s_rightEyeTexturePtr = nullptr; + s_rightEyeTexturePtrBuffer2 = nullptr; + frameInfo.clear(); + } + s_clientContext = nullptr; + +} +#endif + + + diff --git a/OsvrD3DRenderer.h b/OsvrD3DRenderer.h new file mode 100644 index 0000000..d4e10fc --- /dev/null +++ b/OsvrD3DRenderer.h @@ -0,0 +1,90 @@ +/** @file +@brief Header +@date 2017 +@author +Sensics, Inc. + +*/ + +// Copyright 2017 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// D3D- specific includes +// Include headers for the graphics APIs we support +#if SUPPORT_D3D11 +#include + +#include "Unity/IUnityGraphicsD3D11.h" +#include +#include + + +#include "OsvrUnityRenderer.h" + +//D3D Unity Rendering Plugin implementation +class OsvrD3DRenderer : public OsvrUnityRenderer { +public: + OsvrD3DRenderer(); + ~OsvrD3DRenderer(); + virtual OSVR_ReturnCode CreateRenderBuffers(); + virtual OSVR_ReturnCode CreateRenderManager(OSVR_ClientContext context); + virtual OSVR_ReturnCode SetOsvrClientContext(OSVR_ClientContext context); + virtual OSVR_Pose3 GetEyePose(std::uint8_t eye); + virtual OSVR_ProjectionMatrix GetProjectionMatrix(std::uint8_t eye); + virtual OSVR_ViewportDescription GetViewport(std::uint8_t eye); + virtual void OnRenderEvent(); + virtual void OnInitializeGraphicsDeviceEvent(); + virtual void SetFarClipDistance(double distance); + virtual void SetIPD(double ipdMeters); + virtual void SetNearClipDistance(double distance); + virtual void ShutdownRenderManager(); + virtual void UpdateRenderInfo(); + virtual void* GetEyeTexture(int eye, int buffer); + virtual void SetColorBuffer(void *texturePtr, std::uint8_t eye, std::uint8_t buffer); + OSVR_GraphicsLibraryD3D11 s_libraryD3D; + +private: + struct FrameInfoD3D11 { + // Set up the vector of textures to render to and any framebuffer + // we need to group them. + std::vector renderBuffers; + ID3D11Texture2D* depthStencilTexture; + ID3D11DepthStencilView* depthStencilView; + IDXGIKeyedMutex* keyedMutex; + FrameInfoD3D11() : renderBuffers(2) + { + } + + }; + std::vector frameInfo; + OSVR_RenderParams s_renderParams; + OSVR_RenderManager s_render = nullptr; + OSVR_RenderManagerD3D11 s_renderD3D = nullptr; + std::vector s_renderInfo; + std::vector s_lastRenderInfo; + //OSVR_GraphicsLibraryD3D11 s_libraryD3D; + OSVR_RenderInfoCount numRenderInfo; + OSVR_ProjectionMatrix lastGoodProjMatrix; + OSVR_Pose3 lastGoodPose; + OSVR_ViewportDescription lastGoodViewportDescription; + D3D11_TEXTURE2D_DESC s_textureDesc; + void *s_leftEyeTexturePtr = nullptr; + void *s_rightEyeTexturePtr = nullptr; + void *s_leftEyeTexturePtrBuffer2 = nullptr; + void *s_rightEyeTexturePtrBuffer2 = nullptr; + + OSVR_ReturnCode ConstructBuffersD3D11(int eye, int buffer, FrameInfoD3D11* fInfo); + +}; +#endif // SUPPORT_D3D11 diff --git a/OsvrOpenGLRenderer.cpp b/OsvrOpenGLRenderer.cpp new file mode 100644 index 0000000..ca31a44 --- /dev/null +++ b/OsvrOpenGLRenderer.cpp @@ -0,0 +1 @@ +//@todo OpenGL renderer \ No newline at end of file diff --git a/OsvrOpenGLRenderer.h b/OsvrOpenGLRenderer.h new file mode 100644 index 0000000..ca31a44 --- /dev/null +++ b/OsvrOpenGLRenderer.h @@ -0,0 +1 @@ +//@todo OpenGL renderer \ No newline at end of file diff --git a/OsvrRenderingPlugin.cpp b/OsvrRenderingPlugin.cpp index 2816354..fa269a4 100644 --- a/OsvrRenderingPlugin.cpp +++ b/OsvrRenderingPlugin.cpp @@ -21,72 +21,42 @@ Sensics, Inc. // limitations under the License. /// Both of these need to be enabled to force-enable logging to files. -#undef ENABLE_LOGGING -#undef ENABLE_LOGFILE +#define ENABLE_LOGGING 0 +#define ENABLE_LOGFILE 0 // Internal includes #include "OsvrRenderingPlugin.h" #include "Unity/IUnityGraphics.h" #include "UnityRendererType.h" +#include "OsvrUnityRenderer.h" +#include "OsvrD3DRenderer.h" +#include "OsvrAndroidRenderer.h" // Library includes -#include "osvr/RenderKit/RenderManager.h" #include #include #include #include -// standard includes -#if defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) -#include -#include -#endif -#include #if UNITY_WIN #define NO_MINMAX #define WIN32_LEAN_AND_MEAN +// logging on windows +#if defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) +#include +#include +#endif // end define ENABLE_LOGGING +#include #endif -// Include headers for the graphics APIs we support -#if SUPPORT_D3D11 -#include - -#include "Unity/IUnityGraphicsD3D11.h" -#include - -#endif // SUPPORT_D3D11 - -#if SUPPORT_OPENGL -#if UNITY_WIN || UNITY_LINUX -// Needed for render buffer calls. OSVR will have called glewInit() for us -// when we open the display. -#include - -#include - -#include -#include -#else // UNITY_WIN || UNITY_LINUX ^ // v others (mac) // -// Mac OpenGL include -#include -#endif // -#endif // SUPPORT_OPENGL +OSVR_ClientContext gClientContext = NULL; // VARIABLES static IUnityInterfaces *s_UnityInterfaces = nullptr; static IUnityGraphics *s_Graphics = nullptr; static UnityRendererType s_deviceType = {}; -static osvr::renderkit::RenderManager::RenderParams s_renderParams; -static osvr::renderkit::RenderManager *s_render = nullptr; -static OSVR_ClientContext s_clientContext = nullptr; -static std::vector s_renderBuffers; -static std::vector s_renderInfo; -static std::vector s_lastRenderInfo; -static osvr::renderkit::GraphicsLibrary s_library; -static void *s_leftEyeTexturePtr = nullptr; -static void *s_rightEyeTexturePtr = nullptr; /// @todo is this redundant? (given renderParams) static double s_nearClipDistance = 0.1; /// @todo is this redundant? (given renderParams) @@ -94,275 +64,189 @@ static double s_farClipDistance = 1000.0; /// @todo is this redundant? (given renderParams) static double s_ipd = 0.063; +// cached viewport values +static std::uint32_t viewportWidth = 0; +static std::uint32_t viewportHeight = 0; + +static OsvrUnityRenderer* osvrUnityRenderer = nullptr; + + +// logging +#if UNITY_WIN #if defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) static std::ofstream s_debugLogFile; static std::streambuf *s_oldCout = nullptr; static std::streambuf *s_oldCerr = nullptr; #endif // defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) +#endif -// D3D11 vars -#if SUPPORT_D3D11 -static D3D11_TEXTURE2D_DESC s_textureDesc; -#endif // SUPPORT_D3D11 - -// OpenGL vars -#if SUPPORT_OPENGL -GLuint s_frameBuffer; -#endif // SUPPORT_OPENGL // RenderEvents // Called from Unity with GL.IssuePluginEvent enum RenderEvents { - kOsvrEventID_Render = 0, - kOsvrEventID_Shutdown = 1, - kOsvrEventID_Update = 2, - kOsvrEventID_SetRoomRotationUsingHead = 3, - kOsvrEventID_ClearRoomToWorldTransform = 4 + kOsvrEventID_CreateRenderManager = 0, + kOsvrEventID_CreateRenderBuffers = 1, + kOsvrEventID_Update = 2, + kOsvrEventID_Render = 3, + kOsvrEventID_ResetYaw = 4, + kOsvrEventID_SetRoomRotationUsingHead = 5, + kOsvrEventID_ClearRoomToWorldTransform = 6, + kOsvrEventID_Shutdown = 7 }; -// Mutex provides thread safety when accessing s_lastRenderInfo from Unity -std::mutex m_mutex; - // -------------------------------------------------------------------------- // Helper utilities // Allow writing to the Unity debug console from inside DLL land. static DebugFnPtr s_debugLog = nullptr; -void UNITY_INTERFACE_API LinkDebug(DebugFnPtr d) { s_debugLog = d; } +void UNITY_INTERFACE_API LinkDebug(DebugFnPtr d) { + s_debugLog = d; + osvrUnityRenderer->SetDebugLog(d); +} // Only for debugging purposes, as this causes some errors at shutdown inline void DebugLog(const char *str) { +#if UNITY_ANDROID + return;/* + if (androidDebugLogMethodID != nullptr) + { + jstring jstr = jniEnvironment->NewStringUTF(str); + jniEnvironment->CallStaticVoidMethod(osvrJniWrapperClass, + androidDebugLogMethodID, jstr); + } + return;*/ +#else // all platforms besides Android #if !defined(NDEBUG) || defined(ENABLE_LOGGING) - if (s_debugLog != nullptr) { - s_debugLog(str); - } + if (s_debugLog != nullptr) { + s_debugLog(str); + } #endif // !defined(NDEBUG) || defined(ENABLE_LOGGING) #if defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) - if (s_debugLogFile) { - s_debugLogFile << str << std::endl; - } + if (s_debugLogFile) { + s_debugLogFile << str << std::endl; + } #endif // defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) -} - -void UNITY_INTERFACE_API ShutdownRenderManager() { - DebugLog("[OSVR Rendering Plugin] Shutting down RenderManager."); - if (s_render != nullptr) { - delete s_render; - s_render = nullptr; - s_rightEyeTexturePtr = nullptr; - s_leftEyeTexturePtr = nullptr; - } - s_clientContext = nullptr; +#endif // all platforms besides Android } // -------------------------------------------------------------------------- // GraphicsDeviceEvents -#if SUPPORT_D3D11 -// ------------------------------------------------------------------- -/// Direct3D 11 setup/teardown code -inline void DoEventGraphicsDeviceD3D11(UnityGfxDeviceEventType eventType) { - BOOST_ASSERT_MSG( - s_deviceType, - "Should only be able to get in here with a valid device type."); - BOOST_ASSERT_MSG( - s_deviceType.getDeviceTypeEnum() == OSVRSupportedRenderers::D3D11, - "Should only be able to get in here if using D3D11 device type."); - - switch (eventType) { - case kUnityGfxDeviceEventInitialize: { - IUnityGraphicsD3D11 *d3d11 = - s_UnityInterfaces->Get(); - - // Put the device and context into a structure to let RenderManager - // know to use this one rather than creating its own. - s_library.D3D11 = new osvr::renderkit::GraphicsLibraryD3D11; - s_library.D3D11->device = d3d11->GetDevice(); - ID3D11DeviceContext *ctx = nullptr; - s_library.D3D11->device->GetImmediateContext(&ctx); - s_library.D3D11->context = ctx; - DebugLog("[OSVR Rendering Plugin] Passed Unity device/context to " - "RenderManager library."); - break; - } - case kUnityGfxDeviceEventShutdown: { - // Close the Renderer interface cleanly. - // This should be handled in ShutdownRenderManager - /// @todo delete library.D3D11; library.D3D11 = nullptr; ? - break; - } - } -} -#endif // SUPPORT_D3D11 - #if SUPPORT_OPENGL // ------------------------------------------------------------------- /// OpenGL setup/teardown code /// @todo OpenGL path not implemented yet inline void DoEventGraphicsDeviceOpenGL(UnityGfxDeviceEventType eventType) { - BOOST_ASSERT_MSG( - s_deviceType, - "Should only be able to get in here with a valid device type."); - BOOST_ASSERT_MSG( - s_deviceType.getDeviceTypeEnum() == OSVRSupportedRenderers::OpenGL, - "Should only be able to get in here if using OpenGL device type."); - - switch (eventType) { - case kUnityGfxDeviceEventInitialize: - DebugLog("OpenGL Initialize Event"); - break; - case kUnityGfxDeviceEventShutdown: - DebugLog("OpenGL Shutdown Event"); - break; - default: - break; - } + BOOST_ASSERT_MSG( + s_deviceType, + "Should only be able to get in here with a valid device type."); + BOOST_ASSERT_MSG( + s_deviceType.getDeviceTypeEnum() == OSVRSupportedRenderers::OpenGL, + "Should only be able to get in here if using OpenGL device type."); + + switch (eventType) { + case kUnityGfxDeviceEventInitialize: + DebugLog("OpenGL Initialize Event"); + break; + case kUnityGfxDeviceEventShutdown: + DebugLog("OpenGL Shutdown Event"); + break; + default: + break; + } } #endif // SUPPORT_OPENGL -inline void dispatchEventToRenderer(UnityRendererType renderer, - UnityGfxDeviceEventType eventType) { - if (!renderer) { - DebugLog("[OSVR Rendering Plugin] Current device type not supported"); - return; - } - switch (renderer.getDeviceTypeEnum()) { -#if SUPPORT_D3D11 - case OSVRSupportedRenderers::D3D11: - DoEventGraphicsDeviceD3D11(eventType); - break; -#endif -#if SUPPORT_OPENGL - case OSVRSupportedRenderers::OpenGL: - DoEventGraphicsDeviceOpenGL(eventType); - break; -#endif - case OSVRSupportedRenderers::EmptyRenderer: - default: - break; - } -} /// Needs the calling convention, even though it's static and not exported, /// because it's registered as a callback on plugin load. static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType) { - switch (eventType) { - case kUnityGfxDeviceEventInitialize: { - DebugLog( - "[OSVR Rendering Plugin] OnGraphicsDeviceEvent(Initialize).\n"); - s_deviceType = s_Graphics->GetRenderer(); - if (!s_deviceType) { - DebugLog("[OSVR Rendering Plugin] " - "OnGraphicsDeviceEvent(Initialize): New device type is " - "not supported!\n"); - } - break; - } - - case kUnityGfxDeviceEventShutdown: { - DebugLog("[OSVR Rendering Plugin] OnGraphicsDeviceEvent(Shutdown).\n"); - /// Here, we want to dispatch before we reset the device type, so the - /// right device type gets shut down. Thus we return instead of break. - dispatchEventToRenderer(s_deviceType, eventType); - s_deviceType.reset(); - return; - } - - case kUnityGfxDeviceEventBeforeReset: { - DebugLog( - "[OSVR Rendering Plugin] OnGraphicsDeviceEvent(BeforeReset).\n"); - break; - } - - case kUnityGfxDeviceEventAfterReset: { - DebugLog( - "[OSVR Rendering Plugin] OnGraphicsDeviceEvent(AfterReset).\n"); - break; - } - } - - dispatchEventToRenderer(s_deviceType, eventType); + switch (eventType) { + case kUnityGfxDeviceEventInitialize: { + if (osvrUnityRenderer == nullptr) + { +#if SUPPORT_D3D11 + osvrUnityRenderer = new OsvrD3DRenderer(); + IUnityGraphicsD3D11 *d3d11 = + s_UnityInterfaces->Get(); + + OsvrD3DRenderer* d3d = dynamic_cast(osvrUnityRenderer); + // Put the device and context into a structure to let RenderManager + // know to use this one rather than creating its own. + d3d->s_libraryD3D.device = d3d11->GetDevice(); + ID3D11DeviceContext *ctx = nullptr; + d3d->s_libraryD3D.device->GetImmediateContext(&ctx); + d3d->s_libraryD3D.context = ctx; +#elif UNITY_ANDROID + osvrUnityRenderer = new OsvrAndroidRenderer(); + +#endif + } + //osvrUnityRenderer->OnInitializeGraphicsDeviceEvent(); + break; + } + + case kUnityGfxDeviceEventShutdown: { + + return; + } + + case kUnityGfxDeviceEventBeforeReset: { + DebugLog( + "[OSVR Rendering Plugin] OnGraphicsDeviceEvent(BeforeReset).\n"); + break; + } + + case kUnityGfxDeviceEventAfterReset: { + DebugLog( + "[OSVR Rendering Plugin] OnGraphicsDeviceEvent(AfterReset).\n"); + break; + } + } } // -------------------------------------------------------------------------- // UnitySetInterfaces void UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces *unityInterfaces) { +#if UNITY_WIN #if defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) - s_debugLogFile.open("RenderPluginLog.txt"); + s_debugLogFile.open("RenderPluginLog.txt"); - // Capture std::cout and std::cerr from RenderManager. - if (s_debugLogFile) { - s_oldCout = std::cout.rdbuf(); - std::cout.rdbuf(s_debugLogFile.rdbuf()); + // Capture std::cout and std::cerr from RenderManager. + if (s_debugLogFile) { + s_oldCout = std::cout.rdbuf(); + std::cout.rdbuf(s_debugLogFile.rdbuf()); - s_oldCerr = std::cerr.rdbuf(); - std::cerr.rdbuf(s_debugLogFile.rdbuf()); - } + s_oldCerr = std::cerr.rdbuf(); + std::cerr.rdbuf(s_debugLogFile.rdbuf()); + } #endif // defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) - s_UnityInterfaces = unityInterfaces; - s_Graphics = s_UnityInterfaces->Get(); - s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent); +#endif // UNITY_WIN + s_UnityInterfaces = unityInterfaces; + s_Graphics = s_UnityInterfaces->Get(); + s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent); - // Run OnGraphicsDeviceEvent(initialize) manually on plugin load - OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize); + // Run OnGraphicsDeviceEvent(initialize) manually on plugin load + OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize); } void UNITY_INTERFACE_API UnityPluginUnload() { - s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent); - OnGraphicsDeviceEvent(kUnityGfxDeviceEventShutdown); - + s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent); + OnGraphicsDeviceEvent(kUnityGfxDeviceEventShutdown); +#if UNITY_WIN #if defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) - if (s_debugLogFile) { - // Restore the buffers - std::cout.rdbuf(s_oldCout); - std::cerr.rdbuf(s_oldCerr); - s_debugLogFile.close(); - } -#endif // defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) -} - -inline void UpdateRenderInfo() { - std::lock_guard lock(m_mutex); - s_renderInfo = s_render->GetRenderInfo(s_renderParams); - if (s_renderInfo.size() > 0) - { - s_lastRenderInfo = s_renderInfo; + if (s_debugLogFile) { + // Restore the buffers + std::cout.rdbuf(s_oldCout); + std::cerr.rdbuf(s_oldCerr); + s_debugLogFile.close(); } +#endif // defined(ENABLE_LOGGING) && defined(ENABLE_LOGFILE) +#endif // UNITY_WIN } -#if 0 -extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API -UpdateDistortionMesh(float distanceScale[2], float centerOfProjection[2], - float *polynomial, int desiredTriangles = 12800) { - std::vector dp; - osvr::renderkit::RenderManager::DistortionParameters distortion; - distortion.m_desiredTriangles = desiredTriangles; - std::vector Ds; - Ds.push_back(distanceScale[0]); - Ds.push_back(distanceScale[1]); - distortion.m_distortionD = Ds; - std::vector poly; - int len = sizeof(polynomial) / sizeof(int); - for (size_t i = 0; i < len; i++) { - poly.push_back(polynomial[i]); - } - // assume each color is the same for now - distortion.m_distortionPolynomialRed = poly; - distortion.m_distortionPolynomialGreen = poly; - distortion.m_distortionPolynomialBlue = poly; - for (size_t i = 0; i < s_renderInfo.size(); i++) { - std::vector COP = {static_cast(centerOfProjection[0]), - static_cast(centerOfProjection[1])}; - distortion.m_distortionCOP = COP; - dp.push_back(distortion); - } - return s_render->UpdateDistortionMeshes( - osvr::renderkit::RenderManager::DistortionMeshType::SQUARE, dp); -} - -#endif // Updates the internal "room to world" transformation (applied to all // tracker data for this client context instance) based on the user's head @@ -372,334 +256,109 @@ UpdateDistortionMesh(float distanceScale[2], float centerOfProjection[2], // Note that this method internally calls osvrClientUpdate() to get a head pose // so your callbacks may be called during its execution! /// @todo does this actually get called from anywhere or is it dead code? -void SetRoomRotationUsingHead() { s_render->SetRoomRotationUsingHead(); } +void SetRoomRotationUsingHead() { /* s_renderD3D-> SetRoomRotationUsingHead(); + */ +} // Clears/resets the internal "room to world" transformation back to an // identity transformation - that is, clears the effect of any other // manipulation of the room to world transform. /// @todo does this actually get called from anywhere or is it dead code? -void ClearRoomToWorldTransform() { s_render->ClearRoomToWorldTransform(); } +void ClearRoomToWorldTransform() { /*s_render->ClearRoomToWorldTransform(); */ +} + +void UNITY_INTERFACE_API ShutdownRenderManager() { + if (osvrUnityRenderer != nullptr) + { + osvrUnityRenderer->ShutdownRenderManager(); + } +} // Called from Unity to create a RenderManager, passing in a ClientContext OSVR_ReturnCode UNITY_INTERFACE_API CreateRenderManagerFromUnity(OSVR_ClientContext context) { - /// See if we're already created/running - shouldn't happen, but might. - if (s_render != nullptr) { - if (s_render->doingOkay()) { - DebugLog("[OSVR Rendering Plugin] RenderManager already created " - "and doing OK - will just return success without trying " - "to re-initialize."); - return OSVR_RETURN_SUCCESS; - } - - DebugLog("[OSVR Rendering Plugin] RenderManager already created, " - "but not doing OK. Will shut down before creating again."); - ShutdownRenderManager(); - } - if (s_clientContext != nullptr) { - DebugLog( - "[OSVR Rendering Plugin] Client context already set! Replacing..."); - } - s_clientContext = context; - - if (!s_deviceType) { - // @todo pass the platform from Unity - // This is a patch to workaround a bug in Unity where the renderer type - // is not being set on Windows x86 builds. Until the OpenGL path is - // working, it's safe to assume we're using D3D11, but we'd rather get - // the platform from Unity than assume it's D3D11. - - s_deviceType = kUnityGfxRendererD3D11; - - /* DebugLog("[OSVR Rendering Plugin] Attempted to create render manager, " - "but device type wasn't set (to a supported type) by the " - "plugin load/init routine. Order issue?"); - return OSVR_RETURN_FAILURE;*/ - } - - bool setLibraryFromOpenDisplayReturn = false; - /// @todo We should always have a legit value in - /// s_deviceType.getDeviceTypeEnum() at this point, right? - switch (s_deviceType.getDeviceTypeEnum()) { - -#if SUPPORT_D3D11 - case OSVRSupportedRenderers::D3D11: - s_render = osvr::renderkit::createRenderManager(context, "Direct3D11", - s_library); -#ifdef ATTEMPT_D3D_SHARING - setLibraryFromOpenDisplayReturn = true; -#endif // ATTEMPT_D3D_SHARING - break; -#endif // SUPPORT_D3D11 - -#if SUPPORT_OPENGL - case OSVRSupportedRenderers::OpenGL: - s_render = osvr::renderkit::createRenderManager(context, "OpenGL"); - setLibraryFromOpenDisplayReturn = true; - break; -#endif // SUPPORT_OPENGL - } - - if ((s_render == nullptr) || (!s_render->doingOkay())) { - DebugLog("[OSVR Rendering Plugin] Could not create RenderManager"); - - ShutdownRenderManager(); - return OSVR_RETURN_FAILURE; - } - - // Open the display and make sure this worked. - osvr::renderkit::RenderManager::OpenResults ret = s_render->OpenDisplay(); - if (ret.status == osvr::renderkit::RenderManager::OpenStatus::FAILURE) { - DebugLog("[OSVR Rendering Plugin] Could not open display"); - - ShutdownRenderManager(); - return OSVR_RETURN_FAILURE; - } - if (setLibraryFromOpenDisplayReturn) { - // Set our library from the one RenderManager created. - s_library = ret.library; - } - - // create a new set of RenderParams for passing to GetRenderInfo() - s_renderParams = osvr::renderkit::RenderManager::RenderParams(); - UpdateRenderInfo(); - - DebugLog("[OSVR Rendering Plugin] CreateRenderManagerFromUnity Success!"); - return OSVR_RETURN_SUCCESS; -} - -/// Helper function that handles doing the loop of constructing buffers, and -/// returning failure if any of them in the loop return failure. -template -inline OSVR_ReturnCode applyRenderBufferConstructor(const int numBuffers, - F &&bufferConstructor, - G &&bufferCleanup) { - /// If we bail any time before the end, we'll automatically clean up the - /// render buffers with this lambda. - auto cleanupBuffers = osvr::util::finally([&] { - DebugLog("[OSVR Rendering Plugin] Cleaning up render buffers."); - for (auto &rb : s_renderBuffers) { - bufferCleanup(rb); - } - s_renderBuffers.clear(); - DebugLog("[OSVR Rendering Plugin] Render buffer cleanup complete."); - }); - - /// Construct all the buffers as isntructed - for (int i = 0; i < numBuffers; ++i) { - auto ret = bufferConstructor(i); - if (ret != OSVR_RETURN_SUCCESS) { - DebugLog("[OSVR Rendering Plugin] Failed in a buffer constructor!"); - return OSVR_RETURN_FAILURE; - } - } - - /// Register our constructed buffers so that we can use them for - /// presentation. - if (!s_render->RegisterRenderBuffers(s_renderBuffers)) { - DebugLog("RegisterRenderBuffers() returned false, cannot continue"); - return OSVR_RETURN_FAILURE; - } - /// Only if we succeed, do we cancel the cleanup and carry on. - cleanupBuffers.cancel(); - return OSVR_RETURN_SUCCESS; -} + if (osvrUnityRenderer != nullptr) + { + return osvrUnityRenderer->CreateRenderManager(context); + } -#if SUPPORT_OPENGL -inline OSVR_ReturnCode ConstructBuffersOpenGL(int eye) { - // Init glew - glewExperimental = 1u; - /// @todo doesn't rendermanager do this glewInit for us? - GLenum err = glewInit(); - if (err != GLEW_OK) { - DebugLog("glewInit failed, aborting."); - /// @todo shouldn't we return here then? - } - - if (eye == 0) { - // do this once - glGenFramebuffers(1, &s_frameBuffer); - glBindFramebuffer(GL_FRAMEBUFFER, s_frameBuffer); - } - - // The color buffer for this eye. We need to put this into - // a generic structure for the Present function, but we only need - // to fill in the OpenGL portion. - if (eye == 0) // left eye - { - GLuint leftEyeColorBuffer = 0; - glGenRenderbuffers(1, &leftEyeColorBuffer); - osvr::renderkit::RenderBuffer rb; - rb.OpenGL = new osvr::renderkit::RenderBufferOpenGL; - rb.OpenGL->colorBufferName = leftEyeColorBuffer; - s_renderBuffers.push_back(rb); - // "Bind" the newly created texture : all future texture - // functions will modify this texture glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, leftEyeColorBuffer); - - // Give an empty image to OpenGL ( the last "0" means "empty" ) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - static_cast(s_renderInfo[eye].viewport.width), - static_cast(s_renderInfo[eye].viewport.height), 0, - GL_RGB, GL_UNSIGNED_BYTE, &leftEyeColorBuffer); - } else // right eye - { - GLuint rightEyeColorBuffer = 0; - glGenRenderbuffers(1, &rightEyeColorBuffer); - osvr::renderkit::RenderBuffer rb; - rb.OpenGL = new osvr::renderkit::RenderBufferOpenGL; - rb.OpenGL->colorBufferName = rightEyeColorBuffer; - s_renderBuffers.push_back(rb); - // "Bind" the newly created texture : all future texture - // functions will modify this texture glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, rightEyeColorBuffer); - - // Give an empty image to OpenGL ( the last "0" means "empty" ) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - static_cast(s_renderInfo[eye].viewport.width), - static_cast(s_renderInfo[eye].viewport.height), 0, - GL_RGB, GL_UNSIGNED_BYTE, &rightEyeColorBuffer); - } - - // Bilinear filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - return OSVR_RETURN_SUCCESS; + return OSVR_RETURN_SUCCESS; } -inline void CleanupBufferOpenGL(osvr::renderkit::RenderBuffer &rb) { - /// @todo incomplete cleanup - but better than leaking in case of failure. - delete rb.OpenGL; - rb.OpenGL = nullptr; -} -#endif // SUPPORT_OPENGL +OSVR_ReturnCode UNITY_INTERFACE_API +SetOsvrClientContextFromUnity(OSVR_ClientContext context) { + if (osvrUnityRenderer != nullptr) + { + return osvrUnityRenderer->SetOsvrClientContext(context); + } -#if SUPPORT_D3D11 -inline ID3D11Texture2D *GetEyeTextureD3D11(int eye) { - return reinterpret_cast(eye == 0 ? s_leftEyeTexturePtr - : s_rightEyeTexturePtr); + return OSVR_RETURN_SUCCESS; } -inline OSVR_ReturnCode ConstructBuffersD3D11(int eye) { - DebugLog("[OSVR Rendering Plugin] ConstructBuffersD3D11"); - HRESULT hr; - // The color buffer for this eye. We need to put this into - // a generic structure for the Present function, but we only need - // to fill in the Direct3D portion. - // Note that this texture format must be RGBA and unsigned byte, - // so that we can present it to Direct3D for DirectMode. - ID3D11Texture2D *D3DTexture = GetEyeTextureD3D11(eye); - unsigned width = static_cast(s_renderInfo[eye].viewport.width); - unsigned height = static_cast(s_renderInfo[eye].viewport.height); - - D3DTexture->GetDesc(&s_textureDesc); - - // Fill in the resource view for your render texture buffer here - D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc = {}; - // This must match what was created in the texture to be rendered - /// @todo Figure this out by introspection on the texture? - // renderTargetViewDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; - /// @todo Interesting - change this line to DXGI_FORMAT_R8G8B8A8_UNORM_SRGB - /// and not only do you not get direct mode, you get multicolored static on - /// the display. - renderTargetViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - renderTargetViewDesc.Texture2D.MipSlice = 0; - - // Create the render target view. - ID3D11RenderTargetView *renderTargetView = - nullptr; //< Pointer to our render target view - hr = s_renderInfo[eye].library.D3D11->device->CreateRenderTargetView( - D3DTexture, &renderTargetViewDesc, &renderTargetView); - if (FAILED(hr)) { - DebugLog( - "[OSVR Rendering Plugin] Could not create render target for eye"); - return OSVR_RETURN_FAILURE; - } - - // Push the filled-in RenderBuffer onto the stack. - std::unique_ptr rbD3D( - new osvr::renderkit::RenderBufferD3D11); - rbD3D->colorBuffer = D3DTexture; - rbD3D->colorBufferView = renderTargetView; - osvr::renderkit::RenderBuffer rb; - rb.D3D11 = rbD3D.get(); - s_renderBuffers.push_back(rb); - - // OK, we succeeded, must release ownership of that pointer now that it's in - // RenderManager's hands. - rbD3D.release(); - return OSVR_RETURN_SUCCESS; -} +OSVR_ReturnCode UNITY_INTERFACE_API CreateRenderBuffers() { -inline void CleanupBufferD3D11(osvr::renderkit::RenderBuffer &rb) { - delete rb.D3D11; - rb.D3D11 = nullptr; -} -#endif // SUPPORT_D3D11 - -OSVR_ReturnCode UNITY_INTERFACE_API ConstructRenderBuffers() { - if (!s_deviceType) { - DebugLog("Device type not supported."); - return OSVR_RETURN_FAILURE; - } - UpdateRenderInfo(); - - // construct buffers - const int n = static_cast(s_renderInfo.size()); - switch (s_deviceType.getDeviceTypeEnum()) { -#if SUPPORT_D3D11 - case OSVRSupportedRenderers::D3D11: - return applyRenderBufferConstructor(n, ConstructBuffersD3D11, - CleanupBufferD3D11); - break; -#endif -#if SUPPORT_OPENGL - case OSVRSupportedRenderers::OpenGL: - return applyRenderBufferConstructor(n, ConstructBuffersOpenGL, - CleanupBufferOpenGL); - break; -#endif - case OSVRSupportedRenderers::EmptyRenderer: - default: - DebugLog("Device type not supported."); - return OSVR_RETURN_FAILURE; - } + /*if (!s_deviceType) { + DebugLog("[OSVR Rendering Plugin] Device type not supported."); + return OSVR_RETURN_FAILURE; + }*/ + if (osvrUnityRenderer != nullptr) + { + return osvrUnityRenderer->CreateRenderBuffers(); + } + return OSVR_RETURN_FAILURE; } void UNITY_INTERFACE_API SetNearClipDistance(double distance) { - s_nearClipDistance = distance; - s_renderParams.nearClipDistanceMeters = s_nearClipDistance; + if (osvrUnityRenderer != nullptr) + { + osvrUnityRenderer->SetNearClipDistance(distance); + } } void UNITY_INTERFACE_API SetFarClipDistance(double distance) { - s_farClipDistance = distance; - s_renderParams.farClipDistanceMeters = s_farClipDistance; + if (osvrUnityRenderer != nullptr) + { + osvrUnityRenderer->SetFarClipDistance(distance); + } } void UNITY_INTERFACE_API SetIPD(double ipdMeters) { - s_ipd = ipdMeters; - s_renderParams.IPDMeters = s_ipd; + if (osvrUnityRenderer != nullptr) + { + osvrUnityRenderer->SetIPD(ipdMeters); + } } -osvr::renderkit::OSVR_ViewportDescription UNITY_INTERFACE_API -GetViewport(int eye) { - std::lock_guard lock(m_mutex); - return s_lastRenderInfo[eye].viewport; +OSVR_ViewportDescription UNITY_INTERFACE_API GetViewport(std::uint8_t eye) { + + OSVR_ViewportDescription viewportDescription; + if (osvrUnityRenderer != nullptr) + { + return osvrUnityRenderer->GetViewport(eye); + } + return viewportDescription; } -osvr::renderkit::OSVR_ProjectionMatrix UNITY_INTERFACE_API -GetProjectionMatrix(int eye) { - std::lock_guard lock(m_mutex); - return s_lastRenderInfo[eye].projection; +OSVR_ProjectionMatrix UNITY_INTERFACE_API +GetProjectionMatrix(std::uint8_t eye) { + + OSVR_ProjectionMatrix pm; + if (osvrUnityRenderer != nullptr) + { + return osvrUnityRenderer->GetProjectionMatrix(eye); + } + return pm; + } -OSVR_Pose3 UNITY_INTERFACE_API GetEyePose(int eye) { - std::lock_guard lock(m_mutex); - return s_lastRenderInfo[eye].pose; +OSVR_Pose3 UNITY_INTERFACE_API GetEyePose(std::uint8_t eye) { + + OSVR_Pose3 pose; + if (osvrUnityRenderer != nullptr) + { + return osvrUnityRenderer->GetEyePose(eye); + } + return pose; } // -------------------------------------------------------------------------- @@ -715,164 +374,19 @@ OSVR_Pose3 UNITY_INTERFACE_API GetEyePose(int eye) { // to set up needed texture pointers only at initialization time. // For more reference, see: // http://docs.unity3d.com/ScriptReference/Texture.GetNativeTexturePtr.html -int UNITY_INTERFACE_API SetColorBufferFromUnity(void *texturePtr, int eye) { - if (!s_deviceType) { - return OSVR_RETURN_FAILURE; - } - - DebugLog("[OSVR Rendering Plugin] SetColorBufferFromUnity"); - if (eye == 0) { - s_leftEyeTexturePtr = texturePtr; - } else { - s_rightEyeTexturePtr = texturePtr; - } - - return OSVR_RETURN_SUCCESS; -} -#if SUPPORT_D3D11 -// Renders the view from our Unity cameras by copying data at -// Unity.RenderTexture.GetNativeTexturePtr() to RenderManager colorBuffers -void RenderViewD3D11(const osvr::renderkit::RenderInfo &ri, - ID3D11RenderTargetView *renderTargetView, int eyeIndex) { - auto context = ri.library.D3D11->context; - // Set up to render to the textures for this eye - context->OMSetRenderTargets(1, &renderTargetView, NULL); - - // copy the updated RenderTexture from Unity to RenderManager colorBuffer - s_renderBuffers[eyeIndex].D3D11->colorBuffer = GetEyeTextureD3D11(eyeIndex); -} -#endif // SUPPORT_D3D11 - -#if SUPPORT_OPENGL -// Render the world from the specified point of view. -//@todo This is not functional yet. -inline void RenderViewOpenGL( - const osvr::renderkit::RenderInfo &ri, //< Info needed to render - GLuint frameBufferObj, //< Frame buffer object to bind our buffers to - GLuint colorBuffer, //< Color buffer to render into - int eyeIndex) { - // Render to our framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObj); - - // Set color and depth buffers for the frame buffer - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorBuffer, 0); - // glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - // GL_RENDERBUFFER, depthBuffer); - - // Set the list of draw buffers. - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers - - // Always check that our framebuffer is ok - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - DebugLog("RenderView: Incomplete Framebuffer"); - return; - } - - // Set the viewport to cover our entire render texture. - glViewport(0, 0, static_cast(ri.viewport.width), - static_cast(ri.viewport.height)); - - // Set the OpenGL projection matrix - GLdouble projection[16]; - osvr::renderkit::OSVR_Projection_to_OpenGL(projection, ri.projection); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMultMatrixd(projection); - - /// Put the transform into the OpenGL ModelView matrix - GLdouble modelView[16]; - osvr::renderkit::OSVR_PoseState_to_OpenGL(modelView, ri.pose); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glMultMatrixd(modelView); - - // Clear the screen to red and clear depth - glClearColor(1, 0, 0, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // ================================================================= - // This is where we draw our world and hands and any other objects. - // We're in World Space. To find out about where to render objects - // in OSVR spaces (like left/right hand space) we need to query the - // interface and handle the coordinate tranforms ourselves. - - // update native texture from code - glBindTexture(GL_TEXTURE_2D, - s_renderBuffers[eyeIndex].OpenGL->colorBufferName); - int texWidth, texHeight; - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texWidth); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texHeight); - - GLuint glTex = eyeIndex == 0 ? (GLuint)s_leftEyeTexturePtr - : (GLuint)s_rightEyeTexturePtr; - - // unsigned char* data = new unsigned char[texWidth*texHeight * 4]; - // FillTextureFromCode(texWidth, texHeight, texHeight * 4, data); - // glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texWidth, texHeight, GL_RGBA, - // GL_UNSIGNED_BYTE, (GLuint)); - // delete[] data; - // Draw a cube with a 5-meter radius as the room we are floating in. - // draw_cube(5.0); -} -#endif // SUPPORT_OPENGL - -inline void DoRender() { - if (!s_deviceType) { - return; - } - std::lock_guard lock(m_mutex); - const auto n = static_cast(s_lastRenderInfo.size()); - - switch (s_deviceType.getDeviceTypeEnum()) { -#if SUPPORT_D3D11 - case OSVRSupportedRenderers::D3D11: { - // Render into each buffer using the specified information. - for (int i = 0; i < n; ++i) { - RenderViewD3D11(s_lastRenderInfo[i], - s_renderBuffers[i].D3D11->colorBufferView, i); - } - - // Send the rendered results to the screen - // Flip Y because Unity RenderTextures are upside-down on D3D11 - if (!s_render->PresentRenderBuffers( - s_renderBuffers, s_lastRenderInfo, - osvr::renderkit::RenderManager::RenderParams(), - std::vector(), - true)) { - DebugLog("[OSVR Rendering Plugin] PresentRenderBuffers() returned " - "false, maybe because it was asked to quit"); - } - break; - } -#endif // SUPPORT_D3D11 - -#if SUPPORT_OPENGL - case OSVRSupportedRenderers::OpenGL: { - // OpenGL - //@todo OpenGL path is not working yet - // Render into each buffer using the specified information. - - for (int i = 0; i < n; ++i) { - RenderViewOpenGL(s_renderInfo[i], s_frameBuffer, - s_renderBuffers[i].OpenGL->colorBufferName, i); - } - - // Send the rendered results to the screen - if (!s_render->PresentRenderBuffers(s_renderBuffers, s_renderInfo)) { - DebugLog("PresentRenderBuffers() returned false, maybe because " - "it was asked to quit"); - } - break; - } -#endif // SUPPORT_OPENGL - - case OSVRSupportedRenderers::EmptyRenderer: - default: - break; - } +int UNITY_INTERFACE_API SetColorBufferFromUnity(void *texturePtr, + std::uint8_t eye, std::uint8_t buffer) { + /*if (!s_deviceType) { + return OSVR_RETURN_FAILURE; + }*/ + + DebugLog("[OSVR Rendering Plugin] SetColorBufferFromUnity"); + if (osvrUnityRenderer != nullptr) + { + osvrUnityRenderer->SetColorBuffer(texturePtr, eye, buffer); + } + return OSVR_RETURN_SUCCESS; } - // -------------------------------------------------------------------------- // UnityRenderEvent // This will be called for GL.IssuePluginEvent script calls; eventID will @@ -880,35 +394,59 @@ inline void DoRender() { /// @todo does this actually need to be exported? It seems like /// GetRenderEventFunc returning it would be sufficient... void UNITY_INTERFACE_API OnRenderEvent(int eventID) { - // Unknown graphics device type? Do nothing. - if (!s_deviceType) { - return; - } - - switch (eventID) { - // Call the Render loop - case kOsvrEventID_Render: - DoRender(); - break; - case kOsvrEventID_Shutdown: - break; - case kOsvrEventID_Update: - UpdateRenderInfo(); - break; - case kOsvrEventID_SetRoomRotationUsingHead: - SetRoomRotationUsingHead(); - break; - case kOsvrEventID_ClearRoomToWorldTransform: - ClearRoomToWorldTransform(); - break; - default: - break; - } + // Unknown graphics device type? Do nothing. + /*if (!s_deviceType) { + return; + }*/ + + switch (eventID) { + + case kOsvrEventID_CreateRenderManager: + if (osvrUnityRenderer != nullptr) + { + osvrUnityRenderer->CreateRenderManager(nullptr); + } + break; + case kOsvrEventID_CreateRenderBuffers: + if (osvrUnityRenderer != nullptr) + { + osvrUnityRenderer->CreateRenderBuffers(); + } + break; + case kOsvrEventID_Update: + if (osvrUnityRenderer != nullptr) + { + osvrUnityRenderer->UpdateRenderInfo(); + } + break; + case kOsvrEventID_Render: + if (osvrUnityRenderer != nullptr) + { + // Call the Render loop + osvrUnityRenderer->OnRenderEvent(); + } + break; + case kOsvrEventID_ResetYaw: + //@todo + break; + case kOsvrEventID_SetRoomRotationUsingHead: + //@todo + // SetRoomRotationUsingHead(); + break; + case kOsvrEventID_ClearRoomToWorldTransform: + //@todo + // ClearRoomToWorldTransform(); + break; + case kOsvrEventID_Shutdown: + break; + default: + break; + } } // -------------------------------------------------------------------------- // GetRenderEventFunc, a function we export which is used to get a // rendering event callback function. UnityRenderingEvent UNITY_INTERFACE_API GetRenderEventFunc() { - return &OnRenderEvent; + return &OnRenderEvent; } diff --git a/OsvrRenderingPlugin.h b/OsvrRenderingPlugin.h index 25e9687..01243b0 100644 --- a/OsvrRenderingPlugin.h +++ b/OsvrRenderingPlugin.h @@ -26,60 +26,86 @@ Sensics, Inc. #include "Unity/IUnityGraphics.h" #include "Unity/IUnityInterface.h" #include +#include "osvr/RenderKit/RenderManagerC.h" #include #include +#include +#if UNITY_ANDROID +#include +#include +JNIEnv *jniEnvironment = 0; +jclass osvrJniWrapperClass; +jmethodID logMsgId; +jobject unityActivityClassInstance; +const char* OSVR_JNI_CLASS_PATH = "org/osvr/osvrunityjni/OsvrJNIWrapper"; +const char* OSVR_JNI_LOG_METHOD_NAME = "logMsg"; + +jmethodID androidDebugLogMethodID = nullptr; + +// this OnLoad gets called automatically +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + jniEnvironment = 0; + vm->AttachCurrentThread(&jniEnvironment, 0); + return JNI_VERSION_1_6; +} + + +#endif typedef void(UNITY_INTERFACE_API *DebugFnPtr)(const char *); extern "C" { -// No apparent UpdateDistortionMeshes symbol found? + // No apparent UpdateDistortionMeshes symbol found? + + /// @todo These are all the exported symbols, and they all are decorated to use + /// stdcall - yet somehow the managed code refers to some as cdecl. Either those + /// functions are never getting used, or something else is happening there. -/// @todo These are all the exported symbols, and they all are decorated to use -/// stdcall - yet somehow the managed code refers to some as cdecl. Either those -/// functions are never getting used, or something else is happening there. + UNITY_INTERFACE_EXPORT OSVR_ReturnCode UNITY_INTERFACE_API + CreateRenderBuffers(); -UNITY_INTERFACE_EXPORT OSVR_ReturnCode UNITY_INTERFACE_API -ConstructRenderBuffers(); + UNITY_INTERFACE_EXPORT OSVR_ReturnCode UNITY_INTERFACE_API + CreateRenderManagerFromUnity(OSVR_ClientContext context); -UNITY_INTERFACE_EXPORT OSVR_ReturnCode UNITY_INTERFACE_API -CreateRenderManagerFromUnity(OSVR_ClientContext context); + UNITY_INTERFACE_EXPORT OSVR_ReturnCode UNITY_INTERFACE_API + SetOsvrClientContextFromUnity(OSVR_ClientContext context); -UNITY_INTERFACE_EXPORT OSVR_Pose3 UNITY_INTERFACE_API GetEyePose(int eye); + UNITY_INTERFACE_EXPORT OSVR_Pose3 UNITY_INTERFACE_API GetEyePose(std::uint8_t eye); -UNITY_INTERFACE_EXPORT osvr::renderkit::OSVR_ProjectionMatrix - UNITY_INTERFACE_API - GetProjectionMatrix(int eye); + UNITY_INTERFACE_EXPORT OSVR_ProjectionMatrix + UNITY_INTERFACE_API + GetProjectionMatrix(std::uint8_t eye); -UNITY_INTERFACE_EXPORT UnityRenderingEvent UNITY_INTERFACE_API -GetRenderEventFunc(); + UNITY_INTERFACE_EXPORT UnityRenderingEvent UNITY_INTERFACE_API + GetRenderEventFunc(); -UNITY_INTERFACE_EXPORT osvr::renderkit::OSVR_ViewportDescription - UNITY_INTERFACE_API - GetViewport(int eye); + UNITY_INTERFACE_EXPORT OSVR_ViewportDescription + UNITY_INTERFACE_API + GetViewport(std::uint8_t eye); -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API LinkDebug(DebugFnPtr d); + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API LinkDebug(DebugFnPtr d); -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API OnRenderEvent(int eventID); + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API OnRenderEvent(int eventID); -/// @todo should return OSVR_ReturnCode -UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API -SetColorBufferFromUnity(void *texturePtr, int eye); + /// @todo should return OSVR_ReturnCode + UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API + SetColorBufferFromUnity(void *texturePtr, std::uint8_t eye, std::uint8_t buffer); -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API -SetFarClipDistance(double distance); + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API + SetFarClipDistance(double distance); -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetIPD(double ipdMeters); + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetIPD(double ipdMeters); -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API -SetNearClipDistance(double distance); -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API ShutdownRenderManager(); + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API + SetNearClipDistance(double distance); + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API ShutdownRenderManager(); -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API -UnityPluginLoad(IUnityInterfaces *unityInterfaces); + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API + UnityPluginLoad(IUnityInterfaces *unityInterfaces); -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginUnload(); + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginUnload(); -// UpdateDistortionMesh no longer exported - buggy, not used. + // UpdateDistortionMesh no longer exported - buggy, not used. } // extern "C" diff --git a/OsvrUnityRenderer.h b/OsvrUnityRenderer.h new file mode 100644 index 0000000..a57a7b1 --- /dev/null +++ b/OsvrUnityRenderer.h @@ -0,0 +1,129 @@ +/** @file +@brief Header +@date 2017 +@author +Sensics, Inc. + +*/ + +// Copyright 2017 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once +// Internal includes +#include "OsvrRenderingPlugin.h" +#include "Unity/IUnityGraphics.h" +#include "UnityRendererType.h" + +// Library includes +#include +#include +#include +#include + +#include "PluginConfig.h" + +#include "Unity/IUnityGraphics.h" +#include "Unity/IUnityInterface.h" +#include +#include "osvr/RenderKit/RenderManagerC.h" +#include +#include +#include + +//Abstract class for Unity Rendering plugin +//Constains virtual function declarations for render-type-specific sublclasses +class OsvrUnityRenderer { +public: + virtual OSVR_ReturnCode CreateRenderBuffers(){ return OSVR_RETURN_FAILURE; } + virtual OSVR_ReturnCode CreateRenderManager(OSVR_ClientContext context){ return OSVR_RETURN_FAILURE; } + virtual OSVR_ReturnCode SetOsvrClientContext(OSVR_ClientContext context){ return OSVR_RETURN_FAILURE; } + virtual OSVR_Pose3 GetEyePose(std::uint8_t eye) + { + OSVR_Pose3 pose; + return pose; + } + virtual OSVR_ProjectionMatrix GetProjectionMatrix(std::uint8_t eye) + { + OSVR_ProjectionMatrix pm; + return pm; + } + virtual OSVR_ViewportDescription GetViewport(std::uint8_t eye) + { + OSVR_ViewportDescription viewportDescription; + return viewportDescription; + } + virtual void OnRenderEvent(){} + virtual void OnInitializeGraphicsDeviceEvent(){} + virtual void SetFarClipDistance(double distance){} + virtual void SetIPD(double ipdMeters){} + virtual void SetNearClipDistance(double distance){} + virtual void ShutdownRenderManager(){} + virtual void UpdateRenderInfo(){} + virtual void SetColorBuffer(void *texturePtr, std::uint8_t eye, std::uint8_t buffer){} + void SetDebugLog(DebugFnPtr d) + { + s_debugLog = d; + + } + +protected: + OSVR_ClientContext s_clientContext = nullptr; + // logging + DebugFnPtr s_debugLog = nullptr; + OsvrUnityRenderer() + { + + } + + ~OsvrUnityRenderer() + { + + } + void DebugLog(const char *str) + { + if (s_debugLog != nullptr) { + s_debugLog(str); + } + + } + IUnityInterfaces *s_UnityInterfaces = nullptr; + IUnityGraphics *s_Graphics = nullptr; + UnityRendererType s_deviceType = {}; + /// @todo is this redundant? (given renderParams) + double s_nearClipDistance = 0.1; + /// @todo is this redundant? (given renderParams) + double s_farClipDistance = 1000.0; + /// @todo is this redundant? (given renderParams) + double s_ipd = 0.063; + // cached viewport values + std::uint32_t viewportWidth = 0; + std::uint32_t viewportHeight = 0; + + //"double-buffered" swap chain + //alternate buffers every frame + int numBuffers = 2; + int iterations = 0; + + // RenderEvents + // Called from Unity with GL.IssuePluginEvent + enum RenderEvents { + kOsvrEventID_Render = 0, + kOsvrEventID_Shutdown = 1, + kOsvrEventID_Update = 2, + kOsvrEventID_ConstructBuffers = 3, + kOsvrEventID_ClearRoomToWorldTransform = 4 + }; + +}; + diff --git a/PluginConfig.h b/PluginConfig.h index 564dd1b..172806c 100644 --- a/PluginConfig.h +++ b/PluginConfig.h @@ -28,6 +28,8 @@ // Which platform we are on? #ifdef _WIN32 #define UNITY_WIN 1 +#elif defined(__ANDROID__) +#define UNITY_ANDROID 1 #elif defined(__APPLE__) #define UNITY_OSX 1 #elif defined(__linux__) @@ -40,7 +42,7 @@ #if UNITY_WIN #define SUPPORT_D3D11 1 #define SUPPORT_OPENGL 1 -#elif UNITY_OSX || UNITY_LINUX +#elif UNITY_OSX || UNITY_LINUX || UNITY_ANDROID #define SUPPORT_OPENGL 1 #endif diff --git a/Unity/IUnityGraphics.h b/Unity/IUnityGraphics.h index d0347f3..37c12d0 100644 --- a/Unity/IUnityGraphics.h +++ b/Unity/IUnityGraphics.h @@ -15,6 +15,7 @@ typedef enum UnityGfxRenderer kUnityGfxRendererPS4 = 13, // PlayStation 4 kUnityGfxRendererXboxOne = 14, // Xbox One kUnityGfxRendererMetal = 16, // iOS Metal + kUnityGfxRendererOpenGLCore = 17, // Desktop OpenGL core kUnityGfxRendererD3D12 = 18, // Direct3D 12 } UnityGfxRenderer; diff --git a/UnityRendererType.h b/UnityRendererType.h index ca2b57a..ea2e09b 100644 --- a/UnityRendererType.h +++ b/UnityRendererType.h @@ -63,6 +63,9 @@ class UnityRendererType { switch (gfxRenderer) { #if SUPPORT_OPENGL case kUnityGfxRendererOpenGL: + case kUnityGfxRendererOpenGLES20: + case kUnityGfxRendererOpenGLES30: + case kUnityGfxRendererOpenGLCore: renderer_ = OSVRSupportedRenderers::OpenGL; supported_ = true; break; @@ -77,8 +80,6 @@ class UnityRendererType { case kUnityGfxRendererGCM: case kUnityGfxRendererNull: case kUnityGfxRendererXenon: - case kUnityGfxRendererOpenGLES20: - case kUnityGfxRendererOpenGLES30: case kUnityGfxRendererGXM: case kUnityGfxRendererPS4: case kUnityGfxRendererXboxOne: diff --git a/cmake/CMakeBoostHelper.cmake b/cmake/CMakeBoostHelper.cmake new file mode 100644 index 0000000..f52bb13 --- /dev/null +++ b/cmake/CMakeBoostHelper.cmake @@ -0,0 +1,42 @@ +# Help CMake find recent Boost MSVC binaries without manual configuration. +if(MSVC) + if(NOT DEFINED Boost_USE_MULTITHREADED) + set(Boost_USE_MULTITHREADED ON) # Most common ABI + endif() +endif() + +# Function exists solely to introduce a new scope for CMAKE_MODULE_PATH +function(_boosthelper_includehelper) + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") + include(GetMSVCVersion) +endfunction() + +if(MSVC AND (NOT Boost_INCLUDE_DIR OR NOT Boost_LIBRARY_DIR)) + _boosthelper_includehelper() + get_msvc_major_minor_version(_vs_major _vs_minor) + if(CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8) + set(_libdir "lib64-msvc-${_vs_major}.${_vs_minor}") + else() + set(_libdir "lib32-msvc-${_vs_major}.${_vs_minor}") + endif() + + set(_haslibs) + if(EXISTS "c:/local") + # Get all versions, newest first. + file(GLOB _possibilities "c:/local/boost*") + list(REVERSE _possibilities) + foreach(DIR ${_possibilities}) + if(EXISTS "${DIR}/${_libdir}") + list(APPEND _haslibs "${DIR}") + endif() + endforeach() + if(_haslibs) + list(APPEND CMAKE_PREFIX_PATH ${_haslibs}) + find_package(Boost QUIET) + if(Boost_FOUND AND NOT Boost_LIBRARY_DIR) + set(BOOST_ROOT "${Boost_INCLUDE_DIR}" CACHE PATH "") + set(BOOST_LIBRARYDIR "${Boost_INCLUDE_DIR}/${_libdir}" CACHE PATH "") + endif() + endif() + endif() +endif() diff --git a/cmake/CompatibilityVersionFile-BASIC.cmake.in b/cmake/CompatibilityVersionFile-BASIC.cmake.in new file mode 100644 index 0000000..d2b97ba --- /dev/null +++ b/cmake/CompatibilityVersionFile-BASIC.cmake.in @@ -0,0 +1,19 @@ +# will always be the actual version one +# Wrapped in a macro because it's got a return before we want. +macro(_gcvf_version) + @GCVF_PREVIOUS_FILE@ +endmacro() +_gcvf_version() + + +if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "@CMAKE_SYSTEM_NAME@") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (@CMAKE_SYSTEM_NAME@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() +endif() + +if(ANDROID AND NOT ("${ANDROID_ABI}" STREQUAL "@ANDROID_ABI@")) + set(PACKAGE_VERSION "${PACKAGE_VERSION} (Android @ANDROID_ABI@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() +endif() \ No newline at end of file diff --git a/cmake/CompatibilityVersionFile-CXX_ABI.cmake.in b/cmake/CompatibilityVersionFile-CXX_ABI.cmake.in new file mode 100644 index 0000000..f09043d --- /dev/null +++ b/cmake/CompatibilityVersionFile-CXX_ABI.cmake.in @@ -0,0 +1,29 @@ +@GCVF_PREVIOUS_FILE@ + +if(MSVC) + if(NOT "${MSVC_VERSION}" STREQUAL "@MSVC_VERSION@") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (@GCVF_WIN_CXXLAYOUT@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() + endif() +endif() + +macro(_gcvf_compute_cxxabi _var _compilerid _compilerver) + set(${_var}) + if("${_compilerid}" STREQUAL "GNU" AND NOT ("${_compilerver}" STREQUAL "")) + if("${_compilerver}" VER_LESS 5.0) + # This is pre-gcc5, not compatible with post-gcc5 + set(${_var} "g++ < 5.0") + else() + set(${_var} "g++ >= 5.0") + endif() + endif() +endmacro() +_gcvr_compute_cxxabi(_installed_cxx "@CMAKE_CXX_COMPILER_ID@" "@CMAKE_CXX_COMPILER_VERSION@") +_gcvr_compute_cxxabi(_current_cxx "${CMAKE_CXX_COMPILER_ID}" "${CMAKE_CXX_COMPILER_VERSION}") + +# if(NOT "${_installed_cxx}" STREQUAL "${_current_cxx}") +# set(PACKAGE_VERSION "${PACKAGE_VERSION} (${_installed_cxx})") +# set(PACKAGE_VERSION_UNSUITABLE TRUE) +# return() +# endif() diff --git a/cmake/CompatibilityVersionFile-CXX_LAYOUT.cmake.in b/cmake/CompatibilityVersionFile-CXX_LAYOUT.cmake.in new file mode 100644 index 0000000..8f98a08 --- /dev/null +++ b/cmake/CompatibilityVersionFile-CXX_LAYOUT.cmake.in @@ -0,0 +1,16 @@ +@GCVF_PREVIOUS_FILE@ + +set(GCVF_WIN_CXXLAYOUT) +if(MSVC) + set(GCVF_WIN_CXXLAYOUT "MSVC") +elseif(MINGW) + set(GCVF_WIN_CXXLAYOUT "MinGW") +elseif(WIN32) + set(GCVF_WIN_CXXLAYOUT "other") +endif() + +if(NOT "@GCVF_WIN_CXXLAYOUT@" STREQUAL "${GCVF_WIN_CXXLAYOUT}") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (@GCVF_WIN_CXXLAYOUT@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() +endif() diff --git a/cmake/CompatibilityVersionFile-C_ABI.cmake.in b/cmake/CompatibilityVersionFile-C_ABI.cmake.in new file mode 100644 index 0000000..656e90f --- /dev/null +++ b/cmake/CompatibilityVersionFile-C_ABI.cmake.in @@ -0,0 +1,16 @@ +@GCVF_PREVIOUS_FILE@ + +if(NOT ("${CMAKE_C_COMPILER_ABI}" STREQUAL "") AND NOT ("@CMAKE_C_COMPILER_ABI@" STREQUAL "")) + if(NOT "${CMAKE_C_COMPILER_ABI}" STREQUAL "@CMAKE_C_COMPILER_ABI@") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (@CMAKE_C_COMPILER_ABI@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() + endif() +endif() + +if(NOT "${CMAKE_C_COMPILER_TARGET}" STREQUAL "@CMAKE_C_COMPILER_TARGET@") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (@CMAKE_C_COMPILER_TARGET@)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) + return() +endif() +# todo anything for a C ABI beyond just "basic"? \ No newline at end of file diff --git a/cmake/CopyImportedTarget.cmake b/cmake/CopyImportedTarget.cmake new file mode 100644 index 0000000..fed23b4 --- /dev/null +++ b/cmake/CopyImportedTarget.cmake @@ -0,0 +1,32 @@ +# - Copy shared libraries from imported targets to the target build directory +# on Windows during post-build. Install them in all cases. +# +# copy_imported_targets( [ ...]) +# +# install_imported_target( +# +# Copyright Sensics, Inc. 2015. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +function(copy_imported_targets _target) + foreach(_dep ${ARGN}) + if(WIN32) + add_custom_command(TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ $ + COMMENT "Copying required DLL for dependency ${_dep}" + VERBATIM) + endif() + endforeach() +endfunction() + + +function(install_imported_target _dep) + install(FILES $ ${ARGN}) +endfunction() diff --git a/cmake/FindEigen3.cmake b/cmake/FindEigen3.cmake new file mode 100644 index 0000000..9c546a0 --- /dev/null +++ b/cmake/FindEigen3.cmake @@ -0,0 +1,81 @@ +# - Try to find Eigen3 lib +# +# This module supports requiring a minimum version, e.g. you can do +# find_package(Eigen3 3.1.2) +# to require version 3.1.2 or newer of Eigen3. +# +# Once done this will define +# +# EIGEN3_FOUND - system has eigen lib with correct version +# EIGEN3_INCLUDE_DIR - the eigen include directory +# EIGEN3_VERSION - eigen version + +# Copyright (c) 2006, 2007 Montel Laurent, +# Copyright (c) 2008, 2009 Gael Guennebaud, +# Copyright (c) 2009 Benoit Jacob +# Redistribution and use is allowed according to the terms of the 2-clause BSD license. + +if(NOT Eigen3_FIND_VERSION) + if(NOT Eigen3_FIND_VERSION_MAJOR) + set(Eigen3_FIND_VERSION_MAJOR 2) + endif(NOT Eigen3_FIND_VERSION_MAJOR) + if(NOT Eigen3_FIND_VERSION_MINOR) + set(Eigen3_FIND_VERSION_MINOR 91) + endif(NOT Eigen3_FIND_VERSION_MINOR) + if(NOT Eigen3_FIND_VERSION_PATCH) + set(Eigen3_FIND_VERSION_PATCH 0) + endif(NOT Eigen3_FIND_VERSION_PATCH) + + set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") +endif(NOT Eigen3_FIND_VERSION) + +macro(_eigen3_check_version) + file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) + + string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") + set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") + set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") + set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") + + set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) + if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK FALSE) + else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK TRUE) + endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + + if(NOT EIGEN3_VERSION_OK) + + message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " + "but at least version ${Eigen3_FIND_VERSION} is required") + endif(NOT EIGEN3_VERSION_OK) +endmacro(_eigen3_check_version) + +if (EIGEN3_INCLUDE_DIR) + + # in cache already + _eigen3_check_version() + set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) + +else (EIGEN3_INCLUDE_DIR) + + find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library + PATHS + ${CMAKE_INSTALL_PREFIX}/include + ${KDE4_INCLUDE_DIR} + PATH_SUFFIXES eigen3 eigen + ) + + if(EIGEN3_INCLUDE_DIR) + _eigen3_check_version() + endif(EIGEN3_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) + + mark_as_advanced(EIGEN3_INCLUDE_DIR) + +endif(EIGEN3_INCLUDE_DIR) + diff --git a/cmake/FindJsonCpp.cmake b/cmake/FindJsonCpp.cmake index a625647..2f66845 100644 --- a/cmake/FindJsonCpp.cmake +++ b/cmake/FindJsonCpp.cmake @@ -46,10 +46,8 @@ macro(_jsoncpp_check_for_real_jsoncpplib) set(__jsoncpp_have_jsoncpplib FALSE) if(TARGET jsoncpp_lib) get_property(__jsoncpp_lib_type TARGET jsoncpp_lib PROPERTY TYPE) - #message(STATUS "__jsoncpp_lib_type ${__jsoncpp_lib_type}") # We make interface libraries. If an actual config module made it, it would be an imported library. if(NOT __jsoncpp_lib_type STREQUAL "INTERFACE_LIBRARY") - #message("have jsoncpp_lib and we didn't invent it ourselves") set(__jsoncpp_have_jsoncpplib TRUE) endif() endif() @@ -59,106 +57,61 @@ include(FindPackageHandleStandardArgs) # Ensure that if this is TRUE later, it's because we set it. set(JSONCPP_FOUND FALSE) -# See if we find a CMake config file - there is no harm in calling this more than once, -# and we need to call it at least once every CMake invocation to create the original -# imported targets, since those don't stick around like cache variables. +# See if we find a CMake config file. find_package(jsoncpp QUIET NO_MODULE) -if(jsoncpp_FOUND) - # Build a string to help us figure out when to invalidate our cache variables. - # start with where we found jsoncpp - set(__jsoncpp_info_string "[${jsoncpp_DIR}]") - - # part of the string to indicate if we found a real jsoncpp_lib (and what kind) - _jsoncpp_check_for_real_jsoncpplib() - if(__jsoncpp_have_jsoncpplib) - list(APPEND __jsoncpp_info_string "[${__jsoncpp_lib_type}]") - else() - list(APPEND __jsoncpp_info_string "[]") - endif() - # part of the string to indicate if we found jsoncpp_lib_static - if(TARGET jsoncpp_lib_static) - list(APPEND __jsoncpp_info_string "[T]") - else() - list(APPEND __jsoncpp_info_string "[]") - endif() -endif() - - -# If we found something, and it's not the exact same as what we've found before... -# NOTE: The contents of this "if" block update only (internal) cache variables! -# (since this will only get run the first CMake pass that finds jsoncpp or that finds a different/updated install) -if(jsoncpp_FOUND AND NOT __jsoncpp_info_string STREQUAL "${JSONCPP_CACHED_JSONCPP_DIR_DETAILS}") - #message("Updating jsoncpp cache variables! ${__jsoncpp_info_string}") - set(JSONCPP_CACHED_JSONCPP_DIR_DETAILS "${__jsoncpp_info_string}" CACHE INTERNAL "" FORCE) - unset(JSONCPP_IMPORTED_LIBRARY_SHARED) - unset(JSONCPP_IMPORTED_LIBRARY_STATIC) - unset(JSONCPP_IMPORTED_LIBRARY) - unset(JSONCPP_IMPORTED_INCLUDE_DIRS) - unset(JSONCPP_IMPORTED_LIBRARY_IS_SHARED) - - # if(__jsoncpp_have_jsoncpplib) is equivalent to if(TARGET jsoncpp_lib) except it excludes our - # "invented" jsoncpp_lib interface targets, made for convenience purposes after this block. - - if(__jsoncpp_have_jsoncpplib AND TARGET jsoncpp_lib_static) - - # A veritable cache of riches - we have both shared and static! - set(JSONCPP_IMPORTED_LIBRARY_SHARED jsoncpp_lib CACHE INTERNAL "" FORCE) - set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib_static CACHE INTERNAL "" FORCE) - if(WIN32 OR CYGWIN OR MINGW) - # DLL platforms: static library should be default - set(JSONCPP_IMPORTED_LIBRARY ${JSONCPP_IMPORTED_LIBRARY_STATIC} CACHE INTERNAL "" FORCE) +# We will always try first to get a config file. +if(NOT JSONCPP_IMPORTED_LIBRARY) + if(jsoncpp_FOUND) + # OK, so we found something. + unset(JSONCPP_IMPORTED_LIBRARY_IS_SHARED) + _jsoncpp_check_for_real_jsoncpplib() + if(__jsoncpp_have_jsoncpplib AND TARGET jsoncpp_lib_static) + # A veritable cache of riches - we have both shared and static! + set(JSONCPP_IMPORTED_LIBRARY_SHARED jsoncpp_lib CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib_static CACHE INTERNAL "" FORCE) + if(WIN32 OR CYGWIN OR MINGW) + # DLL platforms: static library should be default + set(JSONCPP_IMPORTED_LIBRARY ${JSONCPP_IMPORTED_LIBRARY_STATIC} CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED FALSE CACHE INTERNAL "" FORCE) + else() + # Other platforms - might require PIC to be linked into shared libraries, so safest to prefer shared. + set(JSONCPP_IMPORTED_LIBRARY ${JSONCPP_IMPORTED_LIBRARY_SHARED} CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED TRUE CACHE INTERNAL "" FORCE) + endif() + elseif(TARGET jsoncpp_lib_static) + # Well, only one variant, but we know for sure that it's static. + set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib_static CACHE INTERNAL "" FORCE) + set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib_static CACHE INTERNAL "" FORCE) set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED FALSE CACHE INTERNAL "" FORCE) - else() - # Other platforms - might require PIC to be linked into shared libraries, so safest to prefer shared. - set(JSONCPP_IMPORTED_LIBRARY ${JSONCPP_IMPORTED_LIBRARY_SHARED} CACHE INTERNAL "" FORCE) - set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED TRUE CACHE INTERNAL "" FORCE) + elseif(TARGET __jsoncpp_have_jsoncpplib) + # One variant, and we have no idea if this is just an old version or if + # this is shared based on the target name alone. Hmm. + # TODO figure out if this is shared or static? + set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib CACHE INTERNAL "" FORCE) endif() - elseif(TARGET jsoncpp_lib_static) - # Well, only one variant, but we know for sure that it's static. - set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib_static CACHE INTERNAL "" FORCE) - set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib_static CACHE INTERNAL "" FORCE) - set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED FALSE CACHE INTERNAL "" FORCE) - - elseif(__jsoncpp_have_jsoncpplib AND __jsoncpp_lib_type STREQUAL "STATIC_LIBRARY") - # We were able to figure out the mystery library is static! - set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib CACHE INTERNAL "" FORCE) - set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib CACHE INTERNAL "" FORCE) - set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED FALSE CACHE INTERNAL "" FORCE) - - elseif(__jsoncpp_have_jsoncpplib AND __jsoncpp_lib_type STREQUAL "SHARED_LIBRARY") - # We were able to figure out the mystery library is shared! - set(JSONCPP_IMPORTED_LIBRARY_SHARED jsoncpp_lib CACHE INTERNAL "" FORCE) - set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib CACHE INTERNAL "" FORCE) - set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED TRUE CACHE INTERNAL "" FORCE) - - elseif(__jsoncpp_have_jsoncpplib) - # One variant, and we have no idea if this is just an old version or if - # this is shared based on the target name alone. Hmm. - set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib CACHE INTERNAL "" FORCE) - endif() - - # Now, we need include directories. Can't just limit this to old CMakes, since - # new CMakes might be used to build projects designed to support older ones. - if(__jsoncpp_have_jsoncpplib) - get_property(__jsoncpp_interface_include_dirs TARGET jsoncpp_lib PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - if(__jsoncpp_interface_include_dirs) - set(JSONCPP_IMPORTED_INCLUDE_DIRS "${__jsoncpp_interface_include_dirs}" CACHE INTERNAL "" FORCE) + # Now, we need include directories. Can't just limit this to old CMakes, since + # new CMakes might be used to build projects designed to support older ones. + if(__jsoncpp_have_jsoncpplib) + get_property(__jsoncpp_interface_include_dirs TARGET jsoncpp_lib PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + if(__jsoncpp_interface_include_dirs) + set(JSONCPP_IMPORTED_INCLUDE_DIRS "${__jsoncpp_interface_include_dirs}" CACHE INTERNAL "" FORCE) + endif() endif() - endif() - if(TARGET jsoncpp_lib_static AND NOT JSONCPP_IMPORTED_INCLUDE_DIRS) - get_property(__jsoncpp_interface_include_dirs TARGET jsoncpp_lib_static PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - if(__jsoncpp_interface_include_dirs) - set(JSONCPP_IMPORTED_INCLUDE_DIRS "${__jsoncpp_interface_include_dirs}" CACHE INTERNAL "" FORCE) + if(TARGET jsoncpp_lib_static AND NOT JSONCPP_IMPORTED_INCLUDE_DIRS) + get_property(__jsoncpp_interface_include_dirs TARGET jsoncpp_lib_static PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + if(__jsoncpp_interface_include_dirs) + set(JSONCPP_IMPORTED_INCLUDE_DIRS "${__jsoncpp_interface_include_dirs}" CACHE INTERNAL "" FORCE) + endif() endif() - endif() -endif() -# As a convenience... -if(TARGET jsoncpp_lib_static AND NOT TARGET jsoncpp_lib) - add_library(jsoncpp_lib INTERFACE) - target_link_libraries(jsoncpp_lib INTERFACE jsoncpp_lib_static) + # As a convenience... + if(TARGET jsoncpp_lib_static AND NOT TARGET jsoncpp_lib) + add_library(jsoncpp_lib INTERFACE) + target_link_libraries(jsoncpp_lib INTERFACE jsoncpp_lib_static) + endif() + endif() endif() if(JSONCPP_IMPORTED_LIBRARY) @@ -193,7 +146,6 @@ if(JSONCPP_IMPORTED_LIBRARY) find_package_handle_standard_args(JsonCpp DEFAULT_MSG - jsoncpp_DIR JSONCPP_IMPORTED_LIBRARY JSONCPP_IMPORTED_INCLUDE_DIRS) endif() @@ -221,14 +173,6 @@ if(JSONCPP_FOUND) INTERFACE_INCLUDE_DIRECTORIES "${JSONCPP_IMPORTED_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${JSONCPP_IMPORTED_LIBRARY_STATIC}") endif() - - # Hide the stuff we didn't, and no longer, need. - if(NOT JsonCpp_LIBRARY) - unset(JsonCpp_LIBRARY CACHE) - endif() - if(NOT JsonCpp_INCLUDE_DIR) - unset(JsonCpp_INCLUDE_DIR CACHE) - endif() endif() set(JSONCPP_LIBRARY ${JSONCPP_IMPORTED_LIBRARY}) @@ -364,9 +308,10 @@ if(NOT JSONCPP_FOUND) add_library(JsonCpp::JsonCpp ALIAS jsoncpp_interface) endif() endif() + mark_as_advanced(JsonCpp_INCLUDE_DIR JsonCpp_LIBRARY) endif() endif() if(JSONCPP_FOUND) - mark_as_advanced(jsoncpp_DIR JsonCpp_INCLUDE_DIR JsonCpp_LIBRARY) + mark_as_advanced(jsoncpp_DIR) endif() diff --git a/cmake/FindOpenGLES2.cmake b/cmake/FindOpenGLES2.cmake new file mode 100644 index 0000000..c9307b7 --- /dev/null +++ b/cmake/FindOpenGLES2.cmake @@ -0,0 +1,31 @@ +# - Find OpenGLES2 +# Find the native OpenGLES2 includes and libraries +# +# OPENGLES2_INCLUDE_DIR - where to find GLES2/gl2.h, etc. +# OPENGLES2_LIBRARIES - List of libraries when using OpenGLES2. +# OPENGLES2_FOUND - True if OpenGLES2 found. + +# Downloaded from +# https://sourceforge.net/p/alleg/allegro/ci/5.1/tree/cmake/FindOpenGLES.cmake +# Modified to use the v2 library rather than the v1 library. + +if(OPENGLES2_INCLUDE_DIR) + # Already in cache, be silent + set(OPENGLES2_FIND_QUIETLY TRUE) +endif(OPENGLES2_INCLUDE_DIR) + +find_path(OPENGLES2_INCLUDE_DIR GLES2/gl2.h) + +find_library(OPENGLES2_gl_LIBRARY NAMES GLESv2) + +# Handle the QUIETLY and REQUIRED arguments and set OPENGLES_FOUND +# to TRUE if all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(OPENGLES2 DEFAULT_MSG + OPENGLES2_INCLUDE_DIR OPENGLES2_gl_LIBRARY) + +set(OPENGLES2_LIBRARIES ${OPENGLES2_gl_LIBRARY}) + +mark_as_advanced(OPENGLES2_INCLUDE_DIR) +mark_as_advanced(OPENGLES2_gl_LIBRARY) + diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index f69c68a..9a35dbf 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -16,25 +16,18 @@ # Set up architectures (for windows) and prefixes (for mingw builds) if(WIN32) - if(MINGW) - include(MinGWSearchPathExtras OPTIONAL) - if(MINGWSEARCH_TARGET_TRIPLE) - set(SDL2_PREFIX ${MINGWSEARCH_TARGET_TRIPLE}) - endif() - endif() if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(SDL2_LIB_PATH_SUFFIX lib/x64) - if(NOT MSVC AND NOT SDL2_PREFIX) + if(NOT MSVC) set(SDL2_PREFIX x86_64-w64-mingw32) endif() else() set(SDL2_LIB_PATH_SUFFIX lib/x86) - if(NOT MSVC AND NOT SDL2_PREFIX) + if(NOT MSVC) set(SDL2_PREFIX i686-w64-mingw32) endif() endif() endif() - if(SDL2_PREFIX) set(SDL2_ORIGPREFIXPATH ${CMAKE_PREFIX_PATH}) if(SDL2_ROOT_DIR) @@ -45,9 +38,6 @@ if(SDL2_PREFIX) list(APPEND CMAKE_PREFIX_PATH "${_prefix}/${SDL2_PREFIX}") endforeach() endif() - if(MINGWSEARCH_PREFIXES) - list(APPEND CMAKE_PREFIX_PATH ${MINGWSEARCH_PREFIXES}) - endif() endif() # Invoke pkgconfig for hints @@ -192,15 +182,15 @@ if(SDL2_FOUND) ) endif() - if(APPLE) - # Need Cocoa here, is always a framework - find_library(SDL2_COCOA_LIBRARY Cocoa) - list(APPEND SDL2_EXTRA_REQUIRED SDL2_COCOA_LIBRARY) - if(SDL2_COCOA_LIBRARY) - set_target_properties(SDL2::SDL2 PROPERTIES - IMPORTED_LINK_INTERFACE_LIBRARIES ${SDL2_COCOA_LIBRARY}) - endif() - endif() + if(APPLE) + # Need Cocoa here, is always a framework + find_library(SDL2_COCOA_LIBRARY Cocoa) + list(APPEND SDL2_EXTRA_REQUIRED SDL2_COCOA_LIBRARY) + if(SDL2_COCOA_LIBRARY) + set_target_properties(SDL2::SDL2 PROPERTIES + IMPORTED_LINK_INTERFACE_LIBRARIES ${SDL2_COCOA_LIBRARY}) + endif() + endif() # Compute what to do with SDL2main @@ -211,7 +201,7 @@ if(SDL2_FOUND) set_target_properties(SDL2::SDL2main_real PROPERTIES IMPORTED_LOCATION "${SDL2_SDLMAIN_LIBRARY}") - set(SDL2MAIN_LIBRARIES SDL2::SDL2main_real ${SDL2MAIN_LIBRARIES}) + list(APPEND SDL2MAIN_LIBRARIES SDL2::SDL2main_real) endif() if(MINGW) # MinGW requires some additional libraries to appear earlier in the link line. diff --git a/cmake/FindVRPN.cmake b/cmake/FindVRPN.cmake new file mode 100644 index 0000000..641b62b --- /dev/null +++ b/cmake/FindVRPN.cmake @@ -0,0 +1,156 @@ +# - try to find VRPN library +# +# Cache Variables: +# VRPN_LIBRARY +# VRPN_SERVER_LIBRARY +# VRPN_INCLUDE_DIR +# +# Non-cache variables you might use in your CMakeLists.txt: +# VRPN_FOUND +# VRPN_SERVER_LIBRARIES - server libraries +# VRPN_LIBRARIES - client libraries +# VRPN_CLIENT_DEFINITIONS - definitions if you only use the client library +# VRPN_DEFINITIONS - Client-only definition if all we found was the client library. +# VRPN_INCLUDE_DIRS +# +# VRPN_ROOT_DIR is searched preferentially for these files +# +# Requires these CMake modules: +# FindPackageHandleStandardArgs (known included with CMake >=2.6.2) +# +# Original Author: +# 2009-2012 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(VRPN_ROOT_DIR + "${VRPN_ROOT_DIR}" + CACHE + PATH + "Root directory to search for VRPN") + +if("${CMAKE_SIZEOF_VOID_P}" MATCHES "8") + set(_libsuffixes lib64 lib) + + # 64-bit dir: only set on win64 + file(TO_CMAKE_PATH "$ENV{ProgramW6432}" _progfiles) +else() + set(_libsuffixes lib) + set(_PF86 "ProgramFiles(x86)") + if(NOT "$ENV{${_PF86}}" STREQUAL "") + # 32-bit dir: only set on win64 + file(TO_CMAKE_PATH "$ENV{${_PF86}}" _progfiles) + else() + # 32-bit dir on win32, useless to us on win64 + file(TO_CMAKE_PATH "$ENV{ProgramFiles}" _progfiles) + endif() +endif() + +set(_vrpn_quiet) +if(VRPN_FIND_QUIETLY) + set(_vrpn_quiet QUIET) +endif() + +### +# Configure VRPN +### + +find_path(VRPN_INCLUDE_DIR + NAMES + vrpn_Connection.h + PATH_SUFFIXES + include + include/vrpn + HINTS + "${VRPN_ROOT_DIR}" + PATHS + "${_progfiles}/VRPN" + C:/usr/local + /usr/local) + +find_library(VRPN_LIBRARY + NAMES + vrpn + PATH_SUFFIXES + ${_libsuffixes} + HINTS + "${VRPN_ROOT_DIR}" + PATHS + "${_progfiles}/VRPN" + C:/usr/local + /usr/local) + +find_library(VRPN_SERVER_LIBRARY + NAMES + vrpnserver + PATH_SUFFIXES + ${_libsuffixes} + HINTS + "${VRPN_ROOT_DIR}" + PATHS + "${_progfiles}/VRPN" + C:/usr/local + /usr/local) + +### +# Dependencies +### +set(_deps_libs) +set(_deps_includes) +set(_deps_check) + +find_package(quatlib ${_vrpn_quiet}) +list(APPEND _deps_libs ${QUATLIB_LIBRARIES}) +list(APPEND _deps_includes ${QUATLIB_INCLUDE_DIRS}) +list(APPEND _deps_check QUATLIB_FOUND) + +if(NOT WIN32) + find_package(Threads ${_vrpn_quiet}) + list(APPEND _deps_libs ${CMAKE_THREAD_LIBS_INIT}) + list(APPEND _deps_check CMAKE_HAVE_THREADS_LIBRARY) +endif() + +if(WIN32) + find_package(Libusb1 QUIET) + if(LIBUSB1_FOUND) + list(APPEND _deps_libs ${LIBUSB1_LIBRARIES}) + list(APPEND _deps_includes ${LIBUSB1_INCLUDE_DIRS}) + endif() +endif() + + +# handle the QUIETLY and REQUIRED arguments and set xxx_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(VRPN + DEFAULT_MSG + VRPN_LIBRARY + VRPN_INCLUDE_DIR + ${_deps_check}) + +if(VRPN_FOUND) + set(VRPN_INCLUDE_DIRS "${VRPN_INCLUDE_DIR}" ${_deps_includes}) + set(VRPN_LIBRARIES "${VRPN_LIBRARY}" ${_deps_libs}) + set(VRPN_SERVER_LIBRARIES "${VRPN_SERVER_LIBRARY}" ${_deps_libs}) + + if(VRPN_LIBRARY) + set(VRPN_CLIENT_DEFINITIONS -DVRPN_CLIENT_ONLY) + else() + unset(VRPN_CLIENT_DEFINITIONS) + endif() + + if(VRPN_LIBRARY AND NOT VRPN_SERVER_LIBRARY) + set(VRPN_DEFINITIONS -DVRPN_CLIENT_ONLY) + else() + unset(VRPN_DEFINITIONS) + endif() + + mark_as_advanced(VRPN_ROOT_DIR) +endif() + +mark_as_advanced(VRPN_LIBRARY VRPN_SERVER_LIBRARY VRPN_INCLUDE_DIR) diff --git a/cmake/FindWindowsSDK.cmake b/cmake/FindWindowsSDK.cmake new file mode 100644 index 0000000..17d9342 --- /dev/null +++ b/cmake/FindWindowsSDK.cmake @@ -0,0 +1,585 @@ +# - Find the Windows SDK aka Platform SDK +# +# Relevant Wikipedia article: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK +# +# Pass "COMPONENTS tools" to ignore Visual Studio version checks: in case +# you just want the tool binaries to run, rather than the libraries and headers +# for compiling. +# +# Variables: +# WINDOWSSDK_FOUND - if any version of the windows or platform SDK was found that is usable with the current version of visual studio +# WINDOWSSDK_LATEST_DIR +# WINDOWSSDK_LATEST_NAME +# WINDOWSSDK_FOUND_PREFERENCE - if we found an entry indicating a "preferred" SDK listed for this visual studio version +# WINDOWSSDK_PREFERRED_DIR +# WINDOWSSDK_PREFERRED_NAME +# +# WINDOWSSDK_DIRS - contains no duplicates, ordered most recent first. +# WINDOWSSDK_PREFERRED_FIRST_DIRS - contains no duplicates, ordered with preferred first, followed by the rest in descending recency +# +# Functions: +# windowssdk_name_lookup( ) - Find the name corresponding with the SDK directory you pass in, or +# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work. +# +# windowssdk_build_lookup( ) - Find the build version number corresponding with the SDK directory you pass in, or +# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work. +# +# get_windowssdk_from_component( ) - Given a library or include dir, +# find the Windows SDK root dir corresponding to it, or NOTFOUND if unrecognized. +# +# get_windowssdk_library_dirs( ) - Find the architecture-appropriate +# library directories corresponding to the SDK directory you pass in (or NOTFOUND if none) +# +# get_windowssdk_include_dirs( ) - Find the +# include directories corresponding to the SDK directory you pass in (or NOTFOUND if none) +# +# Requires these CMake modules: +# FindPackageHandleStandardArgs (known included with CMake >=2.6.2) +# +# Original Author: +# 2012 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(_preferred_sdk_dirs) # pre-output +set(_win_sdk_dirs) # pre-output +set(_win_sdk_versanddirs) # pre-output +set(_win_sdk_buildsanddirs) # pre-output +set(_winsdk_vistaonly) # search parameters +set(_winsdk_kits) # search parameters + + +set(_WINDOWSSDK_ANNOUNCE OFF) +if(NOT WINDOWSSDK_FOUND AND (NOT WindowsSDK_FIND_QUIETLY)) + set(_WINDOWSSDK_ANNOUNCE ON) +endif() +macro(_winsdk_announce) + if(_WINSDK_ANNOUNCE) + message(STATUS ${ARGN}) + endif() +endmacro() + +set(_winsdk_win10vers + 10.0.10586.0 # TH2 aka Win10 1511 + 10.0.10240.0 # Win10 RTM + 10.0.10150.0 # just ucrt + 10.0.10056.0 +) + +if(WindowsSDK_FIND_COMPONENTS MATCHES "tools") + set(_WINDOWSSDK_IGNOREMSVC ON) + _winsdk_announce("Checking for tools from Windows/Platform SDKs...") +else() + set(_WINDOWSSDK_IGNOREMSVC OFF) + _winsdk_announce("Checking for Windows/Platform SDKs...") +endif() + +# Appends to the three main pre-output lists used only if the path exists +# and is not already in the list. +function(_winsdk_conditional_append _vername _build _path) + if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}")) + # Path invalid - do not add + return() + endif() + list(FIND _win_sdk_dirs "${_path}" _win_sdk_idx) + if(_win_sdk_idx GREATER -1) + # Path already in list - do not add + return() + endif() + _winsdk_announce( " - ${_vername}, Build ${_build} @ ${_path}") + # Not yet in the list, so we'll add it + list(APPEND _win_sdk_dirs "${_path}") + set(_win_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE) + list(APPEND + _win_sdk_versanddirs + "${_vername}" + "${_path}") + set(_win_sdk_versanddirs "${_win_sdk_versanddirs}" CACHE INTERNAL "" FORCE) + list(APPEND + _win_sdk_buildsanddirs + "${_build}" + "${_path}") + set(_win_sdk_buildsanddirs "${_win_sdk_buildsanddirs}" CACHE INTERNAL "" FORCE) +endfunction() + +# Appends to the "preferred SDK" lists only if the path exists +function(_winsdk_conditional_append_preferred _info _path) + if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}")) + # Path invalid - do not add + return() + endif() + + get_filename_component(_path "${_path}" ABSOLUTE) + + list(FIND _win_sdk_preferred_sdk_dirs "${_path}" _win_sdk_idx) + if(_win_sdk_idx GREATER -1) + # Path already in list - do not add + return() + endif() + _winsdk_announce( " - Found \"preferred\" SDK ${_info} @ ${_path}") + # Not yet in the list, so we'll add it + list(APPEND _win_sdk_preferred_sdk_dirs "${_path}") + set(_win_sdk_preferred_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE) + + # Just in case we somehow missed it: + _winsdk_conditional_append("${_info}" "" "${_path}") +endfunction() + +# Given a version like v7.0A, looks for an SDK in the registry under "Microsoft SDKs". +# If the given version might be in both HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows +# and HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots aka "Windows Kits", +# use this macro first, since these registry keys usually have more information. +# +# Pass a "default" build number as an extra argument in case we can't find it. +function(_winsdk_check_microsoft_sdks_registry _winsdkver) + set(SDKKEY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver}") + get_filename_component(_sdkdir + "[${SDKKEY};InstallationFolder]" + ABSOLUTE) + + set(_sdkname "Windows SDK ${_winsdkver}") + + # Default build number passed as extra argument + set(_build ${ARGN}) + # See if the registry holds a Microsoft-mutilated, err, designated, product name + # (just using get_filename_component to execute the registry lookup) + get_filename_component(_sdkproductname + "[${SDKKEY};ProductName]" + NAME) + if(NOT "${_sdkproductname}" MATCHES "registry") + # Got a product name + set(_sdkname "${_sdkname} (${_sdkproductname})") + endif() + + # try for a version to augment our name + # (just using get_filename_component to execute the registry lookup) + get_filename_component(_sdkver + "[${SDKKEY};ProductVersion]" + NAME) + if(NOT "${_sdkver}" MATCHES "registry" AND NOT MATCHES) + # Got a version + if(NOT "${_sdkver}" MATCHES "\\.\\.") + # and it's not an invalid one with two dots in it: + # use to override the default build + set(_build ${_sdkver}) + if(NOT "${_sdkname}" MATCHES "${_sdkver}") + # Got a version that's not already in the name, let's use it to improve our name. + set(_sdkname "${_sdkname} (${_sdkver})") + endif() + endif() + endif() + _winsdk_conditional_append("${_sdkname}" "${_build}" "${_sdkdir}") +endfunction() + +# Given a name for identification purposes, the build number, and a key (technically a "value name") +# corresponding to a Windows SDK packaged as a "Windows Kit", look for it +# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots +# Note that the key or "value name" tends to be something weird like KitsRoot81 - +# no easy way to predict, just have to observe them in the wild. +# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these: +# sometimes you get keys in both parts of the registry (in the wow64 portion especially), +# and the non-"Windows Kits" location is often more descriptive. +function(_winsdk_check_windows_kits_registry _winkit_name _winkit_build _winkit_key) + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;${_winkit_key}]" + ABSOLUTE) + _winsdk_conditional_append("${_winkit_name}" "${_winkit_build}" "${_sdkdir}") +endfunction() + +# Given a name for identification purposes and the build number +# corresponding to a Windows 10 SDK packaged as a "Windows Kit", look for it +# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots +# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these: +# sometimes you get keys in both parts of the registry (in the wow64 portion especially), +# and the non-"Windows Kits" location is often more descriptive. +function(_winsdk_check_win10_kits _winkit_build) + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" + ABSOLUTE) + if(("${_sdkdir}" MATCHES "registry") OR (NOT EXISTS "${_sdkdir}")) + return() # not found + endif() + if(EXISTS "${_sdkdir}/Include/${_winkit_build}/um") + _winsdk_conditional_append("Windows Kits 10 (Build ${_winkit_build})" "${_winkit_build}" "${_sdkdir}") + endif() +endfunction() + +# Given a name for indentification purposes, the build number, and the associated package GUID, +# look in the registry under both HKLM and HKCU in \\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\ +# for that guid and the SDK it points to. +function(_winsdk_check_platformsdk_registry _platformsdkname _build _platformsdkguid) + foreach(_winsdk_hive HKEY_LOCAL_MACHINE HKEY_CURRENT_USER) + get_filename_component(_sdkdir + "[${_winsdk_hive}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]" + ABSOLUTE) + _winsdk_conditional_append("${_platformsdkname} (${_build})" "${_build}" "${_sdkdir}") + endforeach() +endfunction() + +### +# Detect toolchain information: to know whether it's OK to use Vista+ only SDKs +### +set(_winsdk_vistaonly_ok OFF) +if(MSVC AND NOT _WINDOWSSDK_IGNOREMSVC) + # VC 10 and older has broad target support + if(MSVC_VERSION LESS 1700) + # VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+ + elseif("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp") + # This is the XP-compatible v110+ toolset + elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100" OR "${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v90") + # This is the VS2010/VS2008 toolset + else() + # OK, we're VC11 or newer and not using a backlevel or XP-compatible toolset. + # These versions have no XP (and possibly Vista pre-SP1) support + set(_winsdk_vistaonly_ok ON) + if(_WINDOWSSDK_ANNOUNCE AND NOT WINDOWSSDK_DIRS) + message(STATUS "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!") + endif() + endif() +endif() +if(_WINDOWSSDK_IGNOREMSVC) + set(_winsdk_vistaonly_ok ON) +endif() + +### +# MSVC version checks - keeps messy conditionals in one place +# (messy because of _WINDOWSSDK_IGNOREMSVC) +### +set(_winsdk_msvc_greater_1200 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1200))) + set(_winsdk_msvc_greater_1200 ON) +endif() +# Newer than VS .NET/VS Toolkit 2003 +set(_winsdk_msvc_greater_1310 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1310))) + set(_winsdk_msvc_greater_1310 ON) +endif() + +# VS2005/2008 +set(_winsdk_msvc_less_1600 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION LESS 1600))) + set(_winsdk_msvc_less_1600 ON) +endif() + +# VS2013+ +set(_winsdk_msvc_not_less_1800 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (NOT MSVC_VERSION LESS 1800))) + set(_winsdk_msvc_not_less_1800 ON) +endif() + +### +# START body of find module +### +if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003 + ### + # Look for "preferred" SDKs + ### + + # Environment variable for SDK dir + if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL "")) + _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}") + endif() + + if(_winsdk_msvc_less_1600) + # Per-user current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}") + + # System-wide current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}") + endif() + + ### + # Begin the massive list of SDK searching! + ### + if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800) + # These require at least Visual Studio 2013 (VC12) + + _winsdk_check_microsoft_sdks_registry(v10.0A) + + # Windows Software Development Kit (SDK) for Windows 10 + # Several different versions living in the same directory - if nothing else we can assume RTM (10240) + _winsdk_check_microsoft_sdks_registry(v10.0 10.0.10240.0) + foreach(_win10build ${_winsdk_win10vers}) + _winsdk_check_win10_kits(${_win10build}) + endforeach() + endif() # vista-only and 2013+ + + # Included in Visual Studio 2013 + # Includes the v120_xp toolset + _winsdk_check_microsoft_sdks_registry(v8.1A 8.1.51636) + + if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800) + # Windows Software Development Kit (SDK) for Windows 8.1 + # http://msdn.microsoft.com/en-gb/windows/desktop/bg162891 + _winsdk_check_microsoft_sdks_registry(v8.1 8.1.25984.0) + _winsdk_check_windows_kits_registry("Windows Kits 8.1" 8.1.25984.0 KitsRoot81) + endif() # vista-only and 2013+ + + if(_winsdk_vistaonly_ok) + # Included in Visual Studio 2012 + _winsdk_check_microsoft_sdks_registry(v8.0A 8.0.50727) + + # Microsoft Windows SDK for Windows 8 and .NET Framework 4.5 + # This is the first version to also include the DirectX SDK + # http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx + _winsdk_check_microsoft_sdks_registry(v8.0 6.2.9200.16384) + _winsdk_check_windows_kits_registry("Windows Kits 8.0" 6.2.9200.16384 KitsRoot) + endif() # vista-only + + # Included with VS 2012 Update 1 or later + # Introduces v110_xp toolset + _winsdk_check_microsoft_sdks_registry(v7.1A 7.1.51106) + if(_winsdk_vistaonly_ok) + # Microsoft Windows SDK for Windows 7 and .NET Framework 4 + # http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b + _winsdk_check_microsoft_sdks_registry(v7.1 7.1.7600.0.30514) + endif() # vista-only + + # Included with VS 2010 + _winsdk_check_microsoft_sdks_registry(v7.0A 6.1.7600.16385) + + # Windows SDK for Windows 7 and .NET Framework 3.5 SP1 + # Works with VC9 + # http://www.microsoft.com/en-us/download/details.aspx?id=18950 + _winsdk_check_microsoft_sdks_registry(v7.0 6.1.7600.16385) + + # Two versions call themselves "v6.1": + # Older: + # Windows Vista Update & .NET 3.0 SDK + # http://www.microsoft.com/en-us/download/details.aspx?id=14477 + + # Newer: + # Windows Server 2008 & .NET 3.5 SDK + # may have broken VS9SP1? they recommend v7.0 instead, or a KB... + # http://www.microsoft.com/en-us/download/details.aspx?id=24826 + _winsdk_check_microsoft_sdks_registry(v6.1 6.1.6000.16384.10) + + # Included in VS 2008 + _winsdk_check_microsoft_sdks_registry(v6.0A 6.1.6723.1) + + # Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components + # http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx + _winsdk_check_microsoft_sdks_registry(v6.0 6.0.6000.16384) +endif() + +# Let's not forget the Platform SDKs, which sometimes are useful! +if(_winsdk_msvc_greater_1200) + _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 R2" "5.2.3790.2075.51" "D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1") + _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 SP1" "5.2.3790.1830.15" "8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3") +endif() +### +# Finally, look for "preferred" SDKs +### +if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003 + + + # Environment variable for SDK dir + if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL "")) + _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}") + endif() + + if(_winsdk_msvc_less_1600) + # Per-user current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}") + + # System-wide current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}") + endif() +endif() + + +function(windowssdk_name_lookup _dir _outvar) + list(FIND _win_sdk_versanddirs "${_dir}" _diridx) + math(EXPR _idx "${_diridx} - 1") + if(${_idx} GREATER -1) + list(GET _win_sdk_versanddirs ${_idx} _ret) + else() + set(_ret "NOTFOUND") + endif() + set(${_outvar} "${_ret}" PARENT_SCOPE) +endfunction() + +function(windowssdk_build_lookup _dir _outvar) + list(FIND _win_sdk_buildsanddirs "${_dir}" _diridx) + math(EXPR _idx "${_diridx} - 1") + if(${_idx} GREATER -1) + list(GET _win_sdk_buildsanddirs ${_idx} _ret) + else() + set(_ret "NOTFOUND") + endif() + set(${_outvar} "${_ret}" PARENT_SCOPE) +endfunction() + +# If we found something... +if(_win_sdk_dirs) + list(GET _win_sdk_dirs 0 WINDOWSSDK_LATEST_DIR) + windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}" + WINDOWSSDK_LATEST_NAME) + set(WINDOWSSDK_DIRS ${_win_sdk_dirs}) + + # Fallback, in case no preference found. + set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}") + set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}") + set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS}) + set(WINDOWSSDK_FOUND_PREFERENCE OFF) +endif() + +# If we found indications of a user preference... +if(_win_sdk_preferred_sdk_dirs) + list(GET _win_sdk_preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR) + windowssdk_name_lookup("${WINDOWSSDK_PREFERRED_DIR}" + WINDOWSSDK_PREFERRED_NAME) + set(WINDOWSSDK_PREFERRED_FIRST_DIRS + ${_win_sdk_preferred_sdk_dirs} + ${_win_sdk_dirs}) + list(REMOVE_DUPLICATES WINDOWSSDK_PREFERRED_FIRST_DIRS) + set(WINDOWSSDK_FOUND_PREFERENCE ON) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(WindowsSDK + "No compatible version of the Windows SDK or Platform SDK found." + WINDOWSSDK_DIRS) + +if(WINDOWSSDK_FOUND) + # Internal: Architecture-appropriate library directory names. + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "ARM") + if(CMAKE_SIZEOF_VOID_P MATCHES "8") + # Only supported in Win10 SDK and up. + set(_winsdk_arch8 arm64) # what the WDK for Win8+ calls this architecture + else() + set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs + set(_winsdk_arch arm) # what the architecture used to be called + set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture + endif() + else() + if(CMAKE_SIZEOF_VOID_P MATCHES "8") + set(_winsdk_archbare /x64) # what the architecture used to be called in oldest SDKs + set(_winsdk_arch amd64) # what the architecture used to be called + set(_winsdk_arch8 x64) # what the WDK for Win8+ calls this architecture + else() + set(_winsdk_archbare ) # what the architecture used to be called in oldest SDKs + set(_winsdk_arch i386) # what the architecture used to be called + set(_winsdk_arch8 x86) # what the WDK for Win8+ calls this architecture + endif() + endif() + + function(get_windowssdk_from_component _component _var) + get_filename_component(_component "${_component}" ABSOLUTE) + file(TO_CMAKE_PATH "${_component}" _component) + foreach(_sdkdir ${WINDOWSSDK_DIRS}) + get_filename_component(_sdkdir "${_sdkdir}" ABSOLUTE) + string(LENGTH "${_sdkdir}" _sdklen) + file(RELATIVE_PATH _rel "${_sdkdir}" "${_component}") + # If we don't have any "parent directory" items... + if(NOT "${_rel}" MATCHES "[.][.]") + set(${_var} "${_sdkdir}" PARENT_SCOPE) + return() + endif() + endforeach() + # Fail. + set(${_var} "NOTFOUND" PARENT_SCOPE) + endfunction() + function(get_windowssdk_library_dirs _winsdk_dir _var) + set(_result) + set(_suffixes + "lib${_winsdk_archbare}" # SDKs like 7.1A + "lib/${_winsdk_arch}" # just because some SDKs have x86 dir and root dir + "lib/w2k/${_winsdk_arch}" # Win2k min requirement + "lib/wxp/${_winsdk_arch}" # WinXP min requirement + "lib/wnet/${_winsdk_arch}" # Win Server 2003 min requirement + "lib/wlh/${_winsdk_arch}" + "lib/wlh/um/${_winsdk_arch8}" # Win Vista ("Long Horn") min requirement + "lib/win7/${_winsdk_arch}" + "lib/win7/um/${_winsdk_arch8}" # Win 7 min requirement + ) + foreach(_ver + wlh # Win Vista ("Long Horn") min requirement + win7 # Win 7 min requirement + win8 # Win 8 min requirement + winv6.3 # Win 8.1 min requirement + ) + + list(APPEND _suffixes + "lib/${_ver}/${_winsdk_arch}" + "lib/${_ver}/um/${_winsdk_arch8}" + "lib/${_ver}/km/${_winsdk_arch8}" + ) + endforeach() + + # Look for WDF libraries in Win10+ SDK + foreach(_mode umdf kmdf) + file(GLOB _wdfdirs RELATIVE "${_winsdk_dir}" "${_winsdk_dir}/lib/wdf/${_mode}/${_winsdk_arch8}/*") + if(_wdfdirs) + list(APPEND _suffixes ${_wdfdirs}) + endif() + endforeach() + + foreach(_win10ver ${_winsdk_win10vers}) + foreach(_component um km ucrt mmos) + list(APPEND _suffixes "lib/${_win10ver}/${_component}/${_winsdk_arch8}") + endforeach() + endforeach() + + foreach(_suffix ${_suffixes}) + # Check to see if a library actually exists here. + file(GLOB _libs "${_winsdk_dir}/${_suffix}/*.lib") + if(_libs) + list(APPEND _result "${_winsdk_dir}/${_suffix}") + endif() + endforeach() + if(NOT _result) + set(_result NOTFOUND) + else() + list(REMOVE_DUPLICATES _result) + endif() + set(${_var} ${_result} PARENT_SCOPE) + endfunction() + function(get_windowssdk_include_dirs _winsdk_dir _var) + set(_result) + + set(_subdirs shared um winrt km wdf mmos ucrt) + set(_suffixes Include) + + foreach(_dir ${_subdirs}) + list(APPEND _suffixes "Include/${_dir}") + endforeach() + + foreach(_ver ${_winsdk_win10vers}) + foreach(_dir ${_subdirs}) + list(APPEND _suffixes "Include/${_ver}/${_dir}") + endforeach() + endforeach() + + foreach(_suffix ${_suffixes}) + # Check to see if a header file actually exists here. + file(GLOB _headers "${_winsdk_dir}/${_suffix}/*.h") + if(_headers) + list(APPEND _result "${_winsdk_dir}/${_suffix}") + endif() + endforeach() + if(NOT _result) + set(_result NOTFOUND) + else() + list(REMOVE_DUPLICATES _result) + endif() + set(${_var} ${_result} PARENT_SCOPE) + endfunction() +endif() diff --git a/cmake/Findliquidvr.cmake b/cmake/Findliquidvr.cmake new file mode 100644 index 0000000..c5e6572 --- /dev/null +++ b/cmake/Findliquidvr.cmake @@ -0,0 +1,54 @@ +# - Find liquidvr +# Find the liquidvr header. +# +# LIQUIDVR_INCLUDE_DIRS - where to find LiquidVRD2D.h +# LIQUIDVR_FOUND - True if liquidvr found. +# +# Creates an "liquidvr" interface target with the include dir +# that you can link against instead of using the above variables. +# +# Original Author: +# 2016 Russ Taylor working through ReliaSolve for Sensics. +# +# Copyright Sensics, Inc. 2016. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(LIQUIDVR_ROOT_DIR + "${LIQUIDVR_ROOT_DIR}" + CACHE + PATH + "Path to search for liquidvr library") + +# Look for the header file. +find_path(LIQUIDVR_INCLUDE_DIR + NAMES + LiquidVRD2D.h + PATH_SUFFIXES + include + inc + PATHS + "${LIQUIDVR_ROOT_DIR}") + +# handle the QUIETLY and REQUIRED arguments and set LIQUIDVR_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(liquidvr + REQUIRED_VARS LIQUIDVR_INCLUDE_DIR + HANDLE_COMPONENTS) + +if(LIQUIDVR_FOUND) + set(LIQUIDVR_INCLUDE_DIRS ${LIQUIDVR_INCLUDE_DIR}) + if(NOT TARGET liquidvr) + add_library(liquidvr INTERFACE) + target_include_directories(liquidvr INTERFACE "${LIQUIDVR_INCLUDE_DIR}") + endif() + mark_as_advanced(LIQUIDVR_ROOT_DIR) +else() + set(LIQUIDVR_INCLUDE_DIRS) + set(LIQUIDVR_ROOT_DIR LIQUIDVR_ROOT_DIR_NOTFOUND) + mark_as_advanced(CLEAR LIQUIDVR_ROOT_DIR) +endif() + +mark_as_advanced(LIQUIDVR_LIBRARY LIQUIDVR_INCLUDE_DIR) diff --git a/cmake/Findnvapi.cmake b/cmake/Findnvapi.cmake new file mode 100644 index 0000000..a98588e --- /dev/null +++ b/cmake/Findnvapi.cmake @@ -0,0 +1,109 @@ +# - Find nvapi +# Find the nvapi headers and libraries. Can request component NDA which +# will only succeed if an NDA version of the header is found. +# +# NVAPI_INCLUDE_DIRS - where to find nvapi.h +# NVAPI_LIBRARIES - List of libraries when using nvapi. +# NVAPI_FOUND - True if nvapi found. +# +# Creates an "nvapi" interface target with the libraries and include dir +# that you can link against instead of using the above variables. +# +# Original Author: +# 2016 Russ Taylor working through ReliaSolve for Sensics. +# +# Copyright Sensics, Inc. 2016. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(NVAPI_ROOT_DIR + "${NVAPI_ROOT_DIR}" + CACHE + PATH + "Path to search for nvapi library") + +# Look for the header file. +find_path(NVAPI_INCLUDE_DIR + NAMES + nvapi.h + PATH_SUFFIXES + include + PATHS + "${NVAPI_ROOT_DIR}" + C:/usr/local + /usr/local) + +# Allow user to have us re-detect the edition by clearing NVAPI_EDITION +if(NOT DEFINED NVAPI_EDITION) + set(NVAPI_LAST_INCLUDE_DIR "" CACHE INTERNAL "" FORCE) +endif() +if(NVAPI_INCLUDE_DIR AND NOT "${NVAPI_INCLUDE_DIR}" STREQUAL "${NVAPI_LAST_INCLUDE_DIR}") + file(STRINGS "${NVAPI_INCLUDE_DIR}/nvapi.h" _nvapi_strings REGEX "Target Profile:") + if("${_nvapi_strings}" MATCHES ".* NDA-developer") + set(NVAPI_EDITION "NDA-developer" CACHE STRING "The detected edition of the NVAPI") + elseif("${_nvapi_strings}" MATCHES ".* developer") + set(NVAPI_EDITION "developer" CACHE STRING "The detected edition of the NVAPI") + endif() + # If we found an edition, keep track of where we found it so that we don't re-check next time CMake runs. + if(DEFINED NVAPI_EDITION) + set(NVAPI_LAST_INCLUDE_DIR "${NVAPI_INCLUDE_DIR}" CACHE INTERNAL "" FORCE) + endif() +endif() + +if(NVAPI_INCLUDE_DIR) + # Prioritize finding the lib near the header to hopefully ensure they match. + set(_nvapi_hints "${NVAPI_INCLUDE_DIR}") +endif() + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_nvapiextraname nvapi64 nvapi64.lib) + set(_nvapipathsuffix amd64) +else() + set(_nvapiextraname nvapi nvapi.lib) + set(_nvapipathsuffix x86) +endif() + +# Look for the library. +find_library(NVAPI_LIBRARY + NAMES + ${_nvapiextraname} + libnvapi.a + HINTS + ${_nvapi_hints} + PATH_SUFFIXES + ${_nvapipathsuffix} + PATHS + "${NVAPI_ROOT_DIR}" + C:/usr/local + /usr/local) + +# Handle asking for component "NDA" +if("${NVAPI_EDITION}" STREQUAL "NDA-developer") + set(nvapi_NDA_FOUND TRUE) +endif() + +# handle the QUIETLY and REQUIRED arguments and set NVAPI_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(nvapi + REQUIRED_VARS NVAPI_LIBRARY NVAPI_INCLUDE_DIR + HANDLE_COMPONENTS) + +if(NVAPI_FOUND) + set(NVAPI_LIBRARIES ${NVAPI_LIBRARY}) + set(NVAPI_INCLUDE_DIRS ${NVAPI_INCLUDE_DIR}) + if(NOT TARGET nvapi) + add_library(nvapi INTERFACE) + target_include_directories(nvapi INTERFACE "${NVAPI_INCLUDE_DIR}") + target_link_libraries(nvapi INTERFACE "${NVAPI_LIBRARY}") + endif() + mark_as_advanced(NVAPI_ROOT_DIR) +else() + set(NVAPI_LIBRARIES) + set(NVAPI_INCLUDE_DIRS) + set(NVAPI_ROOT_DIR NVAPI_ROOT_DIR_NOTFOUND) + mark_as_advanced(CLEAR NVAPI_ROOT_DIR) +endif() + +mark_as_advanced(NVAPI_LIBRARY NVAPI_INCLUDE_DIR) diff --git a/cmake/Findquatlib.cmake b/cmake/Findquatlib.cmake new file mode 100644 index 0000000..efca27f --- /dev/null +++ b/cmake/Findquatlib.cmake @@ -0,0 +1,104 @@ +# - Find quatlib +# Find the quatlib headers and libraries. +# +# QUATLIB_INCLUDE_DIRS - where to find quat.h +# QUATLIB_LIBRARIES - List of libraries when using quatlib. +# QUATLIB_FOUND - True if quatlib found. +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(TARGET quat) + # Look for the header file. + find_path(QUATLIB_INCLUDE_DIR NAMES quat.h + PATHS ${quatlib_SOURCE_DIR}) + + set(QUATLIB_LIBRARY "quat") + +else() + set(QUATLIB_ROOT_DIR + "${QUATLIB_ROOT_DIR}" + CACHE + PATH + "Root directory to search for quatlib") + if(DEFINED VRPN_ROOT_DIR AND NOT QUATLIB_ROOT_DIR) + set(QUATLIB_ROOT_DIR "${VRPN_ROOT_DIR}") + mark_as_advanced(QUATLIB_ROOT_DIR) + endif() + + if("${CMAKE_SIZEOF_VOID_P}" MATCHES "8") + set(_libsuffixes lib64 lib) + + # 64-bit dir: only set on win64 + file(TO_CMAKE_PATH "$ENV{ProgramW6432}" _progfiles) + else() + set(_libsuffixes lib) + set(_PF86 "ProgramFiles(x86)") + if(NOT "$ENV{${_PF86}}" STREQUAL "") + # 32-bit dir: only set on win64 + file(TO_CMAKE_PATH "$ENV{${_PF86}}" _progfiles) + else() + # 32-bit dir on win32, useless to us on win64 + file(TO_CMAKE_PATH "$ENV{ProgramFiles}" _progfiles) + endif() + endif() + + # Look for the header file. + find_path(QUATLIB_INCLUDE_DIR + NAMES + quat.h + HINTS + "${QUATLIB_ROOT_DIR}" + PATH_SUFFIXES + include + PATHS + "${_progfiles}/VRPN" + "${_progfiles}/quatlib" + C:/usr/local + /usr/local) + + # Look for the library. + find_library(QUATLIB_LIBRARY + NAMES + quat.lib + libquat.a + HINTS + "${QUATLIB_ROOT_DIR}" + PATH_SUFFIXES + ${_libsuffixes} + PATHS + "${_progfiles}/VRPN" + "${_progfiles}/quatlib" + C:/usr/local + /usr/local) +endif() + +# handle the QUIETLY and REQUIRED arguments and set QUATLIB_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(quatlib + DEFAULT_MSG + QUATLIB_LIBRARY + QUATLIB_INCLUDE_DIR) + +if(QUATLIB_FOUND) + set(QUATLIB_LIBRARIES ${QUATLIB_LIBRARY}) + if(NOT WIN32) + list(APPEND QUATLIB_LIBRARIES m) + endif() + set(QUATLIB_INCLUDE_DIRS ${QUATLIB_INCLUDE_DIR}) + + mark_as_advanced(QUATLIB_ROOT_DIR) +else() + set(QUATLIB_LIBRARIES) + set(QUATLIB_INCLUDE_DIRS) +endif() + +mark_as_advanced(QUATLIB_LIBRARY QUATLIB_INCLUDE_DIR) diff --git a/cmake/GenerateCompatibilityVersionFile.cmake b/cmake/GenerateCompatibilityVersionFile.cmake new file mode 100644 index 0000000..7ac28ed --- /dev/null +++ b/cmake/GenerateCompatibilityVersionFile.cmake @@ -0,0 +1,83 @@ +#.rst: +# .. command:: generate_compatibility_version_file +# +# Create a version file for a project:: +# +# generate_compatibility_version_file( +# [VERSION ] +# COMPATIBILITY +# [C_ABI] +# [CXX_LAYOUT] +# [CXX_ABI]) + +#============================================================================= +# Copyright 2015 Sensics, Inc. +# Copyright 2012 Alexander Neundorf +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +include(CMakeParseArguments) +include(CMakePackageConfigHelpers) + +set(GCVF_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "" FORCE) + +function(generate_compatibility_version_file _filename) + + set(options C_ABI CXX_LAYOUT CXX_ABI) + set(oneValueArgs VERSION COMPATIBILITY ) + set(multiValueArgs ) + cmake_parse_arguments(GCVF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(GCVF_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to generate_compatibility_version_file(): ${GCVF_UNPARSED_ARGUMENTS}") + endif() + set(versionTemplateFile "${CMAKE_ROOT}/Modules/BasicConfigVersion-${GCVF_COMPATIBILITY}.cmake.in") + if(NOT EXISTS "${versionTemplateFile}") + message(FATAL_ERROR "Bad COMPATIBILITY value used for generate_compatibility_version_file(): \"${GCVF_COMPATIBILITY}\"") + endif() + + if(GCVF_CXX_ABI) + set(GCVF_CXX_LAYOUT TRUE) + endif() + if(GCVF_CXX_LAYOUT) + set(GCVF_C_ABI TRUE) + endif() + + if("${GCVF_VERSION}" STREQUAL "") + if("${PROJECT_VERSION}" STREQUAL "") + message(FATAL_ERROR "No VERSION specified for generate_compatibility_version_file()") + else() + set(GCVF_VERSION ${PROJECT_VERSION}) + endif() + endif() + + set(GCVF_WIN_CXXLAYOUT) + if(MSVC) + set(GCVF_WIN_CXXLAYOUT "MSVC") + elseif(MINGW) + set(GCVF_WIN_CXXLAYOUT "MinGW") + elseif(WIN32) + set(GCVF_WIN_CXXLAYOUT "other") + endif() + + set(PREV_FILE "${_filename}.cmakeversion") + write_basic_package_version_file("${PREV_FILE}" VERSION ${GCVF_VERSION} COMPATIBILITY ${GCVF_COMPATIBILITY}) + set(GCVF_BASIC TRUE) + foreach(level BASIC C_ABI CXX_LAYOUT CXX_ABI) + if(GCVF_${level}) + file(READ "${PREV_FILE}" GCVF_PREVIOUS_FILE) + set(PREV_FILE "${_filename}.${level}") + configure_file("${GCVF_DIR}/CompatibilityVersionFile-${level}.cmake.in" "${PREV_FILE}" @ONLY) + endif() + endforeach() + configure_file("${PREV_FILE}" "${_filename}" COPYONLY) +endfunction() \ No newline at end of file diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake new file mode 100644 index 0000000..85eae15 --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake @@ -0,0 +1,130 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _refspecvar _hashvar) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + # check if this is a submodule + if(NOT IS_DIRECTORY ${GIT_DIR}) + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + describe + ${hash} + ${ARGN} + WORKING_DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() diff --git a/cmake/GetGitRevisionDescription.cmake.in b/cmake/GetGitRevisionDescription.cmake.in new file mode 100644 index 0000000..6d8b708 --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake.in @@ -0,0 +1,41 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/cmake/GetMSVCVersion.cmake b/cmake/GetMSVCVersion.cmake new file mode 100644 index 0000000..48d7b7c --- /dev/null +++ b/cmake/GetMSVCVersion.cmake @@ -0,0 +1,127 @@ +#.rst: +# GetMSVCVersion +# -------------- +# +# +# +# get_msvc_major_version() +# get_msvc_minor_version() +# get_msvc_combined_major_minor_version() +# get_msvc_major_minor_version( ) +# get_msvc_unique_decimal_version() +# +# This family of functions is designed to be used to convert +# MSVC_VERSION from the compiler version number to the Visual Studio +# decimal version number (2012 is 11.0, 2015 is 14.0). All take a name +# of a variable in to return their results in. +# +# Consider Visual Studio 2013, which reports 1800 in MSVC_VERSION (and +# the _MSC_VER preprocessor macro). It is also known as VS 12 or 12.0. +# (Minor versions are rarely used, except in the case of 7.1 aka +# VS.NET 2003) The functions would return this output for 2013: +# +# get_msvc_major_version: 12 +# get_msvc_minor_version: 0 +# get_msvc_combined_major_minor_version: 120 +# get_msvc_major_minor_version: 12 in , 0 in +# get_msvc_unique_decimal_version: 12 (this returns with a decimal and +# minor when needed to be precise, e.g. 7.1) +# +# The variable is not modified if not building with MSVC. + +#============================================================================= +# Copyright 2015 Ryan Pavlik +# +# Distributed under the OSI-approved BSD License (the "License"); +# see below. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +# This function serves as the main implementation, with the others just +# tweaking the result. +function(get_msvc_combined_major_minor_version _var) + if(NOT MSVC) + return() + endif() + math(EXPR _vs_ver "${MSVC_VERSION} / 10 - 60") + + # VS 2015 changed the pattern because they skipped VS 13 + if(_vs_ver GREATER 120) + math(EXPR _vs_ver "${_vs_ver} + 10") + endif() + set(${_var} ${_vs_ver} PARENT_SCOPE) +endfunction() + +# This function is also used as backend to some implementation, though +# its contents are simpler, no real business logic to speak of. +function(get_msvc_major_minor_version _major_var _minor_var) + if(NOT MSVC) + return() + endif() + get_msvc_combined_major_minor_version(_vs_ver) + + math(EXPR _vs_minor "${_vs_ver} % 10") + math(EXPR _vs_major "(${_vs_ver} - ${_vs_minor}) / 10") + set(${_major_var} ${_vs_major} PARENT_SCOPE) + set(${_minor_var} ${_vs_minor} PARENT_SCOPE) +endfunction() + +function(get_msvc_major_version _var) + if(NOT MSVC) + return() + endif() + get_msvc_major_minor_version(_vs_ver _dummy) + set(${_var} ${_vs_ver} PARENT_SCOPE) +endfunction() + +function(get_msvc_minor_version _var) + if(NOT MSVC) + return() + endif() + get_msvc_major_minor_version(_dummy _vs_ver) + set(${_var} ${_vs_ver} PARENT_SCOPE) +endfunction() + +function(get_msvc_unique_decimal_version _var) + if(NOT MSVC) + return() + endif() + get_msvc_major_minor_version(_vs_major _vs_minor) + set(_vs_ver ${_vs_major}) + if(_vs_minor GREATER 0) + set(_vs_ver "${_vs_ver}.${_vs_minor}") + endif() + set(${_var} ${_vs_ver} PARENT_SCOPE) +endfunction() diff --git a/cmake/PrintTargetProperties.cmake b/cmake/PrintTargetProperties.cmake new file mode 100644 index 0000000..8e17a02 --- /dev/null +++ b/cmake/PrintTargetProperties.cmake @@ -0,0 +1,256 @@ +# Prints a target's properties. +# +# Usage: +# print_target_properties(target [target...]) +# + +function(print_target_property _target _prop) + get_property(value TARGET ${_target} PROPERTY ${_prop}) + get_property(is_defined TARGET ${_target} PROPERTY ${_prop} DEFINED) + get_property(is_set TARGET ${_target} PROPERTY ${_prop} SET) + + if(is_set) + message(" ${_prop} = [${value}]") + #elseif(NOT is_set) + # message(" ${_prop} is not set") + #elseif(NOT is_defined) + # message(" ${_prop} is not defined") + endif() +endfunction() + +function(print_target_properties _targets) + set(_targets ${ARGV}) + foreach(_target ${_targets}) + if(NOT TARGET ${_target}) + message(WARNING "There is no target named [${_target}].") + return() + endif() + + set(props + ALIASED_TARGET + ANDROID_ANT_ADDITIONAL_OPTIONS + ANDROID_API + ANDROID_API_MIN + ANDROID_ARCH + ANDROID_ASSETS_DIRECTORIES + ANDROID_GUI + ANDROID_JAR_DEPENDENCIES + ANDROID_JAR_DIRECTORIES + ANDROID_JAVA_SOURCE_DIR + ANDROID_NATIVE_LIB_DEPENDENCIES + ANDROID_NATIVE_LIB_DIRECTORIES + ANDROID_PROCESS_MAX + ANDROID_PROGUARD + ANDROID_PROGUARD_CONFIG_PATH + ANDROID_SECURE_PROPS_PATH + ANDROID_SKIP_ANT_STEP + ANDROID_STL_TYPE + ARCHIVE_OUTPUT_DIRECTORY_ + ARCHIVE_OUTPUT_DIRECTORY + ARCHIVE_OUTPUT_NAME_ + ARCHIVE_OUTPUT_NAME + AUTOGEN_TARGET_DEPENDS + AUTOMOC_MOC_OPTIONS + AUTOMOC + AUTOUIC + AUTOUIC_OPTIONS + AUTORCC + AUTORCC_OPTIONS + BINARY_DIR + BUILD_WITH_INSTALL_RPATH + BUNDLE_EXTENSION + BUNDLE + C_EXTENSIONS + C_STANDARD + C_STANDARD_REQUIRED + COMPATIBLE_INTERFACE_BOOL + COMPATIBLE_INTERFACE_NUMBER_MAX + COMPATIBLE_INTERFACE_NUMBER_MIN + COMPATIBLE_INTERFACE_STRING + COMPILE_DEFINITIONS + COMPILE_FEATURES + COMPILE_FLAGS + COMPILE_OPTIONS + COMPILE_PDB_NAME + COMPILE_PDB_NAME_ + COMPILE_PDB_OUTPUT_DIRECTORY + COMPILE_PDB_OUTPUT_DIRECTORY_ + _OUTPUT_NAME + _POSTFIX + CROSSCOMPILING_EMULATOR + CXX_EXTENSIONS + CXX_STANDARD + CXX_STANDARD_REQUIRED + DEBUG_POSTFIX + DEFINE_SYMBOL + EchoString + ENABLE_EXPORTS + EXCLUDE_FROM_ALL + EXCLUDE_FROM_DEFAULT_BUILD_ + EXCLUDE_FROM_DEFAULT_BUILD + EXPORT_NAME + FOLDER + Fortran_FORMAT + Fortran_MODULE_DIRECTORY + FRAMEWORK + FRAMEWORK_VERSION + GENERATOR_FILE_NAME + GNUtoMS + HAS_CXX + IMPLICIT_DEPENDS_INCLUDE_TRANSFORM + IMPORTED_CONFIGURATIONS + IMPORTED_IMPLIB_ + IMPORTED_IMPLIB + IMPORTED_LINK_DEPENDENT_LIBRARIES_ + IMPORTED_LINK_DEPENDENT_LIBRARIES + IMPORTED_LINK_INTERFACE_LANGUAGES_ + IMPORTED_LINK_INTERFACE_LANGUAGES + IMPORTED_LINK_INTERFACE_LIBRARIES_ + IMPORTED_LINK_INTERFACE_LIBRARIES + IMPORTED_LINK_INTERFACE_MULTIPLICITY_ + IMPORTED_LINK_INTERFACE_MULTIPLICITY + IMPORTED_LOCATION_ + IMPORTED_LOCATION + IMPORTED_NO_SONAME_ + IMPORTED_NO_SONAME + IMPORTED + IMPORTED_SONAME_ + IMPORTED_SONAME + IMPORT_PREFIX + IMPORT_SUFFIX + INCLUDE_DIRECTORIES + INSTALL_NAME_DIR + INSTALL_RPATH + INSTALL_RPATH_USE_LINK_PATH + INTERFACE_AUTOUIC_OPTIONS + INTERFACE_COMPILE_DEFINITIONS + INTERFACE_COMPILE_FEATURES + INTERFACE_COMPILE_OPTIONS + INTERFACE_INCLUDE_DIRECTORIES + INTERFACE_LINK_LIBRARIES + INTERFACE_POSITION_INDEPENDENT_CODE + INTERFACE_SOURCES + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES + INTERPROCEDURAL_OPTIMIZATION_ + INTERPROCEDURAL_OPTIMIZATION + IOS_INSTALL_COMBINED + JOB_POOL_COMPILE + JOB_POOL_LINK + LABELS + _COMPILER_LAUNCHER + _INCLUDE_WHAT_YOU_USE + _VISIBILITY_PRESET + LIBRARY_OUTPUT_DIRECTORY_ + LIBRARY_OUTPUT_DIRECTORY + LIBRARY_OUTPUT_NAME_ + LIBRARY_OUTPUT_NAME + LINK_DEPENDS_NO_SHARED + LINK_DEPENDS + LINKER_LANGUAGE + LINK_FLAGS_ + LINK_FLAGS + LINK_INTERFACE_LIBRARIES_ + LINK_INTERFACE_LIBRARIES + LINK_INTERFACE_MULTIPLICITY_ + LINK_INTERFACE_MULTIPLICITY + LINK_LIBRARIES + LINK_SEARCH_END_STATIC + LINK_SEARCH_START_STATIC + LOCATION_ + LOCATION + MACOSX_BUNDLE_INFO_PLIST + MACOSX_BUNDLE + MACOSX_FRAMEWORK_INFO_PLIST + MACOSX_RPATH + MAP_IMPORTED_CONFIG_ + NAME + NO_SONAME + NO_SYSTEM_FROM_IMPORTED + OSX_ARCHITECTURES_ + OSX_ARCHITECTURES + OUTPUT_NAME_ + OUTPUT_NAME + PDB_NAME_ + PDB_NAME + PDB_OUTPUT_DIRECTORY_ + PDB_OUTPUT_DIRECTORY + POSITION_INDEPENDENT_CODE + PREFIX + PRIVATE_HEADER + PROJECT_LABEL + PUBLIC_HEADER + RESOURCE + RULE_LAUNCH_COMPILE + RULE_LAUNCH_CUSTOM + RULE_LAUNCH_LINK + RUNTIME_OUTPUT_DIRECTORY_ + RUNTIME_OUTPUT_DIRECTORY + RUNTIME_OUTPUT_NAME_ + RUNTIME_OUTPUT_NAME + SKIP_BUILD_RPATH + SOURCE_DIR + SOURCES + SOVERSION + STATIC_LIBRARY_FLAGS_ + STATIC_LIBRARY_FLAGS + SUFFIX + TYPE + VERSION + VISIBILITY_INLINES_HIDDEN + VS_DESKTOP_EXTENSIONS_VERSION + VS_DOTNET_REFERENCES + VS_DOTNET_TARGET_FRAMEWORK_VERSION + VS_GLOBAL_KEYWORD + VS_GLOBAL_PROJECT_TYPES + VS_GLOBAL_ROOTNAMESPACE + VS_IOT_EXTENSIONS_VERSION + VS_IOT_STARTUP_TASK + VS_KEYWORD + VS_MOBILE_EXTENSIONS_VERSION + VS_SCC_AUXPATH + VS_SCC_LOCALPATH + VS_SCC_PROJECTNAME + VS_SCC_PROVIDER + VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION + VS_WINRT_COMPONENT + VS_WINRT_EXTENSIONS + VS_WINRT_REFERENCES + WIN32_EXECUTABLE + WINDOWS_EXPORT_ALL_SYMBOLS + XCTEST + ) + + set(all_props) + foreach(p IN LISTS props) + # Expand + string(FIND "${p}" "" _position) + if(_position GREATER "-1") + foreach(config DEBUG RELEASE RELWITHDEBINFO MINSIZEREL) + string(REPLACE "" "${config}" p "${p}") + list(APPEND all_props ${p}) + endforeach() + continue() + endif() + + # Expand + string(FIND "${p}" "" _position) + if(_position GREATER "-1") + foreach(lang C CXX) + string(REPLACE "" "${lang}" p "${p}") + list(APPEND all_props ${p}) + endforeach() + continue() + endif() + + list(APPEND all_props ${p}) + endforeach() + + message("Target ${_target} properties:") + foreach(p ${all_props}) + print_target_property("${_target}" "${p}") + endforeach() + message("") + endforeach() +endfunction() + + diff --git a/cmake/Version.cmake b/cmake/Version.cmake new file mode 100644 index 0000000..3eae488 --- /dev/null +++ b/cmake/Version.cmake @@ -0,0 +1,35 @@ +# Set up package options +set(CPACK_PACKAGE_NAME "OSVR-RenderManager") +set(CPACK_PACKAGE_VENDOR "Sensics, Inc.") +set(CPACK_PACKAGE_CONTACT "") +set(CPACK_PACKAGE_VERSION_MAJOR 0) +set(CPACK_PACKAGE_VERSION_MINOR 6) +set(OSVR_RENDERMANAGER_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}) +set(CPACK_PACKAGE_VERSION ${OSVR_RENDERMANAGER_VERSION}) + +include(GetGitRevisionDescription) +git_describe(GIT_REVISION_DESCRIPTION --tags --match v*) +if(GIT_REVISION_DESCRIPTION) + string(REPLACE "v" "" + GIT_REVISION_DESCRIPTION + "${GIT_REVISION_DESCRIPTION}") + set(CPACK_PACKAGE_VERSION "${GIT_REVISION_DESCRIPTION}") + message(STATUS "Git reports version ${CPACK_PACKAGE_VERSION}") +else() + message(STATUS "Could not get revision information from Git! Calling this just version ${CPACK_PACKAGE_VERSION}!") +endif() + +if(WIN32) + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_CXX_COMPILER_ID}") + if(MSVC) + include(GetMSVCVersion) + get_msvc_major_minor_version(_vs_major _vs_minor) + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}${_vs_major}${_vs_minor}") + endif() + if(CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8) + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-64bit") + else() + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-32bit") + endif() +endif() + diff --git a/cmake/osvrRenderManagerConfig.cmake b/cmake/osvrRenderManagerConfig.cmake new file mode 100644 index 0000000..45673af --- /dev/null +++ b/cmake/osvrRenderManagerConfig.cmake @@ -0,0 +1,112 @@ + +# Hook for a super-build to optionally inject hints before target import. +include("${CMAKE_CURRENT_LIST_DIR}/osvrRenderManagerConfigSuperBuildPrefix.cmake" OPTIONAL) + +set(OSVRRM_IN_BUILD_TREE @OSVRRM_IN_BUILD_TREE@) + +if(NOT OSVRRM_IN_BUILD_TREE) + # Compute the installation prefix relative to this file. + get_filename_component(OSVRRM_ROOT "${CMAKE_CURRENT_LIST_FILE}" PATH) + get_filename_component(OSVRRM_ROOT "${OSVRRM_ROOT}" PATH) + get_filename_component(OSVRRM_ROOT "${OSVRRM_ROOT}" PATH) + get_filename_component(OSVRRM_ROOT "${OSVRRM_ROOT}" PATH) +endif() + +set(OSVRRM_NEED_SDL2 @OSVRRM_NEED_SDL2@) +set(OSVRRM_NEED_GLEW @OSVRRM_NEED_GLEW@) + +set(OSVRRM_PREV_CMAKE_MODULES ${CMAKE_MODULE_PATH}) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}" ${CMAKE_MODULE_PATH}) +include("${CMAKE_CURRENT_LIST_DIR}/osvrRenderManagerConfigBuildTreeHints.cmake" OPTIONAL) +include(osvrStashMapConfig) +include(CMakeFindDependencyMacro) +if(OSVRRM_NEED_SDL2) + # TODO + #find_dependency(SDL2) +endif() +if(OSVRRM_NEED_GLEW) + # TODO + #find_dependency(GLEW) +endif() + +# Set up config mapping +osvr_stash_common_map_config() + +find_dependency(osvr) + +# restore module path +set(CMAKE_MODULE_PATH ${OSVRRM_PREV_CMAKE_MODULES}) + +# The actual exported targets - config mapping still applied. +include("${CMAKE_CURRENT_LIST_DIR}/osvrRenderManagerTargets.cmake") + +# Undo our changes for later consumers +osvr_unstash_common_map_config() + +if(NOT TARGET osvrRenderManager::osvrRenderManagerCpp) + add_library(osvrRenderManager::osvrRenderManagerCpp INTERFACE IMPORTED) + set_target_properties(osvrRenderManager::osvrRenderManagerCpp PROPERTIES + INTERFACE_LINK_LIBRARIES "osvrRenderManager::osvrRenderManager;osvr::osvrClientKitCpp") +endif() + +# Fix up imported targets to add deps: these files will only exist in install trees. +include("${CMAKE_CURRENT_LIST_DIR}/osvrRenderManagerConfigInstalledBoost.cmake" OPTIONAL) + +# A list of filenames of required libraries for running with osvrRenderManager DLL +set(OSVRRM_REQUIRED_LIBRARIES_DEBUG "@OSVRRM_REQUIRED_LIBRARIES_DEBUG@") +set(OSVRRM_REQUIRED_LIBRARIES_RELEASE "@OSVRRM_REQUIRED_LIBRARIES_RELEASE@") +set(OSVRRM_REQUIRED_LIBRARIES_RELWITHDEBINFO "@OSVRRM_REQUIRED_LIBRARIES_RELWITHDEBINFO@") +set(OSVRRM_REQUIRED_LIBRARIES_MINSIZEREL "@OSVRRM_REQUIRED_LIBRARIES_MINSIZEREL@") +set(OSVRRM_NEED_SDL2_COPIED @OSVRRM_NEED_SDL2_COPIED@) +set(OSVRRM_NEED_GLEW_COPIED @OSVRRM_NEED_GLEW_COPIED@) + +# Options +set(OSVRRM_HAVE_D3D11_SUPPORT @OSVRRM_HAVE_D3D11_SUPPORT@) +set(OSVRRM_HAVE_OPENGL_SUPPORT @OSVRRM_HAVE_OPENGL_SUPPORT@) +set(OSVRRM_USE_OPENGLES20 @OSVRRM_USE_OPENGLES20@) + +# Helper function to copy required libraries to an install directory +set(OSVRRM_CONFIG_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "" FORCE) +function(osvrrm_install_dependencies _destination) + foreach(_config Debug Release RelWithDebInfo MinSizeRel) + string(TOUPPER "${_config}" _CONFIG) + # Canonicalize paths relative to the directory containing this .cmake file + set(_files) + foreach(_file IN LISTS OSVRRM_REQUIRED_LIBRARIES_${_CONFIG}) + get_filename_component(_file "${_file}" ABSOLUTE BASE_DIR "${OSVRRM_CONFIG_DIR}") + list(APPEND _files "${_file}") + endforeach() + install(FILES + ${_files} + CONFIGURATIONS ${_config} + DESTINATION ${_destination} + COMPONENT Runtime + OPTIONAL) + endforeach() + set(OSVRRM_NEED_D3DCOMPILER_COPIED @OSVRRM_NEED_D3DCOMPILER_COPIED@) + if(OSVRRM_NEED_D3DCOMPILER_COPIED) + install(FILES "@OSVRRM_D3DCOMPILER_FILE@" + DESTINATION ${_destination} + COMPONENT Runtime + OPTIONAL) + endif() +endfunction() + +# Find SDL2 using the script bundled with RenderManager. +macro(osvrrm_find_SDL2) + set(OSVRRM_PREV_CMAKE_MODULES ${CMAKE_MODULE_PATH}) + set(CMAKE_MODULE_PATH "${OSVRRM_CONFIG_DIR}" ${CMAKE_MODULE_PATH}) + find_package(SDL2 ${ARGN}) + set(CMAKE_MODULE_PATH ${OSVRRM_PREV_CMAKE_MODULES}) +endmacro() + +# Find GLEW using the script bundled with RenderManager. +macro(osvrrm_find_GLEW) + set(OSVRRM_PREV_CMAKE_MODULES ${CMAKE_MODULE_PATH}) + set(CMAKE_MODULE_PATH "${OSVRRM_CONFIG_DIR}" ${CMAKE_MODULE_PATH}) + find_package(GLEW ${ARGN}) + set(CMAKE_MODULE_PATH ${OSVRRM_PREV_CMAKE_MODULES}) +endmacro() + +# Hook for a super-build to optionally inject configuration after target import. +include("${CMAKE_CURRENT_LIST_DIR}/osvrRenderManagerConfigSuperBuildSuffix.cmake" OPTIONAL) diff --git a/cmake/osvrRenderManagerConfigBuildTreeHints.cmake.in b/cmake/osvrRenderManagerConfigBuildTreeHints.cmake.in new file mode 100644 index 0000000..a8852ee --- /dev/null +++ b/cmake/osvrRenderManagerConfigBuildTreeHints.cmake.in @@ -0,0 +1,39 @@ +# Help find OSVR, if required. +if(NOT osvr_DIR) + set(osvr_DIR "@osvr_DIR@" CACHE PATH "" FORCE) +endif() + +# Help find Eigen3 +if(NOT EIGEN3_INCLUDE_DIR) + set(EIGEN3_INCLUDE_DIR "@EIGEN3_INCLUDE_DIR@" CACHE PATH "" FORCE) +endif() + +# Help with SDL2 +if(OSVRRM_NEED_SDL2) + if(WIN32 AND NOT SDL2_RUNTIME_LIBRARY) + set(SDL2_RUNTIME_LIBRARY "@SDL2_RUNTIME_LIBRARY@" CACHE FILEPATH "" FORCE) + endif() + if(NOT SDL2_LIBRARY) + set(SDL2_LIBRARY "@SDL2_LIBRARY@" CACHE FILEPATH "" FORCE) + endif() + if(NOT SDL2_INCLUDE_DIR) + set(SDL2_INCLUDE_DIR "@SDL2_INCLUDE_DIR@" CACHE PATH "" FORCE) + endif() + set(OSVRRM_SDL2MAIN @OSVRRM_SDL2MAIN@) + if(OSVRRM_SDL2MAIN AND NOT SDL2_SDLMAIN_LIBRARY) + set(SDL2_SDLMAIN_LIBRARY "@SDL2_SDLMAIN_LIBRARY@" CACHE FILEPATH "" FORCE) + endif() +endif() + +# Help with GLEW +if(OSVRRM_NEED_GLEW) + if(WIN32 AND NOT GLEW_RUNTIME_LIBRARY) + set(GLEW_RUNTIME_LIBRARY "@GLEW_RUNTIME_LIBRARY@" CACHE FILEPATH "" FORCE) + endif() + if(NOT GLEW_LIBRARY) + set(GLEW_LIBRARY "@GLEW_LIBRARY@" CACHE FILEPATH "" FORCE) + endif() + if(NOT GLEW_INCLUDE_DIR) + set(GLEW_INCLUDE_DIR "@GLEW_INCLUDE_DIR@" CACHE PATH "" FORCE) + endif() +endif() diff --git a/cmake/osvrRenderManagerConfigInstalledBoost.cmake b/cmake/osvrRenderManagerConfigInstalledBoost.cmake new file mode 100644 index 0000000..ab1be9c --- /dev/null +++ b/cmake/osvrRenderManagerConfigInstalledBoost.cmake @@ -0,0 +1,16 @@ +# File included only with installed binaries, to re-find Boost on those systems. + +if(NOT BOOST_FOUND) + # Optionally help Windows machines find Boost easier. + include("${CMAKE_CURRENT_LIST_DIR}/CMakeBoostHelper.cmake" OPTIONAL) +endif() +find_package(Boost QUIET) + +if(BOOST_FOUND) + # Boost is optional for UtilCpp - lots of stuff needs it, but lots doesn't. + set_property(TARGET osvr::osvrUtilCpp APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIRS}) +endif() + +# Boost is required for these bindings. Adding regardless of if we found it - make the build fail early if it's not found. +set_property(TARGET osvr::osvrClientKitCpp APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIRS}) +set_property(TARGET osvr::osvrPluginKitCpp APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIRS}) diff --git a/cmake/osvrStashMapConfig.cmake b/cmake/osvrStashMapConfig.cmake new file mode 100644 index 0000000..3183fe9 --- /dev/null +++ b/cmake/osvrStashMapConfig.cmake @@ -0,0 +1,61 @@ +# Manipulate CMAKE_MAP_IMPORTED_CONFIG_ cautiously and reversibly. +macro(osvr_stash_map_config config) + # Re-entrancy protection + list(APPEND OSVR_IN_MAP_CONFIG_STASH_${config} yes) + list(LENGTH OSVR_IN_MAP_CONFIG_STASH_${config} OSVR_IN_MAP_CONFIG_STASH_LEN) + if(OSVR_IN_MAP_CONFIG_STASH_LEN GREATER 1) + # Not the first stash, get out. + return() + endif() + + # Actually perform the saving and replacement of CMAKE_MAP_IMPORTED_CONFIG_${config} + if(DEFINED CMAKE_MAP_IMPORTED_CONFIG_${config}) + set(OSVR_OLD_CMAKE_MAP_IMPORTED_CONFIG_${config} ${CMAKE_MAP_IMPORTED_CONFIG_${config}}) + endif() + set(CMAKE_MAP_IMPORTED_CONFIG_${config} ${ARGN}) +endmacro() + +macro(osvr_unstash_map_config config) + if(NOT DEFINED OSVR_IN_MAP_CONFIG_STASH_${config}) + # Nobody actually called the matching stash... + return() + endif() + # Other half of re-entrancy protection + list(REMOVE_AT OSVR_IN_MAP_CONFIG_STASH_${config} -1) + list(LENGTH OSVR_IN_MAP_CONFIG_STASH_${config} OSVR_IN_MAP_CONFIG_STASH_LEN) + if(OSVR_IN_MAP_CONFIG_STASH_LEN GREATER 0) + # someone still in here + return() + endif() + + # Restoration of CMAKE_MAP_IMPORTED_CONFIG_${config} + if(DEFINED OSVR_OLD_CMAKE_MAP_IMPORTED_CONFIG_${config}) + set(CMAKE_MAP_IMPORTED_CONFIG_${config} ${OSVR_OLD_CMAKE_MAP_IMPORTED_CONFIG_${config}}) + unset(OSVR_OLD_CMAKE_MAP_IMPORTED_CONFIG_${config}) + else() + unset(CMAKE_MAP_IMPORTED_CONFIG_${config}) + endif() +endmacro() + +macro(osvr_stash_common_map_config) + if(MSVC) + # Can't do this - different runtimes, incompatible ABI, etc. + set(OSVR_DEBUG_FALLBACK) + osvr_stash_map_config(DEBUG DEBUG) + else() + set(OSVR_DEBUG_FALLBACK DEBUG) + osvr_stash_map_config(DEBUG DEBUG RELWITHDEBINFO RELEASE MINSIZEREL NONE) + endif() + osvr_stash_map_config(RELEASE RELEASE RELWITHDEBINFO MINSIZEREL NONE ${OSVR_DEBUG_FALLBACK}) + osvr_stash_map_config(RELWITHDEBINFO RELWITHDEBINFO RELEASE MINSIZEREL NONE ${OSVR_DEBUG_FALLBACK}) + osvr_stash_map_config(MINSIZEREL MINSIZEREL RELEASE RELWITHDEBINFO NONE ${OSVR_DEBUG_FALLBACK}) + osvr_stash_map_config(NONE NONE RELEASE RELWITHDEBINFO MINSIZEREL ${OSVR_DEBUG_FALLBACK}) +endmacro() + +macro(osvr_unstash_common_map_config) + osvr_unstash_map_config(DEBUG) + osvr_unstash_map_config(RELEASE) + osvr_unstash_map_config(RELWITHDEBINFO) + osvr_unstash_map_config(MINSIZEREL) + osvr_unstash_map_config(NONE) +endmacro()