File: flower.c - Tab length: 1 2 4 8 - Lines: on off - No wrap: on off

/****************************************************************************/
/* Fichiers � inclure                                                       */
/****************************************************************************/
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

/* Ici sont d�finies toutes les variables n�cessaires     */
/* pour avour acc�s aux routines graphiques, ainsi qu'aux */
/* fonctions syst�me gemdos() et appels CP/M 68K          */
#include <tos_gem.h>

#include "flower.h"

/* ****************** TYPE DE FENETRE ******************/
/* GEM vous permet de d�finir diff�rents types de fen�tres. Ici, on choisit
un type de fen�tre particulier, et GEM se charge du reste (c�d de
l'ouvrir, changer de taille, etc...). Pour vous il s'agit seulement de faire
les appels n�cessaires aux routines correspondantes. Le type de fen�tre se
d�finit dpnc de la fa�on suivante:                */

/* TYPE DE FENETRE: TAILLE VARIABLE, AVEC NOM, PEUT BOUGER **************/
#define WI_KIND (SIZER | NAME | CLOSER | MOVER | FULLER)

/* Si l'utilisateur r�tr�cit compl�tement sa fen�tre, il n'est plus possible
de s'en sortir. Pour emp�cher ce probl�me d'appara�tre, on d�finit une taille
minimale au del� de laquelle il n'est plus possible de r�tr�cir la fen�tre.
*/

#define NO_WINDOW (-1)
#define MIN_WIDTH (2*gl_wbox)
#define MIN_HEIGHT (3*gl_hbox)

/* La variable msgbuff contient les codes de retour de GEM et permet d'agir
selon le contenu du message pass� par GEM. */

int ret, msgbuff[8];
/* GEM simule un multi-t�ches, et msgbuff est une zone tampon dans laquelle il
est possible pour GEM de vous laisser un message. Une esp�ce de boite �
lettres pour ainsi dire. */


extern int gp_apid; /* variable n�cessaire pour le GEM */

/* Zone de la m�moire n�cessaire pour les fonctions graphiques de GEM. */
int contrl[12];
int intin[128];
int ptsin[128];
int intout[128];
int ptsout[128];
/* GEM permet d'appeler les m�mes utilitaires depuis l'assembleur. Si vous
�tes int�ress�(e) vous pouvez appeler avec les variables contrl, intin, etc
directement les routines graphiques sans aucune interface "C". */


/* "handle" est l'identification de la station de travail. "wi_handle"
identifie la fen�tre dans laquelle ontravaille. */

int handle, wi_handle, top_window, work_in[11], work_out[57];

/* "phys_handle" est le handle physique (il est possible d'avoir plusieurs
stations de travail ouvertes en m�me temps sur la m�me station physique).
"keycode" donne le code de la touche press�e par l'utilisateur, "butdown" est
une drapeau pour indiquer sir l'utilisateur a appui� le bouton de la souris.
*/

int phys_handle, keycode, butdown;

/* zone de la m�moire utilis�e par le GEM */
int pxyarray[128];

/* Variables n�cessaire pour le changement d'une fen�tre.*/
int xold, yold, wold, hold;

/* Utilis�es dans la fonction multi(), "gl_hchar" et "gl_wchar" sont la
largeur et la hauteur des caract�res. "gl_hbox" et "gl_wbox" sont la largeur
et la hauteur de leur encadrement (box=cadre). */

int gl_hchar, gl_wchar, gl_wbox, gl_hbox;

int xdesk, ydesk, hdesk, wdesk; /* taille du bureau. */
int xwind, ywind, hwind, wwind; /* taille de la fen�tre. */

/* "xwork" et "ywork" sont les coordonn�es sup�rieures gauche de la fen�tre
active. Chaque appel � l'�criture graphique doir en tenir compte pour dessiner
les objets dans la fen�tre et pas en dehors... */

int xwork, ywork, hwork, wwork, mx, my;

/* Drapeau pour indiquer si la fen�tre est derri�re ou en plein �cran. */
int hidden, fulled;

/* Pour �viter de calculer � chaque fois le sinus et le cosinus, on calcule
leur valeurs et on les garde dans les tableaux suivants: */

