home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 2 / LSD and 17bit Compendium Deluxe - Volume II.iso / a / prog / cprog / tdddconv.lha / read.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-12  |  32.7 KB  |  1,043 lines

  1. /* read.c - read a TTDDD file and fill the structures
  2.  *        - written by Glenn M. Lewis - 7/19/91
  3.  */
  4.  
  5. static char rcs_id[] = "$Id: read.c,v 1.12 1991/10/14 16:40:43 glewis Exp glewis $";
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include "ttdddlib.h"
  10.  
  11. static void process_INFO();
  12. static void process_OBJ();
  13. static OBJECT *process_EXTR();
  14. static void process_DESC();
  15.  
  16. #define MAXLINE 132
  17. #define get_UBYTE    (UBYTE)get_num
  18. #define get_UWORD    (UWORD)get_num
  19. #define get_ULONG    (ULONG)get_num
  20.  
  21. static char strin[MAXLINE+1], ps[MAXLINE+1];
  22.  
  23. /* Here are a few necessary utilities */
  24.  
  25. static void warn(curline)
  26. int curline;
  27. {
  28.     fprintf(stderr, "WARNING: Line %d: ", curline);
  29. }
  30.  
  31. static void parse_word(name, lim, up)    /* Get next word, optionally limit # of chars */
  32. register char *name;
  33. int lim, up;
  34. {
  35.     register char *c = &strin[0];
  36.     register int i;
  37.     int quote = 0;
  38.  
  39.     while (*c==' ') c++;        /* Skip over leading spaces */
  40.     for (i=0; *c; i++,c++) {
  41.         if (lim && i>=lim) break;    /* No more characters desired */
  42.         if (*c == '\"') {            /* Chop off quotes, ignore spaces */
  43.             if (quote) break;        /* Second quote.  Stop reading string */
  44.             quote=1;
  45.             i--;                    /* Don't want i to increment */
  46.             continue;
  47.         }
  48.         if (up && !quote && islower(*c)) *name++ = toupper(*c);
  49.         else {
  50.             if (!quote && *c==' ') break;    /* End of the line */
  51.             *name++ = *c;            /* Don't modify original case */
  52.         }
  53.     }
  54.     *name = '\0';    /* Truncate the puppy */
  55.     /* Now, delete the command from 'strin' */
  56.     while (*c && *c!=' ') c++;    /* Skip the end of the command */
  57.     while (*c==' ') c++;        /* Skip mid-word spacing */
  58.     strcpy(strin, c);            /* Chop off front of line */
  59. }
  60.  
  61. static int get_line(strin, w)
  62. register char *strin;
  63. WORLD *w;
  64. {
  65.     static int comment = 0;
  66.     int quote = 0, start;
  67.     register char *c;
  68.     extern int already_read_header;            /* A hack to include characters */
  69.     extern unsigned char header_storage[];    /* that were already read from in */
  70.  
  71. GET_MORE:
  72.     if (comment) start = 0; else start = -1;
  73.     if (fgets(&strin[already_read_header], MAXLINE, w->inp) == NULL) {
  74.         already_read_header = 0;
  75.         if (comment)
  76.         fprintf(stderr, "WARNING: Line %d: Unterminated comment.\n",w->cur_line);
  77.         return(0);    /* EOF */
  78.     }
  79.     already_read_header = 0;
  80.     w->cur_line++;
  81.     for (c=strin; *c; c++) {
  82.         if (*c=='/' && c[1]=='*') {            /* Begin of comment */
  83.             if (!quote) {
  84.                 if (!comment++) {            /* First comment */
  85.                     start = (int)(c-strin);
  86.                 }
  87.             }
  88.         } else
  89.         if (*c=='*' && c[1]=='/') {            /* End of comment */
  90.             if (!quote) {
  91.                 comment--;
  92.                 if (comment<0) {
  93.                     fprintf(stderr, "ERROR!  '*/' before '/*'\n*** ABORT ***\n");
  94.                     exit(20);
  95.                 }
  96.                 if (!comment) {                /* Chop off front of line */
  97.                     strcpy(strin, c+2);
  98.                     c = strin-1;            /* Pointer will increment */
  99.                 }
  100.             }
  101.         } else
  102.         if (*c=='%') {                        /* Line comment */
  103.             if (!(quote || comment)) {
  104.                 *c = '\0';                    /* Terminate line */
  105.                 break;
  106.             }
  107.         } else
  108.         if (*c =='\"') {                    /* Quote */
  109.             if (!comment) quote=1-quote;    /* Toggle flag */
  110.         } else
  111.         if (*c == '\t') *c = ' ';            /* Change tabs to spaces */
  112.         else
  113.         if (!quote && (*c=='[' || *c==']' || *c=='=')) *c = ' ';
  114.         if (*c == '\n') { *c = '\0'; break; }
  115.     }
  116.     if (comment) strin[start] = '\0';        /* Chop off comment */
  117. /* Skip leading white space to see if this line contains anything */
  118.     for (c=strin; *c==' '; c++) ;
  119.     if (!*c) goto GET_MORE;
  120.     return(1);
  121. }
  122.  
  123. static int valid_num;
  124.  
  125. static long get_num()
  126. {
  127.     long val = 0;
  128.     char neg = ' ';
  129.     register char *c = &strin[0];
  130.  
  131.     valid_num = 0;
  132.     while (*c == ' ') c++;        /* Skip leading space */
  133.     if (*c == '-') neg = *c++;    /* Save the negation  */
  134.     if (!isdigit(*c)) return(0L);
  135.     while (*c && isdigit(*c))
  136.         val = (val*10) + (*c++ - '0');
  137.     while (*c == ' ') c++;        /* Skip trailing space */
  138.     strcpy(strin, c);            /* Chop off number */
  139.     valid_num = 1;
  140.     return((neg=='-' ? -val : val));
  141. }
  142.  
  143. static int valid_FRACT;
  144.  
  145. static double get_FRACT()
  146. {
  147.     register long whole, frac, place;
  148.     register char *s = &strin[0];
  149.     char neg = ' ';
  150.     double f;
  151.  
  152.     valid_FRACT = 0;
  153.     whole = 0;
  154.     while (*s == ' ') s++;
  155.     if (*s == '-') neg = *s++;
  156.     if (!isdigit(*s) && *s!='.') return(0L);    /* Invalid FRACT */
  157.     while (*s && isdigit(*s))        /* Handle float before decimal point */
  158.         whole = (whole * 10) + (*s++ - '0');
  159.     if (*s == '.') {        /* Handle float after decimal point */
  160.         s++;
  161.         frac = 0;
  162.         for (place=1; *s && isdigit(*s); place*=10)
  163.             frac = (frac * 10) + (*s++ - '0');
  164.         f = (double)whole + ((double)frac/(double)place);
  165.     } else f = (double)whole;
  166.     while (*s == ' ') s++;
  167.     strcpy(strin, s);
  168.     valid_FRACT = 1;
  169.     return((neg=='-' ? -f : f));
  170. }
  171.  
  172. static void stuff_XYZ(st)
  173. XYZ_st *st;
  174. {
  175.     register char *c = &strin[0];
  176.     register int i, flag, cnt;
  177.  
  178.     flag = 0;    /* If they use 'X','Y', or 'Z', they must continue to use it */
  179.     /* On the other hand, if they give only a single parameter, then it applies to all */
  180.     cnt = 0;
  181.     for (i=0; i<3; i++) {
  182.         if (*c=='x' || *c=='X')        /* If !valid, it's an ERROR! */
  183.         { *c=' '; st->val[0] = get_FRACT(); if (valid_FRACT) flag=1; }
  184.         else
  185.         if (*c=='y' || *c=='Y')
  186.         { *c=' '; st->val[1] = get_FRACT(); if (valid_FRACT) flag=1; }
  187.         else
  188.         if (*c=='z' || *c=='Z')
  189.         { *c=' '; st->val[2] = get_FRACT(); if (valid_FRACT) flag=1; }
  190.         else if (!flag) {
  191.             st->val[i] = get_FRACT();
  192.             if (valid_FRACT) cnt++;
  193.         }
  194.     }
  195.     if (!flag && cnt==1) {     /* Copy value into other two elements */
  196.         st->val[1] = st->val[2] = st->val[0];
  197.     }
  198. }
  199.  
  200. static void stuff_RGB(st)
  201. RGB_st *st;
  202. {
  203.     register char *c = &strin[0];
  204.     register int i, flag, cnt;
  205.  
  206.     flag = 0;    /* If they use 'R','G', or 'B', they must continue to use it */
  207.     /* On the other hand, if they give only a single parameter, then it applies to all */
  208.     cnt = 0;
  209.     for (i=0; i<3; i++) {
  210.         if (*c=='r' || *c=='R')        /* If !valid, it's an ERROR! */
  211.         { *c=' '; st->val[0] = get_UBYTE(); if (valid_num) flag=1; }
  212.         else
  213.         if (*c=='g' || *c=='G')
  214.         { *c=' '; st->val[1] = get_UBYTE(); if (valid_num) flag=1; }
  215.         else
  216.         if (*c=='b' || *c=='B')
  217.         { *c=' '; st->val[2] = get_UBYTE(); if (valid_num) flag=1; }
  218.         else if (!flag) {
  219.             st->val[i] = get_UBYTE();
  220.             if (valid_num) cnt++;
  221.         }
  222.     }
  223.     if (!flag && cnt==1) {     /* Copy value into other two elements */
  224.         st->val[1] = st->val[2] = st->val[0];
  225.     }
  226. }
  227.  
  228. /********************/
  229. /* The MAIN section */
  230. /********************/
  231.  
  232. WORLD *read_TTDDD(file)
  233. FILE *file;
  234. {
  235.     char name[5];
  236.     int i;
  237.     WORLD *world;
  238.  
  239.     if (!file) return(0L); /* File not open */
  240.  
  241.     if (!(world = (WORLD*)malloc(sizeof(WORLD)))) { OUT_MEM("WORLD"); }
  242.     bzero((char*)world, sizeof(WORLD));
  243.     world->inp = file;
  244.  
  245. /* Here is the main loop: */
  246.     while (get_line(strin, world)) {
  247.         parse_word(name, 4, 1);        /* And chop it out of the string */
  248.  
  249.         if        (strcmp(name, "INFO")==0) process_INFO(world);
  250.         else if (strcmp(name, "OBJ") ==0) process_OBJ(world);
  251.         else {
  252.             fprintf(stderr, "Invalid chunk on line %d: '%s' (skipped)\n",
  253.                 world->cur_line, name);
  254.             continue;
  255.         }
  256.     }
  257.  
  258. /* All done.  Close up shop. */
  259.     return(world);
  260. }
  261.  
  262. static void process_INFO(world)
  263. WORLD *world;
  264. {
  265.     register INFO *info;
  266.     register ULONG i;
  267.     char this_level[MAXLINE], name[5];
  268.  
  269.     if (world->info) {
  270.         fprintf(stderr, "Parse error: More than one INFO chunk!\n"); exit(-1); }
  271.     if (!(info = world->info = (INFO*)malloc(sizeof(INFO)))) { OUT_MEM("INFO"); }
  272.     bzero((char *)world->info, sizeof(INFO));
  273.  
  274.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  275.     if (strcmp(this_level, "BEGIN") != 0) {
  276.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'INFO'\n",
  277.             world->cur_line);
  278.     }
  279.     parse_word(this_level, 0, 0);    /* No limit, original case */
  280.  
  281.     while (get_line(strin, world)) {
  282.         parse_word(name, 4, 1);        /* Get command */
  283.         if (strcmp(name, "BRSH")==0) {
  284.             i = get_UWORD();
  285.             if (i<0 || i>7) fputs("BRSH error.\n", stderr);
  286.             parse_word(ps, 0, 0);
  287.             strncpy(info->brsh[i], ps, 80);
  288.             info->brsh[i][80]='\0';
  289.         } else
  290.         if (strcmp(name, "STNC")==0) {
  291.             i = get_UWORD();
  292.             if (i<0 || i>7) fputs("STNC error.\n", stderr);
  293.             parse_word(ps, 0, 0);
  294.             strncpy(info->stnc[i], ps, 80);
  295.             info->stnc[i][80]='\0';
  296.         } else
  297.         if (strcmp(name, "TXTR")==0) {
  298.             i = get_UWORD();
  299.             if (i<0 || i>7) fputs("TXTR error.\n", stderr);
  300.             parse_word(ps, 0, 0);
  301.             strncpy(info->txtr[i], ps, 80);
  302.             info->txtr[i][80]='\0';
  303.         } else
  304.         if (strcmp(name, "OBSV")==0) {
  305.             if (!info->obsv) info->obsv=(OBSV*)malloc(sizeof(OBSV));
  306.             if (!info->obsv) { OUT_MEM("OBSV"); }
  307.             parse_word(name, 4, 1);        /* Get field */
  308.             if        (strcmp(name, "CAME")==0) stuff_XYZ(&info->obsv->came);
  309.             else if (strcmp(name, "ROTA")==0) stuff_XYZ(&info->obsv->rota);
  310.             else if (strcmp(name, "FOCA")==0) info->obsv->foca = get_FRACT();
  311.             else {
  312.                 fprintf(stderr, "WARNING: Line %d: Unknown OBSV field: '%s'\n", world->cur_line, name);
  313.                 continue;
  314.             }
  315.         } else
  316.         if (strcmp(name, "OTRK")==0) {
  317.             parse_word(ps, 0, 0);
  318.             strncpy(info->otrk, ps, 18);
  319.             info->otrk[18]='\0';
  320.         } else
  321.         if (strcmp(name, "OSTR")==0) {
  322.             if (!info->ostr) info->ostr=(STRY*)malloc(sizeof(STRY));
  323.             if (!info->ostr) { OUT_MEM("OSTR"); }
  324.             parse_word(name, 4, 1);        /* Get field */
  325.             if (strcmp(name, "PATH")==0) parse_word(info->ostr->path, 18, 0);
  326.             else if (strcmp(name, "TRAN")==0) stuff_XYZ(&info->ostr->tran);
  327.             else if (strcmp(name, "ROTA")==0) stuff_XYZ(&info->ostr->rota);
  328.             else if (strcmp(name, "SCAL")==0) stuff_XYZ(&info->ostr->scal);
  329.             else
  330.             if (strcmp(name, "INFO")==0) {
  331.                 info->ostr->info = 0;
  332.                 while (strin[0]) {
  333.                     parse_word(ps, 7, 1);
  334.                     if        (strcmp(ps, "ABS_TRA")==0) info->ostr->info|=(1<<0);
  335.                     else if (strcmp(ps, "ABS_ROT")==0) info->ostr->info|=(1<<1);
  336.                     else if (strcmp(ps, "ABS_SCL")==0) info->ostr->info|=(1<<2);
  337.                     else if (strcmp(ps, "LOC_TRA")==0) info->ostr->info|=(1<<4);
  338.                     else if (strcmp(ps, "LOC_ROT")==0) info->ostr->info|=(1<<5);
  339.                     else if (strcmp(ps, "LOC_SCL")==0) info->ostr->info|=(1<<6);
  340.                     else if (strcmp(ps, "X_ALIGN")==0) info->ostr->info|=(1<<8);
  341.                     else if (strcmp(ps, "Y_ALIGN")==0) info->ostr->info|=(1<<9);
  342.                     else if (strcmp(ps, "Z_ALIGN")==0) info->ostr->info|=(1<<10);
  343.                     else if (strcmp(ps, "FOLLOW_")==0) info->ostr->info|=(1<<12);
  344.                     else {
  345.                         fprintf(stderr, "WARNING: Line %d: Unknown OSTR INFO flag: '%s'\n", world->cur_line, ps);
  346.                         continue;
  347.                     }
  348.                 }
  349.             } else {
  350.                 fprintf(stderr, "WARNING: Line %d: Unknown OSTR field: '%s'\n", world->cur_line, name);
  351.                 continue;
  352.             }
  353.         } else
  354.         if (strcmp(name, "FADE")==0) {
  355.             if (!info->fade) info->fade=(FADE*)malloc(sizeof(FADE));
  356.             if (!info->fade) { OUT_MEM("FADE"); }
  357.             parse_word(ps, 6, 1);        /* Get field */
  358.             if        (strcmp(ps, "FADEAT")==0) info->fade->at = get_FRACT();
  359.             else if (strcmp(ps, "FADEBY")==0) info->fade->by = get_FRACT();
  360.             else if (strcmp(ps, "FADETO")==0) stuff_RGB(&info->fade->to);
  361.             else {
  362.                 fprintf(stderr, "WARNING: Line %d: Unknown FADE field: '%s'\n", world->cur_line, ps);
  363.                 continue;
  364.             }
  365.         } else
  366.         if (strcmp(name, "SKYC")==0) {
  367.             if (!info->skyc) info->skyc=(SKYC*)malloc(sizeof(SKYC));
  368.             if (!info->skyc) { OUT_MEM("SKYC"); }
  369.             parse_word(name, 4, 1);        /* Get field */
  370.             if        (strcmp(name, "HORI")==0) stuff_RGB(&info->skyc->hori);
  371.             else if (strcmp(name, "ZENI")==0) stuff_RGB(&info->skyc->zeni);
  372.             else {
  373.                 fprintf(stderr, "WARNING: Line %d: Unknown SKYC field: '%s'\n", world->cur_line, name);
  374.                 continue;
  375.             }
  376.         } else
  377.         if (strcmp(name, "AMBI")==0) {
  378.             if (!info->ambi) info->ambi=(RGB_st*)malloc(sizeof(RGB_st));
  379.             if (!info->ambi) { OUT_MEM("AMBI"); }
  380.             stuff_RGB(info->ambi);
  381.         } else
  382.         if (strcmp(name, "GLB0")==0) {
  383.             if (!info->glb0) info->glb0=(BYTE*)malloc(8*sizeof(BYTE));
  384.             if (!info->glb0) { OUT_MEM("GLB0"); }
  385.             i = get_ULONG();    /* Index into array */
  386.             if (i>=0 && i<8) {
  387.                 info->glb0[i] = (BYTE) get_ULONG();
  388.             } else
  389.                 fprintf(stderr, "WARNING: Line %d: Bad index: GLB0[%d] should be [0..7]\n", world->cur_line, i);
  390.         } else if (strcmp(name, "END")==0) {
  391.             parse_word(name, 4, 1);
  392.             if (strcmp(name, "INFO")!=0)
  393.                 fprintf(stderr, "WARNING: Line %d: Expected 'END INFO' but got: 'END %s'\n", world->cur_line, name);
  394.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  395.             if (strcmp(this_level, ps)!=0)
  396.                 fprintf(stderr, "WARNING: Line %d: 'INFO Begin' and 'End INFO' quoted comments do not match\n", world->cur_line);
  397.             break;
  398.         } else fprintf(stderr, "WARNING: Line %d: Unknown INFO sub-sub-chunk: '%s'\n", world->cur_line, name);
  399.     }
  400. }
  401.  
  402. OBJECT *create_object()
  403. {
  404.     OBJECT *p;
  405.     p = (OBJECT*)malloc(sizeof(OBJECT));
  406.     if (!p) { OUT_MEM("Create"); }
  407.     bzero((char*)p,sizeof(OBJECT));
  408.     return(p);
  409. }
  410.  
  411. static void process_OBJ(world)
  412. WORLD *world;
  413. {
  414.     char this_level[MAXLINE], name[5];
  415.     register OBJECT *p;
  416.     int depth;
  417.  
  418.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  419.     if (strcmp(this_level, "BEGIN") != 0) {
  420.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'OBJ'\n",
  421.             world->cur_line);
  422.     }
  423.     parse_word(this_level, 0, 0);    /* No limit, original case */
  424.  
  425.     depth=0;
  426.     while (get_line(strin, world)) {
  427.         parse_word(name, 4, 1);        /* Get command */
  428.         if        (strcmp(name, "EXTR")==0) {
  429.             p = process_EXTR(create_object(), world);
  430.             if (world->curobj) {
  431.                 world->curobj->next = p;
  432.                 p->parent = world->curobj->parent;
  433.             } else {
  434.                 world->object = p;
  435.                 p->parent = 0;
  436.             }
  437.             world->curobj = p;
  438.         } else if (strcmp(name, "DESC")==0) {
  439.             p = create_object();
  440.             if (world->num_DESC > world->num_TOBJ+depth) {    /* This is a child */
  441.                 depth++;    /* Down one in the hierarchy */
  442.                 world->curobj->child = p;
  443.                 p->parent = world->curobj;
  444.             } else {
  445.                 if (world->curobj) {
  446.                     world->curobj->next = p;
  447.                     p->parent = world->curobj->parent;
  448.                 } else {
  449.                     world->object = p;
  450.                     p->parent = 0;
  451.                 }
  452.             }
  453.             world->curobj = p;
  454.             process_DESC(&p->desc, world);
  455.         } else if (strcmp(name, "TOBJ")==0) {
  456.             world->num_TOBJ++;
  457.             if (world->num_TOBJ > world->num_DESC) {
  458.                 warn(world->cur_line);
  459.                 fprintf(stderr, "TOBJ without DESC.  Ignored.\n");
  460.             }
  461.             if (world->num_TOBJ+depth > world->num_DESC) {    /* Go back up a level */
  462.                 depth--;
  463.                 world->curobj=world->curobj->parent;
  464.             }
  465.         } else if (strcmp(name, "END" )==0) {
  466.             if (world->num_DESC > world->num_TOBJ) {
  467.                 int i;
  468.                 warn(world->cur_line);
  469.                 i = world->num_DESC - world->num_TOBJ;
  470.                 fprintf(stderr, "Missing %d 'TOBJ'.  Inserted.\n", i);
  471.             }
  472.             parse_word(name, 4, 1);
  473.             if (strcmp(name, "OBJ")!=0)
  474.                 fprintf(stderr, "WARNING: Line %d: Expected 'END OBJ' but got: 'END %s'\n", world->cur_line, name);
  475.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  476.             if (strcmp(this_level, ps)!=0)
  477.                 fprintf(stderr, "WARNING: Line %d: 'OBJ Begin' and 'End OBJ' quoted comments do not match\n", world->cur_line);
  478.             break;
  479.         } else
  480.         fprintf(stderr, "WARNING: Line %d: Unknown OBJ sub-sub-chunk: '%s'\n",
  481.             world->cur_line, name);
  482.     }
  483. }
  484.  
  485. static OBJECT *process_EXTR(obj, world)
  486. OBJECT *obj;
  487. WORLD *world;
  488. {
  489.     register EXTR *extr;
  490.     register OBJECT *p;
  491.     char this_level[MAXLINE], name[5];
  492.     MTRX *mtrx;
  493.     WORLD *new;
  494.     FILE *newinp;
  495.  
  496.     if (!(extr = obj->extr = (EXTR*)malloc(sizeof(EXTR)))) { OUT_MEM("EXTR"); }
  497.     bzero((char*)extr, sizeof(EXTR));
  498.     mtrx = &extr->mtrx;
  499.     /* Initialize structure */
  500.     mtrx->tran.val[0]  = mtrx->tran.val[1]  = mtrx->tran.val[2]  = 0.0;
  501.     mtrx->scal.val[0]  = mtrx->scal.val[1]  = mtrx->scal.val[2]  = 1.0;
  502.     mtrx->rota1.val[1] = mtrx->rota1.val[2] = 0.0;
  503.     mtrx->rota2.val[0] = mtrx->rota2.val[2] = 0.0;
  504.     mtrx->rota3.val[0] = mtrx->rota3.val[1] = 0.0;
  505.     mtrx->rota1.val[0] = mtrx->rota2.val[1] = mtrx->rota3.val[2] = 1.0;
  506.  
  507.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  508.     if (strcmp(this_level, "BEGIN") != 0) {
  509.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'EXTR'\n",
  510.             world->cur_line);
  511.     }
  512.     parse_word(this_level, 0, 0);    /* No limit, original case */
  513.  
  514.     while (get_line(strin, world)) {
  515.         parse_word(name, 4, 1);        /* Get command */
  516.         if        (strcmp(name, "MTRX")==0) {
  517.             parse_word(name, 4, 1);        /* Get field */
  518.             if      (strcmp(name, "TRAN")==0) stuff_XYZ(&mtrx->tran);
  519.             else if (strcmp(name, "SCAL")==0) stuff_XYZ(&mtrx->scal);
  520.             else if (strcmp(name, "ROTA")==0) {
  521.                 stuff_XYZ(&mtrx->rota1);
  522.                 stuff_XYZ(&mtrx->rota2);
  523.                 stuff_XYZ(&mtrx->rota3);
  524.             } else {
  525.                 fprintf(stderr, "WARNING: Line %d: Unknown MTRX field: '%s'\n", world->cur_line, name);
  526.                 continue;
  527.             }
  528.         } else if (strcmp(name, "LOAD")==0) {
  529.             parse_word(extr->filename, 80, 0);
  530.         } else if (strcmp(name, "END" )==0) {
  531.             parse_word(name, 4, 1);
  532.             if (strcmp(name, "EXTR")!=0)
  533.                 fprintf(stderr, "WARNING: Line %d: Expected 'END EXTR' but got: 'END %s'\n", world->cur_line, name);
  534.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  535.             if (strcmp(this_level, ps)!=0)
  536.                 fprintf(stderr, "WARNING: Line %d: 'EXTR Begin' and 'End EXTR' quoted comments do not match\n", world->cur_line);
  537.             break;
  538.         } else fprintf(stderr, "WARNING: Line %d: Unknown EXTR sub-sub-chunk: '%s'\n", world->cur_line, name);
  539.     }
  540.     /* Now, load in the external object */
  541.     if (!(newinp=fopen(extr->filename, "r"))) {
  542.         fprintf(stderr, "Can't load in EXTR object: '%s'... ignored.\n",
  543.             extr->filename);
  544.         return(obj);
  545.     }
  546.     new = read_World(newinp);
  547.     fclose(newinp);
  548.     /* scale, rotate, and translate new object hierarchy */
  549.     for (p=new->object; p; p=p->next)
  550.         move_extr(p, mtrx);
  551.     /* Free up unused memory */
  552.     free((char*)obj->extr);
  553.     free((char*)obj);
  554.     obj = new->object;
  555.     free((char*)new);
  556.     return(obj);
  557. }
  558.  
  559. void move_extr(obj, mtrx)
  560. register OBJECT *obj;
  561. register MTRX *mtrx;
  562. {
  563.     register XYZ_st *p;
  564.     register int i;
  565.     register double x, y, z;
  566.     if (obj->desc)
  567.         for (p=obj->desc->pnts,i=obj->desc->pcount; i--; p++) {
  568.             x = (p->val[0]*mtrx->scal.val[0]);
  569.             y = (p->val[1]*mtrx->scal.val[1]);
  570.             z = (p->val[2]*mtrx->scal.val[2]);
  571.             p->val[0] = x*mtrx->rota1.val[0] +
  572.                         y*mtrx->rota1.val[1] +
  573.                         z*mtrx->rota1.val[2] +
  574.                         mtrx->tran.val[0];
  575.             p->val[1] = x*mtrx->rota2.val[0] +
  576.                         y*mtrx->rota2.val[1] +
  577.                         z*mtrx->rota2.val[2] +
  578.                         mtrx->tran.val[1];
  579.             p->val[2] = x*mtrx->rota3.val[0] +
  580.                         y*mtrx->rota3.val[1] +
  581.                         z*mtrx->rota3.val[2] +
  582.                         mtrx->tran.val[2];
  583.         }
  584.     for (obj=obj->child; obj; obj=obj->next)
  585.         move_extr(obj, mtrx);    /* Process all children */
  586. }
  587.  
  588. void OUT_MEM(s)
  589. char *s;
  590. {
  591.     if (s)
  592.     fprintf(stderr, "Ran out of memory while processing '%s'.  Sorry.\n", s);
  593.     exit(-1);
  594. }
  595.  
  596. static UBYTE defclst[3], defrlst[3], deftlst[3], defspc1[3];
  597.  
  598. static void process_DESC(orig, world)
  599. DESC **orig;
  600. WORLD *world;
  601. {
  602.     register DESC *desc;
  603.     register int i;
  604.     char this_level[MAXLINE], name[5];
  605.  
  606.     if (!(desc = *orig = (DESC*)malloc(sizeof(DESC)))) { OUT_MEM("DESC"); }
  607.     bzero((char*)desc, sizeof(DESC));
  608.  
  609.     /* Set up defaults: */
  610.     defclst[0] = defclst[1] = defclst[2] = 240;    /* TS default */
  611.     defrlst[0] = defrlst[1] = defrlst[2] = 0;
  612.     deftlst[0] = deftlst[1] = deftlst[2] = 0;
  613.     defspc1[0] = defspc1[1] = defspc1[2] = 0;
  614.  
  615.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  616.     if (strcmp(this_level, "BEGIN") != 0) {
  617.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'DESC'\n",
  618.             world->cur_line);
  619.     }
  620.     parse_word(this_level, 0, 0);    /* No limit, original case */
  621.  
  622.     world->num_DESC++;
  623.  
  624.     while (get_line(strin, world)) {
  625.         parse_word(name, 4, 1);        /* Get command */
  626.         /* Put most-frequent commands near the front of this list */
  627.         if (strcmp(name, "PNTS")==0) {
  628.             parse_word(name, 4, 1);        /* Get field */
  629.             if          (strcmp(name, "POIN")==0) {
  630.                 if (!desc->pcount) {
  631.                     fprintf(stderr, "ERROR: Line %d: 'PNTS Point' encountered before 'PNTS PCount'\n", world->cur_line);
  632.                     OUT_MEM((char*)0);
  633.                 }
  634.                 i = get_UWORD();
  635.                 if (i<0 || i>=desc->pcount) {
  636.                     fprintf(stderr, "WARNING: Line %d: Bad index: PNTS Point[%d] should be [0..%d]\n", world->cur_line, i, desc->pcount);
  637.                     continue;
  638.                 }
  639.                 stuff_XYZ(&desc->pnts[i]);
  640.             } else if (strcmp(name, "PCOU")==0) {
  641.                 if (!desc->pcount) {
  642.                     desc->pcount = get_UWORD();
  643.                     if (!(desc->pnts = (XYZ_st*)malloc(desc->pcount*sizeof(XYZ_st))))
  644.                         OUT_MEM("PNTS");
  645.                     /* Initialize array */
  646.                     for (i=0; i<desc->pcount; i++) {
  647.                         desc->pnts[i].val[0] = 0;
  648.                         desc->pnts[i].val[1] = 0;
  649.                         desc->pnts[i].val[2] = 0;
  650.                     }
  651.                 } else {
  652.                     fprintf(stderr, "WARNING: Line %d: PNTS Pcount defined more than once.\n", world->cur_line);
  653.                 }
  654.             } else {
  655.                 fprintf(stderr, "WARNING: Line %d: Unknown PNTS field: '%s'\n", world->cur_line, name);
  656.                 continue;
  657.             }
  658.         } else
  659.         if (strcmp(name, "EDGE")==0) {
  660.             parse_word(name, 4, 1);        /* Get field */
  661.             if          (strcmp(name, "EDGE")==0) {
  662.                 if (!desc->ecount) {
  663.                     fprintf(stderr, "ERROR: Line %d: 'EDGE Edge' encountered before 'EDGE ECount'\n", world->cur_line);
  664.                     OUT_MEM((char*)0);
  665.                 }
  666.                 i = get_UWORD();
  667.                 if (i<0 || i>=desc->ecount) {
  668.                     fprintf(stderr, "WARNING: Line %d: Bad index: EDGE Edge[%d] should be [0..%d]\n", world->cur_line, i, desc->ecount);
  669.                     continue;
  670.                 }
  671.                 desc->edge[2*i]   = get_UWORD();
  672.                 desc->edge[2*i+1] = get_UWORD();
  673.             } else if (strcmp(name, "ECOU")==0) {
  674.                 if (!desc->ecount) {
  675.                     desc->ecount = get_UWORD();
  676.                     if (!(desc->edge = (UWORD*)malloc(2*desc->ecount*sizeof(UWORD))))
  677.                         OUT_MEM("EDGE");
  678.                     /* Initialize array */
  679.                     for (i=0; i<2*desc->ecount; i++)
  680.                         desc->edge[i] = 0;
  681.                 } else {
  682.                     fprintf(stderr, "WARNING: Line %d: EDGE Ecount defined more than once.\n", world->cur_line);
  683.                 }
  684.             } else {
  685.                 fprintf(stderr, "WARNING: Line %d: Unknown EDGE field: '%s'\n", world->cur_line, name);
  686.                 continue;
  687.             }
  688.         } else
  689.         if (strcmp(name, "FACE")==0) {
  690.             parse_word(name, 4, 1);        /* Get field */
  691.             if          (strcmp(name, "CONN")==0) {
  692.                 if (!desc->fcount) {
  693.                     fprintf(stderr, "ERROR: Line %d: 'FACE Connects' encountered before 'FACE TCount'\n", world->cur_line);
  694.                     OUT_MEM((char*)0);
  695.                 }
  696.                 i = get_UWORD();
  697.                 if (i<0 || i>=desc->fcount) {
  698.                     fprintf(stderr, "WARNING: Line %d: Bad index: FACE Connects[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount);
  699.                     continue;
  700.                 }
  701.                 desc->face[3*i]   = get_UWORD();
  702.                 desc->face[3*i+1] = get_UWORD();
  703.                 desc->face[3*i+2] = get_UWORD();
  704.             } else if (strcmp(name, "TCOU")==0) {
  705.                 i = get_UWORD();
  706.                 malloc_arrays(i, desc);
  707.             } else {
  708.                 fprintf(stderr, "WARNING: Line %d: Unknown FACE field: '%s'\n", world->cur_line, name);
  709.                 continue;
  710.             }
  711.         } else
  712.         if (strcmp(name, "CLST")==0) {
  713.             parse_word(name, 4, 1);        /* Get field */
  714.             if          (strcmp(name, "COLO")==0) {
  715.                 if (!desc->fcount) {
  716.                     fprintf(stderr, "ERROR: Line %d: 'CLST Color' encountered before 'CLST Count'\n", world->cur_line);
  717.                     OUT_MEM((char*)0);
  718.                 }
  719.                 i = get_UWORD();
  720.                 if (i<0 || i>=desc->fcount) {
  721.                     fprintf(stderr, "WARNING: Line %d: Bad index: CLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount);
  722.                     continue;
  723.                 }
  724.                 stuff_RGB((RGB_st*)&desc->clst[3*i]);    /* Place 3 UBYTE's into array */
  725.             } else if (strcmp(name, "COUN")==0) {
  726.                 i = get_UWORD();
  727.                 malloc_arrays(i, desc);
  728.             } else {
  729.                 fprintf(stderr, "WARNING: Line %d: Unknown CLST field: '%s'\n", world->cur_line, name);
  730.                 continue;
  731.             }
  732.         } else
  733.         if (strcmp(name, "RLST")==0) {
  734.             parse_word(name, 4, 1);        /* Get field */
  735.             if          (strcmp(name, "COLO")==0) {
  736.                 if (!desc->fcount) {
  737.                     fprintf(stderr, "ERROR: Line %d: 'RLST Color' encountered before 'RLST Count'\n", world->cur_line);
  738.                     OUT_MEM((char*)0);
  739.                 }
  740.                 i = get_UWORD();
  741.                 if (i<0 || i>=desc->fcount) {
  742.                     fprintf(stderr, "WARNING: Line %d: Bad index: RLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount);
  743.                     continue;
  744.                 }
  745.                 stuff_RGB((RGB_st*)&desc->rlst[3*i]);    /* Place three UBYTE's into array */
  746.             } else if (strcmp(name, "COUN")==0) {
  747.                 i = get_UWORD();
  748.                 malloc_arrays(i, desc);
  749.             } else {
  750.                 fprintf(stderr, "WARNING: Line %d: Unknown RLST field: '%s'\n", world->cur_line, name);
  751.                 continue;
  752.             }
  753.         } else
  754.         if (strcmp(name, "TLST")==0) {
  755.             parse_word(name, 4, 1);        /* Get field */
  756.             if          (strcmp(name, "COLO")==0) {
  757.                 if (!desc->fcount) {
  758.                     fprintf(stderr, "ERROR: Line %d: 'TLST Color' encountered before 'TLST Count'\n", world->cur_line);
  759.                     OUT_MEM((char*)0);
  760.                 }
  761.                 i = get_UWORD();
  762.                 if (i<0 || i>=desc->fcount) {
  763.                     fprintf(stderr, "WARNING: Line %d: Bad index: TLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount);
  764.                     continue;
  765.                 }
  766.                 stuff_RGB((RGB_st*)&desc->tlst[3*i]);    /* Place three UBYTE's into array */
  767.             } else if (strcmp(name, "COUN")==0) {
  768.                 i = get_UWORD();
  769.                 malloc_arrays(i, desc);
  770.             } else {
  771.                 fprintf(stderr, "WARNING: Line %d: Unknown TLST field: '%s'\n", world->cur_line, name);
  772.                 continue;
  773.             }
  774.         } else
  775.         if (strcmp(name, "NAME")==0) {
  776.             parse_word(ps, 0, 0);
  777.             strncpy(desc->name, ps, 18);
  778.             desc->name[18]='\0';
  779.         } else
  780.         if (strcmp(name, "SHAP")==0) {
  781.             if (!desc->shap) {
  782.                 if (!(desc->shap=(WORD*)malloc(2*sizeof(WORD))))
  783.                     { OUT_MEM("SHAP"); }
  784.                 desc->shap[0] = 1;    /* TS defaults */
  785.                 desc->shap[1] = 0;
  786.             }
  787.             parse_word(name, 4, 1);        /* Get field */
  788.             if        (strcmp(name, "SHAP")==0) desc->shap[0] = get_UWORD();
  789.             else if (strcmp(name, "LAMP")==0) desc->shap[1] = get_UWORD();
  790.             else {
  791.                 fprintf(stderr, "WARNING: Line %d: Unknown SHAP field: '%s'\n", world->cur_line, name);
  792.                 continue;
  793.             }
  794.         } else
  795.         if (strcmp(name, "POSI")==0) {
  796.             if (!desc->posi) {
  797.                 if (!(desc->posi=(XYZ_st*)malloc(sizeof(XYZ_st))))
  798.                     { OUT_MEM("POSI"); }
  799.             }
  800.             stuff_XYZ(desc->posi);
  801.         } else
  802.         if (strcmp(name, "AXIS")==0) {
  803.             if (!desc->axis) {
  804.                 if (!(desc->axis=(AXIS*)malloc(sizeof(AXIS))))
  805.                     { OUT_MEM("AXIS"); }
  806.                 bzero((char*)desc->axis, sizeof(AXIS));
  807.                 desc->axis->xaxi.val[0] = 1;
  808.                 desc->axis->yaxi.val[1] = 1;
  809.                 desc->axis->zaxi.val[2] = 1;
  810.             }
  811.             parse_word(name, 4, 1);        /* Get field */
  812.             if        (strcmp(name, "XAXI")==0) stuff_XYZ(&desc->axis->xaxi);
  813.             else if (strcmp(name, "YAXI")==0) stuff_XYZ(&desc->axis->yaxi);
  814.             else if (strcmp(name, "ZAXI")==0) stuff_XYZ(&desc->axis->zaxi);
  815.             else {
  816.                 fprintf(stderr, "WARNING: Line %d: Unknown AXIS field: '%s'\n", world->cur_line, name);
  817.                 continue;
  818.             }
  819.         } else
  820.         if (strcmp(name, "SIZE")==0) {
  821.             if (!desc->size) {
  822.                 if (!(desc->size=(XYZ_st*)malloc(sizeof(XYZ_st))))
  823.                     { OUT_MEM("SIZE"); }
  824.             }
  825.             stuff_XYZ(desc->size);
  826.         } else
  827.         if (strcmp(name, "COLR")==0) {
  828.             if (!desc->colr) {
  829.                 if (!(desc->colr = (RGB_st*)malloc(sizeof(RGB_st))))
  830.                     { OUT_MEM("COLR"); }
  831.             }
  832.             stuff_RGB((RGB_st*)&defclst[0]);
  833.             desc->colr->val[0] = defclst[0];
  834.             desc->colr->val[1] = defclst[1];
  835.             desc->colr->val[2] = defclst[2];
  836. #ifdef DO_I_REALLY_WANT_TO_DO_THIS
  837.             if (desc->fcount) {    /* Already initialized... rewrite */
  838.                 for (i=3*desc->fcount; i; ) {        /* Reverse - efficiency */
  839.                     desc->clst[--i] = defclst[2];
  840.                     desc->clst[--i] = defclst[1];
  841.                     desc->clst[--i] = defclst[0];
  842.                 }
  843.             }
  844. #endif
  845.         } else
  846.         if (strcmp(name, "REFL")==0) {
  847.             if (!desc->refl) {
  848.                 if (!(desc->refl = (RGB_st*)malloc(sizeof(RGB_st))))
  849.                     { OUT_MEM("REFL"); }
  850.             }
  851.             stuff_RGB((RGB_st*)&defrlst[0]);
  852.             desc->refl->val[0] = defrlst[0];
  853.             desc->refl->val[1] = defrlst[1];
  854.             desc->refl->val[2] = defrlst[2];
  855. #ifdef DO_I_REALLY_WANT_TO_DO_THIS
  856.             if (desc->fcount) {    /* Already initialized... rewrite */
  857.                 for (i=3*desc->fcount; i; ) {        /* Reverse - efficiency */
  858.                     desc->rlst[--i] = defrlst[2];
  859.                     desc->rlst[--i] = defrlst[1];
  860.                     desc->rlst[--i] = defrlst[0];
  861.                 }
  862.             }
  863. #endif
  864.         } else
  865.         if (strcmp(name, "TRAN")==0) {
  866.             if (!desc->tran) {
  867.                 if (!(desc->tran = (RGB_st*)malloc(sizeof(RGB_st))))
  868.                     { OUT_MEM("TRAN"); }
  869.             }
  870.             stuff_RGB((RGB_st*)&deftlst[0]);
  871.             desc->tran->val[0] = deftlst[0];
  872.             desc->tran->val[1] = deftlst[1];
  873.             desc->tran->val[2] = deftlst[2];
  874. #ifdef DO_I_REALLY_WANT_TO_DO_THIS
  875.             if (desc->fcount) {    /* Already initialized... rewrite */
  876.                 for (i=3*desc->fcount; i; ) {        /* Reverse - efficiency */
  877.                     desc->tlst[--i] = deftlst[2];
  878.                     desc->tlst[--i] = deftlst[1];
  879.                     desc->tlst[--i] = deftlst[0];
  880.                 }
  881.             }
  882. #endif
  883.         } else
  884.         if (strcmp(name, "SPC1")==0) {
  885.             if (!desc->spc1) {
  886.                 if (!(desc->spc1 = (RGB_st*)malloc(sizeof(RGB_st))))
  887.                     { OUT_MEM("SPC1"); }
  888.             }
  889.             stuff_RGB((RGB_st*)&defspc1[0]);
  890.             desc->spc1->val[0] = defspc1[0];
  891.             desc->spc1->val[1] = defspc1[1];
  892.             desc->spc1->val[2] = defspc1[2];
  893.         } else
  894.         if (strcmp(name, "TPAR")==0) {
  895.             if (!desc->tpar) {
  896.                 if (!(desc->tpar=(double*)malloc(16*sizeof(double))))
  897.                     { OUT_MEM("TPAR"); }
  898.                 bzero((char*)desc->tpar, 16*sizeof(double));
  899.             }
  900.             i = get_UWORD();
  901.             if (i<0 || i>15) {
  902.                 fprintf(stderr, "WARNING: Line %d: Bad index: TPAR[%d] should be [0..15]\n", world->cur_line, i);
  903.                 continue;
  904.             }
  905.             desc->tpar[i] = get_FRACT();
  906.         } else
  907.         if (strcmp(name, "SURF")==0) {
  908.             if (!desc->surf) {
  909.                 if (!(desc->surf=(UBYTE*)malloc(5*sizeof(UBYTE))))
  910.                     { OUT_MEM("SURF"); }
  911.                 bzero((char*)desc->surf, 5*sizeof(UBYTE));
  912.             }
  913.             i = get_UWORD();
  914.             if (i<0 || i>4) {
  915.                 fprintf(stderr, "WARNING: Line %d: Bad index: SURF[%d] should be [0..4]\n", world->cur_line, i);
  916.                 continue;
  917.             }
  918.             desc->surf[i] = get_UBYTE();
  919.         } else
  920.         if (strcmp(name, "MTTR")==0) {
  921.             if (!desc->mttr) {
  922.                 if (!(desc->mttr=(MTTR*)malloc(sizeof(MTTR))))
  923.                     { OUT_MEM("MTTR"); }
  924.                 bzero((char*)desc->mttr, sizeof(MTTR));
  925.             }
  926.             parse_word(name, 4, 1);        /* Get field */
  927.             if        (strcmp(name, "TYPE")==0) {
  928.                 desc->mttr->type = get_UBYTE();
  929.                 if (desc->mttr->type>4) {
  930.                     fprintf(stderr, "WARNING: Line %d: Invalid MTTR refraction Type %d.  Must be [0..4]\n", world->cur_line, desc->mttr->type);
  931.                     desc->mttr->type = 0;
  932.                     continue;
  933.                 }
  934.             } else if (strcmp(name, "INDE")==0) {    /* Must be between 1.0 and 3.55 inclusive */
  935.                 desc->mttr->indx = get_FRACT();
  936.                 if (desc->mttr->indx<1.0 || desc->mttr->indx>3.55) {
  937.                     fprintf(stderr, "WARNING: Line %d: Invalid MTTR Index of refraction.  Must be (1.0 - 3.55)\n", world->cur_line);
  938.                     desc->mttr->indx = 1.0;
  939.                     continue;
  940.                 }
  941.             } else {
  942.                 fprintf(stderr, "WARNING: Line %d: Unknown MTTR field: '%s'\n", world->cur_line, name);
  943.                 continue;
  944.             }
  945.         } else
  946.         if (strcmp(name, "SPEC")==0) {
  947.             if (!desc->spec) {
  948.                 if (!(desc->spec=(UBYTE*)malloc(2*sizeof(UBYTE))))
  949.                     { OUT_MEM("SPEC"); }
  950.                 bzero((char*)desc->spec, 2*sizeof(UBYTE));
  951.             }
  952.             parse_word(name, 4, 1);        /* Get field */
  953.             if        (strcmp(name, "SPEC")==0) desc->spec[0] = get_UBYTE();
  954.             else if (strcmp(name, "HARD")==0) desc->spec[1] = get_UBYTE();
  955.             else {
  956.                 fprintf(stderr, "WARNING: Line %d: Unknown SPEC field: '%s'\n", world->cur_line, name);
  957.                 continue;
  958.             }
  959.         } else
  960.         if (strcmp(name, "PRP0")==0) {
  961.             if (!desc->prp0) {
  962.                 if (!(desc->prp0=(UBYTE*)malloc(6*sizeof(UBYTE))))
  963.                     { OUT_MEM("PRP0"); }
  964.                 bzero((char*)desc->prp0, 6*sizeof(UBYTE));
  965.                 desc->prp0[0] = 255;    /* TS defaults */
  966.                 desc->prp0[3] = 1;
  967.             }
  968.             i = get_UWORD();
  969.             if (i<0 || i>5) {
  970.                 fprintf(stderr, "WARNING: Line %d: Bad index: PRP0[%d] should be [0..5]\n", world->cur_line, i);
  971.                 continue;
  972.             }
  973.             desc->prp0[i] = get_UBYTE();
  974.         } else
  975.         if (strcmp(name, "PRP1")==0) {
  976.             if (!desc->prp1) {
  977.                 if (!(desc->prp1=(UBYTE*)malloc(8*sizeof(UBYTE))))
  978.                     { OUT_MEM("PRP1"); }
  979.                 bzero((char*)desc->prp1, 8*sizeof(UBYTE));
  980.             }
  981.             i = get_UWORD();
  982.             if (i<0 || i>7) {
  983.                 fprintf(stderr, "WARNING: Line %d: Bad index: PRP1[%d] should be [0..7]\n", world->cur_line, i);
  984.                 continue;
  985.             }
  986.             desc->prp1[i] = get_UBYTE();
  987.         } else
  988.         if (strcmp(name, "INTS")==0) {
  989.             if (!desc->ints) {
  990.                 if (!(desc->ints=(double*)malloc(sizeof(double))))
  991.                     { OUT_MEM("INTS"); }
  992.             }
  993.             *desc->ints = get_FRACT();
  994.         } else
  995.         if (strcmp(name, "INT1")==0) {
  996.             if (!desc->int1) desc->int1=(RGB_st*)malloc(sizeof(RGB_st));
  997.             if (!desc->int1) { OUT_MEM("INT1"); }
  998.             stuff_RGB(desc->int1);
  999.         } else
  1000.         if (strcmp(name, "STRY")==0) {
  1001.             parse_word(name, 4, 1);        /* Get field */
  1002.             if        (strcmp(name, "PATH")==0) parse_word(desc->stry->path,18,0);
  1003.             else if (strcmp(name, "TRAN")==0) stuff_XYZ(&desc->stry->tran);
  1004.             else if (strcmp(name, "ROTA")==0) stuff_XYZ(&desc->stry->rota);
  1005.             else if (strcmp(name, "SCAL")==0) stuff_XYZ(&desc->stry->scal);
  1006.             else
  1007.             if (strcmp(name, "INFO")==0) {
  1008.                 desc->stry->info = 0;
  1009.                 while (strin[0]) {
  1010.                     parse_word(ps, 7, 1);
  1011.                     if        (strcmp(ps, "ABS_TRA")==0) desc->stry->info|=(1<<0);
  1012.                     else if (strcmp(ps, "ABS_ROT")==0) desc->stry->info|=(1<<1);
  1013.                     else if (strcmp(ps, "ABS_SCL")==0) desc->stry->info|=(1<<2);
  1014.                     else if (strcmp(ps, "LOC_TRA")==0) desc->stry->info|=(1<<4);
  1015.                     else if (strcmp(ps, "LOC_ROT")==0) desc->stry->info|=(1<<5);
  1016.                     else if (strcmp(ps, "LOC_SCL")==0) desc->stry->info|=(1<<6);
  1017.                     else if (strcmp(ps, "X_ALIGN")==0) desc->stry->info|=(1<<8);
  1018.                     else if (strcmp(ps, "Y_ALIGN")==0) desc->stry->info|=(1<<9);
  1019.                     else if (strcmp(ps, "Z_ALIGN")==0) desc->stry->info|=(1<<10);
  1020.                     else if (strcmp(ps, "FOLLOW_")==0) desc->stry->info|=(1<<12);
  1021.                     else {
  1022.                         fprintf(stderr, "WARNING: Line %d: Unknown STRY INFO flag: '%s'\n", world->cur_line, ps);
  1023.                         continue;
  1024.                     }
  1025.                 }
  1026.             } else {
  1027.                 fprintf(stderr, "WARNING: Line %d: Unknown STRY field: '%s'\n", world->cur_line, name);
  1028.                 continue;
  1029.             }
  1030.         } else
  1031.         if (strcmp(name, "END")==0) {
  1032.             parse_word(name, 4, 1);
  1033.             if (strcmp(name, "DESC")!=0)
  1034.                 fprintf(stderr, "WARNING: Line %d: Expected 'END DESC' but got: 'END %s'\n", world->cur_line, name);
  1035.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  1036.             if (strcmp(this_level, ps)!=0)
  1037.                 fprintf(stderr, "WARNING: Line %d: 'DESC Begin' and 'End DESC' quoted comments do not match\n", world->cur_line);
  1038.             break;
  1039.         } else fprintf(stderr, "WARNING: Line %d: Unknown DESC sub-sub-chunk: '%s'\n", world->cur_line, name);
  1040.     }
  1041. }
  1042.  
  1043.