1
0
Fork 0

Steps to make PUI optional, HiDPI tolerant.

Move all PUI event and rendering into a custom camera, which can be
rendered via an FBO to account for display-resolution scaling (HiDPI).

Start wrapping PUI calls in #ifdefs so PUI can be disabled at compile
time; a run-time switch is trivial now but not implemented yet.
This commit is contained in:
James Turner 2017-10-05 23:06:26 +01:00
parent 9d590feaf3
commit 804dc4e74a
16 changed files with 537 additions and 237 deletions

View file

@ -35,7 +35,7 @@ CanvasWidget::CanvasWidget( int x, int y,
SGPropertyNode* props,
const std::string& module ):
puObject(x, y, width, height),
_canvas_mgr( dynamic_cast<CanvasMgr*>(globals->get_subsystem("Canvas")) ),
_canvas_mgr(globals->get_subsystem<CanvasMgr>()),
_last_x(0),
_last_y(0),
// automatically resize viewport of canvas if no size is given
@ -197,13 +197,17 @@ void CanvasWidget::setSize(int w, int h)
void CanvasWidget::draw(int dx, int dy)
{
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ONE);
glBindTexture(GL_TEXTURE_2D, _canvas_mgr->getCanvasTexId(_canvas));
glBegin( GL_QUADS );
glColor3f(1,1,1);
glColor4f(1,1,1, 1.0f);
glTexCoord2f(0,0); glVertex2f(dx + abox.min[0], dy + abox.min[1]);
glTexCoord2f(1,0); glVertex2f(dx + abox.max[0], dy + abox.min[1]);
glTexCoord2f(1,1); glVertex2f(dx + abox.max[0], dy + abox.max[1]);
glTexCoord2f(0,1); glVertex2f(dx + abox.min[0], dy + abox.max[1]);
glEnd();
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}

View file

@ -988,7 +988,7 @@ void MapWidget::drawLatLonGrid()
int ix = 0;
int iy = 0;
glColor4f(0.8, 0.8, 0.8, 0.4);
glColor4f(0.8, 0.8, 0.8, 1.0);
glBegin(GL_LINES);
bool didDraw;
do {

View file

@ -49,6 +49,7 @@
#include <Viewer/CameraGroup.hxx>
#include <GUI/new_gui.hxx>
#include <GUI/FGFontCache.hxx>
#include <Viewer/PUICamera.hxx>
#include "gui.h"
#include "layout.hxx"
@ -74,8 +75,8 @@ public:
}
void run(osg::GraphicsContext* gc)
{
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
wsa->puInitialize();
flightgear::PUICamera::initPUI();
puSetDefaultStyle ( PUSTYLE_SMALL_SHADED ); //PUSTYLE_DEFAULT
puSetDefaultColourScheme (0.8, 0.8, 0.9, 1);

View file

@ -54,3 +54,5 @@
#cmakedefine HAVE_QT
#define FG_BUILD_TYPE "@FG_BUILD_TYPE@"
#define HAVE_PUI

View file

@ -29,7 +29,6 @@
#include "FGKeyboardInput.hxx"
#include <Main/fg_props.hxx>
#include <Scripting/NasalSys.hxx>
#include <plib/pu.h>
using simgear::PropertyList;
@ -248,10 +247,6 @@ void FGKeyboardInput::doKey (int k, int modifiers, int x, int y)
void FGKeyboardInput::keyHandler(int key, int keymod, int mousex, int mousey)
{
if((keymod & KEYMOD_RELEASED) == 0)
if(puKeyboard(key, PU_DOWN))
return;
if(keyboardInput)
keyboardInput->doKey(key, keymod, mousex, mousey);
if( keyboardInput)
keyboardInput->doKey(key, keymod, mousex, mousey);
}

View file

@ -38,7 +38,6 @@
#include "FGButton.hxx"
#include "Main/globals.hxx"
#include <Viewer/renderer.hxx>
#include <plib/pu.h>
#include <Model/panelnode.hxx>
#include <Cockpit/panel.hxx>
#include <Viewer/FGEventHandler.hxx>
@ -598,11 +597,7 @@ void FGMouseInput::doMouseClick (int b, int updown, int x, int y, bool mainWindo
}
if (mode.pass_through) {
// remove once PUI uses standard picking mechanism
if (0 <= x && 0 <= y && puMouse(b, updown, x, y))
return; // pui handled it
// pui didn't want the click event so compute a
// compute a
// scenegraph intersection point corresponding to the mouse click
if (updown == MOUSE_BUTTON_DOWN) {
d->activePickCallbacks.init( b, ea );
@ -619,7 +614,6 @@ void FGMouseInput::doMouseClick (int b, int updown, int x, int y, bool mainWindo
} // mouse button was released
} // of pass-through mode
// OK, PUI and the panel didn't want the click
if (b >= MAX_MOUSE_BUTTONS) {
SG_LOG(SG_INPUT, SG_ALERT, "Mouse button " << b
<< " where only " << MAX_MOUSE_BUTTONS << " expected");
@ -655,13 +649,7 @@ void FGMouseInput::processMotion(int x, int y, const osgGA::GUIEventAdapter* ea)
}
mouse_mode &mode = m.modes[modeIndex];
// Pass on to PUI if requested, and return
// if PUI consumed the event.
if (mode.pass_through && puMouse(x, y)) {
return;
}
if (d->haveWarped)
{
// don't fire mouse-movement events at the first update after warping the mouse,

View file

@ -32,5 +32,10 @@ if (Qt5Core_FOUND)
list(APPEND SOURCES GraphicsWindowQt5.cpp)
endif()
if (YES)
list(APPEND HEADERS PUICamera.hxx)
list(APPEND SOURCES PUICamera.cxx)
endif()
flightgear_component(Viewer "${SOURCES}" "${HEADERS}")

View file

@ -28,8 +28,7 @@ namespace flightgear
{
const int displayStatsKey = 1;
const int printStatsKey = 2;
// The manipulator is responsible for updating a Viewer's camera. Its
// event handling method is also a convenient place to run the FG idle
// and draw handlers.
@ -53,49 +52,6 @@ FGEventHandler::FGEventHandler() :
statsHandler->setKeyEventPrintsOutStats(printStatsKey);
statsEvent->setEventType(GUIEventAdapter::KEYDOWN);
// OSG reports NumPad keycodes independent of the NumLock modifier.
// Both KP-4 and KP-Left are reported as KEY_KP_Left (0xff96), so we
// have to generate the locked keys ourselves.
numlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = '0';
numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
numlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = '.';
// The comment above is incorrect on Mac osgViewer, at least. So we
// need to map the 'num-locked' key codes to real values.
numlockKeyMap[GUIEventAdapter::KEY_KP_0] = '0';
numlockKeyMap[GUIEventAdapter::KEY_KP_1] = '1';
numlockKeyMap[GUIEventAdapter::KEY_KP_2] = '2';
numlockKeyMap[GUIEventAdapter::KEY_KP_3] = '3';
numlockKeyMap[GUIEventAdapter::KEY_KP_4] = '4';
numlockKeyMap[GUIEventAdapter::KEY_KP_5] = '5';
numlockKeyMap[GUIEventAdapter::KEY_KP_6] = '6';
numlockKeyMap[GUIEventAdapter::KEY_KP_7] = '7';
numlockKeyMap[GUIEventAdapter::KEY_KP_8] = '8';
numlockKeyMap[GUIEventAdapter::KEY_KP_9] = '9';
numlockKeyMap[GUIEventAdapter::KEY_KP_Decimal] = '.';
// mapping when NumLock is off
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = PU_KEY_INSERT;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_End] = PU_KEY_END;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Down] = PU_KEY_DOWN;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = PU_KEY_PAGE_DOWN;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Left] = PU_KEY_LEFT;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Right] = PU_KEY_RIGHT;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Home] = PU_KEY_HOME;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Up] = PU_KEY_UP;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = PU_KEY_PAGE_UP;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = 127;
for (int i = 0; i < 128; i++)
release_keys[i] = i;
@ -110,33 +66,6 @@ void FGEventHandler::reset()
statsHandler->reset();
}
namespace
{
// Translate OSG modifier mask to FG modifier mask.
int osgToFGModifiers(int modifiers)
{
int result = 0;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
result |= KEYMOD_SHIFT;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL)
result |= KEYMOD_CTRL;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT)
result |= KEYMOD_ALT;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_META)
result |= KEYMOD_META;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_SUPER)
result |= KEYMOD_SUPER;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_HYPER)
result |= KEYMOD_HYPER;
return result;
}
}
#if 0
void FGEventHandler::init(const osgGA::GUIEventAdapter& ea,
osgGA::GUIActionAdapter& us)
@ -312,75 +241,151 @@ bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
return false;
}
}
void FGEventHandler::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
int& modifiers)
int FGEventHandler::translateKey(const osgGA::GUIEventAdapter& ea)
{
using namespace osgGA;
key = ea.getKey();
static std::map<int, int> numlockKeyMap;
static std::map<int, int> noNumlockKeyMap;
if (numlockKeyMap.empty()) {
// init these first time around
// OSG reports NumPad keycodes independent of the NumLock modifier.
// Both KP-4 and KP-Left are reported as KEY_KP_Left (0xff96), so we
// have to generate the locked keys ourselves.
numlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = '0';
numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
numlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = '.';
// The comment above is incorrect on Mac osgViewer, at least. So we
// need to map the 'num-locked' key codes to real values.
numlockKeyMap[GUIEventAdapter::KEY_KP_0] = '0';
numlockKeyMap[GUIEventAdapter::KEY_KP_1] = '1';
numlockKeyMap[GUIEventAdapter::KEY_KP_2] = '2';
numlockKeyMap[GUIEventAdapter::KEY_KP_3] = '3';
numlockKeyMap[GUIEventAdapter::KEY_KP_4] = '4';
numlockKeyMap[GUIEventAdapter::KEY_KP_5] = '5';
numlockKeyMap[GUIEventAdapter::KEY_KP_6] = '6';
numlockKeyMap[GUIEventAdapter::KEY_KP_7] = '7';
numlockKeyMap[GUIEventAdapter::KEY_KP_8] = '8';
numlockKeyMap[GUIEventAdapter::KEY_KP_9] = '9';
numlockKeyMap[GUIEventAdapter::KEY_KP_Decimal] = '.';
// mapping when NumLock is off
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = PU_KEY_INSERT;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_End] = PU_KEY_END;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Down] = PU_KEY_DOWN;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = PU_KEY_PAGE_DOWN;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Left] = PU_KEY_LEFT;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Right] = PU_KEY_RIGHT;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Home] = PU_KEY_HOME;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Up] = PU_KEY_UP;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = PU_KEY_PAGE_UP;
noNumlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = 127;
}
int key = ea.getKey();
// XXX Probably other translations are needed too.
switch (key) {
case GUIEventAdapter::KEY_Escape: key = 0x1b; break;
case GUIEventAdapter::KEY_Return: key = '\n'; break;
case GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
case GUIEventAdapter::KEY_Delete: key = 0x7f; break;
case GUIEventAdapter::KEY_Tab: key = '\t'; break;
case GUIEventAdapter::KEY_Left: key = PU_KEY_LEFT; break;
case GUIEventAdapter::KEY_Up: key = PU_KEY_UP; break;
case GUIEventAdapter::KEY_Right: key = PU_KEY_RIGHT; break;
case GUIEventAdapter::KEY_Down: key = PU_KEY_DOWN; break;
case GUIEventAdapter::KEY_Page_Up: key = PU_KEY_PAGE_UP; break;
case GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
case GUIEventAdapter::KEY_Home: key = PU_KEY_HOME; break;
case GUIEventAdapter::KEY_End: key = PU_KEY_END; break;
case GUIEventAdapter::KEY_Insert: key = PU_KEY_INSERT; break;
case GUIEventAdapter::KEY_F1: key = PU_KEY_F1; break;
case GUIEventAdapter::KEY_F2: key = PU_KEY_F2; break;
case GUIEventAdapter::KEY_F3: key = PU_KEY_F3; break;
case GUIEventAdapter::KEY_F4: key = PU_KEY_F4; break;
case GUIEventAdapter::KEY_F5: key = PU_KEY_F5; break;
case GUIEventAdapter::KEY_F6: key = PU_KEY_F6; break;
case GUIEventAdapter::KEY_F7: key = PU_KEY_F7; break;
case GUIEventAdapter::KEY_F8: key = PU_KEY_F8; break;
case GUIEventAdapter::KEY_F9: key = PU_KEY_F9; break;
case GUIEventAdapter::KEY_F10: key = PU_KEY_F10; break;
case GUIEventAdapter::KEY_F11: key = PU_KEY_F11; break;
case GUIEventAdapter::KEY_F12: key = PU_KEY_F12; break;
case GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
case GUIEventAdapter::KEY_KP_Add: key = '+'; break;
case GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
case GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
case GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
case GUIEventAdapter::KEY_Escape: key = 0x1b; break;
case GUIEventAdapter::KEY_Return: key = '\n'; break;
case GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
case GUIEventAdapter::KEY_Delete: key = 0x7f; break;
case GUIEventAdapter::KEY_Tab: key = '\t'; break;
case GUIEventAdapter::KEY_Left: key = PU_KEY_LEFT; break;
case GUIEventAdapter::KEY_Up: key = PU_KEY_UP; break;
case GUIEventAdapter::KEY_Right: key = PU_KEY_RIGHT; break;
case GUIEventAdapter::KEY_Down: key = PU_KEY_DOWN; break;
case GUIEventAdapter::KEY_Page_Up: key = PU_KEY_PAGE_UP; break;
case GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
case GUIEventAdapter::KEY_Home: key = PU_KEY_HOME; break;
case GUIEventAdapter::KEY_End: key = PU_KEY_END; break;
case GUIEventAdapter::KEY_Insert: key = PU_KEY_INSERT; break;
case GUIEventAdapter::KEY_F1: key = PU_KEY_F1; break;
case GUIEventAdapter::KEY_F2: key = PU_KEY_F2; break;
case GUIEventAdapter::KEY_F3: key = PU_KEY_F3; break;
case GUIEventAdapter::KEY_F4: key = PU_KEY_F4; break;
case GUIEventAdapter::KEY_F5: key = PU_KEY_F5; break;
case GUIEventAdapter::KEY_F6: key = PU_KEY_F6; break;
case GUIEventAdapter::KEY_F7: key = PU_KEY_F7; break;
case GUIEventAdapter::KEY_F8: key = PU_KEY_F8; break;
case GUIEventAdapter::KEY_F9: key = PU_KEY_F9; break;
case GUIEventAdapter::KEY_F10: key = PU_KEY_F10; break;
case GUIEventAdapter::KEY_F11: key = PU_KEY_F11; break;
case GUIEventAdapter::KEY_F12: key = PU_KEY_F12; break;
case GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
case GUIEventAdapter::KEY_KP_Add: key = '+'; break;
case GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
case GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
case GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
}
osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
#ifdef __APPLE__
// Num Lock is always true on Mac
std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
auto numPadIter = numlockKeyMap.find(key);
if (numPadIter != numlockKeyMap.end()) {
key = numPadIter->second;
}
#else
if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK)
{
if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) {
// NumLock on: map to numeric keys
std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
auto numPadIter = numlockKeyMap.find(key);
if (numPadIter != numlockKeyMap.end()) {
key = numPadIter->second;
}
}
else
{
} else {
// NumLock off: map to PU arrow keys
std::map<int, int>::iterator numPadIter = noNumlockKeyMap.find(key);
auto numPadIter = noNumlockKeyMap.find(key);
if (numPadIter != noNumlockKeyMap.end()) {
key = numPadIter->second;
}
}
#endif
return key;
}
modifiers = osgToFGModifiers(ea.getModKeyMask());
int FGEventHandler::translateModifiers(const osgGA::GUIEventAdapter& ea)
{
int result = 0;
const auto modifiers = ea.getModKeyMask();
if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
result |= KEYMOD_SHIFT;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL)
result |= KEYMOD_CTRL;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT)
result |= KEYMOD_ALT;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_META)
result |= KEYMOD_META;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_SUPER)
result |= KEYMOD_SUPER;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_HYPER)
result |= KEYMOD_HYPER;
return result;
}
void FGEventHandler::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
int& modifiers)
{
key = translateKey(ea);
modifiers = translateModifiers(ea);
currentModifiers = modifiers;
const auto eventType = ea.getEventType();
if (eventType == osgGA::GUIEventAdapter::KEYUP)
modifiers |= KEYMOD_RELEASED;

View file

@ -99,6 +99,9 @@ public:
void setResizable(bool _resizable) { resizable = _resizable; }
void reset();
static int translateKey(const osgGA::GUIEventAdapter& ea);
static int translateModifiers(const osgGA::GUIEventAdapter& ea);
protected:
osg::ref_ptr<osg::Node> _node;
fgIdleHandler idleHandler;
@ -109,8 +112,7 @@ protected:
osg::ref_ptr<osgGA::GUIEventAdapter> statsEvent;
int statsType;
int currentModifiers;
std::map<int, int> numlockKeyMap;
std::map<int, int> noNumlockKeyMap;
void handleKey(const osgGA::GUIEventAdapter& ea, int& key, int& modifiers);
bool resizable;
bool mouseWarped;

View file

@ -645,6 +645,8 @@ bool GraphicsWindowQt5::realizeImplementation()
getEventQueue()->syncWindowRectangleWithGraphicsContext();
#endif
getEventQueue()->getCurrentEventState()->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS);
_realized = true;
return true;
}

