00001 /* 00002 File: ParseSC.cc 00003 00004 Purpose: Parses Paul's .sc format 00005 00006 Author: Mainly uses code from Paul Heckbert & John Murphy. 00007 */ 00008 00009 #include "gcl/GCLConfig.h" 00010 00011 #ifdef GCL_PARSE_SC 00012 00013 #include <stdlib.h> 00014 #include <string.h> 00015 #include <ctype.h> 00016 #include <stdio.h> 00017 00018 #include "gcl/SceneLang.h" 00019 00020 00022 static int lc; // current line number in scene file 00023 00024 // read whatever is left on a line (for comments) 00025 Void fread_to_eol(FILE *fp) { 00026 char c; 00027 do c = getc(fp); while (c!='\n'); 00028 do {c = getc(fp); lc++;} while (c=='\n'); 00029 if (!feof(fp)) ungetc(c, fp); 00030 } 00031 00032 // Chomp away white space, but keep track of the newlines 00033 Void eatspace(FILE *fp) { 00034 char c; 00035 do { 00036 c = getc(fp); 00037 if (c=='#') {c = ' '; fread_to_eol(fp);} 00038 if (c=='\n') lc++; 00039 if (feof(fp)) return; 00040 } while (isspace(c)); 00041 ungetc(c, fp); 00042 } 00043 00044 // read the next string from the file, returns ptr to static 00045 char *fread_word(FILE *fp) { 00046 static char word[80]; // sets maximum word length 00047 eatspace(fp); 00048 int test = fscanf(fp, "%s", word); 00049 if (test==EOF) strcpy(word, "end"); 00050 else if (test!=1) { 00051 cerr << "Scene Error, line " << lc 00052 << ": scanf returned " << test << endl; 00053 exit(1); 00054 } 00055 return word; 00056 } 00057 00058 // read the next number from the file 00059 double fread_number(FILE *fp) { 00060 eatspace(fp); 00061 double number; 00062 int test = fscanf(fp, "%lf", &number); 00063 if (test!=1) { 00064 cerr << "Scene Error, line " << lc 00065 << ": scanf returned " << test << endl; 00066 exit(1); 00067 } 00068 return number; 00069 } 00070 00071 Vector fread_Vector(FILE *fp) 00072 { 00073 double x = fread_number(fp); 00074 double y = fread_number(fp); 00075 double z = fread_number(fp); 00076 return(Vector(x, y, z)); 00077 } 00078 00079 Colour fread_Colour(FILE *fp) 00080 { 00081 double x = fread_number(fp); 00082 double y = fread_number(fp); 00083 double z = fread_number(fp); 00084 return(Colour(x, y, z)); 00085 } 00086 00087 // parse a scene file 00088 // add to existing scene 00089 00090 scScenePtr ParseSCFile(const Char *filename) 00091 { 00092 FILE *fp; 00093 scScenePtr result; 00094 00095 if ((fp = fopen(filename, "r")) == NULL) 00096 { 00097 cerr << "Cannot access " << filename << endl; 00098 return(0); 00099 } 00100 00101 result = slBeginObject(filename); 00102 slCamera(); 00103 00104 Bool bad; 00105 lc = 1; 00106 char *word = NULL; 00107 00108 for (;;) { 00109 if (feof(fp)) strcpy(word, "end"); 00110 else word = fread_word(fp); 00111 bad = false; 00112 00113 switch (word[0]) { 00114 case '#': // comment 00115 fread_to_eol(fp); 00116 break; 00117 00118 case '/': // comment 00119 fread_to_eol(fp); 00120 break; 00121 00122 case 'a': 00123 if (!strcmp(word, "ambient")) { 00124 // ambient = fread_Vector(fp); 00125 // ambient *= fread_number(fp); 00126 fread_Vector(fp); 00127 fread_number(fp); 00128 } 00129 else bad = true; 00130 break; 00131 case 'b': 00132 if (!strcmp(word, "background")) { 00133 // background = fread_Vector(fp); 00134 // background *= fread_number(fp); 00135 fread_Vector(fp); 00136 fread_number(fp); 00137 } 00138 else bad = true; 00139 break; 00140 case 'd': 00141 if (!strcmp(word, "diffuse")) { 00142 /* 00143 cur_material().color = fread_Vector(fp); 00144 cur_material().kdiffrefl = fread_number(fp); 00145 cur_material().kspecrefl = 0.; 00146 cur_material().kspectran = 0.; 00147 cur_material().exponent = 0.; 00148 cur_material().indexrefr = 1.; 00149 cur_material().kemission = 0.; 00150 new_material = true; 00151 */ 00152 Colour c = fread_Colour(fp); 00153 slColour(c * fread_number(fp)); 00154 00155 } 00156 else if (!strcmp(word, "diffspec")) { 00157 /* 00158 cur_material().color = fread_Vector(fp); 00159 cur_material().kdiffrefl = fread_number(fp); 00160 cur_material().kspecrefl = fread_number(fp); 00161 cur_material().kspectran = fread_number(fp); 00162 cur_material().exponent = fread_number(fp); 00163 cur_material().indexrefr = fread_number(fp); 00164 cur_material().kemission = 0.; 00165 new_material = true; 00166 */ 00167 Colour c = fread_Colour(fp); 00168 slColour(c * fread_number(fp)); 00169 00170 fread_number(fp); 00171 fread_number(fp); 00172 fread_number(fp); 00173 fread_number(fp); 00174 } 00175 else bad = true; 00176 break; 00177 case 'e': 00178 if (!strcmp(word, "emissive")) { 00179 /* 00180 cur_material().color = fread_Vector(fp); 00181 cur_material().kdiffrefl = 0.; 00182 cur_material().kspecrefl = 0.; 00183 cur_material().kspectran = 0.; 00184 cur_material().exponent = 0.; 00185 cur_material().indexrefr = 1.; 00186 cur_material().kemission = fread_number(fp); 00187 new_material = true; 00188 */ 00189 Colour c = fread_Colour(fp); 00190 slEmittance(c * fread_number(fp)); 00191 00192 } 00193 else if (!strcmp(word, "end")) { 00194 cout << "Completed reading the scene\n"; 00195 fclose(fp); 00196 slEndObject(); 00197 return(result); 00198 } 00199 else bad = true; 00200 break; 00201 case 'g': 00202 if (!strcmp(word, "gpop")) { 00203 00204 /* if (!gstack.first()->next()) { 00205 cerr << "Scene Error, line " << lc 00206 << ": Can't pop top level gstate" << endl; 00207 exit(1); 00208 } 00209 gstack.pop(); 00210 cout << "popped stack" << endl; 00211 cout << gstack.first(); 00212 */ 00213 slEndObject(); 00214 00215 } 00216 else if (!strcmp(word, "gpush")) { 00217 00218 /* gstack.dup(); 00219 // dup() copies the material structure, light list 00220 // header, and matrix stack headers. 00221 // At this point, cur_matrix() points to the same 00222 // matrix as before the dup(). 00223 00224 // Set up matrix stack in new Gstate so that it contains a 00225 // copy of current matrix, and nothing else. 00226 // That way, if someone does too many pops, they'll get 00227 // an error message. 00228 // (push and pop must be nested within gpush, gpop) 00229 Matrix_item *m = new Matrix_item(*cur_matrix()); 00230 gstack.first()->matrix_stack.init(); 00231 gstack.first()->matrix_stack.push(*m); 00232 */ 00233 00234 slBeginObject("bob"); 00235 00236 } 00237 else bad = true; 00238 break; 00239 case 'l': 00240 if (!strcmp(word, "lookat")) { 00241 Vec3d from = fread_Vector(fp); 00242 Vec3d to = fread_Vector(fp); 00243 Vec3d up = fread_Vector(fp); 00244 Vec3d vec = to-from; 00245 00246 if (up[2] > 0) 00247 slTransform(Rotation(vl_x, -vl_pi / 2.0)); 00248 else if (up[1] > 0) 00249 slTransform(Rotation(vl_z, vl_pi / 2.0)); 00250 00251 /* double alpha; 00252 if (vec[1]!=0 || vec[2]!=0) alpha = atan2(-vec[1], -vec[2]); 00253 else alpha = 0.; 00254 double beta 00255 = atan2(vec[0], sqrt(vec[1]*vec[1] + vec[2]*vec[2])); 00256 Matrix rm; 00257 rm.MakeUnit(); // identity 00258 rm.rotate('x', -alpha); 00259 rm.rotate('y', -beta); 00260 00261 double gamma 00262 = atan2(up[0]*rm[0][0]+up[1]*rm[1][0]+up[2]*rm[2][0], 00263 up[0]*rm[0][1]+up[1]*rm[1][1]+up[2]*rm[2][1]); 00264 cur_matrix()->rotate('z', gamma); 00265 cur_matrix()->rotate('y', beta); 00266 cur_matrix()->rotate('x', alpha); 00267 cur_matrix()->translate(-from[0], -from[1], -from[2]); 00268 */ 00269 00270 00271 } 00272 else bad = true; 00273 break; 00274 case 'p': 00275 if (!strcmp(word, "persp")) { 00276 fread_number(fp); 00277 fread_number(fp); 00278 } 00279 else if (!strcmp(word, "pointlight")) { 00280 // Light_item *light = new Light_item; 00281 Vec3d pos = fread_Vector(fp); 00282 /* light->position = transform33(*cur_matrix(), pos); 00283 light->color = fread_Vector(fp); 00284 light->color *= fread_number(fp); 00285 cur_lights().append(*light); 00286 */ 00287 fread_Vector(fp); 00288 fread_number(fp); 00289 } 00290 else if (!strcmp(word, "poly3") || !strcmp(word, "poly2")) { 00291 int poly3 = !strcmp(word, "poly3"); 00292 int nvert = (int)fread_number(fp); 00293 00294 if (nvert<3) { 00295 cerr << "Scene Error, line " << lc 00296 << ": poly needs >=3 vertices." << endl; 00297 exit(1); 00298 } 00299 // Polygon *p = new Polygon; 00300 Vec3d point; 00301 int i; 00302 00303 slPointList(); 00304 00305 for (i=0; i<nvert; i++) { 00306 point[0] = fread_number(fp); 00307 point[1] = fread_number(fp); 00308 if (poly3) point[2] = fread_number(fp); 00309 else point[2] = 0.; 00310 // point = transform33(*cur_matrix(), point); 00311 // p->append_vertex(point); 00312 00313 slPoint(point); 00314 } 00315 slPoly(); 00316 00317 // p->precompute(); // set plane & edge equations 00318 // append_prim(*p); 00319 } 00320 else if (!strcmp(word, "pop")) { 00321 /* if (!cur_matrix()->next()) { 00322 cerr << "Scene Error, line " << lc 00323 << ": Attempt to pop last matrix on stack" << endl; 00324 exit(1); 00325 } 00326 gstack.first()->matrix_stack.pop(); 00327 */ 00328 00329 slEndObject(); 00330 } 00331 else if (!strcmp(word, "push")) { 00332 // gstack.first()->matrix_stack.dup(); 00333 slBeginObject("bob"); 00334 } 00335 else bad = true; 00336 break; 00337 case 'r': 00338 if (!strcmp(word, "rotate")) { 00339 char *axis = fread_word(fp); 00340 double angle = fread_number(fp); 00341 if (!axis[1] && (axis[0]=='x' || axis[0]=='y' || axis[0]=='z')) 00342 // cur_matrix()->rotate(axis[0], angle*M_PI/180.); 00343 slTransform(Rotation(vl_axis(axis[0] - 'x'), DegsToRads(angle))); 00344 else { 00345 cerr << "Scene Error, line " << lc 00346 << ": Illegal rotate axis (" << axis << ")" << endl; 00347 exit(1); 00348 } 00349 } 00350 else if (!strcmp(word, "rotgen")) { 00351 Vec3d v = fread_Vector(fp); 00352 double angle = fread_number(fp); 00353 slTransform(Rotation(v, DegsToRads(angle))); 00354 } 00355 else bad = true; 00356 break; 00357 case 's': 00358 if (!strcmp(word, "scale")) { 00359 double sx, sy, sz; 00360 sx = fread_number(fp); 00361 sy = fread_number(fp); 00362 sz = fread_number(fp); 00363 slTransform(Scale(Vector(sx, sy, sz))); 00364 } 00365 else if (!strcmp(word, "screensize")) { 00366 /* 00367 double dscale = (double)scale / 100.0; 00368 double sx = dscale * fread_number(fp); 00369 double sy = dscale * fread_number(fp); 00370 double sz = dscale * fread_number(fp); 00371 width = (int)sx; 00372 height = (int)sy; 00373 cur_matrix()->scale(sx/2.0, -sy/2.0, sz/2); 00374 cur_matrix()->translate(1, -1, 0); 00375 */ 00376 00377 fread_number(fp); 00378 fread_number(fp); 00379 fread_number(fp); 00380 00381 } 00382 else if (!strcmp(word, "sphere")) { 00383 Vec3d center = fread_Vector(fp); 00384 double radius = fread_number(fp); 00385 } 00386 else bad = true; 00387 break; 00388 case 't': 00389 if (!strcmp(word, "translate")) { 00390 double tx, ty, tz; 00391 tx = fread_number(fp); 00392 ty = fread_number(fp); 00393 tz = fread_number(fp); 00394 00395 slTransform(Shift(Vector(tx, ty, tz))); 00396 } 00397 else bad = true; 00398 break; 00399 case 'w': 00400 if (!strcmp(word, "world_space")) { 00401 // currently, all matrices in matrix stacks transform to screen 00402 // space 00403 00404 // save world-to-screen transform 00405 // world_to_screen = *cur_matrix(); 00406 00407 // Step through matrix stacks of all previous graphics states 00408 // and premultiply their matrices by screen_to_world space, 00409 // so that all matrices henceforth transform to world space. 00410 00411 // We could just flush all previous graphics states and all 00412 // matrix stacks, but that is less elegant. 00413 // Doing it this way allows you to place geometry relative to 00414 // camera, and even in screen space. 00415 // Gstate_item *gs; 00416 // Matrix_item *m; 00417 // Matrix sw = inv(world_to_screen); 00418 // for (gs=gstack.first(); gs; gs=gs->next()) 00419 // for (m=gs->matrix_stack.first(); m; m=m->next()) 00420 // *m = sw * *m; // 4x4 matrix multiply 00421 00422 // cur_matrix() is identity+roundoff at this point 00423 // cur_matrix()->MakeUnit(); // to eliminate the roundoff 00424 // (just being fussy) 00425 } 00426 else bad = true; 00427 break; 00428 case 'x': 00429 if (!strcmp(word, "xyzrange")) { 00430 // double xn, xf, yn, yf, zn, zf; 00431 /*xn =*/ fread_number(fp); 00432 /*xf =*/ fread_number(fp); 00433 /*yn =*/ fread_number(fp); 00434 /*yf =*/ fread_number(fp); 00435 /*zn =*/ fread_number(fp); 00436 /*zf =*/ fread_number(fp); 00437 // cur_matrix()->scale(2./(xf-xn), 2./(yf-yn), 2./(zf-zn)); 00438 // cur_matrix()->translate((xf+xn)/-2., (yf+yn)/-2., (zf+zn)/-2.); 00439 } 00440 else bad = true; 00441 break; 00442 case 'z': 00443 if (!strcmp(word, "zrange")) { 00444 //double zn, zf; 00445 /*zn =*/ fread_number(fp); 00446 /*zf =*/ fread_number(fp); 00447 // cur_matrix()->translate(0., 0., (zf+zn)/(zf-zn)); 00448 // cur_matrix()->scale(1., 1., -2./(1./zn-1./zf)); 00449 } 00450 else bad = true; 00451 break; 00452 default: 00453 bad = true; 00454 break; 00455 } 00456 00457 if (bad) { 00458 cerr << "Scene Error, line " << lc 00459 << ": bad keyword (" << word << ")." << endl; 00460 exit(1); 00461 } 00462 } 00463 } 00464 00465 #endif