home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / fractint / fras1611.zip / LSYS.C < prev    next >
Text File  |  1991-07-07  |  13KB  |  586 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <math.h>
  5. #include <malloc.h>
  6. #include "fractint.h"
  7.  
  8. extern int xdots,ydots;
  9. extern int colors;
  10. extern char LFileName[];
  11. extern char LName[];
  12. extern double param[];
  13.  
  14. int Lsystem();
  15. extern int thinking(int,char *);
  16.  
  17. static float      _fastcall getnumber(char far **);
  18. static char far * _fastcall findsize(char far *,char far **,int);
  19. static int      _fastcall findscale(char far *, char far **, int);
  20. static char far * _fastcall drawLSys(char far *, char far **, int);
  21. static int      _fastcall readLSystemFile(char *);
  22. static void      _fastcall free_rules_mem(void);
  23. static int      _fastcall save_rule(char *,char far **);
  24.  
  25. static float aspect; /* aspect ratio of each pixel, ysize/xsize */
  26.  
  27. /* Some notes to Adrian from PB, made when I integrated with v15:
  28.      printfs changed to work with new user interface
  29.      bug at end of readLSystemFile, the line which said rulind=0 fixed
  30.        to say *rulind=0
  31.      the calloc was not worthwhile, it was just for a 54 byte area, cheaper
  32.        to keep it as a static;    but there was a static 201 char buffer I
  33.        changed to not be static
  34.      use of strdup was a nono, caused problems running out of space cause
  35.        the memory allocated each time was never freed; I've changed to
  36.        use far memory and to free when done
  37.    */
  38.  
  39.  
  40. static float far sins[50];
  41. static float far coss[50];
  42. static char maxangle,curcolor;
  43. static float xpos,ypos,size,realangle;
  44. static char counter,angle,reverse,stackoflow;
  45. static float Xmin,Xmax,Ymin,Ymax;
  46.  
  47.  
  48. static float _fastcall getnumber(char far **str)
  49. {
  50.    char numstr[30];
  51.    float ret;
  52.    int i,root,inverse;
  53.  
  54.    root=0;
  55.    inverse=0;
  56.    strcpy(numstr,"");
  57.    (*str)++;
  58.    switch (**str)
  59.    {
  60.    case 'q':
  61.       root=1;
  62.       (*str)++;
  63.       break;
  64.    case 'i':
  65.       inverse=1;
  66.       (*str)++;
  67.       break;
  68.    }
  69.    switch (**str)
  70.    {
  71.    case 'q':
  72.       root=1;
  73.       (*str)++;
  74.       break;
  75.    case 'i':
  76.       inverse=1;
  77.       (*str)++;
  78.       break;
  79.    }
  80.    i=0;
  81.    while (**str<='9' && **str>='0' || **str=='.')
  82.    {
  83.       numstr[i++]=**str;
  84.       (*str)++;
  85.    }
  86.    (*str)--;
  87.    numstr[i]=0;
  88.    ret=atof(numstr);
  89.    if (root) ret=sqrt(ret);
  90.    if (inverse) ret=1/ret;
  91.    return ret;
  92. }
  93.  
  94.  
  95. static char far * _fastcall findsize(char far *command,char far **rules,int depth)
  96. {
  97.    char far **rulind,tran;
  98.  
  99. #ifndef __TURBOC__
  100.    if (stackavail() < 400) { /* leave some margin for calling subrtns */
  101.       stackoflow = 1;
  102.       return NULL;
  103.       }
  104. #endif
  105.  
  106.    while ((*command)&&(*command!=']'))
  107.    {
  108.       if (!(counter++))
  109.       {
  110.      /* let user know we're not dead */
  111.      if (thinking(1,"L-System thinking (higher orders take longer)"))
  112.      {
  113.         counter--;
  114.         return NULL;
  115.      }
  116.       }
  117.       tran=0;
  118.       if (depth)
  119.       {
  120.      for(rulind=rules;*rulind;rulind++)
  121.         if (**rulind==*command)
  122.         {
  123.            tran=1;
  124.            if (findsize((*rulind)+1,rules,depth-1) == NULL)
  125.           return(NULL);
  126.         }
  127.       }
  128.       if (!depth || !tran)
  129.      switch (*command)
  130.      {
  131.      case '+':
  132.         if (reverse)
  133.         {
  134.            if (++angle==maxangle)
  135.           angle=0;
  136.         }
  137.         else
  138.         {
  139.            if (angle)
  140.           angle--;
  141.            else
  142.           angle=maxangle-1;
  143.         }
  144.         break;
  145.      case '-':
  146.         if (reverse)
  147.         {
  148.            if (angle)
  149.           angle--;
  150.            else angle=maxangle-1;
  151.         }
  152.         else
  153.         {
  154.            if (++angle==maxangle)
  155.           angle=0;
  156.         }
  157.         break;
  158.      case '/':
  159.         if (reverse)
  160.         {
  161.          realangle-=getnumber(&command);
  162.          while (realangle<0) realangle+=360;
  163.         }
  164.         else
  165.         {
  166.          realangle+=getnumber(&command);
  167.          while (realangle>=360) realangle-=360;
  168.         }
  169.         break;
  170.      case '\\':
  171.         if (reverse)
  172.         {
  173.          realangle+=getnumber(&command);
  174.          while (realangle>=360) realangle-=360;
  175.         }
  176.         else
  177.         {
  178.         realangle-=getnumber(&command);
  179.         while (realangle<0) realangle+=360;
  180.         }
  181.         break;
  182.      case '@':
  183.         size*=getnumber(&command);
  184.         break;
  185.      case '|':
  186.         angle+=maxangle/2;
  187.         angle%=maxangle;
  188.         break;
  189.      case '!':
  190.         reverse=!reverse;
  191.         break;
  192.      case 'd':
  193.      case 'm':
  194.         xpos+=size*aspect*cos(realangle*PI/180);
  195.         ypos+=size*sin(realangle*PI/180);
  196.         if (xpos>Xmax) Xmax=xpos;
  197.         if (ypos>Ymax) Ymax=ypos;
  198.         if (xpos<Xmin) Xmin=xpos;
  199.         if (ypos<Ymin) Ymin=ypos;
  200.         break;
  201.      case 'g':
  202.      case 'f':
  203.         xpos+=size*coss[angle];
  204.         ypos+=size*sins[angle];
  205.         if (xpos>Xmax) Xmax=xpos;
  206.         if (ypos>Ymax) Ymax=ypos;
  207.         if (xpos<Xmin) Xmin=xpos;
  208.         if (ypos<Ymin) Ymin=ypos;
  209.         break;
  210.      case '[':
  211.         {
  212.            char saveang,saverev;
  213.            float savesize,saverang,savex,savey;
  214.  
  215.            saveang=angle;
  216.            saverev=reverse;
  217.            savesize=size;
  218.            saverang=realangle;
  219.            savex=xpos;
  220.            savey=ypos;
  221.            if ((command=findsize(command+1,rules,depth)) == NULL)
  222.           return(NULL);
  223.            angle=saveang;
  224.            reverse=saverev;
  225.            size=savesize;
  226.            realangle=saverang;
  227.            xpos=savex;
  228.            ypos=savey;
  229.         }
  230.         break;
  231.      }
  232.       command++;
  233.    }
  234.    return command;
  235. }
  236.  
  237.  
  238. static int _fastcall findscale(char far *command, char far **rules, int depth)
  239. {
  240.    float horiz,vert;
  241.    int i;
  242.    char far *fsret;
  243.    aspect=SCREENASPECT*xdots/ydots;
  244.    for(i=0;i<maxangle;i++)
  245.    {
  246.       sins[i]=sin(2*i*PI/maxangle);
  247.       coss[i]=aspect*cos(2*i*PI/maxangle);
  248.    }
  249.    xpos=ypos=Xmin=Xmax=Ymax=Ymin=angle=reverse=realangle=counter=0;
  250.    size=1;
  251.    fsret = findsize(command,rules,depth);
  252.    thinking(0,NULL); /* erase thinking message if any */
  253.    if (fsret == NULL)
  254.       return(0);
  255.    if (Xmax==Xmin)
  256.       horiz=1E37;
  257.    else
  258.       horiz=(xdots-10)/(Xmax-Xmin);
  259.    if (Ymax==Ymin)
  260.       vert=1E37;
  261.    else
  262.       vert=(ydots-6)/(Ymax-Ymin);
  263.    size=vert<horiz?vert:horiz;
  264.    if (horiz==1E37)
  265.       xpos=xdots/2;
  266.    else
  267.       xpos=-Xmin*(size)+5+((xdots-10)-(size)*(Xmax-Xmin))/2;
  268.    if (vert==1E37)
  269.       ypos=ydots/2;
  270.    else
  271.       ypos=-Ymin*(size)+3+((ydots-6)-(size)*(Ymax-Ymin))/2;
  272.    return(1);
  273. }
  274.  
  275. static char far * _fastcall drawLSys(char far *command,char far **rules,int depth)
  276. {
  277.    char far **rulind,tran;
  278.    int lastx,lasty;
  279.  
  280. #ifndef __TURBOC__
  281.    if (stackavail() < 400) { /* leave some margin for calling subrtns */
  282.       stackoflow = 1;
  283.       return NULL;
  284.       }
  285. #endif
  286.  
  287.    while (*command&&*command!=']')
  288.    {
  289.       if (!(counter++))
  290.       {
  291.      if (check_key())
  292.      {
  293.         counter--;
  294.         return NULL;
  295.      }
  296.       }
  297.       tran=0;
  298.       if (depth)
  299.       {
  300.      for(rulind=rules;*rulind;rulind++)
  301.         if (**rulind==*command)
  302.         {
  303.            tran=1;
  304.            if (drawLSys((*rulind)+1,rules,depth-1) == NULL)
  305.           return(NULL);
  306.         }
  307.       }
  308.       if (!depth||!tran)
  309.      switch (*command)
  310.      {
  311.      case '+':
  312.         if (reverse)
  313.         {
  314.            if (++angle==maxangle) angle=0;
  315.         }
  316.         else
  317.         {
  318.            if (angle) angle--;
  319.            else angle=maxangle-1;
  320.         }
  321.         break;
  322.      case '-':
  323.         if (reverse)
  324.         {
  325.            if (angle) angle--;
  326.            else angle=maxangle-1;
  327.         }
  328.         else
  329.         {
  330.            if (++angle==maxangle) angle=0;
  331.         }
  332.         break;
  333.      case '/':
  334.         if (reverse)
  335.         {
  336.          realangle-=getnumber(&command);
  337.          while (realangle<0) realangle+=360;
  338.         }
  339.         else
  340.         {
  341.          realangle+=getnumber(&command);
  342.          while (realangle>=360) realangle-=360;
  343.         }
  344.         break;
  345.      case '\\':
  346.         if (reverse)
  347.         {
  348.          realangle+=getnumber(&command);
  349.          while (realangle>=360) realangle-=360;
  350.         }
  351.         else
  352.         {
  353.         realangle-=getnumber(&command);
  354.         while (realangle<0) realangle+=360;
  355.         }
  356.         break;
  357.      case '@':
  358.         size *= getnumber(&command);
  359.         break;
  360.      case '|':
  361.         angle+=maxangle/2;
  362.         angle%=maxangle;
  363.         break;
  364.      case '!':
  365.         reverse=!reverse;
  366.         break;
  367.      case 'd':
  368.         lastx=xpos;
  369.         lasty=ypos;
  370.         xpos+=size*aspect*cos(realangle*PI/180);
  371.         ypos+=size*sin(realangle*PI/180);
  372.         draw_line(lastx,lasty,(int)xpos,(int)ypos,curcolor);
  373.         break;
  374.      case 'm':
  375.         xpos+=size*aspect*cos(realangle*PI/180);
  376.         ypos+=size*sin(realangle*PI/180);
  377.         break;
  378.      case 'g':
  379.         xpos+=size*coss[angle];
  380.         ypos+=size*sins[angle];
  381.         break;
  382.      case 'f':
  383.         lastx=xpos;
  384.         lasty=ypos;
  385.         xpos+=size*coss[angle];
  386.         ypos+=size*sins[angle];
  387.         draw_line(lastx,lasty,(int)xpos,(int)ypos,curcolor);
  388.         break;
  389.      case '[':
  390.         {
  391.            char saveang,saverev,savecolor;
  392.            float savesize,saverang,savex,savey;
  393.  
  394.            saveang=angle;
  395.            saverev=reverse;
  396.            savesize=size;
  397.            saverang=realangle;
  398.            savex=xpos;
  399.            savey=ypos;
  400.            savecolor=curcolor;
  401.            if ((command=drawLSys(command+1,rules,depth)) == NULL)
  402.           return(NULL);
  403.            angle=saveang;
  404.            reverse=saverev;
  405.            size=savesize;
  406.            realangle=saverang;
  407.            xpos=savex;
  408.            ypos=savey;
  409.            curcolor=savecolor;
  410.         }
  411.         break;
  412.      case 'c':
  413.         curcolor=((int)getnumber(&command))%colors;
  414.         break;
  415.      case '>':
  416.         curcolor-=getnumber(&command);
  417.         if ((curcolor &= colors-1) == 0) curcolor = colors-1;
  418.         break;
  419.      case '<':
  420.         curcolor+=getnumber(&command);
  421.         if ((curcolor &= colors-1) == 0) curcolor = 1;
  422.         break;
  423.      }
  424.       command++;
  425.    }
  426.    return command;
  427. }
  428.  
  429.  
  430. #define MAXRULES 27 /* this limits rules to 25 */
  431. static char far *ruleptrs[MAXRULES];
  432.  
  433. static int _fastcall readLSystemFile(char *str)
  434. {
  435.    int c;
  436.    char far **rulind;
  437.    int err=0;
  438.    int linenum,check=0;
  439.    char inline[161],fixed[161],*word;
  440.    FILE *infile;
  441.    char msgbuf[481]; /* enough for 6 full lines */
  442.  
  443.  
  444.    if (find_file_item(LFileName,str,&infile) < 0)
  445.       return -1;
  446.    while ((c = fgetc(infile)) != '{')
  447.       if (c == EOF) return -1;
  448.  
  449.    maxangle=0;
  450.    for(linenum=0;linenum<MAXRULES;++linenum) ruleptrs[linenum]=NULL;
  451.    rulind=&ruleptrs[1];
  452.    msgbuf[0]=linenum=0;
  453.  
  454.    while(fgets(inline,160,infile))  /* Max line length 160 chars */
  455.    {
  456.       linenum++;
  457.       if ((word = strchr(inline,';'))) /* strip comment */
  458.      *word = 0;
  459.       strlwr(inline);
  460.  
  461.       if (strspn(inline," \t\n") < strlen(inline)) /* not a blank line */
  462.       {
  463.      word=strtok(inline," =\t\n");
  464.      if (!strcmp(word,"axiom"))
  465.      {
  466.         save_rule(strtok(NULL," \t\n"),&ruleptrs[0]);
  467.         check=1;
  468.      }
  469.      else if (!strcmp(word,"angle"))
  470.      {
  471.         maxangle=atoi(strtok(NULL," \t\n"));
  472.         check=1;
  473.      }
  474.      else if (!strcmp(word,"}"))
  475.         break;
  476.      else if (strlen(word)==1)
  477.      {
  478.         strcat(strcpy(fixed,word),strtok(NULL," \t\n"));
  479.         save_rule(fixed,rulind++);
  480.         check=1;
  481.      }
  482.      else
  483.         if (err<6)
  484.         {
  485.            sprintf(&msgbuf[strlen(msgbuf)],
  486.                "Syntax error line %d: %s\n",linenum,word);
  487.            ++err;
  488.         }
  489.      if (check)
  490.      {
  491.         check=0;
  492.         if(word=strtok(NULL," \t\n"))
  493.            if (err<6)
  494.            {
  495.           sprintf(&msgbuf[strlen(msgbuf)],
  496.              "Extra text after command line %d: %s\n",linenum,word);
  497.           ++err;
  498.            }
  499.      }
  500.       }
  501.    }
  502.    fclose(infile);
  503.    if (!ruleptrs[0] && err<6)
  504.    {
  505.       strcat(msgbuf,"Error:  no axiom\n");
  506.       ++err;
  507.    }
  508.    if ((maxangle<3||maxangle>50) && err<6)
  509.    {
  510.       strcat(msgbuf,"Error:  illegal or missing angle\n");
  511.       ++err;
  512.    }
  513.    if (err)
  514.    {
  515.       msgbuf[strlen(msgbuf)-1]=0; /* strip trailing \n */
  516.       stopmsg(0,msgbuf);
  517.       return -1;
  518.    }
  519.    *rulind=NULL;
  520.    return 0;
  521. }
  522.  
  523.  
  524. static char loaded=0;
  525.  
  526. int Lsystem()
  527. {
  528.    int order;
  529.    if ((!loaded)&&LLoad()) return (-1);
  530.    order=param[0];
  531.    if (order<=0) order=0;
  532.    stackoflow = 0;
  533.    if (findscale(ruleptrs[0],&ruleptrs[1],order)) {
  534.       realangle=angle=reverse=0;
  535. /* !! HOW ABOUT A BETTER WAY OF PICKING THE DEFAULT DRAWING COLOR */
  536.       if ((curcolor=15) > colors) curcolor=colors-1;
  537.       drawLSys(ruleptrs[0],&ruleptrs[1],order);
  538.       }
  539.    if (stackoflow)
  540.    {
  541.       static char far msg[]={"insufficient memory, try a lower order"};
  542.       stopmsg(0,msg);
  543.    }   
  544.    free_rules_mem();
  545.    loaded=0;
  546.    return 0;
  547. }
  548.  
  549.  
  550. int LLoad()
  551. {
  552.    char i;
  553.    if (readLSystemFile(LName)) { /* error occurred */
  554.       free_rules_mem();
  555.       loaded=0;
  556.       return -1;
  557.    }
  558.  
  559.    for(i=0;i<maxangle;i++)
  560.    {
  561.       sins[i]=sin(2*i*PI/maxangle);
  562.       coss[i]=aspect*cos(2*i*PI/maxangle);
  563.    }
  564.    loaded=1;
  565.    return 0;
  566. }
  567.  
  568. static void _fastcall free_rules_mem()
  569. {
  570.    int i;
  571.    for(i=0;i<MAXRULES;++i)
  572.       if(ruleptrs[i]) farmemfree(ruleptrs[i]);
  573. }
  574.  
  575. static int _fastcall save_rule(char *rule,char far **saveptr)
  576. {
  577.    int i;
  578.    char far *tmpfar;
  579.    i=strlen(rule)+1;
  580.    if((tmpfar=farmemalloc((long)i))==NULL) return -1;
  581.    *saveptr=tmpfar;
  582.    while(--i>=0) *(tmpfar++)=*(rule++);
  583.    return 0;
  584. }
  585.  
  586.