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