00001 /*
00002 File: ParseMGF.cc
00003
00004 Function: Provides routine to parse .mgf files into a scene.
00005
00006 Author: Andrew Willmott
00007
00008 Notes: Need to support shared vertices, vertex normals.
00009
00010 Copyright: (c) 1996-2000, Andrew Willmott
00011 */
00012
00013 #include "gcl/GCLConfig.h"
00014 #ifdef GCL_MGF
00015 #include "gcl/SceneLang.h"
00016 #include <stdio.h>
00017 #include <string.h>
00018
00019 extern "C"
00020 {
00021 #include <string.h>
00022 #include "parser.h"
00023 #include "lookup.h"
00024 }
00025
00026 static int myObject(int ac, char **av);
00027 static int myTransform(int ac, char **av);
00028 static int myCylinder(int ac, char **av);
00029 static int myFace(int ac, char **av);
00030 static int mySphere(int ac, char **av);
00031 static int myComment(int ac, char **av);
00032
00033 #ifdef DEBUG
00034 #define DBG_COUT if (0) cerr
00035 //#define MGF_DUMP
00036 #else
00037 #define DBG_COUT if (0) cerr
00038 #endif
00039
00040 Colour MGF2Colour(
00041 C_COLOR *cin, // input MGF chrominance
00042 Double intensity // input luminance or reflectance
00043 );
00044
00051 scScenePtr ParseMGFFile(const Char *filename)
00052 {
00053 scScenePtr result;
00054
00055 result = slBeginObject(filename);
00056
00057 // rotate from MGF's standard zup to our standard yup
00058 slTransform(Rotation(vl_x, -vl_halfPi));
00059 // initialize dispatch table
00060
00061 mg_ehand[MG_E_COMMENT] = myComment;
00062 mg_ehand[MG_E_COLOR] = c_hcolor;
00063 mg_ehand[MG_E_CMIX] = c_hcolor;
00064 mg_ehand[MG_E_CSPEC] = c_hcolor;
00065 mg_ehand[MG_E_CXY] = c_hcolor;
00066 mg_ehand[MG_E_CCT] = c_hcolor;
00067 //mg_ehand[MG_E_CYL] = myCylinder;
00068 mg_ehand[MG_E_ED] = c_hmaterial;
00069 mg_ehand[MG_E_FACE] = myFace;
00070 mg_ehand[MG_E_MATERIAL] = c_hmaterial;
00071 mg_ehand[MG_E_NORMAL] = c_hvertex;
00072 //mg_ehand[MG_E_OBJECT] = myObject;
00073 mg_ehand[MG_E_POINT] = c_hvertex;
00074 mg_ehand[MG_E_RD] = c_hmaterial;
00075 mg_ehand[MG_E_RS] = c_hmaterial;
00076 mg_ehand[MG_E_SIDES] = c_hmaterial;
00077 //mg_ehand[MG_E_SPH] = mySphere;
00078 mg_ehand[MG_E_TD] = c_hmaterial;
00079 mg_ehand[MG_E_TS] = c_hmaterial;
00080 mg_ehand[MG_E_VERTEX] = c_hvertex;
00081 mg_ehand[MG_E_XF] = xf_handler;
00082
00083 DBG_COUT << "initialising parser" << endl;
00084
00085 mg_init(); /* initialize the parser */
00086
00087 if (mg_load((char*)filename) != MG_OK)
00088 {
00089 slEndObject();
00090 return(0);
00091 }
00092 slEndObject();
00093 return(result);
00094 }
00095
00096
00097 static Int myObject(int ac, char **av) /* group object name */
00098 {
00099 static int objnest;
00100
00101 #ifdef MGF_DUMP
00102 int i;
00103 for (i = 0; i < ac; i++)
00104 printf("%s ", av[i]);
00105 printf("\n");
00106 #endif
00107
00108 return(MG_OK);
00109 }
00110
00111 static int myComment(int ac, char **av)
00112 {
00113 #ifdef MGF_DUMP
00114 int i;
00115 printf("comment:\n");
00116 for (i = 0; i < ac; i++)
00117 printf("%s ", av[i]);
00118 printf("\n");
00119 #endif
00120 return(MG_OK);
00121 }
00122
00123 #if 0
00124 // shared vertex lookup table
00125 const Char *kVertFmt = "%+16.9e %+16.9e %+16.9e %+6.3f %+6.3f %+6.3f";
00126 const Char *kVZVect = "+0.000 +0.000 +0.000";
00127 const Int kVFLen = 72;
00128 const Int kMaxVert 10240; /* maximum cached vertices */
00129
00130 #define setvkey(k,v) sprintf(k,VERTFMT,(v)->p[0],(v)->p[1],(v)->p[2],\
00131 (v)->n[0],(v)->n[1],(v)->n[2]);
00132
00133 char vlist[MAXVERT][VFLEN]; /* our vertex cache */
00134 int nverts; /* current cache size */
00135
00136 LUTAB vert_tab = LU_SINIT(NULL,NULL);
00137
00138 #endif
00139
00140
00141 static int myFace(int ac, char **av) /* translate an N-sided face */
00142 {
00143 C_VERTEX *vp;
00144 int i;
00145 FVECT n, p;
00146 Bool doNormals = false, ctxChange = false;
00147 Int idx;
00148
00149 static Int gLastXID = -1;
00150 static Colour gLastRClr(-1, -1, -1), gLastEClr(-1, -1, -1);
00151
00152 if (ac < 4)
00153 return(MG_EARGC);
00154
00155 if (xf_context && xf_context->xid != gLastXID)
00156 {
00157 gLastXID = xf_context->xid;
00158 ctxChange = true;
00159 DBG_COUT << "transform context changed: rev = " << xf_context->rev << endl;
00160 }
00161
00162 DBG_COUT << "mtl: " << c_cmname << ' ' << c_cmaterial << ' ' << c_cmaterial->clock << endl;
00163 if (c_cmaterial->clock != 0)
00164 // material has changed...
00165 {
00166 Colour rClr, eClr;
00167
00168 DBG_COUT << "material change: clock = " << c_cmaterial->clock << endl;
00169
00170 rClr = MGF2Colour(&c_cmaterial->rd_c, c_cmaterial->rd);
00171 eClr = MGF2Colour(&c_cmaterial->ed_c, c_cmaterial->ed);
00172 // the MGF 'ed' is measured in lux, photometric irradiance.
00173 // convert to our pure irradiance
00174 eClr /= 179.0;
00175
00176 if (rClr != gLastRClr)
00177 {
00178 DBG_COUT << "reflectance = " << rClr << endl;
00179 slColour(rClr);
00180 gLastRClr = rClr;
00181 ctxChange = true;
00182 }
00183 if (eClr != gLastEClr)
00184 {
00185 DBG_COUT << "emittance = " << eClr << endl;
00186 slEmittance(eClr);
00187 gLastEClr = eClr;
00188 ctxChange = true;
00189 }
00190
00191 c_cmaterial->clock = 0;
00192 }
00193
00194 #ifdef MGF_DUMP
00195 printf("face:\n");
00196 for (i = 0; i < ac; i++)
00197 printf("%s ", av[i]);
00198 printf("\n");
00199 #endif
00200
00201 slPointList();
00202
00203 for (i = 1; i < ac; i++)
00204 {
00205 if (xf_context && xf_context->rev)
00206 vp = c_getvert(av[ac - i]);
00207 else
00208 vp = c_getvert(av[i]);
00209
00210 if (vp == NULL)
00211 return(MG_EUNDEF);
00212
00213 // we wish to use shared vertices -- it appears the only
00214 // way to do this is to use a hash =P
00215
00216 #ifdef MGF_SHARED_VERTS
00217 // XXX unfinished!
00218 lu_init(&vert_tab, MAXVERT);
00219
00220 setvkey(vlist[nverts], vp);
00221 lp = lu_find(&vert_tab, vlist[nverts]);
00222 if (lp == NULL)
00223 return(MG_EMEM);
00224 if (lp->key == NULL)
00225 lp->key = (char *)vlist[nverts++];
00226 newf->vl[i] = ((char (*)[VFLEN])lp->key - vlist);
00227
00228 idx = (Int) vp->client_data;
00229
00230 if (ctxChange || vp->clock != 0 || idx == 0)
00231 {
00232 vp->clock = 0;
00233 xf_xfmpoint(p, vp->p);
00234 idx = slPoint(Vector(p[0], p[1], p[2]));
00235 vp->client_data = (char*) (idx + 1);
00236 DBG_COUT << "create index = " << idx << ", " << vp << endl;
00237
00238 if (i == 1 && (vp->n[0] != 0.0 || vp->n[1] != 0.0 || vp->n[2] != 0.0))
00239 {
00240 // if the first vertex has a vertex normal defined, assume the
00241 // rest do too.
00242 slNormalList();
00243 doNormals = true;
00244 }
00245
00246 if (doNormals)
00247 {
00248 Vector nrm;
00249
00250 xf_rotvect(n, vp->n);
00251 nrm = Vector(n[0], n[1], n[2]);
00252 DBG_COUT << "norm = " << nrm << endl;
00253 nrm.Normalise();
00254 slNormal(nrm);
00255 }
00256 }
00257 else
00258 {
00259 idx = idx - 1;
00260 DBG_COUT << "reused index = " << idx << ", " << vp << endl;
00261 }
00262 //slIndex(idx);
00263 }
00264 #else
00265 xf_xfmpoint(p, vp->p);
00266 slPoint(Vector(p[0], p[1], p[2]));
00267
00268 if (i == 1 && (vp->n[0] != 0.0 || vp->n[1] != 0.0 || vp->n[2] != 0.0))
00269 {
00270 // if the first vertex has a vertex normal defined, assume the
00271 // rest do too.
00272 slNormalList();
00273 doNormals = true;
00274 }
00275
00276 if (doNormals)
00277 {
00278 Vector nrm;
00279
00280 xf_rotvect(n, vp->n);
00281 nrm = Vector(n[0], n[1], n[2]);
00282 DBG_COUT << "norm = " << nrm << endl;
00283 nrm.Normalise();
00284 slNormal(nrm);
00285 }
00286 }
00287 slPoly();
00288 #endif
00289
00290 return(MG_OK);
00291 }
00292
00293
00294 static int mySphere(int ac, char **av) /* translate sphere description */
00295 {
00296 #ifdef MGF_DUMP
00297 printf("sphere:\n");
00298 #endif
00299 return(MG_OK); /* we'll actually put it out later */
00300 }
00301
00302
00303 static int myCylinder(int ac, char **av) /* translate a cylinder description */
00304 {
00305 #ifdef MGF_DUMP
00306 printf("cyl:\n");
00307 int i;
00308 for (i = 0; i < ac; i++)
00309 printf("%s ", av[i]);
00310 printf("\n");
00311 #endif
00312 return(MG_OK); /* we'll actually put it out later */
00313 }
00314
00315
00316 #ifndef OLD
00317 /* Change the following to suit your standard */
00318 #define CIE_x_r 0.640 /* nominal CRT primaries */
00319 #define CIE_y_r 0.330
00320 #define CIE_x_g 0.290
00321 #define CIE_y_g 0.600
00322 #define CIE_x_b 0.150
00323 #define CIE_y_b 0.060
00324 #define CIE_x_w 0.3333 /* use true white */
00325 #define CIE_y_w 0.3333
00326
00327 #define CIE_D ( CIE_x_r*(CIE_y_g - CIE_y_b) + \
00328 CIE_x_g*(CIE_y_b - CIE_y_r) + \
00329 CIE_x_b*(CIE_y_r - CIE_y_g) )
00330
00331 #define CIE_C_rD ( (1./CIE_y_w) * \
00332 ( CIE_x_w*(CIE_y_g - CIE_y_b) - \
00333 CIE_y_w*(CIE_x_g - CIE_x_b) + \
00334 CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g ) )
00335 #define CIE_C_gD ( (1./CIE_y_w) * \
00336 ( CIE_x_w*(CIE_y_b - CIE_y_r) - \
00337 CIE_y_w*(CIE_x_b - CIE_x_r) - \
00338 CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r ) )
00339 #define CIE_C_bD ( (1./CIE_y_w) * \
00340 ( CIE_x_w*(CIE_y_r - CIE_y_g) - \
00341 CIE_y_w*(CIE_x_r - CIE_x_g) + \
00342 CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r ) )
00343
00344 #define CIE_rf (CIE_y_r*CIE_C_rD/CIE_D)
00345 #define CIE_gf (CIE_y_g*CIE_C_gD/CIE_D)
00346 #define CIE_bf (CIE_y_b*CIE_C_bD/CIE_D)
00347
00348 /* XYZ to RGB conversion matrix */
00349
00350 const ClrMat xyz2rgb
00351 (
00352 (CIE_y_g - CIE_y_b - CIE_x_b * CIE_y_g + CIE_y_b * CIE_x_g) / CIE_C_rD,
00353 (CIE_x_b - CIE_x_g - CIE_x_b * CIE_y_g + CIE_x_g * CIE_y_b) / CIE_C_rD,
00354 (CIE_x_g * CIE_y_b - CIE_x_b * CIE_y_g) / CIE_C_rD,
00355
00356 (CIE_y_b - CIE_y_r - CIE_y_b * CIE_x_r + CIE_y_r * CIE_x_b) / CIE_C_gD,
00357 (CIE_x_r - CIE_x_b - CIE_x_r * CIE_y_b + CIE_x_b * CIE_y_r) / CIE_C_gD,
00358 (CIE_x_b * CIE_y_r - CIE_x_r * CIE_y_b) / CIE_C_gD,
00359
00360 (CIE_y_r - CIE_y_g - CIE_y_r * CIE_x_g + CIE_y_g * CIE_x_r) / CIE_C_bD,
00361 (CIE_x_g - CIE_x_r - CIE_x_g * CIE_y_r + CIE_x_r * CIE_y_g) / CIE_C_bD,
00362 (CIE_x_r * CIE_y_g - CIE_x_g * CIE_y_r) / CIE_C_bD
00363 );
00364
00365 // convert MGF color to RGB
00366
00367 Colour gMGFRGBLum(CIE_rf, CIE_gf, CIE_bf);
00368
00369 Colour MGF2Colour(
00370 C_COLOR *cin, /* input MGF chrominance */
00371 Double intensity /* input luminance or reflectance */
00372 )
00373 {
00374 Colour xyz, rgb;
00375 ClrReal rgbLum;
00376
00377 // get CIE XYZ representation
00378 c_ccvt(cin, C_CSXY);
00379
00380 DBG_COUT << "converting: x y L: " << cin->cx << ' ' << cin->cy << ' ' << intensity << endl;
00381
00382 xyz[0] = cin->cx;
00383 xyz[1] = cin->cy;
00384 xyz[2] = (1.0 - cin->cx - cin->cy);
00385
00386 // convert to rgb colour
00387
00388 // XXX change this to use ColourSystem stuff.
00389 rgb = xyz2rgb * xyz;
00390 // correct for out of gamut
00391 ClipColourZero(rgb);
00392 // normalise rgb luminance to 1
00393 rgbLum = (CIE_rf * rgb[0] + CIE_gf * rgb[1] + CIE_bf * rgb[2]);
00394 if (rgbLum > 0.0)
00395 rgb /= rgbLum;
00396 // set intensity.
00397 rgb *= intensity;
00398
00399 DBG_COUT << "got: " << rgb << endl;
00400
00401 return(rgb);
00402 }
00403 #else
00404
00405 #include "gcl/ColourSystem.h"
00406
00407 static ColourSystem mgfCS(
00408 Chroma(0.640, 0.330),
00409 Chroma(0.290, 0.600),
00410 Chroma(0.150, 0.060),
00411 Chroma(0.3333, 0.3333));
00412
00413 Colour MGF2Colour(
00414 C_COLOR *cin, /* input MGF chrominance */
00415 Double intensity /* input luminance or reflectance */
00416 )
00417 {
00418 Colour rgb;
00419
00420 // get CIE XYZ representation
00421 c_ccvt(cin, C_CSXY);
00422
00423 DBG_COUT << "converting: x y L: " << cin->cx << ' ' << cin->cy << ' ' << intensity << endl;
00424
00425 rgb = mgfCS.ChromaToGamut(Chroma(cin->cx, cin->cy));
00426 rgb *= intensity;
00427
00428 DBG_COUT << "got: " << rgb << endl;
00429
00430 return(rgb);
00431 }
00432
00433
00434 #endif
00435
00436 #endif