Canvas - the FlightGear 2D drawing API |
|
|
|
RFC |
|
|
Frameworks |
|
|
Tutorials |
|
|
Reference |
|
|
Related |
|
|
To be ported |
|
|
Deprecated by Canvas |
|
(click on headings to toggle) |
|
This article is intended to be a sandbox for Canvas related ideas/enhancements, including code snippets, patches and boilerplate code for integration layer changes to implement new elements. Readers are generally assumed to be familiar with Building FlightGear, Git for laymen and Canvas Development, as well as C++ and OpenSceneGraph basics.
Each element/idea shown below should have a "references" section, including an introductory paragraph explaining the motivation for the corresponding feature, linking back to the original discussions on the devel list/forum or issue tracker.
On the other hand, some elements/patches below are merely intended to serve as examples/reference for people interested in implementing similar functionality at some point. So just because an element is shown here, does not necessarily mean that it is required in FlightGear.
Also, each paragraph contains patched using the diff format, so that people should be familiar with applying patches to their SG/FG source trees respectively (using git apply
).
Preferably, each paragraph should have a list of pointers (e.g. tutorials) to cover introductory topics (e.g. osg::Camera setup, rendering to a texture etc).
The topics covered below should be listed with ascending complexity, to ensure that the learning curve is not too step..
Most of these features/ideas are not yet ready for "prime time", but they have been repeatedly discussed by contributors, so that it makes sense to archive useful ideas/patches and let them grow over time.
People are invited to test these ideas/patches and get involved in developing these further, even if just by helping update the wiki accordingly.
CanvasAnimation
Note For the time being this is probably the most important addition from a performance standpoint, because it will help dramatically reduce Nasal related overhead in the main loop, while also using native OSG data structures for handling animations.
Supporting native OSG animations will also be beneficial to Unifying the 2D rendering backend via canvas, i.e. for porting the existing HUD/2D panels legacy code to OSG.
|
Animations are currently not handled by any Canvas/OSG code directly - instead, Nasal callbacks (using timers and listeners) are used to emulate animations.
However, this is relatively expensive - on the one hand because it is using Nasal to update scene graph related data structures, and on the other hand because the resulting scenegraph itself is relatively low-level, i.e. OSG does not even know that the scenegraph is used for implementing an animation.
In other words, most Nasal code currently used to update Canvas elements/textures is basically about "animating" child nodes using Nasal callbacks, which is reflecting badly upon Canvas based features, because of the massive performance overhead due to all the required Nasal code.
On the other hand, OSG does provide built-in APIs to provide support for various kinds of animations, so it would make sense to expose this at the Canvas::Element level, so that people using Canvas to implement animations can stop using Nasal, and instead use native OSG code.
The de-facto reference are the animation related child classes inheriting from osg::Group: http://trac.openscenegraph.org/documentation/OpenSceneGraphReferenceDocs/a00357.html
Specifically, these are:
Using just these three APIs, we can come up with a single Canvas::Animation class that supports all important animations, without going through Nasal space unnecessarily.
In addition, it would be possible to map animation callbacks to property rules to use C++ instead of Nasal for more sophisticated purposes.
You will want to add a new Canvas::Element
subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).
For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).
Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.
To create a new element, you need to create a new child class which inherits from Canvas::Element
base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.
To add a new element, these are the main steps:
- Set up a working build environment (including simgear): Building FlightGear
- update/pull simgear,flightgear and fgdata
- check out a new set of topic branches for each repo: git checkout -b topic/canvas-Animation
- Navigate to $SG_SRC/canvas/elements
- Create a new set of files Animation.cxx/.hxx (as per Adding a new Canvas element)
- add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
- edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
- begin replacing the stubs with your own C++ code
- map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
- alternatively, consider using dedicated Nasal/CppBind bindings
Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:
Step #1 is editing $SG_SRC/canvas/elements/CMakeLists.txt to add our set of new files
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0..08f9857 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
CanvasMap.hxx
CanvasPath.hxx
CanvasText.hxx
+ CanvasAnimation.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
CanvasMap.cxx
CanvasPath.cxx
CanvasText.cxx
+ CanvasAnimation.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp
LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
Animation: Canvas Animation support (minimal C++ changes)
Step #2 is creating the new files for our C++ code
diff --git a/simgear/canvas/elements/CanvasAnimation.cxx b/simgear/canvas/elements/CanvasAnimation.cxx
new file mode 100644
index 0000000..8004245
--- /dev/null
+++ b/simgear/canvas/elements/CanvasAnimation.cxx
@@ -0,0 +1,87 @@
+// Animation.cxx: Stub for exposing OSG animation support as a dedicated Canvas element
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "CanvasAnimation.hxx"
+
+
+namespace simgear
+{
+namespace canvas
+{
+ const std::string Animation::TYPE_NAME = "animation";
+ //----------------------------------------------------------------------------
+ void Animation::staticInit()
+ {
+ Element::staticInit();
+
+ if( isInit<Animation>() )
+ return;
+
+ // Do some initialization if needed...
+ }
+
+ //----------------------------------------------------------------------------
+ Animation::Animation( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent ):
+ Element(canvas, node, parent_style, parent)
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Animation element added!");
+ }
+
+ //----------------------------------------------------------------------------
+ Animation::~Animation()
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Animation element removed!");
+ }
+
+ //----------------------------------------------------------------------------
+ void Animation::update(double dt)
+ {
+ Element::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void Animation::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Element::childAdded(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Animation::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Element::childRemoved(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Animation::valueChanged(SGPropertyNode* child)
+ {
+ return Element::valueChanged(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Animation::childChanged(SGPropertyNode* child)
+ {
+ }
+
+ //----------------------------------------------------------------------------
+
+} // namespace canvas
+} // namespace simgear
+
diff --git a/simgear/canvas/elements/CanvasAnimation.hxx b/simgear/canvas/elements/CanvasAnimation.hxx
new file mode 100644
index 0000000..1cd4062
--- /dev/null
+++ b/simgear/canvas/elements/CanvasAnimation.hxx
@@ -0,0 +1,61 @@
+// CanvasAnimation.hxx: Stub for exposing OSG animation support as a dedicated Canvas element
+//
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef CANVAS_ANIMATION_HXX_
+#define CANVAS_ANIMATION_HXX_
+
+#include "CanvasElement.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+ class Animation:
+ public Element
+ {
+ public:
+ static const std::string TYPE_NAME;
+ static void staticInit();
+
+ Animation( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent = 0 );
+ virtual ~Animation();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_ANIMATION_HXX_ */
Animation: Canvas Animation support (registering the new element)
Step #3 is modifying CanvasGroup.cxx to register our new element
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index de289a8..49fa2c1 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -21,6 +21,8 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasAnimation.hxx"
+
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -64,6 +66,8 @@ namespace canvas
add<Map >(_child_factories);
add<Path >(_child_factories);
add<Text >(_child_factories);
+ // add Animation
+ add<Animation>(_child_factories);
}
//----------------------------------------------------------------------------
Animation: Canvas Animation support $FG_ROOT/Nasal/canvas/api.nas changes
Step #4 is extending api.nas to provide Nasal wrappers for the new element (note, the corresponding fgdata structure has been updated recently)
diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 6d39d03..f98fdd9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1099,13 +1099,21 @@ var Image = {
}
};
+var Animation = {
+ new: func(ghost)
+ {
+ return {parents: [Animation, Element.new(ghost)]};
+ },
+};
+
# Element factories used by #Group elements to create children
Group._element_factories = {
"group": Group.new,
"map": Map.new,
"text": Text.new,
"path": Path.new,
- "image": Image.new
+ "image": Image.new,
+ "animation": Animation.new,
};
Animation: Canvas Animation support (testing the new element using the
Nasal Console)
Step #5
var (width,height) = (320,320);
var title = 'Canvas Element test: Animation';
# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var child = root.createChild("animation");
# your code goes here
CanvasShape
Screen shot showing a custom canvas element wrapping osg::Shape
As a simple proof-of-concept, we can begin by exposing osg::Shape as a dedicated Canvas element:
osg::Shape* sphere = new osg::Sphere(osg::Vec3(10.0f, 10.0f, 10.0f), 5.0f);
osg::ShapeDrawable* sphereDrawable = new osg::ShapeDrawable(sphere);
osg::Geode* sphereGeode = new osg::Geode();
sphereGeode->addDrawable(sphereDrawable);
Compared to SVG/OpenVG (ShivaVG) based drawing, the main benefit is that we can create and display 3D objects, using correct orientation/projection in a 3D scene, including even custom texturing by using images from disk, or other Canvas textures.
In addition, OSG provides support for a shapeDrawable based heightfield class that can be used for generating terrain meshes procedurally.
The code shown above, can simple be added to the constructor of the canvas element, but we will want to render it to a texture using a PositionAttitudeTransformMatric and map those to properties in the sub-tree of the canvas element.
You will want to add a new Canvas::Element
subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).
For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).
Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.
To create a new element, you need to create a new child class which inherits from Canvas::Element
base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.
To add a new element, these are the main steps:
- Set up a working build environment (including simgear): Building FlightGear
- update/pull simgear,flightgear and fgdata
- check out a new set of topic branches for each repo: git checkout -b topic/canvas-Shape
- Navigate to $SG_SRC/canvas/elements
- Create a new set of files Shape.cxx/.hxx (as per Adding a new Canvas element)
- add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
- edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
- begin replacing the stubs with your own C++ code
- map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
- alternatively, consider using dedicated Nasal/CppBind bindings
Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:
Step #1 is editing $SG_SRC/canvas/elements/CMakeLists.txt to add our set of new files
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0..08f9857 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
CanvasMap.hxx
CanvasPath.hxx
CanvasText.hxx
+ CanvasShape.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
CanvasMap.cxx
CanvasPath.cxx
CanvasText.cxx
+ CanvasShape.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp
LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
Shape: Canvas osg::Shape (minimal C++ changes)
Step #2 is creating the new files for our C++ code
diff --git a/simgear/canvas/elements/CanvasShape.cxx b/simgear/canvas/elements/CanvasShape.cxx
new file mode 100644
index 0000000..8004245
--- /dev/null
+++ b/simgear/canvas/elements/CanvasShape.cxx
@@ -0,0 +1,87 @@
+// Shape.cxx: Stub for exposing OSG::shapeDrawable support as a dedicated Canvas element
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "CanvasShape.hxx"
+
+
+namespace simgear
+{
+namespace canvas
+{
+ const std::string Shape::TYPE_NAME = "shape";
+ //----------------------------------------------------------------------------
+ void Shape::staticInit()
+ {
+ Element::staticInit();
+
+ if( isInit<Shape>() )
+ return;
+
+ // Do some initialization if needed...
+ }
+
+ //----------------------------------------------------------------------------
+ Shape::Shape( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent ):
+ Element(canvas, node, parent_style, parent)
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Shape element added!");
+ }
+
+ //----------------------------------------------------------------------------
+ Shape::~Shape()
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Shape element removed!");
+ }
+
+ //----------------------------------------------------------------------------
+ void Shape::update(double dt)
+ {
+ Element::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void Shape::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Element::childAdded(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Shape::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Element::childRemoved(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Shape::valueChanged(SGPropertyNode* child)
+ {
+ return Element::valueChanged(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Shape::childChanged(SGPropertyNode* child)
+ {
+ }
+
+ //----------------------------------------------------------------------------
+
+} // namespace canvas
+} // namespace simgear
+
diff --git a/simgear/canvas/elements/CanvasShape.hxx b/simgear/canvas/elements/CanvasShape.hxx
new file mode 100644
index 0000000..1cd4062
--- /dev/null
+++ b/simgear/canvas/elements/CanvasShape.hxx
@@ -0,0 +1,61 @@
+// CanvasShape.hxx: Stub for exposing OSG::shapeDrawable support as a dedicated Canvas element
+//
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef CANVAS_SHAPE_HXX_
+#define CANVAS_SHAPE_HXX_
+
+#include "CanvasElement.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+ class Shape:
+ public Element
+ {
+ public:
+ static const std::string TYPE_NAME;
+ static void staticInit();
+
+ Shape( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent = 0 );
+ virtual ~Shape();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_SHAPE_HXX_ */
Shape: Canvas osg::Shape (registering the new element)
Step #3 is modifying CanvasGroup.cxx to register our new element
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index de289a8..49fa2c1 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -21,6 +21,8 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasShape.hxx"
+
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -64,6 +66,8 @@ namespace canvas
add<Map >(_child_factories);
add<Path >(_child_factories);
add<Text >(_child_factories);
+ // add Shape
+ add<Shape>(_child_factories);
}
//----------------------------------------------------------------------------
Shape: Canvas osg::Shape $FG_ROOT/Nasal/canvas/api.nas changes
Step #4 is extending api.nas to provide Nasal wrappers for the new element (note, the corresponding fgdata structure has been updated recently)
diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 6d39d03..f98fdd9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1099,13 +1099,21 @@ var Image = {
}
};
+var Shape = {
+ new: func(ghost)
+ {
+ return {parents: [Shape, Element.new(ghost)]};
+ },
+};
+
# Element factories used by #Group elements to create children
Group._element_factories = {
"group": Group.new,
"map": Map.new,
"text": Text.new,
"path": Path.new,
- "image": Image.new
+ "image": Image.new,
+ "shape": Shape.new,
};
Shape: Canvas osg::Shape (testing the new element using the
Nasal Console)
Step #5
var (width,height) = (320,320);
var title = 'Canvas Element test: Shape';
# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var child = root.createChild("shape");
# your code goes here
CanvasShapefile
See also [2] (GDAL/OGR support in SimGear)
|
When we have vector road data at runtime, we can do the following:
- render it in moving-map displays - either real ones (Garmin G1000 / G430) or the map dialog
- use it to drive building outline creation as Thomas was suggesting
- animate traffic on the roads, as point lights at night or even meshes in daytime (the important one...)
- generate tile overlay textures dynamically (and based on view distance) to show the roads on the terrain surface. (And the detail of this texture can include road markings / borders based on distance from the viewer / view angle / etc)
|
|
You will want to add a new Canvas::Element
subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).
For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).
Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.
To create a new element, you need to create a new child class which inherits from Canvas::Element
base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.
To add a new element, these are the main steps:
- Set up a working build environment (including simgear): Building FlightGear
- update/pull simgear,flightgear and fgdata
- check out a new set of topic branches for each repo: git checkout -b topic/canvas-Shapefile
- Navigate to $SG_SRC/canvas/elements
- Create a new set of files Shapefile.cxx/.hxx (as per Adding a new Canvas element)
- add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
- edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
- begin replacing the stubs with your own C++ code
- map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
- alternatively, consider using dedicated Nasal/CppBind bindings
Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:
Step #1 is editing $SG_SRC/canvas/elements/CMakeLists.txt to add our set of new files
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0..08f9857 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
CanvasMap.hxx
CanvasPath.hxx
CanvasText.hxx
+ CanvasShapefile.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
CanvasMap.cxx
CanvasPath.cxx
CanvasText.cxx
+ CanvasShapefile.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp
LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
Shapefile: Canvas ESRI Shapefile (minimal C++ changes)
Step #2 is creating the new files for our C++ code
diff --git a/simgear/canvas/elements/CanvasShapefile.cxx b/simgear/canvas/elements/CanvasShapefile.cxx
new file mode 100644
index 0000000..8004245
--- /dev/null
+++ b/simgear/canvas/elements/CanvasShapefile.cxx
@@ -0,0 +1,87 @@
+// Shapefile.cxx: Stub for exposing OSG/GDAL shapefile support as a dedicated Canvas element
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "CanvasShapefile.hxx"
+
+
+namespace simgear
+{
+namespace canvas
+{
+ const std::string Shapefile::TYPE_NAME = "shapefile";
+ //----------------------------------------------------------------------------
+ void Shapefile::staticInit()
+ {
+ Image::staticInit();
+
+ if( isInit<Shapefile>() )
+ return;
+
+ // Do some initialization if needed...
+ }
+
+ //----------------------------------------------------------------------------
+ Shapefile::Shapefile( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent ):
+ Image(canvas, node, parent_style, parent)
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Shapefile element added!");
+ }
+
+ //----------------------------------------------------------------------------
+ Shapefile::~Shapefile()
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Shapefile element removed!");
+ }
+
+ //----------------------------------------------------------------------------
+ void Shapefile::update(double dt)
+ {
+ Image::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void Shapefile::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childAdded(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Shapefile::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childRemoved(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Shapefile::valueChanged(SGPropertyNode* child)
+ {
+ return Image::valueChanged(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Shapefile::childChanged(SGPropertyNode* child)
+ {
+ }
+
+ //----------------------------------------------------------------------------
+
+} // namespace canvas
+} // namespace simgear
+
diff --git a/simgear/canvas/elements/CanvasShapefile.hxx b/simgear/canvas/elements/CanvasShapefile.hxx
new file mode 100644
index 0000000..1cd4062
--- /dev/null
+++ b/simgear/canvas/elements/CanvasShapefile.hxx
@@ -0,0 +1,61 @@
+// CanvasShapefile.hxx: Stub for exposing OSG/GDAL shapefile support as a dedicated Canvas element
+//
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef CANVAS_SHAPEFILE_HXX_
+#define CANVAS_SHAPEFILE_HXX_
+
+#include "CanvasImage.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+ class Shapefile:
+ public Image
+ {
+ public:
+ static const std::string TYPE_NAME;
+ static void staticInit();
+
+ Shapefile( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent = 0 );
+ virtual ~Shapefile();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_SHAPEFILE_HXX_ */
Shapefile: Canvas ESRI Shapefile (registering the new element)
Step #3 is modifying CanvasGroup.cxx to register our new element
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index de289a8..49fa2c1 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -21,6 +21,8 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasShapefile.hxx"
+
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -64,6 +66,8 @@ namespace canvas
add<Map >(_child_factories);
add<Path >(_child_factories);
add<Text >(_child_factories);
+ // add Shapefile
+ add<Shapefile>(_child_factories);
}
//----------------------------------------------------------------------------
Shapefile: Canvas ESRI Shapefile $FG_ROOT/Nasal/canvas/api.nas changes
Step #4 is extending api.nas to provide Nasal wrappers for the new element (note, the corresponding fgdata structure has been updated recently)
diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 6d39d03..f98fdd9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1099,13 +1099,21 @@ var Image = {
}
};
+var Shapefile = {
+ new: func(ghost)
+ {
+ return {parents: [Shapefile, Element.new(ghost)]};
+ },
+};
+
# Element factories used by #Group elements to create children
Group._element_factories = {
"group": Group.new,
"map": Map.new,
"text": Text.new,
"path": Path.new,
- "image": Image.new
+ "image": Image.new,
+ "shapefile": Shapefile.new,
};
Shapefile: Canvas ESRI Shapefile (testing the new element using the
Nasal Console)
Step #5
var (width,height) = (320,320);
var title = 'Canvas Element test: Shapefile';
# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var child = root.createChild("shapefile");
# your code goes here
CanvasHeightField
|
can you give me an idea on how to use od_gauge to continuously render a camera view to texture? I don't really know much about it but then every says that Project Rembrandt involves continuous rendering to texture.And, is there a way to get terrain as a view? I mean, sorta like changing the color based on terrain. Oh, and I'd also need to place my own texture on the terrain, instead of the materials textures..So, that's not just using od_gauge, for a terrain view, I'd need to actually re-render the whole terrain with some extra stuff...
|
|
|
Such a 3D view would be best accomplished by using a scenery child cam, and applying custom effects/shaders to it - but for that, we would need to expose effects/shaders to Canvas::Element.
Alternatively, it would also be possible to come up with a custom "heightfield" element using osg.:HeightField: http://trac.openscenegraph.org/documentation/OpenSceneGraphReferenceDocs/a00364.html
http://osghelp.com/?p=163
It would be relatively straightforward to turn this into a custom Canvas::Element and even hook it up to the built-in terrain presampler, using a configurable resolution.
Anybody familiar with building from source, using git and willing to work through a handful of OSG tutorials should be able to come up with a working "heightfield" element to support such synthetic terrain views.
|
|
|
Instead of using the terrain sampler, it may be faster to create the mesh directly from the scenegraph in c++ space. we already do this in the LOD callback to place the random trees and buildings. We then have a triangle mesh.
|
|
You will want to add a new Canvas::Element
subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).
For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).
Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.
To create a new element, you need to create a new child class which inherits from Canvas::Element
base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.
To add a new element, these are the main steps:
- Set up a working build environment (including simgear): Building FlightGear
- update/pull simgear,flightgear and fgdata
- check out a new set of topic branches for each repo: git checkout -b topic/canvas-Heightfield
- Navigate to $SG_SRC/canvas/elements
- Create a new set of files Heightfield.cxx/.hxx (as per Adding a new Canvas element)
- add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
- edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
- begin replacing the stubs with your own C++ code
- map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
- alternatively, consider using dedicated Nasal/CppBind bindings
Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:
Step #1 is editing $SG_SRC/canvas/elements/CMakeLists.txt to add our set of new files
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0..08f9857 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
CanvasMap.hxx
CanvasPath.hxx
CanvasText.hxx
+ CanvasHeightfield.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
CanvasMap.cxx
CanvasPath.cxx
CanvasText.cxx
+ CanvasHeightfield.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp
LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
Heightfield: Canvas Heightfield (minimal C++ changes)
Step #2 is creating the new files for our C++ code
diff --git a/simgear/canvas/elements/CanvasHeightfield.cxx b/simgear/canvas/elements/CanvasHeightfield.cxx
new file mode 100644
index 0000000..8004245
--- /dev/null
+++ b/simgear/canvas/elements/CanvasHeightfield.cxx
@@ -0,0 +1,87 @@
+// Heightfield.cxx: Stub for exposing osg::Heightfield support as a dedicated Canvas element [http://forum.flightgear.org/viewtopic.php?f=71&t=27985]
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "CanvasHeightfield.hxx"
+
+
+namespace simgear
+{
+namespace canvas
+{
+ const std::string Heightfield::TYPE_NAME = "heightfield";
+ //----------------------------------------------------------------------------
+ void Heightfield::staticInit()
+ {
+ Element::staticInit();
+
+ if( isInit<Heightfield>() )
+ return;
+
+ // Do some initialization if needed...
+ }
+
+ //----------------------------------------------------------------------------
+ Heightfield::Heightfield( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent ):
+ Element(canvas, node, parent_style, parent)
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Heightfield element added!");
+ }
+
+ //----------------------------------------------------------------------------
+ Heightfield::~Heightfield()
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Heightfield element removed!");
+ }
+
+ //----------------------------------------------------------------------------
+ void Heightfield::update(double dt)
+ {
+ Element::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void Heightfield::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Element::childAdded(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Heightfield::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Element::childRemoved(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Heightfield::valueChanged(SGPropertyNode* child)
+ {
+ return Element::valueChanged(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Heightfield::childChanged(SGPropertyNode* child)
+ {
+ }
+
+ //----------------------------------------------------------------------------
+
+} // namespace canvas
+} // namespace simgear
+
diff --git a/simgear/canvas/elements/CanvasHeightfield.hxx b/simgear/canvas/elements/CanvasHeightfield.hxx
new file mode 100644
index 0000000..1cd4062
--- /dev/null
+++ b/simgear/canvas/elements/CanvasHeightfield.hxx
@@ -0,0 +1,61 @@
+// CanvasHeightfield.hxx: Stub for exposing osg::Heightfield support as a dedicated Canvas element [http://forum.flightgear.org/viewtopic.php?f=71&t=27985]
+//
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef CANVAS_HEIGHTFIELD_HXX_
+#define CANVAS_HEIGHTFIELD_HXX_
+
+#include "CanvasElement.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+ class Heightfield:
+ public Element
+ {
+ public:
+ static const std::string TYPE_NAME;
+ static void staticInit();
+
+ Heightfield( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent = 0 );
+ virtual ~Heightfield();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_HEIGHTFIELD_HXX_ */
Heightfield: Canvas Heightfield (registering the new element)
Step #3 is modifying CanvasGroup.cxx to register our new element
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index de289a8..49fa2c1 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -21,6 +21,8 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasHeightfield.hxx"
+
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -64,6 +66,8 @@ namespace canvas
add<Map >(_child_factories);
add<Path >(_child_factories);
add<Text >(_child_factories);
+ // add Heightfield
+ add<Heightfield>(_child_factories);
}
//----------------------------------------------------------------------------
Heightfield: Canvas Heightfield $FG_ROOT/Nasal/canvas/api.nas changes
Step #4 is extending api.nas to provide Nasal wrappers for the new element (note, the corresponding fgdata structure has been updated recently)
diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 6d39d03..f98fdd9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1099,13 +1099,21 @@ var Image = {
}
};
+var Heightfield = {
+ new: func(ghost)
+ {
+ return {parents: [Heightfield, Element.new(ghost)]};
+ },
+};
+
# Element factories used by #Group elements to create children
Group._element_factories = {
"group": Group.new,
"map": Map.new,
"text": Text.new,
"path": Path.new,
- "image": Image.new
+ "image": Image.new,
+ "heightfield": Heightfield.new,
};
Heightfield: Canvas Heightfield (testing the new element using the
Nasal Console)
Step #5
var (width,height) = (320,320);
var title = 'Canvas Element test: Heightfield';
# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var child = root.createChild("heightfield");
# your code goes here
CanvasMovingMap
|
I'd really like to use the Atlas generated maps as a layer in the browser map. Is anybody out there looking for an adventure and is able to modify the Atlas map generator to generate maps on-the-fly? Input would be three parameters: z/x/y where z is the zoom level and x/y are numeric parameters describing latitude and longitude (based on image size). Output should be a generated tile of 256x256 and format png in a memory buffer.
|
|
a large benefit for using the raw DEM will be for moving maps - the elevation is pretty much displayable as-is.[1]
You will want to add a new Canvas::Element
subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).
For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).
Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.
To create a new element, you need to create a new child class which inherits from Canvas::Element
base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.
To add a new element, these are the main steps:
- Set up a working build environment (including simgear): Building FlightGear
- update/pull simgear,flightgear and fgdata
- check out a new set of topic branches for each repo: git checkout -b topic/canvas-MovingMap
- Navigate to $SG_SRC/canvas/elements
- Create a new set of files MovingMap.cxx/.hxx (as per Adding a new Canvas element)
- add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
- edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
- begin replacing the stubs with your own C++ code
- map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
- alternatively, consider using dedicated Nasal/CppBind bindings
Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:
Step #1 is editing $SG_SRC/canvas/elements/CMakeLists.txt to add our set of new files
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0..08f9857 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
CanvasMap.hxx
CanvasPath.hxx
CanvasText.hxx
+ CanvasMovingMap.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
CanvasMap.cxx
CanvasPath.cxx
CanvasText.cxx
+ CanvasMovingMap.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp
LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
MovingMap: Canvas MovingMap (minimal C++ changes)
Step #2 is creating the new files for our C++ code
diff --git a/simgear/canvas/elements/CanvasMovingMap.cxx b/simgear/canvas/elements/CanvasMovingMap.cxx
new file mode 100644
index 0000000..8004245
--- /dev/null
+++ b/simgear/canvas/elements/CanvasMovingMap.cxx
@@ -0,0 +1,87 @@
+// MovingMap.cxx: Stub for exposing moving map support as a dedicated Canvas element
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "CanvasMovingMap.hxx"
+
+
+namespace simgear
+{
+namespace canvas
+{
+ const std::string MovingMap::TYPE_NAME = "movingmap";
+ //----------------------------------------------------------------------------
+ void MovingMap::staticInit()
+ {
+ Image::staticInit();
+
+ if( isInit<MovingMap>() )
+ return;
+
+ // Do some initialization if needed...
+ }
+
+ //----------------------------------------------------------------------------
+ MovingMap::MovingMap( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent ):
+ Image(canvas, node, parent_style, parent)
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New MovingMap element added!");
+ }
+
+ //----------------------------------------------------------------------------
+ MovingMap::~MovingMap()
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New MovingMap element removed!");
+ }
+
+ //----------------------------------------------------------------------------
+ void MovingMap::update(double dt)
+ {
+ Image::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void MovingMap::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childAdded(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void MovingMap::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childRemoved(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void MovingMap::valueChanged(SGPropertyNode* child)
+ {
+ return Image::valueChanged(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void MovingMap::childChanged(SGPropertyNode* child)
+ {
+ }
+
+ //----------------------------------------------------------------------------
+
+} // namespace canvas
+} // namespace simgear
+
diff --git a/simgear/canvas/elements/CanvasMovingMap.hxx b/simgear/canvas/elements/CanvasMovingMap.hxx
new file mode 100644
index 0000000..1cd4062
--- /dev/null
+++ b/simgear/canvas/elements/CanvasMovingMap.hxx
@@ -0,0 +1,61 @@
+// CanvasMovingMap.hxx: Stub for exposing moving map support as a dedicated Canvas element
+//
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef CANVAS_MOVINGMAP_HXX_
+#define CANVAS_MOVINGMAP_HXX_
+
+#include "CanvasImage.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+ class MovingMap:
+ public Image
+ {
+ public:
+ static const std::string TYPE_NAME;
+ static void staticInit();
+
+ MovingMap( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent = 0 );
+ virtual ~MovingMap();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_MOVINGMAP_HXX_ */
MovingMap: Canvas MovingMap (registering the new element)
Step #3 is modifying CanvasGroup.cxx to register our new element
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index de289a8..49fa2c1 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -21,6 +21,8 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasMovingMap.hxx"
+
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -64,6 +66,8 @@ namespace canvas
add<Map >(_child_factories);
add<Path >(_child_factories);
add<Text >(_child_factories);
+ // add MovingMap
+ add<MovingMap>(_child_factories);
}
//----------------------------------------------------------------------------
MovingMap: Canvas MovingMap $FG_ROOT/Nasal/canvas/api.nas changes
Step #4 is extending api.nas to provide Nasal wrappers for the new element (note, the corresponding fgdata structure has been updated recently)
diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 6d39d03..f98fdd9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1099,13 +1099,21 @@ var Image = {
}
};
+var MovingMap = {
+ new: func(ghost)
+ {
+ return {parents: [MovingMap, Element.new(ghost)]};
+ },
+};
+
# Element factories used by #Group elements to create children
Group._element_factories = {
"group": Group.new,
"map": Map.new,
"text": Text.new,
"path": Path.new,
- "image": Image.new
+ "image": Image.new,
+ "movingmap": MovingMap.new,
};
MovingMap: Canvas MovingMap (testing the new element using the
Nasal Console)
Step #5
var (width,height) = (320,320);
var title = 'Canvas Element test: MovingMap';
# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var child = root.createChild("movingmap");
# your code goes here
CanvasGeoTIFF
You will want to add a new Canvas::Element
subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).
For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).
Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.
To create a new element, you need to create a new child class which inherits from Canvas::Element
base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.
To add a new element, these are the main steps:
- Set up a working build environment (including simgear): Building FlightGear
- update/pull simgear,flightgear and fgdata
- check out a new set of topic branches for each repo: git checkout -b topic/canvas-GeoTIFF
- Navigate to $SG_SRC/canvas/elements
- Create a new set of files GeoTIFF.cxx/.hxx (as per Adding a new Canvas element)
- add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
- edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
- begin replacing the stubs with your own C++ code
- map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
- alternatively, consider using dedicated Nasal/CppBind bindings
Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:
Step #1 is editing $SG_SRC/canvas/elements/CMakeLists.txt to add our set of new files
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0..08f9857 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
CanvasMap.hxx
CanvasPath.hxx
CanvasText.hxx
+ CanvasGeoTIFF.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
CanvasMap.cxx
CanvasPath.cxx
CanvasText.cxx
+ CanvasGeoTIFF.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp
LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
GeoTIFF: Canvas GeoTIFF (minimal C++ changes)
Step #2 is creating the new files for our C++ code
diff --git a/simgear/canvas/elements/CanvasGeoTIFF.cxx b/simgear/canvas/elements/CanvasGeoTIFF.cxx
new file mode 100644
index 0000000..8004245
--- /dev/null
+++ b/simgear/canvas/elements/CanvasGeoTIFF.cxx
@@ -0,0 +1,87 @@
+// GeoTIFF.cxx: Stub for exposing GeoTIFF support as a dedicated Canvas element
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "CanvasGeoTIFF.hxx"
+
+
+namespace simgear
+{
+namespace canvas
+{
+ const std::string GeoTIFF::TYPE_NAME = "geotiff";
+ //----------------------------------------------------------------------------
+ void GeoTIFF::staticInit()
+ {
+ Image::staticInit();
+
+ if( isInit<GeoTIFF>() )
+ return;
+
+ // Do some initialization if needed...
+ }
+
+ //----------------------------------------------------------------------------
+ GeoTIFF::GeoTIFF( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent ):
+ Image(canvas, node, parent_style, parent)
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New GeoTIFF element added!");
+ }
+
+ //----------------------------------------------------------------------------
+ GeoTIFF::~GeoTIFF()
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New GeoTIFF element removed!");
+ }
+
+ //----------------------------------------------------------------------------
+ void GeoTIFF::update(double dt)
+ {
+ Image::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void GeoTIFF::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childAdded(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void GeoTIFF::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childRemoved(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void GeoTIFF::valueChanged(SGPropertyNode* child)
+ {
+ return Image::valueChanged(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void GeoTIFF::childChanged(SGPropertyNode* child)
+ {
+ }
+
+ //----------------------------------------------------------------------------
+
+} // namespace canvas
+} // namespace simgear
+
diff --git a/simgear/canvas/elements/CanvasGeoTIFF.hxx b/simgear/canvas/elements/CanvasGeoTIFF.hxx
new file mode 100644
index 0000000..1cd4062
--- /dev/null
+++ b/simgear/canvas/elements/CanvasGeoTIFF.hxx
@@ -0,0 +1,61 @@
+// CanvasGeoTIFF.hxx: Stub for exposing GeoTIFF support as a dedicated Canvas element
+//
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef CANVAS_GEOTIFF_HXX_
+#define CANVAS_GEOTIFF_HXX_
+
+#include "CanvasImage.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+ class GeoTIFF:
+ public Image
+ {
+ public:
+ static const std::string TYPE_NAME;
+ static void staticInit();
+
+ GeoTIFF( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent = 0 );
+ virtual ~GeoTIFF();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_GEOTIFF_HXX_ */
GeoTIFF: Canvas GeoTIFF (registering the new element)
Step #3 is modifying CanvasGroup.cxx to register our new element
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index de289a8..49fa2c1 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -21,6 +21,8 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasGeoTIFF.hxx"
+
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -64,6 +66,8 @@ namespace canvas
add<Map >(_child_factories);
add<Path >(_child_factories);
add<Text >(_child_factories);
+ // add GeoTIFF
+ add<GeoTIFF>(_child_factories);
}
//----------------------------------------------------------------------------
GeoTIFF: Canvas GeoTIFF $FG_ROOT/Nasal/canvas/api.nas changes
Step #4 is extending api.nas to provide Nasal wrappers for the new element (note, the corresponding fgdata structure has been updated recently)
diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 6d39d03..f98fdd9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1099,13 +1099,21 @@ var Image = {
}
};
+var GeoTIFF = {
+ new: func(ghost)
+ {
+ return {parents: [GeoTIFF, Element.new(ghost)]};
+ },
+};
+
# Element factories used by #Group elements to create children
Group._element_factories = {
"group": Group.new,
"map": Map.new,
"text": Text.new,
"path": Path.new,
- "image": Image.new
+ "image": Image.new,
+ "geotiff": GeoTIFF.new,
};
GeoTIFF: Canvas GeoTIFF (testing the new element using the
Nasal Console)
Step #5
var (width,height) = (320,320);
var title = 'Canvas Element test: GeoTIFF';
# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var child = root.createChild("geotiff");
# your code goes here
CanvasPDF
Checking the examples in the osg source tree, the demo rendering a PDF to a osg::Node is fairly compelling and extremely compact, requiring only ~15 lines of code github/openscenegraph/osg/examples/osgpdf/osgpdf.cpp
#include <osgWidget/PdfReader>
// ...
osg::ref_ptr<osgWidget::PdfReader> pdfReader = new osgWidget::PdfReader;
if (pdfReader->open(path)) {
root->addChild(pdfReader.get());
}
Screenshot showing the unmodified osgpdf example which loads a pdf file, renders it to a surface and adds it to the osgviewer scene
So all that is needed is including the osgWidget/PdfReader header and editing the top-level CMakeListst.txt file in sgsrc/fgsrc to ensure that osgWidget is added as a required library in the find_package() call:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5e3b905..c32f830 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -203,7 +203,7 @@ else()
message(STATUS "Sound support: ENABLED")
endif(ENABLE_SOUND)
- find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgViewer osgUtil)
+ find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgViewer osgUtil osgWidget)
endif(SIMGEAR_HEADLESS)
find_package(ZLIB REQUIRED)
Next, we need to edit the constructor accordingly, and make sure that the osg::Node is added to the _transform member of the CanvasElement we are creating.
That will already give us a new element that renders a PDF file to the Cavas.
osgpdf demo wrapped in a CanvasElement, showing the FlightGear manual
To see how the file name can be changed/updated using properties, it makes sense to open CanvasImage.cxx and check how it is working there, so that we can copy/paste and adapt the code accordingly.
To turn this into a proper element, we can next open the header itself and check what methods are available, so that these can be exposed via Canvas properties
You will want to add a new Canvas::Element
subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).
For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).
Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.
To create a new element, you need to create a new child class which inherits from Canvas::Element
base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.
To add a new element, these are the main steps:
- Set up a working build environment (including simgear): Building FlightGear
- update/pull simgear,flightgear and fgdata
- check out a new set of topic branches for each repo: git checkout -b topic/canvas-PDF
- Navigate to $SG_SRC/canvas/elements
- Create a new set of files PDF.cxx/.hxx (as per Adding a new Canvas element)
- add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
- edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
- begin replacing the stubs with your own C++ code
- map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
- alternatively, consider using dedicated Nasal/CppBind bindings
Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:
Step #1 is editing $SG_SRC/canvas/elements/CMakeLists.txt to add our set of new files
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0..08f9857 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
CanvasMap.hxx
CanvasPath.hxx
CanvasText.hxx
+ CanvasPDF.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
CanvasMap.cxx
CanvasPath.cxx
CanvasText.cxx
+ CanvasPDF.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp
LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
PDF: Canvas PDF (minimal C++ changes)
Step #2 is creating the new files for our C++ code
diff --git a/simgear/canvas/elements/CanvasPDF.cxx b/simgear/canvas/elements/CanvasPDF.cxx
new file mode 100644
index 0000000..8004245
--- /dev/null
+++ b/simgear/canvas/elements/CanvasPDF.cxx
@@ -0,0 +1,87 @@
+// PDF.cxx: Stub for exposing OSG PDF support as a dedicated Canvas element
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "CanvasPDF.hxx"
+
+
+namespace simgear
+{
+namespace canvas
+{
+ const std::string PDF::TYPE_NAME = "pdf";
+ //----------------------------------------------------------------------------
+ void PDF::staticInit()
+ {
+ Image::staticInit();
+
+ if( isInit<PDF>() )
+ return;
+
+ // Do some initialization if needed...
+ }
+
+ //----------------------------------------------------------------------------
+ PDF::PDF( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent ):
+ Image(canvas, node, parent_style, parent)
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New PDF element added!");
+ }
+
+ //----------------------------------------------------------------------------
+ PDF::~PDF()
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New PDF element removed!");
+ }
+
+ //----------------------------------------------------------------------------
+ void PDF::update(double dt)
+ {
+ Image::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void PDF::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childAdded(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void PDF::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childRemoved(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void PDF::valueChanged(SGPropertyNode* child)
+ {
+ return Image::valueChanged(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void PDF::childChanged(SGPropertyNode* child)
+ {
+ }
+
+ //----------------------------------------------------------------------------
+
+} // namespace canvas
+} // namespace simgear
+
diff --git a/simgear/canvas/elements/CanvasPDF.hxx b/simgear/canvas/elements/CanvasPDF.hxx
new file mode 100644
index 0000000..1cd4062
--- /dev/null
+++ b/simgear/canvas/elements/CanvasPDF.hxx
@@ -0,0 +1,61 @@
+// CanvasPDF.hxx: Stub for exposing OSG PDF support as a dedicated Canvas element
+//
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef CANVAS_PDF_HXX_
+#define CANVAS_PDF_HXX_
+
+#include "CanvasImage.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+ class PDF:
+ public Image
+ {
+ public:
+ static const std::string TYPE_NAME;
+ static void staticInit();
+
+ PDF( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent = 0 );
+ virtual ~PDF();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_PDF_HXX_ */
PDF: Canvas PDF (registering the new element)
Step #3 is modifying CanvasGroup.cxx to register our new element
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index de289a8..49fa2c1 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -21,6 +21,8 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasPDF.hxx"
+
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -64,6 +66,8 @@ namespace canvas
add<Map >(_child_factories);
add<Path >(_child_factories);
add<Text >(_child_factories);
+ // add PDF
+ add<PDF>(_child_factories);
}
//----------------------------------------------------------------------------
PDF: Canvas PDF $FG_ROOT/Nasal/canvas/api.nas changes
Step #4 is extending api.nas to provide Nasal wrappers for the new element (note, the corresponding fgdata structure has been updated recently)
diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 6d39d03..f98fdd9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1099,13 +1099,21 @@ var Image = {
}
};
+var PDF = {
+ new: func(ghost)
+ {
+ return {parents: [PDF, Element.new(ghost)]};
+ },
+};
+
# Element factories used by #Group elements to create children
Group._element_factories = {
"group": Group.new,
"map": Map.new,
"text": Text.new,
"path": Path.new,
- "image": Image.new
+ "image": Image.new,
+ "pdf": PDF.new,
};
PDF: Canvas PDF (testing the new element using the
Nasal Console)
Step #5
var (width,height) = (320,320);
var title = 'Canvas Element test: PDF';
# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var child = root.createChild("pdf");
# your code goes here
Next, we need to look at the OSG examples to see how a PDF file can be opened and rendered to a texture.
CanvasModel
Screen shot showing a custom canvas element for loading/displaying arbitrary 3D models
Screen shot showing a custom canvas element for loading/displaying arbitrary 3D models (rotated perspective)
You will want to add a new Canvas::Element
subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).
For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).
Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.
To create a new element, you need to create a new child class which inherits from Canvas::Element
base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.
To add a new element, these are the main steps:
- Set up a working build environment (including simgear): Building FlightGear
- update/pull simgear,flightgear and fgdata
- check out a new set of topic branches for each repo: git checkout -b topic/canvas-Model
- Navigate to $SG_SRC/canvas/elements
- Create a new set of files Model.cxx/.hxx (as per Adding a new Canvas element)
- add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
- edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
- begin replacing the stubs with your own C++ code
- map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
- alternatively, consider using dedicated Nasal/CppBind bindings
Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:
Step #1 is editing $SG_SRC/canvas/elements/CMakeLists.txt to add our set of new files
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0..08f9857 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
CanvasMap.hxx
CanvasPath.hxx
CanvasText.hxx
+ CanvasModel.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
CanvasMap.cxx
CanvasPath.cxx
CanvasText.cxx
+ CanvasModel.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp
LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
Model: Canvas Model (minimal C++ changes)
Step #2 is creating the new files for our C++ code
diff --git a/simgear/canvas/elements/CanvasModel.cxx b/simgear/canvas/elements/CanvasModel.cxx
new file mode 100644
index 0000000..8004245
--- /dev/null
+++ b/simgear/canvas/elements/CanvasModel.cxx
@@ -0,0 +1,87 @@
+// Model.cxx: Stub for exposing OSG/SG model loading support as a dedicated Canvas element
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "CanvasModel.hxx"
+
+
+namespace simgear
+{
+namespace canvas
+{
+ const std::string Model::TYPE_NAME = "model";
+ //----------------------------------------------------------------------------
+ void Model::staticInit()
+ {
+ Image::staticInit();
+
+ if( isInit<Model>() )
+ return;
+
+ // Do some initialization if needed...
+ }
+
+ //----------------------------------------------------------------------------
+ Model::Model( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent ):
+ Image(canvas, node, parent_style, parent)
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Model element added!");
+ }
+
+ //----------------------------------------------------------------------------
+ Model::~Model()
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Model element removed!");
+ }
+
+ //----------------------------------------------------------------------------
+ void Model::update(double dt)
+ {
+ Image::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void Model::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childAdded(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Model::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childRemoved(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Model::valueChanged(SGPropertyNode* child)
+ {
+ return Image::valueChanged(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Model::childChanged(SGPropertyNode* child)
+ {
+ }
+
+ //----------------------------------------------------------------------------
+
+} // namespace canvas
+} // namespace simgear
+
diff --git a/simgear/canvas/elements/CanvasModel.hxx b/simgear/canvas/elements/CanvasModel.hxx
new file mode 100644
index 0000000..1cd4062
--- /dev/null
+++ b/simgear/canvas/elements/CanvasModel.hxx
@@ -0,0 +1,61 @@
+// CanvasModel.hxx: Stub for exposing OSG/SG model loading support as a dedicated Canvas element
+//
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef CANVAS_MODEL_HXX_
+#define CANVAS_MODEL_HXX_
+
+#include "CanvasImage.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+ class Model:
+ public Image
+ {
+ public:
+ static const std::string TYPE_NAME;
+ static void staticInit();
+
+ Model( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent = 0 );
+ virtual ~Model();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_MODEL_HXX_ */
Model: Canvas Model (registering the new element)
Step #3 is modifying CanvasGroup.cxx to register our new element
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index de289a8..49fa2c1 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -21,6 +21,8 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasModel.hxx"
+
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -64,6 +66,8 @@ namespace canvas
add<Map >(_child_factories);
add<Path >(_child_factories);
add<Text >(_child_factories);
+ // add Model
+ add<Model>(_child_factories);
}
//----------------------------------------------------------------------------
Model: Canvas Model $FG_ROOT/Nasal/canvas/api.nas changes
Step #4 is extending api.nas to provide Nasal wrappers for the new element (note, the corresponding fgdata structure has been updated recently)
diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 6d39d03..f98fdd9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1099,13 +1099,21 @@ var Image = {
}
};
+var Model = {
+ new: func(ghost)
+ {
+ return {parents: [Model, Element.new(ghost)]};
+ },
+};
+
# Element factories used by #Group elements to create children
Group._element_factories = {
"group": Group.new,
"map": Map.new,
"text": Text.new,
"path": Path.new,
- "image": Image.new
+ "image": Image.new,
+ "model": Model.new,
};
Model: Canvas Model (testing the new element using the
Nasal Console)
Step #5
var (width,height) = (320,320);
var title = 'Canvas Element test: Model';
# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var child = root.createChild("model");
# your code goes here
Next, we need to set up a separate camera to render a sub-scenegraph to a texture - the corresponding OSG code to accomplish this can be taken from existing OSG examples[3][4]/tutorials[5][6][7][8], or we can directly use the ODGauge code in Simgear:
CanvasOsgEarthMap
This article or section contains out-of-date information
Please help improve this article by updating it. There may be additional information on the talk page.
|
https://gitorious.org/fg/hoorays-simgear?p=fg:hoorays-simgear.git;a=commitdiff;h=7382ece6fd0861cf379006d283fe253e210bfc8f
CanvasNasal
This is not directly a new element, it's just an abstract base class that can be used to register a factory of Nasal-space elements (think elements of a MFD like screens, pages etc). While that may be considered problematic from a performance standpoint (implementing new elements in Nasal), the idea is to expose the CanvasElement interface to Nasal space, so that developers can more easily prototype new elements in scripting space, and register those with the main Canvas::Group manager, without having to be proficient in C++.
Primarily, this is about enforcing a well-defined interface using properties.
Hopefully, this will allow fgdata developers to come up with features that are reusable and agnostic to the concrete use-case, as well as support independent instances and styling.
Which are basically the main challenges Canvas adoption is seeing/causing in fgdata in the last 3 years, i.e. tons of useful features that are highly specific to a single aircraft/use case, without supporting other use-cases, and without being sufficiently flexible and customizable.
Preferably, fgdata developers would use inheritance, composition and aggregation to design their Canvas-based features. However, that point is hard to bring across, and the only Canvas-related features that satisfy these requirements, are native Canvas elements using the Canvas::Element interface.
The key thing here is that we want to ensure that the Canvas system, and OSG itself, know what an element is all about, without all this knowledge having to exist solely in scripting space.
This is also the prerequisite for supporting multi-instance or multiplayer setups where Canvas-specific state may need to be propagated to multiple fgfs instances for replication:
|
I think of some kind of separation that will also be good if we would do HLA between a viewer and an application computing physical models or controlling an additional view hooking into a federate ...
|
|
|
I'm guessing it would be somewhat similar to ARINC661, and the actual arrangement of these widgets could be marked up in an XML file. The framework could render to a texture (for display in a 3D virtual cockpit), a memory buffer (for direct blitting onto the screen) or to a separate device context altogether (for an external display). Network support on this would be a really interesting feature -- allowing outboard 'dumb' cockpit displays to be run off a diskless thin client.
|
|
|
The layout might be similar to a VM, with high-level instructions to represent points, lines, rectangles, text, etc. The advantage of this is that it will set a predefined interface for displaying geometry but not define the low-level implementation.
|
|
|
If we're rendering each display as an OSG sub-camera, extracting that logic and wrapping it in a stand-alone OSG viewer should be simplicity itself - and so long as it's driven by properties, those can be sent over a socket. That's an approach which seems a lot more bearable to me than sending per-frame pixel surfaces over shared memory or sockets / pipes.
|
|
Which is to say, in an interlinked FlightGear setup, we want to avoid having to replicate low-level scenegraph information, but deal with a high-level representation, e.g. sending information about update a "navaid layer" rather than a "VOR symbol" or even a much lower-level "SVG/OpenVG group".
Dealing with Canvas features at the element level is the only sane way of doing so, but is causing quite some traffic for low-level primitives, so that it makes sense to introduce higher level elements for specific use-cases.
While it may seem ironic at first that moving the implementation of new elements to Nasal, all the internal handling logic would directly use the proper interface of Canvas::element
In turn, this would mean, that we can prototype new elements, e.g. to add a dedicated "navaid-layer" element, which can make safe assumptions about its contents and purpose, including not just visible state, but also internal state (center of the map, range, symbols to be displayed etc).
Once new elements have been refined and once they are proven, they could be partially/completely re-implemented in native C++ code, without any of the front-end code having to be changed.
You will want to add a new Canvas::Element
subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).
For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).
Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.
To create a new element, you need to create a new child class which inherits from Canvas::Element
base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.
To add a new element, these are the main steps:
- Set up a working build environment (including simgear): Building FlightGear
- update/pull simgear,flightgear and fgdata
- check out a new set of topic branches for each repo: git checkout -b topic/canvas-Nasal
- Navigate to $SG_SRC/canvas/elements
- Create a new set of files Nasal.cxx/.hxx (as per Adding a new Canvas element)
- add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
- edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
- begin replacing the stubs with your own C++ code
- map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
- alternatively, consider using dedicated Nasal/CppBind bindings
Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:
Nasal: Canvas::Element exposed to scripting space (required
cmake changes)
Step #1 is editing $SG_SRC/canvas/elements/CMakeLists.txt to add our set of new files
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0..08f9857 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
CanvasMap.hxx
CanvasPath.hxx
CanvasText.hxx
+ CanvasNasal.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
CanvasMap.cxx
CanvasPath.cxx
CanvasText.cxx
+ CanvasNasal.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp
LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
Nasal: Canvas::Element exposed to scripting space (minimal C++ changes)
Step #2 is creating the new files for our C++ code
diff --git a/simgear/canvas/elements/CanvasNasal.cxx b/simgear/canvas/elements/CanvasNasal.cxx
new file mode 100644
index 0000000..8004245
--- /dev/null
+++ b/simgear/canvas/elements/CanvasNasal.cxx
@@ -0,0 +1,87 @@
+// Nasal.cxx: Stub for exposing Canvas::Element a dedicated Nasal extension point
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "CanvasNasal.hxx"
+
+
+namespace simgear
+{
+namespace canvas
+{
+ const std::string Nasal::TYPE_NAME = "nasal";
+ //----------------------------------------------------------------------------
+ void Nasal::staticInit()
+ {
+ Element::staticInit();
+
+ if( isInit<Nasal>() )
+ return;
+
+ // Do some initialization if needed...
+ }
+
+ //----------------------------------------------------------------------------
+ Nasal::Nasal( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent ):
+ Element(canvas, node, parent_style, parent)
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Nasal element added!");
+ }
+
+ //----------------------------------------------------------------------------
+ Nasal::~Nasal()
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Nasal element removed!");
+ }
+
+ //----------------------------------------------------------------------------
+ void Nasal::update(double dt)
+ {
+ Element::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void Nasal::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Element::childAdded(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Nasal::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Element::childRemoved(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Nasal::valueChanged(SGPropertyNode* child)
+ {
+ return Element::valueChanged(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Nasal::childChanged(SGPropertyNode* child)
+ {
+ }
+
+ //----------------------------------------------------------------------------
+
+} // namespace canvas
+} // namespace simgear
+
diff --git a/simgear/canvas/elements/CanvasNasal.hxx b/simgear/canvas/elements/CanvasNasal.hxx
new file mode 100644
index 0000000..1cd4062
--- /dev/null
+++ b/simgear/canvas/elements/CanvasNasal.hxx
@@ -0,0 +1,61 @@
+// CanvasNasal.hxx: Stub for exposing Canvas::Element a dedicated Nasal extension point
+//
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef CANVAS_NASAL_HXX_
+#define CANVAS_NASAL_HXX_
+
+#include "CanvasElement.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+ class Nasal:
+ public Element
+ {
+ public:
+ static const std::string TYPE_NAME;
+ static void staticInit();
+
+ Nasal( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent = 0 );
+ virtual ~Nasal();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_NASAL_HXX_ */
Nasal: Canvas::Element exposed to scripting space (registering the new element)
Step #3 is modifying CanvasGroup.cxx to register our new element
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index de289a8..49fa2c1 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -21,6 +21,8 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasNasal.hxx"
+
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -64,6 +66,8 @@ namespace canvas
add<Map >(_child_factories);
add<Path >(_child_factories);
add<Text >(_child_factories);
+ // add Nasal
+ add<Nasal>(_child_factories);
}
//----------------------------------------------------------------------------
Nasal: Canvas::Element exposed to scripting space $FG_ROOT/Nasal/canvas/api.nas changes
Step #4 is extending api.nas to provide Nasal wrappers for the new element (note, the corresponding fgdata structure has been updated recently)
diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 6d39d03..f98fdd9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1099,13 +1099,21 @@ var Image = {
}
};
+var Nasal = {
+ new: func(ghost)
+ {
+ return {parents: [Nasal, Element.new(ghost)]};
+ },
+};
+
# Element factories used by #Group elements to create children
Group._element_factories = {
"group": Group.new,
"map": Map.new,
"text": Text.new,
"path": Path.new,
- "image": Image.new
+ "image": Image.new,
+ "nasal": Nasal.new,
};
Nasal: Canvas::Element exposed to scripting space (testing the new element using the
Nasal Console)
Step #5
var (width,height) = (320,320);
var title = 'Canvas Element test: Nasal';
# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var child = root.createChild("nasal");
# your code goes here
CanvasCamera
|
I've been working on improving the camera configuration system in FG. It is almost done, but needs some cleanup before I can put up a merge request. Here is the list of new features:
- Support for setting the rendering order of cameras
- Can set the clear mask (color, depth and stencil buffer separately)
- Can set the texture format in render-to-texture (which already was there, but had almost no use before this update), rgb, rgba, depth or depth-stencil at the moment.
- Can set the texture type (normalied 2d or rectangle)
- Support for multiple render targets, via just specifying multiple texture targets. This needs modification to shaders though, but works.
- Can set whether camera uses scene data or a custom model (e.g. screen aligned quad)
- Can bind render target textures to texture units for rendering to screen. (In the future should allow using these in models by specifying the texture name...)
|
|
You will want to add a new Canvas::Element
subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).
For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).
Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.
To create a new element, you need to create a new child class which inherits from Canvas::Element
base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.
To add a new element, these are the main steps:
- Set up a working build environment (including simgear): Building FlightGear
- update/pull simgear,flightgear and fgdata
- check out a new set of topic branches for each repo: git checkout -b topic/canvas-Camera
- Navigate to $SG_SRC/canvas/elements
- Create a new set of files Camera.cxx/.hxx (as per Adding a new Canvas element)
- add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
- edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
- begin replacing the stubs with your own C++ code
- map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
- alternatively, consider using dedicated Nasal/CppBind bindings
Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:
Step #1 is editing $SG_SRC/canvas/elements/CMakeLists.txt to add our set of new files
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0..08f9857 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
CanvasMap.hxx
CanvasPath.hxx
CanvasText.hxx
+ CanvasCamera.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
CanvasMap.cxx
CanvasPath.cxx
CanvasText.cxx
+ CanvasCamera.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp
LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
Camera: Canvas Camera (slaved) (minimal C++ changes)
Step #2 is creating the new files for our C++ code
diff --git a/simgear/canvas/elements/CanvasCamera.cxx b/simgear/canvas/elements/CanvasCamera.cxx
new file mode 100644
index 0000000..8004245
--- /dev/null
+++ b/simgear/canvas/elements/CanvasCamera.cxx
@@ -0,0 +1,87 @@
+// Camera.cxx: Stub for exposing OSG slaved cameras as a dedicated Canvas element
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#include "CanvasCamera.hxx"
+
+
+namespace simgear
+{
+namespace canvas
+{
+ const std::string Camera::TYPE_NAME = "camera";
+ //----------------------------------------------------------------------------
+ void Camera::staticInit()
+ {
+ Image::staticInit();
+
+ if( isInit<Camera>() )
+ return;
+
+ // Do some initialization if needed...
+ }
+
+ //----------------------------------------------------------------------------
+ Camera::Camera( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent ):
+ Image(canvas, node, parent_style, parent)
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Camera element added!");
+ }
+
+ //----------------------------------------------------------------------------
+ Camera::~Camera()
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "New Camera element removed!");
+ }
+
+ //----------------------------------------------------------------------------
+ void Camera::update(double dt)
+ {
+ Image::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void Camera::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childAdded(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Camera::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ return Image::childRemoved(parent, child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Camera::valueChanged(SGPropertyNode* child)
+ {
+ return Image::valueChanged(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Camera::childChanged(SGPropertyNode* child)
+ {
+ }
+
+ //----------------------------------------------------------------------------
+
+} // namespace canvas
+} // namespace simgear
+
diff --git a/simgear/canvas/elements/CanvasCamera.hxx b/simgear/canvas/elements/CanvasCamera.hxx
new file mode 100644
index 0000000..1cd4062
--- /dev/null
+++ b/simgear/canvas/elements/CanvasCamera.hxx
@@ -0,0 +1,61 @@
+// CanvasCamera.hxx: Stub for exposing OSG slaved cameras as a dedicated Canvas element
+//
+//
+// Copyright (C) 2015 your name
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+#ifndef CANVAS_CAMERA_HXX_
+#define CANVAS_CAMERA_HXX_
+
+#include "CanvasImage.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+ class Camera:
+ public Image
+ {
+ public:
+ static const std::string TYPE_NAME;
+ static void staticInit();
+
+ Camera( const CanvasWeakPtr& canvas,
+ const SGPropertyNode_ptr& node,
+ const Style& parent_style,
+ ElementWeakPtr parent = 0 );
+ virtual ~Camera();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_CAMERA_HXX_ */
Camera: Canvas Camera (slaved) (registering the new element)
Step #3 is modifying CanvasGroup.cxx to register our new element
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index de289a8..49fa2c1 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -21,6 +21,8 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasCamera.hxx"
+
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -64,6 +66,8 @@ namespace canvas
add<Map >(_child_factories);
add<Path >(_child_factories);
add<Text >(_child_factories);
+ // add Camera
+ add<Camera>(_child_factories);
}
//----------------------------------------------------------------------------
Camera: Canvas Camera (slaved) $FG_ROOT/Nasal/canvas/api.nas changes
Step #4 is extending api.nas to provide Nasal wrappers for the new element (note, the corresponding fgdata structure has been updated recently)
diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 6d39d03..f98fdd9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1099,13 +1099,21 @@ var Image = {
}
};
+var Camera = {
+ new: func(ghost)
+ {
+ return {parents: [Camera, Element.new(ghost)]};
+ },
+};
+
# Element factories used by #Group elements to create children
Group._element_factories = {
"group": Group.new,
"map": Map.new,
"text": Text.new,
"path": Path.new,
- "image": Image.new
+ "image": Image.new,
+ "camera": Camera.new,
};
Camera: Canvas Camera (slaved) (testing the new element using the
Nasal Console)
Step #5
var (width,height) = (320,320);
var title = 'Canvas Element test: Camera';
# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var child = root.createChild("camera");
# your code goes here
Next, we need to look at $FG_SRC/Viewer/CameraGroup.cxx to see how slave cameras are set up:
OSG slave camera rendered to an TextureRectangle
[1]
2D Plotting
Screen shot showing a Canvas GUI dialog with a custom MathGL element rendering a simple sine (proof-of-concept) - the point being, while simple stuff like this can certainly be renderered using our existing Canvas.Path element, more complex/mathematical expressions and functions are better handled by a dedicated plotting library, that is threaded and hardware accelerated (OpenGL+ GLSL).
This is the same custom MathGL Canvas element rendering a more complex 3D mesh/function, fully hardware accelerated using OpenGL and GLSL, including support for threaded number crunching in pthread-enabled MathGL builds
|
Trivial graphs can certainly be plotted using Nasal/Canvas (as per the screen shots/examples discussed above), but anything more complex (think multiple 2d/3d graphs) are unlikely to benefit from the explicit nature of using Canvas (OpenVG) for plotting purposes, keep in mind all the property I/O and setup overhead for otherwise identical graphs.
So anybody really wanting to do 2D/3D plotting (analogous to gnuplot), inside the fgfs main process, would be well-advised to use an existing library like MathGL (GPL, multi-platform), or GNU Octave, and expose this to Canvas as a custom element, specifically dedicated to 2d/3d plotting - possibly with Nasal/CppBind support:
|
|