Basic 2D canvas implementation.
Support text and transformations for the moment, more features to follow in due course.
This commit is contained in:
parent
fe0a703a19
commit
d82fd7cc5f
19 changed files with 2165 additions and 98 deletions
157
docs-mini/README.canvas
Normal file
157
docs-mini/README.canvas
Normal file
|
@ -0,0 +1,157 @@
|
|||
Canvas - A 2D Drawing API
|
||||
=========================
|
||||
|
||||
Author: Thomas Geymayer <admin@tomprogs.at>
|
||||
Revision: 2012/05/04
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
With the increasing complexity of (glass) cockpits the need for a simple API to
|
||||
draw on a 2D surface without modifying the C++ core increased heavily in the
|
||||
last time. The 2D canvas is an effort to satisfy this needs. It is now possible
|
||||
to create offscreen rendertargets only by using the property tree and placing
|
||||
them on any 3D object on the aircraft by using certain filter criteria.
|
||||
|
||||
Currently it is only possible to place text on the canvas but 2d shapes (using
|
||||
OpenVG) are going to follow.
|
||||
|
||||
Creating a canvas
|
||||
-----------------
|
||||
|
||||
A new canvas can be instantiated by creating a node /canvas/texture[<INDEX>]
|
||||
with at least the following children:
|
||||
|
||||
<size-x type="int"> The width of the underlying texture
|
||||
<size-y type="int"> The height of the underlying texture
|
||||
|
||||
<view-width type="int"> The width of the canvas
|
||||
<view-height type="int"> The height of the canvas
|
||||
|
||||
The dimensions of the canvas are needed to be able to use textures with
|
||||
different resolutions but use the same units for rendering to the canvas.
|
||||
Therefore you can choose any texture size with the same canvas size and always
|
||||
get the same results (apart from resolution dependent artifacts).
|
||||
|
||||
* Filtering:
|
||||
|
||||
Optionally you can enable mipmapping and/or multisampling (Coverage Sampling
|
||||
Antialiasing):
|
||||
|
||||
<mipmapping type="bool"> Use mipmapping (default: false)
|
||||
<coverage-samples type="int"> Coverage Samples (default: 0)
|
||||
<color-samples type="int"> Color Samples (default: 0, always
|
||||
have to be <= coverage-samples)
|
||||
Drawing
|
||||
-------
|
||||
|
||||
Drawing to the canvas is accomplished by creating nodes as childs of the
|
||||
canvas root node. Every shape has to be a child of a <group> node. Currently
|
||||
only drawing Text is possible:
|
||||
|
||||
* General:
|
||||
The following parameters are used by multiple elements:
|
||||
|
||||
Color:
|
||||
A color can be specified by the following subtree (NAME is replaced by
|
||||
another name depending on the usage of the color)
|
||||
|
||||
<NAME>
|
||||
<red type="float">
|
||||
<green type="float">
|
||||
<blue type="float">
|
||||
</NAME>
|
||||
|
||||
* Text:
|
||||
Create a <text> node and configure with the following properties:
|
||||
|
||||
<text type="string"> The text to be displayed
|
||||
<font type="string"> The font to be used (Searched in
|
||||
1. aircraft-dir/Fonts
|
||||
2. aircraft-dir
|
||||
3. $FG_DATA/Fonts
|
||||
4. Default osg font paths
|
||||
<size type="float"> The font size (default: 32)
|
||||
<tf> A 3x3 transformation matrix specified by 6 values
|
||||
(child elements <a>, ..., <f>) See
|
||||
http://www.w3.org/TR/SVG/coords.html#TransformMatrixDefined
|
||||
for details.
|
||||
You can also use shortcuts and use an alternative to
|
||||
specifying six values:
|
||||
- Translation: <tx>, <ty> (ty, ty default to 0)
|
||||
- Totation: <rot>
|
||||
- Scale: <sx>, <sy> (sx is required, sy defaults to sx)
|
||||
<alginment type="string"> Text alignment (default: "left-baseline") One of:
|
||||
|
||||
"left-top"
|
||||
"left-center"
|
||||
"left-bottom"
|
||||
|
||||
"center-top"
|
||||
"center-center"
|
||||
"center-bottom"
|
||||
|
||||
"right-top"
|
||||
"right-center"
|
||||
"right-bottom"
|
||||
|
||||
"left-baseline"
|
||||
"center-baseline"
|
||||
"right-baseline"
|
||||
|
||||
"left-bottom-baseline"
|
||||
"center-bottom-baseline"
|
||||
"right-bottom-baseline"
|
||||
<draw-mode type="int"> A bitwise combination of the following values
|
||||
1 (Text - default)
|
||||
2 (Boundingbox)
|
||||
4 (Filled boundingbox)
|
||||
8 (Alignment -> Draw a cross at the position
|
||||
of the text)
|
||||
<padding type="float"> Padding between for the boundingbox (default: 0)
|
||||
<color> Text color
|
||||
<color-fill> Fill color (for the bounding box)
|
||||
|
||||
Placement
|
||||
---------
|
||||
|
||||
To place the canvas into the scene one ore more <placement> elements can be
|
||||
added to the texture node. By setting at least on of the following nodes
|
||||
the objects where the canvas texture should be placed on are selected:
|
||||
|
||||
<texture type="string"> Match objects with the given texture assigned
|
||||
<node type="string"> Match objects with the given name
|
||||
<parent type="string"> Match objects with a parent matching the given name
|
||||
(Not necessarily the direct parent)
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
<canvas>
|
||||
<texture>
|
||||
<size-x type="int">384</size-x>
|
||||
<size-y type="int">512</size-y>
|
||||
<view-width type="int">768</view-width>
|
||||
<view-height type="int">1024</view-height>
|
||||
<mipmapping type="bool">false</mipmapping>
|
||||
<coverage-samples type="int">0</coverage-samples>
|
||||
<color-samples type="int">0</color-samples>
|
||||
<group>
|
||||
<text>
|
||||
<text type="string">TEST MESSAGE</text>
|
||||
<font type="string">helvetica_bold.txf</font>
|
||||
<tf>
|
||||
<!-- Translate (18|50) -->
|
||||
<tx>18</tx>
|
||||
<ty>50</ty>
|
||||
</tf>
|
||||
</text>
|
||||
</group>
|
||||
<placement>
|
||||
<!-- Place on objects with the texture EICAS.png
|
||||
and a parent called HDD 1 -->
|
||||
<texture type="string">EICAS.png</texture>
|
||||
<parent type="string">HDD 1</parent>
|
||||
</placement>
|
||||
</texture>
|
||||
</canvas>
|
|
@ -8,6 +8,7 @@ foreach( mylibfolder
|
|||
Aircraft
|
||||
ATC
|
||||
ATCDCL
|
||||
Canvas
|
||||
Radio
|
||||
Autopilot
|
||||
Cockpit
|
||||
|
|
19
src/Canvas/CMakeLists.txt
Normal file
19
src/Canvas/CMakeLists.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
include(FlightGearComponent)
|
||||
|
||||
set(SOURCES
|
||||
canvas.cxx
|
||||
canvas_mgr.cxx
|
||||
elements/element.cxx
|
||||
elements/group.cxx
|
||||
elements/text.cxx
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
canvas.hxx
|
||||
canvas_mgr.hxx
|
||||
elements/element.hxx
|
||||
elements/group.hxx
|
||||
elements/text.hxx
|
||||
)
|
||||
|
||||
flightgear_component(Canvas "${SOURCES}" "${HEADERS}")
|
430
src/Canvas/canvas.cxx
Normal file
430
src/Canvas/canvas.cxx
Normal file
|
@ -0,0 +1,430 @@
|
|||
// The canvas for rendering with the 2d api
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 "canvas.hxx"
|
||||
#include "elements/group.hxx"
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/Geode>
|
||||
#include <osgText/Text>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
//#include <Main/globals.hxx>
|
||||
//#include <Viewer/renderer.hxx>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Callback used to disable/enable rendering to the texture if it is not
|
||||
* visible
|
||||
*/
|
||||
class CameraCullCallback:
|
||||
public osg::NodeCallback
|
||||
{
|
||||
public:
|
||||
|
||||
CameraCullCallback():
|
||||
_render( true )
|
||||
{}
|
||||
|
||||
/**
|
||||
* Enable rendering for the next frame
|
||||
*/
|
||||
void enableRendering()
|
||||
{
|
||||
_render = true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool _render;
|
||||
|
||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
if( _render )
|
||||
{
|
||||
traverse(node, nv);
|
||||
_render = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This callback is installed on every placement of the canvas in the scene to
|
||||
* only render the canvas if at least one placement is visible
|
||||
*/
|
||||
class PlacementCullCallback:
|
||||
public osg::NodeCallback
|
||||
{
|
||||
public:
|
||||
|
||||
PlacementCullCallback(Canvas* canvas, CameraCullCallback* camera_cull):
|
||||
_canvas( canvas ),
|
||||
_camera_cull( camera_cull )
|
||||
{}
|
||||
|
||||
private:
|
||||
|
||||
Canvas *_canvas;
|
||||
CameraCullCallback *_camera_cull;
|
||||
|
||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
_camera_cull->enableRendering();
|
||||
traverse(node, nv);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Canvas::Canvas():
|
||||
_size_x(-1),
|
||||
_size_y(-1),
|
||||
_view_width(-1),
|
||||
_view_height(-1),
|
||||
_status(0),
|
||||
_node(0),
|
||||
_sampling_dirty(false)
|
||||
{
|
||||
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
|
||||
|
||||
CameraCullCallback *camera_callback = new CameraCullCallback;
|
||||
_camera_callback = camera_callback;
|
||||
_cull_callback = new PlacementCullCallback(this, camera_callback);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Canvas::~Canvas()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Canvas::getStatus() const
|
||||
{
|
||||
return _status;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::reset(SGPropertyNode* node)
|
||||
{
|
||||
if( _node )
|
||||
{
|
||||
_node->untie("size[0]");
|
||||
_node->untie("size[1]");
|
||||
_node->untie("view[0]");
|
||||
_node->untie("view[1]");
|
||||
_node->untie("status");
|
||||
_node->untie("status-msg");
|
||||
_node->removeChangeListener(this);
|
||||
_node = 0;
|
||||
}
|
||||
|
||||
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
|
||||
|
||||
if( node )
|
||||
{
|
||||
_node = node;
|
||||
_node->tie
|
||||
(
|
||||
"size[0]",
|
||||
SGRawValueMethods<Canvas, int>( *this, &Canvas::getSizeX,
|
||||
&Canvas::setSizeX )
|
||||
);
|
||||
_node->tie
|
||||
(
|
||||
"size[1]",
|
||||
SGRawValueMethods<Canvas, int>( *this, &Canvas::getSizeY,
|
||||
&Canvas::setSizeY )
|
||||
);
|
||||
_node->tie
|
||||
(
|
||||
"view[0]",
|
||||
SGRawValueMethods<Canvas, int>( *this, &Canvas::getViewWidth,
|
||||
&Canvas::setViewWidth )
|
||||
);
|
||||
_node->tie
|
||||
(
|
||||
"view[1]",
|
||||
SGRawValueMethods<Canvas, int>( *this, &Canvas::getViewHeight,
|
||||
&Canvas::setViewHeight )
|
||||
);
|
||||
_node->tie
|
||||
(
|
||||
"status",
|
||||
SGRawValueMethods<Canvas, int>(*this, &Canvas::getStatus)
|
||||
);
|
||||
_node->tie
|
||||
(
|
||||
"status-msg",
|
||||
SGRawValueMethods<Canvas, const char*>(*this, &Canvas::getStatusMsg)
|
||||
);
|
||||
_node->addChangeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::update(double delta_time_sec)
|
||||
{
|
||||
if( !_texture.serviceable() )
|
||||
{
|
||||
if( _status != STATUS_OK )
|
||||
return;
|
||||
|
||||
_texture.setSize(_size_x, _size_y);
|
||||
_texture.useImageCoords(true);
|
||||
_texture.useStencil(true);
|
||||
_texture.allocRT(_camera_callback);
|
||||
_texture.getCamera()->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f , 1.0f));
|
||||
|
||||
for( size_t i = 0; i < _groups.size(); ++i )
|
||||
_texture.getCamera()->addChild( _groups[i]->getMatrixTransform() );
|
||||
|
||||
if( _texture.serviceable() )
|
||||
{
|
||||
setStatusFlags(STATUS_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
setStatusFlags(CREATE_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for( size_t i = 0; i < _groups.size(); ++i )
|
||||
_groups[i]->update(delta_time_sec);
|
||||
|
||||
if( _sampling_dirty )
|
||||
{
|
||||
_texture.setSampling(
|
||||
_node->getBoolValue("mipmapping"),
|
||||
_node->getIntValue("coverage-samples"),
|
||||
_node->getIntValue("color-samples")
|
||||
);
|
||||
_sampling_dirty = false;
|
||||
}
|
||||
|
||||
while( !_dirty_placements.empty() )
|
||||
{
|
||||
SGPropertyNode *node = _dirty_placements.back();
|
||||
_dirty_placements.pop_back();
|
||||
|
||||
if( node->getIndex() >= static_cast<int>(_placements.size()) )
|
||||
// New placement
|
||||
_placements.resize(node->getIndex() + 1);
|
||||
else
|
||||
// Remove maybe already existing placements
|
||||
clearPlacements(node->getIndex());
|
||||
|
||||
// add new placements
|
||||
_placements[node->getIndex()] = _texture.set_texture(
|
||||
node,
|
||||
_texture.getTexture(),
|
||||
_cull_callback
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::setSizeX(int sx)
|
||||
{
|
||||
if( _size_x == sx )
|
||||
return;
|
||||
_size_x = sx;
|
||||
|
||||
// TODO resize if texture already allocated
|
||||
|
||||
if( _size_x <= 0 )
|
||||
setStatusFlags(MISSING_SIZE_X);
|
||||
else
|
||||
setStatusFlags(MISSING_SIZE_X, false);
|
||||
|
||||
// reset flag to allow creation with new size
|
||||
setStatusFlags(CREATE_FAILED, false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Canvas::getSizeX() const
|
||||
{
|
||||
return _size_x;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::setSizeY(int sy)
|
||||
{
|
||||
if( _size_y == sy )
|
||||
return;
|
||||
_size_y = sy;
|
||||
|
||||
// TODO resize if texture already allocated
|
||||
|
||||
if( _size_y <= 0 )
|
||||
setStatusFlags(MISSING_SIZE_Y);
|
||||
else
|
||||
setStatusFlags(MISSING_SIZE_Y, false);
|
||||
|
||||
// reset flag to allow creation with new size
|
||||
setStatusFlags(CREATE_FAILED, false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Canvas::getSizeY() const
|
||||
{
|
||||
return _size_y;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::setViewWidth(int w)
|
||||
{
|
||||
if( _view_width == w )
|
||||
return;
|
||||
_view_width = w;
|
||||
|
||||
_texture.setViewSize(_view_width, _view_height);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Canvas::getViewWidth() const
|
||||
{
|
||||
return _view_width;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::setViewHeight(int h)
|
||||
{
|
||||
if( _view_height == h )
|
||||
return;
|
||||
_view_height = h;
|
||||
|
||||
_texture.setViewSize(_view_width, _view_height);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int Canvas::getViewHeight() const
|
||||
{
|
||||
return _view_height;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char* Canvas::getStatusMsg() const
|
||||
{
|
||||
return _status_msg.c_str();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child )
|
||||
{
|
||||
if( parent != _node )
|
||||
return;
|
||||
|
||||
if( child->getNameString() == "group" )
|
||||
{
|
||||
_groups.push_back
|
||||
(
|
||||
boost::shared_ptr<canvas::Group>(new canvas::Group(child))
|
||||
);
|
||||
if( _texture.serviceable() )
|
||||
_texture.getCamera()->addChild( _groups.back()->getMatrixTransform() );
|
||||
}
|
||||
else if( child->getNameString() == "placement" )
|
||||
{
|
||||
_dirty_placements.push_back(child);
|
||||
}
|
||||
// else
|
||||
// std::cout << "Canvas::childAdded: " << child->getPath() << std::endl;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::childRemoved( SGPropertyNode * parent,
|
||||
SGPropertyNode * child )
|
||||
{
|
||||
if( parent != _node )
|
||||
return;
|
||||
|
||||
if( child->getNameString() == "placement" )
|
||||
clearPlacements(child->getIndex());
|
||||
else
|
||||
std::cout << "Canvas::childRemoved: " << child->getPath() << std::endl;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::valueChanged(SGPropertyNode * node)
|
||||
{
|
||||
if( node->getParent()->getParent() == _node
|
||||
&& node->getParent()->getNameString() == "placement" )
|
||||
{
|
||||
// prevent double updates...
|
||||
for( size_t i = 0; i < _dirty_placements.size(); ++i )
|
||||
{
|
||||
if( node->getParent() == _dirty_placements[i] )
|
||||
return;
|
||||
}
|
||||
|
||||
_dirty_placements.push_back(node->getParent());
|
||||
}
|
||||
else if( node->getParent() == _node )
|
||||
{
|
||||
if( node->getNameString() == "mipmapping"
|
||||
|| node->getNameString() == "coverage-samples"
|
||||
|| node->getNameString() == "color-samples" )
|
||||
_sampling_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::setStatusFlags(unsigned int flags, bool set)
|
||||
{
|
||||
if( set )
|
||||
_status |= flags;
|
||||
else
|
||||
_status &= ~flags;
|
||||
|
||||
if( (_status & MISSING_SIZE_X) && (_status & MISSING_SIZE_Y) )
|
||||
_status_msg = "Missing size";
|
||||
else if( _status & MISSING_SIZE_X )
|
||||
_status_msg = "Missing size-x";
|
||||
else if( _status & MISSING_SIZE_Y )
|
||||
_status_msg = "Missing size-y";
|
||||
else if( _status & CREATE_FAILED )
|
||||
_status_msg = "Creating render target failed";
|
||||
else if( _status == STATUS_OK && !_texture.serviceable() )
|
||||
_status_msg = "Creation pending...";
|
||||
else
|
||||
_status_msg = "Ok";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::clearPlacements(int index)
|
||||
{
|
||||
Placements& placements = _placements.at(index);
|
||||
while( !placements.empty() )
|
||||
{
|
||||
osg::ref_ptr<osg::Group> group = placements.back();
|
||||
placements.pop_back();
|
||||
|
||||
assert( group->getNumParents() == 1 );
|
||||
assert( group->getNumChildren() == 1 );
|
||||
|
||||
osg::Group *parent = group->getParent(0);
|
||||
osg::Node *child = group->getChild(0);
|
||||
|
||||
parent->addChild(child);
|
||||
group->removeChild(child);
|
||||
parent->removeChild(group);
|
||||
}
|
||||
}
|
101
src/Canvas/canvas.hxx
Normal file
101
src/Canvas/canvas.hxx
Normal file
|
@ -0,0 +1,101 @@
|
|||
// The canvas for rendering with the 2d api
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 CANVAS_HXX_
|
||||
#define CANVAS_HXX_
|
||||
|
||||
#include <Instrumentation/od_gauge.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <osg/NodeCallback>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace canvas
|
||||
{
|
||||
class Group;
|
||||
}
|
||||
|
||||
class Canvas:
|
||||
public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
|
||||
enum StatusFlags
|
||||
{
|
||||
STATUS_OK,
|
||||
MISSING_SIZE_X = 0x0001,
|
||||
MISSING_SIZE_Y = 0x0002,
|
||||
CREATE_FAILED = 0x0004
|
||||
};
|
||||
|
||||
Canvas();
|
||||
virtual ~Canvas();
|
||||
|
||||
void reset(SGPropertyNode* node);
|
||||
void update(double delta_time_sec);
|
||||
|
||||
void setSizeX(int sx);
|
||||
int getSizeX() const;
|
||||
|
||||
void setSizeY(int sy);
|
||||
int getSizeY() const;
|
||||
|
||||
void setViewWidth(int w);
|
||||
int getViewWidth() const;
|
||||
|
||||
void setViewHeight(int h);
|
||||
int getViewHeight() const;
|
||||
|
||||
int getStatus() const;
|
||||
const char* getStatusMsg() const;
|
||||
|
||||
virtual void childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
virtual void childRemoved( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
virtual void valueChanged (SGPropertyNode * node);
|
||||
|
||||
private:
|
||||
|
||||
int _size_x,
|
||||
_size_y,
|
||||
_view_width,
|
||||
_view_height;
|
||||
|
||||
int _status;
|
||||
std::string _status_msg;
|
||||
|
||||
FGODGauge _texture;
|
||||
SGPropertyNode *_node;
|
||||
|
||||
bool _sampling_dirty;
|
||||
|
||||
osg::ref_ptr<osg::NodeCallback> _camera_callback;
|
||||
osg::ref_ptr<osg::NodeCallback> _cull_callback;
|
||||
std::vector<SGPropertyNode*> _dirty_placements;
|
||||
std::vector<Placements> _placements;
|
||||
|
||||
// TODO replace auto_ptr with unique_ptr as soon as C++11 is used!
|
||||
std::vector<boost::shared_ptr<canvas::Group> > _groups;
|
||||
|
||||
void setStatusFlags(unsigned int flags, bool set = true);
|
||||
void clearPlacements(int index);
|
||||
};
|
||||
|
||||
#endif /* CANVAS_HXX_ */
|
144
src/Canvas/canvas_mgr.cxx
Normal file
144
src/Canvas/canvas_mgr.cxx
Normal file
|
@ -0,0 +1,144 @@
|
|||
// Canvas with 2D rendering api
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 "canvas_mgr.hxx"
|
||||
#include "canvas.hxx"
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
CanvasMgr::CanvasMgr():
|
||||
_props( fgGetNode("/canvas", true) )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
CanvasMgr::~CanvasMgr()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::init()
|
||||
{
|
||||
_props->addChangeListener(this);
|
||||
triggerChangeRecursive(_props);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::reinit()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::shutdown()
|
||||
{
|
||||
_props->removeChangeListener(this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::bind()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::unbind()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::update(double delta_time_sec)
|
||||
{
|
||||
for( size_t i = 0; i < _canvases.size(); ++i )
|
||||
_canvases[i].update(delta_time_sec);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child )
|
||||
{
|
||||
if( parent != _props )
|
||||
return;
|
||||
|
||||
if( child->getNameString() == "texture" )
|
||||
textureAdded(child);
|
||||
else
|
||||
std::cout << "CanvasMgr::childAdded: " << child->getPath() << std::endl;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::childRemoved( SGPropertyNode * parent,
|
||||
SGPropertyNode * child )
|
||||
{
|
||||
if( parent != _props )
|
||||
return;
|
||||
|
||||
std::cout << "CanvasMgr::childRemoved: " << child->getPath() << std::endl;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::textureAdded(SGPropertyNode* node)
|
||||
{
|
||||
size_t index = node->getIndex();
|
||||
|
||||
if( index >= _canvases.size() )
|
||||
{
|
||||
if( index > _canvases.size() )
|
||||
SG_LOG(SG_GL, SG_WARN, "Skipping unused texture slot(s)!");
|
||||
SG_LOG(SG_GL, SG_INFO, "Add new texture[" << index << "]");
|
||||
|
||||
_canvases.resize(index + 1);
|
||||
_canvases[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG(SG_GL, SG_WARN, "texture[" << index << "] already exists!");
|
||||
}
|
||||
|
||||
_canvases[index].reset(node);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::triggerChangeRecursive(SGPropertyNode* node)
|
||||
{
|
||||
node->getParent()->fireChildAdded(node);
|
||||
|
||||
if( node->nChildren() == 0 && node->getType() != simgear::props::NONE )
|
||||
return node->fireValueChanged();
|
||||
|
||||
for( int i = 0; i < node->nChildren(); ++i )
|
||||
triggerChangeRecursive( node->getChild(i) );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template<class T>
|
||||
T CanvasMgr::getParam(const SGPropertyNode* node, const char* prop)
|
||||
{
|
||||
const SGPropertyNode* child = node->getChild(prop);
|
||||
if( !child )
|
||||
throw std::runtime_error(std::string("Missing property ") + prop);
|
||||
return getValue<T>(child);
|
||||
}
|
76
src/Canvas/canvas_mgr.hxx
Normal file
76
src/Canvas/canvas_mgr.hxx
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Canvas with 2D rendering api
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 CANVAS_MGR_H_
|
||||
#define CANVAS_MGR_H_
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <vector>
|
||||
|
||||
class Canvas;
|
||||
|
||||
class CanvasMgr:
|
||||
public SGSubsystem,
|
||||
public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
CanvasMgr();
|
||||
virtual ~CanvasMgr();
|
||||
|
||||
virtual void init();
|
||||
virtual void reinit();
|
||||
virtual void shutdown();
|
||||
|
||||
virtual void bind();
|
||||
virtual void unbind();
|
||||
|
||||
virtual void update(double delta_time_sec);
|
||||
|
||||
virtual void childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
virtual void childRemoved( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
|
||||
private:
|
||||
|
||||
/** Root node for everything concerning the canvas system */
|
||||
SGPropertyNode_ptr _props;
|
||||
|
||||
/** The actual canvases */
|
||||
std::vector<Canvas> _canvases;
|
||||
|
||||
void textureAdded(SGPropertyNode* node);
|
||||
|
||||
/**
|
||||
* Trigger a childAdded and valueChanged event for every child of node
|
||||
* (Unlimited depth) and node itself.
|
||||
*/
|
||||
void triggerChangeRecursive(SGPropertyNode* node);
|
||||
|
||||
/**
|
||||
* Get the value of a property or throw an exception if it doesn't exist.
|
||||
*/
|
||||
template<class T>
|
||||
T getParam(const SGPropertyNode* node, const char* prop);
|
||||
|
||||
};
|
||||
|
||||
#endif /* CANVAS_MGR_H_ */
|
266
src/Canvas/elements/element.cxx
Normal file
266
src/Canvas/elements/element.cxx
Normal file
|
@ -0,0 +1,266 @@
|
|||
// Interface for 2D canvas element
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 "element.hxx"
|
||||
#include <cassert>
|
||||
|
||||
#include <osg/Drawable>
|
||||
|
||||
namespace canvas
|
||||
{
|
||||
const std::string NAME_TRANSFORM = "tf";
|
||||
const std::string NAME_COLOR = "color";
|
||||
const std::string NAME_COLOR_FILL = "color-fill";
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Element::~Element()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
SGPropertyNode* Element::getPropertyNode()
|
||||
{
|
||||
return _node;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::update(double dt)
|
||||
{
|
||||
if( _transform_dirty )
|
||||
{
|
||||
osg::Matrix m;
|
||||
for( size_t i = 0; i < _transform_types.size(); ++i )
|
||||
{
|
||||
// Skip unused indizes...
|
||||
if( _transform_types[i] == TT_NONE )
|
||||
continue;
|
||||
|
||||
SGPropertyNode* tf_node = _node->getChild("tf", i, true);
|
||||
|
||||
// Build up the matrix representation of the current transform node
|
||||
osg::Matrix tf;
|
||||
switch( _transform_types[i] )
|
||||
{
|
||||
case TT_MATRIX:
|
||||
tf = osg::Matrix( tf_node->getDoubleValue("a", 1),
|
||||
tf_node->getDoubleValue("b", 0), 0, 0,
|
||||
|
||||
tf_node->getDoubleValue("c", 0),
|
||||
tf_node->getDoubleValue("d", 1), 0, 0,
|
||||
|
||||
0, 0, 1, 0,
|
||||
tf_node->getDoubleValue("e", 0),
|
||||
tf_node->getDoubleValue("f", 0), 0, 1 );
|
||||
break;
|
||||
case TT_TRANSLATE:
|
||||
tf.makeTranslate( osg::Vec3f( tf_node->getDoubleValue("tx", 0),
|
||||
tf_node->getDoubleValue("ty", 0),
|
||||
0 ) );
|
||||
break;
|
||||
case TT_ROTATE:
|
||||
tf.makeRotate( tf_node->getDoubleValue("rot", 0), 0, 0, 1 );
|
||||
break;
|
||||
case TT_SCALE:
|
||||
{
|
||||
float sx = tf_node->getDoubleValue("sx", 1);
|
||||
// sy defaults to sx...
|
||||
tf.makeScale( sx, tf_node->getDoubleValue("sy", sx), 1 );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m.postMult( tf );
|
||||
}
|
||||
_transform->setMatrix(m);
|
||||
_transform_dirty = false;
|
||||
}
|
||||
|
||||
if( _attributes_dirty & COLOR )
|
||||
{
|
||||
colorChanged( osg::Vec4( _color[0]->getFloatValue(),
|
||||
_color[1]->getFloatValue(),
|
||||
_color[2]->getFloatValue(),
|
||||
1 ) );
|
||||
_attributes_dirty &= ~COLOR;
|
||||
}
|
||||
|
||||
if( _attributes_dirty & COLOR_FILL )
|
||||
{
|
||||
colorFillChanged( osg::Vec4( _color_fill[0]->getFloatValue(),
|
||||
_color_fill[1]->getFloatValue(),
|
||||
_color_fill[2]->getFloatValue(),
|
||||
1 ) );
|
||||
_attributes_dirty &= ~COLOR_FILL;
|
||||
}
|
||||
|
||||
if( _drawable && (_attributes_dirty & BOUNDING_BOX) )
|
||||
{
|
||||
_bounding_box[0]->setFloatValue(_drawable->getBound()._min.x());
|
||||
_bounding_box[1]->setFloatValue(_drawable->getBound()._min.y());
|
||||
_bounding_box[2]->setFloatValue(_drawable->getBound()._max.x());
|
||||
_bounding_box[3]->setFloatValue(_drawable->getBound()._max.y());
|
||||
|
||||
_attributes_dirty &= ~BOUNDING_BOX;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::ref_ptr<osg::MatrixTransform> Element::getMatrixTransform()
|
||||
{
|
||||
return _transform;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Element::Element(SGPropertyNode* node, uint32_t attributes_used):
|
||||
_node( node ),
|
||||
_drawable( 0 ),
|
||||
_attributes_used( attributes_used ),
|
||||
_attributes_dirty( 0 ),
|
||||
_transform_dirty( false ),
|
||||
_transform( new osg::MatrixTransform )
|
||||
{
|
||||
assert( _node );
|
||||
_node->addChangeListener(this);
|
||||
|
||||
if( _attributes_used & COLOR )
|
||||
linkColorNodes("color", _color, osg::Vec4f(0,1,0,1));
|
||||
if( _attributes_used & COLOR_FILL )
|
||||
linkColorNodes("color-fill", _color_fill);
|
||||
if( _attributes_used & BOUNDING_BOX )
|
||||
{
|
||||
SGPropertyNode* bb = _node->getChild("bounding-box", 0, true);
|
||||
_bounding_box[0] = bb->getChild("x-min", 0, true);
|
||||
_bounding_box[1] = bb->getChild("y-min", 0, true);
|
||||
_bounding_box[2] = bb->getChild("x-max", 0, true);
|
||||
_bounding_box[3] = bb->getChild("y-max", 0, true);
|
||||
}
|
||||
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_DEBUG,
|
||||
"New canvas element " << node->getPath()
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::linkColorNodes( const char* name,
|
||||
SGPropertyNode** nodes,
|
||||
const osg::Vec4& def )
|
||||
{
|
||||
// Don't tie to allow the usage of aliases
|
||||
SGPropertyNode* color = _node->getChild(name, 0, true);
|
||||
|
||||
static const char* color_names[] = {"red", "green", "blue"};
|
||||
for( size_t i = 0; i < sizeof(color_names)/sizeof(color_names[0]); ++i )
|
||||
{
|
||||
color->setFloatValue
|
||||
(
|
||||
color_names[i],
|
||||
color->getFloatValue(color_names[i], def[i])
|
||||
);
|
||||
nodes[i] = color->getChild(color_names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( parent == _node )
|
||||
{
|
||||
if( child->getNameString() == NAME_TRANSFORM )
|
||||
{
|
||||
if( child->getIndex() >= static_cast<int>(_transform_types.size()) )
|
||||
_transform_types.resize( child->getIndex() + 1 );
|
||||
|
||||
_transform_types[ child->getIndex() ] = TT_NONE;
|
||||
_transform_dirty = true;
|
||||
}
|
||||
else
|
||||
childAdded(child);
|
||||
}
|
||||
else if( parent->getParent() == _node
|
||||
&& parent->getNameString() == NAME_TRANSFORM )
|
||||
{
|
||||
assert(parent->getIndex() < static_cast<int>(_transform_types.size()));
|
||||
|
||||
const std::string& name = child->getNameString();
|
||||
|
||||
TransformType& type = _transform_types[parent->getIndex()];
|
||||
|
||||
if( name == "a" || name == "b" || name == "c"
|
||||
|| name == "d" || name == "e" || name == "f" )
|
||||
type = TT_MATRIX;
|
||||
else if( name == "tx" || name == "ty" )
|
||||
type = TT_TRANSLATE;
|
||||
else if( name == "rot" )
|
||||
type = TT_ROTATE;
|
||||
else if( name == "sx" || name == "sy" )
|
||||
type = TT_SCALE;
|
||||
else
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_WARN,
|
||||
"Unknown transform element " << child->getPath()
|
||||
);
|
||||
|
||||
_transform_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( parent != _node )
|
||||
return;
|
||||
|
||||
if( child->getNameString() == NAME_TRANSFORM )
|
||||
{
|
||||
assert(child->getIndex() < static_cast<int>(_transform_types.size()));
|
||||
_transform_types[ child->getIndex() ] = TT_NONE;
|
||||
|
||||
while( !_transform_types.empty() && _transform_types.back() == TT_NONE )
|
||||
_transform_types.pop_back();
|
||||
|
||||
_transform_dirty = true;
|
||||
}
|
||||
else
|
||||
childRemoved(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::valueChanged(SGPropertyNode* child)
|
||||
{
|
||||
SGPropertyNode *parent = child->getParent();
|
||||
if( parent->getParent() == _node )
|
||||
{
|
||||
if( parent->getNameString() == NAME_TRANSFORM )
|
||||
_transform_dirty = true;
|
||||
else if( parent->getNameString() == NAME_COLOR )
|
||||
_attributes_dirty |= COLOR;
|
||||
else if( parent->getNameString() == NAME_COLOR_FILL )
|
||||
_attributes_dirty |= COLOR_FILL;
|
||||
}
|
||||
else
|
||||
childChanged(child);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
106
src/Canvas/elements/element.hxx
Normal file
106
src/Canvas/elements/element.hxx
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Interface for 2D canvas element
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 CANVAS_ELEMENT_HXX_
|
||||
#define CANVAS_ELEMENT_HXX_
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <osg/MatrixTransform>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Drawable;
|
||||
}
|
||||
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class Element:
|
||||
private SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
virtual ~Element() = 0;
|
||||
SGPropertyNode* getPropertyNode();
|
||||
|
||||
/**
|
||||
* Called every frame to update internal state
|
||||
*
|
||||
* @param dt Frame time in seconds
|
||||
*/
|
||||
virtual void update(double dt);
|
||||
|
||||
osg::ref_ptr<osg::MatrixTransform> getMatrixTransform();
|
||||
|
||||
protected:
|
||||
|
||||
enum Attributes
|
||||
{
|
||||
COLOR = 0x0001,
|
||||
COLOR_FILL = 0x0002,
|
||||
BOUNDING_BOX = 0x0004
|
||||
};
|
||||
|
||||
enum TransformType
|
||||
{
|
||||
TT_NONE,
|
||||
TT_MATRIX,
|
||||
TT_TRANSLATE,
|
||||
TT_ROTATE,
|
||||
TT_SCALE
|
||||
};
|
||||
|
||||
SGPropertyNode *_node;
|
||||
osg::Drawable *_drawable;
|
||||
|
||||
uint32_t _attributes_used;
|
||||
uint32_t _attributes_dirty;
|
||||
|
||||
bool _transform_dirty;
|
||||
osg::ref_ptr<osg::MatrixTransform> _transform;
|
||||
std::vector<TransformType> _transform_types;
|
||||
|
||||
SGPropertyNode *_bounding_box[4]; ///<! x-min, y-min, x-max, y-max
|
||||
SGPropertyNode *_color[3];
|
||||
SGPropertyNode *_color_fill[3];
|
||||
|
||||
Element(SGPropertyNode* node, uint32_t attributes_used = 0);
|
||||
|
||||
virtual void childAdded(SGPropertyNode * child) {}
|
||||
virtual void childRemoved(SGPropertyNode * child){}
|
||||
virtual void childChanged(SGPropertyNode * child){}
|
||||
|
||||
virtual void colorChanged(const osg::Vec4& color) {}
|
||||
virtual void colorFillChanged(const osg::Vec4& color){}
|
||||
|
||||
void linkColorNodes( const char* name,
|
||||
SGPropertyNode** nodes,
|
||||
const osg::Vec4& def = osg::Vec4(1,1,0,1) );
|
||||
|
||||
private:
|
||||
Element(const Element&);// = delete
|
||||
|
||||
virtual void childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
virtual void childRemoved( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
virtual void valueChanged(SGPropertyNode * child);
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
#endif /* CANVAS_ELEMENT_HXX_ */
|
65
src/Canvas/elements/group.cxx
Normal file
65
src/Canvas/elements/group.cxx
Normal file
|
@ -0,0 +1,65 @@
|
|||
// A group of 2D canvas elements
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 "group.hxx"
|
||||
#include "text.hxx"
|
||||
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Group::Group(SGPropertyNode* node):
|
||||
Element(node)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Group::~Group()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Group::update(double dt)
|
||||
{
|
||||
for( size_t i = 0; i < _children.size(); ++i )
|
||||
_children[i]->update(dt);
|
||||
|
||||
Element::update(dt);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Group::childAdded(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getNameString() == "text" )
|
||||
{
|
||||
_children.push_back( boost::shared_ptr<Element>(new Text(child)) );
|
||||
_transform->addChild( _children.back()->getMatrixTransform() );
|
||||
}
|
||||
else
|
||||
std::cout << "New unknown child: " << child->getDisplayName() << std::endl;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Group::childRemoved(SGPropertyNode* child)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // namespace canvas
|
47
src/Canvas/elements/group.hxx
Normal file
47
src/Canvas/elements/group.hxx
Normal file
|
@ -0,0 +1,47 @@
|
|||
// A group of 2D canvas elements
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 CANVAS_GROUP_HXX_
|
||||
#define CANVAS_GROUP_HXX_
|
||||
|
||||
#include "element.hxx"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class Group:
|
||||
public Element
|
||||
{
|
||||
public:
|
||||
Group(SGPropertyNode* node);
|
||||
virtual ~Group();
|
||||
|
||||
virtual void update(double dt);
|
||||
|
||||
protected:
|
||||
std::vector<boost::shared_ptr<Element> > _children;
|
||||
|
||||
virtual void childAdded(SGPropertyNode * child);
|
||||
virtual void childRemoved(SGPropertyNode * child);
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
#endif /* CANVAS_GROUP_HXX_ */
|
41
src/Canvas/elements/text-alignment.hxx
Normal file
41
src/Canvas/elements/text-alignment.hxx
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Mapping between strings and osg text alignment flags
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 ENUM_MAPPING
|
||||
# error "Only include with ENUM_MAPPING defined!"
|
||||
#endif
|
||||
|
||||
ENUM_MAPPING(LEFT_TOP, "left-top")
|
||||
ENUM_MAPPING(LEFT_CENTER, "left-center")
|
||||
ENUM_MAPPING(LEFT_BOTTOM, "left-bottom")
|
||||
|
||||
ENUM_MAPPING(CENTER_TOP, "center-top")
|
||||
ENUM_MAPPING(CENTER_CENTER, "center-center")
|
||||
ENUM_MAPPING(CENTER_BOTTOM, "center-bottom")
|
||||
|
||||
ENUM_MAPPING(RIGHT_TOP, "right-top")
|
||||
ENUM_MAPPING(RIGHT_CENTER, "right-center")
|
||||
ENUM_MAPPING(RIGHT_BOTTOM, "right-bottom")
|
||||
|
||||
ENUM_MAPPING(LEFT_BASE_LINE, "left-baseline")
|
||||
ENUM_MAPPING(CENTER_BASE_LINE, "center-baseline")
|
||||
ENUM_MAPPING(RIGHT_BASE_LINE, "right-baseline")
|
||||
|
||||
ENUM_MAPPING(LEFT_BOTTOM_BASE_LINE, "left-bottom-baseline")
|
||||
ENUM_MAPPING(CENTER_BOTTOM_BASE_LINE, "center-bottom-baseline")
|
||||
ENUM_MAPPING(RIGHT_BOTTOM_BASE_LINE, "right-bottom-baseline")
|
184
src/Canvas/elements/text.cxx
Normal file
184
src/Canvas/elements/text.cxx
Normal file
|
@ -0,0 +1,184 @@
|
|||
// A text on the canvas
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 "text.hxx"
|
||||
#include <osgText/Text>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Text::Text(SGPropertyNode* node):
|
||||
Element(node, COLOR | COLOR_FILL | BOUNDING_BOX),
|
||||
_text( new osgText::Text )
|
||||
{
|
||||
_drawable = _text;
|
||||
_text->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
|
||||
|
||||
// font size and property node
|
||||
float character_size = _node->getFloatValue("size", 32);
|
||||
_text->setCharacterSize( character_size );
|
||||
_node->setFloatValue("size", character_size);
|
||||
|
||||
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
|
||||
geode->addDrawable(_text);
|
||||
_transform->addChild(geode);
|
||||
|
||||
_node->tie
|
||||
(
|
||||
"alignment",
|
||||
SGRawValueMethods<Text, const char*>
|
||||
(
|
||||
*this,
|
||||
&Text::getAlignment,
|
||||
&Text::setAlignment
|
||||
)
|
||||
);
|
||||
_node->tie
|
||||
(
|
||||
"padding",
|
||||
SGRawValueMethods<osgText::Text, float>
|
||||
(
|
||||
*_text.get(),
|
||||
&osgText::Text::getBoundingBoxMargin,
|
||||
&osgText::Text::setBoundingBoxMargin
|
||||
)
|
||||
);
|
||||
typedef SGRawValueMethods<osgText::Text, int> TextIntMethods;
|
||||
_node->tie
|
||||
(
|
||||
"draw-mode",
|
||||
// TEXT = 1 default
|
||||
// BOUNDINGBOX = 2
|
||||
// FILLEDBOUNDINGBOX = 4
|
||||
// ALIGNMENT = 8
|
||||
TextIntMethods
|
||||
(
|
||||
*_text.get(),
|
||||
(TextIntMethods::getter_t)&osgText::Text::getDrawMode,
|
||||
(TextIntMethods::setter_t)&osgText::Text::setDrawMode
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Text::~Text()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::setFont(const char* name)
|
||||
{
|
||||
_text->setFont( getFont(name) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::setAlignment(const char* align)
|
||||
{
|
||||
const std::string align_string(align);
|
||||
if( 0 ) return;
|
||||
#define ENUM_MAPPING(enum_val, string_val) \
|
||||
else if( align_string == string_val )\
|
||||
_text->setAlignment( osgText::Text::enum_val );
|
||||
#include "text-alignment.hxx"
|
||||
#undef ENUM_MAPPING
|
||||
else
|
||||
_text->setAlignment(osgText::Text::LEFT_BASE_LINE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const char* Text::getAlignment() const
|
||||
{
|
||||
switch( _text->getAlignment() )
|
||||
{
|
||||
#define ENUM_MAPPING(enum_val, string_val) \
|
||||
case osgText::Text::enum_val:\
|
||||
return string_val;
|
||||
#include "text-alignment.hxx"
|
||||
#undef ENUM_MAPPING
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::childChanged(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getNameString() == "text" )
|
||||
_text->setText(child->getStringValue());
|
||||
else if( child->getNameString() == "size" )
|
||||
_text->setCharacterSize( child->getFloatValue() );
|
||||
else if( child->getNameString() == "font" )
|
||||
setFont( child->getStringValue() );
|
||||
else
|
||||
return;
|
||||
|
||||
_attributes_dirty |= BOUNDING_BOX;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::colorChanged(const osg::Vec4& color)
|
||||
{
|
||||
_text->setColor(color);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::colorFillChanged(const osg::Vec4& color)
|
||||
{
|
||||
_text->setBoundingBoxColor(color);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Text::font_ptr Text::getFont(const std::string& name)
|
||||
{
|
||||
SGPath path = globals->resolve_ressource_path("Fonts/" + name);
|
||||
if( path.isNull() )
|
||||
{
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_ALERT,
|
||||
"canvas::Text: No such font: " << name
|
||||
);
|
||||
return font_ptr();
|
||||
}
|
||||
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_INFO,
|
||||
"canvas::Text: using font file " << path.str()
|
||||
);
|
||||
|
||||
font_ptr font = osgText::readFontFile(path.c_str());
|
||||
if( !font )
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_ALERT,
|
||||
"canvas::Text: Failed to open font file " << path.c_str()
|
||||
);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
} // namespace canvas
|
56
src/Canvas/elements/text.hxx
Normal file
56
src/Canvas/elements/text.hxx
Normal file
|
@ -0,0 +1,56 @@
|
|||
// A text on the canvas
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 CANVAS_TEXT_HXX_
|
||||
#define CANVAS_TEXT_HXX_
|
||||
|
||||
#include "element.hxx"
|
||||
#include <osgText/Text>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class Text:
|
||||
public Element
|
||||
{
|
||||
public:
|
||||
Text(SGPropertyNode* node);
|
||||
virtual ~Text();
|
||||
|
||||
void setFont(const char* name);
|
||||
|
||||
void setAlignment(const char* align);
|
||||
const char* getAlignment() const;
|
||||
|
||||
protected:
|
||||
osg::ref_ptr<osgText::Text> _text;
|
||||
|
||||
virtual void childChanged(SGPropertyNode * child);
|
||||
virtual void colorChanged(const osg::Vec4& color);
|
||||
virtual void colorFillChanged(const osg::Vec4& color);
|
||||
|
||||
typedef osg::ref_ptr<osgText::Font> font_ptr;
|
||||
static font_ptr getFont(const std::string& name);
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
#endif /* CANVAS_TEXT_HXX_ */
|
|
@ -6,6 +6,10 @@
|
|||
//
|
||||
// Ported to OSG by Tim Moore - Jun 2007
|
||||
//
|
||||
// Heavily modified to be usable for the 2d Canvas by Thomas Geymayer - April 2012
|
||||
// Supports now multisampling/mipmapping, usage of the stencil buffer and placing
|
||||
// the texture in the scene by certain filter criteria
|
||||
//
|
||||
// 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
|
||||
|
@ -38,133 +42,399 @@
|
|||
#include <osg/StateSet>
|
||||
#include <osgDB/FileNameUtils>
|
||||
|
||||
#include <simgear/scene/material/EffectGeode.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Viewer/renderer.hxx>
|
||||
#include <Scenery/scenery.hxx>
|
||||
#include "od_gauge.hxx"
|
||||
|
||||
FGODGauge::FGODGauge() :
|
||||
#include <cassert>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGODGauge::FGODGauge():
|
||||
_size_x( -1 ),
|
||||
_size_y( -1 ),
|
||||
_view_width( -1 ),
|
||||
_view_height( -1 ),
|
||||
_use_image_coords( false ),
|
||||
_use_stencil( false ),
|
||||
_use_mipmapping( false ),
|
||||
_coverage_samples( 0 ),
|
||||
_color_samples( 0 ),
|
||||
rtAvailable( false )
|
||||
{
|
||||
}
|
||||
|
||||
void FGODGauge::allocRT ()
|
||||
{
|
||||
camera = new osg::Camera;
|
||||
// Only the far camera should trigger this texture to be rendered.
|
||||
camera->setNodeMask(simgear::BACKGROUND_BIT);
|
||||
camera->setProjectionMatrix(osg::Matrix::ortho2D(-textureWH/2.0, textureWH/2.0, -textureWH/2.0, textureWH/2.0));
|
||||
camera->setViewport(0, 0, textureWH, textureWH);
|
||||
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
camera->setRenderOrder(osg::Camera::PRE_RENDER);
|
||||
camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
camera->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f , 0.0f));
|
||||
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::FRAME_BUFFER);
|
||||
osg::StateSet* stateSet = camera->getOrCreateStateSet();
|
||||
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
stateSet->setAttributeAndModes(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,
|
||||
osg::PolygonMode::FILL),
|
||||
osg::StateAttribute::ON);
|
||||
stateSet->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::GREATER,
|
||||
0.0f),
|
||||
osg::StateAttribute::ON);
|
||||
stateSet->setAttribute(new osg::ShadeModel(osg::ShadeModel::FLAT));
|
||||
stateSet->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA,
|
||||
osg::BlendFunc::ONE_MINUS_SRC_ALPHA),
|
||||
osg::StateAttribute::ON);
|
||||
if (!texture.valid()) {
|
||||
texture = new osg::Texture2D;
|
||||
texture->setTextureSize(textureWH, textureWH);
|
||||
texture->setInternalFormat(GL_RGBA);
|
||||
texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
|
||||
texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
|
||||
}
|
||||
camera->attach(osg::Camera::COLOR_BUFFER, texture.get());
|
||||
globals->get_renderer()->addCamera(camera.get(), false);
|
||||
rtAvailable = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGODGauge::~FGODGauge()
|
||||
{
|
||||
if (camera.valid()) {
|
||||
globals->get_renderer()->removeCamera(camera.get());
|
||||
}
|
||||
if( camera.valid() )
|
||||
globals->get_renderer()->removeCamera(camera.get());
|
||||
}
|
||||
|
||||
void FGODGauge::setSize(int viewSize)
|
||||
//------------------------------------------------------------------------------
|
||||
void FGODGauge::setSize(int size_x, int size_y)
|
||||
{
|
||||
textureWH = viewSize;
|
||||
if (texture.valid()) {
|
||||
texture->setTextureSize(textureWH, textureWH);
|
||||
}
|
||||
_size_x = size_x;
|
||||
_size_y = size_y < 0 ? size_x : size_y;
|
||||
|
||||
if( texture.valid() )
|
||||
texture->setTextureSize(_size_x, _size_x);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void FGODGauge::setViewSize(int width, int height)
|
||||
{
|
||||
_view_width = width;
|
||||
_view_height = height < 0 ? width : height;
|
||||
|
||||
if( camera )
|
||||
updateCoordinateFrame();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FGODGauge::useImageCoords(bool use)
|
||||
{
|
||||
if( use == _use_image_coords )
|
||||
return;
|
||||
|
||||
_use_image_coords = use;
|
||||
|
||||
if( texture )
|
||||
updateCoordinateFrame();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FGODGauge::useStencil(bool use)
|
||||
{
|
||||
if( use == _use_stencil )
|
||||
return;
|
||||
|
||||
_use_stencil = use;
|
||||
|
||||
if( texture )
|
||||
updateStencil();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FGODGauge::setSampling( bool mipmapping,
|
||||
int coverage_samples,
|
||||
int color_samples )
|
||||
{
|
||||
if( _use_mipmapping == mipmapping
|
||||
&& _coverage_samples == coverage_samples
|
||||
&& _color_samples == color_samples )
|
||||
return;
|
||||
|
||||
_use_mipmapping = mipmapping;
|
||||
|
||||
if( color_samples > coverage_samples )
|
||||
{
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_WARN,
|
||||
"FGODGauge::setSampling: color_samples > coverage_samples not allowed!"
|
||||
);
|
||||
color_samples = coverage_samples;
|
||||
}
|
||||
|
||||
_coverage_samples = coverage_samples;
|
||||
_color_samples = color_samples;
|
||||
|
||||
updateSampling();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool FGODGauge::serviceable(void)
|
||||
{
|
||||
return rtAvailable;
|
||||
return rtAvailable;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FGODGauge::allocRT(osg::NodeCallback* camera_cull_callback)
|
||||
{
|
||||
camera = new osg::Camera;
|
||||
camera->setDataVariance(osg::Object::DYNAMIC);
|
||||
// Only the far camera should trigger this texture to be rendered.
|
||||
camera->setNodeMask(simgear::BACKGROUND_BIT);
|
||||
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
camera->setRenderOrder(osg::Camera::PRE_RENDER);
|
||||
camera->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f , 0.0f));
|
||||
camera->setClearStencil(0);
|
||||
camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT,
|
||||
osg::Camera::FRAME_BUFFER );
|
||||
|
||||
if( camera_cull_callback )
|
||||
camera->setCullCallback(camera_cull_callback);
|
||||
|
||||
updateCoordinateFrame();
|
||||
updateStencil();
|
||||
|
||||
osg::StateSet* stateSet = camera->getOrCreateStateSet();
|
||||
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
stateSet->setAttributeAndModes(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,
|
||||
osg::PolygonMode::FILL),
|
||||
osg::StateAttribute::ON);
|
||||
stateSet->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::GREATER,
|
||||
0.0f),
|
||||
osg::StateAttribute::ON);
|
||||
stateSet->setAttribute(new osg::ShadeModel(osg::ShadeModel::FLAT));
|
||||
stateSet->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA,
|
||||
osg::BlendFunc::ONE_MINUS_SRC_ALPHA),
|
||||
osg::StateAttribute::ON);
|
||||
if( !texture )
|
||||
{
|
||||
texture = new osg::Texture2D;
|
||||
texture->setTextureSize(_size_x, _size_y);
|
||||
texture->setInternalFormat(GL_RGBA);
|
||||
}
|
||||
|
||||
updateSampling();
|
||||
|
||||
globals->get_renderer()->addCamera(camera.get(), false);
|
||||
rtAvailable = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FGODGauge::updateCoordinateFrame()
|
||||
{
|
||||
assert( camera );
|
||||
|
||||
if( _view_width < 0 )
|
||||
_view_width = _size_x;
|
||||
if( _view_height < 0 )
|
||||
_view_height = _size_y;
|
||||
|
||||
camera->setViewport(0, 0, _size_x, _size_y);
|
||||
|
||||
if( _use_image_coords )
|
||||
camera->setProjectionMatrix(
|
||||
osg::Matrix::ortho2D(0, _view_width, _view_height, 0)
|
||||
);
|
||||
else
|
||||
camera->setProjectionMatrix(
|
||||
osg::Matrix::ortho2D( -_view_width/2., _view_width/2.,
|
||||
-_view_height/2., _view_height/2. )
|
||||
);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FGODGauge::updateStencil()
|
||||
{
|
||||
assert( camera );
|
||||
|
||||
GLbitfield mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
|
||||
|
||||
if( _use_stencil)
|
||||
{
|
||||
camera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER,
|
||||
GL_DEPTH_STENCIL_EXT );
|
||||
mask |= GL_STENCIL_BUFFER_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
camera->detach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER);
|
||||
}
|
||||
|
||||
camera->setClearMask(mask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FGODGauge::updateSampling()
|
||||
{
|
||||
assert( camera );
|
||||
assert( texture );
|
||||
|
||||
texture->setFilter(
|
||||
osg::Texture2D::MIN_FILTER,
|
||||
_use_mipmapping ? osg::Texture2D::LINEAR_MIPMAP_NEAREST
|
||||
: osg::Texture2D::LINEAR
|
||||
);
|
||||
camera->attach(
|
||||
osg::Camera::COLOR_BUFFER,
|
||||
texture.get(),
|
||||
0, 0,
|
||||
_use_mipmapping,
|
||||
_coverage_samples,
|
||||
_color_samples
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace a texture in the airplane model with the gauge texture.
|
||||
*/
|
||||
|
||||
class ReplaceStaticTextureVisitor : public osg::NodeVisitor
|
||||
class ReplaceStaticTextureVisitor:
|
||||
public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
ReplaceStaticTextureVisitor(const std::string& name,
|
||||
osg::Texture2D* _newTexture) :
|
||||
public:
|
||||
|
||||
ReplaceStaticTextureVisitor( const char* name,
|
||||
osg::Texture2D* new_texture ):
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
newTexture(_newTexture)
|
||||
_tex_name( osgDB::getSimpleFileName(name) ),
|
||||
_new_texture(new_texture)
|
||||
{}
|
||||
|
||||
ReplaceStaticTextureVisitor( const SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback = 0 ):
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
_tex_name( osgDB::getSimpleFileName(
|
||||
placement->getStringValue("texture"))
|
||||
),
|
||||
_node_name( placement->getStringValue("node") ),
|
||||
_parent_name( placement->getStringValue("parent") ),
|
||||
_new_texture(new_texture),
|
||||
_cull_callback(cull_callback)
|
||||
{
|
||||
textureFileName = osgDB::getSimpleFileName(name);
|
||||
if( _tex_name.empty()
|
||||
&& _node_name.empty()
|
||||
&& _parent_name.empty() )
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_WARN,
|
||||
"No filter criterion for replacing texture. "
|
||||
" Every texture will be replaced!"
|
||||
);
|
||||
}
|
||||
|
||||
virtual void apply(osg::Node& node)
|
||||
/**
|
||||
* Get a list of groups which have been inserted into the scene graph to
|
||||
* replace the given texture
|
||||
*/
|
||||
Placements& getPlacements()
|
||||
{
|
||||
osg::StateSet* ss = node.getStateSet();
|
||||
if (ss)
|
||||
changeStateSetTexture(ss);
|
||||
traverse(node);
|
||||
return _placements;
|
||||
}
|
||||
|
||||
virtual void apply(osg::Geode& node)
|
||||
{
|
||||
int numDrawables = node.getNumDrawables();
|
||||
for (int i = 0; i < numDrawables; i++) {
|
||||
osg::Drawable* drawable = node.getDrawable(i);
|
||||
osg::StateSet* ss = drawable->getStateSet();
|
||||
if (ss)
|
||||
changeStateSetTexture(ss);
|
||||
}
|
||||
traverse(node);
|
||||
}
|
||||
protected:
|
||||
void changeStateSetTexture(osg::StateSet *ss)
|
||||
{
|
||||
osg::Texture2D* tex
|
||||
= dynamic_cast<osg::Texture2D*>(ss->getTextureAttribute(0,
|
||||
osg::StateAttribute::TEXTURE));
|
||||
if (!tex || tex == newTexture || !tex->getImage())
|
||||
simgear::EffectGeode* eg = dynamic_cast<simgear::EffectGeode*>(&node);
|
||||
if( !eg )
|
||||
return;
|
||||
|
||||
osg::StateSet* ss = eg->getEffect()->getDefaultStateSet();
|
||||
if( !ss )
|
||||
return;
|
||||
|
||||
osg::Group *parent = node.getParent(0);
|
||||
if( !_node_name.empty() && parent->getName() != _node_name )
|
||||
return;
|
||||
|
||||
if( !_parent_name.empty() )
|
||||
{
|
||||
// Traverse nodes upwards starting at the parent node (skip current
|
||||
// node)
|
||||
const osg::NodePath& np = getNodePath();
|
||||
bool found = false;
|
||||
for( int i = static_cast<int>(np.size()) - 2; i >= 0; --i )
|
||||
{
|
||||
const osg::Node* path_segment = np[i];
|
||||
const osg::Node* path_parent = path_segment->getParent(0);
|
||||
|
||||
// A node without a name is always the parent of the root node of
|
||||
// the model just containing the file name
|
||||
if( path_parent && path_parent->getName().empty() )
|
||||
return;
|
||||
std::string fileName = tex->getImage()->getFileName();
|
||||
std::string simpleName = osgDB::getSimpleFileName(fileName);
|
||||
if (osgDB::equalCaseInsensitive(textureFileName, simpleName))
|
||||
ss->setTextureAttribute(0, newTexture);
|
||||
|
||||
if( path_segment->getName() == _parent_name )
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !found )
|
||||
return;
|
||||
}
|
||||
|
||||
for( size_t unit = 0; unit < ss->getNumTextureAttributeLists(); ++unit )
|
||||
{
|
||||
osg::Texture2D* tex = dynamic_cast<osg::Texture2D*>
|
||||
(
|
||||
ss->getTextureAttribute(unit, osg::StateAttribute::TEXTURE)
|
||||
);
|
||||
|
||||
if( !tex || !tex->getImage() || tex == _new_texture )
|
||||
continue;
|
||||
|
||||
if( !_tex_name.empty() )
|
||||
{
|
||||
std::string tex_name = tex->getImage()->getFileName();
|
||||
std::string tex_name_simple = osgDB::getSimpleFileName(tex_name);
|
||||
if( !osgDB::equalCaseInsensitive(_tex_name, tex_name_simple) )
|
||||
continue;
|
||||
}
|
||||
|
||||
// insert a new group between the geode an it's parent which overrides
|
||||
// the texture
|
||||
osg::ref_ptr<osg::Group> group = new osg::Group;
|
||||
group->setName("canvas texture group");
|
||||
group->addChild(eg);
|
||||
parent->removeChild(eg);
|
||||
parent->addChild(group);
|
||||
|
||||
if( _cull_callback )
|
||||
group->setCullCallback(_cull_callback);
|
||||
|
||||
_placements.push_back(group);
|
||||
|
||||
osg::StateSet* stateSet = group->getOrCreateStateSet();
|
||||
stateSet->setTextureAttribute( unit, _new_texture,
|
||||
osg::StateAttribute::OVERRIDE );
|
||||
stateSet->setTextureMode( unit, GL_TEXTURE_2D,
|
||||
osg::StateAttribute::ON );
|
||||
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_INFO,
|
||||
"Replaced texture '" << _tex_name << "'"
|
||||
<< " for object '" << parent->getName() << "'"
|
||||
<< (!_parent_name.empty() ? " with parent '" + _parent_name + "'"
|
||||
: "")
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::string textureFileName;
|
||||
osg::Texture2D* newTexture;
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
std::string _tex_name, ///<! Name of texture to be replaced
|
||||
_node_name, ///<! Only replace if node name matches
|
||||
_parent_name; ///<! Only replace if any parent node matches
|
||||
/// given name (all the tree upwards)
|
||||
osg::Texture2D *_new_texture;
|
||||
osg::NodeCallback *_cull_callback;
|
||||
|
||||
Placements _placements;
|
||||
};
|
||||
|
||||
void FGODGauge::set_texture(const char * name, osg::Texture2D* new_texture)
|
||||
//------------------------------------------------------------------------------
|
||||
Placements FGODGauge::set_texture(const char* name, osg::Texture2D* new_texture)
|
||||
{
|
||||
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
|
||||
ReplaceStaticTextureVisitor visitor(name, new_texture);
|
||||
root->accept(visitor);
|
||||
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
|
||||
ReplaceStaticTextureVisitor visitor(name, new_texture);
|
||||
root->accept(visitor);
|
||||
return visitor.getPlacements();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Placements FGODGauge::set_texture( const SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback )
|
||||
{
|
||||
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
|
||||
ReplaceStaticTextureVisitor visitor(placement, new_texture, cull_callback);
|
||||
root->accept(visitor);
|
||||
return visitor.getPlacements();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
//
|
||||
// Ported to OSG by Tim Moore - Jun 2007
|
||||
//
|
||||
// Heavily modified to be usable for the 2d Canvas by Thomas Geymayer - April 2012
|
||||
// Supports now multisampling/mipmapping, usage of the stencil buffer and placing
|
||||
// the texture in the scene by certain filter criteria
|
||||
//
|
||||
// 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
|
||||
|
@ -25,14 +29,17 @@
|
|||
#ifndef _OD_GAUGE_HXX
|
||||
#define _OD_GAUGE_HXX
|
||||
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/NodeCallback>
|
||||
#include <osg/Group>
|
||||
|
||||
namespace osg {
|
||||
class Camera;
|
||||
class Texture2D;
|
||||
}
|
||||
|
||||
class SGPropertyNode;
|
||||
typedef std::vector<osg::ref_ptr<osg::Group> > Placements;
|
||||
|
||||
/**
|
||||
* Owner Drawn Gauge helper class.
|
||||
*/
|
||||
|
@ -42,11 +49,53 @@ public:
|
|||
FGODGauge();
|
||||
virtual ~FGODGauge();
|
||||
|
||||
|
||||
void setSize(int viewSize);
|
||||
int size() const
|
||||
{ return textureWH; }
|
||||
/**
|
||||
* Set the size of the render target.
|
||||
*
|
||||
* @param size_x X size
|
||||
* @param size_y Y size. Defaults to size_x if not specified
|
||||
*/
|
||||
void setSize(int size_x, int size_y = -1);
|
||||
|
||||
/**
|
||||
* Set the size of the viewport
|
||||
*
|
||||
* @param width
|
||||
* @param height Defaults to width if not specified
|
||||
*/
|
||||
void setViewSize(int width, int height = -1);
|
||||
|
||||
/**
|
||||
* DEPRECATED
|
||||
*
|
||||
* Get size of squared texture
|
||||
*/
|
||||
int size() const { return _size_x; }
|
||||
|
||||
/**
|
||||
* Set whether to use image coordinates or not.
|
||||
*
|
||||
* Default: origin == center of texture
|
||||
* Image Coords: origin == top left corner
|
||||
*/
|
||||
void useImageCoords(bool use = true);
|
||||
|
||||
/**
|
||||
* Enable/Disable using a stencil buffer
|
||||
*/
|
||||
void useStencil(bool use = true);
|
||||
|
||||
/**
|
||||
* Set sampling parameters for mipmapping and coverage sampling
|
||||
* antialiasing.
|
||||
*
|
||||
* @note color_samples is not allowed to be higher than coverage_samples
|
||||
*
|
||||
*/
|
||||
void setSampling( bool mipmapping,
|
||||
int coverage_samples = 0,
|
||||
int color_samples = 0 );
|
||||
|
||||
/**
|
||||
* Say if we can render to a texture.
|
||||
* @return true if rtt is available
|
||||
|
@ -58,8 +107,27 @@ public:
|
|||
* This is to replace a static texture by a dynamic one
|
||||
* @param name texture filename
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
* @return A list of groups which override the given texture
|
||||
*/
|
||||
void set_texture(const char * name, osg::Texture2D* new_texture);
|
||||
Placements set_texture(const char * name, osg::Texture2D* new_texture);
|
||||
|
||||
/**
|
||||
* Replace an opengl texture name inside the aircraft scene graph.
|
||||
* This is to replace a static texture by a dynamic one. The replacement
|
||||
* is base on certain filtering criteria which have to be stored in string
|
||||
* value childs of the placement node. Recognized nodes are:
|
||||
* - texture Match the name of the texture
|
||||
* - node Match the name of the object
|
||||
* - parent Match any of the object parents names (all the tree upwards)
|
||||
* @param placement the node containing the replacement criteria
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
* @param an optional cull callback which will be installed on any matching
|
||||
* object
|
||||
* @return A list of groups which override the given texture
|
||||
*/
|
||||
Placements set_texture( const SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback = 0 );
|
||||
|
||||
/**
|
||||
* Get the OSG camera for drawing this gauge.
|
||||
|
@ -67,17 +135,32 @@ public:
|
|||
osg::Camera* getCamera() { return camera.get(); }
|
||||
|
||||
osg::Texture2D* getTexture() { return texture.get(); }
|
||||
void setTexture(osg::Texture2D* t) { texture = t; }
|
||||
//void setTexture(osg::Texture2D* t) { texture = t; }
|
||||
|
||||
// Real initialization function. Bad name.
|
||||
void allocRT(void);
|
||||
void allocRT(osg::NodeCallback* camera_cull_callback = 0);
|
||||
|
||||
private:
|
||||
int textureWH;
|
||||
int _size_x,
|
||||
_size_y,
|
||||
_view_width,
|
||||
_view_height;
|
||||
bool _use_image_coords,
|
||||
_use_stencil,
|
||||
_use_mipmapping;
|
||||
|
||||
// Multisampling parameters
|
||||
int _coverage_samples,
|
||||
_color_samples;
|
||||
|
||||
bool rtAvailable;
|
||||
osg::ref_ptr<osg::Camera> camera;
|
||||
osg::ref_ptr<osg::Texture2D> texture;
|
||||
|
||||
void updateCoordinateFrame();
|
||||
void updateStencil();
|
||||
void updateSampling();
|
||||
|
||||
};
|
||||
|
||||
#endif // _OD_GAUGE_HXX
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
#include <Cockpit/panel.hxx>
|
||||
#include <Cockpit/panel_io.hxx>
|
||||
|
||||
#include <Canvas/canvas_mgr.hxx>
|
||||
#include <GUI/new_gui.hxx>
|
||||
#include <Input/input.hxx>
|
||||
#include <Instrumentation/instrument_mgr.hxx>
|
||||
|
@ -1158,6 +1159,11 @@ bool fgInitSubsystems() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
fgGetBool("/sim/rendering/bump-mapping", false);
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Initialize the canvas 2d drawing subsystem.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
globals->add_subsystem("Canvas2D", new CanvasMgr, SGSubsystemMgr::DISPLAY);
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Initialise the ATIS Manager
|
||||
// Note that this is old stuff, but is necessary for the
|
||||
|
|
|
@ -335,6 +335,12 @@ SGPath FGGlobals::resolve_maybe_aircraft_path(const std::string& branch) const
|
|||
return simgear::ResourceManager::instance()->findPath(branch);
|
||||
}
|
||||
|
||||
SGPath FGGlobals::resolve_ressource_path(const std::string& branch) const
|
||||
{
|
||||
return simgear::ResourceManager::instance()
|
||||
->findPath(branch, SGPath(fgGetString("/sim/aircraft-dir")));
|
||||
}
|
||||
|
||||
FGRenderer *
|
||||
FGGlobals::get_renderer () const
|
||||
{
|
||||
|
|
|
@ -215,6 +215,15 @@ public:
|
|||
*/
|
||||
SGPath resolve_maybe_aircraft_path(const std::string& branch) const;
|
||||
|
||||
/**
|
||||
* Search in the following directories:
|
||||
*
|
||||
* 1. Root directory of current aircraft (defined by /sim/aircraft-dir)
|
||||
* 2. All aircraft directories if branch starts with Aircraft/
|
||||
* 3. fg_data directory
|
||||
*/
|
||||
SGPath resolve_ressource_path(const std::string& branch) const;
|
||||
|
||||
inline const std::string &get_browser () const { return browser; }
|
||||
void set_browser (const std::string &b) { browser = b; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue