White_dune developer documentation
"white_dune", what's that ?
"white_dune" is a continuation of the "dune" project by Stephan F. White.
"dune" is a graphical VRML97 Editor, simple NURBS modeller and animation
tool with some OpenGL scene rendering capabilities.
white_dune program overview
In princple, the structure of the white_dune program can be written as:
-
evaluate commandline parameters
-
enter GUI (Grapical User Interface) mainloop
For details, see the file main.cpp
white_dune GUI overview
The GUI of white_dune consists of 2 parts:
-
2D GUI
This handles two dimensional operations like opening windows,
display icons, menus, buttons etc.
2D GUI operations are seperated in a extra programming level,
called swt (Stephan White Toolkit).
Currently, there are two different implementations of swt written in C,
one for Motif/Lesstif (Unix/Linux) and one for Win32 (M$Windows).
For details, see the directory swt.
swt use M$Windows rc files. For details about non M$Windows
implementation see the directory swt/rc.
- 3D GUI
This handles three dimensional operations. This is displaying 3D data
(rendering, implemented in OpenGL) and manipulating 3D Objects.
Some 3D operations, like mouseinput and reaction to desktop events
(e.g. resize of Windows) are handled in connection with the 2D GUI
(see the file Scene3DView.cpp for details).
Additional, there are other sources of information for manipulating
3D Objects (also handled in Scene3DView.cpp): input from
devices like joystick, dialbox or spaceball. Code for input
from this devices is located in the file InputDevice.cpp.
The 2D GUI mainloop of white_dune is event driven. Typical events are
mouse-movement, mouse-click, resize of window and so on.
Additionally the mainloop can produce timer events.
When a event occures, the matching callback function is started.
The callbacks work for every subwindow of white_dune.
The following image shows the subwindows (red text) of the mainwindow.
Some 2D GUI events are distributed to the different subwindows.
The distribution of this events is based on inheritance.
The class SceneView define inheritable 2D GUI callbacks like
OnMouseMove and is parent class to the classes
ChannelView, FieldView, Scene3DView,
SceneGraphView, SceneTreeView, StatusBar,
ToolbarWindow and PanedWindow. PanedWindow is
parent class to the class MainWindow.
A additional callback OnUpdate is used to distribute
messages like UPDATE_FIELD or UPDATE_ADD_NODE to the
child classes of SceneView. OnUpdate is started by
the function UpdateViews of class Scene.
Some operations require additional input of data. Then a "Dialog"
is opened, that block the data input to all other windows.
*Dialog classes are all inheritable from the class Dialog,
which implements functions like SaveData() and Validate().
The layout of Dialogs (as well as the layout of the menues) is defined
in the dune*.rc files.
VRML implementation overview
The class Scene (Scene.h/cpp) can be identified with one VRML file.
For example Scene.write() writes the VRML file to disk.
The global variable TheApp of class DuneApp (DuneApp.h/cpp)
can be identified with things that are global to all VRML files.
The internals of each VRML Nodes are implemented in the files named
NodeNodeName (for example NodeTransform (NodeTransform.h/cpp),
NodeShape (NodeShape.h/cpp) or NodeBox (NodeBox.h/cpp)).
Every NodeNodeName.h file contain 2 classes: the
class NodeNodeName which contain functionality
like draw() for 3D rendering of shapes and the class
ProtoNodeName which are used to build the definitions
of the VRML97 standard.
For example, the definiton of the Transform Node in
the ISO/IEC 14772 standard

