From: Mikko Rasa Date: Thu, 6 Mar 2008 12:54:18 +0000 (+0000) Subject: Reorganize files to separate gbase and input X-Git-Tag: 0.9~7 X-Git-Url: http://git.tdb.fi/?p=libs%2Fgui.git;a=commitdiff_plain;h=999ca92aa9ee10585c0b2094d84364159253982f Reorganize files to separate gbase and input --- diff --git a/Build b/Build index 3386119..17a6fdc 100644 --- a/Build +++ b/Build @@ -27,10 +27,22 @@ package "mspgbase" }; }; + headers "gbase" + { + source "source/gbase"; + install_headers "msp/gbase"; + }; + + headers "input" + { + source "source/input"; + install_headers "msp/input"; + }; + library "mspgbase" { - source "source"; + source "source/gbase"; + source "source/input"; install true; - install_headers "msp/gbase"; }; }; diff --git a/source/binarycontrol.cpp b/source/binarycontrol.cpp deleted file mode 100644 index daafd95..0000000 --- a/source/binarycontrol.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include "binarycontrol.h" -#include "inputdevice.h" - -namespace Msp { -namespace Input { - -BinaryControl::BinaryControl(): - state(false) -{ } - -BinaryControl::BinaryControl(const ControlSource &s): - Control(s), - state(false) -{ } - -BinaryControl::BinaryControl(Device &d, ControlSrcType t, unsigned i): - Control(d, t, i), - state(false) -{ } - -void BinaryControl::on_press() -{ - if(!state) - { - state=true; - signal_press.emit(); - } -} - -void BinaryControl::on_release() -{ - if(state) - { - state=false; - signal_release.emit(); - } -} - -void BinaryControl::on_motion(float value, float) -{ - if(value>src.dev->get_axis_threshold()) - on_press(); - else - on_release(); -} - -} // namespace Input -} // namespace Msp diff --git a/source/binarycontrol.h b/source/binarycontrol.h deleted file mode 100644 index 44aaef4..0000000 --- a/source/binarycontrol.h +++ /dev/null @@ -1,45 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_BINARYCONTROL_H_ -#define MSP_GBASE_BINARYCONTROL_H_ - -#include "control.h" - -namespace Msp { -namespace Input { - -/** -A control with two possible states. Button state is mapped directly. An axis -is considered to be active when its value is above a threshold (defined by the -input device). -*/ -class BinaryControl: public Control -{ -public: - sigc::signal signal_press; - sigc::signal signal_release; - -private: - bool state; - -public: - BinaryControl(); - BinaryControl(const ControlSource &); - BinaryControl(Device &, ControlSrcType, unsigned); - bool get_state() const { return state; } - -private: - virtual void on_press(); - virtual void on_release(); - virtual void on_motion(float, float); -}; - -} // namespace Input -} // namespace Msp - -#endif diff --git a/source/control.cpp b/source/control.cpp deleted file mode 100644 index 823202d..0000000 --- a/source/control.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include -#include -#include "control.h" -#include "inputdevice.h" - -namespace Msp { -namespace Input { - -ControlSource::ControlSource(): - dev(0), - type(NONE), - index(0) -{ } - -ControlSource::ControlSource(Device &d, ControlSrcType t, unsigned i): - dev(&d), - type(t), - index(i) -{ } - -std::string ControlSource::str() const -{ - if(type==BUTTON) - return dev->get_button_name(index); - else if(type==AXIS_POS || type==AXIS_NEG) - return dev->get_axis_name(index); - else if(type==NONE) - return "None"; - - return lexical_cast(index); -} - - -Control::Control(): - capture_dev(0) -{ } - -Control::Control(const ControlSource &s): - src(s), - capture_dev(0) -{ } - -Control::Control(Device &d, ControlSrcType t, unsigned i): - src(d, t, i), - capture_dev(0) -{ - connect_signals(); -} - -Control::Control(const Control &c): - trackable(c), - src(c.src), - capture_dev(0) -{ - connect_signals(); -} - -Control &Control::operator=(const Control &c) -{ - notify_callbacks(); - src=c.src; - capture_dev=0; - connect_signals(); - - return *this; -} - -void Control::capture(Device &d) -{ - notify_callbacks(); - capture_dev=&d; - capture_dev->signal_button_press.connect(sigc::mem_fun(this, &Control::button_press)); - capture_dev->signal_axis_motion.connect(sigc::mem_fun(this, &Control::axis_motion)); -} - -void Control::cancel_capture() -{ - notify_callbacks(); - capture_dev=0; - connect_signals(); -} - -void Control::connect_signals() -{ - switch(src.type) - { - case NONE: - break; - case BUTTON: - src.dev->signal_button_press.connect(sigc::mem_fun(this, &Control::button_press)); - src.dev->signal_button_release.connect(sigc::mem_fun(this, &Control::button_release)); - break; - case AXIS_POS: - case AXIS_NEG: - src.dev->signal_axis_motion.connect(sigc::mem_fun(this, &Control::axis_motion)); - break; - default: - throw Exception("Invalid source in Control"); - } -} - -void Control::button_press(unsigned i) -{ - if(capture_dev) - { - src.dev=capture_dev; - src.type=BUTTON; - src.index=i; - - notify_callbacks(); - capture_dev=0; - connect_signals(); - signal_capture_complete.emit(); - } - else if(src.type==BUTTON && i==src.index) - on_press(); -} - -void Control::button_release(unsigned i) -{ - if(src.type==BUTTON && i==src.index) - on_release(); -} - -void Control::axis_motion(unsigned i, float v, float r) -{ - if(capture_dev) - { - ControlSrcType type=NONE; - if(v<-src.dev->get_axis_threshold()) - type=AXIS_NEG; - else if(v>src.dev->get_axis_threshold()) - type=AXIS_POS; - - if(type!=NONE) - { - src.dev=capture_dev; - src.type=type; - src.index=i; - - notify_callbacks(); - capture_dev=0; - connect_signals(); - signal_capture_complete.emit(); - } - } - else if(src.type==AXIS_POS && i==src.index && v>=0) - on_motion(v, r); - else if(src.type==AXIS_NEG && i==src.index && v<=0) - on_motion(-v, -r); -} - -} // namespace Input -} // namespace Msp diff --git a/source/control.h b/source/control.h deleted file mode 100644 index f7146b4..0000000 --- a/source/control.h +++ /dev/null @@ -1,86 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_CONTROL_H_ -#define MSP_GBASE_CONTROL_H_ - -#include -#include - -namespace Msp { -namespace Input { - -class Device; - -enum ControlSrcType -{ - NONE, - BUTTON, - AXIS_POS, - AXIS_NEG -}; - -/** -Specifies the source of a control. This provides a way for setting sources for -different types of controls in a uniform way. -*/ -struct ControlSource -{ - Device *dev; - ControlSrcType type; - unsigned index; - - ControlSource(); - ControlSource(Device &, ControlSrcType, unsigned); - std::string str() const; -}; - -/** -Provides further abstraction on top of input devices. There are two types of -controls currently defined: BinaryControl and SmoothControl. - -A control uses either a button or half of an axis (positive or negative) as its -source. How the source values are interpreted depends on the exact type of the -control. Controls also support interactive binding by capturing a button press -or axis motion. -*/ -class Control: public sigc::trackable -{ -public: - sigc::signal signal_capture_complete; - -protected: - ControlSource src; - Device *capture_dev; - - Control(); - Control(const ControlSource &); - Control(Device &, ControlSrcType, unsigned); - Control(const Control &); -public: - Control &operator=(const Control &); - virtual ~Control() { } - - void capture(Device &); - void cancel_capture(); - const ControlSource &get_source() const { return src; } -protected: - virtual void on_press() =0; - virtual void on_release() =0; - virtual void on_motion(float, float) =0; - -private: - void connect_signals(); - void button_press(unsigned); - void button_release(unsigned); - void axis_motion(unsigned, float, float); -}; - -} // namespace Input -} // namespace Msp - -#endif diff --git a/source/display.cpp b/source/display.cpp deleted file mode 100644 index 3baf7c1..0000000 --- a/source/display.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include -#ifndef WIN32 -#include -#include -#endif -#include -#include -#include -#include "display.h" -#include "window.h" - -using namespace std; - -namespace { - -bool error_flag=false; -std::string error_msg; - -#ifndef WIN32 -int x_error_handler(Display *display, XErrorEvent *event) -{ - char err[128]; - XGetErrorText(display, event->error_code, err, sizeof(err)); - - string request_code=Msp::lexical_cast(static_cast(event->request_code)); - char req[128]; - XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), request_code.c_str(), req, sizeof(req)); - - string msg=Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid); - if(error_flag) - cerr<<"Discarding error: "<get_handle()]=wnd; -} - -void Display::remove_window(Window *wnd) -{ - windows.erase(wnd->get_handle()); -} - -void Display::set_mode(const VideoMode &mode) -{ -#ifndef WIN32 - int screen=DefaultScreen(display); - - int nmodes; - XF86VidModeModeInfo **infos; - XF86VidModeGetAllModeLines(display, screen, &nmodes, &infos); - for(int i=0; i::iterator j=windows.find(event.xany.window); - if(j!=windows.end()) - j->second->event(event); - } -#endif - } -} - -void Display::check_error() -{ - if(error_flag) - { - error_flag=false; - throw Exception(error_msg); - } -} - -} // namespace Graphics -} // namespace Msp diff --git a/source/display.h b/source/display.h deleted file mode 100644 index 70efd20..0000000 --- a/source/display.h +++ /dev/null @@ -1,63 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_DISPLAY_H_ -#define MSP_GBASE_DISPLAY_H_ - -#include -#include -#include -#include "types.h" - -namespace Msp { -namespace Graphics { - -class Window; - -struct VideoMode -{ - unsigned width; - unsigned height; - unsigned rate; - - VideoMode(): width(0), height(0), rate(0) { } - VideoMode(unsigned w, unsigned h): width(w), height(h), rate(0) { } -}; - -class Display -{ -private: -#ifndef WIN32 - ::Display *display; -#endif - std::list modes; - VideoMode orig_mode; - std::map windows; - -public: - Display(const std::string &disp_name=std::string()); - ~Display(); - -#ifndef WIN32 - ::Display *get_display() const { return display; } -#endif - - void add_window(Window *); - void remove_window(Window *); - - const std::list &get_modes() const { return modes; } - void set_mode(const VideoMode &); - void restore_mode() { set_mode(orig_mode); } - - void tick(); - void check_error(); -}; - -} // namespace Graphics -} // namespace Msp - -#endif diff --git a/source/drawcontext.cpp b/source/drawcontext.cpp deleted file mode 100644 index d3ac485..0000000 --- a/source/drawcontext.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef WIN32 -#include -#include -#include -#endif -#include -#include "display.h" -#include "drawcontext.h" -#include "window.h" - -namespace Msp { -namespace Graphics { - -DrawContext::DrawContext(Window &w): - display(w.get_display()), - window(w), - image(0) -{ -#ifndef WIN32 - ::Display *dpy=display.get_display(); - - use_shm=XShmQueryExtension(dpy); - - XWindowAttributes wa; - XGetWindowAttributes(dpy, window.get_handle(), &wa); - - if(use_shm) - { - image=XShmCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, &shminfo, wa.width, wa.height); - if(!image) - throw Exception("Could not create shared memory XImage"); - - shminfo.shmid=shmget(IPC_PRIVATE, image->bytes_per_line*image->height, IPC_CREAT|0666); - shminfo.shmaddr=image->data=reinterpret_cast(shmat(shminfo.shmid, 0, 0)); - shminfo.readOnly=false; - - XShmAttach(dpy, &shminfo); - - XSync(dpy, false); - display.check_error(); - } - else - { - image=XCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, 0, wa.width, wa.height, 8, 0); - if(!image) - throw Exception("Could not create XImage"); - image->data=new char[image->bytes_per_line*image->height]; - } -#endif -} - -DrawContext::~DrawContext() -{ -#ifndef WIN32 - if(use_shm) - { - XShmDetach(display.get_display(), &shminfo); - shmdt(shminfo.shmaddr); - shmctl(shminfo.shmid, IPC_RMID, 0); - } - - XDestroyImage(image); -#endif -} - -void DrawContext::update() -{ -#ifndef WIN32 - ::Display *dpy=display.get_display(); - - GC gc=XCreateGC(dpy, window.get_handle(), 0, 0); - - if(use_shm) - XShmPutImage(dpy, window.get_handle(), gc, image, 0, 0, 0, 0, image->width, image->height, false); - else - XPutImage(dpy, window.get_handle(), gc, image, 0, 0, 0, 0, image->width, image->height); - - XFreeGC(dpy, gc); -#endif -} - -} // namespace Graphics -} // namespace Msp diff --git a/source/drawcontext.h b/source/drawcontext.h deleted file mode 100644 index 54ae3b3..0000000 --- a/source/drawcontext.h +++ /dev/null @@ -1,46 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_DRAWCONTEXT_H_ -#define MSP_GBASE_DRAWCONTEXT_H_ - -#ifndef WIN32 -#include -#include -#endif - -namespace Msp { -namespace Graphics { - -class Display; -class Window; - -class DrawContext -{ -private: - Display &display; - Window &window; -#ifndef WIN32 - XImage *image; - bool use_shm; - XShmSegmentInfo shminfo; -#endif - -public: - DrawContext(Window &); - ~DrawContext(); - - Window &get_window() const { return window; } - unsigned get_depth() const { return image->bits_per_pixel; } - unsigned char *get_data() { return reinterpret_cast(image->data); } - void update(); -}; - -} // namespace Graphics -} // namespace Msp - -#endif diff --git a/source/gbase/display.cpp b/source/gbase/display.cpp new file mode 100644 index 0000000..3baf7c1 --- /dev/null +++ b/source/gbase/display.cpp @@ -0,0 +1,180 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#ifndef WIN32 +#include +#include +#endif +#include +#include +#include +#include "display.h" +#include "window.h" + +using namespace std; + +namespace { + +bool error_flag=false; +std::string error_msg; + +#ifndef WIN32 +int x_error_handler(Display *display, XErrorEvent *event) +{ + char err[128]; + XGetErrorText(display, event->error_code, err, sizeof(err)); + + string request_code=Msp::lexical_cast(static_cast(event->request_code)); + char req[128]; + XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), request_code.c_str(), req, sizeof(req)); + + string msg=Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid); + if(error_flag) + cerr<<"Discarding error: "<get_handle()]=wnd; +} + +void Display::remove_window(Window *wnd) +{ + windows.erase(wnd->get_handle()); +} + +void Display::set_mode(const VideoMode &mode) +{ +#ifndef WIN32 + int screen=DefaultScreen(display); + + int nmodes; + XF86VidModeModeInfo **infos; + XF86VidModeGetAllModeLines(display, screen, &nmodes, &infos); + for(int i=0; i::iterator j=windows.find(event.xany.window); + if(j!=windows.end()) + j->second->event(event); + } +#endif + } +} + +void Display::check_error() +{ + if(error_flag) + { + error_flag=false; + throw Exception(error_msg); + } +} + +} // namespace Graphics +} // namespace Msp diff --git a/source/gbase/display.h b/source/gbase/display.h new file mode 100644 index 0000000..70efd20 --- /dev/null +++ b/source/gbase/display.h @@ -0,0 +1,63 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_DISPLAY_H_ +#define MSP_GBASE_DISPLAY_H_ + +#include +#include +#include +#include "types.h" + +namespace Msp { +namespace Graphics { + +class Window; + +struct VideoMode +{ + unsigned width; + unsigned height; + unsigned rate; + + VideoMode(): width(0), height(0), rate(0) { } + VideoMode(unsigned w, unsigned h): width(w), height(h), rate(0) { } +}; + +class Display +{ +private: +#ifndef WIN32 + ::Display *display; +#endif + std::list modes; + VideoMode orig_mode; + std::map windows; + +public: + Display(const std::string &disp_name=std::string()); + ~Display(); + +#ifndef WIN32 + ::Display *get_display() const { return display; } +#endif + + void add_window(Window *); + void remove_window(Window *); + + const std::list &get_modes() const { return modes; } + void set_mode(const VideoMode &); + void restore_mode() { set_mode(orig_mode); } + + void tick(); + void check_error(); +}; + +} // namespace Graphics +} // namespace Msp + +#endif diff --git a/source/gbase/drawcontext.cpp b/source/gbase/drawcontext.cpp new file mode 100644 index 0000000..d3ac485 --- /dev/null +++ b/source/gbase/drawcontext.cpp @@ -0,0 +1,90 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef WIN32 +#include +#include +#include +#endif +#include +#include "display.h" +#include "drawcontext.h" +#include "window.h" + +namespace Msp { +namespace Graphics { + +DrawContext::DrawContext(Window &w): + display(w.get_display()), + window(w), + image(0) +{ +#ifndef WIN32 + ::Display *dpy=display.get_display(); + + use_shm=XShmQueryExtension(dpy); + + XWindowAttributes wa; + XGetWindowAttributes(dpy, window.get_handle(), &wa); + + if(use_shm) + { + image=XShmCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, &shminfo, wa.width, wa.height); + if(!image) + throw Exception("Could not create shared memory XImage"); + + shminfo.shmid=shmget(IPC_PRIVATE, image->bytes_per_line*image->height, IPC_CREAT|0666); + shminfo.shmaddr=image->data=reinterpret_cast(shmat(shminfo.shmid, 0, 0)); + shminfo.readOnly=false; + + XShmAttach(dpy, &shminfo); + + XSync(dpy, false); + display.check_error(); + } + else + { + image=XCreateImage(dpy, wa.visual, wa.depth, ZPixmap, 0, 0, wa.width, wa.height, 8, 0); + if(!image) + throw Exception("Could not create XImage"); + image->data=new char[image->bytes_per_line*image->height]; + } +#endif +} + +DrawContext::~DrawContext() +{ +#ifndef WIN32 + if(use_shm) + { + XShmDetach(display.get_display(), &shminfo); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + } + + XDestroyImage(image); +#endif +} + +void DrawContext::update() +{ +#ifndef WIN32 + ::Display *dpy=display.get_display(); + + GC gc=XCreateGC(dpy, window.get_handle(), 0, 0); + + if(use_shm) + XShmPutImage(dpy, window.get_handle(), gc, image, 0, 0, 0, 0, image->width, image->height, false); + else + XPutImage(dpy, window.get_handle(), gc, image, 0, 0, 0, 0, image->width, image->height); + + XFreeGC(dpy, gc); +#endif +} + +} // namespace Graphics +} // namespace Msp diff --git a/source/gbase/drawcontext.h b/source/gbase/drawcontext.h new file mode 100644 index 0000000..54ae3b3 --- /dev/null +++ b/source/gbase/drawcontext.h @@ -0,0 +1,46 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_DRAWCONTEXT_H_ +#define MSP_GBASE_DRAWCONTEXT_H_ + +#ifndef WIN32 +#include +#include +#endif + +namespace Msp { +namespace Graphics { + +class Display; +class Window; + +class DrawContext +{ +private: + Display &display; + Window &window; +#ifndef WIN32 + XImage *image; + bool use_shm; + XShmSegmentInfo shminfo; +#endif + +public: + DrawContext(Window &); + ~DrawContext(); + + Window &get_window() const { return window; } + unsigned get_depth() const { return image->bits_per_pixel; } + unsigned char *get_data() { return reinterpret_cast(image->data); } + void update(); +}; + +} // namespace Graphics +} // namespace Msp + +#endif diff --git a/source/gbase/glcontext.cpp b/source/gbase/glcontext.cpp new file mode 100644 index 0000000..a749c6c --- /dev/null +++ b/source/gbase/glcontext.cpp @@ -0,0 +1,149 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#ifdef WIN32 +#include +#endif +#include +#include +#include +#include "display.h" +#include "glcontext.h" +#include "window.h" + +#include +using namespace std; + +namespace Msp { +namespace Graphics { + +GLOptions::GLOptions(): + alpha(false), + stencil(false), + doublebuffer(true), + multisample(0) +{ } + + +GLContext::GLContext(Window &wnd, const GLOptions &opts): + display(wnd.get_display()), + window(wnd) +{ +#ifdef WIN32 + HDC dc=GetDC(window.get_handle()); + + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(pfd)); + + pfd.nSize=sizeof(pfd); + pfd.nVersion=1; + pfd.dwFlags=PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + if(opts.doublebuffer) + pfd.dwFlags|=PFD_DOUBLEBUFFER; + pfd.iPixelType=PFD_TYPE_RGBA; + if(opts.alpha) + pfd.cAlphaBits=1; + pfd.cDepthBits=1; + if(opts.stencil) + pfd.cStencilBits=1; + + int pf_index=ChoosePixelFormat(dc, &pfd); + if(!pf_index) + throw Exception("Couldn't find a suitable pixel format"); + SetPixelFormat(dc, pf_index, &pfd); + + context=wglCreateContext(dc); + wglMakeCurrent(dc, context); + + ReleaseDC(window.get_handle(), dc); +#else + std::vector attribs; + + attribs.push_back(GLX_RGBA); + attribs.push_back(GLX_DEPTH_SIZE); + attribs.push_back(1); + + if(opts.alpha) + { + attribs.push_back(GLX_ALPHA_SIZE); + attribs.push_back(1); + } + + if(opts.stencil) + { + attribs.push_back(GLX_STENCIL_SIZE); + attribs.push_back(1); + } + + if(opts.doublebuffer) + attribs.push_back(GLX_DOUBLEBUFFER); + + if(opts.multisample>0) + { + attribs.push_back(GLX_SAMPLE_BUFFERS_ARB); + attribs.push_back(opts.multisample); + } + + attribs.push_back(0); + + ::Display *dpy=display.get_display(); + + XVisualInfo *vi=glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front()); + if(!vi) + throw Exception("Couldn't find a suitable GLX visual"); + context=glXCreateContext(dpy, vi, 0, true); + + XSetWindowAttributes attr; + attr.colormap=XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone); + + subwnd=XCreateWindow(dpy, window.get_handle(), 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr); + XMapWindow(display.get_display(), subwnd); + + XFree(vi); + + glXMakeCurrent(dpy, subwnd, context); + + window.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized)); +#endif +} + +GLContext::~GLContext() +{ +#ifdef WIN32 + wglMakeCurrent(0, 0); + wglDeleteContext(context); +#else + ::Display *dpy=display.get_display(); + + glXMakeCurrent(dpy, 0, 0); + glXDestroyContext(dpy, context); + XDestroyWindow(dpy, subwnd); +#endif +} + +void GLContext::swap_buffers() +{ +#ifdef WIN32 + HDC dc=GetDC(window.get_handle()); + SwapBuffers(dc); + ReleaseDC(window.get_handle(), dc); +#else + glXSwapBuffers(display.get_display(), subwnd); +#endif +} + +void GLContext::window_resized(unsigned w, unsigned h) +{ +#ifndef WIN32 + XMoveResizeWindow(display.get_display(), subwnd, 0, 0, w, h); +#endif + glViewport(0, 0, w, h); +} + +} // namespace Graphics +} // namespace Msp diff --git a/source/gbase/glcontext.h b/source/gbase/glcontext.h new file mode 100644 index 0000000..297bc34 --- /dev/null +++ b/source/gbase/glcontext.h @@ -0,0 +1,59 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_GLCONTEXT_H_ +#define MSP_GBASE_GLCONTEXT_H_ + +#ifndef WIN32 +#include +#endif +#include "types.h" + +namespace Msp { +namespace Graphics { + +class Display; + +struct GLOptions +{ + bool alpha; + bool stencil; + bool doublebuffer; + unsigned multisample; + + GLOptions(); +}; + +class GLContext +{ +private: +#ifdef WIN32 + typedef HGLRC Context; +#else + typedef GLXContext Context; +#endif + + Display &display; + Window &window; + Context context; +#ifndef WIN32 + WindowHandle subwnd; +#endif + +public: + GLContext(Window &wnd, const GLOptions &opts=GLOptions()); + ~GLContext(); + + void swap_buffers(); +private: + void window_resized(unsigned, unsigned); +}; + +} // namespace Graphics +} // namespace Msp + +#endif diff --git a/source/gbase/types.h b/source/gbase/types.h new file mode 100644 index 0000000..e3524f3 --- /dev/null +++ b/source/gbase/types.h @@ -0,0 +1,29 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_TYPES_H_ +#define MSP_GBASE_TYPES_H_ + +#ifdef WIN32 +#include +#else +#include +#endif + +namespace Msp { +namespace Graphics { + +#ifdef WIN32 +typedef HWND WindowHandle; +#else +typedef ::Window WindowHandle; +#endif + +} // namespace Graphics +} // namespace Msp + +#endif diff --git a/source/gbase/window.cpp b/source/gbase/window.cpp new file mode 100644 index 0000000..da877e9 --- /dev/null +++ b/source/gbase/window.cpp @@ -0,0 +1,322 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#ifndef WIN32 +#include +#include +#else +#include +#endif +#include +#include +#include "display.h" +#include "window.h" + +using namespace std; + +#include + +namespace Msp { +namespace Graphics { + +WindowOptions::WindowOptions(): + width(640), + height(480), + fullscreen(false), + resizable(false) +{ } + + +Window::Window(Display &dpy, unsigned w, unsigned h, bool fs): + display(dpy) +{ + options.width=w; + options.height=h; + options.fullscreen=fs; + + init(); +} + +Window::Window(Display &dpy, const WindowOptions &opts): + display(dpy), + options(opts) +{ + init(); +} + +Window::~Window() +{ + if(window) +#ifdef WIN32 + CloseWindow(window); +#else + XDestroyWindow(display.get_display(), window); +#endif + + display.remove_window(this); + + if(options.fullscreen) + display.restore_mode(); +} + +void Window::set_title(const string &title) +{ +#ifdef WIN32 + SetWindowText(window, title.c_str()); +#else + vector buf(title.begin(), title.end()); + XTextProperty prop; + prop.value=&buf[0]; + prop.encoding=XA_STRING; + prop.format=8; + prop.nitems=title.size(); + XSetWMName(display.get_display(), window, &prop); + display.check_error(); +#endif +} + +void Window::reconfigure(const WindowOptions &opts) +{ + bool fullscreen_changed=(opts.fullscreen!=options.fullscreen); + + options=opts; + +#ifdef WIN32 + // XXX Preserve position + MoveWindow(window, 0, 0, options.width, options.height, false); + + (void)fullscreen_changed; +#else + ::Display *dpy=display.get_display(); + + XMoveResizeWindow(dpy, window, 0, 0, options.width, options.height); + + if(fullscreen_changed) + { + hide(); + XSetWindowAttributes attr; + attr.override_redirect=options.fullscreen; + XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &attr); + show(); + } + + if(options.fullscreen) + display.set_mode(VideoMode(options.width, options.height)); + else if(fullscreen_changed) + display.restore_mode(); +#endif +} + +void Window::show() +{ +#ifdef WIN32 + ShowWindow(window, SW_SHOWNORMAL); +#else + XMapRaised(display.get_display(), window); + display.check_error(); +#endif +} + +void Window::hide() +{ +#ifdef WIN32 + ShowWindow(window, SW_HIDE); +#else + XUnmapWindow(display.get_display(), window); + display.check_error(); +#endif +} + +void Window::init() +{ +#ifdef WIN32 + static bool wndclass_created=false; + + if(!wndclass_created) + { + WNDCLASSEX wndcl; + + wndcl.cbSize=sizeof(WNDCLASSEX); + wndcl.style=0; + wndcl.lpfnWndProc=&wndproc_; + wndcl.cbClsExtra=0; + wndcl.cbWndExtra=sizeof(Window *); + wndcl.hInstance=reinterpret_cast(Application::get_data()); + wndcl.hIcon=0; + wndcl.hCursor=LoadCursor(0, IDC_ARROW); + wndcl.hbrBackground=0; + wndcl.lpszMenuName=0; + wndcl.lpszClassName="mspgbase"; + wndcl.hIconSm=0; + + if(!RegisterClassEx(&wndcl)) + throw Exception("Couldn't register window class"); + + wndclass_created=true; + } + + RECT rect; + rect.left=0; + rect.top=0; + rect.right=options.width; + rect.bottom=options.height; + AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW); + + window=CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, + "mspgbase", + "Window", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + rect.right-rect.left, rect.bottom-rect.top, + 0, + 0, + reinterpret_cast(Application::get_data()), + this); + if(!window) + throw Exception("CreateWindowEx failed"); + +#else + ::Display *dpy=display.get_display(); + + wm_delete_window=XInternAtom(dpy, "WM_DELETE_WINDOW", true); + + XSetWindowAttributes attr; + attr.override_redirect=options.fullscreen; + attr.event_mask=ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask; + + window=XCreateWindow(dpy, + DefaultRootWindow(dpy), + 0, 0, + options.width, options.height, + 0, + CopyFromParent, + InputOutput, + CopyFromParent, + CWOverrideRedirect|CWEventMask, &attr); + + XSetWMProtocols(dpy, window, &wm_delete_window, 1); + + if(options.fullscreen) + { + display.set_mode(VideoMode(options.width, options.height)); + XWarpPointer(dpy, None, window, 0, 0, 0, 0, options.width/2, options.height/2); + } +#endif + + display.add_window(this); + display.check_error(); +} + +#ifndef WIN32 +void Window::event(const XEvent &ev) +{ + switch(ev.type) + { + case ButtonPress: + signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state); + break; + case ButtonRelease: + signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state); + break; + case MotionNotify: + signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y); + break; + case KeyPress: + { + char buf[16]; + XLookupString(const_cast(&ev.xkey), buf, sizeof(buf), 0, 0); + // XXX Handle the result according to locale + signal_key_press.emit(ev.xkey.keycode, ev.xkey.state, buf[0]); + } + break; + case KeyRelease: + signal_key_release.emit(ev.xkey.keycode, ev.xkey.state); + break; + case ConfigureNotify: + options.width=ev.xconfigure.width; + options.height=ev.xconfigure.height; + signal_resize.emit(options.width, options.height); + break; + case ClientMessage: + if(ev.xclient.data.l[0]==static_cast(wm_delete_window)) + signal_close.emit(); + break; + case EnterNotify: + XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime); + break; + case MapNotify: + if(options.fullscreen) + XGrabPointer(display.get_display(), window, true, None, GrabModeAsync, GrabModeAsync, window, None, CurrentTime); + break; + default:; + } +} +#endif + +#ifdef WIN32 +int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp) +{ + switch(msg) + { + case WM_KEYDOWN: + signal_key_press.emit((lp>>16)&0x1FF, 0, wp); + break; + case WM_KEYUP: + signal_key_release.emit((lp>>16)&0x1FF, 0); + break; + case WM_LBUTTONDOWN: + signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0); + break; + case WM_LBUTTONUP: + signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0); + break; + case WM_MBUTTONDOWN: + signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0); + break; + case WM_MBUTTONUP: + signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0); + break; + case WM_RBUTTONDOWN: + signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); + break; + case WM_RBUTTONUP: + signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); + break; + case WM_MOUSEMOVE: + signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp)); + break; + case WM_CLOSE: + signal_close.emit(); + break; + default: + return 0; + } + + return 1; +} + +LRESULT CALLBACK Window::wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if(msg==WM_CREATE) + { + CREATESTRUCT *cs=reinterpret_cast(lparam); + SetWindowLong(hwnd, 0, reinterpret_cast(cs->lpCreateParams)); + } + else + { + Window *wnd=reinterpret_cast(GetWindowLong(hwnd, 0)); + if(wnd && wnd->wndproc(msg, wparam, lparam)) + return 0; + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} +#endif + +} // namespace Graphics +} // namespace Msp diff --git a/source/gbase/window.h b/source/gbase/window.h new file mode 100644 index 0000000..e85f86a --- /dev/null +++ b/source/gbase/window.h @@ -0,0 +1,80 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_WINDOW_H_ +#define MSP_GBASE_WINDOW_H_ + +#include +#include +#include "types.h" + +namespace Msp { +namespace Graphics { + +class Display; + +struct WindowOptions +{ + unsigned width; + unsigned height; + bool fullscreen; + bool resizable; + + WindowOptions(); +}; + +class Window +{ +public: + sigc::signal signal_button_press; + sigc::signal signal_button_release; + sigc::signal signal_pointer_motion; + sigc::signal signal_key_press; + sigc::signal signal_key_release; + sigc::signal signal_resize; + sigc::signal signal_close; + +protected: + Display &display; + WindowOptions options; + WindowHandle window; +#ifndef WIN32 + Atom wm_delete_window; +#endif + +public: + Window(Display &, unsigned w, unsigned h, bool fs=false); + Window(Display &, const WindowOptions &); + ~Window(); + + void set_title(const std::string &); + void reconfigure(const WindowOptions &); + + Display &get_display() const { return display; } + const WindowOptions &get_options() const { return options; } + unsigned get_width() const { return options.width; } + unsigned get_height() const { return options.height; } + WindowHandle get_handle() const { return window; } + + void show(); + void hide(); + +#ifndef WIN32 + void event(const XEvent &ev); +#endif +protected: + void init(); +#ifdef WIN32 + int wndproc(UINT, WPARAM, LPARAM); + static LRESULT CALLBACK wndproc_(HWND, UINT, WPARAM, LPARAM); +#endif +}; + +} // namespace Graphics +} // namespace Msp + +#endif diff --git a/source/glcontext.cpp b/source/glcontext.cpp deleted file mode 100644 index a749c6c..0000000 --- a/source/glcontext.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include -#ifdef WIN32 -#include -#endif -#include -#include -#include -#include "display.h" -#include "glcontext.h" -#include "window.h" - -#include -using namespace std; - -namespace Msp { -namespace Graphics { - -GLOptions::GLOptions(): - alpha(false), - stencil(false), - doublebuffer(true), - multisample(0) -{ } - - -GLContext::GLContext(Window &wnd, const GLOptions &opts): - display(wnd.get_display()), - window(wnd) -{ -#ifdef WIN32 - HDC dc=GetDC(window.get_handle()); - - PIXELFORMATDESCRIPTOR pfd; - memset(&pfd, 0, sizeof(pfd)); - - pfd.nSize=sizeof(pfd); - pfd.nVersion=1; - pfd.dwFlags=PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; - if(opts.doublebuffer) - pfd.dwFlags|=PFD_DOUBLEBUFFER; - pfd.iPixelType=PFD_TYPE_RGBA; - if(opts.alpha) - pfd.cAlphaBits=1; - pfd.cDepthBits=1; - if(opts.stencil) - pfd.cStencilBits=1; - - int pf_index=ChoosePixelFormat(dc, &pfd); - if(!pf_index) - throw Exception("Couldn't find a suitable pixel format"); - SetPixelFormat(dc, pf_index, &pfd); - - context=wglCreateContext(dc); - wglMakeCurrent(dc, context); - - ReleaseDC(window.get_handle(), dc); -#else - std::vector attribs; - - attribs.push_back(GLX_RGBA); - attribs.push_back(GLX_DEPTH_SIZE); - attribs.push_back(1); - - if(opts.alpha) - { - attribs.push_back(GLX_ALPHA_SIZE); - attribs.push_back(1); - } - - if(opts.stencil) - { - attribs.push_back(GLX_STENCIL_SIZE); - attribs.push_back(1); - } - - if(opts.doublebuffer) - attribs.push_back(GLX_DOUBLEBUFFER); - - if(opts.multisample>0) - { - attribs.push_back(GLX_SAMPLE_BUFFERS_ARB); - attribs.push_back(opts.multisample); - } - - attribs.push_back(0); - - ::Display *dpy=display.get_display(); - - XVisualInfo *vi=glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front()); - if(!vi) - throw Exception("Couldn't find a suitable GLX visual"); - context=glXCreateContext(dpy, vi, 0, true); - - XSetWindowAttributes attr; - attr.colormap=XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone); - - subwnd=XCreateWindow(dpy, window.get_handle(), 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr); - XMapWindow(display.get_display(), subwnd); - - XFree(vi); - - glXMakeCurrent(dpy, subwnd, context); - - window.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized)); -#endif -} - -GLContext::~GLContext() -{ -#ifdef WIN32 - wglMakeCurrent(0, 0); - wglDeleteContext(context); -#else - ::Display *dpy=display.get_display(); - - glXMakeCurrent(dpy, 0, 0); - glXDestroyContext(dpy, context); - XDestroyWindow(dpy, subwnd); -#endif -} - -void GLContext::swap_buffers() -{ -#ifdef WIN32 - HDC dc=GetDC(window.get_handle()); - SwapBuffers(dc); - ReleaseDC(window.get_handle(), dc); -#else - glXSwapBuffers(display.get_display(), subwnd); -#endif -} - -void GLContext::window_resized(unsigned w, unsigned h) -{ -#ifndef WIN32 - XMoveResizeWindow(display.get_display(), subwnd, 0, 0, w, h); -#endif - glViewport(0, 0, w, h); -} - -} // namespace Graphics -} // namespace Msp diff --git a/source/glcontext.h b/source/glcontext.h deleted file mode 100644 index 297bc34..0000000 --- a/source/glcontext.h +++ /dev/null @@ -1,59 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_GLCONTEXT_H_ -#define MSP_GBASE_GLCONTEXT_H_ - -#ifndef WIN32 -#include -#endif -#include "types.h" - -namespace Msp { -namespace Graphics { - -class Display; - -struct GLOptions -{ - bool alpha; - bool stencil; - bool doublebuffer; - unsigned multisample; - - GLOptions(); -}; - -class GLContext -{ -private: -#ifdef WIN32 - typedef HGLRC Context; -#else - typedef GLXContext Context; -#endif - - Display &display; - Window &window; - Context context; -#ifndef WIN32 - WindowHandle subwnd; -#endif - -public: - GLContext(Window &wnd, const GLOptions &opts=GLOptions()); - ~GLContext(); - - void swap_buffers(); -private: - void window_resized(unsigned, unsigned); -}; - -} // namespace Graphics -} // namespace Msp - -#endif diff --git a/source/input/binarycontrol.cpp b/source/input/binarycontrol.cpp new file mode 100644 index 0000000..9bf2408 --- /dev/null +++ b/source/input/binarycontrol.cpp @@ -0,0 +1,55 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include "binarycontrol.h" +#include "device.h" + +namespace Msp { +namespace Input { + +BinaryControl::BinaryControl(): + state(false) +{ } + +BinaryControl::BinaryControl(const ControlSource &s): + Control(s), + state(false) +{ } + +BinaryControl::BinaryControl(Device &d, ControlSrcType t, unsigned i): + Control(d, t, i), + state(false) +{ } + +void BinaryControl::on_press() +{ + if(!state) + { + state=true; + signal_press.emit(); + } +} + +void BinaryControl::on_release() +{ + if(state) + { + state=false; + signal_release.emit(); + } +} + +void BinaryControl::on_motion(float value, float) +{ + if(value>src.dev->get_axis_threshold()) + on_press(); + else + on_release(); +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/binarycontrol.h b/source/input/binarycontrol.h new file mode 100644 index 0000000..44aaef4 --- /dev/null +++ b/source/input/binarycontrol.h @@ -0,0 +1,45 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_BINARYCONTROL_H_ +#define MSP_GBASE_BINARYCONTROL_H_ + +#include "control.h" + +namespace Msp { +namespace Input { + +/** +A control with two possible states. Button state is mapped directly. An axis +is considered to be active when its value is above a threshold (defined by the +input device). +*/ +class BinaryControl: public Control +{ +public: + sigc::signal signal_press; + sigc::signal signal_release; + +private: + bool state; + +public: + BinaryControl(); + BinaryControl(const ControlSource &); + BinaryControl(Device &, ControlSrcType, unsigned); + bool get_state() const { return state; } + +private: + virtual void on_press(); + virtual void on_release(); + virtual void on_motion(float, float); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/input/control.cpp b/source/input/control.cpp new file mode 100644 index 0000000..8ddcdd7 --- /dev/null +++ b/source/input/control.cpp @@ -0,0 +1,161 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include +#include "control.h" +#include "device.h" + +namespace Msp { +namespace Input { + +ControlSource::ControlSource(): + dev(0), + type(NONE), + index(0) +{ } + +ControlSource::ControlSource(Device &d, ControlSrcType t, unsigned i): + dev(&d), + type(t), + index(i) +{ } + +std::string ControlSource::str() const +{ + if(type==BUTTON) + return dev->get_button_name(index); + else if(type==AXIS_POS || type==AXIS_NEG) + return dev->get_axis_name(index); + else if(type==NONE) + return "None"; + + return lexical_cast(index); +} + + +Control::Control(): + capture_dev(0) +{ } + +Control::Control(const ControlSource &s): + src(s), + capture_dev(0) +{ } + +Control::Control(Device &d, ControlSrcType t, unsigned i): + src(d, t, i), + capture_dev(0) +{ + connect_signals(); +} + +Control::Control(const Control &c): + trackable(c), + src(c.src), + capture_dev(0) +{ + connect_signals(); +} + +Control &Control::operator=(const Control &c) +{ + notify_callbacks(); + src=c.src; + capture_dev=0; + connect_signals(); + + return *this; +} + +void Control::capture(Device &d) +{ + notify_callbacks(); + capture_dev=&d; + capture_dev->signal_button_press.connect(sigc::mem_fun(this, &Control::button_press)); + capture_dev->signal_axis_motion.connect(sigc::mem_fun(this, &Control::axis_motion)); +} + +void Control::cancel_capture() +{ + notify_callbacks(); + capture_dev=0; + connect_signals(); +} + +void Control::connect_signals() +{ + switch(src.type) + { + case NONE: + break; + case BUTTON: + src.dev->signal_button_press.connect(sigc::mem_fun(this, &Control::button_press)); + src.dev->signal_button_release.connect(sigc::mem_fun(this, &Control::button_release)); + break; + case AXIS_POS: + case AXIS_NEG: + src.dev->signal_axis_motion.connect(sigc::mem_fun(this, &Control::axis_motion)); + break; + default: + throw Exception("Invalid source in Control"); + } +} + +void Control::button_press(unsigned i) +{ + if(capture_dev) + { + src.dev=capture_dev; + src.type=BUTTON; + src.index=i; + + notify_callbacks(); + capture_dev=0; + connect_signals(); + signal_capture_complete.emit(); + } + else if(src.type==BUTTON && i==src.index) + on_press(); +} + +void Control::button_release(unsigned i) +{ + if(src.type==BUTTON && i==src.index) + on_release(); +} + +void Control::axis_motion(unsigned i, float v, float r) +{ + if(capture_dev) + { + ControlSrcType type=NONE; + if(v<-src.dev->get_axis_threshold()) + type=AXIS_NEG; + else if(v>src.dev->get_axis_threshold()) + type=AXIS_POS; + + if(type!=NONE) + { + src.dev=capture_dev; + src.type=type; + src.index=i; + + notify_callbacks(); + capture_dev=0; + connect_signals(); + signal_capture_complete.emit(); + } + } + else if(src.type==AXIS_POS && i==src.index && v>=0) + on_motion(v, r); + else if(src.type==AXIS_NEG && i==src.index && v<=0) + on_motion(-v, -r); +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/control.h b/source/input/control.h new file mode 100644 index 0000000..f7146b4 --- /dev/null +++ b/source/input/control.h @@ -0,0 +1,86 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_CONTROL_H_ +#define MSP_GBASE_CONTROL_H_ + +#include +#include + +namespace Msp { +namespace Input { + +class Device; + +enum ControlSrcType +{ + NONE, + BUTTON, + AXIS_POS, + AXIS_NEG +}; + +/** +Specifies the source of a control. This provides a way for setting sources for +different types of controls in a uniform way. +*/ +struct ControlSource +{ + Device *dev; + ControlSrcType type; + unsigned index; + + ControlSource(); + ControlSource(Device &, ControlSrcType, unsigned); + std::string str() const; +}; + +/** +Provides further abstraction on top of input devices. There are two types of +controls currently defined: BinaryControl and SmoothControl. + +A control uses either a button or half of an axis (positive or negative) as its +source. How the source values are interpreted depends on the exact type of the +control. Controls also support interactive binding by capturing a button press +or axis motion. +*/ +class Control: public sigc::trackable +{ +public: + sigc::signal signal_capture_complete; + +protected: + ControlSource src; + Device *capture_dev; + + Control(); + Control(const ControlSource &); + Control(Device &, ControlSrcType, unsigned); + Control(const Control &); +public: + Control &operator=(const Control &); + virtual ~Control() { } + + void capture(Device &); + void cancel_capture(); + const ControlSource &get_source() const { return src; } +protected: + virtual void on_press() =0; + virtual void on_release() =0; + virtual void on_motion(float, float) =0; + +private: + void connect_signals(); + void button_press(unsigned); + void button_release(unsigned); + void axis_motion(unsigned, float, float); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/input/device.cpp b/source/input/device.cpp new file mode 100644 index 0000000..23393de --- /dev/null +++ b/source/input/device.cpp @@ -0,0 +1,75 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include "device.h" + +namespace Msp { +namespace Input { + +bool Device::get_button_state(unsigned btn) const +{ + if(btn>buttons.size()) + return false; + + return buttons[btn]; +} + +float Device::get_axis_value(unsigned axis) const +{ + if(axis>axes.size()) + return 0; + + return axes[axis]; +} + +std::string Device::get_button_name(unsigned btn) const +{ + return format("Button %d", btn); +} + +std::string Device::get_axis_name(unsigned axis) const +{ + return format("Axis %d", axis); +} + +void Device::set_button_state(unsigned btn, bool state, bool event) +{ + if(btn>=buttons.size()) + buttons.resize(btn+1, false); + + if(state!=buttons[btn]) + { + buttons[btn]=state; + + if(event) + { + if(state) + signal_button_press.emit(btn); + else + signal_button_release.emit(btn); + } + } +} + +void Device::set_axis_value(unsigned axis, float value, bool event) +{ + if(axis>=axes.size()) + axes.resize(axis+1, 0); + + if(value!=axes[axis]) + { + float old=axes[axis]; + axes[axis]=value; + + if(event) + signal_axis_motion.emit(axis, value, value-old); + } +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/device.h b/source/input/device.h new file mode 100644 index 0000000..d1c96f2 --- /dev/null +++ b/source/input/device.h @@ -0,0 +1,55 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_INPUTDEVICE_H_ +#define MSP_GBASE_INPUTDEVICE_H_ + +#include +#include +#include + +namespace Msp { +namespace Input { + +/** +Base class for input devices. Input devices have two types of controls: +buttons and axes. Buttons are either on or off. Axes have a floating-point +value, with range depending on the device. +*/ +class Device +{ +public: + sigc::signal signal_button_press; + sigc::signal signal_button_release; + sigc::signal signal_axis_motion; + +protected: + std::string name; + std::vector buttons; + std::vector axes; + float axis_threshold; + float axis_dead_zone; + + Device() { } +public: + virtual ~Device() { } + const std::string &get_name() const { return name; } + bool get_button_state(unsigned) const; + float get_axis_value(unsigned) const; + float get_axis_threshold() const { return axis_threshold; } + + virtual std::string get_button_name(unsigned) const; + virtual std::string get_axis_name(unsigned) const; +protected: + void set_button_state(unsigned, bool, bool); + void set_axis_value(unsigned, float, bool); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/input/hub.cpp b/source/input/hub.cpp new file mode 100644 index 0000000..51b9717 --- /dev/null +++ b/source/input/hub.cpp @@ -0,0 +1,56 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include +#include "hub.h" + +namespace Msp { +namespace Input { + +Hub::Hub() +{ + name="Hub"; +} + +unsigned Hub::attach(Device &dev) +{ + unsigned index=devices.size(); + devices.push_back(&dev); + dev.signal_button_press.connect(sigc::bind(sigc::mem_fun(this, &Hub::button_press), index)); + dev.signal_button_release.connect(sigc::bind(sigc::mem_fun(this, &Hub::button_release), index)); + dev.signal_axis_motion.connect(sigc::bind(sigc::mem_fun(this, &Hub::axis_motion), index)); + return index; +} + +std::string Hub::get_button_name(unsigned btn) const +{ + unsigned dev_index=btn>>12; + if(dev_index>devices.size()) + throw InvalidParameterValue("Button does not exist"); + + const Device &dev=*devices[dev_index]; + return dev.get_name()+": "+dev.get_button_name(btn&0xFFF); +} + +void Hub::button_press(unsigned btn, unsigned index) +{ + set_button_state(index<<12 | btn&0xFFF, true, true); +} + +void Hub::button_release(unsigned btn, unsigned index) +{ + set_button_state(index<<12 | btn&0xFFF, false, true); +} + +void Hub::axis_motion(unsigned axis, float value, float, unsigned index) +{ + set_axis_value(index<<12 | axis&0xFFF, value, true); +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/hub.h b/source/input/hub.h new file mode 100644 index 0000000..4385f27 --- /dev/null +++ b/source/input/hub.h @@ -0,0 +1,47 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_INPUTHUB_H_ +#define MSP_GBASE_INPUTHUB_H_ + +#include "device.h" + +namespace Msp { +namespace Input { + +/** +The Hub device collects events from multiple input devices and presents an +aggregate of them. Button and axis numbers are mapped to unique values. +*/ +class Hub: public Device +{ +protected: + std::vector devices; + +public: + Hub(); + + /** + Attaches an input device to the hub. + + @param dev Device to attach + + @return Index of the device within the hub + */ + unsigned attach(Device &dev); + + virtual std::string get_button_name(unsigned) const; +protected: + void button_press(unsigned, unsigned); + void button_release(unsigned, unsigned); + void axis_motion(unsigned, float, float, unsigned); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/input/keyboard.cpp b/source/input/keyboard.cpp new file mode 100644 index 0000000..240d700 --- /dev/null +++ b/source/input/keyboard.cpp @@ -0,0 +1,50 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include "../gbase/display.h" +#include "keyboard.h" + +namespace Msp { +namespace Input { + +Keyboard::Keyboard(Graphics::Window &w): + window(w) +{ + name="Keyboard"; + + buttons.resize(256, false); + + window.signal_key_press.connect(sigc::mem_fun(this, &Keyboard::key_press)); + window.signal_key_release.connect(sigc::mem_fun(this, &Keyboard::key_release)); +} + +std::string Keyboard::get_button_name(unsigned btn) const +{ +#ifndef WIN32 + KeySym ksym=XKeycodeToKeysym(window.get_display().get_display(), btn, 0); + return XKeysymToString(ksym); +#else + char buf[128]; + if(!GetKeyNameText(btn<<16, buf, sizeof(buf))) + return format("Key %d", btn); + return buf; +#endif +} + +void Keyboard::key_press(unsigned key, unsigned, unsigned) +{ + set_button_state(key, true, true); +} + +void Keyboard::key_release(unsigned key, unsigned) +{ + set_button_state(key, false, true); +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/keyboard.h b/source/input/keyboard.h new file mode 100644 index 0000000..54479ea --- /dev/null +++ b/source/input/keyboard.h @@ -0,0 +1,34 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_KEYBOARD_H_ +#define MSP_GBASE_KEYBOARD_H_ + +#include "device.h" +#include "../gbase/window.h" + +namespace Msp { +namespace Input { + +class Keyboard: public Device +{ +private: + Graphics::Window &window; + +public: + Keyboard(Graphics::Window &); + + virtual std::string get_button_name(unsigned) const; +private: + void key_press(unsigned, unsigned, unsigned); + void key_release(unsigned, unsigned); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/input/mouse.cpp b/source/input/mouse.cpp new file mode 100644 index 0000000..931b204 --- /dev/null +++ b/source/input/mouse.cpp @@ -0,0 +1,64 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include "mouse.h" + +namespace Msp { +namespace Input { + +Mouse::Mouse(Graphics::Window &w): + window(w), + axis_scale(0.01) +{ + name="Mouse"; + + buttons.resize(3); + axes.resize(2); + + window.signal_button_press.connect(sigc::mem_fun(this, &Mouse::button_press)); + window.signal_button_release.connect(sigc::mem_fun(this, &Mouse::button_release)); + window.signal_pointer_motion.connect(sigc::mem_fun(this, &Mouse::pointer_motion)); +} + +std::string Mouse::get_button_name(unsigned btn) const +{ + switch(btn) + { + case 1: + return "Left"; + case 2: + return "Middle"; + case 3: + return "Right"; + case 4: + return "Wheel Up"; + case 5: + return "Wheel Down"; + default: + return format("Button %d", btn); + } +} + +void Mouse::button_press(int, int, unsigned btn, unsigned) +{ + set_button_state(btn, true, true); +} + +void Mouse::button_release(int, int, unsigned btn, unsigned) +{ + set_button_state(btn, false, true); +} + +void Mouse::pointer_motion(int x, int y) +{ + set_axis_value(0, x*axis_scale, true); + set_axis_value(1, y*axis_scale, true); +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/mouse.h b/source/input/mouse.h new file mode 100644 index 0000000..8d5086f --- /dev/null +++ b/source/input/mouse.h @@ -0,0 +1,35 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_MOUSE_H_ +#define MSP_GBASE_MOUSE_H_ + +#include "device.h" +#include "../gbase/window.h" + +namespace Msp { +namespace Input { + +class Mouse: public Device +{ +private: + Graphics::Window &window; + float axis_scale; + +public: + Mouse(Graphics::Window &); + virtual std::string get_button_name(unsigned) const; +private: + void button_press(int, int, unsigned, unsigned); + void button_release(int, int, unsigned, unsigned); + void pointer_motion(int, int); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/input/smoothcontrol.cpp b/source/input/smoothcontrol.cpp new file mode 100644 index 0000000..69dfacf --- /dev/null +++ b/source/input/smoothcontrol.cpp @@ -0,0 +1,81 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include "smoothcontrol.h" + +namespace Msp { +namespace Input { + +SmoothControl::SmoothControl(): + value(0), + paired_ctrl(0) +{ } + +SmoothControl::SmoothControl(const ControlSource &s): + Control(s), + value(0), + paired_ctrl(0) +{ } + +SmoothControl::SmoothControl(Device &d, ControlSrcType t, unsigned i): + Control(d, t, i), + value(0), + paired_ctrl(0) +{ } + +SmoothControl &SmoothControl::operator=(const SmoothControl &sc) +{ + Control::operator=(sc); + + return *this; +} + +SmoothControl::~SmoothControl() +{ + pair(0); +} + +void SmoothControl::pair(SmoothControl *ctrl) +{ + if(ctrl==paired_ctrl) + return; + + if(paired_ctrl) + { + SmoothControl *old_pair=paired_ctrl; + paired_ctrl=0; + old_pair->pair(0); + } + + paired_ctrl=ctrl; + + if(paired_ctrl) + paired_ctrl->pair(this); +} + +void SmoothControl::on_press() +{ + on_motion(1, 1-value); +} + +void SmoothControl::on_release() +{ + if(value>0) + on_motion(0, -value); +} + +void SmoothControl::on_motion(float v, float) +{ + value=v; + signal_motion.emit(value); + + if(paired_ctrl && paired_ctrl->get_value()!=-value) + paired_ctrl->on_motion(-value, -value-paired_ctrl->get_value()); +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/smoothcontrol.h b/source/input/smoothcontrol.h new file mode 100644 index 0000000..26484a9 --- /dev/null +++ b/source/input/smoothcontrol.h @@ -0,0 +1,52 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_SMOOTHCONTROL_H_ +#define MSP_GBASE_SMOOTHCONTROL_H_ + +#include "control.h" + +namespace Msp { +namespace Input { + +/** +A control with a continuous range of values. A button is treated as either 1 +or 0. Axis values are mapped to absolute value. + +Two smooth controls can also be paired to each other. Motion on one control of +the pair will cause negative motion on the other. This works best when the +controls are bound to the opposite sides of the same joystick axis. +*/ +class SmoothControl: public Control +{ +public: + sigc::signal signal_motion; + +private: + float value; + SmoothControl *paired_ctrl; + +public: + SmoothControl(); + SmoothControl(const ControlSource &); + SmoothControl(Device &, ControlSrcType, unsigned); + SmoothControl &operator=(const SmoothControl &); + virtual ~SmoothControl(); + + void pair(SmoothControl *ctrl); + float get_value() const { return value; } + +private: + virtual void on_press(); + virtual void on_release(); + virtual void on_motion(float, float); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/inputdevice.cpp b/source/inputdevice.cpp deleted file mode 100644 index f3092e1..0000000 --- a/source/inputdevice.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include -#include "inputdevice.h" - -namespace Msp { -namespace Input { - -bool Device::get_button_state(unsigned btn) const -{ - if(btn>buttons.size()) - return false; - - return buttons[btn]; -} - -float Device::get_axis_value(unsigned axis) const -{ - if(axis>axes.size()) - return 0; - - return axes[axis]; -} - -std::string Device::get_button_name(unsigned btn) const -{ - return format("Button %d", btn); -} - -std::string Device::get_axis_name(unsigned axis) const -{ - return format("Axis %d", axis); -} - -void Device::set_button_state(unsigned btn, bool state, bool event) -{ - if(btn>=buttons.size()) - buttons.resize(btn+1, false); - - if(state!=buttons[btn]) - { - buttons[btn]=state; - - if(event) - { - if(state) - signal_button_press.emit(btn); - else - signal_button_release.emit(btn); - } - } -} - -void Device::set_axis_value(unsigned axis, float value, bool event) -{ - if(axis>=axes.size()) - axes.resize(axis+1, 0); - - if(value!=axes[axis]) - { - float old=axes[axis]; - axes[axis]=value; - - if(event) - signal_axis_motion.emit(axis, value, value-old); - } -} - -} // namespace Input -} // namespace Msp diff --git a/source/inputdevice.h b/source/inputdevice.h deleted file mode 100644 index d1c96f2..0000000 --- a/source/inputdevice.h +++ /dev/null @@ -1,55 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_INPUTDEVICE_H_ -#define MSP_GBASE_INPUTDEVICE_H_ - -#include -#include -#include - -namespace Msp { -namespace Input { - -/** -Base class for input devices. Input devices have two types of controls: -buttons and axes. Buttons are either on or off. Axes have a floating-point -value, with range depending on the device. -*/ -class Device -{ -public: - sigc::signal signal_button_press; - sigc::signal signal_button_release; - sigc::signal signal_axis_motion; - -protected: - std::string name; - std::vector buttons; - std::vector axes; - float axis_threshold; - float axis_dead_zone; - - Device() { } -public: - virtual ~Device() { } - const std::string &get_name() const { return name; } - bool get_button_state(unsigned) const; - float get_axis_value(unsigned) const; - float get_axis_threshold() const { return axis_threshold; } - - virtual std::string get_button_name(unsigned) const; - virtual std::string get_axis_name(unsigned) const; -protected: - void set_button_state(unsigned, bool, bool); - void set_axis_value(unsigned, float, bool); -}; - -} // namespace Input -} // namespace Msp - -#endif diff --git a/source/inputhub.cpp b/source/inputhub.cpp deleted file mode 100644 index 1fa95d0..0000000 --- a/source/inputhub.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include -#include -#include "inputhub.h" - -namespace Msp { -namespace Input { - -Hub::Hub() -{ - name="Hub"; -} - -unsigned Hub::attach(Device &dev) -{ - unsigned index=devices.size(); - devices.push_back(&dev); - dev.signal_button_press.connect(sigc::bind(sigc::mem_fun(this, &Hub::button_press), index)); - dev.signal_button_release.connect(sigc::bind(sigc::mem_fun(this, &Hub::button_release), index)); - dev.signal_axis_motion.connect(sigc::bind(sigc::mem_fun(this, &Hub::axis_motion), index)); - return index; -} - -std::string Hub::get_button_name(unsigned btn) const -{ - unsigned dev_index=btn>>12; - if(dev_index>devices.size()) - throw InvalidParameterValue("Button does not exist"); - - const Device &dev=*devices[dev_index]; - return dev.get_name()+": "+dev.get_button_name(btn&0xFFF); -} - -void Hub::button_press(unsigned btn, unsigned index) -{ - set_button_state(index<<12 | btn&0xFFF, true, true); -} - -void Hub::button_release(unsigned btn, unsigned index) -{ - set_button_state(index<<12 | btn&0xFFF, false, true); -} - -void Hub::axis_motion(unsigned axis, float value, float, unsigned index) -{ - set_axis_value(index<<12 | axis&0xFFF, value, true); -} - -} // namespace Input -} // namespace Msp diff --git a/source/inputhub.h b/source/inputhub.h deleted file mode 100644 index c66ae98..0000000 --- a/source/inputhub.h +++ /dev/null @@ -1,47 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_INPUTHUB_H_ -#define MSP_GBASE_INPUTHUB_H_ - -#include "inputdevice.h" - -namespace Msp { -namespace Input { - -/** -The Hub device collects events from multiple input devices and presents an -aggregate of them. Button and axis numbers are mapped to unique values. -*/ -class Hub: public Device -{ -protected: - std::vector devices; - -public: - Hub(); - - /** - Attaches an input device to the hub. - - @param dev Device to attach - - @return Index of the device within the hub - */ - unsigned attach(Device &dev); - - virtual std::string get_button_name(unsigned) const; -protected: - void button_press(unsigned, unsigned); - void button_release(unsigned, unsigned); - void axis_motion(unsigned, float, float, unsigned); -}; - -} // namespace Input -} // namespace Msp - -#endif diff --git a/source/keyboard.cpp b/source/keyboard.cpp deleted file mode 100644 index 2e3c92d..0000000 --- a/source/keyboard.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include -#include "display.h" -#include "keyboard.h" - -namespace Msp { -namespace Input { - -Keyboard::Keyboard(Graphics::Window &w): - window(w) -{ - name="Keyboard"; - - buttons.resize(256, false); - - window.signal_key_press.connect(sigc::mem_fun(this, &Keyboard::key_press)); - window.signal_key_release.connect(sigc::mem_fun(this, &Keyboard::key_release)); -} - -std::string Keyboard::get_button_name(unsigned btn) const -{ -#ifndef WIN32 - KeySym ksym=XKeycodeToKeysym(window.get_display().get_display(), btn, 0); - return XKeysymToString(ksym); -#else - char buf[128]; - if(!GetKeyNameText(btn<<16, buf, sizeof(buf))) - return format("Key %d", btn); - return buf; -#endif -} - -void Keyboard::key_press(unsigned key, unsigned, unsigned) -{ - set_button_state(key, true, true); -} - -void Keyboard::key_release(unsigned key, unsigned) -{ - set_button_state(key, false, true); -} - -} // namespace Input -} // namespace Msp diff --git a/source/keyboard.h b/source/keyboard.h deleted file mode 100644 index 3e0efa2..0000000 --- a/source/keyboard.h +++ /dev/null @@ -1,34 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_KEYBOARD_H_ -#define MSP_GBASE_KEYBOARD_H_ - -#include "inputdevice.h" -#include "window.h" - -namespace Msp { -namespace Input { - -class Keyboard: public Device -{ -private: - Graphics::Window &window; - -public: - Keyboard(Graphics::Window &); - - virtual std::string get_button_name(unsigned) const; -private: - void key_press(unsigned, unsigned, unsigned); - void key_release(unsigned, unsigned); -}; - -} // namespace Input -} // namespace Msp - -#endif diff --git a/source/mouse.cpp b/source/mouse.cpp deleted file mode 100644 index 931b204..0000000 --- a/source/mouse.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include -#include "mouse.h" - -namespace Msp { -namespace Input { - -Mouse::Mouse(Graphics::Window &w): - window(w), - axis_scale(0.01) -{ - name="Mouse"; - - buttons.resize(3); - axes.resize(2); - - window.signal_button_press.connect(sigc::mem_fun(this, &Mouse::button_press)); - window.signal_button_release.connect(sigc::mem_fun(this, &Mouse::button_release)); - window.signal_pointer_motion.connect(sigc::mem_fun(this, &Mouse::pointer_motion)); -} - -std::string Mouse::get_button_name(unsigned btn) const -{ - switch(btn) - { - case 1: - return "Left"; - case 2: - return "Middle"; - case 3: - return "Right"; - case 4: - return "Wheel Up"; - case 5: - return "Wheel Down"; - default: - return format("Button %d", btn); - } -} - -void Mouse::button_press(int, int, unsigned btn, unsigned) -{ - set_button_state(btn, true, true); -} - -void Mouse::button_release(int, int, unsigned btn, unsigned) -{ - set_button_state(btn, false, true); -} - -void Mouse::pointer_motion(int x, int y) -{ - set_axis_value(0, x*axis_scale, true); - set_axis_value(1, y*axis_scale, true); -} - -} // namespace Input -} // namespace Msp diff --git a/source/mouse.h b/source/mouse.h deleted file mode 100644 index ccc2e8e..0000000 --- a/source/mouse.h +++ /dev/null @@ -1,35 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_MOUSE_H_ -#define MSP_GBASE_MOUSE_H_ - -#include "inputdevice.h" -#include "window.h" - -namespace Msp { -namespace Input { - -class Mouse: public Device -{ -private: - Graphics::Window &window; - float axis_scale; - -public: - Mouse(Graphics::Window &); - virtual std::string get_button_name(unsigned) const; -private: - void button_press(int, int, unsigned, unsigned); - void button_release(int, int, unsigned, unsigned); - void pointer_motion(int, int); -}; - -} // namespace Input -} // namespace Msp - -#endif diff --git a/source/smoothcontrol.cpp b/source/smoothcontrol.cpp deleted file mode 100644 index 69dfacf..0000000 --- a/source/smoothcontrol.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include "smoothcontrol.h" - -namespace Msp { -namespace Input { - -SmoothControl::SmoothControl(): - value(0), - paired_ctrl(0) -{ } - -SmoothControl::SmoothControl(const ControlSource &s): - Control(s), - value(0), - paired_ctrl(0) -{ } - -SmoothControl::SmoothControl(Device &d, ControlSrcType t, unsigned i): - Control(d, t, i), - value(0), - paired_ctrl(0) -{ } - -SmoothControl &SmoothControl::operator=(const SmoothControl &sc) -{ - Control::operator=(sc); - - return *this; -} - -SmoothControl::~SmoothControl() -{ - pair(0); -} - -void SmoothControl::pair(SmoothControl *ctrl) -{ - if(ctrl==paired_ctrl) - return; - - if(paired_ctrl) - { - SmoothControl *old_pair=paired_ctrl; - paired_ctrl=0; - old_pair->pair(0); - } - - paired_ctrl=ctrl; - - if(paired_ctrl) - paired_ctrl->pair(this); -} - -void SmoothControl::on_press() -{ - on_motion(1, 1-value); -} - -void SmoothControl::on_release() -{ - if(value>0) - on_motion(0, -value); -} - -void SmoothControl::on_motion(float v, float) -{ - value=v; - signal_motion.emit(value); - - if(paired_ctrl && paired_ctrl->get_value()!=-value) - paired_ctrl->on_motion(-value, -value-paired_ctrl->get_value()); -} - -} // namespace Input -} // namespace Msp diff --git a/source/smoothcontrol.h b/source/smoothcontrol.h deleted file mode 100644 index 26484a9..0000000 --- a/source/smoothcontrol.h +++ /dev/null @@ -1,52 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_SMOOTHCONTROL_H_ -#define MSP_GBASE_SMOOTHCONTROL_H_ - -#include "control.h" - -namespace Msp { -namespace Input { - -/** -A control with a continuous range of values. A button is treated as either 1 -or 0. Axis values are mapped to absolute value. - -Two smooth controls can also be paired to each other. Motion on one control of -the pair will cause negative motion on the other. This works best when the -controls are bound to the opposite sides of the same joystick axis. -*/ -class SmoothControl: public Control -{ -public: - sigc::signal signal_motion; - -private: - float value; - SmoothControl *paired_ctrl; - -public: - SmoothControl(); - SmoothControl(const ControlSource &); - SmoothControl(Device &, ControlSrcType, unsigned); - SmoothControl &operator=(const SmoothControl &); - virtual ~SmoothControl(); - - void pair(SmoothControl *ctrl); - float get_value() const { return value; } - -private: - virtual void on_press(); - virtual void on_release(); - virtual void on_motion(float, float); -}; - -} // namespace Input -} // namespace Msp - -#endif diff --git a/source/types.h b/source/types.h deleted file mode 100644 index e3524f3..0000000 --- a/source/types.h +++ /dev/null @@ -1,29 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_TYPES_H_ -#define MSP_GBASE_TYPES_H_ - -#ifdef WIN32 -#include -#else -#include -#endif - -namespace Msp { -namespace Graphics { - -#ifdef WIN32 -typedef HWND WindowHandle; -#else -typedef ::Window WindowHandle; -#endif - -} // namespace Graphics -} // namespace Msp - -#endif diff --git a/source/window.cpp b/source/window.cpp deleted file mode 100644 index da877e9..0000000 --- a/source/window.cpp +++ /dev/null @@ -1,322 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include -#ifndef WIN32 -#include -#include -#else -#include -#endif -#include -#include -#include "display.h" -#include "window.h" - -using namespace std; - -#include - -namespace Msp { -namespace Graphics { - -WindowOptions::WindowOptions(): - width(640), - height(480), - fullscreen(false), - resizable(false) -{ } - - -Window::Window(Display &dpy, unsigned w, unsigned h, bool fs): - display(dpy) -{ - options.width=w; - options.height=h; - options.fullscreen=fs; - - init(); -} - -Window::Window(Display &dpy, const WindowOptions &opts): - display(dpy), - options(opts) -{ - init(); -} - -Window::~Window() -{ - if(window) -#ifdef WIN32 - CloseWindow(window); -#else - XDestroyWindow(display.get_display(), window); -#endif - - display.remove_window(this); - - if(options.fullscreen) - display.restore_mode(); -} - -void Window::set_title(const string &title) -{ -#ifdef WIN32 - SetWindowText(window, title.c_str()); -#else - vector buf(title.begin(), title.end()); - XTextProperty prop; - prop.value=&buf[0]; - prop.encoding=XA_STRING; - prop.format=8; - prop.nitems=title.size(); - XSetWMName(display.get_display(), window, &prop); - display.check_error(); -#endif -} - -void Window::reconfigure(const WindowOptions &opts) -{ - bool fullscreen_changed=(opts.fullscreen!=options.fullscreen); - - options=opts; - -#ifdef WIN32 - // XXX Preserve position - MoveWindow(window, 0, 0, options.width, options.height, false); - - (void)fullscreen_changed; -#else - ::Display *dpy=display.get_display(); - - XMoveResizeWindow(dpy, window, 0, 0, options.width, options.height); - - if(fullscreen_changed) - { - hide(); - XSetWindowAttributes attr; - attr.override_redirect=options.fullscreen; - XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &attr); - show(); - } - - if(options.fullscreen) - display.set_mode(VideoMode(options.width, options.height)); - else if(fullscreen_changed) - display.restore_mode(); -#endif -} - -void Window::show() -{ -#ifdef WIN32 - ShowWindow(window, SW_SHOWNORMAL); -#else - XMapRaised(display.get_display(), window); - display.check_error(); -#endif -} - -void Window::hide() -{ -#ifdef WIN32 - ShowWindow(window, SW_HIDE); -#else - XUnmapWindow(display.get_display(), window); - display.check_error(); -#endif -} - -void Window::init() -{ -#ifdef WIN32 - static bool wndclass_created=false; - - if(!wndclass_created) - { - WNDCLASSEX wndcl; - - wndcl.cbSize=sizeof(WNDCLASSEX); - wndcl.style=0; - wndcl.lpfnWndProc=&wndproc_; - wndcl.cbClsExtra=0; - wndcl.cbWndExtra=sizeof(Window *); - wndcl.hInstance=reinterpret_cast(Application::get_data()); - wndcl.hIcon=0; - wndcl.hCursor=LoadCursor(0, IDC_ARROW); - wndcl.hbrBackground=0; - wndcl.lpszMenuName=0; - wndcl.lpszClassName="mspgbase"; - wndcl.hIconSm=0; - - if(!RegisterClassEx(&wndcl)) - throw Exception("Couldn't register window class"); - - wndclass_created=true; - } - - RECT rect; - rect.left=0; - rect.top=0; - rect.right=options.width; - rect.bottom=options.height; - AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW); - - window=CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, - "mspgbase", - "Window", - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, - rect.right-rect.left, rect.bottom-rect.top, - 0, - 0, - reinterpret_cast(Application::get_data()), - this); - if(!window) - throw Exception("CreateWindowEx failed"); - -#else - ::Display *dpy=display.get_display(); - - wm_delete_window=XInternAtom(dpy, "WM_DELETE_WINDOW", true); - - XSetWindowAttributes attr; - attr.override_redirect=options.fullscreen; - attr.event_mask=ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask; - - window=XCreateWindow(dpy, - DefaultRootWindow(dpy), - 0, 0, - options.width, options.height, - 0, - CopyFromParent, - InputOutput, - CopyFromParent, - CWOverrideRedirect|CWEventMask, &attr); - - XSetWMProtocols(dpy, window, &wm_delete_window, 1); - - if(options.fullscreen) - { - display.set_mode(VideoMode(options.width, options.height)); - XWarpPointer(dpy, None, window, 0, 0, 0, 0, options.width/2, options.height/2); - } -#endif - - display.add_window(this); - display.check_error(); -} - -#ifndef WIN32 -void Window::event(const XEvent &ev) -{ - switch(ev.type) - { - case ButtonPress: - signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state); - break; - case ButtonRelease: - signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state); - break; - case MotionNotify: - signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y); - break; - case KeyPress: - { - char buf[16]; - XLookupString(const_cast(&ev.xkey), buf, sizeof(buf), 0, 0); - // XXX Handle the result according to locale - signal_key_press.emit(ev.xkey.keycode, ev.xkey.state, buf[0]); - } - break; - case KeyRelease: - signal_key_release.emit(ev.xkey.keycode, ev.xkey.state); - break; - case ConfigureNotify: - options.width=ev.xconfigure.width; - options.height=ev.xconfigure.height; - signal_resize.emit(options.width, options.height); - break; - case ClientMessage: - if(ev.xclient.data.l[0]==static_cast(wm_delete_window)) - signal_close.emit(); - break; - case EnterNotify: - XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime); - break; - case MapNotify: - if(options.fullscreen) - XGrabPointer(display.get_display(), window, true, None, GrabModeAsync, GrabModeAsync, window, None, CurrentTime); - break; - default:; - } -} -#endif - -#ifdef WIN32 -int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp) -{ - switch(msg) - { - case WM_KEYDOWN: - signal_key_press.emit((lp>>16)&0x1FF, 0, wp); - break; - case WM_KEYUP: - signal_key_release.emit((lp>>16)&0x1FF, 0); - break; - case WM_LBUTTONDOWN: - signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0); - break; - case WM_LBUTTONUP: - signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0); - break; - case WM_MBUTTONDOWN: - signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0); - break; - case WM_MBUTTONUP: - signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0); - break; - case WM_RBUTTONDOWN: - signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); - break; - case WM_RBUTTONUP: - signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); - break; - case WM_MOUSEMOVE: - signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp)); - break; - case WM_CLOSE: - signal_close.emit(); - break; - default: - return 0; - } - - return 1; -} - -LRESULT CALLBACK Window::wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - if(msg==WM_CREATE) - { - CREATESTRUCT *cs=reinterpret_cast(lparam); - SetWindowLong(hwnd, 0, reinterpret_cast(cs->lpCreateParams)); - } - else - { - Window *wnd=reinterpret_cast(GetWindowLong(hwnd, 0)); - if(wnd && wnd->wndproc(msg, wparam, lparam)) - return 0; - } - - return DefWindowProc(hwnd, msg, wparam, lparam); -} -#endif - -} // namespace Graphics -} // namespace Msp diff --git a/source/window.h b/source/window.h deleted file mode 100644 index e85f86a..0000000 --- a/source/window.h +++ /dev/null @@ -1,80 +0,0 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#ifndef MSP_GBASE_WINDOW_H_ -#define MSP_GBASE_WINDOW_H_ - -#include -#include -#include "types.h" - -namespace Msp { -namespace Graphics { - -class Display; - -struct WindowOptions -{ - unsigned width; - unsigned height; - bool fullscreen; - bool resizable; - - WindowOptions(); -}; - -class Window -{ -public: - sigc::signal signal_button_press; - sigc::signal signal_button_release; - sigc::signal signal_pointer_motion; - sigc::signal signal_key_press; - sigc::signal signal_key_release; - sigc::signal signal_resize; - sigc::signal signal_close; - -protected: - Display &display; - WindowOptions options; - WindowHandle window; -#ifndef WIN32 - Atom wm_delete_window; -#endif - -public: - Window(Display &, unsigned w, unsigned h, bool fs=false); - Window(Display &, const WindowOptions &); - ~Window(); - - void set_title(const std::string &); - void reconfigure(const WindowOptions &); - - Display &get_display() const { return display; } - const WindowOptions &get_options() const { return options; } - unsigned get_width() const { return options.width; } - unsigned get_height() const { return options.height; } - WindowHandle get_handle() const { return window; } - - void show(); - void hide(); - -#ifndef WIN32 - void event(const XEvent &ev); -#endif -protected: - void init(); -#ifdef WIN32 - int wndproc(UINT, WPARAM, LPARAM); - static LRESULT CALLBACK wndproc_(HWND, UINT, WPARAM, LPARAM); -#endif -}; - -} // namespace Graphics -} // namespace Msp - -#endif