xref: /plan9/sys/src/cmd/venti/srv/graph.c (revision 368c31ab13393dea083228fdd1c3445076f83a4b)
1*368c31abSDavid du Colombier #include "stdinc.h"
2*368c31abSDavid du Colombier #include "dat.h"
3*368c31abSDavid du Colombier #include "fns.h"
4*368c31abSDavid du Colombier 
5*368c31abSDavid du Colombier enum
6*368c31abSDavid du Colombier {
7*368c31abSDavid du Colombier 	Top = 1,
8*368c31abSDavid du Colombier 	Bottom = 1,
9*368c31abSDavid du Colombier 	Left = 40,
10*368c31abSDavid du Colombier 	Right = 0,
11*368c31abSDavid du Colombier 	MinWidth = Left+Right+2,
12*368c31abSDavid du Colombier 	MinHeight = Top+Bottom+2,
13*368c31abSDavid du Colombier 	DefaultWidth = Left+Right+500,
14*368c31abSDavid du Colombier 	DefaultHeight = Top+Bottom+40
15*368c31abSDavid du Colombier };
16*368c31abSDavid du Colombier 
17*368c31abSDavid du Colombier QLock memdrawlock;
18*368c31abSDavid du Colombier static Memsubfont *smallfont;
19*368c31abSDavid du Colombier static Memimage *black;
20*368c31abSDavid du Colombier static Memimage *blue;
21*368c31abSDavid du Colombier static Memimage *red;
22*368c31abSDavid du Colombier static Memimage *lofill[6];
23*368c31abSDavid du Colombier static Memimage *hifill[6];
24*368c31abSDavid du Colombier static Memimage *grid;
25*368c31abSDavid du Colombier 
26*368c31abSDavid du Colombier static ulong fill[] = {
27*368c31abSDavid du Colombier 	0xFFAAAAFF,	0xBB5D5DFF,	/* peach */
28*368c31abSDavid du Colombier 	DPalegreygreen, DPurpleblue,	/* aqua */
29*368c31abSDavid du Colombier 	DDarkyellow, DYellowgreen,	/* yellow */
30*368c31abSDavid du Colombier 	DMedgreen, DDarkgreen,		/* green */
31*368c31abSDavid du Colombier 	0x00AAFFFF, 0x0088CCFF,	/* blue */
32*368c31abSDavid du Colombier 	0xCCCCCCFF, 0x888888FF,	/* grey */
33*368c31abSDavid du Colombier };
34*368c31abSDavid du Colombier 
35*368c31abSDavid du Colombier Memimage*
allocrepl(ulong color)36*368c31abSDavid du Colombier allocrepl(ulong color)
37*368c31abSDavid du Colombier {
38*368c31abSDavid du Colombier 	Memimage *m;
39*368c31abSDavid du Colombier 
40*368c31abSDavid du Colombier 	m = allocmemimage(Rect(0,0,1,1), RGB24);
41*368c31abSDavid du Colombier 	memfillcolor(m, color);
42*368c31abSDavid du Colombier 	m->flags |= Frepl;
43*368c31abSDavid du Colombier 	m->clipr = Rect(-1000000, -1000000, 1000000, 1000000);
44*368c31abSDavid du Colombier 	return m;
45*368c31abSDavid du Colombier }
46*368c31abSDavid du Colombier 
47*368c31abSDavid du Colombier static void
ginit(void)48*368c31abSDavid du Colombier ginit(void)
49*368c31abSDavid du Colombier {
50*368c31abSDavid du Colombier 	static int first = 1;
51*368c31abSDavid du Colombier 	int i;
52*368c31abSDavid du Colombier 
53*368c31abSDavid du Colombier 	if(!first)
54*368c31abSDavid du Colombier 		return;
55*368c31abSDavid du Colombier 
56*368c31abSDavid du Colombier 	first = 0;
57*368c31abSDavid du Colombier 	memimageinit();
58*368c31abSDavid du Colombier #ifdef PLAN9PORT
59*368c31abSDavid du Colombier 	smallfont = openmemsubfont(unsharp("#9/font/lucsans/lstr.10"));
60*368c31abSDavid du Colombier #else
61*368c31abSDavid du Colombier 	smallfont = openmemsubfont("/lib/font/bit/lucidasans/lstr.10");
62*368c31abSDavid du Colombier #endif
63*368c31abSDavid du Colombier 	black = memblack;
64*368c31abSDavid du Colombier 	blue = allocrepl(DBlue);
65*368c31abSDavid du Colombier 	red = allocrepl(DRed);
66*368c31abSDavid du Colombier 	grid = allocrepl(0x77777777);
67*368c31abSDavid du Colombier 	for(i=0; i<nelem(fill)/2 && i<nelem(lofill) && i<nelem(hifill); i++){
68*368c31abSDavid du Colombier 		lofill[i] = allocrepl(fill[2*i]);
69*368c31abSDavid du Colombier 		hifill[i] = allocrepl(fill[2*i+1]);
70*368c31abSDavid du Colombier 	}
71*368c31abSDavid du Colombier }
72*368c31abSDavid du Colombier 
73*368c31abSDavid du Colombier static void
mklabel(char * str,int v)74*368c31abSDavid du Colombier mklabel(char *str, int v)
75*368c31abSDavid du Colombier {
76*368c31abSDavid du Colombier 	if(v < 0){
77*368c31abSDavid du Colombier 		v = -v;
78*368c31abSDavid du Colombier 		*str++ = '-';
79*368c31abSDavid du Colombier 	}
80*368c31abSDavid du Colombier 	if(v < 10000)
81*368c31abSDavid du Colombier 		sprint(str, "%d", v);
82*368c31abSDavid du Colombier 	else if(v < 10000000)
83*368c31abSDavid du Colombier 		sprint(str, "%dk", v/1000);
84*368c31abSDavid du Colombier 	else
85*368c31abSDavid du Colombier 		sprint(str, "%dM", v/1000000);
86*368c31abSDavid du Colombier }
87*368c31abSDavid du Colombier 
88*368c31abSDavid du Colombier static void
drawlabel(Memimage * m,Point p,int n)89*368c31abSDavid du Colombier drawlabel(Memimage *m, Point p, int n)
90*368c31abSDavid du Colombier {
91*368c31abSDavid du Colombier 	char buf[30];
92*368c31abSDavid du Colombier 	Point w;
93*368c31abSDavid du Colombier 
94*368c31abSDavid du Colombier 	mklabel(buf, n);
95*368c31abSDavid du Colombier 	w = memsubfontwidth(smallfont, buf);
96*368c31abSDavid du Colombier 	memimagestring(m, Pt(p.x-5-w.x, p.y), memblack, ZP, smallfont, buf);
97*368c31abSDavid du Colombier }
98*368c31abSDavid du Colombier 
99*368c31abSDavid du Colombier static int
scalept(int val,int valmin,int valmax,int ptmin,int ptmax)100*368c31abSDavid du Colombier scalept(int val, int valmin, int valmax, int ptmin, int ptmax)
101*368c31abSDavid du Colombier {
102*368c31abSDavid du Colombier 	if(val <= valmin)
103*368c31abSDavid du Colombier 		val = valmin;
104*368c31abSDavid du Colombier 	if(val >= valmax)
105*368c31abSDavid du Colombier 		val = valmax;
106*368c31abSDavid du Colombier 	if(valmax == valmin)
107*368c31abSDavid du Colombier 		valmax++;
108*368c31abSDavid du Colombier 	return ptmin + (vlong)(val-valmin)*(ptmax-ptmin)/(valmax-valmin);
109*368c31abSDavid du Colombier }
110*368c31abSDavid du Colombier 
111*368c31abSDavid du Colombier Memimage*
statgraph(Graph * g)112*368c31abSDavid du Colombier statgraph(Graph *g)
113*368c31abSDavid du Colombier {
114*368c31abSDavid du Colombier 	int i, nbin, x, lo, hi, min, max, first;
115*368c31abSDavid du Colombier 	Memimage *m;
116*368c31abSDavid du Colombier 	Rectangle r;
117*368c31abSDavid du Colombier 	Statbin *b, bin[2000];	/* 32 kB, but whack is worse */
118*368c31abSDavid du Colombier 
119*368c31abSDavid du Colombier 	needstack(8192);	/* double check that bin didn't kill us */
120*368c31abSDavid du Colombier 
121*368c31abSDavid du Colombier 	if(g->wid <= MinWidth)
122*368c31abSDavid du Colombier 		g->wid = DefaultWidth;
123*368c31abSDavid du Colombier 	if(g->ht <= MinHeight)
124*368c31abSDavid du Colombier 		g->ht = DefaultHeight;
125*368c31abSDavid du Colombier 	if(g->wid > nelem(bin))
126*368c31abSDavid du Colombier 		g->wid = nelem(bin);
127*368c31abSDavid du Colombier 	if(g->fill < 0)
128*368c31abSDavid du Colombier 		g->fill = ((uint)(uintptr)g->arg>>8)%nelem(lofill);
129*368c31abSDavid du Colombier 	if(g->fill > nelem(lofill))
130*368c31abSDavid du Colombier 		g->fill %= nelem(lofill);
131*368c31abSDavid du Colombier 
132*368c31abSDavid du Colombier 	nbin = g->wid - (Left+Right);
133*368c31abSDavid du Colombier 	binstats(g->fn, g->arg, g->t0, g->t1, bin, nbin);
134*368c31abSDavid du Colombier 
135*368c31abSDavid du Colombier 	/*
136*368c31abSDavid du Colombier 	 * compute bounds
137*368c31abSDavid du Colombier 	 */
138*368c31abSDavid du Colombier 	min = g->min;
139*368c31abSDavid du Colombier 	max = g->max;
140*368c31abSDavid du Colombier 	if(min < 0 || max <= min){
141*368c31abSDavid du Colombier 		min = max = 0;
142*368c31abSDavid du Colombier 		first = 1;
143*368c31abSDavid du Colombier 		for(i=0; i<nbin; i++){
144*368c31abSDavid du Colombier 			b = &bin[i];
145*368c31abSDavid du Colombier 			if(b->nsamp == 0)
146*368c31abSDavid du Colombier 				continue;
147*368c31abSDavid du Colombier 			if(first || b->min < min)
148*368c31abSDavid du Colombier 				min = b->min;
149*368c31abSDavid du Colombier 			if(first || b->max > max)
150*368c31abSDavid du Colombier 				max = b->max;
151*368c31abSDavid du Colombier 			first = 0;
152*368c31abSDavid du Colombier 		}
153*368c31abSDavid du Colombier 	}
154*368c31abSDavid du Colombier 
155*368c31abSDavid du Colombier 	qlock(&memdrawlock);
156*368c31abSDavid du Colombier 	ginit();
157*368c31abSDavid du Colombier 	if(smallfont==nil || black==nil || blue==nil || red==nil || hifill==nil || lofill==nil){
158*368c31abSDavid du Colombier 		werrstr("graphics initialization failed: %r");
159*368c31abSDavid du Colombier 		qunlock(&memdrawlock);
160*368c31abSDavid du Colombier 		return nil;
161*368c31abSDavid du Colombier 	}
162*368c31abSDavid du Colombier 
163*368c31abSDavid du Colombier 	/* fresh image */
164*368c31abSDavid du Colombier 	m = allocmemimage(Rect(0,0,g->wid,g->ht), ABGR32);
165*368c31abSDavid du Colombier 	if(m == nil){
166*368c31abSDavid du Colombier 		qunlock(&memdrawlock);
167*368c31abSDavid du Colombier 		return nil;
168*368c31abSDavid du Colombier 	}
169*368c31abSDavid du Colombier 	r = Rect(Left, Top, g->wid-Right, g->ht-Bottom);
170*368c31abSDavid du Colombier 	memfillcolor(m, DTransparent);
171*368c31abSDavid du Colombier 
172*368c31abSDavid du Colombier 	/* x axis */
173*368c31abSDavid du Colombier 	memimagedraw(m, Rect(r.min.x, r.max.y, r.max.x, r.max.y+1), black, ZP, memopaque, ZP, S);
174*368c31abSDavid du Colombier 
175*368c31abSDavid du Colombier 	/* y labels */
176*368c31abSDavid du Colombier 	drawlabel(m, r.min, max);
177*368c31abSDavid du Colombier 	if(min != 0)
178*368c31abSDavid du Colombier 		drawlabel(m, Pt(r.min.x, r.max.y-smallfont->height), min);
179*368c31abSDavid du Colombier 
180*368c31abSDavid du Colombier 	/* actual data */
181*368c31abSDavid du Colombier 	for(i=0; i<nbin; i++){
182*368c31abSDavid du Colombier 		b = &bin[i];
183*368c31abSDavid du Colombier 		if(b->nsamp == 0)
184*368c31abSDavid du Colombier 			continue;
185*368c31abSDavid du Colombier 		lo = scalept(b->min, min, max, r.max.y, r.min.y);
186*368c31abSDavid du Colombier 		hi = scalept(b->max, min, max, r.max.y, r.min.y);
187*368c31abSDavid du Colombier 		x = r.min.x+i;
188*368c31abSDavid du Colombier 		hi-=2;
189*368c31abSDavid du Colombier 		memimagedraw(m, Rect(x, hi, x+1,lo), hifill[g->fill%nelem(hifill)], ZP, memopaque, ZP, S);
190*368c31abSDavid du Colombier 		memimagedraw(m, Rect(x, lo, x+1, r.max.y), lofill[g->fill%nelem(lofill)], ZP, memopaque, ZP, S);
191*368c31abSDavid du Colombier 	}
192*368c31abSDavid du Colombier 
193*368c31abSDavid du Colombier 	if(bin[nbin-1].nsamp)
194*368c31abSDavid du Colombier 		drawlabel(m, Pt(r.max.x, r.min.y+(Dy(r)-smallfont->height)/2), bin[nbin-1].avg);
195*368c31abSDavid du Colombier 	qunlock(&memdrawlock);
196*368c31abSDavid du Colombier 	return m;
197*368c31abSDavid du Colombier }
198