|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Home
|
How to add new Nodes to FreeWRLThis document will show examples of how to add nodes to FreeWRL.There is a companion document containing some ideosyncracies of programming on FreeWRL: general coding notes for FreeWRL/FreeX3D. Last change: October 14, 2009.
QuestionsThere is one decision, and two concepts you have to work through:
Example 1. Adding a node that takes an SFFloat, and returns the value, multiplied by two.
step 1) choose a node that is close in functionality to abstract some methodology from.Lets choose the BooleanToggle node - it takes a boolean value and inverts it.
step 2) Look through the source for files that have "BooleanToggle" in them.As of this time of writing:
We will go through each of these files in turn. a) codegen/VRMLNodes.pm
BooleanToggle =>
new VRML::NodeType("BooleanToggle", {
set_boolean =>[SFBool,undef,inputOnly],
toggle => [SFBool, FALSE, outputOnly],
metadata => [SFNode, NULL, inputOutput],
__oldmetadata => [SFNode, 0, inputOutput], # see code for event macro
},"X3DChildNode"),
Copy and paste this node. At the end of VRMLNodes.pm, you will see a "testing" area. Paste in there. Change "BooleanToggle" to "FloatMultiply", and "SFBool" to "SFFloat":
FloatMultiply =>
new VRML::NodeType("FloatMultiply", {
set_float =>[SFFloat,undef,inputOnly],
newFloat => [SFFloat, FALSE, outputOnly],
metadata => [SFNode, NULL, inputOutput],
__oldmetadata => [SFNode, 0, inputOutput], # see code for event macro
},"X3DChildNode"),
and write out the file. b) codegen/VRMLRend.pm You will see the line:
BooleanToggle =>children,
in a grouping called "defaultContainerType". We will keep the default as a child node so simply copy the "BooleanToggle" line, and edit it so it looks like:
FloatMultiply =>children,
Run the command "perl VRMLC.pm" and check for errors.
c) src/lib/main/headers.h You will see a Function Prototype for "do_BooleanToggle" here - copy this, and change it to: void do_FloatMultiply (void *node);
d) src/lib/scenegraph/Component_EventUtils.c Look for BooleanToggle, and you will see the function do_BooleanToggle; copy this and change the code as shown:
/* testing... */
void do_FloatMultiply (void *node){
struct X3D_FloatMultiply *px;
if (!node) return;
px = (struct X3D_FloatMultiply *) node;
/* has the value changed? */
if (!APPROX(px->set_float,px->newFloat)) {
/* value has changed */
printf ("FloatMultiply, value has changed\n");
px->newFloat = px->set_float * 2.0;
MARK_EVENT(node, offsetof (struct X3D_FloatMultiply, newFloat));
}
}
e) src/lib/scenegraph/GeneratedCode.c This file is generated from the Perl-formatted tables, DO NOT edit this file. f) src/lib/scenegraph/RenderFuncs.c BooleanToggle is an interpolator - it just modifies the input value and gives a new output value, nothing else. Lets copy, paste, and edit the one "BooleanToggle" line in this file, so we have:
} else if (strcmp("BooleanToggle",x)==0) { return (void *)do_BooleanToggle;
} else if (strcmp("FloatMultiply",x)==0) { return (void *)do_FloatMultiply;
g) src/lib/vrml_parser/NodeFields.h This file is generated from the Perl-formatted tables, DO NOT edit this file. h) src/lib/vrml_parser/Structs.h This file is generated from the Perl-formatted tables, DO NOT edit this file. -------------------
step 3) Compile the source code.If you do not know already, see the FAQ for info on how to compile FreeWRL.step 4) Run an example.Here is an example that shows the execution of our "FloatMultiply" function:
#VRML V2.0 utf8
DEF SPH1 Transform {
translation -2 0 0
children [
Shape {
appearance Appearance { material Material {} }
geometry Cylinder {}
}
]
}
DEF SPH2 Transform {
translation 2 0 0
children [
Shape {
appearance Appearance { material Material {} }
geometry Cylinder {}
}
]
}
# Animation clock
DEF Clock TimeSensor { cycleInterval 1.5 loop TRUE },
# Position
# - note that the key goes from 0 to 2 for both:
# - note that POS1 and POS2 are identical, EXCEPT for the "x" component on each keyValue.
# this places the resulting movement on left or right side of screen
DEF POS2 PositionInterpolator {
key [ 0, 1, 2 ]
keyValue [
2 -2.0 0 # right side
2 2.0 0 # right side
2 -2.0 0 # right side
]
}
DEF POS1 PositionInterpolator {
key [ 0, 1, 2]
keyValue [
-2 -2.0 0 # left side
-2 2.0 0 # left side
-2 -2.0 0 # left side
]
}
# our new node
DEF MYMUL FloatMultiply {}
# route the Clock for animation of left and right shapes.
ROUTE Clock.fraction_changed TO POS1.set_fraction
ROUTE Clock.fraction_changed TO MYMUL.set_float
#left shape, will have keyValue of 0->1
ROUTE POS1.value_changed TO SPH1.set_translation
# right shape, will have keyValue of 0->2
ROUTE MYMUL.newFloat TO POS2.set_fraction
ROUTE POS2.value_changed TO SPH2.set_translation
Example 2. A new interactive node.coming...Example 3. A new graphics node.Ok, a new but old graphics node. We will show how to implement the VRML1 IndexedFaceSet node; it is moderately complex, and it uses the "PolyRep" internal structure, and, VRML1 support is requested, so it is a good candidate. We will call this node VRML1_IndexedFaceSet
step 1) choose a node that is close in functionality to abstract some methodology from.Here is a table comparing the specification entries for VRML1 IndexedFaceSet, to the X3D IndexedFaceSet:
You will notice that the VRML1 fields, if they apply, have a pointer. This is because, in VRML1, one codes as as siblings, separated by the Separator node:
Separator {
MaterialBinding {...}
ShapeHints {...}
IndexedFaceSet {...}
}
while in X3D, the fields are specific child-style nodes, eg:
IndexedFaceSet {
colorPerVertex TRUE
creaseAngle 0.3
...
}
We will have to take this into account later on.
step 2) Look through the source for files that have "IndexedFaceSet" in them.
We will go through each of these files in turn.
a) codegen/VRMLNodes.pm
defines the node type; this is a "Perl-ized" copy of the node from the spec.
You will see the following lines near the end of the VRMLNodes.pm file:
Compare the above, to the VRML1 spec. You will notice the field names, the types, and the default values.
There will be other fields in here - that start with an underscore - look for these below.
b) codegen/VRMLRend.pm
In here, you will see the VRML1_IndexedFaceSet
keyword in a few places - FreeWRL has an object-oriented scene graph, so we have to define and fill in some methods in order to have a node operate properly. These methods will get defined in more detail later; just remember that we need to put our VRML1_IndexedFaceSet in some of these tables in order to get our methods called.
The VRML1_IndexedFaceSet keyword is found in the following tables:
c) codegen/VRMLC.pm
This file is a Perl file that is called during the build process to create "C" code for calling methods.
We care in that this file contains some Macros for casting types, and an extremely important definition for the PolyRep
structure that we will be using.
Do the following from within the codegen directory to see if your additions to the above were syntactically correct:
It should run with no visible output. (It will, however, create a bunch of tables that we now have to fill in)
d) src/lib/main/headers.h
This file holds function prototypes; we will need prototypes for:
e) src/lib/scenegraph/Component_Geometry3D.c
Just note the function render_IndexedFaceSet - we will have to clone this in the next step.
f) src/lib/scenegraph/Component_VRML1.c
This file contains the one full function prototype expansion that we require - render_VRML1_IndexedFaceSet.
Remember the table above, where it was shown that the VRML1 IndexedFaceSet node fields were actually in sibling nodes? Now is where the petal hits the metal - we have to gather these nodes up and place references here in our node. How do we do this?
Now, we create the render_VRML1_IndexedFaceSet function like this:
g) src/lib/scenegraph/GenPolyRep.c
The code in here takes specific fields from all of the PolyRep nodes, and makes the internal PolyRep structure.
You will see the code gathering information in the code:
h) src/lib/scenegraph/Polyrep.c
Nothing needed!
i) src/lib/scenegraph/StreamPoly.c
The Function defaultTextureMap collects information for creating a texture mapping, if a mapping has not been supplied.
i) src/lib/opengl/RenderTextures.c
Nothing needed!
Here is an example for you:
If you want to help develop FreeWRL to use in an interesting project,
join the mailing list (send mail to freewrl-join@crc.ca). Anyone is
welcome.
Contact If you want to help, please email John Stewart (freewrl-09 -at- rogers.com)
- an employee of the
Communications Research Centre (CRC), Canada.
FreeWRL is produced by
dedicated volunteers, and
employees of CRC, and is released under the
LGPL License
as Open Source to the world community.
DISCLAIMER: All information and programs
presented on these pages is presented strictly on an as-is basis without
an explicit or implicit warranty or guarantee of any kind, not even
for fitness for any particular purpose. The FreeWRL logo is based
on the Linux Penguin logo by Larry Ewing. All trademarks are owned
by their respective owners.
|