| 1 |
MGF PACKAGE DESCRIPTION |
| 2 |
RCSid "$Id: readme.txt,v 1.9 2007/07/28 07:12:21 greg Exp $" |
| 3 |
|
| 4 |
This package includes a description and parser for a new scene |
| 5 |
description standard, called for the lack of a better name, MGF |
| 6 |
for Materials and Geometry Format. It was developed by Greg |
| 7 |
Ward of the Lawrence Berkeley Laboratory <[email protected]> with |
| 8 |
help and advice from Rob Shakespeare of Indiana University |
| 9 |
<[email protected]>, Ian Ashdown of Ledalite Corporation |
| 10 |
<[email protected]> and Holly Rushmeier of the National |
| 11 |
Institute for Standards and Technology <[email protected]>. |
| 12 |
|
| 13 |
The language itself is described in the file "spec.txt", and |
| 14 |
the included Makefile should make building the parser library |
| 15 |
fairly straightforward on most systems. What's left then, is |
| 16 |
explaining the why and how of using this package. |
| 17 |
|
| 18 |
The initial purpose of developing a scene description standard |
| 19 |
was for inclusion in the Illumination Engineering Society's (IES) |
| 20 |
standard data representation for luminaires. It occurred to us |
| 21 |
early on that such a standard might have broader applications, |
| 22 |
so an effort was made to create a fairly general description |
| 23 |
language, while keeping it as simple as possible for the people |
| 24 |
who have to create descriptions with it as well as the programmers |
| 25 |
who have to support it. |
| 26 |
|
| 27 |
Why create a new standard rather than exploiting an existing one? |
| 28 |
Some of the rationale for our decision is explained at the end of |
| 29 |
the specification document, but it mostly boils down to materials. |
| 30 |
As easy as it is to describe physically valid materials, most |
| 31 |
scene description languages cannot do it. The material specification |
| 32 |
included in the MGF standard may not be perfect, but at least it's |
| 33 |
physically plausible. Furthermore, we are committed to making any |
| 34 |
future modifications to the standard backwards-compatible -- a rather |
| 35 |
tricky proposition. |
| 36 |
|
| 37 |
This takes us to the how of supporting this new standard. The basic |
| 38 |
approach is to use the standard parser, which does a lot of the work |
| 39 |
in supporting the language itself. The programmer tells the parser |
| 40 |
which entities it will support, and the parser does the rest. |
| 41 |
That way, it isn't necessary to modify the program when a new version |
| 42 |
of the standard comes out; all one has to do is link to the new |
| 43 |
standard's parser. (The include file will change as well, so it's |
| 44 |
not QUITE that simple, but close.) |
| 45 |
|
| 46 |
There are two ways to support the language, by linking the parser to |
| 47 |
the program itself, or by linking the parser to a translator program |
| 48 |
that expresses MGF entities in the native scene description format. |
| 49 |
The differences in the two approaches are slight, and we will mention |
| 50 |
them following a general explanation of the parser and support library. |
| 51 |
|
| 52 |
The Parser |
| 53 |
========== |
| 54 |
The MGF parser is written in ANSI-C (though the -DNOPROTO flag may be |
| 55 |
used to get back K&R compatibility). All of the declarations and |
| 56 |
definitions needed are in the single include file "parser.h". This |
| 57 |
file is a good place to look for details on using the various support |
| 58 |
routines as well. The parser itself is parser.c, though it relies for |
| 59 |
some translations on other C modules. These same support routines will |
| 60 |
no doubt be useful for applications programmers, and we will explain |
| 61 |
some of them in the following sections. |
| 62 |
|
| 63 |
Initializing the parser is the most important part of writing an MGF |
| 64 |
program, and it is done through the mg_ehand array and a call to mg_init. |
| 65 |
The global mg_ehand variable is an array of pointers to entity handler |
| 66 |
functions. The arguments to these functions are always the same, an |
| 67 |
argument count and an array of argument pointers (ala main). The return |
| 68 |
value for these integer functions is one of the error codes defined in |
| 69 |
parser.h, or MG_OK if the entity was handled correctly. You must |
| 70 |
set the appropriate entries for the entities you can support, then call |
| 71 |
mg_init to fill in the rest. Most of the entities you cannot support |
| 72 |
will be translated into (approximately) equivalent ones you can. |
| 73 |
Entities that have no equivalent (such as color), will be safely |
| 74 |
ignored on the input. If you have specified support for some entities |
| 75 |
without offering support to their prerequisites, mg_init will report an |
| 76 |
error and exit. |
| 77 |
|
| 78 |
Once the parser has been properly initialized, MGF input files may be |
| 79 |
loaded at will with the mg_load call. This function takes a single |
| 80 |
argument, which is the name of the MGF file. (The NULL pointer may be |
| 81 |
used to specify standard input.) The behavior of the parser in part |
| 82 |
depends on input history, so the mg_clear call should be used after |
| 83 |
each file if starting fresh is important. This also frees any data |
| 84 |
structures used by the parser, which may be desirable if the program |
| 85 |
is going to do something after loading besides exit. |
| 86 |
|
| 87 |
Support Functions |
| 88 |
================= |
| 89 |
In translating unsupported entities, the parser makes use of a number |
| 90 |
of support functions, contained in associated C modules. The most |
| 91 |
important of these are in context.c, which includes three handler |
| 92 |
functions that can support all color, material and vertex entities. |
| 93 |
To understand what these functions do, it is necessary to know a |
| 94 |
little about the MGF language itself, so please familiarize yourself |
| 95 |
with it now if you haven't already. (See the file "spec.txt".) |
| 96 |
|
| 97 |
Context Support |
| 98 |
=============== |
| 99 |
The MGF language defines three named contexts, the current vertex, |
| 100 |
the current color and the current material. (The current color is |
| 101 |
used mostly for setting parameters in the current material.) There |
| 102 |
are three handler routines defined in context.c, and they can handle |
| 103 |
all entities related to these three contexts. The simplest way to |
| 104 |
support materials, for example, is to initialize the mg_ehand array |
| 105 |
such that the MG_E_MATERIAL, MG_E_RD, MG_E_RS, etc. entries all point |
| 106 |
to c_hmaterial. Then, whenever a material is needed, the global |
| 107 |
c_cmaterial variable will be pointing to a structure with all the |
| 108 |
current settings. (Note that you would have to also set the color |
| 109 |
mg_ehand entries to c_hcolor if you intended to support color |
| 110 |
materials.) A list of related mg_ehand assignments is given below: |
| 111 |
|
| 112 |
mg_ehand[MG_E_COLOR] = c_hcolor; |
| 113 |
mg_ehand[MG_E_CCT] = c_hcolor; |
| 114 |
mg_ehand[MG_E_CMIX] = c_hcolor; |
| 115 |
mg_ehand[MG_E_CSPEC] = c_hcolor; |
| 116 |
mg_ehand[MG_E_CXY] = c_hcolor; |
| 117 |
mg_ehand[MG_E_ED] = c_hmaterial; |
| 118 |
mg_ehand[MG_E_IR] = c_hmaterial; |
| 119 |
mg_ehand[MG_E_MATERIAL] = c_hmaterial; |
| 120 |
mg_ehand[MG_E_NORMAL] = c_hvertex; |
| 121 |
mg_ehand[MG_E_POINT] = c_hvertex; |
| 122 |
mg_ehand[MG_E_RD] = c_hmaterial; |
| 123 |
mg_ehand[MG_E_RS] = c_hmaterial; |
| 124 |
mg_ehand[MG_E_SIDES] = c_hmaterial; |
| 125 |
mg_ehand[MG_E_TD] = c_hmaterial; |
| 126 |
mg_ehand[MG_E_TS] = c_hmaterial; |
| 127 |
mg_ehand[MG_E_VERTEX] = c_hvertex; |
| 128 |
|
| 129 |
In addition to the three handler functions, context.c contains a |
| 130 |
few support routines that make life simpler. For vertices, there |
| 131 |
is the c_getvertex call, which returns a pointer to a named vertex |
| 132 |
structure (or NULL if there is no corresponding definition for the |
| 133 |
given name). This function is needed for support of most surface |
| 134 |
entities. For color support, there is the analogous c_getcolor call, |
| 135 |
and the c_ccvt routine, which is used to convert from one color |
| 136 |
representation to another (e.g. spectral color to xy chromaticity |
| 137 |
coordinates). Also, there is a function called c_isgrey, which |
| 138 |
simply returns 1 or 0 based on whether the passed color structure |
| 139 |
is close to grey or not. Finally, there is the c_clearall routine, |
| 140 |
which clears and frees all context data structures, and is the |
| 141 |
principal action of the parser's mg_clear function. |
| 142 |
|
| 143 |
Transform Support |
| 144 |
================= |
| 145 |
If your program is supporting any geometry at all (and what would be |
| 146 |
the point if it wasn't?) you will need to support the transform |
| 147 |
entity (MG_E_XF). This would be tricky, if it weren't for the support |
| 148 |
routines provided, which make the task fairly painless. First, there |
| 149 |
is the transform handler itself, xf_handler. Just set the MG_E_XF |
| 150 |
entry of the mg_ehand array to this function. Then, anytime you want |
| 151 |
to transform something, call one of the associated functions, xf_xfmpoint, |
| 152 |
xf_xfmvect, xf_rotvect or xf_scale. These functions transform a 3-D |
| 153 |
point, 3-D vector (without translation), rotate a 3-D vector (without |
| 154 |
scaling) and scale a floating-point value, respectively. |
| 155 |
|
| 156 |
Object Support |
| 157 |
============== |
| 158 |
The MGF language includes a single entity for naming objects, MG_E_OBJECT. |
| 159 |
It is mostly provided as a convenience for the user, so that individual |
| 160 |
geometric parts may be easily identified. Although supporting this entity |
| 161 |
directly is possible, it's hierarchical nature requires maintaining a stack |
| 162 |
of object names. The object handler in object.c provides this functionality. |
| 163 |
Simply set the MG_E_OBJECT entry of the mg_ehand array to obj_handler, |
| 164 |
and the current object name list will be kept in the global array obj_name. |
| 165 |
The number of names is stored in the global obj_nnames variable. To clear |
| 166 |
this array (freeing any memory used in the process), call obj_clear. |
| 167 |
|
| 168 |
Loading vs. Translating |
| 169 |
======================= |
| 170 |
As mentioned in the introduction, the parser may be used either to load |
| 171 |
data into a rendering program directly, or to get MGF input for translation |
| 172 |
to another file format. In either case, the procedure is nearly identical. |
| 173 |
The only important difference is what you do with the parser data structures |
| 174 |
after loading. For a translator, this is not an issue, but rendering |
| 175 |
programs usually need all the memory they can get. Therefore, once the |
| 176 |
input process is complete, you should call the mg_clear function to free |
| 177 |
the parser data structures and return to an initialized state (i.e. it |
| 178 |
is never necessary to recall the mg_init routine). |
| 179 |
|
| 180 |
Also, if you use some of the support functions, you should call their |
| 181 |
specific clearing functions. For the transform module, the call is |
| 182 |
xf_clear. For the object support module, the call is obj_clear. The |
| 183 |
context routines use the c_clearall function, but this is actually |
| 184 |
called by mg_clear, so calling it again is unnecessary. |
| 185 |
|
| 186 |
Linking Vertices |
| 187 |
================ |
| 188 |
Although the MGF language was designed with linking vertices in mind, |
| 189 |
there are certain aspects which make this goal more challenging. |
| 190 |
Specifically, the ability to redefine values for a previously named |
| 191 |
vertex is troublesome for the programmer, since the same vertex can |
| 192 |
have different values at different points in the input. Likewise, the |
| 193 |
effect of the transform entity on surfaces rather than vertices means |
| 194 |
that the same named vertex can appear in many positions. |
| 195 |
|
| 196 |
It is not possible to use the parser data structures directly for |
| 197 |
linking vertices, but we've taken a couple of steps in the support |
| 198 |
routines to make the task of organizing your own data structures a |
| 199 |
little easier. First, there is a clock member in the C_VERTEX |
| 200 |
structure that is incremented on each change. (The same member is |
| 201 |
contained in the C_COLOR and C_MATERIAL structures.) Second, the |
| 202 |
current transform (pointed to by xf_context) contains a unique |
| 203 |
identifier, xf_context->xid. This is a long integer that will be |
| 204 |
different for each unique transform. (It is actually a hash key on the |
| 205 |
transformation matrix, and there is about 1 chance in 2 billion that |
| 206 |
two different matrices will hash to the same value. Is this a bug? |
| 207 |
I guess it depends on how long the programmer lives -- or vice versa.) |
| 208 |
|
| 209 |
There are two ways to use of this additional information. One |
| 210 |
is to record the vertex clock value along with it's id and the |
| 211 |
current xf_context->xid value. If another vertex comes along with |
| 212 |
the same name, but one of these two additional values fails to match, |
| 213 |
then it (probably) is a different vertex. Alternatively, one can reset |
| 214 |
the clock member every time a new vertex is stored. That way, it is |
| 215 |
only necessary to check the clock against zero rather than storing this |
| 216 |
value along with the vertex name and transform id. If the name and |
| 217 |
transform are the same and the clock is zero, then it's the same vertex |
| 218 |
as last time. |
| 219 |
|
| 220 |
Yet another approach is to ignore the parser structures entirely and |
| 221 |
focus on the actual vertex values. After all, the user is not compelled |
| 222 |
to reuse the same vertex names for the same points. It is just as likely |
| 223 |
that the same vertices will appear under different names, so that none |
| 224 |
of the above would help to merge them. The most sure-fire approach to |
| 225 |
linking identical vertices is therefore to hash the point and normal |
| 226 |
values directly and use the functions in lookup.c to associate them. |
| 227 |
You will have to write your own hash function, and we recommend making |
| 228 |
one that allows a little slop so that nearly identical points hash to |
| 229 |
the same value. |
| 230 |
|
| 231 |
Examples |
| 232 |
======== |
| 233 |
Two example translator programs are included with this package. |
| 234 |
|
| 235 |
The simplest is a translator from MGF to MGF called mgfilt.c, which |
| 236 |
produces on the standard output only those entities from the standard |
| 237 |
input that are supported according to the first command line argument. |
| 238 |
For example, one could remove everything but the raw, flat polygonal |
| 239 |
geometry with the following command: |
| 240 |
|
| 241 |
mgfilt v,p,f,xf any.mgf > faces.mgf |
| 242 |
|
| 243 |
Note that the xf entity must also be included, for its support is |
| 244 |
required by all geometric entities. |
| 245 |
|
| 246 |
The second translator converts from MGF to the Radiance scene description |
| 247 |
language, and is a more practical example of parser use. Unfortunately, |
| 248 |
we did not include all of the support functions required by this translator, |
| 249 |
so it serves as a source code example only. If you wish to get the rest |
| 250 |
of it because you intend to run it, contact Greg Ward <[email protected]> |
| 251 |
and he'll be happy to provide you with the missing pieces. |
| 252 |
|
| 253 |
Copyright |
| 254 |
========= |
| 255 |
This library was put in public domain and is offered free |
| 256 |
of charge to all those who wish to use it for any purpose. |
| 257 |
We take no responsibility for its use, misuse, correctess, |
| 258 |
or suitability. |
| 259 |
|
| 260 |
Questions |
| 261 |
========= |
| 262 |
Questions should be directed to Greg Ward <[email protected]>>, who will be |
| 263 |
happy to offer any reasonable assistance in using this standard. |