v01
This commit is contained in:
95
thirdparty/Pangolin/src/display/device/PangolinNSApplication.mm
vendored
Normal file
95
thirdparty/Pangolin/src/display/device/PangolinNSApplication.mm
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2011 Steven Lovegrove
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pangolin/platform.h>
|
||||
#include <pangolin/display/display.h>
|
||||
#include <pangolin/display/device/PangolinNSApplication.h>
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
|
||||
# define NSAnyEventMask NSEventMaskAny
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// PangolinNSApplication
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
@implementation PangolinNSApplication
|
||||
|
||||
+ (void)run_pre
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:NSApplicationWillFinishLaunchingNotification
|
||||
object:NSApp];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:NSApplicationDidFinishLaunchingNotification
|
||||
object:NSApp];
|
||||
}
|
||||
|
||||
+ (void)run_step
|
||||
{
|
||||
NSEvent *event;
|
||||
do{
|
||||
event = [NSApp
|
||||
nextEventMatchingMask:NSAnyEventMask
|
||||
untilDate:nil
|
||||
// untilDate: [NSDate distantFuture]
|
||||
inMode:NSDefaultRunLoopMode
|
||||
dequeue:YES];
|
||||
[NSApp sendEvent:event];
|
||||
[NSApp updateWindows];
|
||||
}while(event != nil);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// PangolinWindowDelegate
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
@implementation PangolinWindowDelegate
|
||||
|
||||
- (BOOL)windowShouldClose:(id)sender {
|
||||
PANGOLIN_UNUSED(sender);
|
||||
|
||||
pangolin::Quit();
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// PangolinAppDelegate
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
@implementation PangolinAppDelegate
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
325
thirdparty/Pangolin/src/display/device/PangolinNSGLView.mm
vendored
Normal file
325
thirdparty/Pangolin/src/display/device/PangolinNSGLView.mm
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
#include <pangolin/platform.h>
|
||||
#include <pangolin/gl/glinclude.h>
|
||||
#include <pangolin/display/device/PangolinNSGLView.h>
|
||||
#include <pangolin/display/display.h>
|
||||
#include <pangolin/display/display_internal.h>
|
||||
#include <pangolin/handler/handler_enums.h>
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
|
||||
# define NSDeviceIndependentModifierFlagsMask NSEventModifierFlagDeviceIndependentFlagsMask
|
||||
# define NSShiftKeyMask NSEventModifierFlagShift
|
||||
# define NSControlKeyMask NSEventModifierFlagControl
|
||||
# define NSAlternateKeyMask NSEventModifierFlagOption
|
||||
# define NSCommandKeyMask NSEventModifierFlagCommand
|
||||
# define NSFunctionKeyMask NSEventModifierFlagFunction
|
||||
#endif
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
extern __thread PangolinGl* context;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Input maps
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline
|
||||
int mapMouseButton(int osx_button )
|
||||
{
|
||||
const int map[] = {0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
return map[osx_button];
|
||||
}
|
||||
|
||||
inline
|
||||
int mapKeymap(int osx_key)
|
||||
{
|
||||
if(osx_key == NSUpArrowFunctionKey)
|
||||
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_UP;
|
||||
else if(osx_key == NSDownArrowFunctionKey)
|
||||
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_DOWN;
|
||||
else if(osx_key == NSLeftArrowFunctionKey)
|
||||
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_LEFT;
|
||||
else if(osx_key == NSRightArrowFunctionKey)
|
||||
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_RIGHT;
|
||||
else if(osx_key == NSPageUpFunctionKey)
|
||||
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_PAGE_UP;
|
||||
else if(osx_key == NSPageDownFunctionKey)
|
||||
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_PAGE_DOWN;
|
||||
else if(osx_key == NSHomeFunctionKey)
|
||||
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_HOME;
|
||||
else if(osx_key == NSEndFunctionKey)
|
||||
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_END;
|
||||
else if(osx_key == NSInsertFunctionKey)
|
||||
return pangolin::PANGO_SPECIAL + pangolin::PANGO_KEY_INSERT;
|
||||
else if(osx_key == NSDeleteCharacter )
|
||||
return NSBackspaceCharacter;
|
||||
else if(osx_key == NSDeleteFunctionKey)
|
||||
return NSDeleteCharacter;
|
||||
else {
|
||||
return osx_key;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// PangolinNSGLView
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
@implementation PangolinNSGLView
|
||||
|
||||
-(id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat *)format
|
||||
{
|
||||
self = [super initWithFrame:frameRect pixelFormat:format];
|
||||
context = pangolin::context;
|
||||
return(self);
|
||||
}
|
||||
|
||||
- (void)prepareOpenGL
|
||||
{
|
||||
[super prepareOpenGL];
|
||||
}
|
||||
|
||||
-(void)reshape
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
|
||||
if ( [self wantsBestResolutionOpenGLSurface] && [ self.window respondsToSelector:@selector(backingScaleFactor) ] )
|
||||
backing_scale = [self.window backingScaleFactor];
|
||||
else
|
||||
#endif
|
||||
backing_scale = 1.0;
|
||||
|
||||
pangolin::process::Resize(self.bounds.size.width * backing_scale, self.bounds.size.height * backing_scale);
|
||||
|
||||
[[self openGLContext] update];
|
||||
}
|
||||
|
||||
-(BOOL)acceptsFirstResponder
|
||||
{
|
||||
return(YES);
|
||||
}
|
||||
|
||||
-(BOOL)becomeFirstResponder
|
||||
{
|
||||
return(YES);
|
||||
}
|
||||
|
||||
-(BOOL)resignFirstResponder
|
||||
{
|
||||
return(YES);
|
||||
}
|
||||
|
||||
-(BOOL)isFlipped
|
||||
{
|
||||
return(YES);
|
||||
}
|
||||
|
||||
-(NSPoint)_Location:(NSEvent *)theEvent
|
||||
{
|
||||
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
|
||||
location.x *= backing_scale;
|
||||
location.y *= backing_scale;
|
||||
return location;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Keyboard
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)keyDown:(NSEvent *)theEvent
|
||||
{
|
||||
const NSPoint location = [self _Location: theEvent];
|
||||
NSString *str = [theEvent characters];
|
||||
int len = (int)[str length];
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
const int osx_key = [str characterAtIndex:i];
|
||||
pangolin::process::Keyboard(mapKeymap(osx_key), location.x, location.y);
|
||||
}
|
||||
}
|
||||
|
||||
-(void)keyUp:(NSEvent *)theEvent
|
||||
{
|
||||
const NSPoint location = [self _Location: theEvent];
|
||||
NSString *str = [theEvent characters];
|
||||
int len = (int)[str length];
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
const int osx_key = [str characterAtIndex:i];
|
||||
pangolin::process::KeyboardUp(mapKeymap(osx_key), location.x, location.y);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)event
|
||||
{
|
||||
unsigned int flags = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
|
||||
|
||||
if(flags&NSShiftKeyMask) {
|
||||
context->mouse_state |= pangolin::KeyModifierShift;
|
||||
}else{
|
||||
context->mouse_state &= ~pangolin::KeyModifierShift;
|
||||
}
|
||||
|
||||
if(flags&NSControlKeyMask) {
|
||||
context->mouse_state |= pangolin::KeyModifierCtrl;
|
||||
}else{
|
||||
context->mouse_state &= ~pangolin::KeyModifierCtrl;
|
||||
}
|
||||
|
||||
if(flags&NSAlternateKeyMask) {
|
||||
context->mouse_state |= pangolin::KeyModifierAlt;
|
||||
}else{
|
||||
context->mouse_state &= ~pangolin::KeyModifierAlt;
|
||||
}
|
||||
|
||||
if(flags&NSCommandKeyMask) {
|
||||
context->mouse_state |= pangolin::KeyModifierCmd;
|
||||
}else{
|
||||
context->mouse_state &= ~pangolin::KeyModifierCmd;
|
||||
}
|
||||
|
||||
if(flags&NSFunctionKeyMask) {
|
||||
context->mouse_state |= pangolin::KeyModifierFnc;
|
||||
}else{
|
||||
context->mouse_state &= ~pangolin::KeyModifierFnc;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Mouse Input
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)mouseDownCommon:(NSEvent *)theEvent
|
||||
{
|
||||
const int button = (int)[theEvent buttonNumber];
|
||||
const NSPoint location = [self _Location: theEvent];
|
||||
pangolin::process::Mouse(mapMouseButton(button), 0, location.x, location.y);
|
||||
}
|
||||
|
||||
-(void)mouseUpCommon:(NSEvent *)theEvent
|
||||
{
|
||||
const int button = (int)[theEvent buttonNumber];
|
||||
const NSPoint location = [self _Location: theEvent];
|
||||
pangolin::process::Mouse(mapMouseButton(button), 1, location.x, location.y);
|
||||
}
|
||||
|
||||
- (void)mouseDraggedCommon: (NSEvent *)theEvent
|
||||
{
|
||||
const NSPoint location = [self _Location: theEvent];
|
||||
pangolin::process::MouseMotion(location.x, location.y);
|
||||
// pangolin::process::SubpixMotion(location.x, location.y, 1.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
-(void)mouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
[self mouseDownCommon:theEvent];
|
||||
}
|
||||
|
||||
-(void)mouseUp:(NSEvent *)theEvent
|
||||
{
|
||||
[self mouseUpCommon:theEvent];
|
||||
}
|
||||
|
||||
- (void)mouseDragged: (NSEvent *)theEvent
|
||||
{
|
||||
[self mouseDraggedCommon:theEvent];
|
||||
}
|
||||
|
||||
-(void)rightMouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
[self mouseDownCommon:theEvent];
|
||||
}
|
||||
|
||||
-(void)rightMouseUp:(NSEvent *)theEvent
|
||||
{
|
||||
[self mouseUpCommon:theEvent];
|
||||
}
|
||||
|
||||
- (void)rightMouseDragged: (NSEvent *)theEvent
|
||||
{
|
||||
[self mouseDraggedCommon:theEvent];
|
||||
}
|
||||
|
||||
-(void)otherMouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
[self mouseDownCommon:theEvent];
|
||||
}
|
||||
|
||||
-(void)otherMouseUp:(NSEvent *)theEvent
|
||||
{
|
||||
[self mouseUpCommon:theEvent];
|
||||
}
|
||||
|
||||
- (void)otherMouseDragged: (NSEvent *)theEvent
|
||||
{
|
||||
[self mouseDraggedCommon:theEvent];
|
||||
}
|
||||
|
||||
- (void)mouseMoved: (NSEvent *)theEvent
|
||||
{
|
||||
const NSPoint location = [self _Location: theEvent];
|
||||
// pangolin::process::PassiveMouseMotion(location.x, location.y);
|
||||
pangolin::process::SubpixMotion(location.x, location.y, 0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)theEvent
|
||||
{
|
||||
const NSPoint location = [self _Location: theEvent];
|
||||
|
||||
float dx, dy;
|
||||
if([theEvent respondsToSelector:@selector(scrollingDeltaX)]) {
|
||||
dx = theEvent.scrollingDeltaX; dy = theEvent.scrollingDeltaY;
|
||||
} else {
|
||||
dx = theEvent.deltaX; dy = theEvent.deltaY;
|
||||
}
|
||||
|
||||
if(dx != 0.0f || dy != 0.0f) {
|
||||
pangolin::process::SpecialInput(
|
||||
pangolin::InputSpecialScroll,
|
||||
location.x, context->base.v.h - location.y,
|
||||
dx, dy,
|
||||
0, 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)magnifyWithEvent: (NSEvent *)theEvent
|
||||
{
|
||||
const NSPoint location = [self _Location: theEvent];
|
||||
const float dm = theEvent.magnification;
|
||||
if(dm != 0.0f) {
|
||||
pangolin::process::SpecialInput(
|
||||
pangolin::InputSpecialZoom,
|
||||
location.x, context->base.v.h - location.y,
|
||||
dm, 0.0f, 0.0f, 0.0f
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)rotateWithEvent: (NSEvent *)theEvent
|
||||
{
|
||||
const NSPoint location = [self _Location: theEvent];
|
||||
const float dr = theEvent.rotation;
|
||||
if(dr != 0.0f) {
|
||||
pangolin::process::SpecialInput(
|
||||
pangolin::InputSpecialRotate,
|
||||
location.x, context->base.v.h - location.y,
|
||||
dr, 0.0f, 0.0f, 0.0f
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseEntered: (NSEvent *)theEvent
|
||||
{
|
||||
PANGOLIN_UNUSED(theEvent);
|
||||
}
|
||||
|
||||
- (void)mouseExited: (NSEvent *)theEvent
|
||||
{
|
||||
PANGOLIN_UNUSED(theEvent);
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
1026
thirdparty/Pangolin/src/display/device/display_android.cpp
vendored
Normal file
1026
thirdparty/Pangolin/src/display/device/display_android.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
166
thirdparty/Pangolin/src/display/device/display_headless.cpp
vendored
Executable file
166
thirdparty/Pangolin/src/display/device/display_headless.cpp
vendored
Executable file
@@ -0,0 +1,166 @@
|
||||
#include <pangolin/display/display_internal.h>
|
||||
#include <pangolin/factory/factory_registry.h>
|
||||
#include <EGL/egl.h>
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
extern __thread PangolinGl* context;
|
||||
|
||||
namespace headless {
|
||||
|
||||
class EGLDisplayHL {
|
||||
public:
|
||||
EGLDisplayHL(const int width, const int height);
|
||||
|
||||
~EGLDisplayHL();
|
||||
|
||||
void swap();
|
||||
|
||||
void makeCurrent();
|
||||
|
||||
void removeCurrent();
|
||||
|
||||
private:
|
||||
EGLSurface egl_surface;
|
||||
EGLContext egl_context;
|
||||
EGLDisplay egl_display;
|
||||
|
||||
static constexpr EGLint attribs[] = {
|
||||
EGL_SURFACE_TYPE , EGL_PBUFFER_BIT,
|
||||
EGL_RENDERABLE_TYPE , EGL_OPENGL_BIT,
|
||||
EGL_RED_SIZE , 8,
|
||||
EGL_GREEN_SIZE , 8,
|
||||
EGL_BLUE_SIZE , 8,
|
||||
EGL_ALPHA_SIZE , 8,
|
||||
EGL_DEPTH_SIZE , 24,
|
||||
EGL_STENCIL_SIZE , 8,
|
||||
EGL_NONE
|
||||
};
|
||||
};
|
||||
|
||||
constexpr EGLint EGLDisplayHL::attribs[];
|
||||
|
||||
struct HeadlessWindow : public PangolinGl {
|
||||
HeadlessWindow(const int width, const int height);
|
||||
|
||||
~HeadlessWindow() override;
|
||||
|
||||
void ToggleFullscreen() override;
|
||||
|
||||
void Move(const int x, const int y) override;
|
||||
|
||||
void Resize(const unsigned int w, const unsigned int h) override;
|
||||
|
||||
void MakeCurrent() override;
|
||||
|
||||
void RemoveCurrent() override;
|
||||
|
||||
void SwapBuffers() override;
|
||||
|
||||
void ProcessEvents() override;
|
||||
|
||||
EGLDisplayHL display;
|
||||
};
|
||||
|
||||
EGLDisplayHL::EGLDisplayHL(const int width, const int height) {
|
||||
egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if(!egl_display) {
|
||||
std::cerr << "Failed to open EGL display" << std::endl;
|
||||
}
|
||||
|
||||
EGLint major, minor;
|
||||
if(eglInitialize(egl_display, &major, &minor)==EGL_FALSE) {
|
||||
std::cerr << "EGL init failed" << std::endl;
|
||||
}
|
||||
|
||||
if(eglBindAPI(EGL_OPENGL_API)==EGL_FALSE) {
|
||||
std::cerr << "EGL bind failed" << std::endl;
|
||||
}
|
||||
|
||||
EGLint count;
|
||||
eglGetConfigs(egl_display, nullptr, 0, &count);
|
||||
|
||||
std::vector<EGLConfig> egl_configs(count);
|
||||
|
||||
EGLint numConfigs;
|
||||
eglChooseConfig(egl_display, attribs, egl_configs.data(), count, &numConfigs);
|
||||
|
||||
egl_context = eglCreateContext(egl_display, egl_configs[0], EGL_NO_CONTEXT, nullptr);
|
||||
|
||||
const EGLint pbufferAttribs[] = {
|
||||
EGL_WIDTH, width,
|
||||
EGL_HEIGHT, height,
|
||||
EGL_NONE,
|
||||
};
|
||||
egl_surface = eglCreatePbufferSurface(egl_display, egl_configs[0], pbufferAttribs);
|
||||
if (egl_surface == EGL_NO_SURFACE) {
|
||||
std::cerr << "Cannot create EGL surface" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
EGLDisplayHL::~EGLDisplayHL() {
|
||||
if(egl_context) eglDestroyContext(egl_display, egl_context);
|
||||
if(egl_surface) eglDestroySurface(egl_display, egl_surface);
|
||||
if(egl_display) eglTerminate(egl_display);
|
||||
}
|
||||
|
||||
void EGLDisplayHL::swap() {
|
||||
eglSwapBuffers(egl_display, egl_surface);
|
||||
}
|
||||
|
||||
void EGLDisplayHL::makeCurrent() {
|
||||
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
||||
}
|
||||
|
||||
void EGLDisplayHL::removeCurrent() {
|
||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
HeadlessWindow::HeadlessWindow(const int w, const int h) : display(w, h) {
|
||||
windowed_size[0] = w;
|
||||
windowed_size[1] = h;
|
||||
}
|
||||
|
||||
HeadlessWindow::~HeadlessWindow() { }
|
||||
|
||||
void HeadlessWindow::MakeCurrent() {
|
||||
display.makeCurrent();
|
||||
context = this;
|
||||
}
|
||||
|
||||
void HeadlessWindow::RemoveCurrent() {
|
||||
display.removeCurrent();
|
||||
}
|
||||
|
||||
void HeadlessWindow::ToggleFullscreen() { }
|
||||
|
||||
void HeadlessWindow::Move(const int /*x*/, const int /*y*/) { }
|
||||
|
||||
void HeadlessWindow::Resize(const unsigned int /*w*/, const unsigned int /*h*/) { }
|
||||
|
||||
void HeadlessWindow::ProcessEvents() { }
|
||||
|
||||
void HeadlessWindow::SwapBuffers() {
|
||||
display.swap();
|
||||
MakeCurrent();
|
||||
}
|
||||
|
||||
} // namespace headless
|
||||
|
||||
PANGOLIN_REGISTER_FACTORY(NoneWindow) {
|
||||
struct HeadlessWindowFactory : public FactoryInterface<WindowInterface> {
|
||||
std::unique_ptr<WindowInterface> Open(const Uri& uri) override {
|
||||
return std::unique_ptr<WindowInterface>(new headless::HeadlessWindow(uri.Get<int>("w", 640), uri.Get<int>("h", 480)));
|
||||
}
|
||||
|
||||
virtual ~HeadlessWindowFactory() { }
|
||||
};
|
||||
|
||||
auto factory = std::make_shared<HeadlessWindowFactory>();
|
||||
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 1, "none");
|
||||
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 1, "nogui");
|
||||
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 1, "headless");
|
||||
}
|
||||
|
||||
} // namespace pangolin
|
||||
|
||||
249
thirdparty/Pangolin/src/display/device/display_osx.mm
vendored
Normal file
249
thirdparty/Pangolin/src/display/device/display_osx.mm
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2011-2018 Steven Lovegrove, Andrey Mnatsakanov
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Silence all the OSX GL deprecation messages.
|
||||
#define GL_SILENCE_DEPRECATION
|
||||
|
||||
#include <pangolin/factory/factory_registry.h>
|
||||
#include <pangolin/platform.h>
|
||||
#include <pangolin/gl/glinclude.h>
|
||||
#include <pangolin/display/display.h>
|
||||
#include <pangolin/display/display_internal.h>
|
||||
#include <pangolin/display/device/OsxWindow.h>
|
||||
#include <pangolin/display/device/PangolinNSGLView.h>
|
||||
#include <pangolin/display/device/PangolinNSApplication.h>
|
||||
#include <memory>
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
|
||||
# define NSFullScreenWindowMask NSWindowStyleMaskFullScreen
|
||||
# define NSTitledWindowMask NSWindowStyleMaskTitled
|
||||
# define NSMiniaturizableWindowMask NSWindowStyleMaskMiniaturizable
|
||||
# define NSResizableWindowMask NSWindowStyleMaskResizable
|
||||
# define NSClosableWindowMask NSWindowStyleMaskClosable
|
||||
#endif
|
||||
|
||||
// Hack to fix window focus issue
|
||||
// http://www.miscdebris.net/blog/2010/03/30/solution-for-my-mac-os-x-gui-program-doesnt-get-focus-if-its-outside-an-application-bundle/
|
||||
extern "C" { void CPSEnableForegroundOperation(ProcessSerialNumber* psn); }
|
||||
inline void FixOsxFocus()
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
ProcessSerialNumber psn;
|
||||
GetCurrentProcess( &psn );
|
||||
CPSEnableForegroundOperation( &psn );
|
||||
SetFrontProcess( &psn );
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
|
||||
extern __thread PangolinGl* context;
|
||||
|
||||
std::unique_ptr<WindowInterface> CreateOsxWindowAndBind(std::string window_title, int w, int h, const bool is_highres)
|
||||
{
|
||||
|
||||
OsxWindow* win = new OsxWindow(window_title, w, h, is_highres);
|
||||
|
||||
return std::unique_ptr<WindowInterface>(win);
|
||||
}
|
||||
|
||||
OsxWindow::OsxWindow(
|
||||
const std::string& title, int width, int height, bool USE_RETINA
|
||||
) {
|
||||
context = this;
|
||||
|
||||
PangolinGl::is_double_buffered = true;
|
||||
PangolinGl::windowed_size[0] = width;
|
||||
PangolinGl::windowed_size[1] = height;
|
||||
|
||||
// // These are important I think!
|
||||
// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
// [pool release];
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Make sure Application is initialised correctly.
|
||||
// This can be run repeatedly.
|
||||
|
||||
[NSApplication sharedApplication];
|
||||
PangolinAppDelegate *delegate = [[PangolinAppDelegate alloc] init];
|
||||
|
||||
[NSApp setDelegate:delegate];
|
||||
[NSApp setPresentationOptions:NSFullScreenWindowMask];
|
||||
|
||||
[PangolinNSApplication run_pre];
|
||||
[PangolinNSApplication run_step];
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Create Window
|
||||
|
||||
NSRect viewRect = NSMakeRect( 0.0, 0.0, width, height );
|
||||
|
||||
_window = [[NSWindow alloc] initWithContentRect:viewRect styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask|NSClosableWindowMask backing:NSBackingStoreBuffered defer:YES];
|
||||
[_window setTitle:[NSString stringWithUTF8String:title.c_str()]];
|
||||
[_window setOpaque:YES];
|
||||
[_window makeKeyAndOrderFront:NSApp];
|
||||
[_window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
|
||||
|
||||
PangolinWindowDelegate *windelegate = [[PangolinWindowDelegate alloc] init];
|
||||
[_window setDelegate:windelegate];
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Setup Menu
|
||||
|
||||
// NSMenu *mainMenuBar;
|
||||
// NSMenu *appMenu;
|
||||
// NSMenuItem *menuItem;
|
||||
|
||||
// mainMenuBar = [[NSMenu alloc] init];
|
||||
|
||||
// appMenu = [[NSMenu alloc] initWithTitle:@"Pangolin Application"];
|
||||
// menuItem = [appMenu addItemWithTitle:@"Quit Pangolin Application" action:@selector(terminate:) keyEquivalent:@"q"];
|
||||
// [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
|
||||
|
||||
// menuItem = [[NSMenuItem alloc] init];
|
||||
// [menuItem setSubmenu:appMenu];
|
||||
|
||||
// [mainMenuBar addItem:menuItem];
|
||||
|
||||
// //[NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu];
|
||||
// [appMenu release];
|
||||
// [NSApp setMainMenu:mainMenuBar];
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Create OpenGL View for Window
|
||||
|
||||
NSOpenGLPixelFormatAttribute attrs[] =
|
||||
{
|
||||
NSOpenGLPFADoubleBuffer,
|
||||
NSOpenGLPFADepthSize, 32,
|
||||
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy,
|
||||
0
|
||||
};
|
||||
|
||||
NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
|
||||
view = [[PangolinNSGLView alloc] initWithFrame:_window.frame pixelFormat:format];
|
||||
[format release];
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if( USE_RETINA && floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
|
||||
[view setWantsBestResolutionOpenGLSurface:YES];
|
||||
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
|
||||
|
||||
[_window setContentView:view];
|
||||
|
||||
[PangolinNSApplication run_step];
|
||||
|
||||
glewInit();
|
||||
|
||||
FixOsxFocus();
|
||||
}
|
||||
|
||||
OsxWindow::~OsxWindow()
|
||||
{
|
||||
// Not sure how to deallocate...
|
||||
}
|
||||
|
||||
void OsxWindow::StartFullScreen()
|
||||
{
|
||||
if(!is_fullscreen) {
|
||||
[_window toggleFullScreen:nil];
|
||||
is_fullscreen = true;
|
||||
}
|
||||
}
|
||||
|
||||
void OsxWindow::StopFullScreen()
|
||||
{
|
||||
if(is_fullscreen) {
|
||||
[_window toggleFullScreen:nil];
|
||||
is_fullscreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
void OsxWindow::ToggleFullscreen()
|
||||
{
|
||||
[_window toggleFullScreen:nil];
|
||||
PangolinGl::is_fullscreen = !PangolinGl::is_fullscreen;
|
||||
}
|
||||
|
||||
void OsxWindow::Move(int x, int y)
|
||||
{
|
||||
[_window setFrame:CGRectMake(x, y, [_window frame].size.width,
|
||||
[_window frame].size.height) display:NO];
|
||||
}
|
||||
|
||||
void OsxWindow::Resize(unsigned int w, unsigned int h)
|
||||
{
|
||||
[_window setFrame:CGRectMake([_window frame].origin.x,
|
||||
[_window frame].origin.y, w, h) display:NO];
|
||||
}
|
||||
|
||||
void OsxWindow::MakeCurrent()
|
||||
{
|
||||
[[view openGLContext] makeCurrentContext];
|
||||
context = this;
|
||||
}
|
||||
|
||||
void OsxWindow::RemoveCurrent()
|
||||
{
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
}
|
||||
|
||||
void OsxWindow::SwapBuffers()
|
||||
{
|
||||
[[view openGLContext] flushBuffer];
|
||||
// [[view openGLContext] update];
|
||||
// [view setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
void OsxWindow::ProcessEvents()
|
||||
{
|
||||
[PangolinNSApplication run_step];
|
||||
}
|
||||
|
||||
PANGOLIN_REGISTER_FACTORY(OsxWindow)
|
||||
{
|
||||
struct OsxWindowFactory : public FactoryInterface<WindowInterface> {
|
||||
std::unique_ptr<WindowInterface> Open(const Uri& uri) override {
|
||||
|
||||
const std::string window_title = uri.Get<std::string>("window_title", "window");
|
||||
const int w = uri.Get<int>("w", 640);
|
||||
const int h = uri.Get<int>("h", 480);
|
||||
const bool is_highres = uri.Get<bool>(PARAM_HIGHRES, false);
|
||||
return std::unique_ptr<WindowInterface>(CreateOsxWindowAndBind(window_title, w, h, is_highres));
|
||||
}
|
||||
};
|
||||
|
||||
auto factory = std::make_shared<OsxWindowFactory>();
|
||||
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 10, "cocoa");
|
||||
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 100, "default");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
1048
thirdparty/Pangolin/src/display/device/display_wayland.cpp
vendored
Executable file
1048
thirdparty/Pangolin/src/display/device/display_wayland.cpp
vendored
Executable file
File diff suppressed because it is too large
Load Diff
599
thirdparty/Pangolin/src/display/device/display_win.cpp
vendored
Normal file
599
thirdparty/Pangolin/src/display/device/display_win.cpp
vendored
Normal file
@@ -0,0 +1,599 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2011-2018 Steven Lovegrove, Andrey Mnatsakanov
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pangolin/factory/factory_registry.h>
|
||||
#include <pangolin/platform.h>
|
||||
#include <pangolin/gl/glinclude.h>
|
||||
#include <pangolin/display/display.h>
|
||||
#include <pangolin/display/display_internal.h>
|
||||
|
||||
#include <pangolin/display/device/WinWindow.h>
|
||||
#include <memory>
|
||||
|
||||
#define CheckWGLDieOnError() pangolin::_CheckWLDieOnError( __FILE__, __LINE__ );
|
||||
namespace pangolin {
|
||||
inline void _CheckWLDieOnError( const char *sFile, const int nLine )
|
||||
{
|
||||
DWORD errorCode = GetLastError();
|
||||
if(errorCode!=0) {
|
||||
LPVOID lpMsgBuf;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR) &lpMsgBuf, 0, NULL);
|
||||
// MessageBox( NULL, (LPCTSTR)lpMsgBuf, ("Error "+std::to_string(errorCode)).c_str(), MB_OK | MB_ICONINFORMATION );
|
||||
pango_print_error("Error %i: %s", errorCode, (char *)lpMsgBuf);
|
||||
pango_print_error("In: %s, line %d\n", sFile, nLine);
|
||||
// exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
|
||||
const char *className = "Pangolin";
|
||||
|
||||
extern __thread PangolinGl* context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned char GetPangoKey(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (wParam)
|
||||
{
|
||||
case VK_F1: return PANGO_SPECIAL + PANGO_KEY_F1;
|
||||
case VK_F2: return PANGO_SPECIAL + PANGO_KEY_F2;
|
||||
case VK_F3: return PANGO_SPECIAL + PANGO_KEY_F3;
|
||||
case VK_F4: return PANGO_SPECIAL + PANGO_KEY_F4;
|
||||
case VK_F5: return PANGO_SPECIAL + PANGO_KEY_F5;
|
||||
case VK_F6: return PANGO_SPECIAL + PANGO_KEY_F6;
|
||||
case VK_F7: return PANGO_SPECIAL + PANGO_KEY_F7;
|
||||
case VK_F8: return PANGO_SPECIAL + PANGO_KEY_F8;
|
||||
case VK_F9: return PANGO_SPECIAL + PANGO_KEY_F9;
|
||||
case VK_F10: return PANGO_SPECIAL + PANGO_KEY_F10;
|
||||
case VK_F11: return PANGO_SPECIAL + PANGO_KEY_F11;
|
||||
case VK_F12: return PANGO_SPECIAL + PANGO_KEY_F12;
|
||||
case VK_LEFT: return PANGO_SPECIAL + PANGO_KEY_LEFT;
|
||||
case VK_UP: return PANGO_SPECIAL + PANGO_KEY_UP;
|
||||
case VK_RIGHT: return PANGO_SPECIAL + PANGO_KEY_RIGHT;
|
||||
case VK_DOWN: return PANGO_SPECIAL + PANGO_KEY_DOWN;
|
||||
case VK_HOME: return PANGO_SPECIAL + PANGO_KEY_HOME;
|
||||
case VK_END: return PANGO_SPECIAL + PANGO_KEY_END;
|
||||
case VK_INSERT: return PANGO_SPECIAL + PANGO_KEY_INSERT;
|
||||
case VK_DELETE: return 127;
|
||||
default:
|
||||
const int lBufferSize = 2;
|
||||
WCHAR lBuffer[lBufferSize];
|
||||
|
||||
BYTE State[256];
|
||||
GetKeyboardState(State);
|
||||
|
||||
const UINT scanCode = (lParam >> 8) & 0xFFFFFF00;
|
||||
if( ToUnicode((UINT)wParam, scanCode, State, lBuffer, lBufferSize, 0) >=1 ) {
|
||||
return (unsigned char)lBuffer[0];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetMouseModifierKey(WPARAM wParam)
|
||||
{
|
||||
//maps windows key modifier to glutGetModifiers values
|
||||
int gluKeyModVal = 0;
|
||||
if (wParam & MK_SHIFT) gluKeyModVal += 1;
|
||||
if (wParam & MK_CONTROL) gluKeyModVal += 2;
|
||||
if (HIBYTE(GetKeyState(VK_MENU))) gluKeyModVal += 4;
|
||||
return gluKeyModVal << 4;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// WinWindow Implementation
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void WinWindow::SetupPixelFormat(HDC hDC)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd = {
|
||||
sizeof(PIXELFORMATDESCRIPTOR), /* size */
|
||||
1, /* version */
|
||||
PFD_SUPPORT_OPENGL |
|
||||
PFD_DRAW_TO_WINDOW |
|
||||
PFD_DOUBLEBUFFER, /* support double-buffering */
|
||||
PFD_TYPE_RGBA, /* color type */
|
||||
24, /* prefered color depth */
|
||||
0, 0, 0, 0, 0, 0, /* color bits (ignored) */
|
||||
8, /* alpha bits */
|
||||
0, /* alpha shift (ignored) */
|
||||
0, /* no accumulation buffer */
|
||||
0, 0, 0, 0, /* accum bits (ignored) */
|
||||
32, /* depth buffer */
|
||||
0, /* no stencil buffer */
|
||||
0, /* no auxiliary buffers */
|
||||
PFD_MAIN_PLANE, /* main layer */
|
||||
0, /* reserved */
|
||||
0, 0, 0, /* no layer, visible, damage masks */
|
||||
};
|
||||
int pixelFormat;
|
||||
|
||||
pixelFormat = ChoosePixelFormat(hDC, &pfd);
|
||||
if (pixelFormat == 0) {
|
||||
MessageBoxA(WindowFromDC(hDC), "ChoosePixelFormat failed.", "Error", MB_ICONERROR | MB_OK);
|
||||
CheckWGLDieOnError();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE) {
|
||||
MessageBoxA(WindowFromDC(hDC), "SetPixelFormat failed.", "Error", MB_ICONERROR | MB_OK);
|
||||
CheckWGLDieOnError();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void WinWindow::SetupPalette(HDC hDC)
|
||||
{
|
||||
int pixelFormat = GetPixelFormat(hDC);
|
||||
if(!pixelFormat) {
|
||||
std::cerr << "GetPixelFormat() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
LOGPALETTE* pPal;
|
||||
int paletteSize;
|
||||
|
||||
if(!DescribePixelFormat(hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) {
|
||||
std::cerr << "DescribePixelFormat() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
|
||||
if (pfd.dwFlags & PFD_NEED_PALETTE) {
|
||||
paletteSize = 1 << pfd.cColorBits;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
pPal = (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
|
||||
pPal->palVersion = 0x300;
|
||||
pPal->palNumEntries = paletteSize;
|
||||
|
||||
/* build a simple RGB color palette */
|
||||
{
|
||||
int redMask = (1 << pfd.cRedBits) - 1;
|
||||
int greenMask = (1 << pfd.cGreenBits) - 1;
|
||||
int blueMask = (1 << pfd.cBlueBits) - 1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i<paletteSize; ++i) {
|
||||
pPal->palPalEntry[i].peRed =
|
||||
(((i >> pfd.cRedShift) & redMask) * 255) / redMask;
|
||||
pPal->palPalEntry[i].peGreen =
|
||||
(((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
|
||||
pPal->palPalEntry[i].peBlue =
|
||||
(((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
|
||||
pPal->palPalEntry[i].peFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
hPalette = CreatePalette(pPal);
|
||||
free(pPal);
|
||||
|
||||
if (hPalette) {
|
||||
SelectPalette(hDC, hPalette, FALSE);
|
||||
RealizePalette(hDC);
|
||||
}
|
||||
else {
|
||||
std::cerr << "CreatePalette() failed" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
WinWindow::WinWindow(
|
||||
const std::string& window_title, int width, int height
|
||||
) : hWnd(0)
|
||||
{
|
||||
const HMODULE hCurrentInst = GetModuleHandleA(nullptr);
|
||||
if(hCurrentInst==NULL) {
|
||||
std::cerr << "GetModuleHandle() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
RegisterThisClass(hCurrentInst);
|
||||
|
||||
HWND thishwnd = CreateWindowA(
|
||||
className, window_title.c_str(),
|
||||
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
||||
0, 0, width, height,
|
||||
NULL, NULL, hCurrentInst, this);
|
||||
if(thishwnd==NULL) {
|
||||
std::cerr << "CreateWindow() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
|
||||
if( thishwnd != hWnd ) {
|
||||
throw std::runtime_error("Pangolin Window Creation Failed.");
|
||||
}
|
||||
|
||||
// Gets the size of the window, excluding the top bar
|
||||
RECT cRect;
|
||||
GetClientRect(thishwnd, &cRect);
|
||||
|
||||
PangolinGl::windowed_size[0] = cRect.right;
|
||||
PangolinGl::windowed_size[1] = cRect.bottom;
|
||||
|
||||
// Display Window
|
||||
ShowWindow(hWnd, SW_SHOW);
|
||||
PangolinGl::is_double_buffered = true;
|
||||
}
|
||||
|
||||
WinWindow::~WinWindow()
|
||||
{
|
||||
if(!DestroyWindow(hWnd)) {
|
||||
std::cerr << "DestroyWindow() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
}
|
||||
|
||||
void WinWindow::RegisterThisClass(HMODULE hCurrentInst)
|
||||
{
|
||||
WNDCLASSA wndClass;
|
||||
wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
|
||||
wndClass.lpfnWndProc = WinWindow::WndProc;
|
||||
wndClass.cbClsExtra = 0;
|
||||
wndClass.cbWndExtra = 0;
|
||||
wndClass.hInstance = hCurrentInst;
|
||||
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
wndClass.lpszMenuName = NULL;
|
||||
wndClass.lpszClassName = className;
|
||||
if(!RegisterClassA(&wndClass)) {
|
||||
std::cerr << "RegisterClass() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT APIENTRY
|
||||
WinWindow::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
WinWindow* self = 0;
|
||||
|
||||
if (uMsg == WM_NCCREATE) {
|
||||
auto lpcs = reinterpret_cast<LPCREATESTRUCTA>(lParam);
|
||||
self = reinterpret_cast<WinWindow*>(lpcs->lpCreateParams);
|
||||
if(self) {
|
||||
self->hWnd = hwnd;
|
||||
SetWindowLongPtrA(hwnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(self));
|
||||
}
|
||||
} else {
|
||||
self = reinterpret_cast<WinWindow*>(GetWindowLongPtrA(hwnd, GWLP_USERDATA));
|
||||
}
|
||||
|
||||
if (self) {
|
||||
return self->HandleWinMessages(uMsg, wParam, lParam);
|
||||
} else {
|
||||
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT WinWindow::HandleWinMessages(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message) {
|
||||
case WM_CREATE:
|
||||
/* initialize OpenGL rendering */
|
||||
hDC = GetDC(hWnd);
|
||||
if(hDC==NULL) {
|
||||
std::cerr << "WM_CREATE GetDC() failed" << std::endl;
|
||||
}
|
||||
SetupPixelFormat(hDC);
|
||||
SetupPalette(hDC);
|
||||
hGLRC = wglCreateContext(hDC);
|
||||
if(!hGLRC) {
|
||||
std::cerr << "WM_CREATE wglCreateContext() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
if(!wglMakeCurrent(hDC, hGLRC)) {
|
||||
std::cerr << "WM_CREATE wglMakeCurrent() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
return 0;
|
||||
case WM_DESTROY:
|
||||
/* finish OpenGL rendering */
|
||||
if (hGLRC) {
|
||||
if(!wglMakeCurrent(NULL, NULL)) {
|
||||
std::cerr << "WM_DESTROY wglMakeCurrent() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
if(!wglDeleteContext(hGLRC)) {
|
||||
std::cerr << "WM_DESTROY wglDeleteContext() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
}
|
||||
if (hPalette) {
|
||||
DeleteObject(hPalette);
|
||||
}
|
||||
ReleaseDC(hWnd, hDC);
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
case WM_SIZE:
|
||||
/* track window size changes */
|
||||
if (context == this) {
|
||||
process::Resize((int)LOWORD(lParam), (int)HIWORD(lParam));
|
||||
}
|
||||
return 0;
|
||||
case WM_PALETTECHANGED:
|
||||
/* realize palette if this is *not* the current window */
|
||||
if (hGLRC && hPalette && (HWND)wParam != hWnd) {
|
||||
if(!UnrealizeObject(hPalette)) {
|
||||
std::cerr << "WM_PALETTECHANGED UnrealizeObject() failed" << std::endl;
|
||||
}
|
||||
if(!SelectPalette(hDC, hPalette, FALSE)) {
|
||||
std::cerr << "WM_PALETTECHANGED SelectPalette() failed" << std::endl;
|
||||
}
|
||||
if(RealizePalette(hDC)==GDI_ERROR) {
|
||||
std::cerr << "WM_PALETTECHANGED RealizePalette() failed" << std::endl;
|
||||
}
|
||||
//redraw();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WM_QUERYNEWPALETTE:
|
||||
/* realize palette if this is the current window */
|
||||
if (hGLRC && hPalette) {
|
||||
if(!UnrealizeObject(hPalette)) {
|
||||
std::cerr << "WM_QUERYNEWPALETTE UnrealizeObject() failed" << std::endl;
|
||||
}
|
||||
if(!SelectPalette(hDC, hPalette, FALSE)) {
|
||||
std::cerr << "WM_QUERYNEWPALETTE SelectPalette() failed" << std::endl;
|
||||
}
|
||||
if(RealizePalette(hDC)==GDI_ERROR) {
|
||||
std::cerr << "WM_QUERYNEWPALETTE RealizePalette() failed" << std::endl;
|
||||
}
|
||||
//redraw();
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
case WM_PAINT:
|
||||
{
|
||||
//PAINTSTRUCT ps;
|
||||
//BeginPaint(hWnd, &ps);
|
||||
//if (hGLRC) {
|
||||
// redraw();
|
||||
//}
|
||||
//EndPaint(hWnd, &ps);
|
||||
//return 0;
|
||||
}
|
||||
break;
|
||||
case WM_KEYDOWN:
|
||||
{
|
||||
unsigned char key = GetPangoKey(wParam, lParam);
|
||||
if(key>0) process::Keyboard(key, 1, 1);
|
||||
return 0;
|
||||
}
|
||||
case WM_KEYUP:
|
||||
{
|
||||
unsigned char key = GetPangoKey(wParam, lParam);
|
||||
if (key>0) process::KeyboardUp(key, 1, 1);
|
||||
return 0;
|
||||
}
|
||||
case WM_LBUTTONDOWN:
|
||||
process::Mouse(0 | GetMouseModifierKey(wParam), 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
return 0;
|
||||
case WM_MBUTTONDOWN:
|
||||
process::Mouse(1 | GetMouseModifierKey(wParam), 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
return 0;
|
||||
case WM_RBUTTONDOWN:
|
||||
process::Mouse(2 | GetMouseModifierKey(wParam), 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
return 0;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
process::Mouse(0 | GetMouseModifierKey(wParam), 1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
return 0;
|
||||
case WM_MBUTTONUP:
|
||||
process::Mouse(1 | GetMouseModifierKey(wParam), 1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
return 0;
|
||||
case WM_RBUTTONUP:
|
||||
process::Mouse(2 | GetMouseModifierKey(wParam), 1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
return 0;
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) ) {
|
||||
process::MouseMotion(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
} else{
|
||||
process::PassiveMouseMotion(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_MOUSEWHEEL:
|
||||
process::Scroll(0.0f, GET_WHEEL_DELTA_WPARAM(wParam) / 5.0f );
|
||||
return 0;
|
||||
case WM_MOUSEHWHEEL:
|
||||
process::Scroll(GET_WHEEL_DELTA_WPARAM(wParam) / 5.0f, 0.0f);
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return DefWindowProcA(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void WinWindow::StartFullScreen() {
|
||||
LONG dwExStyle = GetWindowLongA(hWnd, GWL_EXSTYLE)
|
||||
& ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
|
||||
if(dwExStyle==0) {
|
||||
std::cerr << "GetWindowLongA() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
LONG dwStyle = GetWindowLongA(hWnd, GWL_STYLE)
|
||||
& ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
|
||||
if(dwStyle==0) {
|
||||
std::cerr << "GetWindowLongA() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
|
||||
if(!SetWindowLongA(hWnd, GWL_EXSTYLE, dwExStyle)) {
|
||||
std::cerr << "SetWindowLongA() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
if(!SetWindowLongA(hWnd, GWL_STYLE, dwStyle)) {
|
||||
std::cerr << "SetWindowLongA() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
|
||||
GLint prev[2];
|
||||
std::memcpy(prev, context->windowed_size, sizeof(prev));
|
||||
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
|
||||
std::memcpy(context->windowed_size, prev, sizeof(prev));
|
||||
}
|
||||
|
||||
void WinWindow::StopFullScreen() {
|
||||
ChangeDisplaySettings(NULL, 0);
|
||||
ShowCursor(TRUE);
|
||||
|
||||
LONG dwExStyle = GetWindowLongA(hWnd, GWL_EXSTYLE) | WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
|
||||
LONG dwStyle = GetWindowLongA(hWnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW;
|
||||
|
||||
if(dwExStyle==0) {
|
||||
std::cerr << "GetWindowLongA() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
if(dwStyle==0) {
|
||||
std::cerr << "GetWindowLongA() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
|
||||
if(!SetWindowLongA(hWnd, GWL_EXSTYLE, dwExStyle)) {
|
||||
std::cerr << "SetWindowLongA() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
if(!SetWindowLongA(hWnd, GWL_STYLE, dwStyle)) {
|
||||
std::cerr << "SetWindowLongA() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
|
||||
if(!SetWindowPos(hWnd, HWND_TOP, 0, 0, context->windowed_size[0], context->windowed_size[1], SWP_FRAMECHANGED)) {
|
||||
std::cerr << "SetWindowPos() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
}
|
||||
|
||||
void WinWindow::ToggleFullscreen()
|
||||
{
|
||||
if(!context->is_fullscreen) {
|
||||
StartFullScreen();
|
||||
context->is_fullscreen = true;
|
||||
}else{
|
||||
StopFullScreen();
|
||||
context->is_fullscreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
void WinWindow::Move(int x, int y)
|
||||
{
|
||||
if( !SetWindowPos(hWnd, 0, x, y, 0, 0, SWP_NOSIZE) ) {
|
||||
std::cerr << "WinWindow::Move failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
}
|
||||
|
||||
void WinWindow::Resize(unsigned int w, unsigned int h)
|
||||
{
|
||||
if( !SetWindowPos(hWnd, 0, 0, 0, w, h, SWP_NOMOVE) ) {
|
||||
std::cerr << "WinWindow::Resize failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
}
|
||||
|
||||
void WinWindow::MakeCurrent()
|
||||
{
|
||||
if(wglMakeCurrent(hDC, hGLRC)==FALSE) {
|
||||
std::cerr << "wglMakeCurrent() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
|
||||
// Setup threadlocal context as this
|
||||
context = this;
|
||||
|
||||
RECT rect;
|
||||
if(!GetWindowRect(hWnd, &rect)) {
|
||||
std::cerr << "GetWindowRect() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
Resize(rect.right - rect.left, rect.bottom - rect.top);
|
||||
}
|
||||
|
||||
void WinWindow::RemoveCurrent()
|
||||
{
|
||||
if(wglMakeCurrent(NULL, NULL)==0) {
|
||||
std::cerr << "wglMakeCurrent() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
}
|
||||
|
||||
void WinWindow::SwapBuffers()
|
||||
{
|
||||
if(!::SwapBuffers(hDC)) {
|
||||
std::cerr << "SwapBuffers() failed" << std::endl;
|
||||
CheckWGLDieOnError();
|
||||
}
|
||||
}
|
||||
|
||||
void WinWindow::ProcessEvents()
|
||||
{
|
||||
MSG msg;
|
||||
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
if (msg.message == WM_QUIT) {
|
||||
pangolin::Quit();
|
||||
break;
|
||||
}
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowInterface> CreateWinWindowAndBind(std::string window_title, int w, int h)
|
||||
{
|
||||
WinWindow* win = new WinWindow(window_title, w, h);
|
||||
|
||||
return std::unique_ptr<WindowInterface>(win);
|
||||
}
|
||||
|
||||
PANGOLIN_REGISTER_FACTORY(WinWindow)
|
||||
{
|
||||
struct WinWindowFactory : public FactoryInterface<WindowInterface> {
|
||||
std::unique_ptr<WindowInterface> Open(const Uri& uri) override {
|
||||
|
||||
const std::string window_title = uri.Get<std::string>("window_title", "window");
|
||||
const int w = uri.Get<int>("w", 640);
|
||||
const int h = uri.Get<int>("h", 480);
|
||||
return std::unique_ptr<WindowInterface>(CreateWinWindowAndBind(window_title, w, h));
|
||||
}
|
||||
};
|
||||
|
||||
auto factory = std::make_shared<WinWindowFactory>();
|
||||
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 10, "winapi");
|
||||
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 100, "default");
|
||||
}
|
||||
|
||||
}
|
||||
530
thirdparty/Pangolin/src/display/device/display_x11.cpp
vendored
Normal file
530
thirdparty/Pangolin/src/display/device/display_x11.cpp
vendored
Normal file
@@ -0,0 +1,530 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2011-2018 Steven Lovegrove, Andrey Mnatsakanov
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
// Code based on public domain sample at
|
||||
// https://www.opengl.org/wiki/Tutorial:_OpenGL_3.0_Context_Creation_%28GLX%29
|
||||
|
||||
#include <pangolin/factory/factory_registry.h>
|
||||
#include <pangolin/platform.h>
|
||||
#include <pangolin/gl/glinclude.h>
|
||||
#include <pangolin/display/display.h>
|
||||
#include <pangolin/display/display_internal.h>
|
||||
#include <pangolin/display/window.h>
|
||||
|
||||
#include <pangolin/display/device/X11Window.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <GL/glx.h>
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
|
||||
extern __thread PangolinGl* context;
|
||||
|
||||
std::mutex window_mutex;
|
||||
std::weak_ptr<X11GlContext> global_gl_context;
|
||||
|
||||
const long EVENT_MASKS = ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|FocusChangeMask;
|
||||
|
||||
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
typedef GLXContext (*glXCreateContextAttribsARBProc)(::Display*, ::GLXFBConfig, ::GLXContext, Bool, const int*);
|
||||
|
||||
// Adapted from: http://www.opengl.org/resources/features/OGLextensions/
|
||||
bool isExtensionSupported(const char *extList, const char *extension)
|
||||
{
|
||||
/* Extension names should not have spaces. */
|
||||
const char* where = strchr(extension, ' ');
|
||||
if (where || *extension == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(const char* start=extList;;) {
|
||||
where = strstr(start, extension);
|
||||
if (!where) {
|
||||
break;
|
||||
}
|
||||
|
||||
const char *terminator = where + strlen(extension);
|
||||
|
||||
if ( where == start || *(where - 1) == ' ' ) {
|
||||
if ( *terminator == ' ' || *terminator == '\0' ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
start = terminator;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
::GLXFBConfig ChooseFrameBuffer(
|
||||
::Display *display, bool glx_doublebuffer,
|
||||
int glx_sample_buffers, int glx_samples
|
||||
) {
|
||||
// Desired attributes
|
||||
int visual_attribs[] =
|
||||
{
|
||||
GLX_X_RENDERABLE , True,
|
||||
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
|
||||
GLX_RENDER_TYPE , GLX_RGBA_BIT,
|
||||
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
|
||||
GLX_RED_SIZE , 8,
|
||||
GLX_GREEN_SIZE , 8,
|
||||
GLX_BLUE_SIZE , 8,
|
||||
GLX_ALPHA_SIZE , 8,
|
||||
GLX_DEPTH_SIZE , 24,
|
||||
GLX_STENCIL_SIZE , 8,
|
||||
GLX_DOUBLEBUFFER , glx_doublebuffer ? True : False,
|
||||
None
|
||||
};
|
||||
|
||||
int fbcount;
|
||||
GLXFBConfig* fbc = glXChooseFBConfig(display, DefaultScreen(display), visual_attribs, &fbcount);
|
||||
if (!fbc) {
|
||||
throw std::runtime_error("Pangolin X11: Unable to retrieve framebuffer options");
|
||||
}
|
||||
|
||||
int best_fbc = -1;
|
||||
int worst_fbc = -1;
|
||||
int best_num_samp = -1;
|
||||
int worst_num_samp = 999;
|
||||
|
||||
// Enumerate framebuffer options, storing the best and worst that match our attribs
|
||||
for (int i=0; i<fbcount; ++i)
|
||||
{
|
||||
XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] );
|
||||
if ( vi )
|
||||
{
|
||||
int samp_buf, samples;
|
||||
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf );
|
||||
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLES , &samples );
|
||||
|
||||
// Filter for the best available.
|
||||
if ( samples > best_num_samp ) {
|
||||
best_fbc = i;
|
||||
best_num_samp = samples;
|
||||
}
|
||||
|
||||
// Filter lowest settings which match minimum user requirement.
|
||||
if ( samp_buf >= glx_sample_buffers && samples >= glx_samples && samples < worst_num_samp ) {
|
||||
worst_fbc = i;
|
||||
worst_num_samp = samples;
|
||||
}
|
||||
}
|
||||
XFree( vi );
|
||||
}
|
||||
|
||||
// Select the minimum suitable option. The 'best' is often too slow.
|
||||
int chosen_fbc_id = worst_fbc;
|
||||
|
||||
// If minimum requested isn't available, return the best that is.
|
||||
if(chosen_fbc_id < 0) {
|
||||
pango_print_warn("Framebuffer with requested attributes not available. Using available framebuffer. You may see visual artifacts.");
|
||||
chosen_fbc_id = best_fbc;
|
||||
}
|
||||
|
||||
::GLXFBConfig chosenFbc = fbc[ chosen_fbc_id ];
|
||||
XFree( fbc );
|
||||
return chosenFbc;
|
||||
}
|
||||
|
||||
static bool ctxErrorOccurred = false;
|
||||
static int ctxErrorHandler( ::Display * /*dpy*/, ::XErrorEvent * ev )
|
||||
{
|
||||
const int buffer_size = 10240;
|
||||
char buffer[buffer_size];
|
||||
XGetErrorText(ev->display, ev->error_code, buffer, buffer_size );
|
||||
pango_print_error("X11 Error: %s\n", buffer);
|
||||
ctxErrorOccurred = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLXContext CreateGlContext(::Display *display, ::GLXFBConfig chosenFbc, GLXContext share_context = 0)
|
||||
{
|
||||
int glx_major, glx_minor;
|
||||
if ( !glXQueryVersion( display, &glx_major, &glx_minor ) ||
|
||||
( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) )
|
||||
{
|
||||
throw std::runtime_error("Pangolin X11: Invalid GLX version. Require GLX >= 1.3");
|
||||
}
|
||||
|
||||
GLXContext new_ctx;
|
||||
|
||||
// Get the default screen's GLX extension list
|
||||
const char *glxExts = glXQueryExtensionsString( display, DefaultScreen( display ) );
|
||||
|
||||
glXCreateContextAttribsARBProc glXCreateContextAttribsARB =
|
||||
(glXCreateContextAttribsARBProc) glXGetProcAddressARB(
|
||||
(const GLubyte *) "glXCreateContextAttribsARB"
|
||||
);
|
||||
|
||||
// Install an X error handler so the application won't exit if GL 3.0
|
||||
// context allocation fails. Handler is global and shared across all threads.
|
||||
ctxErrorOccurred = false;
|
||||
int (*oldHandler)(::Display*, ::XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
|
||||
|
||||
if ( isExtensionSupported( glxExts, "GLX_ARB_create_context" ) && glXCreateContextAttribsARB )
|
||||
{
|
||||
int context_attribs[] = {
|
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
|
||||
//GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
|
||||
None
|
||||
};
|
||||
|
||||
new_ctx = glXCreateContextAttribsARB( display, chosenFbc, share_context, True, context_attribs );
|
||||
|
||||
// Sync to ensure any errors generated are processed.
|
||||
XSync( display, False );
|
||||
if ( ctxErrorOccurred || !new_ctx ) {
|
||||
ctxErrorOccurred = false;
|
||||
// Fall back to old-style 2.x context. Implementations will return the newest
|
||||
// context version compatible with OpenGL versions less than version 3.0.
|
||||
context_attribs[1] = 1; // GLX_CONTEXT_MAJOR_VERSION_ARB = 1
|
||||
context_attribs[3] = 0; // GLX_CONTEXT_MINOR_VERSION_ARB = 0
|
||||
new_ctx = glXCreateContextAttribsARB( display, chosenFbc, share_context, True, context_attribs );
|
||||
}
|
||||
} else {
|
||||
// Fallback to GLX 1.3 Context
|
||||
new_ctx = glXCreateNewContext( display, chosenFbc, GLX_RGBA_TYPE, share_context, True );
|
||||
}
|
||||
|
||||
// Sync to ensure any errors generated are processed.
|
||||
XSync( display, False );
|
||||
|
||||
// Restore the original error handler
|
||||
XSetErrorHandler( oldHandler );
|
||||
|
||||
if ( ctxErrorOccurred || !new_ctx ) {
|
||||
throw std::runtime_error("Pangolin X11: Failed to create an OpenGL context");
|
||||
}
|
||||
|
||||
// Verifying that context is a direct context
|
||||
if ( ! glXIsDirect ( display, new_ctx ) ) {
|
||||
pango_print_warn("Pangolin X11: Indirect GLX rendering context obtained\n");
|
||||
}
|
||||
|
||||
return new_ctx;
|
||||
}
|
||||
|
||||
X11GlContext::X11GlContext(std::shared_ptr<X11Display>& d, ::GLXFBConfig chosenFbc, std::shared_ptr<X11GlContext> shared_context)
|
||||
: display(d), shared_context(shared_context)
|
||||
{
|
||||
// prevent chained sharing
|
||||
while(shared_context && shared_context->shared_context) {
|
||||
shared_context = shared_context->shared_context;
|
||||
}
|
||||
|
||||
// Contexts can't be shared across different displays.
|
||||
if(shared_context && shared_context->display != d) {
|
||||
shared_context.reset();
|
||||
}
|
||||
|
||||
glcontext = CreateGlContext(display->display, chosenFbc, shared_context ? shared_context->glcontext : 0);
|
||||
}
|
||||
|
||||
X11GlContext::~X11GlContext()
|
||||
{
|
||||
glXDestroyContext( display->display, glcontext );
|
||||
}
|
||||
|
||||
X11Window::X11Window(
|
||||
const std::string& title, int width, int height,
|
||||
std::shared_ptr<X11Display>& display, ::GLXFBConfig chosenFbc
|
||||
) : display(display), glcontext(0), win(0), cmap(0)
|
||||
{
|
||||
PangolinGl::windowed_size[0] = width;
|
||||
PangolinGl::windowed_size[1] = height;
|
||||
|
||||
// Get a visual
|
||||
XVisualInfo *vi = glXGetVisualFromFBConfig( display->display, chosenFbc );
|
||||
|
||||
// Create colourmap
|
||||
XSetWindowAttributes swa;
|
||||
swa.background_pixmap = None;
|
||||
swa.border_pixel = 0;
|
||||
swa.event_mask = StructureNotifyMask;
|
||||
swa.colormap = cmap = XCreateColormap( display->display,
|
||||
RootWindow( display->display, vi->screen ),
|
||||
vi->visual, AllocNone );
|
||||
|
||||
// Create window
|
||||
win = XCreateWindow( display->display, RootWindow( display->display, vi->screen ),
|
||||
0, 0, width, height, 0, vi->depth, InputOutput,
|
||||
vi->visual,
|
||||
CWBorderPixel|CWColormap|CWEventMask, &swa );
|
||||
|
||||
XFree( vi );
|
||||
|
||||
if ( !win ) {
|
||||
throw std::runtime_error("Pangolin X11: Failed to create window." );
|
||||
}
|
||||
|
||||
XStoreName( display->display, win, title.c_str() );
|
||||
XMapWindow( display->display, win );
|
||||
|
||||
// Request to be notified of these events
|
||||
XSelectInput(display->display, win, EVENT_MASKS );
|
||||
|
||||
delete_message = XInternAtom(display->display, "WM_DELETE_WINDOW", False);
|
||||
XSetWMProtocols(display->display, win, &delete_message, 1);
|
||||
}
|
||||
|
||||
X11Window::~X11Window()
|
||||
{
|
||||
glXMakeCurrent( display->display, 0, 0 );
|
||||
XDestroyWindow( display->display, win );
|
||||
XFreeColormap( display->display, cmap );
|
||||
}
|
||||
|
||||
void X11Window::MakeCurrent(GLXContext ctx)
|
||||
{
|
||||
glXMakeCurrent( display->display, win, ctx );
|
||||
context = this;
|
||||
}
|
||||
|
||||
void X11Window::MakeCurrent()
|
||||
{
|
||||
MakeCurrent(glcontext ? glcontext->glcontext : global_gl_context.lock()->glcontext);
|
||||
}
|
||||
|
||||
void X11Window::RemoveCurrent()
|
||||
{
|
||||
glXMakeCurrent(display->display, 0, nullptr);
|
||||
}
|
||||
|
||||
void X11Window::ToggleFullscreen()
|
||||
{
|
||||
const Atom _NET_WM_STATE_FULLSCREEN = XInternAtom(display->display, "_NET_WM_STATE_FULLSCREEN", True);
|
||||
const Atom _NET_WM_STATE = XInternAtom(display->display, "_NET_WM_STATE", True);
|
||||
XEvent e;
|
||||
e.xclient.type = ClientMessage;
|
||||
e.xclient.window = win;
|
||||
e.xclient.message_type = _NET_WM_STATE;
|
||||
e.xclient.format = 32;
|
||||
e.xclient.data.l[0] = 2; // Toggle
|
||||
e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
|
||||
e.xclient.data.l[2] = 0;
|
||||
e.xclient.data.l[3] = 1;
|
||||
e.xclient.data.l[4] = 0;
|
||||
|
||||
XSendEvent(display->display, DefaultRootWindow(display->display), False, SubstructureRedirectMask | SubstructureNotifyMask, &e);
|
||||
XMoveResizeWindow(display->display, win, 0, 0, windowed_size[0], windowed_size[1]);
|
||||
}
|
||||
|
||||
void X11Window::Move(int x, int y)
|
||||
{
|
||||
XMoveWindow(display->display, win, x, y);
|
||||
}
|
||||
|
||||
void X11Window::Resize(unsigned int w, unsigned int h)
|
||||
{
|
||||
XResizeWindow(display->display, win, w, h);
|
||||
}
|
||||
|
||||
void X11Window::ProcessEvents()
|
||||
{
|
||||
XEvent ev;
|
||||
while(!pangolin::ShouldQuit() && XPending(display->display) > 0)
|
||||
{
|
||||
XNextEvent(display->display, &ev);
|
||||
|
||||
switch(ev.type){
|
||||
case ConfigureNotify:
|
||||
pangolin::process::Resize(ev.xconfigure.width, ev.xconfigure.height);
|
||||
break;
|
||||
case ClientMessage:
|
||||
// We've only registered to receive WM_DELETE_WINDOW, so no further checks needed.
|
||||
pangolin::Quit();
|
||||
break;
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
{
|
||||
const int button = ev.xbutton.button-1;
|
||||
pangolin::process::Mouse(
|
||||
button,
|
||||
ev.xbutton.type == ButtonRelease,
|
||||
ev.xbutton.x, ev.xbutton.y
|
||||
);
|
||||
break;
|
||||
}
|
||||
case FocusOut:
|
||||
pangolin::context->mouse_state = 0;
|
||||
break;
|
||||
case MotionNotify:
|
||||
if(ev.xmotion.state & (Button1Mask|Button2Mask|Button3Mask) ) {
|
||||
pangolin::process::MouseMotion(ev.xmotion.x, ev.xmotion.y);
|
||||
}else{
|
||||
pangolin::process::PassiveMouseMotion(ev.xmotion.x, ev.xmotion.y);
|
||||
}
|
||||
break;
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
int key;
|
||||
char ch;
|
||||
KeySym sym;
|
||||
|
||||
if( XLookupString(&ev.xkey,&ch,1,&sym,0) == 0) {
|
||||
switch (sym) {
|
||||
case XK_F1: key = PANGO_SPECIAL + PANGO_KEY_F1 ; break;
|
||||
case XK_F2: key = PANGO_SPECIAL + PANGO_KEY_F2 ; break;
|
||||
case XK_F3: key = PANGO_SPECIAL + PANGO_KEY_F3 ; break;
|
||||
case XK_F4: key = PANGO_SPECIAL + PANGO_KEY_F4 ; break;
|
||||
case XK_F5: key = PANGO_SPECIAL + PANGO_KEY_F5 ; break;
|
||||
case XK_F6: key = PANGO_SPECIAL + PANGO_KEY_F6 ; break;
|
||||
case XK_F7: key = PANGO_SPECIAL + PANGO_KEY_F7 ; break;
|
||||
case XK_F8: key = PANGO_SPECIAL + PANGO_KEY_F8 ; break;
|
||||
case XK_F9: key = PANGO_SPECIAL + PANGO_KEY_F9 ; break;
|
||||
case XK_F10: key = PANGO_SPECIAL + PANGO_KEY_F10 ; break;
|
||||
case XK_F11: key = PANGO_SPECIAL + PANGO_KEY_F11 ; break;
|
||||
case XK_F12: key = PANGO_SPECIAL + PANGO_KEY_F12 ; break;
|
||||
case XK_Left: key = PANGO_SPECIAL + PANGO_KEY_LEFT ; break;
|
||||
case XK_Up: key = PANGO_SPECIAL + PANGO_KEY_UP ; break;
|
||||
case XK_Right: key = PANGO_SPECIAL + PANGO_KEY_RIGHT ; break;
|
||||
case XK_Down: key = PANGO_SPECIAL + PANGO_KEY_DOWN ; break;
|
||||
case XK_Page_Up: key = PANGO_SPECIAL + PANGO_KEY_PAGE_UP ; break;
|
||||
case XK_Page_Down: key = PANGO_SPECIAL + PANGO_KEY_PAGE_DOWN ; break;
|
||||
case XK_Home: key = PANGO_SPECIAL + PANGO_KEY_HOME ; break;
|
||||
case XK_End: key = PANGO_SPECIAL + PANGO_KEY_END ; break;
|
||||
case XK_Insert: key = PANGO_SPECIAL + PANGO_KEY_INSERT ; break;
|
||||
case XK_Shift_L:
|
||||
case XK_Shift_R:
|
||||
key = -1;
|
||||
if(ev.type==KeyPress) {
|
||||
pangolin::context->mouse_state |= pangolin::KeyModifierShift;
|
||||
}else{
|
||||
pangolin::context->mouse_state &= ~pangolin::KeyModifierShift;
|
||||
}
|
||||
break;
|
||||
case XK_Control_L:
|
||||
case XK_Control_R:
|
||||
key = -1;
|
||||
if(ev.type==KeyPress) {
|
||||
pangolin::context->mouse_state |= pangolin::KeyModifierCtrl;
|
||||
}else{
|
||||
pangolin::context->mouse_state &= ~pangolin::KeyModifierCtrl;
|
||||
}
|
||||
break;
|
||||
case XK_Alt_L:
|
||||
case XK_Alt_R:
|
||||
key = -1;
|
||||
if(ev.type==KeyPress) {
|
||||
pangolin::context->mouse_state |= pangolin::KeyModifierAlt;
|
||||
}else{
|
||||
pangolin::context->mouse_state &= ~pangolin::KeyModifierAlt;
|
||||
}
|
||||
break;
|
||||
case XK_Super_L:
|
||||
case XK_Super_R:
|
||||
key = -1;
|
||||
if(ev.type==KeyPress) {
|
||||
pangolin::context->mouse_state |= pangolin::KeyModifierCmd;
|
||||
}else{
|
||||
pangolin::context->mouse_state &= ~pangolin::KeyModifierCmd;
|
||||
}
|
||||
break;
|
||||
default: key = -1; break;
|
||||
}
|
||||
}else{
|
||||
key = ch;
|
||||
}
|
||||
|
||||
if(key >=0) {
|
||||
if(ev.type == KeyPress) {
|
||||
pangolin::process::Keyboard(key, ev.xkey.x, ev.xkey.y);
|
||||
}else{
|
||||
pangolin::process::KeyboardUp(key, ev.xkey.x, ev.xkey.y);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void X11Window::SwapBuffers() {
|
||||
glXSwapBuffers(display->display, win);
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowInterface> CreateX11WindowAndBind(const std::string& window_title, const int w, const int h, const std::string& display_name, const bool double_buffered, const int sample_buffers, const int samples)
|
||||
{
|
||||
std::shared_ptr<X11Display> newdisplay = std::make_shared<X11Display>(display_name.empty() ? NULL : display_name.c_str() );
|
||||
if (!newdisplay) {
|
||||
throw std::runtime_error("Pangolin X11: Failed to open X display");
|
||||
}
|
||||
::GLXFBConfig newfbc = ChooseFrameBuffer(newdisplay->display, double_buffered, sample_buffers, samples);
|
||||
|
||||
window_mutex.lock();
|
||||
std::shared_ptr<X11GlContext> newglcontext = std::make_shared<X11GlContext>(
|
||||
newdisplay, newfbc, global_gl_context.lock()
|
||||
);
|
||||
|
||||
if(!global_gl_context.lock()) {
|
||||
global_gl_context = newglcontext;
|
||||
}
|
||||
window_mutex.unlock();
|
||||
|
||||
X11Window* win = new X11Window(window_title, w, h, newdisplay, newfbc);
|
||||
win->glcontext = newglcontext;
|
||||
win->is_double_buffered = double_buffered;
|
||||
|
||||
return std::unique_ptr<WindowInterface>(win);
|
||||
}
|
||||
|
||||
PANGOLIN_REGISTER_FACTORY(X11Window)
|
||||
{
|
||||
struct X11WindowFactory : public FactoryInterface<WindowInterface> {
|
||||
std::unique_ptr<WindowInterface> Open(const Uri& uri) override {
|
||||
|
||||
const std::string window_title = uri.Get<std::string>("window_title", "window");
|
||||
const int w = uri.Get<int>("w", 640);
|
||||
const int h = uri.Get<int>("h", 480);
|
||||
const std::string display_name = uri.Get<std::string>("display_name", "");
|
||||
const bool double_buffered = uri.Get<bool>("double_buffered", true);
|
||||
const int sample_buffers = uri.Get<int>("sample_buffers", 1);
|
||||
const int samples = uri.Get<int>("samples", 1);
|
||||
return std::unique_ptr<WindowInterface>(CreateX11WindowAndBind(window_title, w, h, display_name, double_buffered, sample_buffers, samples));
|
||||
}
|
||||
};
|
||||
|
||||
auto factory = std::make_shared<X11WindowFactory>();
|
||||
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 10, "x11");
|
||||
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 10, "linux");
|
||||
FactoryRegistry<WindowInterface>::I().RegisterFactory(factory, 100, "default");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
660
thirdparty/Pangolin/src/display/display.cpp
vendored
Normal file
660
thirdparty/Pangolin/src/display/display.cpp
vendored
Normal file
@@ -0,0 +1,660 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2011 Steven Lovegrove, Richard Newcombe
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pangolin/platform.h>
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
#include <pangolin/python/pyinterpreter.h>
|
||||
#include <pangolin/console/ConsoleView.h>
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <pangolin/factory/factory_registry.h>
|
||||
#include <pangolin/window_frameworks.h>
|
||||
#include <pangolin/gl/glinclude.h>
|
||||
#include <pangolin/gl/gldraw.h>
|
||||
#include <pangolin/display/display.h>
|
||||
#include <pangolin/display/display_internal.h>
|
||||
#include <pangolin/handler/handler.h>
|
||||
#include <pangolin/utils/simple_math.h>
|
||||
#include <pangolin/utils/timer.h>
|
||||
#include <pangolin/utils/type_convert.h>
|
||||
#include <pangolin/image/image_io.h>
|
||||
|
||||
#ifdef BUILD_PANGOLIN_VARS
|
||||
#include <pangolin/var/var.h>
|
||||
#endif
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
|
||||
#ifdef BUILD_PANGOLIN_VIDEO
|
||||
// Forward declaration.
|
||||
void SaveFramebuffer(VideoOutput& video, const Viewport& v);
|
||||
#endif // BUILD_PANGOLIN_VIDEO
|
||||
|
||||
const char* PARAM_DISPLAYNAME = "DISPLAYNAME";
|
||||
const char* PARAM_DOUBLEBUFFER = "DOUBLEBUFFER";
|
||||
const char* PARAM_SAMPLE_BUFFERS = "SAMPLE_BUFFERS";
|
||||
const char* PARAM_SAMPLES = "SAMPLES";
|
||||
const char* PARAM_HIGHRES = "HIGHRES";
|
||||
|
||||
|
||||
typedef std::map<std::string,std::shared_ptr<PangolinGl> > ContextMap;
|
||||
|
||||
// Map of active contexts
|
||||
ContextMap contexts;
|
||||
std::recursive_mutex contexts_mutex;
|
||||
bool one_time_window_frameworks_init = false;
|
||||
|
||||
// Context active for current thread
|
||||
__thread PangolinGl* context = 0;
|
||||
|
||||
PangolinGl::PangolinGl()
|
||||
: user_app(0), is_high_res(false), quit(false), mouse_state(0),activeDisplay(0)
|
||||
#ifdef BUILD_PANGOLIN_VIDEO
|
||||
, record_view(0)
|
||||
#endif
|
||||
#ifdef HAVE_PYTHON
|
||||
, console_view(0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
PangolinGl::~PangolinGl()
|
||||
{
|
||||
// Free displays owned by named_managed_views
|
||||
for(ViewMap::iterator iv = named_managed_views.begin(); iv != named_managed_views.end(); ++iv) {
|
||||
delete iv->second;
|
||||
}
|
||||
named_managed_views.clear();
|
||||
}
|
||||
|
||||
PangolinGl* GetCurrentContext()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
PangolinGl *FindContext(const std::string& name)
|
||||
{
|
||||
contexts_mutex.lock();
|
||||
ContextMap::iterator ic = contexts.find(name);
|
||||
PangolinGl* context = (ic == contexts.end()) ? 0 : ic->second.get();
|
||||
contexts_mutex.unlock();
|
||||
return context;
|
||||
}
|
||||
|
||||
WindowInterface& CreateWindowAndBind(std::string window_title, int w, int h, const Params& params)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> l(contexts_mutex);
|
||||
|
||||
if(!one_time_window_frameworks_init) {
|
||||
one_time_window_frameworks_init = LoadBuiltInWindowFrameworks();
|
||||
}
|
||||
|
||||
pangolin::Uri win_uri;
|
||||
|
||||
if(const char* extra_params = std::getenv("PANGOLIN_WINDOW_URI"))
|
||||
{
|
||||
// Take any defaults from the environment
|
||||
win_uri = pangolin::ParseUri(extra_params);
|
||||
}else{
|
||||
// Otherwise revert to 'default' scheme.
|
||||
win_uri.scheme = "default";
|
||||
}
|
||||
|
||||
// Allow params to override
|
||||
win_uri.scheme = params.Get("scheme", win_uri.scheme);
|
||||
|
||||
// Override with anything the program specified
|
||||
win_uri.params.insert(std::end(win_uri.params), std::begin(params.params), std::end(params.params));
|
||||
win_uri.Set("w", w);
|
||||
win_uri.Set("h", h);
|
||||
win_uri.Set("window_title", window_title);
|
||||
|
||||
std::unique_ptr<WindowInterface> window = FactoryRegistry<WindowInterface>::I().Open(win_uri);
|
||||
|
||||
// We're expecting not only a WindowInterface, but a PangolinGl.
|
||||
if(!window || !dynamic_cast<PangolinGl*>(window.get())) {
|
||||
throw WindowExceptionNoKnownHandler(win_uri.scheme);
|
||||
}
|
||||
|
||||
std::shared_ptr<PangolinGl> context(dynamic_cast<PangolinGl*>(window.release()));
|
||||
RegisterNewContext(window_title, context );
|
||||
// is_high_res will alter default font size and a few other gui elements.
|
||||
context->is_high_res = win_uri.Get(PARAM_HIGHRES,false);
|
||||
context->MakeCurrent();
|
||||
context->ProcessEvents();
|
||||
glewInit();
|
||||
|
||||
return *context;
|
||||
}
|
||||
|
||||
// Assumption: unique lock is held on contexts_mutex for multi-threaded operation
|
||||
void RegisterNewContext(const std::string& name, std::shared_ptr<PangolinGl> newcontext)
|
||||
{
|
||||
// Set defaults
|
||||
newcontext->base.left = 0.0;
|
||||
newcontext->base.bottom = 0.0;
|
||||
newcontext->base.top = 1.0;
|
||||
newcontext->base.right = 1.0;
|
||||
newcontext->base.aspect = 0;
|
||||
newcontext->base.handler = &StaticHandler;
|
||||
newcontext->is_fullscreen = false;
|
||||
|
||||
// Create and add
|
||||
if( contexts.find(name) != contexts.end() ) {
|
||||
throw std::runtime_error("Context already exists.");
|
||||
}
|
||||
contexts[name] = newcontext;
|
||||
|
||||
// Process the following as if this context is now current.
|
||||
PangolinGl *oldContext = context;
|
||||
context = newcontext.get();
|
||||
process::Resize(
|
||||
newcontext->windowed_size[0],
|
||||
newcontext->windowed_size[1]
|
||||
);
|
||||
|
||||
// Default key bindings can be overridden
|
||||
RegisterKeyPressCallback(PANGO_KEY_ESCAPE, Quit );
|
||||
RegisterKeyPressCallback('\t', ToggleFullscreen );
|
||||
RegisterKeyPressCallback('`', ToggleConsole );
|
||||
|
||||
context = oldContext;
|
||||
}
|
||||
|
||||
WindowInterface* GetBoundWindow()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
void DestroyWindow(const std::string& name)
|
||||
{
|
||||
contexts_mutex.lock();
|
||||
ContextMap::iterator ic = contexts.find(name);
|
||||
PangolinGl *context_to_destroy = (ic == contexts.end()) ? 0 : ic->second.get();
|
||||
if (context_to_destroy == context) {
|
||||
context = nullptr;
|
||||
}
|
||||
size_t erased = contexts.erase(name);
|
||||
if(erased == 0) {
|
||||
pango_print_warn("Context '%s' doesn't exist for deletion.\n", name.c_str());
|
||||
}
|
||||
contexts_mutex.unlock();
|
||||
}
|
||||
|
||||
WindowInterface& BindToContext(std::string name)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> l(contexts_mutex);
|
||||
|
||||
// N.B. context is modified prior to invoking MakeCurrent so that
|
||||
// state management callbacks (such as Resize()) can be correctly
|
||||
// processed.
|
||||
PangolinGl *context_to_bind = FindContext(name);
|
||||
if( !context_to_bind )
|
||||
{
|
||||
std::shared_ptr<PangolinGl> newcontext(new PangolinGl());
|
||||
RegisterNewContext(name, newcontext);
|
||||
return *(newcontext.get());
|
||||
}else{
|
||||
context_to_bind->MakeCurrent();
|
||||
return *context_to_bind;
|
||||
}
|
||||
}
|
||||
|
||||
void Quit()
|
||||
{
|
||||
context->quit = true;
|
||||
}
|
||||
|
||||
void QuitAll()
|
||||
{
|
||||
for(auto nc : contexts) {
|
||||
nc.second->quit = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldQuit()
|
||||
{
|
||||
return !context || context->quit;
|
||||
}
|
||||
|
||||
bool HadInput()
|
||||
{
|
||||
if( context->had_input > 0 )
|
||||
{
|
||||
--context->had_input;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasResized()
|
||||
{
|
||||
if( context->has_resized > 0 )
|
||||
{
|
||||
--context->has_resized;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void StartFullScreen() {
|
||||
if(!context->is_fullscreen) {
|
||||
context->ToggleFullscreen();
|
||||
context->is_fullscreen = true;
|
||||
}
|
||||
}
|
||||
|
||||
void StopFullScreen() {
|
||||
if(context->is_fullscreen) {
|
||||
context->ToggleFullscreen();
|
||||
context->is_fullscreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SetFullscreen(bool fullscreen)
|
||||
{
|
||||
if(fullscreen) {
|
||||
StartFullScreen();
|
||||
}else{
|
||||
StopFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderViews()
|
||||
{
|
||||
Viewport::DisableScissor();
|
||||
DisplayBase().Render();
|
||||
}
|
||||
|
||||
void RenderRecordGraphic(const Viewport& v)
|
||||
{
|
||||
const float r = 7;
|
||||
v.ActivatePixelOrthographic();
|
||||
glRecordGraphic(v.w-2*r, v.h-2*r, r);
|
||||
}
|
||||
|
||||
void PostRender()
|
||||
{
|
||||
while(context->screen_capture.size()) {
|
||||
std::pair<std::string,Viewport> fv = context->screen_capture.front();
|
||||
context->screen_capture.pop();
|
||||
SaveFramebuffer(fv.first, fv.second);
|
||||
}
|
||||
|
||||
#ifdef BUILD_PANGOLIN_VIDEO
|
||||
if(context->recorder.IsOpen()) {
|
||||
SaveFramebuffer(context->recorder, context->record_view->GetBounds() );
|
||||
RenderRecordGraphic(context->record_view->GetBounds());
|
||||
}
|
||||
#endif // BUILD_PANGOLIN_VIDEO
|
||||
|
||||
// Disable scissor each frame
|
||||
Viewport::DisableScissor();
|
||||
}
|
||||
|
||||
void FinishFrame()
|
||||
{
|
||||
RenderViews();
|
||||
PostRender();
|
||||
context->SwapBuffers();
|
||||
context->ProcessEvents();
|
||||
}
|
||||
|
||||
View& DisplayBase()
|
||||
{
|
||||
return context->base;
|
||||
}
|
||||
|
||||
View& CreateDisplay()
|
||||
{
|
||||
int iguid = rand();
|
||||
std::stringstream ssguid;
|
||||
ssguid << iguid;
|
||||
return Display(ssguid.str());
|
||||
}
|
||||
|
||||
void ToggleConsole()
|
||||
{
|
||||
#ifdef HAVE_PYTHON
|
||||
if( !context->console_view) {
|
||||
// Create console and let the pangolin context take ownership
|
||||
context->console_view = new ConsoleView(new PyInterpreter());
|
||||
context->named_managed_views["pangolin_console"] = context->console_view;
|
||||
context->console_view->SetFocus();
|
||||
context->console_view->zorder = std::numeric_limits<int>::max();
|
||||
DisplayBase().AddDisplay(*context->console_view);
|
||||
}else{
|
||||
context->console_view->ToggleShow();
|
||||
if(context->console_view->IsShown()) {
|
||||
context->console_view->SetFocus();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ToggleFullscreen()
|
||||
{
|
||||
SetFullscreen(!context->is_fullscreen);
|
||||
}
|
||||
|
||||
View& Display(const std::string& name)
|
||||
{
|
||||
// Get / Create View
|
||||
ViewMap::iterator vi = context->named_managed_views.find(name);
|
||||
if( vi != context->named_managed_views.end() )
|
||||
{
|
||||
return *(vi->second);
|
||||
}else{
|
||||
View * v = new View();
|
||||
context->named_managed_views[name] = v;
|
||||
v->handler = &StaticHandler;
|
||||
context->base.views.push_back(v);
|
||||
return *v;
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterKeyPressCallback(int key, std::function<void(void)> func)
|
||||
{
|
||||
context->keypress_hooks[key] = func;
|
||||
}
|
||||
|
||||
void SaveWindowOnRender(std::string prefix)
|
||||
{
|
||||
context->screen_capture.push(std::pair<std::string,Viewport>(prefix, context->base.v) );
|
||||
}
|
||||
|
||||
void SaveFramebuffer(std::string prefix, const Viewport& v)
|
||||
{
|
||||
PANGOLIN_UNUSED(prefix);
|
||||
PANGOLIN_UNUSED(v);
|
||||
|
||||
#ifndef HAVE_GLES
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
PixelFormat fmt = PixelFormatFromString("RGBA32");
|
||||
TypedImage buffer(v.w, v.h, fmt );
|
||||
glReadBuffer(GL_BACK);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1); // TODO: Avoid this?
|
||||
glReadPixels(v.l, v.b, v.w, v.h, GL_RGBA, GL_UNSIGNED_BYTE, buffer.ptr );
|
||||
SaveImage(buffer, fmt, prefix + ".png", false);
|
||||
#endif // HAVE_PNG
|
||||
|
||||
#endif // HAVE_GLES
|
||||
}
|
||||
|
||||
#ifdef BUILD_PANGOLIN_VIDEO
|
||||
void SaveFramebuffer(VideoOutput& video, const Viewport& v)
|
||||
{
|
||||
#ifndef HAVE_GLES
|
||||
const StreamInfo& si = video.Streams()[0];
|
||||
if(video.Streams().size()==0 || (int)si.Width() != v.w || (int)si.Height() != v.h) {
|
||||
video.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
static basetime last_time = TimeNow();
|
||||
const basetime time_now = TimeNow();
|
||||
last_time = time_now;
|
||||
|
||||
static std::vector<unsigned char> img;
|
||||
img.resize(v.w*v.h*4);
|
||||
|
||||
glReadBuffer(GL_BACK);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1); // TODO: Avoid this?
|
||||
glReadPixels(v.l, v.b, v.w, v.h, GL_RGB, GL_UNSIGNED_BYTE, &img[0] );
|
||||
video.WriteStreams(&img[0]);
|
||||
#endif // HAVE_GLES
|
||||
}
|
||||
#endif // BUILD_PANGOLIN_VIDEO
|
||||
|
||||
|
||||
namespace process
|
||||
{
|
||||
float last_x = 0;
|
||||
float last_y = 0;
|
||||
|
||||
void Keyboard( unsigned char key, int x, int y)
|
||||
{
|
||||
// Force coords to match OpenGl Window Coords
|
||||
y = context->base.v.h - y;
|
||||
|
||||
#ifdef HAVE_APPLE_OPENGL_FRAMEWORK
|
||||
// Switch backspace and delete for OSX!
|
||||
if(key== '\b') {
|
||||
key = 127;
|
||||
}else if(key == 127) {
|
||||
key = '\b';
|
||||
}
|
||||
#endif
|
||||
|
||||
context->had_input = context->is_double_buffered ? 2 : 1;
|
||||
|
||||
// Check if global key hook exists
|
||||
const KeyhookMap::iterator hook = context->keypress_hooks.find(key);
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
// Console receives all input when it is open
|
||||
if( context->console_view && context->console_view->IsShown() ) {
|
||||
context->console_view->Keyboard(*(context->console_view),key,x,y,true);
|
||||
}else
|
||||
#endif
|
||||
if(hook != context->keypress_hooks.end() ) {
|
||||
hook->second();
|
||||
} else if(context->activeDisplay && context->activeDisplay->handler) {
|
||||
context->activeDisplay->handler->Keyboard(*(context->activeDisplay),key,x,y,true);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardUp(unsigned char key, int x, int y)
|
||||
{
|
||||
// Force coords to match OpenGl Window Coords
|
||||
y = context->base.v.h - y;
|
||||
|
||||
if(context->activeDisplay && context->activeDisplay->handler)
|
||||
{
|
||||
context->activeDisplay->handler->Keyboard(*(context->activeDisplay),key,x,y,false);
|
||||
}
|
||||
}
|
||||
|
||||
void SpecialFunc(int key, int x, int y)
|
||||
{
|
||||
Keyboard(key+128,x,y);
|
||||
}
|
||||
|
||||
void SpecialFuncUp(int key, int x, int y)
|
||||
{
|
||||
KeyboardUp(key+128,x,y);
|
||||
}
|
||||
|
||||
|
||||
void Mouse( int button_raw, int state, int x, int y)
|
||||
{
|
||||
// Force coords to match OpenGl Window Coords
|
||||
y = context->base.v.h - y;
|
||||
|
||||
last_x = (float)x;
|
||||
last_y = (float)y;
|
||||
|
||||
const MouseButton button = (MouseButton)(1 << (button_raw & 0xf) );
|
||||
const bool pressed = (state == 0);
|
||||
|
||||
context->had_input = context->is_double_buffered ? 2 : 1;
|
||||
|
||||
const bool fresh_input = ( (context->mouse_state & 7) == 0);
|
||||
|
||||
if( pressed ) {
|
||||
context->mouse_state |= (button&7);
|
||||
}else{
|
||||
context->mouse_state &= ~(button&7);
|
||||
}
|
||||
|
||||
#if defined(_WIN_)
|
||||
context->mouse_state &= 0x0000ffff;
|
||||
context->mouse_state |= (button_raw >> 4) << 16;
|
||||
#endif
|
||||
|
||||
if(fresh_input) {
|
||||
context->base.handler->Mouse(context->base,button,x,y,pressed,context->mouse_state);
|
||||
}else if(context->activeDisplay && context->activeDisplay->handler) {
|
||||
context->activeDisplay->handler->Mouse(*(context->activeDisplay),button,x,y,pressed,context->mouse_state);
|
||||
}
|
||||
}
|
||||
|
||||
void MouseMotion( int x, int y)
|
||||
{
|
||||
// Force coords to match OpenGl Window Coords
|
||||
y = context->base.v.h - y;
|
||||
|
||||
last_x = (float)x;
|
||||
last_y = (float)y;
|
||||
|
||||
context->had_input = context->is_double_buffered ? 2 : 1;
|
||||
|
||||
if( context->activeDisplay)
|
||||
{
|
||||
if( context->activeDisplay->handler )
|
||||
context->activeDisplay->handler->MouseMotion(*(context->activeDisplay),x,y,context->mouse_state);
|
||||
}else{
|
||||
context->base.handler->MouseMotion(context->base,x,y,context->mouse_state);
|
||||
}
|
||||
}
|
||||
|
||||
void PassiveMouseMotion(int x, int y)
|
||||
{
|
||||
// Force coords to match OpenGl Window Coords
|
||||
y = context->base.v.h - y;
|
||||
|
||||
context->base.handler->PassiveMouseMotion(context->base,x,y,context->mouse_state);
|
||||
|
||||
last_x = (float)x;
|
||||
last_y = (float)y;
|
||||
}
|
||||
|
||||
void Display()
|
||||
{
|
||||
// No implementation
|
||||
}
|
||||
|
||||
void Resize( int width, int height )
|
||||
{
|
||||
if( !context->is_fullscreen )
|
||||
{
|
||||
context->windowed_size[0] = width;
|
||||
context->windowed_size[1] = height;
|
||||
}
|
||||
// TODO: Fancy display managers seem to cause this to mess up?
|
||||
context->had_input = 20; //context->is_double_buffered ? 2 : 1;
|
||||
context->has_resized = 20; //context->is_double_buffered ? 2 : 1;
|
||||
Viewport win(0,0,width,height);
|
||||
context->base.Resize(win);
|
||||
}
|
||||
|
||||
void SpecialInput(InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4)
|
||||
{
|
||||
// Assume coords already match OpenGl Window Coords
|
||||
|
||||
context->had_input = context->is_double_buffered ? 2 : 1;
|
||||
|
||||
const bool fresh_input = (context->mouse_state == 0);
|
||||
|
||||
if(fresh_input) {
|
||||
context->base.handler->Special(context->base,inType,x,y,p1,p2,p3,p4,context->mouse_state);
|
||||
}else if(context->activeDisplay && context->activeDisplay->handler) {
|
||||
context->activeDisplay->handler->Special(*(context->activeDisplay),inType,x,y,p1,p2,p3,p4,context->mouse_state);
|
||||
}
|
||||
}
|
||||
|
||||
void Scroll(float x, float y)
|
||||
{
|
||||
SpecialInput(InputSpecialScroll, last_x, last_y, x, y, 0, 0);
|
||||
}
|
||||
|
||||
void Zoom(float m)
|
||||
{
|
||||
SpecialInput(InputSpecialZoom, last_x, last_y, m, 0, 0, 0);
|
||||
}
|
||||
|
||||
void Rotate(float r)
|
||||
{
|
||||
SpecialInput(InputSpecialRotate, last_x, last_y, r, 0, 0, 0);
|
||||
}
|
||||
|
||||
void SubpixMotion(float x, float y, float pressure, float rotation, float tiltx, float tilty)
|
||||
{
|
||||
// Force coords to match OpenGl Window Coords
|
||||
y = context->base.v.h - y;
|
||||
SpecialInput(InputSpecialTablet, x, y, pressure, rotation, tiltx, tilty);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawTextureToViewport(GLuint texid)
|
||||
{
|
||||
OpenGlRenderState::ApplyIdentity();
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
GLfloat sq_vert[] = { -1,-1, 1,-1, 1, 1, -1, 1 };
|
||||
glVertexPointer(2, GL_FLOAT, 0, sq_vert);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
GLfloat sq_tex[] = { 0,0, 1,0, 1,1, 0,1 };
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, sq_tex);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
ToggleViewFunctor::ToggleViewFunctor(View& view)
|
||||
: view(view)
|
||||
{
|
||||
}
|
||||
|
||||
ToggleViewFunctor::ToggleViewFunctor(const std::string& name)
|
||||
: view(Display(name))
|
||||
{
|
||||
}
|
||||
|
||||
void ToggleViewFunctor::operator()()
|
||||
{
|
||||
view.ToggleShow();
|
||||
}
|
||||
|
||||
}
|
||||
223
thirdparty/Pangolin/src/display/image_view.cpp
vendored
Normal file
223
thirdparty/Pangolin/src/display/image_view.cpp
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
#include <pangolin/display/image_view.h>
|
||||
#include <pangolin/image/image_utils.h>
|
||||
#include <pangolin/image/image_convert.h>
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
|
||||
ImageView::ImageView()
|
||||
: offset_scale(0.0f, 1.0f), lastPressed(false), mouseReleased(false), mousePressed(false), overlayRender(true)
|
||||
{
|
||||
SetHandler(this);
|
||||
}
|
||||
|
||||
ImageView::~ImageView()
|
||||
{
|
||||
}
|
||||
|
||||
void ImageView::Render()
|
||||
{
|
||||
LoadPending();
|
||||
|
||||
glPushAttrib(GL_DEPTH_BITS);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
Activate();
|
||||
this->UpdateView();
|
||||
this->glSetViewOrtho();
|
||||
|
||||
if(tex.IsValid())
|
||||
{
|
||||
if(offset_scale.first != 0.0 || offset_scale.second != 1.0)
|
||||
{
|
||||
pangolin::GlSlUtilities::OffsetAndScale(offset_scale.first, offset_scale.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
glColor4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
this->glRenderTexture(tex);
|
||||
pangolin::GlSlUtilities::UseNone();
|
||||
}
|
||||
|
||||
if(overlayRender)
|
||||
{
|
||||
this->glRenderOverlay();
|
||||
}
|
||||
|
||||
if(extern_draw_function)
|
||||
{
|
||||
extern_draw_function(*this);
|
||||
}
|
||||
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
void ImageView::Mouse(View& view, pangolin::MouseButton button, int x, int y, bool pressed, int button_state)
|
||||
{
|
||||
ImageViewHandler::Mouse(view, button, x, y, pressed, button_state);
|
||||
|
||||
mouseReleased = (!pressed && lastPressed);
|
||||
|
||||
mousePressed = lastPressed = (pressed && button == pangolin::MouseButtonLeft);
|
||||
}
|
||||
|
||||
void ImageView::Keyboard(View& view, unsigned char key, int x, int y, bool pressed)
|
||||
{
|
||||
if(key == 'a')
|
||||
{
|
||||
if(!tex.IsValid())
|
||||
{
|
||||
std::cerr << "ImageViewHandler does not contain valid texture." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// compute scale
|
||||
const bool have_selection = std::isfinite(GetSelection().Area()) && std::abs(GetSelection().Area()) >= 4;
|
||||
const pangolin::XYRangef froi = have_selection ? GetSelection() : GetViewToRender();
|
||||
|
||||
// Download texture so that we can take min / max
|
||||
pangolin::TypedImage img;
|
||||
tex.Download(img);
|
||||
offset_scale = pangolin::GetOffsetScale(img, pangolin::Round(froi), img.fmt);
|
||||
}
|
||||
else if(key == 'b')
|
||||
{
|
||||
if(!tex.IsValid())
|
||||
{
|
||||
std::cerr << "ImageViewHandler does not contain valid texture." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// compute scale
|
||||
const bool have_selection = std::isfinite(GetSelection().Area()) && std::abs(GetSelection().Area()) >= 4;
|
||||
const pangolin::XYRangef froi = have_selection ? GetSelection() : GetViewToRender();
|
||||
|
||||
// Download texture so that we can take min / max
|
||||
pangolin::TypedImage img;
|
||||
tex.Download(img);
|
||||
std::pair<float, float> mm = pangolin::GetMinMax(img, pangolin::Round(froi), img.fmt);
|
||||
|
||||
printf("Min / Max in Region: %f / %f\n", mm.first, mm.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
pangolin::ImageViewHandler::Keyboard(view, key, x, y, pressed);
|
||||
}
|
||||
}
|
||||
|
||||
pangolin::GlTexture& ImageView::Tex() {
|
||||
return tex;
|
||||
}
|
||||
|
||||
ImageView& ImageView::SetImage(void* ptr, size_t w, size_t h, size_t pitch, pangolin::GlPixFormat img_fmt, bool delayed_upload )
|
||||
{
|
||||
const size_t pix_bytes =
|
||||
pangolin::GlFormatChannels(img_fmt.glformat) * pangolin::GlDataTypeBytes(img_fmt.gltype);
|
||||
|
||||
const bool convert_first = (img_fmt.gltype == GL_DOUBLE);
|
||||
|
||||
if(delayed_upload || !pangolin::GetBoundWindow() || IsDevicePtr(ptr) || convert_first )
|
||||
{
|
||||
texlock.lock();
|
||||
if(!convert_first) {
|
||||
img_to_load = ManagedImage<unsigned char>(w,h,w*pix_bytes);
|
||||
PitchedCopy((char*)img_to_load.ptr, img_to_load.pitch, (char*)ptr, pitch, w * pix_bytes, h);
|
||||
img_fmt_to_load = img_fmt;
|
||||
}else if(img_fmt.gltype == GL_DOUBLE) {
|
||||
Image<double> double_image( (double*)ptr, w, h, pitch);
|
||||
img_to_load.OwnAndReinterpret(ImageConvert<float>(double_image));
|
||||
img_fmt_to_load = GlPixFormat::FromType<float>();
|
||||
}else{
|
||||
pango_print_warn("TextureView: Unable to display image.\n");
|
||||
}
|
||||
texlock.unlock();
|
||||
return *this;
|
||||
}
|
||||
|
||||
PANGO_ASSERT(pitch % pix_bytes == 0);
|
||||
const size_t stride = pitch / pix_bytes;
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||
|
||||
// Initialise if it didn't already exist or the size was too small
|
||||
if(!tex.tid || tex.width != (int)w || tex.height != (int)h ||
|
||||
tex.internal_format != img_fmt.scalable_internal_format)
|
||||
{
|
||||
fmt = img_fmt;
|
||||
SetDimensions(w, h);
|
||||
SetAspect((float)w / (float)h);
|
||||
tex.Reinitialise(w, h, img_fmt.scalable_internal_format, true, 0, img_fmt.glformat, img_fmt.gltype, ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
tex.Upload(ptr, img_fmt.glformat, img_fmt.gltype);
|
||||
}
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ImageView& ImageView::SetImage(const pangolin::Image<unsigned char>& img, const pangolin::GlPixFormat& glfmt, bool delayed_upload )
|
||||
{
|
||||
return SetImage(img.ptr, img.w, img.h, img.pitch, glfmt, delayed_upload);
|
||||
}
|
||||
|
||||
ImageView& ImageView::SetImage(const pangolin::TypedImage& img, bool delayed_upload )
|
||||
{
|
||||
return SetImage(img.ptr, img.w, img.h, img.pitch, pangolin::GlPixFormat(img.fmt), delayed_upload);
|
||||
}
|
||||
|
||||
ImageView& ImageView::SetImage(const pangolin::GlTexture& texture)
|
||||
{
|
||||
// Initialise if it didn't already exist or the size was too small
|
||||
if(!tex.tid || tex.width != texture.width || tex.height != texture.height ||
|
||||
tex.internal_format != texture.internal_format)
|
||||
{
|
||||
SetDimensions(texture.width, texture.height);
|
||||
SetAspect((float)texture.width / (float)texture.height);
|
||||
tex.Reinitialise(texture.width, texture.height, texture.internal_format, true);
|
||||
}
|
||||
|
||||
glCopyImageSubData(
|
||||
texture.tid, GL_TEXTURE_2D, 0, 0, 0, 0, tex.tid, GL_TEXTURE_2D, 0, 0, 0, 0, tex.width, tex.height, 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ImageView::LoadPending()
|
||||
{
|
||||
if(img_to_load.ptr)
|
||||
{
|
||||
// Scoped lock
|
||||
texlock.lock();
|
||||
SetImage(img_to_load, img_fmt_to_load, false);
|
||||
img_to_load.Deallocate();
|
||||
texlock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
ImageView& ImageView::Clear()
|
||||
{
|
||||
tex.Delete();
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::pair<float, float>& ImageView::GetOffsetScale() {
|
||||
return offset_scale;
|
||||
}
|
||||
|
||||
bool ImageView::MouseReleased() const {
|
||||
return mouseReleased;
|
||||
}
|
||||
|
||||
bool ImageView::MousePressed() const {
|
||||
return mousePressed;
|
||||
}
|
||||
|
||||
void ImageView::SetRenderOverlay(const bool& val) {
|
||||
overlayRender = val;
|
||||
}
|
||||
|
||||
}
|
||||
707
thirdparty/Pangolin/src/display/opengl_render_state.cpp
vendored
Normal file
707
thirdparty/Pangolin/src/display/opengl_render_state.cpp
vendored
Normal file
@@ -0,0 +1,707 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2011 Steven Lovegrove, Richard Newcombe
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pangolin/display/opengl_render_state.h>
|
||||
#include <pangolin/gl/glinclude.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
|
||||
inline void glLoadMatrix(const float* m) { glLoadMatrixf(m); }
|
||||
inline void glMultMatrix(const float* m) { glMultMatrixf(m); }
|
||||
|
||||
#ifndef HAVE_GLES
|
||||
inline void glLoadMatrix(const double* m) { glLoadMatrixd(m); }
|
||||
inline void glMultMatrix(const double* m) { glMultMatrixd(m); }
|
||||
#endif
|
||||
|
||||
OpenGlMatrix OpenGlMatrix::Translate(GLprecision x, GLprecision y, GLprecision z)
|
||||
{
|
||||
OpenGlMatrix mat;
|
||||
mat.SetIdentity();
|
||||
mat(0, 3) = x;
|
||||
mat(1, 3) = y;
|
||||
mat(2, 3) = z;
|
||||
return mat;
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlMatrix::Scale(GLprecision x, GLprecision y, GLprecision z)
|
||||
{
|
||||
OpenGlMatrix mat;
|
||||
mat.SetIdentity();
|
||||
mat(0, 0) = x;
|
||||
mat(1, 1) = y;
|
||||
mat(2, 2) = z;
|
||||
return mat;
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlMatrix::RotateX(GLprecision theta_rad)
|
||||
{
|
||||
OpenGlMatrix mat;
|
||||
mat.SetIdentity();
|
||||
const GLprecision costh = cos(theta_rad);
|
||||
const GLprecision sinth = sin(theta_rad);
|
||||
mat(1, 1) = costh;
|
||||
mat(1, 2) = -sinth;
|
||||
mat(2, 1) = sinth;
|
||||
mat(2, 2) = costh;
|
||||
return mat;
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlMatrix::RotateY(GLprecision theta_rad)
|
||||
{
|
||||
OpenGlMatrix mat;
|
||||
mat.SetIdentity();
|
||||
const GLprecision costh = cos(theta_rad);
|
||||
const GLprecision sinth = sin(theta_rad);
|
||||
mat(0, 0) = costh;
|
||||
mat(0, 2) = sinth;
|
||||
mat(2, 0) = -sinth;
|
||||
mat(2, 2) = costh;
|
||||
return mat;
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlMatrix::RotateZ(GLprecision theta_rad)
|
||||
{
|
||||
OpenGlMatrix mat;
|
||||
mat.SetIdentity();
|
||||
const GLprecision costh = cos(theta_rad);
|
||||
const GLprecision sinth = sin(theta_rad);
|
||||
mat(0, 0) = costh;
|
||||
mat(0, 1) = -sinth;
|
||||
mat(1, 0) = sinth;
|
||||
mat(1, 1) = costh;
|
||||
return mat;
|
||||
}
|
||||
|
||||
void OpenGlMatrix::Load() const
|
||||
{
|
||||
glLoadMatrix(m);
|
||||
}
|
||||
|
||||
void OpenGlMatrix::Multiply() const
|
||||
{
|
||||
glMultMatrix(m);
|
||||
}
|
||||
|
||||
void OpenGlMatrix::SetIdentity()
|
||||
{
|
||||
m[0] = 1.0f; m[1] = 0.0f; m[2] = 0.0f; m[3] = 0.0f;
|
||||
m[4] = 0.0f; m[5] = 1.0f; m[6] = 0.0f; m[7] = 0.0f;
|
||||
m[8] = 0.0f; m[9] = 0.0f; m[10] = 1.0f; m[11] = 0.0f;
|
||||
m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f;
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlMatrix::Transpose() const
|
||||
{
|
||||
OpenGlMatrix trans;
|
||||
trans.m[0] = m[0]; trans.m[4] = m[1]; trans.m[8] = m[2]; trans.m[12] = m[3];
|
||||
trans.m[1] = m[4]; trans.m[5] = m[5]; trans.m[9] = m[6]; trans.m[13] = m[7];
|
||||
trans.m[2] = m[8]; trans.m[6] = m[9]; trans.m[10] = m[10]; trans.m[14] = m[11];
|
||||
trans.m[3] = m[12]; trans.m[7] = m[13]; trans.m[11] = m[14]; trans.m[15] = m[15];
|
||||
return trans;
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlMatrix::Inverse() const
|
||||
{
|
||||
OpenGlMatrix inv;
|
||||
inv.m[0] = m[0]; inv.m[4] = m[1]; inv.m[8] = m[2]; inv.m[12] = -(m[0]*m[12] + m[1]*m[13] + m[2]*m[14]);
|
||||
inv.m[1] = m[4]; inv.m[5] = m[5]; inv.m[9] = m[6]; inv.m[13] = -(m[4]*m[12] + m[5]*m[13] + m[6]*m[14]);
|
||||
inv.m[2] = m[8]; inv.m[6] = m[9]; inv.m[10] = m[10]; inv.m[14] = -(m[8]*m[12] + m[9]*m[13] + m[10]*m[14]);
|
||||
inv.m[3] = 0; inv.m[7] = 0; inv.m[11] = 0; inv.m[15] = 1;
|
||||
return inv;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const OpenGlMatrix& mat)
|
||||
{
|
||||
for(int r=0; r< 4; ++r) {
|
||||
for(int c=0; c<4; ++c) {
|
||||
std::cout << mat.m[4*c+r] << '\t';
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
void OpenGlRenderState::Apply() const
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
projection[0].Load();
|
||||
|
||||
// Leave in MODEVIEW mode
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
modelview.Load();
|
||||
|
||||
if(follow) {
|
||||
T_cw.Multiply();
|
||||
}
|
||||
}
|
||||
|
||||
OpenGlMatrix& OpenGlRenderState::GetProjectionMatrix(unsigned int view)
|
||||
{
|
||||
if( projection.size() <= view ) {
|
||||
projection.resize(view+1);
|
||||
}
|
||||
return projection[view];
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlRenderState::GetProjectionMatrix(unsigned int view) const
|
||||
{
|
||||
if( projection.size() <= view ) {
|
||||
return IdentityMatrix();
|
||||
}
|
||||
return projection[view];
|
||||
}
|
||||
|
||||
OpenGlMatrix& OpenGlRenderState::GetViewOffset(unsigned int view)
|
||||
{
|
||||
if( modelview_premult.size() <= view ) {
|
||||
modelview_premult.resize(view+1);
|
||||
}
|
||||
return modelview_premult[view];
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlRenderState::GetViewOffset(unsigned int view) const
|
||||
{
|
||||
if( modelview_premult.size() <= view ) {
|
||||
return IdentityMatrix();
|
||||
}
|
||||
return modelview_premult[view];
|
||||
}
|
||||
|
||||
void OpenGlRenderState::ApplyNView(int view) const
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
projection[view].Load();
|
||||
|
||||
// Leave in MODEVIEW mode
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
OpenGlMatrix m = GetModelViewMatrix(view);
|
||||
m.Load();
|
||||
|
||||
if(follow) {
|
||||
T_cw.Multiply();
|
||||
}
|
||||
}
|
||||
|
||||
OpenGlRenderState::OpenGlRenderState()
|
||||
: modelview(IdentityMatrix()), follow(false)
|
||||
{
|
||||
projection.push_back( IdentityMatrix() );
|
||||
}
|
||||
|
||||
OpenGlRenderState::OpenGlRenderState(const OpenGlMatrix& projection_matrix)
|
||||
: modelview(IdentityMatrix()), follow(false)
|
||||
{
|
||||
projection.push_back( projection_matrix );
|
||||
}
|
||||
|
||||
OpenGlRenderState::OpenGlRenderState(const OpenGlMatrix& projection_matrix, const OpenGlMatrix& modelview_matrx)
|
||||
: modelview(modelview_matrx), follow(false)
|
||||
{
|
||||
projection.push_back( projection_matrix );
|
||||
}
|
||||
|
||||
void OpenGlRenderState::ApplyIdentity()
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
OpenGlRenderState& OpenGlRenderState::SetProjectionMatrix(OpenGlMatrix m)
|
||||
{
|
||||
projection[0] = m;
|
||||
return *this;
|
||||
}
|
||||
|
||||
OpenGlRenderState& OpenGlRenderState::SetModelViewMatrix(OpenGlMatrix m)
|
||||
{
|
||||
modelview = m;
|
||||
return *this;
|
||||
}
|
||||
|
||||
OpenGlRenderState& OpenGlRenderState::Set(OpenGlMatrixSpec m)
|
||||
{
|
||||
switch (m.type) {
|
||||
case GlProjectionStack:
|
||||
projection[0] = m;
|
||||
break;
|
||||
case GlModelViewStack:
|
||||
modelview = m;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unexpected matrix type");
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
OpenGlMatrix operator*(const OpenGlMatrix& lhs, const OpenGlMatrix& rhs)
|
||||
{
|
||||
OpenGlMatrix ret;
|
||||
pangolin::MatMul<4,4,4>(ret.m, lhs.m, rhs.m);
|
||||
return ret;
|
||||
}
|
||||
|
||||
OpenGlMatrix& OpenGlRenderState::GetProjectionMatrix()
|
||||
{
|
||||
// guarenteed to have at least one projection matrix element
|
||||
return projection[0];
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlRenderState::GetProjectionMatrix() const
|
||||
{
|
||||
// guarenteed to have at least one projection matrix element
|
||||
return projection[0];
|
||||
}
|
||||
|
||||
OpenGlMatrix& OpenGlRenderState::GetModelViewMatrix()
|
||||
{
|
||||
return modelview;
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlRenderState::GetModelViewMatrix() const
|
||||
{
|
||||
return modelview;
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlRenderState::GetModelViewMatrix(int i) const
|
||||
{
|
||||
return modelview_premult[i] * modelview;
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlRenderState::GetProjectionModelViewMatrix() const
|
||||
{
|
||||
return GetProjectionMatrix() * GetModelViewMatrix();
|
||||
}
|
||||
|
||||
OpenGlMatrix OpenGlRenderState::GetProjectiveTextureMatrix() const
|
||||
{
|
||||
return OpenGlMatrix::Translate(0.5,0.5,0.5) * OpenGlMatrix::Scale(0.5,0.5,0.5) * GetProjectionModelViewMatrix();
|
||||
}
|
||||
|
||||
void OpenGlRenderState::EnableProjectiveTexturing() const
|
||||
{
|
||||
#ifndef HAVE_GLES
|
||||
const pangolin::OpenGlMatrix projmattrans = GetProjectiveTextureMatrix().Transpose();
|
||||
glEnable(GL_TEXTURE_GEN_S);
|
||||
glEnable(GL_TEXTURE_GEN_T);
|
||||
glEnable(GL_TEXTURE_GEN_R);
|
||||
glEnable(GL_TEXTURE_GEN_Q);
|
||||
glTexGendv(GL_S, GL_EYE_PLANE, projmattrans.m);
|
||||
glTexGendv(GL_T, GL_EYE_PLANE, projmattrans.m+4);
|
||||
glTexGendv(GL_R, GL_EYE_PLANE, projmattrans.m+8);
|
||||
glTexGendv(GL_Q, GL_EYE_PLANE, projmattrans.m+12);
|
||||
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
||||
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
||||
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
||||
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGlRenderState::DisableProjectiveTexturing() const
|
||||
{
|
||||
#ifndef HAVE_GLES
|
||||
glDisable(GL_TEXTURE_GEN_S);
|
||||
glDisable(GL_TEXTURE_GEN_T);
|
||||
glDisable(GL_TEXTURE_GEN_R);
|
||||
glDisable(GL_TEXTURE_GEN_Q);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGlRenderState::Follow(const OpenGlMatrix& T_wc, bool follow)
|
||||
{
|
||||
this->T_cw = T_wc.Inverse();
|
||||
|
||||
if(follow != this->follow) {
|
||||
if(follow) {
|
||||
const OpenGlMatrix T_vc = GetModelViewMatrix() * T_wc;
|
||||
SetModelViewMatrix(T_vc);
|
||||
this->follow = true;
|
||||
}else{
|
||||
Unfollow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGlRenderState::Unfollow()
|
||||
{
|
||||
const OpenGlMatrix T_vw = GetModelViewMatrix() * T_cw;
|
||||
SetModelViewMatrix(T_vw);
|
||||
this->follow = false;
|
||||
}
|
||||
|
||||
// Use OpenGl's default frame of reference
|
||||
OpenGlMatrixSpec ProjectionMatrix(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
|
||||
{
|
||||
return ProjectionMatrixRUB_BottomLeft(w,h,fu,fv,u0,v0,zNear,zFar);
|
||||
}
|
||||
|
||||
OpenGlMatrixSpec ProjectionMatrixOrthographic(GLprecision l, GLprecision r, GLprecision b, GLprecision t, GLprecision n, GLprecision f )
|
||||
{
|
||||
OpenGlMatrixSpec P;
|
||||
P.type = GlProjectionStack;
|
||||
|
||||
P.m[0] = 2/(r-l);
|
||||
P.m[1] = 0;
|
||||
P.m[2] = 0;
|
||||
P.m[3] = 0;
|
||||
|
||||
P.m[4] = 0;
|
||||
P.m[5] = 2/(t-b);
|
||||
P.m[6] = 0;
|
||||
P.m[7] = 0;
|
||||
|
||||
P.m[8] = 0;
|
||||
P.m[9] = 0;
|
||||
P.m[10] = -2/(f-n);
|
||||
P.m[11] = 0;
|
||||
|
||||
P.m[12] = -(r+l)/(r-l);
|
||||
P.m[13] = -(t+b)/(t-b);
|
||||
P.m[14] = -(f+n)/(f-n);
|
||||
P.m[15] = 1;
|
||||
|
||||
return P;
|
||||
}
|
||||
|
||||
|
||||
// Camera Axis:
|
||||
// X - Right, Y - Up, Z - Back
|
||||
// Image Origin:
|
||||
// Bottom Left
|
||||
// Caution: Principal point defined with respect to image origin (0,0) at
|
||||
// top left of top-left pixel (not center, and in different frame
|
||||
// of reference to projection function image)
|
||||
OpenGlMatrixSpec ProjectionMatrixRUB_BottomLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
|
||||
{
|
||||
// http://www.songho.ca/opengl/gl_projectionmatrix.html
|
||||
const GLprecision L = +(u0) * zNear / -fu;
|
||||
const GLprecision T = +(v0) * zNear / fv;
|
||||
const GLprecision R = -(w-u0) * zNear / -fu;
|
||||
const GLprecision B = -(h-v0) * zNear / fv;
|
||||
|
||||
OpenGlMatrixSpec P;
|
||||
P.type = GlProjectionStack;
|
||||
std::fill_n(P.m,4*4,0);
|
||||
|
||||
P.m[0*4+0] = 2 * zNear / (R-L);
|
||||
P.m[1*4+1] = 2 * zNear / (T-B);
|
||||
P.m[2*4+2] = -(zFar +zNear) / (zFar - zNear);
|
||||
P.m[2*4+0] = (R+L)/(R-L);
|
||||
P.m[2*4+1] = (T+B)/(T-B);
|
||||
P.m[2*4+3] = -1.0;
|
||||
P.m[3*4+2] = -(2*zFar*zNear)/(zFar-zNear);
|
||||
|
||||
return P;
|
||||
}
|
||||
|
||||
// Camera Axis:
|
||||
// X - Right, Y - Up, Z - Back
|
||||
// Image Origin:
|
||||
// Top Left
|
||||
// Caution: Principal point defined with respect to image origin (0,0) at
|
||||
// top left of top-left pixel (not center, and in different frame
|
||||
// of reference to projection function image)
|
||||
OpenGlMatrixSpec ProjectionMatrixRUB_TopLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
|
||||
{
|
||||
// http://www.songho.ca/opengl/gl_projectionmatrix.html
|
||||
const GLprecision L = +(u0) * zNear / -fu;
|
||||
const GLprecision R = -(w-u0) * zNear / -fu;
|
||||
const GLprecision T = -(h-v0) * zNear / fv;
|
||||
const GLprecision B = +(v0) * zNear / fv;
|
||||
|
||||
OpenGlMatrixSpec P;
|
||||
P.type = GlProjectionStack;
|
||||
std::fill_n(P.m,4*4,0);
|
||||
|
||||
P.m[0*4+0] = 2 * zNear / (R-L);
|
||||
P.m[1*4+1] = 2 * zNear / (T-B);
|
||||
P.m[2*4+2] = -(zFar +zNear) / (zFar - zNear);
|
||||
P.m[2*4+0] = (R+L)/(R-L);
|
||||
P.m[2*4+1] = (T+B)/(T-B);
|
||||
P.m[2*4+3] = -1.0;
|
||||
P.m[3*4+2] = -(2*zFar*zNear)/(zFar-zNear);
|
||||
|
||||
return P;
|
||||
}
|
||||
|
||||
// Camera Axis:
|
||||
// X - Right, Y - Down, Z - Forward
|
||||
// Image Origin:
|
||||
// Top Left
|
||||
// Pricipal point specified with image origin (0,0) at top left of top-left pixel (not center)
|
||||
OpenGlMatrixSpec ProjectionMatrixRDF_TopLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
|
||||
{
|
||||
// http://www.songho.ca/opengl/gl_projectionmatrix.html
|
||||
const GLprecision L = -(u0) * zNear / fu;
|
||||
const GLprecision R = +(w-u0) * zNear / fu;
|
||||
const GLprecision T = -(v0) * zNear / fv;
|
||||
const GLprecision B = +(h-v0) * zNear / fv;
|
||||
|
||||
OpenGlMatrixSpec P;
|
||||
P.type = GlProjectionStack;
|
||||
std::fill_n(P.m,4*4,0);
|
||||
|
||||
P.m[0*4+0] = 2 * zNear / (R-L);
|
||||
P.m[1*4+1] = 2 * zNear / (T-B);
|
||||
|
||||
P.m[2*4+0] = (R+L)/(L-R);
|
||||
P.m[2*4+1] = (T+B)/(B-T);
|
||||
P.m[2*4+2] = (zFar +zNear) / (zFar - zNear);
|
||||
P.m[2*4+3] = 1.0;
|
||||
|
||||
P.m[3*4+2] = (2*zFar*zNear)/(zNear - zFar);
|
||||
return P;
|
||||
}
|
||||
|
||||
// Camera Axis:
|
||||
// X - Right, Y - Down, Z - Forward
|
||||
// Image Origin:
|
||||
// Top Right
|
||||
// Pricipal point specified with image origin (0,0) at top right of top-right pixel (not center)
|
||||
OpenGlMatrixSpec ProjectionMatrixRDF_TopRight(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
|
||||
{
|
||||
// http://www.songho.ca/opengl/gl_projectionmatrix.html
|
||||
const GLprecision L = +(w-u0) * zNear / fu;
|
||||
const GLprecision R = -(u0) * zNear / fu;
|
||||
const GLprecision T = -(v0) * zNear / fv;
|
||||
const GLprecision B = +(h-v0) * zNear / fv;
|
||||
|
||||
OpenGlMatrixSpec P;
|
||||
P.type = GlProjectionStack;
|
||||
std::fill_n(P.m,4*4,0);
|
||||
|
||||
P.m[0*4+0] = 2 * zNear / (R-L);
|
||||
P.m[1*4+1] = 2 * zNear / (T-B);
|
||||
|
||||
P.m[2*4+0] = (R+L)/(L-R);
|
||||
P.m[2*4+1] = (T+B)/(B-T);
|
||||
P.m[2*4+2] = (zFar +zNear) / (zFar - zNear);
|
||||
P.m[2*4+3] = 1.0;
|
||||
|
||||
P.m[3*4+2] = (2*zFar*zNear)/(zNear - zFar);
|
||||
return P;
|
||||
}
|
||||
|
||||
// Camera Axis:
|
||||
// X - Right, Y - Down, Z - Forward
|
||||
// Image Origin:
|
||||
// Bottom Left
|
||||
// Pricipal point specified with image origin (0,0) at top left of top-left pixel (not center)
|
||||
OpenGlMatrixSpec ProjectionMatrixRDF_BottomLeft(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
|
||||
{
|
||||
// http://www.songho.ca/opengl/gl_projectionmatrix.html
|
||||
const GLprecision L = -(u0) * zNear / fu;
|
||||
const GLprecision R = +(w-u0) * zNear / fu;
|
||||
const GLprecision B = -(v0) * zNear / fv;
|
||||
const GLprecision T = +(h-v0) * zNear / fv;
|
||||
|
||||
OpenGlMatrixSpec P;
|
||||
P.type = GlProjectionStack;
|
||||
std::fill_n(P.m,4*4,0);
|
||||
|
||||
P.m[0*4+0] = 2 * zNear / (R-L);
|
||||
P.m[1*4+1] = 2 * zNear / (T-B);
|
||||
|
||||
P.m[2*4+0] = (R+L)/(L-R);
|
||||
P.m[2*4+1] = (T+B)/(B-T);
|
||||
P.m[2*4+2] = (zFar +zNear) / (zFar - zNear);
|
||||
P.m[2*4+3] = 1.0;
|
||||
|
||||
P.m[3*4+2] = (2*zFar*zNear)/(zNear - zFar);
|
||||
return P;
|
||||
}
|
||||
|
||||
// Camera Axis:
|
||||
// X - Right, Y - Down, Z - Forward
|
||||
// Image Origin:
|
||||
// Bottom Right
|
||||
// Pricipal point specified with image origin (0,0) at top right of top-right pixel (not center)
|
||||
OpenGlMatrixSpec ProjectionMatrixRDF_BottomRight(int w, int h, GLprecision fu, GLprecision fv, GLprecision u0, GLprecision v0, GLprecision zNear, GLprecision zFar )
|
||||
{
|
||||
// http://www.songho.ca/opengl/gl_projectionmatrix.html
|
||||
const GLprecision R = -(u0) * zNear / fu;
|
||||
const GLprecision L = +(w-u0) * zNear / fu;
|
||||
const GLprecision B = -(v0) * zNear / fv;
|
||||
const GLprecision T = +(h-v0) * zNear / fv;
|
||||
|
||||
OpenGlMatrixSpec P;
|
||||
P.type = GlProjectionStack;
|
||||
std::fill_n(P.m,4*4,0);
|
||||
|
||||
P.m[0*4+0] = 2 * zNear / (R-L);
|
||||
P.m[1*4+1] = 2 * zNear / (T-B);
|
||||
|
||||
P.m[2*4+0] = (R+L)/(L-R);
|
||||
P.m[2*4+1] = (T+B)/(B-T);
|
||||
P.m[2*4+2] = (zFar +zNear) / (zFar - zNear);
|
||||
P.m[2*4+3] = 1.0;
|
||||
|
||||
P.m[3*4+2] = (2*zFar*zNear)/(zNear - zFar);
|
||||
return P;
|
||||
}
|
||||
|
||||
OpenGlMatrix ModelViewLookAtRUB(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, GLprecision ux, GLprecision uy, GLprecision uz)
|
||||
{
|
||||
OpenGlMatrix mat;
|
||||
GLprecision* m = mat.m;
|
||||
|
||||
const GLprecision u_o[3] = {ux,uy,uz};
|
||||
|
||||
GLprecision x[3], y[3];
|
||||
GLprecision z[] = {ex - lx, ey - ly, ez - lz};
|
||||
Normalise<3>(z);
|
||||
|
||||
CrossProduct(x,u_o,z);
|
||||
CrossProduct(y,z,x);
|
||||
|
||||
// Normalize x, y
|
||||
const GLprecision lenx = Length<3>(x);
|
||||
const GLprecision leny = Length<3>(y);
|
||||
|
||||
if( lenx > 0 && leny > 0) {
|
||||
for(size_t r = 0; r < 3; ++r ) {
|
||||
x[r] /= lenx;
|
||||
y[r] /= leny;
|
||||
}
|
||||
#define M(row,col) m[col*4+row]
|
||||
M(0,0) = x[0];
|
||||
M(0,1) = x[1];
|
||||
M(0,2) = x[2];
|
||||
M(1,0) = y[0];
|
||||
M(1,1) = y[1];
|
||||
M(1,2) = y[2];
|
||||
M(2,0) = z[0];
|
||||
M(2,1) = z[1];
|
||||
M(2,2) = z[2];
|
||||
M(3,0) = 0.0;
|
||||
M(3,1) = 0.0;
|
||||
M(3,2) = 0.0;
|
||||
M(0,3) = -(M(0,0)*ex + M(0,1)*ey + M(0,2)*ez);
|
||||
M(1,3) = -(M(1,0)*ex + M(1,1)*ey + M(1,2)*ez);
|
||||
M(2,3) = -(M(2,0)*ex + M(2,1)*ey + M(2,2)*ez);
|
||||
M(3,3) = 1.0;
|
||||
#undef M
|
||||
return mat;
|
||||
}else{
|
||||
throw std::invalid_argument("'Look' and 'up' vectors cannot be parallel when calling ModelViewLookAt.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
OpenGlMatrix ModelViewLookAtRDF(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, GLprecision ux, GLprecision uy, GLprecision uz)
|
||||
{
|
||||
OpenGlMatrix mat;
|
||||
GLprecision* m = mat.m;
|
||||
|
||||
const GLprecision u_o[3] = {ux,uy,uz};
|
||||
|
||||
GLprecision x[3], y[3];
|
||||
GLprecision z[] = {lx - ex, ly - ey, lz - ez};
|
||||
Normalise<3>(z);
|
||||
|
||||
CrossProduct(x,z,u_o);
|
||||
CrossProduct(y,z,x);
|
||||
|
||||
// Normalize x, y
|
||||
const GLprecision lenx = Length<3>(x);
|
||||
const GLprecision leny = Length<3>(y);
|
||||
|
||||
if( lenx > 0 && leny > 0) {
|
||||
for(size_t r = 0; r < 3; ++r ) {
|
||||
x[r] /= lenx;
|
||||
y[r] /= leny;
|
||||
}
|
||||
#define M(row,col) m[col*4+row]
|
||||
M(0,0) = x[0];
|
||||
M(0,1) = x[1];
|
||||
M(0,2) = x[2];
|
||||
M(1,0) = y[0];
|
||||
M(1,1) = y[1];
|
||||
M(1,2) = y[2];
|
||||
M(2,0) = z[0];
|
||||
M(2,1) = z[1];
|
||||
M(2,2) = z[2];
|
||||
M(3,0) = 0.0;
|
||||
M(3,1) = 0.0;
|
||||
M(3,2) = 0.0;
|
||||
M(0,3) = -(M(0,0)*ex + M(0,1)*ey + M(0,2)*ez);
|
||||
M(1,3) = -(M(1,0)*ex + M(1,1)*ey + M(1,2)*ez);
|
||||
M(2,3) = -(M(2,0)*ex + M(2,1)*ey + M(2,2)*ez);
|
||||
M(3,3) = 1.0;
|
||||
#undef M
|
||||
return mat;
|
||||
}else{
|
||||
throw std::invalid_argument("'Look' and 'up' vectors cannot be parallel when calling ModelViewLookAt.");
|
||||
}
|
||||
}
|
||||
|
||||
OpenGlMatrix ModelViewLookAt(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, GLprecision ux, GLprecision uy, GLprecision uz)
|
||||
{
|
||||
return ModelViewLookAtRUB(ex,ey,ez,lx,ly,lz,ux,uy,uz);
|
||||
}
|
||||
|
||||
OpenGlMatrix ModelViewLookAt(GLprecision ex, GLprecision ey, GLprecision ez, GLprecision lx, GLprecision ly, GLprecision lz, AxisDirection up)
|
||||
{
|
||||
const GLprecision* u = AxisDirectionVector[up];
|
||||
return ModelViewLookAtRUB(ex,ey,ez,lx,ly,lz,u[0],u[1],u[2]);
|
||||
}
|
||||
|
||||
OpenGlMatrix IdentityMatrix()
|
||||
{
|
||||
OpenGlMatrix P;
|
||||
std::fill_n(P.m,4*4,0);
|
||||
for( int i=0; i<4; ++i ) P.m[i*4+i] = 1;
|
||||
return P;
|
||||
}
|
||||
|
||||
OpenGlMatrixSpec IdentityMatrix(OpenGlStack type)
|
||||
{
|
||||
OpenGlMatrixSpec P;
|
||||
P.type = type;
|
||||
std::fill_n(P.m,4*4,0);
|
||||
for( int i=0; i<4; ++i ) P.m[i*4+i] = 1;
|
||||
return P;
|
||||
}
|
||||
|
||||
OpenGlMatrixSpec negIdentityMatrix(OpenGlStack type)
|
||||
{
|
||||
OpenGlMatrixSpec P;
|
||||
P.type = type;
|
||||
std::fill_n(P.m,4*4,0);
|
||||
for( int i=0; i<4; ++i ) P.m[i*4+i] = -1;
|
||||
|
||||
P.m[3*4+3] =1;
|
||||
return P;
|
||||
}
|
||||
|
||||
}
|
||||
583
thirdparty/Pangolin/src/display/view.cpp
vendored
Normal file
583
thirdparty/Pangolin/src/display/view.cpp
vendored
Normal file
@@ -0,0 +1,583 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2011 Steven Lovegrove
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pangolin/display/display.h>
|
||||
#include <pangolin/display/display_internal.h>
|
||||
#include <pangolin/display/opengl_render_state.h>
|
||||
#include <pangolin/display/view.h>
|
||||
#include <pangolin/display/viewport.h>
|
||||
#include <pangolin/gl/gl.h>
|
||||
#include <pangolin/platform.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
|
||||
// Pointer to context defined in display.cpp
|
||||
extern __thread PangolinGl* context;
|
||||
|
||||
const int panal_v_margin = 6;
|
||||
|
||||
int AttachAbs( int low, int high, Attach a)
|
||||
{
|
||||
if( a.unit == Pixel ) return low + (int)a.p;
|
||||
if( a.unit == ReversePixel ) return high - (int)a.p;
|
||||
return (int)(low + a.p * (high - low));
|
||||
}
|
||||
|
||||
double AspectAreaWithinTarget(double target, double test)
|
||||
{
|
||||
if( test < target )
|
||||
return test / target;
|
||||
else
|
||||
return target / test;
|
||||
}
|
||||
|
||||
void SaveViewFromFbo(std::string prefix, View& view, float scale)
|
||||
{
|
||||
PANGOLIN_UNUSED(prefix);
|
||||
|
||||
#ifndef HAVE_GLES
|
||||
const Viewport orig = view.v;
|
||||
view.v.l = 0;
|
||||
view.v.b = 0;
|
||||
view.v.w = (int)(view.v.w * scale);
|
||||
view.v.h = (int)(view.v.h * scale);
|
||||
|
||||
const int w = view.v.w;
|
||||
const int h = view.v.h;
|
||||
|
||||
float origLineWidth;
|
||||
glGetFloatv(GL_LINE_WIDTH, &origLineWidth);
|
||||
glLineWidth(origLineWidth * scale);
|
||||
|
||||
float origPointSize;
|
||||
glGetFloatv(GL_POINT_SIZE, &origPointSize);
|
||||
glPointSize(origPointSize * scale);
|
||||
|
||||
// Create FBO
|
||||
GlTexture color(w,h);
|
||||
GlRenderBuffer depth(w,h);
|
||||
GlFramebuffer fbo(color, depth);
|
||||
|
||||
// Render into FBO
|
||||
fbo.Bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
view.Render();
|
||||
glFlush();
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
const PixelFormat fmt = PixelFormatFromString("RGBA32");
|
||||
TypedImage buffer(w, h, fmt );
|
||||
glReadBuffer(GL_BACK);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1); // TODO: Avoid this?
|
||||
glReadPixels(0,0,w,h, GL_RGBA, GL_UNSIGNED_BYTE, buffer.ptr );
|
||||
SaveImage(buffer, fmt, prefix + ".png", false);
|
||||
#endif // HAVE_PNG
|
||||
|
||||
// unbind FBO
|
||||
fbo.Unbind();
|
||||
|
||||
// restore viewport / line width
|
||||
view.v = orig;
|
||||
glLineWidth(origLineWidth);
|
||||
glPointSize(origPointSize);
|
||||
#endif // HAVE_GLES
|
||||
}
|
||||
|
||||
void View::Resize(const Viewport& p)
|
||||
{
|
||||
// Compute Bounds based on specification
|
||||
v.l = AttachAbs(p.l,p.r(),left);
|
||||
v.b = AttachAbs(p.b,p.t(),bottom);
|
||||
int r = AttachAbs(p.l,p.r(),right);
|
||||
int t = AttachAbs(p.b,p.t(),top);
|
||||
|
||||
// Make sure left and right, top and bottom are correct order
|
||||
if( t < v.b ) std::swap(t,v.b);
|
||||
if( r < v.l ) std::swap(r,v.l);
|
||||
|
||||
v.w = r - v.l;
|
||||
v.h = t - v.b;
|
||||
|
||||
vp = v;
|
||||
|
||||
// Adjust based on aspect requirements
|
||||
if( aspect != 0 )
|
||||
{
|
||||
const float current_aspect = (float)v.w / (float)v.h;
|
||||
if( aspect > 0 )
|
||||
{
|
||||
// Fit to space
|
||||
if( current_aspect < aspect )
|
||||
{
|
||||
//Adjust height
|
||||
const int nh = (int)(v.w / aspect);
|
||||
v.b += vlock == LockBottom ? 0 : (vlock == LockCenter ? (v.h-nh)/2 : (v.h-nh) );
|
||||
v.h = nh;
|
||||
}else if( current_aspect > aspect )
|
||||
{
|
||||
//Adjust width
|
||||
const int nw = (int)(v.h * aspect);
|
||||
v.l += hlock == LockLeft? 0 : (hlock == LockCenter ? (v.w-nw)/2 : (v.w-nw) );
|
||||
v.w = nw;
|
||||
}
|
||||
}else{
|
||||
// Overfit
|
||||
double true_aspect = -aspect;
|
||||
if( current_aspect < true_aspect )
|
||||
{
|
||||
//Adjust width
|
||||
const int nw = (int)(v.h * true_aspect);
|
||||
v.l += hlock == LockLeft? 0 : (hlock == LockCenter ? (v.w-nw)/2 : (v.w-nw) );
|
||||
v.w = nw;
|
||||
}else if( current_aspect > true_aspect )
|
||||
{
|
||||
//Adjust height
|
||||
const int nh = (int)(v.w / true_aspect);
|
||||
v.b += vlock == LockBottom ? 0 : (vlock == LockCenter ? (v.h-nh)/2 : (v.h-nh) );
|
||||
v.h = nh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResizeChildren();
|
||||
}
|
||||
|
||||
inline int zcompare(const View* lhs, const View* rhs)
|
||||
{
|
||||
return lhs->zorder < rhs->zorder;
|
||||
}
|
||||
|
||||
void View::ResizeChildren()
|
||||
{
|
||||
if( layout == LayoutOverlay )
|
||||
{
|
||||
// Sort children into z-order
|
||||
std::sort(views.begin(), views.end(), zcompare);
|
||||
|
||||
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv ) {
|
||||
(*iv)->Resize(v);
|
||||
}
|
||||
}else if( layout == LayoutVertical )
|
||||
{
|
||||
// Allocate space incrementally
|
||||
Viewport space = v.Inset(panal_v_margin);
|
||||
int num_children = 0;
|
||||
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv )
|
||||
{
|
||||
if (!(*iv)->show) continue;
|
||||
num_children++;
|
||||
if(scroll_offset >= num_children ) {
|
||||
(*iv)->scroll_show = false;
|
||||
}else{
|
||||
(*iv)->scroll_show = true;
|
||||
(*iv)->Resize(space);
|
||||
space.h = (*iv)->v.b - panal_v_margin - space.b;
|
||||
}
|
||||
}
|
||||
}else if(layout == LayoutHorizontal )
|
||||
{
|
||||
// Allocate space incrementally
|
||||
const int margin = 8;
|
||||
Viewport space = v.Inset(margin);
|
||||
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv )
|
||||
{
|
||||
(*iv)->Resize(space);
|
||||
space.w = (*iv)->v.l + margin + space.l;
|
||||
}
|
||||
}else if(layout == LayoutEqualVertical )
|
||||
{
|
||||
// Allocate vertical space equally
|
||||
const size_t visiblechildren = NumVisibleChildren();
|
||||
const float height = (float)v.h / (float)visiblechildren;
|
||||
|
||||
for( size_t i=0; i < visiblechildren; ++i) {
|
||||
Viewport space(v.l, (GLint)(v.b+(visiblechildren-1-i)*height), v.w, (GLint)(height) );
|
||||
VisibleChild(i).Resize(space);
|
||||
}
|
||||
}else if(layout == LayoutEqualHorizontal )
|
||||
{
|
||||
// Allocate vertical space equally
|
||||
const size_t visiblechildren = NumVisibleChildren();
|
||||
const float width = (float)v.w / (float)visiblechildren;
|
||||
|
||||
for( size_t i=0; i < visiblechildren; ++i) {
|
||||
Viewport space( (GLint)(v.l+i*width), v.b, (GLint)width, v.h);
|
||||
VisibleChild(i).Resize(space);
|
||||
}
|
||||
}else if(layout == LayoutEqual )
|
||||
{
|
||||
const size_t visiblechildren = NumVisibleChildren();
|
||||
// TODO: Make this neater, and make fewer assumptions!
|
||||
if( visiblechildren > 0 )
|
||||
{
|
||||
// This containers aspect
|
||||
const double this_a = std::fabs(v.aspect());
|
||||
|
||||
// Use first child with fixed aspect for all children
|
||||
double child_a = std::fabs(VisibleChild(0).aspect);
|
||||
for(size_t i=1; (child_a==0) && i < visiblechildren; ++i ) {
|
||||
child_a = std::fabs(VisibleChild(i).aspect);
|
||||
}
|
||||
|
||||
if(child_a == 0) {
|
||||
child_a = 1;
|
||||
}
|
||||
|
||||
double a = visiblechildren*child_a;
|
||||
double area = AspectAreaWithinTarget(this_a, a);
|
||||
|
||||
size_t cols = visiblechildren-1;
|
||||
for(; cols > 0; --cols)
|
||||
{
|
||||
const size_t rows = visiblechildren / cols + (visiblechildren % cols == 0 ? 0 : 1);
|
||||
const double na = cols * child_a / rows;
|
||||
const double new_area = visiblechildren*AspectAreaWithinTarget(this_a,na)/(rows*cols);
|
||||
if( new_area <= area )
|
||||
break;
|
||||
area = new_area;
|
||||
a = na;
|
||||
}
|
||||
|
||||
cols++;
|
||||
const size_t rows = visiblechildren / cols + (visiblechildren % cols == 0 ? 0 : 1);
|
||||
size_t cw, ch;
|
||||
if( a > this_a )
|
||||
{
|
||||
cw = v.w / cols;
|
||||
ch = (int)(cw / child_a); //v.h / rows;
|
||||
}else{
|
||||
ch = v.h / rows;
|
||||
cw = (int)(ch * child_a);
|
||||
}
|
||||
|
||||
for(size_t i=0; i< visiblechildren; ++i )
|
||||
{
|
||||
size_t c = i % cols;
|
||||
size_t r = i / cols;
|
||||
Viewport space( GLint(v.l + c*cw), GLint(v.t() - (r+1)*ch), GLint(cw), GLint(ch) );
|
||||
VisibleChild(i).Resize(space);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void View::Render()
|
||||
{
|
||||
if(extern_draw_function && show && scroll_show) {
|
||||
extern_draw_function(*this);
|
||||
}
|
||||
RenderChildren();
|
||||
}
|
||||
|
||||
void View::RenderChildren()
|
||||
{
|
||||
for(std::vector<View*>::iterator iv = views.begin(); iv != views.end(); ++iv )
|
||||
{
|
||||
if((*iv)->show && (*iv)->scroll_show) (*iv)->Render();
|
||||
}
|
||||
}
|
||||
|
||||
void View::Activate() const
|
||||
{
|
||||
v.Activate();
|
||||
}
|
||||
|
||||
void View::ActivateAndScissor() const
|
||||
{
|
||||
vp.Scissor();
|
||||
v.Activate();
|
||||
}
|
||||
|
||||
void View::ActivateScissorAndClear() const
|
||||
{
|
||||
vp.Scissor();
|
||||
v.Activate();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void View::Activate(const OpenGlRenderState& state ) const
|
||||
{
|
||||
v.Activate();
|
||||
state.Apply();
|
||||
}
|
||||
|
||||
void View::ActivateAndScissor(const OpenGlRenderState& state) const
|
||||
{
|
||||
vp.Scissor();
|
||||
v.Activate();
|
||||
state.Apply();
|
||||
}
|
||||
|
||||
void View::ActivateScissorAndClear(const OpenGlRenderState& state ) const
|
||||
{
|
||||
vp.Scissor();
|
||||
v.Activate();
|
||||
state.Apply();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void View::ActivatePixelOrthographic() const
|
||||
{
|
||||
v.ActivatePixelOrthographic();
|
||||
}
|
||||
|
||||
void View::ActivateIdentity() const
|
||||
{
|
||||
v.ActivateIdentity();
|
||||
}
|
||||
|
||||
GLfloat View::GetClosestDepth(int x, int y, int radius) const
|
||||
{
|
||||
// TODO: Get to work on android
|
||||
|
||||
#ifdef _MSVC_
|
||||
// MSVC Requires fixed sized arrays on stack
|
||||
radius = 5;
|
||||
const int zl = (5*2+1);
|
||||
#else
|
||||
const int zl = (radius*2+1);
|
||||
#endif
|
||||
|
||||
const int zsize = zl*zl;
|
||||
GLfloat zs[zsize];
|
||||
|
||||
#ifndef HAVE_GLES
|
||||
glReadBuffer(GL_FRONT);
|
||||
glReadPixels(x-radius,y-radius,zl,zl,GL_DEPTH_COMPONENT,GL_FLOAT,zs);
|
||||
#else
|
||||
std::fill(zs,zs+zsize, 0.8);
|
||||
#endif
|
||||
|
||||
const GLfloat mindepth = *(std::min_element(zs,zs+zsize));
|
||||
return mindepth;
|
||||
}
|
||||
|
||||
void View::GetObjectCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const
|
||||
{
|
||||
const GLint viewport[4] = {v.l,v.b,v.w,v.h};
|
||||
const OpenGlMatrix proj = cam_state.GetProjectionMatrix();
|
||||
const OpenGlMatrix mv = cam_state.GetModelViewMatrix();
|
||||
glUnProject(winx, winy, winzdepth, mv.m, proj.m, viewport, &x, &y, &z);
|
||||
}
|
||||
|
||||
void View::GetCamCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const
|
||||
{
|
||||
v.GetCamCoordinates(cam_state, winx, winy, winzdepth, x, y, z);
|
||||
}
|
||||
|
||||
View& View::SetFocus()
|
||||
{
|
||||
context->activeDisplay = this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool View::HasFocus() const
|
||||
{
|
||||
return context->activeDisplay == this;
|
||||
}
|
||||
|
||||
View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right)
|
||||
{
|
||||
this->left = left;
|
||||
this->top = top;
|
||||
this->right = right;
|
||||
this->bottom = bottom;
|
||||
context->base.ResizeChildren();
|
||||
return *this;
|
||||
}
|
||||
|
||||
View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right, bool keep_aspect)
|
||||
{
|
||||
aspect = keep_aspect ? v.aspect() : 0;
|
||||
SetBounds(top,bottom,left,right);
|
||||
return *this;
|
||||
}
|
||||
|
||||
View& View::SetBounds(Attach bottom, Attach top, Attach left, Attach right, double aspect)
|
||||
{
|
||||
this->aspect = aspect;
|
||||
SetBounds(top,bottom,left,right);
|
||||
return *this;
|
||||
}
|
||||
|
||||
View& View::SetAspect(double aspect)
|
||||
{
|
||||
this->aspect = aspect;
|
||||
context->base.ResizeChildren();
|
||||
return *this;
|
||||
}
|
||||
|
||||
View& View::SetLock(Lock horizontal, Lock vertical )
|
||||
{
|
||||
vlock = vertical;
|
||||
hlock = horizontal;
|
||||
return *this;
|
||||
}
|
||||
|
||||
View& View::SetLayout(Layout l)
|
||||
{
|
||||
layout = l;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
View& View::AddDisplay(View& child)
|
||||
{
|
||||
// detach child from any other view, and add to this
|
||||
std::vector<View*>::iterator f = std::find(
|
||||
context->base.views.begin(), context->base.views.end(), &child
|
||||
);
|
||||
|
||||
if( f != context->base.views.end() )
|
||||
context->base.views.erase(f);
|
||||
|
||||
views.push_back(&child);
|
||||
context->base.ResizeChildren();
|
||||
return *this;
|
||||
}
|
||||
|
||||
View& View::Show(bool show)
|
||||
{
|
||||
this->show = show;
|
||||
context->base.ResizeChildren();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void View::ToggleShow()
|
||||
{
|
||||
Show(!show);
|
||||
}
|
||||
|
||||
bool View::IsShown() const
|
||||
{
|
||||
return show;
|
||||
}
|
||||
|
||||
Viewport View::GetBounds() const
|
||||
{
|
||||
return Viewport( std::max(v.l, vp.l), std::max(v.b, vp.b), std::min(v.w, vp.w), std::min(v.h, vp.h) );
|
||||
}
|
||||
|
||||
void View::SaveOnRender(const std::string& filename_prefix)
|
||||
{
|
||||
const Viewport tosave = this->v.Intersect(this->vp);
|
||||
context->screen_capture.push(std::pair<std::string,Viewport>(filename_prefix,tosave ) );
|
||||
}
|
||||
|
||||
void View::RecordOnRender(const std::string& record_uri)
|
||||
{
|
||||
PANGOLIN_UNUSED(record_uri);
|
||||
|
||||
#ifdef BUILD_PANGOLIN_VIDEO
|
||||
if(!context->recorder.IsOpen()) {
|
||||
Viewport area = GetBounds();
|
||||
context->record_view = this;
|
||||
try{
|
||||
context->recorder.Open(record_uri);
|
||||
std::vector<StreamInfo> streams;
|
||||
const PixelFormat fmt = PixelFormatFromString("RGB24");
|
||||
streams.push_back( StreamInfo(fmt, area.w, area.h, area.w * fmt.bpp / 8) );
|
||||
context->recorder.SetStreams(streams);
|
||||
}catch(const std::exception& e) {
|
||||
pango_print_error("Unable to open VideoRecorder:\n\t%s\n", e.what());
|
||||
}
|
||||
}else{
|
||||
context->recorder.Close();
|
||||
}
|
||||
#else
|
||||
std::cerr << "Error: Video Support hasn't been built into this library." << std::endl;
|
||||
#endif // BUILD_PANGOLIN_VIDEO
|
||||
}
|
||||
|
||||
void View::SaveRenderNow(const std::string& filename_prefix, float scale)
|
||||
{
|
||||
SaveViewFromFbo(filename_prefix, *this, scale);
|
||||
}
|
||||
|
||||
View& View::operator[](size_t i)
|
||||
{
|
||||
return *views[i];
|
||||
}
|
||||
|
||||
size_t View::NumChildren() const
|
||||
{
|
||||
return views.size();
|
||||
}
|
||||
|
||||
size_t View::NumVisibleChildren() const
|
||||
{
|
||||
int numvis = 0;
|
||||
for(std::vector<View*>::const_iterator i=views.begin(); i!=views.end(); ++i)
|
||||
{
|
||||
if((*i)->show) {
|
||||
numvis++;
|
||||
}
|
||||
}
|
||||
return numvis;
|
||||
}
|
||||
|
||||
View& View::VisibleChild(size_t i)
|
||||
{
|
||||
size_t numvis = 0;
|
||||
for(size_t v=0; v < views.size(); ++v ) {
|
||||
if(views[v]->show) {
|
||||
if( i == numvis ) {
|
||||
return *views[v];
|
||||
}
|
||||
numvis++;
|
||||
}
|
||||
}
|
||||
// Shouldn't get here
|
||||
throw std::out_of_range("No such child.");
|
||||
}
|
||||
|
||||
View* View::FindChild(int x, int y)
|
||||
{
|
||||
// Find in reverse order to mirror draw order
|
||||
for( std::vector<View*>::const_reverse_iterator i = views.rbegin(); i != views.rend(); ++i )
|
||||
if( (*i)->show && (*i)->GetBounds().Contains(x,y) )
|
||||
return (*i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
View& View::SetHandler(Handler* h)
|
||||
{
|
||||
handler = h;
|
||||
return *this;
|
||||
}
|
||||
|
||||
View& View::SetDrawFunction(const std::function<void(View&)>& drawFunc)
|
||||
{
|
||||
extern_draw_function = drawFunc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
113
thirdparty/Pangolin/src/display/viewport.cpp
vendored
Normal file
113
thirdparty/Pangolin/src/display/viewport.cpp
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2013 Steven Lovegrove
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pangolin/display/viewport.h>
|
||||
#include <algorithm>
|
||||
#include <pangolin/utils/simple_math.h>
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
void Viewport::Activate() const
|
||||
{
|
||||
glViewport(l,b,w,h);
|
||||
}
|
||||
|
||||
void Viewport::Scissor() const
|
||||
{
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(l,b,w,h);
|
||||
}
|
||||
|
||||
void Viewport::ActivateAndScissor() const
|
||||
{
|
||||
glViewport(l,b,w,h);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(l,b,w,h);
|
||||
}
|
||||
|
||||
|
||||
void Viewport::DisableScissor()
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
bool Viewport::Contains(int x, int y) const
|
||||
{
|
||||
return l <= x && x < (l+w) && b <= y && y < (b+h);
|
||||
}
|
||||
|
||||
void Viewport::ActivatePixelOrthographic() const
|
||||
{
|
||||
Activate();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(-0.5, w-0.5, -0.5, h-0.5, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void Viewport::ActivateIdentity() const
|
||||
{
|
||||
Activate();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
|
||||
Viewport Viewport::Inset(int i) const
|
||||
{
|
||||
return Viewport(l+i, b+i, w-2*i, h-2*i);
|
||||
}
|
||||
|
||||
Viewport Viewport::Inset(int horiz, int vert) const
|
||||
{
|
||||
return Viewport(l+horiz, b+vert, w-horiz, h-vert);
|
||||
}
|
||||
|
||||
Viewport Viewport::Intersect(const Viewport& vp) const
|
||||
{
|
||||
GLint nl = std::max(l,vp.l);
|
||||
GLint nr = std::min(r(),vp.r());
|
||||
GLint nb = std::max(b,vp.b);
|
||||
GLint nt = std::min(t(),vp.t());
|
||||
return Viewport(nl,nb, nr-nl, nt-nb);
|
||||
}
|
||||
|
||||
void Viewport::GetCamCoordinates(const OpenGlRenderState& cam_state, double winx, double winy, double winzdepth, GLdouble& x, GLdouble& y, GLdouble& z) const
|
||||
{
|
||||
const GLint viewport[4] = {l, b, w, h};
|
||||
const OpenGlMatrix proj = cam_state.GetProjectionMatrix();
|
||||
#ifndef HAVE_GLES
|
||||
glUnProject(winx, winy, winzdepth, Identity4d, proj.m, viewport, &x, &y, &z);
|
||||
#else
|
||||
glUnProject(winx, winy, winzdepth, Identity4f, proj.m, viewport, &x, &y, &z);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
680
thirdparty/Pangolin/src/display/widgets/widgets.cpp
vendored
Normal file
680
thirdparty/Pangolin/src/display/widgets/widgets.cpp
vendored
Normal file
@@ -0,0 +1,680 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2011 Steven Lovegrove
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pangolin/display/widgets/widgets.h>
|
||||
#include <pangolin/display/display.h>
|
||||
#include <pangolin/display/display_internal.h>
|
||||
#include <pangolin/gl/gldraw.h>
|
||||
#include <pangolin/var/varextra.h>
|
||||
#include <pangolin/utils/file_utils.h>
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
|
||||
// Pointer to context defined in display.cpp
|
||||
extern __thread PangolinGl* context;
|
||||
|
||||
|
||||
const static GLfloat colour_s1[4] = {0.2f, 0.2f, 0.2f, 1.0f};
|
||||
const static GLfloat colour_s2[4] = {0.6f, 0.6f, 0.6f, 1.0f};
|
||||
const static GLfloat colour_bg[4] = {0.9f, 0.9f, 0.9f, 1.0f};
|
||||
const static GLfloat colour_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
const static GLfloat colour_tx[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
const static GLfloat colour_dn[4] = {1.0f, 0.7f, 0.7f, 1.0f};
|
||||
|
||||
static inline GlFont& font()
|
||||
{
|
||||
return GlFont::I();
|
||||
}
|
||||
|
||||
static inline int cb_height()
|
||||
{
|
||||
return (int)(font().Height() * 1.0);
|
||||
}
|
||||
|
||||
static inline int tab_h()
|
||||
{
|
||||
return (int)(font().Height() * 1.4);
|
||||
}
|
||||
|
||||
std::mutex display_mutex;
|
||||
|
||||
template<typename T>
|
||||
void GuiVarChanged( Var<T>& var)
|
||||
{
|
||||
VarState::I().FlagVarChanged();
|
||||
var.Meta().gui_changed = true;
|
||||
|
||||
for(std::vector<GuiVarChangedCallback>::iterator igvc = VarState::I().gui_var_changed_callbacks.begin(); igvc != VarState::I().gui_var_changed_callbacks.end(); ++igvc) {
|
||||
if( StartsWith(var.Meta().full_name, igvc->filter) ) {
|
||||
igvc->fn( igvc->data, var.Meta().full_name, var.Ref() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void glRect(Viewport v)
|
||||
{
|
||||
GLfloat vs[] = { (float)v.l,(float)v.b,
|
||||
(float)v.l,(float)v.t(),
|
||||
(float)v.r(),(float)v.t(),
|
||||
(float)v.r(),(float)v.b };
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, vs);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
void glRect(Viewport v, int inset)
|
||||
{
|
||||
glRect(v.Inset(inset));
|
||||
}
|
||||
|
||||
void DrawShadowRect(Viewport& v)
|
||||
{
|
||||
glColor4fv(colour_s2);
|
||||
glDrawRectPerimeter((GLfloat)v.l, (GLfloat)v.b, (GLfloat)v.r(), (GLfloat)v.t());
|
||||
}
|
||||
|
||||
void DrawShadowRect(Viewport& v, bool pushed)
|
||||
{
|
||||
const GLfloat* c1 = pushed ? colour_s1 : colour_s2;
|
||||
const GLfloat* c2 = pushed ? colour_s2 : colour_s1;
|
||||
|
||||
GLfloat vs[] = { (float)v.l,(float)v.b,
|
||||
(float)v.l,(float)v.t(),
|
||||
(float)v.r(),(float)v.t(),
|
||||
(float)v.r(),(float)v.b,
|
||||
(float)v.l,(float)v.b };
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, vs);
|
||||
glColor4fv(c1);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, 3);
|
||||
|
||||
glColor4fv(c2);
|
||||
glDrawArrays(GL_LINE_STRIP, 2, 3);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
}
|
||||
|
||||
Panel::Panel()
|
||||
{
|
||||
handler = &StaticHandlerScroll;
|
||||
layout = LayoutVertical;
|
||||
}
|
||||
|
||||
Panel::Panel(const std::string& auto_register_var_prefix)
|
||||
{
|
||||
handler = &StaticHandlerScroll;
|
||||
layout = LayoutVertical;
|
||||
RegisterNewVarCallback(&Panel::AddVariable,(void*)this,auto_register_var_prefix);
|
||||
ProcessHistoricCallbacks(&Panel::AddVariable,(void*)this,auto_register_var_prefix);
|
||||
}
|
||||
|
||||
void Panel::AddVariable(void* data, const std::string& name, VarValueGeneric& var, bool /*brand_new*/)
|
||||
{
|
||||
Panel* thisptr = (Panel*)data;
|
||||
|
||||
const string& title = var.Meta().friendly;
|
||||
|
||||
display_mutex.lock();
|
||||
|
||||
ViewMap::iterator pnl = context->named_managed_views.find(name);
|
||||
|
||||
// Only add if a widget by the same name doesn't
|
||||
// already exist
|
||||
if( pnl == context->named_managed_views.end() )
|
||||
{
|
||||
View* nv = NULL;
|
||||
if( !strcmp(var.TypeId(), typeid(bool).name()) ) {
|
||||
nv = (var.Meta().flags & META_FLAG_TOGGLE) ? (View*)new Checkbox(title,var) : (View*)new Button(title,var);
|
||||
} else if (!strcmp(var.TypeId(), typeid(double).name()) ||
|
||||
!strcmp(var.TypeId(), typeid(float).name()) ||
|
||||
!strcmp(var.TypeId(), typeid(int).name()) ||
|
||||
!strcmp(var.TypeId(), typeid(unsigned int).name()))
|
||||
{
|
||||
nv = new Slider(title, var);
|
||||
} else if (!strcmp(var.TypeId(), typeid(std::function<void(void)>).name() ) ) {
|
||||
nv = (View*)new FunctionButton(title, var);
|
||||
}else{
|
||||
nv = new TextInput(title,var);
|
||||
}
|
||||
if(nv) {
|
||||
context->named_managed_views[name] = nv;
|
||||
thisptr->views.push_back( nv );
|
||||
thisptr->ResizeChildren();
|
||||
}
|
||||
}
|
||||
|
||||
display_mutex.unlock();
|
||||
}
|
||||
|
||||
void Panel::Render()
|
||||
{
|
||||
#ifndef HAVE_GLES
|
||||
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT | GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
|
||||
#endif
|
||||
glEnable (GL_BLEND);
|
||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
DisplayBase().ActivatePixelOrthographic();
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glDisable( GL_COLOR_MATERIAL );
|
||||
glLineWidth(1.0);
|
||||
|
||||
glColor4fv(colour_bg);
|
||||
glRect(v);
|
||||
DrawShadowRect(v);
|
||||
|
||||
RenderChildren();
|
||||
|
||||
#ifndef HAVE_GLES
|
||||
glPopAttrib();
|
||||
#else
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Panel::ResizeChildren()
|
||||
{
|
||||
View::ResizeChildren();
|
||||
}
|
||||
|
||||
|
||||
View& CreatePanel(const std::string& name)
|
||||
{
|
||||
if(context->named_managed_views.find(name) != context->named_managed_views.end()) {
|
||||
throw std::runtime_error("Panel already registered with this name.");
|
||||
}
|
||||
Panel * p = new Panel(name);
|
||||
context->named_managed_views[name] = p;
|
||||
context->base.views.push_back(p);
|
||||
return *p;
|
||||
}
|
||||
|
||||
Button::Button(string title, VarValueGeneric& tv)
|
||||
: Widget<bool>(title,tv), down(false)
|
||||
{
|
||||
top = 1.0; bottom = Attach::Pix(-tab_h());
|
||||
left = 0.0; right = 1.0;
|
||||
hlock = LockLeft;
|
||||
vlock = LockBottom;
|
||||
gltext = font().Text(title);
|
||||
}
|
||||
|
||||
void Button::Mouse(View&, MouseButton button, int /*x*/, int /*y*/, bool pressed, int /*mouse_state*/)
|
||||
{
|
||||
if(button == MouseButtonLeft )
|
||||
{
|
||||
down = pressed;
|
||||
if( !pressed ) {
|
||||
var->Set(!var->Get());
|
||||
GuiVarChanged(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Button::Render()
|
||||
{
|
||||
glColor4fv(colour_fg );
|
||||
glRect(v);
|
||||
glColor4fv(colour_tx);
|
||||
gltext.DrawWindow(raster[0],raster[1]-down);
|
||||
DrawShadowRect(v, down);
|
||||
}
|
||||
|
||||
void Button::ResizeChildren()
|
||||
{
|
||||
raster[0] = floor(v.l + (v.w-gltext.Width())/2.0f);
|
||||
raster[1] = floor(v.b + (v.h-gltext.Height())/2.0f);
|
||||
}
|
||||
|
||||
FunctionButton::FunctionButton(string title, VarValueGeneric& tv)
|
||||
: Widget<std::function<void(void)> >(title, tv), down(false)
|
||||
{
|
||||
top = 1.0; bottom = Attach::Pix(-tab_h());
|
||||
left = 0.0; right = 1.0;
|
||||
hlock = LockLeft;
|
||||
vlock = LockBottom;
|
||||
gltext = font().Text(title);
|
||||
}
|
||||
|
||||
void FunctionButton::Mouse(View&, MouseButton button, int /*x*/, int /*y*/, bool pressed, int /*mouse_state*/)
|
||||
{
|
||||
if (button == MouseButtonLeft)
|
||||
{
|
||||
down = pressed;
|
||||
if (!pressed) {
|
||||
var->Get()();
|
||||
GuiVarChanged(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionButton::Render()
|
||||
{
|
||||
glColor4fv(colour_fg);
|
||||
glRect(v);
|
||||
glColor4fv(colour_tx);
|
||||
gltext.DrawWindow(raster[0],raster[1]-down);
|
||||
DrawShadowRect(v, down);
|
||||
}
|
||||
|
||||
void FunctionButton::ResizeChildren()
|
||||
{
|
||||
raster[0] = v.l + (v.w - gltext.Width()) / 2.0f;
|
||||
raster[1] = v.b + (v.h - gltext.Height()) / 2.0f;
|
||||
}
|
||||
|
||||
Checkbox::Checkbox(std::string title, VarValueGeneric& tv)
|
||||
: Widget<bool>(title,tv)
|
||||
{
|
||||
top = 1.0; bottom = Attach::Pix(-tab_h());
|
||||
left = 0.0; right = 1.0;
|
||||
hlock = LockLeft;
|
||||
vlock = LockBottom;
|
||||
handler = this;
|
||||
gltext = font().Text(title);
|
||||
}
|
||||
|
||||
void Checkbox::Mouse(View&, MouseButton button, int /*x*/, int /*y*/, bool pressed, int /*mouse_state*/)
|
||||
{
|
||||
if( button == MouseButtonLeft && pressed ) {
|
||||
var->Set(!var->Get());
|
||||
GuiVarChanged(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void Checkbox::ResizeChildren()
|
||||
{
|
||||
raster[0] = v.l + cb_height() + 4.0f;
|
||||
raster[1] = v.b + (v.h-gltext.Height())/2.0f;
|
||||
const int h = v.h;
|
||||
const int t = (int)((h-cb_height()) / 2.0f);
|
||||
vcb = Viewport(v.l,v.b+t,cb_height(),cb_height());
|
||||
}
|
||||
|
||||
void Checkbox::Render()
|
||||
{
|
||||
const bool val = var->Get();
|
||||
|
||||
if( val )
|
||||
{
|
||||
glColor4fv(colour_dn);
|
||||
glRect(vcb);
|
||||
}
|
||||
glColor4fv(colour_tx);
|
||||
gltext.DrawWindow(raster[0],raster[1]);
|
||||
DrawShadowRect(vcb, val);
|
||||
}
|
||||
|
||||
inline bool IsIntegral(const char* typeidname)
|
||||
{
|
||||
// TODO: There must be a better way of doing this...
|
||||
return !strcmp(typeidname, typeid(char).name()) ||
|
||||
!strcmp(typeidname, typeid(short).name()) ||
|
||||
!strcmp(typeidname, typeid(int).name()) ||
|
||||
!strcmp(typeidname, typeid(long).name()) ||
|
||||
!strcmp(typeidname, typeid(unsigned char).name()) ||
|
||||
!strcmp(typeidname, typeid(unsigned short).name()) ||
|
||||
!strcmp(typeidname, typeid(unsigned int).name()) ||
|
||||
!strcmp(typeidname, typeid(unsigned long).name());
|
||||
}
|
||||
|
||||
Slider::Slider(std::string title, VarValueGeneric& tv)
|
||||
: Widget<double>(title+":", tv), lock_bounds(true)
|
||||
{
|
||||
top = 1.0; bottom = Attach::Pix(-tab_h());
|
||||
left = 0.0; right = 1.0;
|
||||
hlock = LockLeft;
|
||||
vlock = LockBottom;
|
||||
handler = this;
|
||||
logscale = (int)tv.Meta().logscale;
|
||||
gltext = font().Text(title);
|
||||
is_integral_type = IsIntegral(tv.TypeId());
|
||||
}
|
||||
|
||||
void Slider::Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed)
|
||||
{
|
||||
if( pressed && var->Meta().range[0] < var->Meta().range[1] )
|
||||
{
|
||||
double val = !logscale ? var->Get() : log(var->Get());
|
||||
|
||||
if(key=='-' || key=='_' || key=='=' || key=='+') {
|
||||
double inc = var->Meta().increment;
|
||||
if (key == '-') inc *= -1.0;
|
||||
if (key == '_') inc *= -0.1;
|
||||
if (key == '+') inc *= 0.1;
|
||||
const double newval = max(var->Meta().range[0], min(var->Meta().range[1], val + inc));
|
||||
var->Set( logscale ? exp(newval) : newval );
|
||||
}else if(key == 'r'){
|
||||
Reset();
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
GuiVarChanged(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void Slider::Mouse(View& view, MouseButton button, int x, int y, bool pressed, int mouse_state)
|
||||
{
|
||||
if(pressed)
|
||||
{
|
||||
// Wheel
|
||||
if( button == MouseWheelUp || button == MouseWheelDown )
|
||||
{
|
||||
// Change scale around current value
|
||||
const double frac = max(0.0,min(1.0,(double)(x - v.l)/(double)v.w));
|
||||
double val = frac * (var->Meta().range[1] - var->Meta().range[0]) + var->Meta().range[0];
|
||||
|
||||
if (logscale)
|
||||
{
|
||||
if (val<=0)
|
||||
val = std::numeric_limits<double>::min();
|
||||
else
|
||||
val = log(val);
|
||||
}
|
||||
|
||||
const double scale = (button == MouseWheelUp ? 1.2 : 1.0 / 1.2 );
|
||||
var->Meta().range[1] = val + (var->Meta().range[1] - val)*scale;
|
||||
var->Meta().range[0] = val - (val - var->Meta().range[0])*scale;
|
||||
}else{
|
||||
lock_bounds = (button == MouseButtonLeft);
|
||||
MouseMotion(view,x,y,mouse_state);
|
||||
}
|
||||
}else{
|
||||
if(!lock_bounds)
|
||||
{
|
||||
double val = !logscale ? var->Get() : log(var->Get());
|
||||
|
||||
var->Meta().range[0] = min(var->Meta().range[0], val);
|
||||
var->Meta().range[1] = max(var->Meta().range[1], val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Slider::MouseMotion(View&, int x, int /*y*/, int /*mouse_state*/)
|
||||
{
|
||||
if( var->Meta().range[0] != var->Meta().range[1] )
|
||||
{
|
||||
const double range = (var->Meta().range[1] - var->Meta().range[0]);
|
||||
const double frac = (double)(x - v.l)/(double)v.w;
|
||||
double val;
|
||||
|
||||
if( lock_bounds )
|
||||
{
|
||||
const double bfrac = max(0.0,min(1.0,frac));
|
||||
val = bfrac * range + var->Meta().range[0] ;
|
||||
}else{
|
||||
val = frac * range + var->Meta().range[0];
|
||||
}
|
||||
|
||||
if (logscale) {
|
||||
val = exp(val);
|
||||
}
|
||||
|
||||
if( is_integral_type ) {
|
||||
val = std::round(val);
|
||||
}
|
||||
|
||||
var->Set(val);
|
||||
GuiVarChanged(*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Slider::ResizeChildren()
|
||||
{
|
||||
raster[0] = v.l + 2.0f;
|
||||
raster[1] = v.b + (v.h-gltext.Height())/2.0f;
|
||||
}
|
||||
|
||||
void Slider::Render()
|
||||
{
|
||||
const double val = var->Get();
|
||||
|
||||
if( var->Meta().range[0] != var->Meta().range[1] )
|
||||
{
|
||||
double rval = val;
|
||||
if (logscale)
|
||||
{
|
||||
rval = log(val);
|
||||
}
|
||||
glColor4fv(colour_fg);
|
||||
glRect(v);
|
||||
glColor4fv(colour_dn);
|
||||
const double norm_val = max(0.0,min(1.0,(rval - var->Meta().range[0]) / (var->Meta().range[1] - var->Meta().range[0])));
|
||||
glRect(Viewport(v.l,v.b, (int)(v.w*norm_val),v.h));
|
||||
DrawShadowRect(v);
|
||||
}
|
||||
|
||||
glColor4fv(colour_tx);
|
||||
if(gltext.Text() != var->Meta().friendly) {
|
||||
gltext = font().Text(var->Meta().friendly);
|
||||
}
|
||||
gltext.DrawWindow(raster[0], raster[1]);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << setprecision(4) << val;
|
||||
string str = oss.str();
|
||||
GlText glval = font().Text(str);
|
||||
const float l = glval.Width() + 2.0f;
|
||||
glval.DrawWindow( v.l + v.w - l, raster[1] );
|
||||
}
|
||||
|
||||
|
||||
TextInput::TextInput(std::string title, VarValueGeneric& tv)
|
||||
: Widget<std::string>(title+":", tv), can_edit(!(tv.Meta().flags & META_FLAG_READONLY)), do_edit(false)
|
||||
{
|
||||
top = 1.0; bottom = Attach::Pix(-tab_h());
|
||||
left = 0.0; right = 1.0;
|
||||
hlock = LockLeft;
|
||||
vlock = LockBottom;
|
||||
handler = this;
|
||||
sel[0] = -1;
|
||||
sel[1] = -1;
|
||||
gltext = font().Text(title);
|
||||
}
|
||||
|
||||
void TextInput::Keyboard(View&, unsigned char key, int /*x*/, int /*y*/, bool pressed)
|
||||
{
|
||||
if(can_edit && pressed && do_edit)
|
||||
{
|
||||
const bool selection = sel[1] > sel[0] && sel[0] >= 0;
|
||||
|
||||
if(key == 13)
|
||||
{
|
||||
var->Set(edit);
|
||||
GuiVarChanged(*this);
|
||||
|
||||
do_edit = false;
|
||||
sel[0] = sel[1] = -1;
|
||||
}else if(key == 8) {
|
||||
// backspace
|
||||
if(selection)
|
||||
{
|
||||
edit = edit.substr(0,sel[0]) + edit.substr(sel[1],edit.length()-sel[1]);
|
||||
sel[1] = sel[0];
|
||||
}else{
|
||||
if(sel[0] >0)
|
||||
{
|
||||
edit = edit.substr(0,sel[0]-1) + edit.substr(sel[0],edit.length()-sel[0]);
|
||||
sel[0]--;
|
||||
sel[1]--;
|
||||
}
|
||||
}
|
||||
}else if(key == 127){
|
||||
// delete
|
||||
if(selection)
|
||||
{
|
||||
edit = edit.substr(0,sel[0]) + edit.substr(sel[1],edit.length()-sel[1]);
|
||||
sel[1] = sel[0];
|
||||
}else{
|
||||
if(sel[0] < (int)edit.length())
|
||||
{
|
||||
edit = edit.substr(0,sel[0]) + edit.substr(sel[0]+1,edit.length()-sel[0]+1);
|
||||
}
|
||||
}
|
||||
}else if(key == 230){
|
||||
// right
|
||||
sel[0] = min((int)edit.length(),sel[0]+1);
|
||||
sel[1] = sel[0];
|
||||
}else if(key == 228){
|
||||
// left
|
||||
sel[0] = max(0,sel[0]-1);
|
||||
sel[1] = sel[0];
|
||||
}else if(key == 234){
|
||||
// home
|
||||
sel[0] = sel[1] = 0;
|
||||
}else if(key == 235){
|
||||
// end
|
||||
sel[0] = sel[1] = (int)edit.length();
|
||||
}else if(key < PANGO_SPECIAL){
|
||||
edit = edit.substr(0,sel[0]).append(1,key) + edit.substr(sel[1],edit.length()-sel[1]);
|
||||
sel[1] = sel[0];
|
||||
sel[0]++;
|
||||
sel[1]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextInput::Mouse(View& /*view*/, MouseButton button, int x, int /*y*/, bool pressed, int /*mouse_state*/)
|
||||
{
|
||||
if(can_edit && button != MouseWheelUp && button != MouseWheelDown )
|
||||
{
|
||||
|
||||
if(do_edit)
|
||||
{
|
||||
const int sl = (int)gledit.Width() + 2;
|
||||
const int rl = v.l + v.w - sl;
|
||||
int ep = (int)edit.length();
|
||||
|
||||
if( x < rl )
|
||||
{
|
||||
ep = 0;
|
||||
}else{
|
||||
for( unsigned i=0; i<edit.length(); ++i )
|
||||
{
|
||||
const int tl = (int)(rl + font().Text(edit.substr(0,i)).Width());
|
||||
if(x < tl+2)
|
||||
{
|
||||
ep = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pressed)
|
||||
{
|
||||
sel[0] = sel[1] = ep;
|
||||
}else{
|
||||
sel[1] = ep;
|
||||
}
|
||||
|
||||
if(sel[0] > sel[1])
|
||||
std::swap(sel[0],sel[1]);
|
||||
}else{
|
||||
do_edit = !pressed;
|
||||
sel[0] = 0;
|
||||
sel[1] = (int)edit.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextInput::MouseMotion(View&, int x, int /*y*/, int /*mouse_state*/)
|
||||
{
|
||||
if(can_edit && do_edit)
|
||||
{
|
||||
const int sl = (int)gledit.Width() + 2;
|
||||
const int rl = v.l + v.w - sl;
|
||||
int ep = (int)edit.length();
|
||||
|
||||
if( x < rl )
|
||||
{
|
||||
ep = 0;
|
||||
}else{
|
||||
for( unsigned i=0; i<edit.length(); ++i )
|
||||
{
|
||||
const int tl = (int)(rl + font().Text(edit.substr(0,i)).Width());
|
||||
if(x < tl+2)
|
||||
{
|
||||
ep = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sel[1] = ep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TextInput::ResizeChildren()
|
||||
{
|
||||
raster[0] = v.l + 2.0f;
|
||||
raster[1] = v.b + (v.h-gltext.Height()) / 2.0f;
|
||||
}
|
||||
|
||||
void TextInput::Render()
|
||||
{
|
||||
if(!do_edit) edit = var->Get();
|
||||
|
||||
gledit = font().Text(edit);
|
||||
|
||||
glColor4fv(colour_fg);
|
||||
if(can_edit) glRect(v);
|
||||
|
||||
const int sl = (int)gledit.Width() + 2;
|
||||
const int rl = v.l + v.w - sl;
|
||||
|
||||
if( do_edit && sel[0] >= 0)
|
||||
{
|
||||
const int tl = (int)(rl + font().Text(edit.substr(0,sel[0])).Width());
|
||||
const int tr = (int)(rl + font().Text(edit.substr(0,sel[1])).Width());
|
||||
glColor4fv(colour_dn);
|
||||
glRect(Viewport(tl,v.b,tr-tl,v.h));
|
||||
}
|
||||
|
||||
glColor4fv(colour_tx);
|
||||
gltext.DrawWindow(raster[0], raster[1]);
|
||||
|
||||
gledit.DrawWindow((GLfloat)(rl), raster[1]);
|
||||
if(can_edit) DrawShadowRect(v);
|
||||
}
|
||||
|
||||
}
|
||||
42
thirdparty/Pangolin/src/display/window_factory.cpp
vendored
Normal file
42
thirdparty/Pangolin/src/display/window_factory.cpp
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2011-2017 Steven Lovegrove, Andrey Mnatsakanov
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pangolin/display/window.h>
|
||||
#include <pangolin/factory/factory_registry.h>
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
|
||||
template<>
|
||||
FactoryRegistry<WindowInterface>& FactoryRegistry<WindowInterface>::I()
|
||||
{
|
||||
// Singleton instance
|
||||
static FactoryRegistry instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user