315
src/Viewer/PUICamera.cxx Normal file
View file

@ -0,0 +1,315 @@
// Copyright (C) 2017 James Turner
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "config.h"
#include "PUICamera.hxx"
#include <osg/StateSet>
#include <osg/State>
#include <osg/Texture2D>
#include <osg/Version>
#include <osg/RenderInfo>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/BlendFunc>
#include <osg/NodeVisitor>
#include <osgGA/GUIEventHandler>
#include <osgGA/GUIEventAdapter>
#include <plib/pu.h>
#include <simgear/scene/util/SGNodeMasks.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Main/locale.hxx>
#include <Viewer/CameraGroup.hxx>
#include <Viewer/FGEventHandler.hxx>
using namespace flightgear;
class PUIDrawable : public osg::Drawable
{
public:
PUIDrawable()
{
setUseDisplayList(false);
setDataVariance(Object::DYNAMIC);
}
void drawImplementation(osg::RenderInfo& renderInfo) const override
{
osg::State* state = renderInfo.getState();
state->setActiveTextureUnit(0);
state->setClientActiveTextureUnit(0);
state->disableAllVertexArrays();
state->applyMode(GL_FOG, false);
state->applyMode(GL_DEPTH_TEST, false);
state->applyMode(GL_LIGHTING, false);
glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushClientAttrib(~0u);
// reset pixel storage stuff for PLIB FNT drawing via glBitmap
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
puDisplay();
glPopClientAttrib();
glPopAttrib();
}
osg::Object* cloneType() const override { return new PUIDrawable; }
osg::Object* clone(const osg::CopyOp&) const override { return new PUIDrawable; }
private:
};
class PUIEventHandler : public osgGA::GUIEventHandler
{
public:
PUIEventHandler(PUICamera* cam) :
_puiCamera(cam)
{}
bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, osg::Object *, osg::NodeVisitor *nv) override
{
if (ea.getHandled()) return false;
const double ratio = fgGetDouble("/sim/rendering/gui-pixel-ratio", 1.0);
// PUI expects increasing downward mouse coords
const int fixedY = (ea.getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS) ?
ea.getWindowHeight() - ea.getY() : ea.getY();
const int scaledX = static_cast<int>(ea.getX() / ratio);
const int scaledY = static_cast<int>(fixedY / ratio);
switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::MOVE):
case(osgGA::GUIEventAdapter::DRAG):
{
bool handled = puMouse(scaledX, scaledY);
return handled;
}
// you might thnk the code below is a good idea, but apparently it's not
// PUI synthesises PU_DRAG internally, it doesn't want to see it delivered
// from the windowing system
#if 0
case(osgGA::GUIEventAdapter::DRAG):
{
bool handled = puMouse(osgButtonToPUI(ea), PU_DRAG, scaledX, scaledY);
return handled;
}
#endif
case(osgGA::GUIEventAdapter::PUSH):
case(osgGA::GUIEventAdapter::RELEASE):
{
bool upOrDown = (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE);
bool handled = puMouse(osgButtonToPUI(ea), upOrDown, scaledX, scaledY);
return handled;
}
case(osgGA::GUIEventAdapter::KEYDOWN):
case(osgGA::GUIEventAdapter::KEYUP):
{
const bool isKeyRelease = (ea.getEventType() == osgGA::GUIEventAdapter::KEYUP);
const int key = flightgear::FGEventHandler::translateKey(ea);
bool handled = puKeyboard(key, isKeyRelease);
return handled;
}
case osgGA::GUIEventAdapter::SCROLL:
{
const int button = (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP) ?
PU_SCROLL_UP_BUTTON : PU_SCROLL_DOWN_BUTTON;
bool handled = puMouse(button, PU_DOWN, scaledX, scaledY);
return handled;
}
case (osgGA::GUIEventAdapter::RESIZE):
_puiCamera->resizeUi(ea.getWindowWidth(), ea.getWindowHeight());
break;
default:
return false;
}
return false;
}
private:
int osgButtonToPUI(const osgGA::GUIEventAdapter &ea) const
{
switch (ea.getButton()) {
case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
return 0;
case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
return 1;
case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
return 2;
}
return 0;
}
PUICamera* _puiCamera;
};
// The pu getWindow callback is supposed to return a window ID that
// would allow drawing a GUI on different windows. All that stuff is
// broken in multi-threaded OSG, and we only have one GUI "window"
// anyway, so just return a constant.
int PUICamera::puGetWindow()
{
return 1;
}
void PUICamera::puGetWindowSize(int* width, int* height)
{
*width = 0;
*height = 0;
osg::Camera* camera = getGUICamera(CameraGroup::getDefault());
if (!camera)
return;
osg::Viewport* vport = camera->getViewport();
const double ratio = fgGetDouble("/sim/rendering/gui-pixel-ratio", 1.0);
*width = static_cast<int>(vport->width() / ratio);
*height = static_cast<int>(vport->height() / ratio);
}
void PUICamera::initPUI()
{
puSetWindowFuncs(PUICamera::puGetWindow, nullptr,
PUICamera::puGetWindowSize, nullptr);
puRealInit();
}
PUICamera::PUICamera() :
osg::Camera()
{
}
void PUICamera::init(osg::Group* parent)
{
setName("PUI FBO camera");
_fboTexture = new osg::Texture2D;
_fboTexture->setInternalFormat(GL_RGBA);
_fboTexture->setResizeNonPowerOfTwoHint(false);
_fboTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
_fboTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
// setup the camera as render to texture
setReferenceFrame(osg::Transform::ABSOLUTE_RF);
setViewMatrix(osg::Matrix::identity());
setClearMask( GL_COLOR_BUFFER_BIT );
setClearColor( osg::Vec4( 0.0, 0.0, 0.0, 0.0 ) );
setAllowEventFocus(false);
setCullingActive(false);
setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
setRenderOrder(osg::Camera::PRE_RENDER);
attach(osg::Camera::COLOR_BUFFER, _fboTexture);
// set the camera's node mask, ensure the pick bit is clear
setNodeMask(SG_NODEMASK_GUI_BIT);
// geode+drawable to call puDisplay, as a child of this FBO-camera
osg::Geode* geode = new osg::Geode;
geode->setName("PUIDrawableGeode");
geode->addDrawable(new PUIDrawable);
addChild(geode);
// geometry (full-screen quad) to draw the output
_fullScreenQuad = new osg::Geometry;
_fullScreenQuad = osg::createTexturedQuadGeometry(osg::Vec3(0.0, 0.0, 0.0),
osg::Vec3(200.0, 0.0, 0.0),
osg::Vec3(0.0, 200.0, 0.0));
_fullScreenQuad->setSupportsDisplayList(false);
_fullScreenQuad->setNodeMask(SG_NODEMASK_GUI_BIT);
_fullScreenQuad->setName("PUI fullscreen quad");
// state used for drawing the quad (not for rendering PUI, that's done in the
// drawbale above)
osg::StateSet* stateSet = _fullScreenQuad->getOrCreateStateSet();
stateSet->setRenderBinDetails(1001, "RenderBin");
stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
stateSet->setTextureAttribute(0, _fboTexture);
stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
// geode to display the FSquad in the parent scene (which is GUI camera)
osg::Geode* fsQuadGeode = new osg::Geode;
fsQuadGeode->addDrawable(_fullScreenQuad);
fsQuadGeode->setName("PUI fullscreen Geode");
fsQuadGeode->setNodeMask(SG_NODEMASK_GUI_BIT);
// set the event callback on the Geode; if we set it on the Drawable,
// osgGA calls it twice (as a NodeCallback and also a Drawable::EventCallback)
fsQuadGeode->setEventCallback(new PUIEventHandler(this));
parent->addChild(this);
parent->addChild(fsQuadGeode);
osg::Camera* camera = getGUICamera(CameraGroup::getDefault());
if (camera) {
osg::Viewport* vport = camera->getViewport();
resizeUi(vport->width(), vport->height());
}
}
// remove once we require OSG 3.4
void PUICamera::manuallyResizeFBO(int width, int height)
{
_fboTexture->setTextureSize(width, height);
_fboTexture->dirtyTextureObject();
}
void PUICamera::resizeUi(int width, int height)
{
double ratio = fgGetDouble("/sim/rendering/gui-pixel-ratio", 1.0);
const int scaledWidth = static_cast<int>(width / ratio);
const int scaledHeight = static_cast<int>(height / ratio);
osg::Camera::resize(scaledWidth, scaledHeight);
setViewport(0, 0, scaledWidth, scaledHeight);
#if OSG_VERSION_LESS_THAN(3,4,0)
manuallyResizeFBO(scaledWidth, scaledHeight);
#else
resizeAttachments(scaledWidth, scaledHeight);
#endif
// resize the full-screen quad
osg::Vec3Array* fsQuadVertices = static_cast<osg::Vec3Array*>(_fullScreenQuad->getVertexArray());
(*fsQuadVertices)[0] = osg::Vec3(0.0, height, 0.0);
(*fsQuadVertices)[1] = osg::Vec3(0.0, 0.0, 0.0);
(*fsQuadVertices)[2] = osg::Vec3(width, 0.0, 0.0);
(*fsQuadVertices)[3] = osg::Vec3(width, height, 0.0);
fsQuadVertices->dirty();
}