static float sinus[720], cosinus[720], trd[720];

/* Texte pour afficher les param�tres RD (Radius Differential) et TD (T...
Differential). Voir text. */

static char *titre = { "RD = [ ], TD = [ ]" };

/* Autres variables pour calculer la figure. */
static int theta, rad, radius, points[2880], centrex, centrey;

/****************************************************************************/
/* PROGRAMME PRINCIPAL                                                      */
/****************************************************************************/

int main(int argc, char *argv[], char *envp[])
{
/*  while (*envp)
  {
    printf(*envp);
    envp++;
  }
*/

  int x, y, term;

  appl_init();
  phys_handle = graf_handle(&gl_wchar, &gl_hchar, &gl_wbox, &gl_hbox);
  wind_get(0, WF_WORKXYWH, &xdesk, &ydesk, &wdesk, &hdesk);
  open_vwork();         /* Ouvre la station de travail */
  open_window();        /* Ouvre la fen�tre */
  graf_mouse(5,NULL);   /* Change la forme de la souris */
  vsm_type(handle, 1);  /* point = polymarker */

  /* Initialisation de diverses variables. */
  hidden = FALSE;
  fulled = FALSE;
  rad =1;
  theta = 1;
  butdown = TRUE;

  initfleur();    /* Initialisation du cosinus et sinus */
  multi();        /* Appel au multi-t�ches */

  return 0;
}

/****************************************************************************/
/*        OUVRIR LA STATION DE TRAVAIL                                      */
/* Ici, on fait appel � la fonction GEM v_opnvwk (open virtual workstation:
ouvrir une station de travail virtuelle). Les param�tres � passer sont d�crits
d'un fa�on plus approfondie dans le mode d'emploi GEM. Il suffit ici de
remarquer que work_in[10] est 2, cela signifie qu'on travaille dans les
coordonn�es raster de la machine, et pas dans le syst�me de coordonn�es
virtuelles. La diff�rence est que dans notre cas, les coordonn�es utilis�es
ici ne sont pas portables sur une autre machine. Par contre, le dessin est
plus rapide parce que l'effort de translation de coordonn�es n'est plus
n�cessaire. Remarquez que l'origine est en haut � gauche de l'�cran.        */


void open_vwork()
{
  int i;
  for (i=0; i<10; work_in[i++] = 1);
  work_in[10] = 2;    /* Coordonn�es absolues RC */
  handle = phys_handle;
  /* Ouvre la station de travail */
  v_opnvwk(work_in, &handle, work_out);
}

/* Fonction pour dessiner une fleur avec les param�tres rd et td. */
/* Pour gagner du temps, on utilise les sym�tries de la figure */
void unefleur(int rd, int td)
{
  int z, c, s;
  register int i,m;

  i = 0;
  for (m=0; m<180; m++)
  {
    z = (int)(0.5 + td*(double)m)%720;
    c = (int)(0.5 + trd[m]*cosinus[z]);
    s = (int)(0.5 + trd[m]*sinus[z]);
    points[i]       = centrex + c;      points[i+1]     = centrey + s;
    points[i+360]   = centrex + c;      points[i+361]   = centrey - s;
    points[i+720]   = centrex - c;      points[i+721]   = centrey + s;
    points[i+1080]  = centrex - c;      points[i+1081]  = centrey - s;
    i += 2;
  }
}

/* Initialisation de sinus et cosinus ======================================*/
void initfleur()
{
  float angle, delta;
  int i, cadre[4];
  angle = -M_PI;
  delta = M_PI / 180.0;
  for (i=0; i<720; i++)
  {
    sinus[i] = sin(angle);
    cosinus[i] = cos(angle);
    angle = angle + delta;
  }
  initrd();
}

/* Ouvre la fen�tre et obtient xwork et ywork du GEM avec wind_get */
/* Pour utiliser une fen�tre, uk faut:
        1: la cr�er avec wind_create.
        2: lui donner un nom avec wind_set.
        3: l'ouvrir avec wind_open.
        4: �tablir les coordonn�es dans xwork etc avec wind_get (WF_WORKXYWH).
   Toutes les variables en majuscules sont d�finies dans les fichiers
   "include" d�s les premi�res lignes du programme.
*/