is implemented in the constructor of the class ProtoTransform
(in file NodeTransform.cpp):
ProtoTransform::ProtoTransform(Scene *scene)
: Proto(scene, "Transform")
{
addEventIn(MFNODE, "addChildren");
addEventIn(MFNODE, "removeChildren");
center.set(addExposedField(SFVEC3F, "center", new SFVec3f(0.0f, 0.0f, 0.0f)));
children.set (addExposedField(MFNODE, "children", new MFNode(), NODE_CHILD));
rotation.set(addExposedField(SFROTATION, "rotation", new SFRotation(0.0f, 0.0f, 1.0f, 0.0f)));
scale.set(addExposedField(SFVEC3F, "scale", new SFVec3f(1.0f, 1.0f, 1.0f), new SFFloat(0.0f)));
scaleOrientation.set(addExposedField(SFROTATION, "scaleOrientation",new SFRotation(0.0f, 0.0f, 1.0f, 0.0f)));
translation.set(addExposedField(SFVEC3F, "translation", new SFVec3f(0.0f, 0.0f, 0.0f)));
bboxCenter.set(addField(SFVEC3F, "bboxCenter", new SFVec3f(0, 0, 0)));
bboxSize.set(addField(SFVEC3F, "bboxSize", new SFVec3f(-1, -1, -1), new SFFloat(-1.0f)));
}
Different fields are internally handled as integer values.
The variables center, children, rotation, scale, scaleOrientation, translation,
bboxCenter and bboxSize are of type "fieldIndex", something like a readonly
integer, that can be only set once.
There are NodeTransform memberfunctions to get and set field values.
For example, the memberfunctions for the field "center" of class
"NodeTransform" are:
The memberfunctions "something_Index()" deliver the integer number that is
needed for example for a
MoveCommand to move nodes in the scenegraph.
Functionality common to all Nodes (like writing a Node to a file (Node.write())
is in the class Node (file Node.h/cpp). All NodeNodeName classes are
subclasses of the class Node.
Some of the memberfunctions of the class Node are virtual and can be
overwritten by the NodeNodeName classes (for example, the
class NodeScript need a special version of Node.write()).
Here is a list of important virtual Node memberfunctions:
- getType()
deliver a
value needed to identify different nodes. For example,
the transform node deliver NODE_TRANSFORM.
- write
write the node to a VRML file.
- update
update a node after a field change.
- setHandle
change a node field from handles (e.g. white boxes in the Scene3DView,
that can be moved around with the mouse).
- getHandle
get the value of a handle.
- drawHandles
draw the handle in the Scene3DView.
- preDraw
do operations that prepare the drawing of nodes in the Scene3DView.
- draw
drawing the nodes in the Scene3DView (and internally to find
mouse hits).
Some geometry nodes (like ElevationGrid) are implemented as a subclass of
MeshBasedNode. The MeshBasedNode class is used for geometry that
can implemented as a IndexedFaceSet type of mesh. The MeshBasedNode class
provides important virtual Node memberfunctions like draw.
The creation of the mesh in a MeshBasedNode is done via the virtual
function createMesh.
VRML97 parser
Dune need to read and parse ("understand") VRML97 files.
This is done with using the tools lex/yacc (it looks like, the advanced
tools flex and bison from the GNU project are needed).
The file lexer.l do the lexical analysis (detect things like "what is
a string", "what is a number", "what is that VRML97 keyword").
The file parser.y do the grammatical analysis (detect and prove, if the
tokens found by the lexical analysis form valid VRML contructions
(like Node or ROUTE statements).
Dangerous constructs
The buildin stringtype ("MyString") can be misleading, it act very
pointerlike. For example be carefull about constructs like the following:
MyString str = node->getProto()->getName();
str += "something";
This do not only copy the name of a Proto of "node" to str and append
"something" to it, it also appends "something" to the name of a Proto !
In this situation, it is better to use something like
MyString str = strdup(node->getProto()->getName());
str += "something";
"Adding a new (scripted) geometry node to white_dune"-cookbook
- Select a name of the new node (here "Something")
- define a ID_NEW_SOMETHING in resource.h
- Add
MENUITEM "Something", ID_NEW_SOMETHING
under
POPUP "Scripted Nodes (slow)"
BEGIN
and
ID_NEW_SOMETHING "Create a new Something Scripted Node\nSomething Sc$
in dune.rc (or dune.english.rc for UNIX type compilation with configure))
- add a
_protos["Something"] = new ProtoSomething(this);
in a matching place (sorted by the alphabet) in Scene::Scene()
and add
#include "NodeSomething.h"
to Scene.cpp
-
add a NODE_SOMETHING to the matching place (sorted by the alphabet) to
the matching enum in Node.h
- copy a similar Node*.h/cpp to NodeSomething.h/cpp and change
the fields/EventIns and draw, setHandle etc. functions.
- add a
NODE_SOMETHING, ID_NEW_SOMETHING,
to
static int buttonsScripted[] = {
in Windows.cpp
- Use gimp to include a new icon (16 pixels width) of your node
(nodenames need to be sorted by the alphabet) into res/node_icons.bmp
(or res_color/node_icons.bmp for UNIX type compilation with configure)
Warning: DO NOT change the numbers of colors in this bitmap file !
Under Linux/UNIX/MacOSX you can use the script "batch/inserticon.sh" by
typing
sh batch/inserticon.sh NODE_SOMETHING
gimp will then open and select the matching node icons that has to be
moved 16 pixels to left. Use "edit->cut" and "edit->paste" then move
the icons to the left border of the gimp window. Draw your new icon
in the new 16 pixels wide white gap.
- add a
case ID_NEW_SOMETHING:
CreateGeometryNode("Something");
break;
to MainWindow::OnCommand(int id)
- Do not forget the GPL license, which forces you to public somehow
the complete sources, if you want to redistribute a modified version
of white_dune...
class overview
The name of most sourcefiles in the "src" directory is identical
to the name of the major contained class.
The following class/filenames have special meanings:
-
NodeSomeNodeName:
Implement details for the VRML Node "SomeNodeName"
-
SomethingDialog, SomethingWindow, SomethingView:
Implement details for the graphical user interface (GUI)
-
SomethingApp:
Implement details for data global to the whole application
-
SomethingCommand:
Implement details for sending internal commands
-
SFSomething, MFSomething:
Implement details for VRML datatypes
If doxygen
is installed, a class hierarchy of white_dune can be produced by typing
make documentation
and can then be found here.