/*
* Euler - a numerical lab
*
* platform : neutral
*
* file : meta.c -- portable independant graphic system
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <float.h>
#include <time.h>
#include "sysdep.h"
#include "stack.h"
#include "output.h"
#include "meta.h"
static double delay=0;
double getcolor (int i, int j);
extern int fillcolor1,fillcolor2,usecolors;
double pswidth=15,psheight=15;
typedef struct metastruct {
char *start, *end;
size_t size;
int full, active, recording, playingframe;
long nframes;
int width, height;
int wchar, hchar;
int lines;
short colors[3][MAX_COLORS];
metadevice *device;
} metastruct;
static struct metastruct *m = NULL;
static void commandwrite (int i);
static void longwrite (double n);
static void shortwrite (short n);
static void stringwrite (char *s);
static int nextcommand (char **p);
static double nextlong (char **p);
static int nextint (char **p);
//static void showcommand(int cmd);
/****************************************************************************
* public metafile api
*
****************************************************************************/
int openmeta(int size, metadevice *device)
{
m = (metastruct*)malloc(sizeof(metastruct));
if (m) {
m->size = size*1024L;
m->full = 0;
m->active = 1;
m->recording = 0;
m->playingframe = 0;
m->device = device;
m->nframes = 0;
m->lines = 40;
m->wchar = m->hchar = 1;
m->height = m->width = 0;
m->start = m->end = (char*)malloc(m->size);
if (m->start)
return 1;
}
return 0;
}
void closemeta()
{
if (m) {
if (m->start)
free(m->start);
free(m);
}
}
metadevice * setmetadevice(metadevice *d)
{
metadevice *old = m->device;
if (d)
m->device = d;
return old;
}
metadevice * getmetadevice()
{
return m->device;
}
void setmetawidth(int width)
{
m->width = width;
}
void setmetaheight(int height)
{
m->height = height;
}
int getmetawidth()
{
return m->width;
}
int getmetaheight()
{
return m->height;
}
void setmetacharwidth(int w)
{
m->wchar = w;
}
void setmetacharheight(int h)
{
m->hchar = h;
}
int getmetacharwidth()
{
return m->wchar;
}
int getmetacharheight()
{
return m->hchar;
}
void setmetalines(int lines)
{
m->lines = lines;
}
int getmetalines()
{
return m->lines;
}
void setmetacolors(short colors[3][MAX_COLORS])
{
int i, j;
for (i=0 ; i<3 ; i++)
for (j=0 ; j<MAX_COLORS ; j++)
m->colors[i][j] = colors[i][j];
}
short getmetacolor(int rgb, int index)
{
return m->colors[rgb][index];
}
void playmeta()
{
char *p=m->start;
double c,r,c1,r1,cc[16],hue;
int col,st,width,n,i,co[16],again=-1;
if (m->recording || !m->device) return;
m->active = 0;
if (!m->playingframe) again = 1;
while (p<m->end)
{ int command=nextcommand(&p);
switch(command)
{ case 1 :
if (!m->playingframe && !again) {
m->active = 1;
return;
} else again--;
if (m->playingframe) {
sys_wait(delay,&n);
if (n==escape) {
m->active = 1;
return;
}
// else if (n) {
// m->active=1;
// return;
// }
}
m->device->clear(m->device->data);
break;
case 2 :
c=nextlong(&p);
r=nextlong(&p);
c1=nextlong(&p);
r1=nextlong(&p);
m->device->clip(m->device->data,c,r,c1,r1);
break;
case 10 :
c=nextlong(&p);
r=nextlong(&p);
c1=nextlong(&p);
r1=nextlong(&p);
col=nextint(&p);
st=nextint(&p);
width=nextint(&p);
m->device->line(m->device->data,c,r,c1,r1,col,st,width);
break;
case 20 :
c=nextlong(&p);
r=nextlong(&p);
col=nextint(&p);
st=nextint(&p);
m->device->marker(m->device->data,c,r,col,st);
break;
case 30 :
n=nextint(&p);
for (i=0; i<n; i++)
{ cc[2*i]=nextlong(&p);
cc[2*i+1]=nextlong(&p);
co[i]=nextint(&p);
}
st=nextint(&p);
m->device->fill(m->device->data,cc,st,n,co);
break;
case 31 :
for (i=0; i<8; i++) cc[i]=nextlong(&p);
hue=nextlong(&p);
col=nextint(&p);
st=nextint(&p);
m->device->fillh(m->device->data,cc,hue,col,st);
break;
case 32 :
c=nextlong(&p);
r=nextlong(&p);
c1=nextlong(&p);
r1=nextlong(&p);
hue=nextlong(&p);
col=nextint(&p);
st=nextint(&p);
m->device->bar(m->device->data,c,r,c1,r1,hue,col,st);
break;
case 33 :
c=nextlong(&p);
r=nextlong(&p);
c1=nextlong(&p);
r1=nextlong(&p);
col=nextint(&p);
st=nextint(&p);
m->device->bar1(m->device->data,c,r,c1,r1,col,st);
break;
case 40 :
c=nextlong(&p);
r=nextlong(&p);
col=nextint(&p);
st=nextint(&p);
m->device->text(m->device->data,c,r,p,col,st);
p+=strlen(p)+1;
break;
case 41 :
c=nextlong(&p);
r=nextlong(&p);
col=nextint(&p);
st=nextint(&p);
m->device->vtext(m->device->data,c,r,p,col,st);
p+=strlen(p)+1;
break;
case 42 :
c=nextlong(&p);
r=nextlong(&p);
col=nextint(&p);
st=nextint(&p);
m->device->vutext(m->device->data,c,r,p,col,st);
p+=strlen(p)+1;
break;
case 50 :
nextlong(&p);
break;
default :
break;
}
}
m->active = 1;
}
/****************************************************************************
* frame support
*
****************************************************************************/
void mbeginframes(header *hd)
{
// gclear();
m->recording = 1;
m->end = m->start;
m->full = 0;
m->nframes = 0;
new_real(m->nframes,"");
}
void mendframes(header *h)
{
// gclear();
m->recording = 0;
new_real(m->nframes,"");
}
void mframes (header *hd)
{
new_real(m->nframes,"");
}
void mplayframes(header *hd)
{
header *st=hd,*result;
hd=getvalue(hd);
if (error) return;
if (hd->type!=s_real) wrong_arg_in("play");
graphic_mode();
delay = *realof(hd);
m->playingframe = 1;
m->device->begin(m->device->data);
playmeta();
m->device->end(m->device->data);
m->playingframe = 0;
delay=0.0;
result=new_real(m->nframes,"");
moveresult(st,result);
}
/****************************************************************************
* basic drawing commands
*
****************************************************************************/
void gclear()
{
if (!m->active) return;
if (m->recording) {
m->nframes++;
} else {
m->end = m->start;
m->full = 0;
m->nframes = 0;
}
commandwrite(1);
if (!m->recording && m->device && m->device->clear)
m->device->clear(m->device->data);
}
void gclip(double c, double r, double c1, double r1)
{
if (!m->active) return;
if (fabs(r)>10000.0) return;
if (fabs(c)>10000.0) return;
if (fabs(r1)>10000.0) return;
if (fabs(c1)>10000.0) return;
commandwrite(2);
longwrite(c);
longwrite(r);
longwrite(c1);
longwrite(r1);
if (!m->recording && m->device && m->device->clip)
m->device->clip(m->device->data,c,r,c1,r1);
}
/***** gline
draw a line.
col is the color, where 0 should be white and 1 black.
st is a style from linetyp.
width is the linewidth, where 0 or 1 are equal defaults.
*****/
void gline(double c, double r, double c1, double r1, int color, int st, int width)
{
if (!m->active) return;
if (fabs(r)>10000.0) return;
if (fabs(c)>10000.0) return;
if (fabs(r1)>10000.0) return;
if (fabs(c1)>10000.0) return;
commandwrite(10);
longwrite(c);
longwrite(r);
longwrite(c1);
longwrite(r1);
shortwrite(color);
shortwrite(st);
shortwrite(width);
if (!m->recording && m->device && m->device->line)
m->device->line(m->device->data,c,r,c1,r1,color,st,width);
}
/***** gmarker
plot a single marker on screen.
col is the color.
type is a type from markertyp.
*****/
void gmarker(double c, double r, int color, int type)
{
if (!m->active) return;
commandwrite(20);
longwrite(c);
longwrite(r);
shortwrite(color);
shortwrite(type);
if (!m->recording && m->device && m->device->marker)
m->device->marker(m->device->data,c,r,color,type);
}
void gfill(double c[], int st, int n, int connect[])
{
int i;
if (!m->active) return;
for (i=0; i<2*n; i++) if (fabs(c[i])>10000.0) return;
commandwrite(30);
shortwrite(n);
for (i=0; i<n; i++) {
longwrite(c[2*i]);
longwrite(c[2*i+1]);
shortwrite(connect[i]);
}
shortwrite(st);
if (!m->recording && m->device && m->device->fill)
m->device->fill(m->device->data,c,st,n,connect);
}
/***** Draw a filled polygon.
Works like gfill, but uses hue.
*****/
void gfillh(double c[8], double hue, int color, int connect)
{
int i;
if (!m->active) return;
for (i=0; i<8; i++) if (fabs(c[i])>10000.0) return;
hue-=floor(hue);
commandwrite(31);
for (i=0; i<8; i+=2) {
longwrite(c[i]);
longwrite(c[i+1]);
}
longwrite(hue);
shortwrite(color);
shortwrite(connect);
if (!m->recording && m->device && m->device->fillh)
m->device->fillh(m->device->data,c,hue,color,connect);
}
/***** Draw a rectangle.
hue is a hue intensity from 0 to 1.
style determines, if a black boundary should be drawn.
******/
void gbar(double c, double r, double c1, double r1, double hue, int color, int style)
{
if (!m->active) return;
commandwrite(32);
longwrite(c);
longwrite(r);
longwrite(c1);
longwrite(r1);
longwrite(hue);
shortwrite(color);
shortwrite(style);
if (!m->recording && m->device && m->device->bar)
m->device->bar(m->device->data,c,r,c1,r1,hue,color,style);
}
/***** Draw a rectangle.
hue is a hue intensity from 0 to 1.
style determines, if a black boundary should be drawn.
******/
void gbar1(double c, double r, double c1, double r1, int color, int style)
{
if (!m->active) return;
commandwrite(33);
longwrite(c);
longwrite(r);
longwrite(c1);
longwrite(r1);
shortwrite(color);
shortwrite(style);
if (!m->recording && m->device && m->device->bar1)
m->device->bar1(m->device->data,c,r,c1,r1,color,style);
}
/***** gtext
output a graphic text on screen.
alignment is left=0, centered=1, right=2.
*****/
void gtext(double c, double r, char *text, int color, int alignment)
{
if (!m->active) return;
commandwrite(40);
longwrite(c);
longwrite(r);
shortwrite(color);
shortwrite(alignment);
stringwrite(text);
if (!m->recording && m->device && m->device->text)
m->device->text(m->device->data,c,r,text,color,alignment);
}
/***** gvtext
like gtext downwards
*****/
void gvtext(double c, double r, char *text, int color, int alignment)
{
if (!m->active) return;
commandwrite(41);
longwrite(c);
longwrite(r);
shortwrite(color);
shortwrite(alignment);
stringwrite(text);
if (!m->recording && m->device && m->device->vtext)
m->device->vtext(m->device->data,c,r,text,color,alignment);
}
/***** gvutext
like gtext upwards.
*****/
void gvutext(double c, double r, char *text, int color, int alignment)
{
if (!m->active) return;
commandwrite(42);
longwrite(c);
longwrite(r);
shortwrite(color);
shortwrite(alignment);
stringwrite(text);
if (!m->recording && m->device && m->device->vutext)
m->device->vutext(m->device->data,c,r,text,color,alignment);
}
void gscale (double s)
{
if (!m->active) return;
commandwrite(50);
longwrite(s*1000);
if (!m->recording && m->device && m->device->scale)
m->device->scale(m->device->data,s);
}
int dump_meta (char *filename)
{
FILE *out=fopen(filename,"w");
if (!out) return 0;
fwrite(m->start,m->end-m->start,1,out);
fclose(out);
return 1;
}
void pswindow (double w, double h)
{ pswidth=w;
psheight=h;
}
/****************************************************************************
* private metafile
*
****************************************************************************/
static void write (void *l, int n)
{ if (!m->active || m->full) return;
memmove(m->end,l,n);
m->end+=n;
}
static void commandwrite (int i)
{
if (!m->active) return;
if ((int)(m->end-m->start)>(int)(m->size-512)) { m->full=1; return; }
*m->end++=i;
}
/*****
write a double to the metafile as long
*****/
static void longwrite (double n)
{
long k=(long)(n*1000.0);
write(&k,sizeof(long));
}
/*****
write an int to the metafile
*****/
static void shortwrite (short n)
{ write(&n,sizeof(short));
}
/*****
write a string to the metafile
*****/
static void stringwrite (char *s)
{ write(s,strlen(s)+1);
}
static int nextcommand (char **p)
{ int k=**p; (*p)++; return k;
}
static double nextlong (char **p)
{ long x;
memmove(&x,*p,sizeof(long));
(*p)+=sizeof(long);
return x/1000.0;
}
static int nextint (char **p)
{ short n;
memmove(&n,*p,sizeof(short));
(*p)+=sizeof(short);
return n;
}
#if 0
static void showcommand(int cmd)
{
switch (cmd) {
case 1 :
fprintf(stderr,"%2d : clear\n",cmd);
break;
case 2 :
fprintf(stderr,"%2d : clip\n",cmd);
break;
case 10 :
fprintf(stderr,"%2d : line\n",cmd);
break;
case 20 :
fprintf(stderr,"%2d : marker\n",cmd);
break;
case 30 :
fprintf(stderr,"%2d : fill\n",cmd);
break;
case 31 :
fprintf(stderr,"%2d : fillh\n",cmd);
break;
case 32 :
fprintf(stderr,"%2d : bar\n",cmd);
break;
case 33 :
fprintf(stderr,"%2d : bar1\n",cmd);
break;
case 40 :
fprintf(stderr,"%2d : text\n",cmd);
break;
case 41 :
fprintf(stderr,"%2d : vtext\n",cmd);
break;
case 42 :
fprintf(stderr,"%2d : vutext\n",cmd);
break;
case 50 :
fprintf(stderr,"%2d : scale\n",cmd);
break;
default :
fprintf(stderr,"%2d : unknown\n",cmd);
break;
}
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1