void open_window()
{
  wi_handle = wind_create(WI_KIND,xdesk,ydesk,wdesk,hdesk);
  wind_set(wi_handle,WF_NAME, " FLEUR ", 0, 0);
  graf_growbox(xwind+wwind/2, ywind+hwind/2, gl_wbox, gl_hbox,
                xdesk, ydesk, wdesk, hdesk);
  wind_open(wi_handle, xdesk, ydesk, wdesk, hdesk);
  /* On donne � GEM l'adresse du xwork etc. GEM remplit les valeurs */
  wind_get(wi_handle, WF_WORKXYWH,&xwork,&ywork,&wwork,&hwork);
}

/* La fameuse fonction multit�ches =========================================*/
void multi()
{
  int event;
  do {
    event = evnt_multi(MU_MESAG | MU_BUTTON | MU_KEYBD,
                          1,1,butdown,
                          0,0,0,0,0,
                          0,0,0,0,0,
                       msgbuff,0,0,&mx,&my,&ret,&ret,&keycode,&ret);
    wind_update(TRUE);    /* Il faut mettre � jour le fen�tre alors */
    if(event & MU_MESAG)
      switch (msgbuff[0]) {
        case WM_REDRAW: /* Voil�, on redessine la fen�tre */
          do_redraw(msgbuff[4],msgbuff[5],
                    msgbuff[6],msgbuff[7]);
          break;
        case WM_NEWTOP:
        case WM_TOPPED:
          wind_set(wi_handle, WF_TOP,0,0,0,0);
          do_redraw(msgbuff[4],msgbuff[5],
                    msgbuff[6],msgbuff[7]);
          break;
        case WM_SIZED:
        case WM_MOVED:
        /* Si l'utilisateur a boug� la fen�tre, on la redessine apr�s avoir
        recalcul� les param�tres xwork et ywork.
        ATTENTION: si la fen�tre est au minimum, on interdit � l'utilisateur
        de la r�tr�cir davantage! */

          if(msgbuff[6]<MIN_WIDTH)
            msgbuff[6] = MIN_WIDTH;
          if(msgbuff[7]<MIN_HEIGHT)
            msgbuff[7] = MIN_HEIGHT;
          /* Appel � GEM pour mettre � jour les coordonn�es de la fen�tres. */
          wind_set(wi_handle, WF_CURRXYWH, msgbuff[4], msgbuff[5], msgbuff[6],
          msgbuff[7]);
          wind_get(wi_handle,WF_WORKXYWH,&xwork,&ywork,&wwork,&hwork);
          break;
        case WM_FULLED: /* Plein �cran */
          if (fulled) {
            wind_calc(WC_BORDER, WI_KIND,
                      xold, yold, wold, hold,
                      &xwork, &ywork, &wwork, &hwork);
            wind_set(wi_handle, WF_CURRXYWH, xold,
                    yold, wold, hold);
          } else {
            wind_calc(WC_BORDER, WI_KIND, xwork,
                      ywork, wwork, hwork, &xold,
                      &yold,&wold,&hold);
            wind_calc(WC_WORK, WI_KIND, xdesk, ydesk,wdesk, hdesk,
                      &xwork, &ywork, &wwork, &hwork);
            wind_set(wi_handle,WF_CURRXYWH,xdesk,ydesk,wdesk,hdesk);
          }
          fulled = !fulled;
          break;
      } /* fin du switch msgbuff[0] */
      if((event & MU_BUTTON)&&(wi_handle == top_window))
        if (butdown) butdown = FALSE;
        else butdown = TRUE;
      if(event & MU_KEYBD) do_redraw(xwork,ywork,wwork,hwork);
      wind_update(FALSE);
  } while (!((event & MU_MESAG)&&(msgbuff[0] == WM_CLOSED)));
  /* ======================= SORTIE ======================================= */
  /* Quand on arrive ici, l'application est termin�e. Il faut tout fermer et
  sortir sans faire de d�gats... */

  wind_close(wi_handle);
  /* On dessine le shrinkbox pour dire au revoir ========================== */
  graf_shrinkbox(xdesk+wdesk/2, ydesk+hdesk/2, gl_wbox, gl_hbox,
                 xdesk,ydesk,wdesk,hdesk);
  wind_delete(wi_handle);
  wi_handle = NO_WINDOW;
  v_clsvwk(handle);
  appl_exit();  /* important de tout fermer, je r�p�te! */
}

