diff --git a/.travis.yml b/.travis.yml index 397fb06b..0f431c19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,5 +14,6 @@ before_install: - sudo apt-get install -qq git || /bin/true - sudo apt-get install -qq libgl1-mesa-dev || /bin/true - sudo apt-get install -qq libglewmx1.6-dev || /bin/true + - sudo apt-get install -qq libxxf86vm-dev || /bin/true - sudo chmod +x external/setup-travis.sh - external/setup-travis.sh diff --git a/Authors.txt b/Authors.txt index 9fcde771..554d6a47 100644 --- a/Authors.txt +++ b/Authors.txt @@ -1,10 +1,11 @@ INSTITUTIONS --------------------------------------- Work on Omegalib core and modules was supported by the following institutions: - The Electronic Visualization Lab, University of Illinois at Chicago - Northwestern University, Chicago - Monash University, Melbourne - Politecnico di Milano, Milan + The Electronic Visualization Lab at the University of Illinois at Chicago, Chicago, US + Northwestern University, Evanston, US + Monash University, Melbourne, Australia + Politecnico di Milano, Milan, Italy + Center for Visual Computing at Stony Brook University, Stony Brook, US AUTHORS @@ -13,28 +14,31 @@ Lead Developer: Alessandro Febretti Contributors: - Arthur Nishimoto + Dennis Chau Victor Mateviitsi + Koosha Mirhosseini Brad McGinnis - Dennis Chau + Arthur Nishimoto JD Pirtle + Qi Sun Module Contributors: - Jason Leigh - Andrew Johnson - Thomas Marrinan David Barnes + Daniele Donghi + Andrew Johnson Owen Kaluza Andreas Limbera - Daniele Donghi + Jason Leigh + Thomas Marrinan + Matt McCrory Alex Simes Patch Contributors: - Shi Yin - Cai Shanli J Markus Maunus Jonathan Khoo + Cai Shanli Connor Taffe + Shi Yin Academic Supervisors: Andrew Johnson diff --git a/CMakeLists.txt b/CMakeLists.txt index fb094904..f9157bff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,13 @@ execute_process( OUTPUT_VARIABLE GIT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE ) - +if(CMAKE_GENERATOR STREQUAL "Xcode") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++" CACHE STRING "" FORCE) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -stdlib=libstdc++" CACHE STRING "" FORCE) + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libstdc++" CACHE STRING "" FORCE) + SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -stdlib=libstdc++" CACHE STRING "" FORCE) + SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libstdc++" CACHE STRING "" FORCE) +endif(CMAKE_GENERATOR STREQUAL "Xcode") #------------------------------------------------------------------------------- # Create a build name depending on the OS, Toolset and architecture. if(CMAKE_GENERATOR STREQUAL "Visual Studio 9 2008") diff --git a/README.md b/README.md index 92fa87f5..04c11023 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ -A framework for virtual reality and cluster-driven display systems. +A hybrid visualization framework for desktops, large immersive displays and the web. - Intro page: http://uic-evl.github.io/omegalib/ - Wiki: https://github.com/uic-evl/omegalib/wiki diff --git a/external/UseEqualizer.cmake b/external/UseEqualizer.cmake index f23cd72d..76ce4fea 100644 --- a/external/UseEqualizer.cmake +++ b/external/UseEqualizer.cmake @@ -2,6 +2,7 @@ set(EQUALIZER_BASE_DIR ${CMAKE_BINARY_DIR}/3rdparty/equalizer) # Equalizer support enabled: uncompress and prepare the external project. if(APPLE) + string(REGEX MATCH "[0-9]+\\.[0-9]+" OSX_FAMILY ${CURRENT_OSX_VERSION} ) ExternalProject_Add( equalizer URL http://github.com/omega-hub/Equalizer-1.0.2/archive/master.tar.gz @@ -12,14 +13,14 @@ if(APPLE) -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} -DCMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} #-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE:PATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE} - -DCMAKE_OSX_SYSROOT:PATH=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${CURRENT_OSX_VERSION}.sdk - -DCMAKE_OSX_DEPLOYMENT_TARGET:VAR=${CURRENT_OSX_VERSION} + -DCMAKE_OSX_SYSROOT:PATH=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${OSX_FAMILY}.sdk + -DCMAKE_OSX_DEPLOYMENT_TARGET:VAR=${OSX_FAMILY} -DEQUALIZER_PREFER_AGL:BOOL=OFF -DEQUALIZER_USE_CUDA:BOOL=OFF -DEQUALIZER_USE_BOOST:BOOL=OFF -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} INSTALL_COMMAND "" - PATCH_COMMAND patch -p1 < ${CMAKE_SOURCE_DIR}/external/equalizer.${CURRENT_OSX_VERSION}.patch + PATCH_COMMAND patch -p1 < ${CMAKE_SOURCE_DIR}/external/equalizer.${OSX_FAMILY}.patch # directories TMP_DIR ${CMAKE_BINARY_DIR}/3rdparty/tmp STAMP_DIR ${CMAKE_BINARY_DIR}/3rdparty/stamp @@ -79,14 +80,18 @@ if(WIN32) else() if(APPLE) - set(EQUALIZER_EQ_LIB_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libEqualizer.dylib) - set(EQUALIZER_CO_LIB_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libCollage.dylib) + set(EQUALIZER_EQ_LIB_DEBUG debug ${EQUALIZER_BINARY_DIR}/libs/client/Debug/libEqualizer.dylib) + set(EQUALIZER_CO_LIB_DEBUG debug ${EQUALIZER_BINARY_DIR}/libs/collage/Debug/libCollage.dylib) + set(EQUALIZER_EQ_LIB_RELEASE optimized ${EQUALIZER_BINARY_DIR}/libs/client/Release/libEqualizer.dylib) + set(EQUALIZER_CO_LIB_RELEASE optimized ${EQUALIZER_BINARY_DIR}/libs/collage/Release/libCollage.dylib) else() set(EQUALIZER_EQ_LIB_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libEqualizer.so) set(EQUALIZER_CO_LIB_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libCollage.so) + set(EQUALIZER_EQ_LIB_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libEqualizer.so) + set(EQUALIZER_CO_LIB_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libCollage.so) endif() set(EQUALIZER_LIBS_DEBUG ${EQUALIZER_EQ_LIB_DEBUG} ${EQUALIZER_CO_LIB_DEBUG}) - set(EQUALIZER_LIBS_RELEASE ${EQUALIZER_EQ_LIB_DEBUG} ${EQUALIZER_CO_LIB_DEBUG}) + set(EQUALIZER_LIBS_RELEASE ${EQUALIZER_EQ_LIB_RELEASE} ${EQUALIZER_CO_LIB_RELEASE}) endif() set(EQUALIZER_LIBS ${EQUALIZER_LIBS_DEBUG} ${EQUALIZER_LIBS_RELEASE}) set(EQUALIZER_INCLUDES ${EQUALIZER_BINARY_DIR}/include) diff --git a/external/UseOmicron.cmake b/external/UseOmicron.cmake index 5d5164a5..2480300a 100644 --- a/external/UseOmicron.cmake +++ b/external/UseOmicron.cmake @@ -82,14 +82,19 @@ else() ################################################################################################### # Set the output directories for libraries and binary files - if(MSVC OR CMAKE_GENERATOR STREQUAL "Xcode") + if(MSVC) # omicron set(OMICRON_LIB_DEBUG ${OMICRON_LIB_DIR_DEBUG}/omicron.lib) set(OMICRON_LIB_RELEASE ${OMICRON_LIB_DIR_RELEASE}/omicron.lib) else() if(APPLE) - set(OMICRON_LIB_DEBUG ${OMICRON_BIN_DIR}/libomicron.dylib) - set(OMICRON_LIB_RELEASE ${OMICRON_BIN_DIR}/libomicron.dylib) + if(CMAKE_GENERATOR STREQUAL "Xcode") + set(OMICRON_LIB_DEBUG ${OMICRON_BIN_DIR}/debug/libomicron.dylib) + set(OMICRON_LIB_RELEASE ${OMICRON_BIN_DIR}/release/libomicron.dylib) + else(CMAKE_GENERATOR STREQUAL "Xcode") + set(OMICRON_LIB_DEBUG ${OMICRON_BIN_DIR}/libomicron.dylib) + set(OMICRON_LIB_RELEASE ${OMICRON_BIN_DIR}/libomicron.dylib) + endif(CMAKE_GENERATOR STREQUAL "Xcode") else(APPLE) set(OMICRON_LIB_DEBUG ${OMICRON_BIN_DIR}/libomicron.so) set(OMICRON_LIB_RELEASE ${OMICRON_BIN_DIR}/libomicron.so) diff --git a/external/equalizer.10.10.patch b/external/equalizer.10.10.patch index 6bb72edd..bb39b723 100644 --- a/external/equalizer.10.10.patch +++ b/external/equalizer.10.10.patch @@ -20,13 +20,20 @@ diff -Naur Equalizer-1.0.2/CMake/Equalizer.spec equalizer/CMake/Equalizer.spec diff -Naur Equalizer-1.0.2/CMakeLists.txt equalizer/CMakeLists.txt --- Equalizer-1.0.2/CMakeLists.txt 2013-04-01 15:38:52.000000000 -0500 +++ equalizer/CMakeLists.txt 2014-03-13 17:29:21.000000000 -0500 -@@ -137,17 +137,17 @@ +@@ -137,17 +137,24 @@ if(X11_FOUND) if(APPLE) set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ") # Disabled by GNU.cmake!? - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.6" ) - if(EXISTS /Developer/SDKs/MacOSX10.6.sdk) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.6 -stdlib=libstdc++" ) ++ if(CMAKE_GENERATOR STREQUAL "Xcode") ++ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++" CACHE STRING "" FORCE) ++ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -stdlib=libstdc++" CACHE STRING "" FORCE) ++ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libstdc++" CACHE STRING "" FORCE) ++ SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -stdlib=libstdc++" CACHE STRING "" FORCE) ++ SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libstdc++" CACHE STRING "" FORCE) ++ endif(CMAKE_GENERATOR STREQUAL "Xcode") + if(EXISTS /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk) if(EQUALIZER_PREFER_AGL) set(EQ_AGL_USED 1) @@ -42,7 +49,7 @@ diff -Naur Equalizer-1.0.2/CMakeLists.txt equalizer/CMakeLists.txt else(APPLE) set(EQ_GLX_USED 1) endif(APPLE) -@@ -191,7 +191,7 @@ +@@ -191,7 +198,7 @@ if(_CMAKE_OSX_MACHINE MATCHES "ppc") set(CMAKE_OSX_ARCHITECTURES "ppc") else() @@ -51,7 +58,7 @@ diff -Naur Equalizer-1.0.2/CMakeLists.txt equalizer/CMakeLists.txt endif() endif() set(CUDA_64_BIT_DEVICE_CODE OFF) -@@ -219,7 +219,7 @@ +@@ -219,7 +226,7 @@ set(EQ_DEFINITIONS -DEQ_BUILD_DIR="${CMAKE_BINARY_DIR}/" -DEQ_SOURCE_DIR="${CMAKE_SOURCE_DIR}/") if(EQUALIZER_RELEASE) set(EQ_DEFINITIONS ${EQ_DEFINITIONS} -DEQ_RELEASE) diff --git a/include/omega/ApplicationBase.h b/include/omega/ApplicationBase.h index ea0911df..fc9b0117 100644 --- a/include/omega/ApplicationBase.h +++ b/include/omega/ApplicationBase.h @@ -69,12 +69,23 @@ namespace omega // Some useful properties parsed from the command line or settable by // an application before calling omain + //!! Application interactive mode + enum InteractiveMode + { + //!! Use the interactive mode specified in the configuration filesyn s + FromConfig, + //!! Force interactive mode + Interactive, + //! Force non-interactive mode + NonInteractive + }; + //! Runs the program in interactive mode, even if the script console //! is not enabled in the system configuration - bool interactive; + InteractiveMode interactive; public: - ApplicationBase() : interactive(false) {} + ApplicationBase() : interactive(FromConfig) {} virtual const char* getName() { return "OmegaLib"; } virtual void setName(const String& name) = 0; diff --git a/include/omega/Camera.h b/include/omega/Camera.h index c31011cc..c200c810 100644 --- a/include/omega/Camera.h +++ b/include/omega/Camera.h @@ -54,7 +54,7 @@ namespace omega { //! Implements a listener that can be attached to cameras to listen to draw //! methods. All user method implementations must be reentrant, since they //! can be called from mulitple threads. - class ICameraListener + class OMEGA_API ICameraListener { public: virtual void endDraw(Camera* cam, DrawContext& context) {} @@ -75,6 +75,7 @@ namespace omega { { DrawScene = 1 << 1, DrawOverlay = 1 << 2, + CullingEnabled = 1 << 3, DefaultFlags = DrawScene | DrawOverlay }; @@ -122,6 +123,14 @@ namespace omega { //! this camera. Set to true by default. void setOverlayEnabled(bool value); bool isOverlayEnabled(); + //! When set to false, disables all culling for this camera. + //! All drawables will attempt drawing, even the ones that + //! are outside of this camera frustum. + //! This is useful to force drawing of all objects when we want to + //! use vertex shaders with custom projections. + //! By default, culling is enabled. + void setCullingEnabled(bool value); + bool isCullingEnabled(); //@} //! Navigation management @@ -144,6 +153,10 @@ namespace omega { //! render. If it's enabled it will still be checked agains the active //! draw context. void setEnabled(bool value); + //! Returns true if the frame is enabled, false otherwise + //! @remarks even if the camera is enabled, this method can return + //! false if on-demand frame drawing is on and the camera is not + //! currently scheduled to draw a frame bool isEnabled(); //! Observer control @@ -209,6 +222,20 @@ namespace omega { bool isClearDepthEnabled() { return myClearDepth; } //@} + //! On-demand drawing + //@{ + //! Queues one frame for drawing. Use this to force a frame + //! draw when MaxFps is set to 0. + void queueFrameDraw(); + //! Set the maximum fps that this camera will render at. + //! Use 0 to stop camera drawing and use queueFrameDraw to + //! draw frames on-demand. + //! Use -1 to disable the fps cap and let this camera draw + //! at the maximum renderer speed (typically 60fps) + void setMaxFps(float fps); + float getMaxFps(); + //@} + //! DEPRECATED //@{ Vector3f localToWorldPosition(const Vector3f& position); @@ -299,6 +326,11 @@ namespace omega { Vector3f myCanvasPosition; Quaternion myCanvasOrientation; Vector3f myCanvasScale; + + // On-demand drawing + bool myDrawNextFrame; + float myMaxFps; + float myTimeSinceLastFrame; }; /////////////////////////////////////////////////////////////////////////// @@ -373,7 +405,7 @@ namespace omega { /////////////////////////////////////////////////////////////////////////// inline bool Camera::isEnabled() - { return myEnabled; } + { return myEnabled && (myDrawNextFrame || myMaxFps < 0); } /////////////////////////////////////////////////////////////////////////// inline void Camera::setSceneEnabled(bool value) @@ -391,6 +423,18 @@ namespace omega { inline bool Camera::isOverlayEnabled() { return myFlags & DrawOverlay; } + /////////////////////////////////////////////////////////////////////////// + inline void Camera::setCullingEnabled(bool value) + { + if(value) myFlags |= CullingEnabled; else myFlags &= ~CullingEnabled; + } + + /////////////////////////////////////////////////////////////////////////// + inline bool Camera::isCullingEnabled() + { + return myFlags & CullingEnabled; + } + /////////////////////////////////////////////////////////////////////////// inline const Vector3f& Camera::getCanvasPosition() const { return myCanvasPosition; } @@ -403,6 +447,19 @@ namespace omega { inline const Vector3f& Camera::getCanvasScale() const { return myCanvasScale; } + /////////////////////////////////////////////////////////////////////////// + inline void Camera::queueFrameDraw() + { myDrawNextFrame = true; } + + /////////////////////////////////////////////////////////////////////////// + inline void Camera::setMaxFps(float fps) + { myMaxFps = fps; } + + /////////////////////////////////////////////////////////////////////////// + inline float Camera::getMaxFps() + { return myMaxFps; } + + }; // namespace omega #endif diff --git a/include/omega/DisplayTileConfig.h b/include/omega/DisplayTileConfig.h index 08faf0de..fb7c8151 100644 --- a/include/omega/DisplayTileConfig.h +++ b/include/omega/DisplayTileConfig.h @@ -5,6 +5,7 @@ * University of Illinois at Chicago * Authors: * Alessandro Febretti febret@gmail.com + * Koosha Mirhosseini koosha.mirhosseini@gmail.com *----------------------------------------------------------------------------- * Copyright (c) 2010-2015, Electronic Visualization Laboratory, * University of Illinois at Chicago @@ -63,7 +64,7 @@ namespace omega class OMEGA_API DisplayTileConfig: public ReferenceType { public: - enum StereoMode { Mono, LineInterleaved, ColumnInterleaved, PixelInterleaved, SideBySide, Default }; + enum StereoMode { Mono, LineInterleaved, ColumnInterleaved, PixelInterleaved, SideBySide, Quad, Default }; DisplayTileConfig(DisplayConfig& dc) : displayConfig(dc), diff --git a/include/omega/DrawContext.h b/include/omega/DrawContext.h index 3635b07e..89b6c5ad 100644 --- a/include/omega/DrawContext.h +++ b/include/omega/DrawContext.h @@ -5,6 +5,7 @@ * University of Illinois at Chicago * Authors: * Alessandro Febretti febret@gmail.com + * Koosha Mirhosseini koosha.mirhosseini@gmail.com *----------------------------------------------------------------------------- * Copyright (c) 2010-2015, Electronic Visualization Laboratory, * University of Illinois at Chicago @@ -110,7 +111,10 @@ namespace omega //! viewport, active eye and stereo settings. void updateViewport(); void setupInterleaver(); + void setupStereo(); void initializeStencilInterleaver(); + void initializeQuad(); + DisplayTileConfig::StereoMode getCurrentStereoMode(); @@ -127,6 +131,7 @@ namespace omega //! sure OS windows and frame buffers have been updated before a stencil //! mask update. short stencilInitialized; + short quadInitialized; int stencilMaskWidth; int stencilMaskHeight; diff --git a/include/omega/MissionControl.h b/include/omega/MissionControl.h index 929b79f0..95ebf525 100644 --- a/include/omega/MissionControl.h +++ b/include/omega/MissionControl.h @@ -137,7 +137,7 @@ namespace omega { MissionControlConnection( ConnectionInfo ci, IMissionControlMessageHandler* msgHandler, MissionControlServer* server); - virtual ~MissionControlConnection() {} + virtual ~MissionControlConnection(); virtual void handleData(); virtual void handleClosed(); @@ -155,8 +155,8 @@ namespace omega { void setLogForwardingEnabled(bool value); private: - static const int BufferSize = 1024; - char myBuffer[BufferSize]; + char* myBuffer; + uint myBufferSize; MissionControlServer* myServer; MissionControlConnection* myRecipient; // Message destination when private-message mode is enabled. IMissionControlMessageHandler* myMessageHandler; diff --git a/include/omegaToolkit/ui/Container.h b/include/omegaToolkit/ui/Container.h index bec335c9..dcf18a8f 100644 --- a/include/omegaToolkit/ui/Container.h +++ b/include/omegaToolkit/ui/Container.h @@ -1,286 +1,292 @@ -/****************************************************************************** - * THE OMEGA LIB PROJECT - *----------------------------------------------------------------------------- - * Copyright 2010-2015 Electronic Visualization Laboratory, - * University of Illinois at Chicago - * Authors: - * Alessandro Febretti febret@gmail.com - *----------------------------------------------------------------------------- - * Copyright (c) 2010-2015, Electronic Visualization Laboratory, - * University of Illinois at Chicago - * All rights reserved. - * 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. - * - * 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 OWNER 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. - *----------------------------------------------------------------------------- - * What's in this file: - * A container of widgets that supports automatic layout - ******************************************************************************/ -#ifndef __CONTAINER_H__ -#define __CONTAINER_H__ - -#include "omegaToolkit/ui/Widget.h" -#include "omegaToolkit/UiRenderPass.h" - -namespace omegaToolkit { namespace ui { - - //////////////////////////////////////////////////////////////////////////// - struct Container3dSettings - { - Container3dSettings(): - enable3d(false), - center(false), - node(NULL), - position(Vector3f::Zero()), - normal(Vector3f::UnitZ()), - up(Vector3f::UnitY()), - // The default scale is based on common display dot pitch, so that 3d uis drawn on - // display plane will be about the same size of corresponding 2d ui. - scale(0.002f), alpha(1.0) {} - - bool enable3d; - Vector3f position; - Vector3f normal; - Vector3f up; - - float alpha; - bool center; - - //! The 3d scale is the conversion factor between pixel sizes and world units. - //! For example, a 100x300 pixel container with a scale of 0.01 will be drawn as a - // billboard 1x3 meters big in 3d mode. - float scale; - - //! node is used to make transforms relative to a scene node. - SceneNode* node; - }; - - //////////////////////////////////////////////////////////////////////////// - class OTK_API Container: public Widget - { - //friend class Engine; - friend class ContainerRenderable; - friend class UiRenderPass; - public: - enum Layout {LayoutFree, LayoutHorizontal, LayoutVertical, LayoutGridHorizontal, LayoutGridVertical}; - enum HorizontalAlign { AlignRight, AlignLeft, AlignCenter}; - enum VerticalAlign { AlignTop, AlignMiddle, AlignBottom}; - - static Container* create(Layout layout, Container* parent); - - public: - Container(Engine* server); - virtual ~Container(); - - virtual Renderable* createRenderable(); - - virtual void handleEvent(const omega::Event& evt); - virtual void update(const omega::UpdateContext& context); - - void load(Setting& setting); - - //! Child management - //@{ - //! Add a child to this widget. - void addChild(Widget* child); - //! Remove a child from this widget. - void removeChild(Widget* child); - //! Return the number of children - int getNumChildren(); - //! Find a child by its name - Widget* getChildByName(const String& name); - Widget* getChildByIndex(int index); - Widget* getChildBefore(const Widget* w); - Widget* getChildAfter(const Widget* w); - //@} - - //!Layout options - //@{ - void setLayout(Layout layout); - Layout getLayout(); - //! Sets the margin between the container's content and its borders. - void setPadding(float value); - float getPadding(); - //! Sets the padding space between elements within the container. - void setMargin(float value); - float getMargin(); - HorizontalAlign getHorizontalAlign(); - void setHorizontalAlign(HorizontalAlign value); - VerticalAlign getVerticalAlign(); - void setVerticalAlign(VerticalAlign value); - int getGridRows(); - int getGridColumns(); - void setGridRows(int value); - void setGridColumns(int value); - bool isClippingEnabled(); - void setClippingEnabled(bool value); - //@} - - //! Returns true if the event happens within the container boundaries. This method - //! supports all pointer and ray-generating events, and works with 2D and 3D mode containers. - bool isEventInside(const Event& evt); - //! For 3D mode containers: converts a ray event to a pointer event with 2D coordintes in the container coordinate space. - //! Returns true if the event happens within the container boundaries, and could be converted to a pointer event successfully. - bool rayToPointerEvent(const Event& inEvt, Event& outEvt); - - virtual void layout(); - - //! Gets the container 3d settings. - Container3dSettings& get3dSettings() { return my3dSettings; } - //! Returns true if this widget is part of a container that will be drawn - //! in 3D mode. - virtual bool isIn3DContainer(); - - virtual void updateSize(); - virtual void autosize(); - - //! Pixel output - //@{ - bool isPixelOutputEnabled(); - void setPixelOutputEnabled(bool value); - PixelData* getPixels(); - //@} - - //! Recomputes navigation links for widgets in this container. - //! Only enabled widgets take part in navigation. - void updateChildrenNavigation(); - - protected: - virtual void activate(); - - private: - int expandStep(int childSpace, Orientation orientation); - void updateChildrenLayoutPosition(Orientation orientation); - void updateChildrenFreeBounds(Orientation orientation); - void resetChildrenSize(Orientation orientation); - void computeLinearLayout(Orientation orientation); - void computeGridLayout(Orientation orientation); - - protected: - List< Ref > myChildren; - List myChildrenToRemove; - - Layout myLayout; - float myPadding; - float myMargin; - int myGridRows; - int myGridColumns; - HorizontalAlign myHorizontalAlign; - VerticalAlign myVerticalAlign; - bool myClipping; - - Container3dSettings my3dSettings; - - Ref myPixels; - bool myPixelOutputEnabled; - }; - - //////////////////////////////////////////////////////////////////////////// - class OTK_API ContainerRenderable: public WidgetRenderable - { - public: - ContainerRenderable(Container* owner): WidgetRenderable(owner), myOwner(owner), myRenderTarget(NULL), myTexture(NULL) {} - virtual void draw(const DrawContext& context); - - protected: - void draw3d(const DrawContext& context); - void drawChildren(const DrawContext& context, bool containerOnly); - void beginDraw(const DrawContext& context); - void endDraw(const DrawContext& context); - - private: - // We use a raw pointer here to avoid cyclic references. - Container* myOwner; - - // Stuff used for 3d ui rendering. - Ref myRenderTarget; - Ref myTexture; - }; - - //////////////////////////////////////////////////////////////////////////// - inline int Container::getNumChildren() - { return myChildren.size(); } - - //////////////////////////////////////////////////////////////////////////// - inline void Container::setLayout(Layout layout) - { - myLayout = layout; updateChildrenNavigation(); - } - - //////////////////////////////////////////////////////////////////////////// - inline Container::Layout Container::getLayout() - { return myLayout; } - - //////////////////////////////////////////////////////////////////////////// - inline float Container::getPadding() - { return myPadding; } - - //////////////////////////////////////////////////////////////////////////// - inline float Container::getMargin() - { return myMargin; } - - //////////////////////////////////////////////////////////////////////////// - inline void Container::setPadding(float value) - { myPadding = value; requestLayoutRefresh(); } - - //////////////////////////////////////////////////////////////////////////// - inline void Container::setMargin(float value) - { myMargin = value; requestLayoutRefresh(); } - - //////////////////////////////////////////////////////////////////////////// - inline Container::HorizontalAlign Container::getHorizontalAlign() - { return myHorizontalAlign; } - - //////////////////////////////////////////////////////////////////////////// - inline void Container::setHorizontalAlign(HorizontalAlign value) - { myHorizontalAlign = value; requestLayoutRefresh();} - - //////////////////////////////////////////////////////////////////////////// - inline Container::VerticalAlign Container::getVerticalAlign() - { return myVerticalAlign; } - - //////////////////////////////////////////////////////////////////////////// - inline void Container::setVerticalAlign(VerticalAlign value) - { myVerticalAlign = value; requestLayoutRefresh();} - - //////////////////////////////////////////////////////////////////////////// - inline int Container::getGridRows() - { return myGridRows; } - - //////////////////////////////////////////////////////////////////////////// - inline int Container::getGridColumns() - { return myGridColumns; } - - //////////////////////////////////////////////////////////////////////////// - inline void Container::setGridRows(int value) - { myGridRows = value; } - - //////////////////////////////////////////////////////////////////////////// - inline void Container::setGridColumns(int value) - { myGridColumns = value; } - - /////////////////////////////////////////////////////////////////////////// - inline bool Container::isIn3DContainer() - { - if(my3dSettings.enable3d) return true; - if(myContainer != NULL) return myContainer->isIn3DContainer(); - return false; - } -};}; +/****************************************************************************** + * THE OMEGA LIB PROJECT + *----------------------------------------------------------------------------- + * Copyright 2010-2015 Electronic Visualization Laboratory, + * University of Illinois at Chicago + * Authors: + * Alessandro Febretti febret@gmail.com + *----------------------------------------------------------------------------- + * Copyright (c) 2010-2015, Electronic Visualization Laboratory, + * University of Illinois at Chicago + * All rights reserved. + * 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. + * + * 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 OWNER 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. + *----------------------------------------------------------------------------- + * What's in this file: + * A container of widgets that supports automatic layout + ******************************************************************************/ +#ifndef __CONTAINER_H__ +#define __CONTAINER_H__ + +#include "omegaToolkit/ui/Widget.h" +#include "omegaToolkit/UiRenderPass.h" + +namespace omegaToolkit { namespace ui { + + //////////////////////////////////////////////////////////////////////////// + struct Container3dSettings + { + Container3dSettings(): + enable3d(false), + center(false), + wandPointerEnabled(false), + node(NULL), + position(Vector3f::Zero()), + normal(Vector3f::UnitZ()), + up(Vector3f::UnitY()), + // The default scale is based on common display dot pitch, so that 3d uis drawn on + // display plane will be about the same size of corresponding 2d ui. + scale(0.002f), alpha(1.0) {} + + bool enable3d; + Vector3f position; + Vector3f normal; + Vector3f up; + + float alpha; + bool center; + + //! The 3d scale is the conversion factor between pixel sizes and world units. + //! For example, a 100x300 pixel container with a scale of 0.01 will be drawn as a + // billboard 1x3 meters big in 3d mode. + float scale; + + //! node is used to make transforms relative to a scene node. + SceneNode* node; + + //! when set to true and pointer interaction is enabled, a 3D wand will be + //! used as a pointer device to interact with this container. + //! @default false + bool wandPointerEnabled; + }; + + //////////////////////////////////////////////////////////////////////////// + class OTK_API Container: public Widget + { + //friend class Engine; + friend class ContainerRenderable; + friend class UiRenderPass; + public: + enum Layout {LayoutFree, LayoutHorizontal, LayoutVertical, LayoutGridHorizontal, LayoutGridVertical}; + enum HorizontalAlign { AlignRight, AlignLeft, AlignCenter}; + enum VerticalAlign { AlignTop, AlignMiddle, AlignBottom}; + + static Container* create(Layout layout, Container* parent); + + public: + Container(Engine* server); + virtual ~Container(); + + virtual Renderable* createRenderable(); + + virtual void handleEvent(const omega::Event& evt); + virtual void update(const omega::UpdateContext& context); + + void load(Setting& setting); + + //! Child management + //@{ + //! Add a child to this widget. + void addChild(Widget* child); + //! Remove a child from this widget. + void removeChild(Widget* child); + //! Return the number of children + int getNumChildren(); + //! Find a child by its name + Widget* getChildByName(const String& name); + Widget* getChildByIndex(int index); + Widget* getChildBefore(const Widget* w); + Widget* getChildAfter(const Widget* w); + //@} + + //!Layout options + //@{ + void setLayout(Layout layout); + Layout getLayout(); + //! Sets the margin between the container's content and its borders. + void setPadding(float value); + float getPadding(); + //! Sets the padding space between elements within the container. + void setMargin(float value); + float getMargin(); + HorizontalAlign getHorizontalAlign(); + void setHorizontalAlign(HorizontalAlign value); + VerticalAlign getVerticalAlign(); + void setVerticalAlign(VerticalAlign value); + int getGridRows(); + int getGridColumns(); + void setGridRows(int value); + void setGridColumns(int value); + bool isClippingEnabled(); + void setClippingEnabled(bool value); + //@} + + //! Returns true if the event happens within the container boundaries. This method + //! supports all pointer and ray-generating events, and works with 2D and 3D mode containers. + bool isEventInside(const Event& evt); + //! For 3D mode containers: converts a ray event to a pointer event with 2D coordintes in the container coordinate space. + //! Returns true if the event happens within the container boundaries, and could be converted to a pointer event successfully. + bool rayToPointerEvent(const Event& inEvt, Event& outEvt); + + virtual void layout(); + + //! Gets the container 3d settings. + Container3dSettings& get3dSettings() { return my3dSettings; } + //! Returns true if this widget is part of a container that will be drawn + //! in 3D mode. + virtual bool isIn3DContainer(); + + virtual void updateSize(); + virtual void autosize(); + + //! Pixel output + //@{ + bool isPixelOutputEnabled(); + void setPixelOutputEnabled(bool value); + PixelData* getPixels(); + //@} + + //! Recomputes navigation links for widgets in this container. + //! Only enabled widgets take part in navigation. + void updateChildrenNavigation(); + + protected: + virtual void activate(); + + private: + int expandStep(int childSpace, Orientation orientation); + void updateChildrenLayoutPosition(Orientation orientation); + void updateChildrenFreeBounds(Orientation orientation); + void resetChildrenSize(Orientation orientation); + void computeLinearLayout(Orientation orientation); + void computeGridLayout(Orientation orientation); + + protected: + List< Ref > myChildren; + List myChildrenToRemove; + + Layout myLayout; + float myPadding; + float myMargin; + int myGridRows; + int myGridColumns; + HorizontalAlign myHorizontalAlign; + VerticalAlign myVerticalAlign; + bool myClipping; + + Container3dSettings my3dSettings; + + Ref myPixels; + bool myPixelOutputEnabled; + }; + + //////////////////////////////////////////////////////////////////////////// + class OTK_API ContainerRenderable: public WidgetRenderable + { + public: + ContainerRenderable(Container* owner): WidgetRenderable(owner), myOwner(owner), myRenderTarget(NULL), myTexture(NULL) {} + virtual void draw(const DrawContext& context); + + protected: + void draw3d(const DrawContext& context); + void drawChildren(const DrawContext& context, bool containerOnly); + void beginDraw(const DrawContext& context); + void endDraw(const DrawContext& context); + + private: + // We use a raw pointer here to avoid cyclic references. + Container* myOwner; + + // Stuff used for 3d ui rendering. + Ref myRenderTarget; + Ref myTexture; + }; + + //////////////////////////////////////////////////////////////////////////// + inline int Container::getNumChildren() + { return myChildren.size(); } + + //////////////////////////////////////////////////////////////////////////// + inline void Container::setLayout(Layout layout) + { + myLayout = layout; updateChildrenNavigation(); + } + + //////////////////////////////////////////////////////////////////////////// + inline Container::Layout Container::getLayout() + { return myLayout; } + + //////////////////////////////////////////////////////////////////////////// + inline float Container::getPadding() + { return myPadding; } + + //////////////////////////////////////////////////////////////////////////// + inline float Container::getMargin() + { return myMargin; } + + //////////////////////////////////////////////////////////////////////////// + inline void Container::setPadding(float value) + { myPadding = value; requestLayoutRefresh(); } + + //////////////////////////////////////////////////////////////////////////// + inline void Container::setMargin(float value) + { myMargin = value; requestLayoutRefresh(); } + + //////////////////////////////////////////////////////////////////////////// + inline Container::HorizontalAlign Container::getHorizontalAlign() + { return myHorizontalAlign; } + + //////////////////////////////////////////////////////////////////////////// + inline void Container::setHorizontalAlign(HorizontalAlign value) + { myHorizontalAlign = value; requestLayoutRefresh();} + + //////////////////////////////////////////////////////////////////////////// + inline Container::VerticalAlign Container::getVerticalAlign() + { return myVerticalAlign; } + + //////////////////////////////////////////////////////////////////////////// + inline void Container::setVerticalAlign(VerticalAlign value) + { myVerticalAlign = value; requestLayoutRefresh();} + + //////////////////////////////////////////////////////////////////////////// + inline int Container::getGridRows() + { return myGridRows; } + + //////////////////////////////////////////////////////////////////////////// + inline int Container::getGridColumns() + { return myGridColumns; } + + //////////////////////////////////////////////////////////////////////////// + inline void Container::setGridRows(int value) + { myGridRows = value; } + + //////////////////////////////////////////////////////////////////////////// + inline void Container::setGridColumns(int value) + { myGridColumns = value; } + + /////////////////////////////////////////////////////////////////////////// + inline bool Container::isIn3DContainer() + { + if(my3dSettings.enable3d) return true; + if(myContainer != NULL) return myContainer->isIn3DContainer(); + return false; + } +};}; #endif \ No newline at end of file diff --git a/include/version.h b/include/version.h index 8049ecfc..71daf232 100644 --- a/include/version.h +++ b/include/version.h @@ -1,8 +1,8 @@ #ifndef __OMEGA_VERSION_ #define __OMEGA_VERSION_ -#define OMEGA_VERSION_MAJOR 7 -#define OMEGA_VERSION_MINOR 2 +#define OMEGA_VERSION_MAJOR 9 +#define OMEGA_VERSION_MINOR 0 #define OMEGA_VERSION_REVISION 0 #define _VSTH(v) #v @@ -11,7 +11,7 @@ #define _WVSTH(v) L#v #define _WVERSTR(v) _WVSTH(v) -#if (OMEGA_VERSION_REV > 0) +#if (OMEGA_VERSION_REVISION > 0) #define OMEGA_VERSION _VERSTR(OMEGA_VERSION_MAJOR) "." _VERSTR(OMEGA_VERSION_MINOR) "." _VERSTR(OMEGA_VERSION_REVISION) #define OMEGA_WIDE_VERSION _WVERSTR(OMEGA_VERSION_MAJOR) L"." _WVERSTR(OMEGA_VERSION_MINOR) L"." _WVERSTR(OMEGA_VERSION_REVISION) #else diff --git a/modules/README.md b/modules/README.md index d8855a10..c2876d1b 100644 --- a/modules/README.md +++ b/modules/README.md @@ -12,7 +12,7 @@ Or using the **omegalib maintenance tools** (See omegalib main github page) >omega add [local install] [module name] ``` -For more information on how modules work read this wiki page: https://github.com/febret/omegalib/wiki/ExtendingOmegalib +For more information on how modules work read this wiki page: https://github.com/uic-evl/omegalib/wiki/Omegalib-modules ## The modules.py script > NOTE: modules.py is deprecated. Use the omega update and omega add maintenance tools diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 73617b13..4299ef65 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -194,6 +194,12 @@ if(MODULES_UPDATE_LIST) # This function contains all the module definitions and is defined in the hub CMakeListst file. process_omegalib_modules() + + #If we have a local module definition file, include it + if(EXISTS ${CMAKE_SOURCE_DIR}/modules/local_modules.cmake) + include(${CMAKE_SOURCE_DIR}/modules/local_modules.cmake) + endif() + #message("REGENERATE_REQUESTED ${REGENERATE_REQUESTED}") configure_file(${PACK_FILE}.in ${PACK_FILE} @ONLY) endwhile() diff --git a/src/displaySystems/GLFW/CMakeLists.txt b/src/displaySystems/GLFW/CMakeLists.txt index ec4c9208..0ffcc144 100644 --- a/src/displaySystems/GLFW/CMakeLists.txt +++ b/src/displaySystems/GLFW/CMakeLists.txt @@ -25,8 +25,15 @@ if(WIN32) debug ${GLFW_BASE_DIR}/build/src/Debug/glfw3.lib optimized ${GLFW_BASE_DIR}/build/src/Release/glfw3.lib ) -else() +elseif(CMAKE_GENERATOR STREQUAL "Xcode") + set(GLFW_LIBS + debug ${GLFW_BASE_DIR}/build/src/Debug/libglfw3.a + optimized ${GLFW_BASE_DIR}/build/src/Release/libglfw3.a + ) +elseif(APPLE) set(GLFW_LIBS ${GLFW_BASE_DIR}/build/src/libglfw3.a) +else() + set(GLFW_LIBS ${GLFW_BASE_DIR}/build/src/libglfw3.a -lXxf86vm -lXrandr -lXinerama -lXi -lXcursor) endif() # build displaySystem_GLFW diff --git a/src/displaySystems/GLFW/displaySystem_GLFW.cpp b/src/displaySystems/GLFW/displaySystem_GLFW.cpp index d5960f7e..0f3a71eb 100644 --- a/src/displaySystems/GLFW/displaySystem_GLFW.cpp +++ b/src/displaySystems/GLFW/displaySystem_GLFW.cpp @@ -174,7 +174,7 @@ void GLFWDisplaySystem::run() //glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE); DisplayTileConfig* tile = dcfg.tileGrid[0][0]; Vector2i& ws = tile->pixelSize; @@ -228,8 +228,17 @@ void GLFWDisplaySystem::run() im->unlockEvents(); } + // NULL here is needed so glfwMakeContextCurrent after update actually + // resets the context instead of just being a NOP. + // Note that we need to make sure the window / gl context are current + // because some modules (ie osgEarth) tinker with the context during + // initialization and lave it in an inconsistent state. + glfwMakeContextCurrent(NULL); + myEngine->update(uc); + glfwMakeContextCurrent(window); + // Handle window resize int width, height; glfwGetFramebufferSize(window, &width, &height); @@ -244,7 +253,13 @@ void GLFWDisplaySystem::run() tile->displayConfig.setCanvasRect(tile->activeCanvasRect); } myRenderer->prepare(dc); - dc.drawFrame(frame++); + + // Enable lighting by default (expected by native osg applications) + // We might want to move this into the omegaOsg render pass if this + // causes problems with other code. + glEnable(GL_LIGHTING); + + dc.drawFrame(frame++); glfwSwapBuffers(window); // Poll the service manager for new events. diff --git a/src/omega/Camera.cpp b/src/omega/Camera.cpp index 82c6cf62..cebd1304 100644 --- a/src/omega/Camera.cpp +++ b/src/omega/Camera.cpp @@ -75,13 +75,19 @@ Camera::Camera(Engine* e, uint flags): myBackgroundColor(Color(0.1f,0.1f, 0.15f, 1)), myCanvasOrientation(Quaternion::Identity()), myCanvasPosition(Vector3f::Zero()), - myCanvasScale(Vector3f::Ones()) + myCanvasScale(Vector3f::Ones()), + myDrawNextFrame(true), + myMaxFps(-1), + myTimeSinceLastFrame(0) { DisplaySystem* ds = SystemManager::instance()->getDisplaySystem(); myCustomTileConfig = new DisplayTileConfig(ds->getDisplayConfig()); // set camera Id and increment the counter this->myCameraId = omega::CamerasCounter++; + + // Culling always enabled by default + setCullingEnabled(true); } /////////////////////////////////////////////////////////////////////////////// @@ -189,6 +195,17 @@ void Camera::updateTraversal(const UpdateContext& context) AffineTransform3 t = AffineTransform3::Identity(); } + // Queue a frame draw if on-demand frame drawing is enabled + if(myMaxFps > 0) + { + myTimeSinceLastFrame += context.dt; + if(myTimeSinceLastFrame > (1.0f / myMaxFps)) + { + myTimeSinceLastFrame = 0; + myDrawNextFrame = true; + } + } + SceneNode::updateTraversal(context); } @@ -236,7 +253,7 @@ bool Camera::isEnabledInContext(const DrawContext& context) bool Camera::isEnabledInContext(DrawContext::Task task, const DisplayTileConfig* tile) { // If the camera is not enabled always return false. - if(!myEnabled) return false; + if(!isEnabled()) return false; // If the camera is not enabled for the current task, return false. if((task == DrawContext::SceneDrawTask && @@ -337,6 +354,9 @@ void Camera::finishFrame(const FrameInfo& frame) output->finishFrame(frame); } if(myListener != NULL) myListener->finishFrame(this, frame); + + // Reset on-demand draw frame flag. + myDrawNextFrame = false; } /////////////////////////////////////////////////////////////////////////////// @@ -352,6 +372,12 @@ void Camera::clear(DrawContext& context) context.camera = this; if(myCustomTileConfig->enabled) { + // If we are using a camera output AND a custom tile configuration, + // the tile pixel size is automatically set to the render target size. + if(output != NULL && output->isEnabled()) + { + myCustomTileConfig->pixelSize = output->getReadbackViewport().size(); + } context.pushTileConfig(myCustomTileConfig); } @@ -364,13 +390,13 @@ void Camera::clear(DrawContext& context) // together yet. If side-by-side stereo is enabled, it will override camera // viewport settings. context.updateViewport(); - glPushAttrib(GL_SCISSOR_BIT); glScissor( context.viewport.x(), context.viewport.y(), context.viewport.width(), context.viewport.height()); + oglError; if(rt != NULL) rt->bind(); diff --git a/src/omega/DisplayConfig.cpp b/src/omega/DisplayConfig.cpp index bab3c28c..44647870 100755 --- a/src/omega/DisplayConfig.cpp +++ b/src/omega/DisplayConfig.cpp @@ -5,6 +5,7 @@ * University of Illinois at Chicago * Authors: * Alessandro Febretti febret@gmail.com + * Koosha Mirhosseini koosha.mirhosseini@gmail.com *----------------------------------------------------------------------------- * Copyright (c) 2010-2015, Electronic Visualization Laboratory, * University of Illinois at Chicago @@ -73,6 +74,7 @@ void DisplayConfig::LoadConfig(Setting& scfg, DisplayConfig& cfg) else if(sm == "mono") cfg.stereoMode = DisplayTileConfig::Mono; // 'interleaved' defaults to row interleaved else if(sm == "interleaved") cfg.stereoMode = DisplayTileConfig::LineInterleaved; + else if(sm == "quad") cfg.stereoMode = DisplayTileConfig::Quad; else if(sm == "rowinterleaved") cfg.stereoMode = DisplayTileConfig::LineInterleaved; else if(sm == "sidebyside") cfg.stereoMode = DisplayTileConfig::SideBySide; else if(sm == "columninterleaved") cfg.stereoMode = DisplayTileConfig::ColumnInterleaved; diff --git a/src/omega/DrawContext.cpp b/src/omega/DrawContext.cpp index 9ebdcbb9..4d464456 100644 --- a/src/omega/DrawContext.cpp +++ b/src/omega/DrawContext.cpp @@ -5,6 +5,7 @@ * University of Illinois at Chicago * Authors: * Alessandro Febretti febret@gmail.com + * Koosha Mirhosseini koosha.mirhosseini@gmail.com *----------------------------------------------------------------------------- * Copyright (c) 2010-2015, Electronic Visualization Laboratory, * University of Illinois at Chicago @@ -42,6 +43,7 @@ using namespace omega; /////////////////////////////////////////////////////////////////////////////// DrawContext::DrawContext(): + quadInitialized(0), stencilInitialized(0), camera(NULL), stencilMaskWidth(0), @@ -164,6 +166,14 @@ void DrawContext::drawFrame(uint64 frameNum) } } + if(getCurrentStereoMode() == DisplayTileConfig::Quad) + { + if (quadInitialized == 0) + { + initializeQuad(); + } + } + if(getCurrentStereoMode() == DisplayTileConfig::Mono) { eye = DrawContext::EyeCyclop; @@ -174,6 +184,35 @@ void DrawContext::drawFrame(uint64 frameNum) task = DrawContext::OverlayDrawTask; renderer->draw(*this); } + else if(getCurrentStereoMode() == DisplayTileConfig::Quad) + { + // Draw left eye scene and overlay + glDrawBuffer(GL_BACK_LEFT); + glClear( GL_COLOR_BUFFER_BIT ); + glClear( GL_DEPTH_BUFFER_BIT ); + renderer->clear(*this); + eye = DrawContext::EyeLeft; + task = DrawContext::SceneDrawTask; + renderer->draw(*this); + task = DrawContext::OverlayDrawTask; + renderer->draw(*this); + + // Draw right eye scene and overlay + glDrawBuffer(GL_BACK_RIGHT); + glClear( GL_COLOR_BUFFER_BIT ); + glClear( GL_DEPTH_BUFFER_BIT ); + renderer->clear(*this); + eye = DrawContext::EyeRight; + task = DrawContext::SceneDrawTask; + renderer->draw(*this); + task = DrawContext::OverlayDrawTask; + renderer->draw(*this); + + // Draw mono overlay + eye = DrawContext::EyeCyclop; + task = DrawContext::OverlayDrawTask; + renderer->draw(*this); + } else { // Draw left eye scene and overlay @@ -284,6 +323,59 @@ void DrawContext::updateViewport() } } +/////////////////////////////////////////////////////////////////////////////// +void DrawContext::setupStereo() +{ + if (getCurrentStereoMode() == DisplayTileConfig::Quad) + { + DisplaySystem* ds = renderer->getDisplaySystem(); + DisplayConfig& dcfg = ds->getDisplayConfig(); + if(quadInitialized) + { + if(dcfg.forceMono || eye == DrawContext::EyeCyclop) + { + glDrawBuffer(GL_BACK); //to avoid interaction with quad content + } + else + { + if(eye == DrawContext::EyeLeft) + { + glDrawBuffer(GL_BACK_LEFT); + } + else if(eye == DrawContext::EyeRight) + { + glDrawBuffer(GL_BACK_RIGHT); + } + } + } + } + + else if (getCurrentStereoMode() == DisplayTileConfig::LineInterleaved) + { + DisplaySystem* ds = renderer->getDisplaySystem(); + DisplayConfig& dcfg = ds->getDisplayConfig(); + + if(stencilInitialized) + { + if(dcfg.forceMono || eye == DrawContext::EyeCyclop) + { + glStencilFunc(GL_ALWAYS,0x2,0x2); // to avoid interaction with stencil content + } + else + { + if(eye == DrawContext::EyeLeft) + { + glStencilFunc(GL_NOTEQUAL,0x2,0x2); // draws if stencil <> 1 + } + else if(eye == DrawContext::EyeRight) + { + glStencilFunc(GL_EQUAL,0x2,0x2); // draws if stencil <> 0 + } + } + } + } +} + /////////////////////////////////////////////////////////////////////////////// void DrawContext::setupInterleaver() { @@ -313,6 +405,29 @@ void DrawContext::setupInterleaver() } } +/////////////////////////////////////////////////////////////////////////////// +void DrawContext::initializeQuad() +{ + GLboolean g_valid3D = false; + glGetBooleanv(GL_STEREO, &g_valid3D); + + int gliWindowWidth = tile->activeRect.width(); + int gliWindowHeight = tile->activeRect.height(); + DisplaySystem* ds = renderer->getDisplaySystem(); + DisplayConfig& dcfg = ds->getDisplayConfig(); + + glViewport(0,0,gliWindowWidth,gliWindowHeight); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + if (g_valid3D) + { + glEnable(GL_STEREO); + } + quadInitialized = 1; +} + /////////////////////////////////////////////////////////////////////////////// void DrawContext::initializeStencilInterleaver() { diff --git a/src/omega/MissionControl.cpp b/src/omega/MissionControl.cpp index 861891e8..25e44d63 100644 --- a/src/omega/MissionControl.cpp +++ b/src/omega/MissionControl.cpp @@ -71,8 +71,17 @@ MissionControlConnection::MissionControlConnection(ConnectionInfo ci, IMissionCo myRecipient(NULL), myLogEnabled(false) { + // Set initial buffer size to 1k + myBufferSize = 1024; + myBuffer = (char*)malloc(myBufferSize); } - + +/////////////////////////////////////////////////////////////////////////////// +MissionControlConnection::~MissionControlConnection() +{ + free(myBuffer); + myBuffer = NULL; +} /////////////////////////////////////////////////////////////////////////////// void MissionControlConnection::setName(const String& name) @@ -106,6 +115,16 @@ void MissionControlConnection::handleData() read(myBuffer, 4); memcpy(&dataSize, myBuffer, 4); + // Do we need to resize the incoming data buffer? + if(myBufferSize < dataSize + 1) + { + myBufferSize = dataSize + 1; + oflog(Verbose, "[MissionControlConnection] %1%: resizing buffer to %2%", + %myName %myBufferSize); + free(myBuffer); + myBuffer = (char*)malloc(myBufferSize); + } + // Read data. read(myBuffer, dataSize); myBuffer[dataSize] = '\0'; @@ -289,12 +308,22 @@ void MissionControlServer::handleMessage(const char* header, void* data, int siz { *sp = '\0'; String clientId = &str[1]; + // If clientId ends with '*' we use clientId as a prefix to + // send a message to multiple clients. + bool prefix = false; + if(StringUtils::endsWith(clientId, "*")) + { + prefix = true; + *(sp - 1) = '\0'; + clientId = &str[1]; + } String cmd = (sp + 1); foreach(MissionControlConnection* conn, myConnections) { if(conn->getState() == TcpConnection::ConnectionOpen && conn != sender - && conn->getName() == clientId) + && ((conn->getName() == clientId) || + (prefix && StringUtils::startsWith(conn->getName(), clientId)))) { conn->sendMessage( header, diff --git a/src/omega/PythonInterpreter.cpp b/src/omega/PythonInterpreter.cpp index 985226dc..8696d9ff 100644 --- a/src/omega/PythonInterpreter.cpp +++ b/src/omega/PythonInterpreter.cpp @@ -38,6 +38,7 @@ #include "omega/ModuleServices.h" #include "omega/SystemManager.h" #include "omega/DisplaySystem.h" +#include "omega/MissionControl.h" using namespace omega; @@ -80,14 +81,18 @@ class PythonInteractiveThread: public Thread { PythonInterpreter* interp = SystemManager::instance()->getScriptInterpreter(); String prompt = ""; - - while(!SystemManager::instance()->isExitRequested()) + // Name if the mission control client we are sending commands to + String mccTarget = ""; + + SystemManager* sys = SystemManager::instance(); + while(!sys->isExitRequested()) { String line; #ifdef OMEGA_READLINE_FOUND + if(mccTarget == "") prompt = ostr("%1%>>", %sys->getApplication()->getName()); + else prompt = ostr("@%1%>>", %mccTarget); char *inp_c = readline(prompt.c_str()); //Instead of getline() - - prompt = ostr("%1%>>", %SystemManager::instance()->getApplication()->getName()); + // THE COMMAND OF DEATH if(inp_c[0] == 'D' && inp_c[1] == 'I' && @@ -102,10 +107,44 @@ class PythonInteractiveThread: public Thread #else getline(std::cin, line); #endif - - //ofmsg("line read: %1%", %line); - - interp->queueCommand(line); + // NEW IN 8.0 - use @ to enable forwarding commands to other connected + // mission control clients. + if(line[0] == '@') + { + MissionControlClient* mcc = sys->getMissionControlClient(); + if(mcc != NULL) + { + // command @ - disable mission control command forwarding + mccTarget = line.substr(1); + // Special command @? - list clients + if(mccTarget == "?") + { + vector& clients = mcc->listConnectedClients(); + omsg("[connected clients]"); + foreach(String cli, clients) ofmsg(" %1%", %cli); + mccTarget = ""; + } + } + } + else if(mccTarget != "") + { + MissionControlClient* mcc = sys->getMissionControlClient(); + if(mcc != NULL) + { + if(mccTarget == "*") + { + mcc->postCommand(line); + } + else + { + mcc->postCommand(ostr("@%1%: %2%", %mccTarget %line)); + } + } + } + else + { + interp->queueCommand(line); + } osleep(100); } //omsg("Ending console interactive thread"); @@ -115,7 +154,7 @@ class PythonInteractiveThread: public Thread /////////////////////////////////////////////////////////////////////////////// void PythonInterpreter::lockInterpreter() { - if(myDebugShell) omsg("PythonInterpreter::lockInterpreter()"); + //if(myDebugShell) omsg("PythonInterpreter::lockInterpreter()"); //myLock.lock(); // Acquire GIL. If GIL is already aquired, increase aquire count, so we @@ -123,6 +162,7 @@ void PythonInterpreter::lockInterpreter() if(sPythonMainThreadState) { PyEval_RestoreThread(sPythonMainThreadState); + if(myDebugShell) omsg("[PythonInterpreter] "); } sPythonMainThreadState = NULL; sGILAquireCount++; @@ -138,6 +178,7 @@ void PythonInterpreter::unlockInterpreter() if(sGILAquireCount == 0) { sPythonMainThreadState = PyEval_SaveThread(); + if(myDebugShell) omsg("[PythonInterpreter] UNLOCK"); } } else @@ -145,7 +186,6 @@ void PythonInterpreter::unlockInterpreter() oerror("PythonInterpreter::unlockInterpreter: missing lockInterpreter call"); } - if(myDebugShell) omsg("PythonInterpreter::unlockInterpreter()"); //myLock.unlock(); } @@ -318,7 +358,11 @@ void PythonInterpreter::initialize(const char* programName) String modulePath = ogetdataprefix() + "/modules"; addPythonPath(modulePath.c_str()); - if((myShellEnabled || SystemManager::instance()->getApplication()->interactive) + ApplicationBase* app = SystemManager::instance()->getApplication(); + bool forceInteractive = app->interactive == ApplicationBase::Interactive; + bool forceNonInteractive = app->interactive == ApplicationBase::NonInteractive; + + if((myShellEnabled || forceInteractive) && !forceNonInteractive && SystemManager::instance()->isMaster()) { //omsg("PythonInterpreter: starting interactive shell thread."); diff --git a/src/omega/PythonShellWrapper.cpp b/src/omega/PythonShellWrapper.cpp index a32983ce..30efa6d0 100644 --- a/src/omega/PythonShellWrapper.cpp +++ b/src/omega/PythonShellWrapper.cpp @@ -57,7 +57,7 @@ class PythonInterpreterWrapper if(!strncmp(string, "Traceback", 9)) { omsg(""); - omsg("[PYTHON ERROR] "); + ofmsg("[%1% :: PYTHON ERROR] ", %SystemManager::instance()->getApplication()->getName()); owarn(string); } else diff --git a/src/omega/Texture.cpp b/src/omega/Texture.cpp index fb0c7016..b8984537 100644 --- a/src/omega/Texture.cpp +++ b/src/omega/Texture.cpp @@ -104,7 +104,7 @@ void Texture::initialize(int width, int height, TextureType tt, ChannelType ct, glTexImage2D(textureType, 0, myGlFormat, myWidth, myHeight, 0, myGlFormat, channelFormat, NULL); glTexParameteri(textureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(textureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(textureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if(sUsePbo) { diff --git a/src/omega/omegaPythonApi.cpp b/src/omega/omegaPythonApi.cpp index b9e5ba1b..20a1ff3e 100644 --- a/src/omega/omegaPythonApi.cpp +++ b/src/omega/omegaPythonApi.cpp @@ -789,6 +789,12 @@ MissionControlClient* getMissionControlClient() return SystemManager::instance()->getMissionControlClient(); } +/////////////////////////////////////////////////////////////////////////////// +MissionControlServer* getMissionControlServer() +{ + return SystemManager::instance()->getMissionControlServer(); +} + /////////////////////////////////////////////////////////////////////////////// void toggleStereo() { @@ -1246,10 +1252,10 @@ BOOST_PYTHON_MODULE(omega) PYAPI_GETTER(Event, getOrientation) PYAPI_GETTER(Event, getExtraDataInt) PYAPI_GETTER(Event, getExtraDataFloat) - PYAPI_GETTER(Event, getExtraDataString) - PYAPI_GETTER(Event, getExtraDataVector3) - PYAPI_GETTER(Event, getExtraDataType) - PYAPI_GETTER(Event, getExtraDataSize) + PYAPI_GETTER(Event, getExtraDataString) + PYAPI_GETTER(Event, getExtraDataVector3) + PYAPI_GETTER(Event, getExtraDataType) + PYAPI_GETTER(Event, getExtraDataSize) ; PYAPI_ENUM(Node::TransformSpace, Space) @@ -1429,6 +1435,8 @@ BOOST_PYTHON_MODULE(omega) PYAPI_METHOD(Camera, setSceneEnabled) PYAPI_METHOD(Camera, isOverlayEnabled) PYAPI_METHOD(Camera, setOverlayEnabled) + PYAPI_METHOD(Camera, isCullingEnabled) + PYAPI_METHOD(Camera, setCullingEnabled) PYAPI_METHOD(Camera, setNearFarZ) PYAPI_METHOD(Camera, getNearZ) PYAPI_METHOD(Camera, getFarZ) @@ -1437,6 +1445,9 @@ BOOST_PYTHON_MODULE(omega) PYAPI_METHOD(Camera, isClearColorEnabled) PYAPI_METHOD(Camera, clearDepth) PYAPI_METHOD(Camera, isClearDepthEnabled) + PYAPI_METHOD(Camera, queueFrameDraw) + PYAPI_METHOD(Camera, setMaxFps) + PYAPI_METHOD(Camera, getMaxFps) ; // Color @@ -1612,6 +1623,13 @@ BOOST_PYTHON_MODULE(omega) PYAPI_METHOD(MissionControlClient, setClientListUpdatedCommand) ; + // MissionControlClient + PYAPI_REF_BASE_CLASS(MissionControlServer) + PYAPI_METHOD(MissionControlServer, getPort) + PYAPI_METHOD(MissionControlServer, broadcastEvent) + PYAPI_METHOD(MissionControlServer, sendEventTo) + ; + class_< vector >("StringVector").def(vector_indexing_suite< vector >()); @@ -1704,6 +1722,7 @@ BOOST_PYTHON_MODULE(omega) def("getDisplayPixelSize", getDisplayPixelSize); def("getMissionControlClient", getMissionControlClient, PYAPI_RETURN_REF); + def("getMissionControlServer", getMissionControlServer, PYAPI_RETURN_REF); def("quaternionToEuler", quaternionToEuler, PYAPI_RETURN_VALUE); def("quaternionToEulerDeg", quaternionToEulerDeg, PYAPI_RETURN_VALUE); diff --git a/src/omega/osystem.cpp b/src/omega/osystem.cpp index fa9be832..461c3e50 100644 --- a/src/omega/osystem.cpp +++ b/src/omega/osystem.cpp @@ -244,6 +244,9 @@ namespace omega bool disableSIGINTHandler = false; bool logRemoteNodes = false; + bool forceInteractiveOn = false; + bool forceInteractiveOff = false; + oargs().setStringVector( "args", "optional arguments. If the first argument ends with .cfg it will be used as a configuration file", @@ -321,8 +324,14 @@ namespace omega sArgs.newFlag( 'i', "interactive", - "Runs the program in interactive mode, even if the script console is not enabled in the system configuration", - app.interactive); + "Runs the program in interactive mode, overriding configuration file settings", + forceInteractiveOn); + + sArgs.newFlag( + 0, + "interactive-off", + "Runs the program in non interactive mode, , overriding configuration file settings", + forceInteractiveOff); sArgs.setAuthor("The Electronic Visualization Lab, UIC"); //String appName; @@ -339,6 +348,9 @@ namespace omega return -1; } + if(forceInteractiveOff) app.interactive = ApplicationBase::NonInteractive; + else if(forceInteractiveOn) app.interactive = ApplicationBase::Interactive; + // Update the application name. app.setName(appName); @@ -405,7 +417,8 @@ namespace omega } else { - ologopen(logFilename.c_str()); + if(logFilename != "off") ologopen(logFilename.c_str()); + else ologdisable(); } SystemManager* sys = SystemManager::instance(); @@ -468,7 +481,8 @@ namespace omega // If we have an auxiliary config file specified, // load it and append it to the main config. if(sOptionalArgs.size() > 0 && - StringUtils::endsWith(sOptionalArgs[0], ".cfg")) + (StringUtils::endsWith(sOptionalArgs[0], ".cfg") || + StringUtils::endsWith(sOptionalArgs[0], ".oapp"))) { oflog(Verbose, "Loading auxiliary config %1%", %sOptionalArgs[0]); Config* auxcfg = new Config(sOptionalArgs[0]); diff --git a/src/omegaToolkit/WandPointerSwitcher.cpp b/src/omegaToolkit/WandPointerSwitcher.cpp index aeeecf99..7b6d733f 100644 --- a/src/omegaToolkit/WandPointerSwitcher.cpp +++ b/src/omegaToolkit/WandPointerSwitcher.cpp @@ -67,6 +67,9 @@ void WandPointerSwitcher::poll() { evt->setPosition(Vector3f(out[0], out[1], 0)); evt->setServiceType(Service::Pointer); + // If the event is an Update event, also convert it to a Move event, since + // pointer handling code expects that. + if(evt->getType() == Event::Update) evt->resetType(Event::Move); } } } diff --git a/src/omegaToolkit/ui/Container.cpp b/src/omegaToolkit/ui/Container.cpp index 32280229..b3f31401 100644 --- a/src/omegaToolkit/ui/Container.cpp +++ b/src/omegaToolkit/ui/Container.cpp @@ -683,16 +683,28 @@ void Container::handleEvent(const Event& evt) // standard pointer events. if(my3dSettings.enable3d && isPointerInteractionEnabled()) { - Event newEvt; - if(rayToPointerEvent(evt, newEvt)) + // CHANGE 9/7/2015 - v8.0.5 + // For 3D containers with pointer interaction enabled, by + // default only forward true pointer events. Perform the conversion + // between ie ray to pointer only on containers that explicitly say so + // in their 3D settings. + // This lets us keep pointer interaction enabled system-wide, and still avoid + // unwanted ray-pointer interaction. + // EXAMPLE: In CAVE2 apps we want to use the wand as a pointer on 2D containers + // but not on 3D menus. + if(evt.getServiceType() == Service::Pointer || my3dSettings.wandPointerEnabled) { - foreach(Widget* w, myChildren) + Event newEvt; + if(rayToPointerEvent(evt, newEvt)) { - w->handleEvent(newEvt); + foreach(Widget* w, myChildren) + { + w->handleEvent(newEvt); + } } + // Copy back processe flag into original event. + if(newEvt.isProcessed()) evt.setProcessed(); } - // Copy back processe flag into original event. - if(newEvt.isProcessed()) evt.setProcessed(); } else { diff --git a/src/omegaToolkit/ui/DefaultSkin.cpp b/src/omegaToolkit/ui/DefaultSkin.cpp index a6c95703..b8cbeeab 100644 --- a/src/omegaToolkit/ui/DefaultSkin.cpp +++ b/src/omegaToolkit/ui/DefaultSkin.cpp @@ -59,7 +59,8 @@ void DefaultButtonRenderable::drawContent(const DrawContext& context) col = myOwner->getLabel()->getColor(); originalColor = col; } - if(myOwner->isPointerInside() || myOwner->isActive()) + if((myOwner->isPointerInteractionEnabled() && myOwner->isPointerInside()) + || myOwner->isActive()) { focused = true; col = myOwner->getFactory()->getFocusColor(); diff --git a/system/headless.cfg b/system/headless.cfg index 11ce4ecd..b5b92b87 100644 --- a/system/headless.cfg +++ b/system/headless.cfg @@ -1,20 +1,5 @@ config: { - // A headless display configuration - display: - { - type = "Null"; - }; - services: - { - }; - orun: - { - initScript = ""; - }; - pythonShellEnabled = true; - missionControl: - { - serverEnabled = true; - }; + services: {}; + orun: { initScript = ""; appStart = ""; }; }; \ No newline at end of file diff --git a/system/test-multinode.cfg b/system/test-multinode.cfg index 52b4f638..2b22d8a1 100644 --- a/system/test-multinode.cfg +++ b/system/test-multinode.cfg @@ -47,7 +47,7 @@ config: localhost-2: { hostname = "localhost"; - port = 24001; + port = 24002; t1x0: {}; }; };