57
src/Viewer/PUICamera.hxx Normal file
View file

@ -0,0 +1,57 @@
// Copyright (C) 2017 James Turner
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef PUICAMERA_HXX
#define PUICAMERA_HXX
#include <osg/Camera>
namespace osg
{
class Texture2D;
class Geometry;
}
namespace flightgear
{
class PUICamera : public osg::Camera
{
public:
static void initPUI();
PUICamera();
osg::Object* cloneType() const override { return new PUICamera; }
osg::Object* clone(const osg::CopyOp&) const override { return new PUICamera; }
// osg::Camera already defines a resize() so use this name
void resizeUi(int width, int height);
void init(osg::Group *parent);
private:
void manuallyResizeFBO(int width, int height);
osg::Texture2D* _fboTexture = nullptr;
osg::Geometry* _fullScreenQuad = nullptr;
static void puGetWindowSize(int *width, int *height);
static int puGetWindow();
};
} // of namespace flightgear
#endif // PUICAMERA_HXX

View file

@ -17,8 +17,6 @@
# include <config.h>
#endif
#include <plib/pu.h>
#include<algorithm>
#include <functional>
@ -43,7 +41,7 @@ void GraphicsContextOperation::operator()(GraphicsContext* gc)
}
WindowSystemAdapter::WindowSystemAdapter() :
_nextWindowID(0), _isPuInitialized(false)
_nextWindowID(0)
{
}
@ -57,33 +55,6 @@ WindowSystemAdapter::registerWindow(GraphicsContext* gc,
return window;
}
// The pu getWindow callback is supposed to return a window ID that
// would allow drawing a GUI on different windows. All that stuff is
// broken in multi-threaded OSG, and we only have one GUI "window"
// anyway, so just return a constant.
int WindowSystemAdapter::puGetWindow()
{
return 1;
}
void WindowSystemAdapter::puGetWindowSize(int* width, int* height)
{
*width = 0;
*height = 0;
Camera* camera = getGUICamera(CameraGroup::getDefault());
if (!camera)
return;
Viewport* vport = camera->getViewport();
*width = (int)vport->width();
*height = (int)vport->height();
}
void WindowSystemAdapter::puInitialize()
{
puSetWindowFuncs(puGetWindow, 0, puGetWindowSize, 0);
puRealInit();
}
GraphicsWindow* WindowSystemAdapter::findWindow(const string& name)
{
for (WindowVector::iterator iter = windows.begin(), e = windows.end();

View file

@ -110,10 +110,7 @@ public:
*/
GraphicsWindow* registerWindow(osg::GraphicsContext* gc,
const std::string& windowName);
/** Initialize the plib pui interface library. This might happen
*in another thread and may be deferred.
*/
virtual void puInitialize();
/** Find a window by name.
* @param name the window name
* @return the window or 0
@ -129,12 +126,7 @@ public:
static void setWSA(WindowSystemAdapter* wsa) { _wsa = wsa; }
protected:
int _nextWindowID;
osg::ref_ptr<GraphicsContextOperation> _puInitOp;
bool _isPuInitialized;
static osg::ref_ptr<WindowSystemAdapter> _wsa;
// Default callbacks for plib
static int puGetWindow();
static void puGetWindowSize(int* width, int* height);
};

View file

@ -19,9 +19,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <config.h>
#ifdef HAVE_WINDOWS_H
# include <windows.h>
@ -117,7 +115,9 @@
#include <Viewer/GraphicsWindowQt5.hxx>
#endif
#include <plib/pu.h>
#if defined(HAVE_PUI)
#include <Viewer/puicamera.hxx>
#endif
using namespace osg;
using namespace simgear;
@ -149,52 +149,6 @@ private:
};
class SGPuDrawable : public osg::Drawable {
public:
SGPuDrawable()
{
// Dynamic stuff, do not store geometry
setUseDisplayList(false);
setDataVariance(Object::DYNAMIC);
osg::StateSet* stateSet = getOrCreateStateSet();
stateSet->setRenderBinDetails(1001, "RenderBin");
// speed optimization?
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
// We can do translucent menus, so why not. :-)
stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
}
virtual void drawImplementation(osg::RenderInfo& renderInfo) const
{ drawImplementation(*renderInfo.getState()); }
void drawImplementation(osg::State& state) const
{
state.setActiveTextureUnit(0);
state.setClientActiveTextureUnit(0);
state.disableAllVertexArrays();
glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushClientAttrib(~0u);
puDisplay();
glPopClientAttrib();
glPopAttrib();
}
virtual osg::Object* cloneType() const { return new SGPuDrawable; }
virtual osg::Object* clone(const osg::CopyOp&) const { return new SGPuDrawable; }
private:
};
class SGHUDDrawable : public osg::Drawable {
public:
SGHUDDrawable()
@ -1548,7 +1502,12 @@ FGRenderer::setupView( void )
if (guiCamera) {
osg::Geode* geode = new osg::Geode;
geode->addDrawable(new SGHUDDrawable);
geode->addDrawable(new SGPuDrawable);
#if defined(HAVE_PUI)
_puiCamera = new flightgear::PUICamera;
_puiCamera->init(guiCamera);
#endif
#if defined(HAVE_QT)
std::string rootQMLPath = fgGetString("/sim/gui/qml-root-path");
auto graphicsWindowQt = dynamic_cast<GraphicsWindowQt5*>(guiCamera->getGraphicsContext());
@ -1746,7 +1705,7 @@ FGRenderer::resize( int width, int height )
_ysize->setIntValue(height);
}
// update splash node if present ?
// update splash node if present
_splash->resize(width, height);
#if defined(HAVE_QT)
if (_quickDrawable) {

View file

@ -39,6 +39,7 @@ namespace flightgear
class FGEventHandler;
struct CameraInfo;
class CameraGroup;
class PUICamera;
}
class SGSky;
@ -193,6 +194,7 @@ protected:
SplashScreen* _splash;
QQuickDrawable* _quickDrawable;
flightgear::PUICamera* _puiCamera = nullptr;
};
bool fgDumpSceneGraphToFile(const char* filename);