void dofleur()
{
  int temp[4];
  double angle, delta, top;

  centrex = xwork+wwork/2; centrey = ywork+hwork/2;
  vsf_interior(handle,2);
  vsf_style(handle,8);
  vsf_color(handle,0);
  temp[0] = xwork;          temp[1] = ywork;
  temp[2] = xwork+wwork-1;  temp[3] = ywork+hwork-1;
  v_bar(handle,temp); /* efface l'int�rieur de la fen�tre */
  vsf_interior(handle,4);
  vsf_color(handle,1);
  angle = 1.0; delta = 0.2; top = 9.0 + delta;
  while (angle < top) {
    /* Boucle du dessin */
    unefleur(rad, angle);
    vsf_color(handle, 0);
    v_bar(handle, temp);
    vsf_color(handle, 1);
    v_pline(handle, (int)720, points);
    angle = angle + delta;
  }
  rad++;
  if (rad>12) {
    /* Si rad > 12 on recommence � nouveau */
    rad = 1;
    initrd();
  }
  else initrd(); /* Sinon on recommence une nouvelle s�rie */
}

/* Pour �viter de laisser des traces pendant le temps qu'une fen�tre est
boug�e par l'utilisateur, il FAUT cacher la souris. */

void hide_mouse()
{
  if (!hidden) {
    graf_mouse(256, NULL);
    hidden = TRUE;
  }
}

void show_mouse()
{
  if (hidden) {
    graf_mouse(257,NULL);
    hidden = FALSE;
  }
}

/* Coupe toutes les lignes en dehors de la fen�tre */
void set_clip(int x,int y,int w,int h)
{
  int p[4];

  p[0] = x;
  p[1] = y;
  p[2] = x+w;
  p[3] = y+h;
  vs_clip(handle, 1, p);
}

/* Ecrit les param�tres =================================================== */
void ecrit(int x, int y, char *str)
{
  /* La fonction v_justified a besoin de handle, coordonn�es x,y, la longueur
  du texte (dans notre cas en coordonn�es r�elles RC) et de deux param�tres
  qui d�finissent le type de centrage d�sir� par l'utilisateur. */

  v_justified(handle,x,y,str,100,1,1);
}

/* redessine la fen�tre =================================================== */
void do_redraw(int xc, int yc, int wc, int hc)
{
  GRECT t1, t2;
  hide_mouse();
  wind_update(TRUE);
  t2.g_x = xc;
  t2.g_y = yc;
  t2.g_w = wc;
  t2.g_h = hc;
  wind_get(wi_handle,WF_FIRSTXYWH,&t1.g_x,&t1.g_y,&t1.g_w,&t1.g_h);
  while (t1.g_w && t1.g_h) {
    if(rc_intersect(&t2,&t1)) {
      set_clip(t1.g_x,t1.g_y,t1.g_w,t1.g_h);
      dofleur();
    }
    wind_get(wi_handle,WF_NEXTXYWH,&t1.g_x,&t1.g_y,&t1.g_w,&t1.g_h);
  }
  wind_update(FALSE);
  show_mouse();
}

/* Initialise RD ========================================================== */
void initrd()
{
  register int i,t;
  if (hwork<wwork) radius = (double) (hwork/6);
  else radius = (double)(wwork/6);
  for (i=0;i<720;i++)
  {
    t=rad*i % 720;
    trd[i] = radius * exp(cosinus[t]);
  }
  legende();
}

/* Ecrit la l�gende ======================================================= */
void legende()
{
  titre[7] = (char) (rad%10) + '0';
  titre[18] = (char) (theta%10) + '0';
  titre[17] = (char) (theta/10) + '0';
  titre[6] = (char) (rad/10) + '0';
  ecrit(xwork,ywork,ywork+20,titre);
}