"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.
In princple, the structure of the white_dune program can be written as:
The GUI of white_dune consists of 2 parts:
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.
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.
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(), CHILD_NODE)); 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.
SFVec3f * | center (void) |
void | center (SFVec3f *value) |
void | center (SFVec3f &value) |
int | center_Field (void) |
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:
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). If some tokens of the grammar are valid,
the action part of the command in the parser.y file create the matching
VRML Nodes, Numbers etc.
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"; // also appended to the name...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";or
MyString str = ""; str += node->getProto()->getName(); str += "something";
Another dangerous constructs are the constructors for MF* types with pointers
to multiple data of the basic datatype.
The philosophy favour speed over unsuspicion, this constructors do not
copy the data, it copies the pointer.
So if the orginal pointer was not alloced with new(), problems will accure
at the end of the livetime of the MF* type.
For example should not use something like
float floats[3] = { 1, 2, 3 }; MFFloat mfFloat = new MFFloat(floats, 3); // possible crash lateryou must use something like
float *floats = new float[3]; for (int i = 1; i <= 3; i++) floats[i] = i; MFFloat mfFloat = new MFFloat(floats, 3);
MENUITEM "Something", ID_NEW_SOMETHINGin the matching submenu of the POPUP "&Create" menu and and
ID_NEW_SOMETHING "Create a new Something Scripted PROTO\nSomething Scripted"to all src/dune.*.rc files. See the chapter about localisation for more informations about handling the needed language translations.
protos->add("Something", new ProtoAnchor(scene));in a matching place (sorted by the alphabet of the SOMETHING in the list in Node.h) in the function SceneProtoMap::createProtoMap and add
#include "NodeSomething.h"to SceneProtoMap.cpp
{ DUNE_SOMETHING, ID_NEW_SOMETHING, true, true },(you may replace DUNE_SOMETHING with VRML_SOMETHING or X3D_SOMETHING) to the matching NodeButton arrays in MainWindow.cpp
{ DUNE_SOMETHING, ID_NEW_SOMETHING, false, true },to MainWindows.cpp and add something like
case DUNE_SOMETHING: valid = node->findValidFieldType(VRML_REQUIRED_BY_SOMETHING) != -1; break;to the swich in MainWindow::UpdateToolbar(STOOLBAR toolbar, Node *node, int field, NodeButton *buttons, int count)
sh batch/inserticon.sh DUNE_SOMETHINGor
sh batch/inserticon.sh X3D_SOMETHINGgimp 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.
case ID_NEW_SOMETHING: CreateNode("Something"); break;to MainWindow::OnCommand(int id) in MainWindow.cpp
It requires absolute no programming skills to translate the program to a
foreign language, if the foreign languages uses ASCII characters:
you only need to copy the file "src/dune.english.rc" into a similar file,
use a texteditor with search and replace und at end translate the strings
in this file to the foreign language.
The problems when trying to translate the program to a foreign language with non ASCII characters (like chinease UTF8 characters) are untested/unknown.
To complete the task to create a new runnable program a compatible compiler
is needed. Of course, this task can be done (after publicing the main
translation file src/dune.something.rc) by a programmer later, it do not need to
be done by the translator.
All "src/dune.*.rc" files are copied together into one src/dune.rc file during the
run of "configure" and "make".
This means, that for creating a new runnable program, you need either a
UNIX like system (e.g. Linux or MacOSX) or a bunch of unixtools:
m4, make, cat, grep and sh (e.g. bash or ksh).
A complete free/opensource installable collection of unixtools for M$Windows
is called cygwin and is available for free from the internet.
For Translaton, first search the ISO 3166 two characters of your language (e.g. "en" for english, "de" for german, "it" for italian, etc...) and build the uppercase version of this characters (e.g. EN for english, DE for german, IT for italian, etc).
Second, select a src/dune.something.rc file. In the simpler case, do not select
"src/dune.english.rc" cause this requires more complicated search and replace
commands.
Third you need to translate all the strings in the new src/dune.something.rc file.
A so called string is a term that starts with a " and ends with a "
For example, the translation of the line from src/dune.english.rc
POPUP "&File"to german language in src/dune.german.rc would result in
POPUP "&Datei"where the german word Datei is the translation of the english word File. The "&" sign marks the keyboard shortcut. The next character after "&" should not be ambient in the same level of a menu.
After the translation of the strings is ready, the translation step is
ready. On a Linux/UNIX/MacOSX/cygwin system with the gawk (GNU awk) program
you can use
sh test/testmenus.shone the commandline to use some consistency testing of the new rc file.
The new file src/dune.something.rc can be now publiced (e.g. in a usenet group like comp.lang.vrml, or at the sourceforge site for the original dune project).
For a recompilation, you first need to extend the list of lanugages,
white_dune understands.
Currently you need to extend the list of known languages in the file
src/swt/include/languages.m4. E.g. to extend the list of known
languages from english (empty default) and german (DE) in
src/swt/include/languages.m4
define(`M4_LANGUAGES_CONFIG',` DE,german')to english, italian (IT) and german, then change the list to
define(`M4_LANGUAGES_CONFIG',` IT,italian, DE,german')or extent to english, italian and spanish (ES) and german, then change the list to
define(`M4_LANGUAGES_CONFIG',` IT,italian, ES,spanish, DE,german')Take care that the last language line (here with "DE,german") do not end with a comma.
It is also possible to change the yes/no strings in Linux/UNIX messageboxes.
E.g. you extend the yes/no strings from english and german in
src/swt/include/languages.m4
define(M4_YES_english,"yes") define(M4_YES_german,"Ja") define(M4_NO_english,"no") define(M4_NO_german,"Nein")with the yes/no strings of italian, you have to change src/swt/include/languages.m4 to
define(M4_YES_english,"yes") define(M4_YES_italian,"si") define(M4_YES_german,"Ja") define(M4_NO_english,"no") define(M4_NO_italian,"no") define(M4_NO_german,"Nein")
The final step is rebuilding the needed files for compilation. On a
Linux/UNIX/MacOSX/cygwin system, this is done automatically by using
"sh build.sh"
(or "configure && make").
On other systems, at least a text editor and a port of the m4 program is
required.
With the texteditor, copy all dune.*.rc files together and store the
result in the file "dune.rc"
With m4 you need to execute the following commands in the src directory:
m4 resource.h.m4 > resource.h
m4 CommandlineLanguages.h.m4 > CommandlineLanguages.h
After recompilation (see the file INSTALL for details), the new language can
be used with a commandline parameter.
The name of the new commandline parameter is the minus sign followed by
the second word in the new line in M4_LANGUAGES_CONFIG.
E.g. if you added "IT,italian," to M4_LANGUAGES_CONFIG, the new commandline
parameter to switch to the italien language is -italien
All that have to be done now is to add the new commandline parameter to the documentation in the manpage file man/dune.1
When handling text messages from a programmers point of view, always try to use the function "swLoadString" to get a language related string (e.g. for a errormessage) from the "src/dune.rc" file. The first argument of the swLoadString file is a identifier, like IDS_INTERNAL_ERROR, which refers to the message in the default (english) language. To get the current language translation, add the term TheApp->getLang() to the idenifier, e.g . with swLoadString(IDS_INTERNAL_ERROR + TheApp->getLang(),...
As a programmer, take care about the fact, that each program code
modification (e.g. addition of new menu items) in one of the
src/dune.something.rc
files requires the change of a all other "src/dune.somelanguage.rc" files.
Cause a programmer is usually not a multilingual genius, the addition of
a new menuitem, icon tooltip or errormessage comes with a translation
problem. There are two possible solutions: either use a dictionary/internet
translation service like babelfish.altavista.com, or leave the english
word in the src/dune.something.rc file and hope for modification by users.
To leave the line blank cause of a unknown foreign word is not a option,
cause this can result in a crash of the program when used in this foreign
language.
The addition of a new icon tooltip or errormessage also requires the
inclusion of a new "#define" command which can be usually found in the
resource.h file.
Do not change the resource.h file directly. The file resource.h is a
autogenerated file, that could be overwritten at each run of the "make"
command or "configure" command.
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:
If doxygen
is installed, a class hierarchy of white_dune can be produced by typing
make documentationand can then be found here.