/****************************************************************************/
/* 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);
}