wmcube: imported Upstream version 0.98
[dockapps.git] / wmcube / wmcube / wmcube.c
bloba586b55387a05393690a60445e967a7a93ea9980
1 /*
3 wmcube.c
4 Version 0.98 (2000-10-20)
6 Robert Kling (robkli-8@student.luth.se)
7 http://boombox.campus.luth.se/projects.php
9 Contributions:
10 -n option patch by Thorsten Jens (thodi@et-inf.fho-emden.de) (2000-05-12)
11 Various bugfixes and optimizations by Jakob Borg (2000-05-13)
12 Solaris Port by Dan Price (dp@rampant.org) (2000-07-16)
13 OpenBSD Port by Brian Joseph Czapiga (rys@godsey.net) (2000-07-19)
14 FreeBSD Port by Tai-hwa Liang (avatar@mmlab.cse.yzu.edu.tw) (2000-07-20)
15 NetBSD Port by Jared Smolens <jsmolens+@andrew.cmu.edu> (2000-09-23)
17 This software is licensed through the GNU General Public Licence.
19 See http://www.BenSinclair.com/dockapp/ for more wm dock apps.
21 If you want to port wmcube to another OS the system specific code is
22 sectioned the bottom of this file. See instructions there.
26 #define WMCUBE_VERSION "0.98"
27 #define REV_DATE "2000-10-23"
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <time.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <ctype.h>
36 #include <math.h>
38 #include <sys/wait.h>
39 #include <sys/stat.h>
40 #include <sys/param.h>
41 #include <sys/types.h>
42 #include <sys/ioctl.h>
43 #include <sys/socket.h>
45 #include <utmp.h>
46 #include <dirent.h>
48 #include <X11/Xlib.h>
49 #include <X11/xpm.h>
50 #include <X11/extensions/shape.h>
52 #ifdef FREEBSD
53 #include <kvm.h>
54 #endif
56 #include "../wmgeneral/wmgeneral.h"
57 #include "../wmgeneral/misc.h"
59 #include "wmcube.xpm"
60 char wmcube_mask_bits[64*64];
61 int wmcube_mask_width = 64;
62 int wmcube_mask_height = 64;
64 #define CHAR_WIDTH 5
65 #define CHAR_HEIGHT 7
66 #define PI 3.1415926535
68 //**** Graphics ***********************************
70 void putpixel(int x, int y, int c);
71 void line(int x1, int y1, int x2, int y2, int c);
72 void hline(int x1, int x2, int y, int c);
73 void triangle(int x1, int y1, int x2, int y2, int x3, int y3, int c);
74 void BlitString(char *name, int x, int y);
75 void BlitNum(int num, int x, int y);
76 void clearscr();
77 void draw();
78 void startup_seq();
80 //**** 3d specific ********************************
82 void setupobj(char *filename) ;
83 void setUpAngles();
84 void rotate(int xang, int yang, int zang);
85 int normal(float p1[], float p2[], float p3[]);
86 int luminate(float p1[], float p2[], float p3[]);
87 void sortz(int nofelements);
89 //**** Application Management, I/O etc. ***********
91 void print_help();
92 int loadobj(char *filename);
93 void mem_alloc_error(void *block);
94 int scan4objects(char *dir);
95 int next_object();
96 void die();
98 //**** System specific functions ******************
100 int init_calc_cpu();
101 int calc_cpu_total();
103 //**** Global variables ***************************
105 int xcenter, ycenter, zoff;
106 double cost[361], sint[361];
107 double acost[100];
108 float **matrix;
109 float **rmatrix;
110 int **planes;
111 int *plane_color;
112 int *zorder;
113 int *cline;
114 int nofcoords, noflines, nofplanes;
115 char *objects[1000];
116 int nof_objects = 0;
117 int show_load = 1;
118 int use_nice = 1;
119 int which_cpu = -1;
120 int planesORlines = 1;
121 char *pname;
123 float lum_vector[3] = { 0, 0, 100 }; // Lightsource vector
125 #ifdef FREEBSD
126 static kvm_t *kd;
127 static struct nlist nlst[] = { {"_cp_time"}, {0} };
128 #endif
130 int main(int argc, char **argv)
132 int j, i = 0, rot_speed = 0, cpu_usage = 0, rot_step = 1;
133 long screen_speed = 10000; // microseconds between screen updates (approx.)
134 long cpu_update = 490000; // microseconds between cpu update (approx.)
135 int but_stat = -1;
136 int loop = 0;
137 XEvent Event;
139 char *rotdiv = {"25"};
140 char *rotstep = {"1"};
141 char *obj_filename = {""};
142 int rot;
143 int cube_color = 1;
144 int c = 0;
145 int invert_speed = 0;
147 pname = strrchr(argv[0], '/');
148 if (pname == NULL) pname = argv[0];
150 srand((unsigned)time(NULL));
151 opterr = 0;
153 while ((c = getopt (argc, argv, "d:nhpbir:o:c:")) != -1) {
154 switch (c)
156 case 'c':
157 which_cpu = atoi(optarg);
158 break;
159 case 'd':
160 rotstep = optarg;
161 break;
162 case 'h':
163 print_help();
164 return 1;
165 case 'i':
166 invert_speed = 1;
167 break;
168 case 'p':
169 show_load = 0;
170 break;
171 case 'b':
172 cube_color = 2;
173 break;
174 case 'r':
175 rotdiv = optarg;
176 break;
177 case 'o':
178 obj_filename = optarg;
179 break;
180 case 'n':
181 use_nice = 0;
182 break;
183 case '?':
184 print_help();
185 return 1;
186 default:
187 abort();
192 * Validate that wmcube can run on this system given the parameters,
193 * then setup the statistics gathering subsystem.
196 if (init_calc_cpu() != 0) die();
199 * Scan directory for .wmc files and choose one randomly. If the user
200 * specified a particular file, load that one.
203 #ifndef SOLARIS // scan4objects doesnt work on Solaris, load object immediatly
204 scan4objects(obj_filename);
206 if (nof_objects != 0)
207 next_object();
208 else
209 #endif
210 setupobj(obj_filename);
213 * Various initializion stuff for the 3d-engine etc.
216 setUpAngles();
218 rot = atoi(rotdiv);
219 if ((rot >= 1) && (rot <=100)) ; else rot = 25;
221 rot_step = atoi(rotstep);
222 if (rot_step < 0) rot_step = -rot_step;
224 if (calc_cpu_total() == -1) die();
226 cpu_update /= screen_speed;
228 createXBMfromXPM(wmcube_mask_bits, wmcube_xpm, wmcube_mask_width, wmcube_mask_height);
229 openXwindow(argc, argv, wmcube_xpm, wmcube_mask_bits, wmcube_mask_width, wmcube_mask_height);
231 startup_seq();
233 if (calc_cpu_total() == -1) die();
235 // index, left, top, right, bottom
236 AddMouseRegion(1, 45, 45, 58, 58); // + Zoom In
237 AddMouseRegion(5, 5, 45, 20, 58); // - Zoom Out
238 AddMouseRegion(3, 21, 45, 45, 58); // Show cpu-load
239 AddMouseRegion(2, 5, 5, 55, 45); // Everywhere else (almost) to change object
242 * Main loop begins here
245 while (1)
247 i = (i+rot_speed+rot_step) % 360;
249 clearscr();
250 rotate(i,i,i);
252 draw(cube_color);
254 if (show_load) {
255 BlitNum(cpu_usage,24,49);
256 BlitString("Z",38,49);
259 RedrawWindow();
261 if (loop++ == cpu_update) {
262 loop = 0;
265 * call calc_cpu_total to update statistics. If some
266 * sort of bad event occurs, calc_cpu_total will return
267 * -1, and we exit.
270 if ((cpu_usage = calc_cpu_total()) == -1) {
271 die();
273 rot_speed = abs( invert_speed*(100 / rot) - cpu_usage / rot);
276 // X Events
278 while (XPending(display))
280 XNextEvent(display, &Event);
281 switch (Event.type)
283 case Expose:
284 RedrawWindow();
285 break;
286 case DestroyNotify:
287 XCloseDisplay(display);
288 exit(0);
289 break;
290 case ButtonPress:
291 j = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
292 but_stat = j;
294 break;
295 case ButtonRelease:
296 j = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
298 switch(j)
300 case 1:
301 if (zoff > 750) {
302 BlitString("ö",48,48);
303 RedrawWindow();
304 zoff -= 150;
306 break;
308 case 2:
309 next_object();
310 break;
312 case 3:
313 if (show_load == 1) show_load = 0; else show_load = 1;
314 ycenter = 15 - 2*show_load;
315 break;
317 case 5:
318 BlitString("ä",11,49);
319 RedrawWindow();
320 zoff += 150;
321 break;
324 break;
326 usleep(screen_speed);
330 * Free up memory used by the object (dirty...)
333 free(matrix);
334 free(rmatrix);
335 free(cline);
337 return 1;
341 //**** Graphics ***********************************
342 //*************************************************
344 void startup_seq()
346 char *tmp = malloc(32);
347 int oldzoff = 3600;
349 sprintf(tmp,"V%s",WMCUBE_VERSION);
351 RedrawWindow();
352 BlitString("WMCUBE",13,22);
353 BlitString(tmp,15,31);
354 RedrawWindow();
355 RedrawWindow();
356 usleep(3000000);
357 RedrawWindow();
359 zoff = 1200;
361 for (;zoff < oldzoff; zoff += 35)
363 rotate((zoff-1200)/8,0,0);
364 clearscr();
365 BlitString("WMCUBE",13,22);
366 BlitString(tmp,15,31);
367 draw(1);
368 RedrawWindow();
369 usleep(9000);
372 zoff = 3600;
375 void draw(int color)
377 int i;
379 if (planesORlines) {
381 sortz(nofplanes);
382 for (i = 0; i < nofplanes; i++) {
383 if (normal(rmatrix[planes[zorder[i]][0]], rmatrix[planes[zorder[i]][1]], rmatrix[planes[zorder[i]][2]]) > 0) {
385 triangle(xcenter+rmatrix[planes[zorder[i]][0]][0], ycenter+rmatrix[planes[zorder[i]][0]][1],
386 xcenter+rmatrix[planes[zorder[i]][1]][0], ycenter+rmatrix[planes[zorder[i]][1]][1],
387 xcenter+rmatrix[planes[zorder[i]][2]][0], ycenter+rmatrix[planes[zorder[i]][2]][1], plane_color[zorder[i]]);
391 } else {
392 for (i = 0; i < noflines; i += 2)
393 line(xcenter+rmatrix[cline[i ]-1][0], ycenter+rmatrix[cline[i ]-1][1],
394 xcenter+rmatrix[cline[i+1]-1][0], ycenter+rmatrix[cline[i+1]-1][1],color);
398 void putpixel(int x, int y,int c)
400 if ((x > 4) && (x < 59) && (y > 4) && (y < 59))
401 copyXPMArea(160-c,0,1,1,x,y);
404 void hline(int x1, int x2, int y, int c)
406 if ((y > 4) && (y < 59)) {
407 if (x1 <= 4) x1 = 5; else if (x1 > 57) return;
408 if (x2 > 57) x2 = 57; else if (x2 <= 4) return;
410 copyXPMArea(105, 56+c + 9*(c/18), x2-x1, 1, x1, y);
414 void triangle(int x1, int y1, int x2, int y2, int x3, int y3, int c) // Draws a filled triangle
416 int k,k2,x,x_2,i, tmp1;
418 int x1t, x2t;
420 if (y3<y2)
422 tmp1=y2;
423 y2=y3;
424 y3=tmp1;
425 tmp1=x2;
426 x2=x3;
427 x3=tmp1;
430 if (y2<y1)
432 tmp1=y1;
433 y1=y2;
434 y2=tmp1;
435 tmp1=x1;
436 x1=x2;
437 x2=tmp1;
440 if (y3<y2)
442 tmp1=y2;
443 y2=y3;
444 y3=tmp1;
445 tmp1=x2;
446 x2=x3;
447 x3=tmp1;
450 if (y1!=y3) k=((x1-x3) << 6) / (y1-y3);
451 else k=(x1-x3) << 6;
453 if (y1!=y2) k2=((x1-x2) << 6) / (y1-y2);
454 else k2=(x1-x2) << 6;
456 x=x1 << 6;
457 x_2=x;
458 i=y1;
460 if (i!=y2)
463 x+=k;
464 x_2+=k2;
465 i++;
467 if ((x1t = x >> 6) > (x2t = x_2 >> 6))
468 hline(x2t, x1t, i, c);
469 else
470 hline(x1t, x2t, i, c);
472 while (i!=y2);
474 if (i==y3) return;
476 if (y2!=y3) k2=((x2-x3) << 6) / (y2-y3);
477 else k2=((x2-x3) << 6);
479 x_2=x2 << 6;
480 i=y2;
483 x+=k;
484 x_2+=k2;
485 i++;
487 if ((x1t = x >> 6) > (x2t = x_2 >> 6))
488 hline(x2t, x1t, i, c);
489 else
490 hline(x1t, x2t, i, c);
492 while (i!=y3);
495 void clearscr()
497 copyXPMArea(78,0,56,56,4,4);
500 // Blits a string at given co-ordinates
501 void BlitString(char *name, int x, int y)
503 int i;
504 int c;
505 int k;
507 k = x;
509 copyXPMArea(73,64,1,8,k-1,y);
511 for (i=0; name[i]; i++)
513 c = toupper(name[i]);
514 //printf("%c",c);
516 if (c >= 'A' && c <= 'Z')
517 { // its a letter
518 c -= 'A';
519 if ( k > -2) copyXPMArea(c * 6, 74, 6, 8, k, y);
520 k += 6;
521 } else
522 if (c >= '0' && c<= ':')
523 { // its a number or symbol
524 c -= '0';
525 if ( k > -2) copyXPMArea(c * 6, 64, 6, 8, k, y);
526 k += 6;
527 } else
528 if (c == 246) {
529 if ( k > -2) copyXPMArea(0, 84, 6, 9, k, y);
530 k += 6;
531 } else
532 if (c == 228) {
533 if ( k > -2) copyXPMArea(6, 84, 6, 9, k, y);
534 k += 6;
535 } else
536 if (c == 229) {
537 if ( k > -2) copyXPMArea(12, 84, 6, 9, k, y);
538 k += 6;
539 } else
540 { // its a blank or something else
541 if ( k > -2) copyXPMArea(73,64,6,8,k,y);
542 k += 6;
544 if (k >= 58) break;
546 copyXPMArea(73,64,1,8,k,y);
550 // Blits number to given coordinates.. two 0's, right justified
552 void BlitNum(int num, int x, int y)
554 char buf[1024];
555 int newx=x;
557 if (num > 99)
559 newx -= CHAR_WIDTH;
562 if (num > 999)
564 newx -= CHAR_WIDTH;
567 sprintf(buf, "%02i", num);
569 BlitString(buf, newx, y);
572 void line(int x1, int y1, int x2, int y2, int c)
574 int i, deltax, deltay, numpixels,
575 d, dinc1, dinc2,
576 x, xinc1, xinc2,
577 y, yinc1, yinc2;
579 deltax = abs(x2 - x1);
580 deltay = abs(y2 - y1);
581 if (deltax >= deltay)
583 numpixels = deltax + 1;
584 d = (deltay << 1) - deltax;
585 dinc1 = deltay << 1;
586 dinc2 = (deltay - deltax) << 1;
587 xinc1 = 1;
588 xinc2 = 1;
589 yinc1 = 0;
590 yinc2 = 1;
592 else
594 numpixels = deltay + 1;
595 d = (deltax << 1) - deltay;
596 dinc1 = deltax << 1;
597 dinc2 = (deltax - deltay) << 1;
598 xinc1 = 0;
599 xinc2 = 1;
600 yinc1 = 1;
601 yinc2 = 1;
603 if (x1 > x2)
605 xinc1 = - xinc1;
606 xinc2 = - xinc2;
608 if (y1 > y2)
610 yinc1 = - yinc1;
611 yinc2 = - yinc2;
613 x = x1;
614 y = y1;
615 for (i=1; i<numpixels; i++)
617 putpixel(x, y, c);
618 if (d < 0)
620 d = d + dinc1;
621 x = x + xinc1;
622 y = y + yinc1;
624 else
626 d = d + dinc2;
627 x = x + xinc2;
628 y = y + yinc2;
634 //**** 3d specific ********************************
635 //*************************************************
637 void rotate(int xang, int yang, int zang)
639 float tx, ty, tz;
640 int i;
642 for (i = 0; i < nofcoords; i++)
644 tx = cost[yang]*matrix[i][0]-sint[yang]*matrix[i][2];
645 tz = sint[yang]*matrix[i][0]+cost[yang]*matrix[i][2];
646 ty = cost[zang]*matrix[i][1]-sint[zang]*tx;
648 rmatrix[i][0] = (cost[zang]*tx+sint[zang]*matrix[i][1]);
649 rmatrix[i][1] = (sint[xang]*tz+cost[xang]*ty);
650 rmatrix[i][2] = (cost[xang]*tz-sint[xang]*ty);
653 if (planesORlines)
654 for (i = 0; i < nofplanes; i++)
655 if (normal(rmatrix[planes[i][0]], rmatrix[planes[i][1]], rmatrix[planes[i][2]]) > 0)
656 plane_color[i] = luminate(rmatrix[planes[i][0]], rmatrix[planes[i][1]], rmatrix[planes[i][2]]);
658 for (i = 0; i < nofcoords; i++) {
659 // Perspective correcting lines...
660 rmatrix[i][0] = (rmatrix[i][0] *256) / (2*rmatrix[i][2] - zoff) + xcenter;
661 rmatrix[i][1] = (rmatrix[i][1] *256) / (2*rmatrix[i][2] - zoff) + ycenter;
665 void sortz(int nofelements) { // Insertion-sort the planes in increasing z-distance
667 int i, j, k;
668 float key;
669 float temparr[nofelements];
671 for (i = 0; i < nofelements; i++)
673 zorder[i] = i;
674 temparr[i] = rmatrix[planes[i][0]][2]+rmatrix[planes[i][1]][2]+rmatrix[planes[i][2]][2];
677 for (j = 1; j < nofelements; j++) {
679 key = temparr[j];
680 k = zorder[j];
681 i = j - 1;
683 while ((i > -1) && (temparr[i] > key)) {
684 temparr[i+1] = temparr[i];
685 zorder[i+1] = zorder[i--];
688 zorder[i+1] = k;
689 temparr[i+1] = key;
693 int normal(float p1[], float p2[], float p3[])
695 return ((p1[0]-p3[0])*(p2[1]-p3[1])-(p2[0]-p3[0])*(p1[1]-p3[1]));
698 int luminate(float p1[], float p2[], float p3[])
700 double x1 = (float)(p1[0]-p3[0]), y1 = (float)(p1[1]-p3[1]), z1 = (float)(p1[2]-p3[2]);
701 double x2 = (float)(p2[0]-p3[0]), y2 = (float)(p2[1]-p3[1]), z2 = (float)(p2[2]-p3[2]);
702 double nx = y1*z2-y2*z1, ny =-(x1*z2-x2*z1),nz = x1*y2-y1*x2;
704 return (int)(53 * (acost[(int)(50 + 50*(nx*lum_vector[0]+ny*lum_vector[1]+nz*lum_vector[2])/
705 (sqrt(nx*nx+ny*ny+nz*nz)*
706 sqrt(lum_vector[0]*lum_vector[0]+lum_vector[1]*lum_vector[1]+
707 lum_vector[2]*lum_vector[2])))] / PI));
709 // Do I smell optimization? :-)
712 void setUpAngles()
714 int i;
715 for (i = 0; i < 361; i++) {
716 cost[i] = cos((double)i*(2*PI/(double)360));
717 sint[i] = sin((double)i*(2*PI/(double)360));
720 for (i = 0; i < 100; i++) acost[i] = acos((double)(-50+i)/50);
723 void setupobj(char *filename)
725 int i, j = 0;
726 int biggest = 0;
727 float scale = 1;
729 xcenter = 16;
730 ycenter = 15 - 2*show_load;
732 if (strcmp(filename,"") != 0)
733 loadobj(filename);
734 else
736 nofcoords = 8;
737 noflines = 24;
738 nofplanes = 12;
739 planesORlines = 1;
741 matrix = (float **)malloc(nofcoords*sizeof(float *)); mem_alloc_error(matrix);
742 planes = (int **)malloc(nofplanes*sizeof(int *)); mem_alloc_error(planes);
743 plane_color = (int *)malloc(nofplanes*sizeof(int)); mem_alloc_error(plane_color);
744 zorder = (int *)malloc(nofplanes*sizeof(int)); mem_alloc_error(zorder);
746 for (i = 0; i < nofplanes; i++) zorder[i] = i;
748 for (i = 0; i < nofcoords; i++) {
749 matrix[i] = (float *)malloc(3*sizeof(float));
750 mem_alloc_error(matrix[i]);
753 for (i = 0; i < nofplanes; i++) {
754 planes[i] = (int *)malloc(3*sizeof(int));
755 mem_alloc_error(planes[i]);
758 cline = (int *)malloc((noflines+1)*sizeof(int)); mem_alloc_error(cline);
760 matrix[0][0] = -180; matrix[0][1] = -180; matrix[0][2] = 180; // 0
761 matrix[1][0] = 180; matrix[1][1] = -180; matrix[1][2] = 180; // 1
762 matrix[2][0] = 180; matrix[2][1] = 180; matrix[2][2] = 180; // 2
763 matrix[3][0] = -180; matrix[3][1] = 180; matrix[3][2] = 180; // 3
764 matrix[4][0] = -180; matrix[4][1] = -180; matrix[4][2] = -180; // 4
765 matrix[5][0] = 180; matrix[5][1] = -180; matrix[5][2] = -180; // 5
766 matrix[6][0] = 180; matrix[6][1] = 180; matrix[6][2] = -180; // 6
767 matrix[7][0] = -180; matrix[7][1] = 180; matrix[7][2] = -180; // 7
769 cline[0] = 1; cline[1] = 2;
770 cline[2] = 2; cline[3] = 3;
771 cline[4] = 3; cline[5] = 4;
772 cline[6] = 4; cline[7] = 1;
773 cline[8] = 5; cline[9] = 6;
774 cline[10] = 6; cline[11] = 7;
775 cline[12] = 7; cline[13] = 8;
776 cline[14] = 8; cline[15] = 5;
777 cline[16] = 1; cline[17] = 5;
778 cline[18] = 2; cline[19] = 6;
779 cline[20] = 3; cline[21] = 7;
780 cline[22] = 4; cline[23] = 8;
782 planes[0][0] = 0; planes[0][1] = 1; planes[0][2] = 3;
783 planes[1][0] = 1; planes[1][1] = 2; planes[1][2] = 3;
784 planes[2][0] = 1; planes[2][1] = 5; planes[2][2] = 6;
785 planes[3][0] = 1; planes[3][1] = 6; planes[3][2] = 2;
787 planes[4][0] = 4; planes[4][1] = 0; planes[4][2] = 3;
788 planes[5][0] = 4; planes[5][1] = 3; planes[5][2] = 7;
789 planes[6][0] = 3; planes[6][1] = 2; planes[6][2] = 7;
790 planes[7][0] = 7; planes[7][1] = 2; planes[7][2] = 6;
792 planes[8][0] = 4; planes[8][1] = 1; planes[8][2] = 0;
793 planes[9][0] = 4; planes[9][1] = 5; planes[9][2] = 1;
794 planes[10][0] = 5; planes[10][1] = 4; planes[10][2] = 7;
795 planes[11][0] = 5; planes[11][1] = 7; planes[11][2] = 6;
798 rmatrix = (float **)realloc(rmatrix,nofcoords*sizeof(float *)); mem_alloc_error(rmatrix);
799 for (i = 0; i < nofcoords; i++) {
800 rmatrix[i] = (float *)malloc(3*sizeof(float));
801 mem_alloc_error(rmatrix[i]);
805 * Find the longest discance between all coordinates relative to the origin
808 for (i = 0; i < nofcoords; i++) {
809 j = (int)sqrt((pow(matrix[i][0],2)+pow(matrix[i][1],2)+pow(matrix[i][2],2)));
810 if (j > biggest) biggest = j;
814 * Scale every coordinate using the calculated factor
817 scale = 280 / (float)biggest;
819 for (i = 0; i < nofcoords; i++) {
820 matrix[i][0] *= scale;
821 matrix[i][1] *= scale;
822 matrix[i][2] *= scale;
829 //**** Application Management, I/O etc. ***********
830 //*************************************************
832 void print_help() {
833 printf("\nwmCube %s (%s)\n\n", WMCUBE_VERSION, REV_DATE);
835 #ifndef SOLARIS
836 printf(" -o <filename or directory>: load external 3d-object(s).\n\n");
837 #else
838 printf(" -o <filename>: load external 3d-object.\n\n");
839 #endif
841 printf(" -d x: rotate x degrees/step when the cpu is idle. (default 1)\n");
842 printf(" -r x: rotate 1 degree faster every x percent of cpu-usage. (default 25)\n");
844 #ifdef LINUX
845 printf(" -c x: which cpu (0,1,2..) to monitor. (default average over all)\n");
846 printf(" -n : exclude \"nice\" processes. (default OFF)\n");
847 #endif
849 #ifdef SOLARIS
850 printf(" -c x: which cpu (0,1,2..) to monitor. (default average over all)\n");
851 #endif
853 #ifdef FREEBSD
854 printf(" -n : exclude \"nice\" processes. (default OFF)\n");
855 #endif
857 #ifdef NETBSD
858 printf(" -n : exclude \"nice\" processes. (default OFF)\n");
859 #endif
861 printf(" -b : draw the cube in a brighter color. (default OFF)\n");
862 printf(" -i : invert cube speed. (default OFF)\n");
863 printf(" -p : do not display cpu-load (default OFF)\n");
864 printf(" -h : display this helptext.\n\n");
867 void die()
869 fprintf(stderr, "%s: exiting", pname);
870 exit (1);
873 #ifndef SOLARIS // scan4objects doesnt work on Solaris because of alphasort
874 int scan4objects(char *dir)
876 struct dirent **names;
877 int n;
879 n = scandir(dir,&names,0,alphasort);
881 while (n-- > 0)
882 if (strstr(names[n]->d_name,".wmc") != NULL)
884 objects[nof_objects] = (char *)malloc(strlen(dir)+strlen(names[n]->d_name)+2);
885 strcpy(objects[nof_objects],dir);
886 if (dir[strlen(dir)] != '/') strcat(objects[nof_objects],"/");
887 strcat(objects[nof_objects++],names[n]->d_name);
890 return nof_objects;
892 #endif
894 int next_object()
896 if (nof_objects == 0) return -1;
897 setupobj(objects[rand() % (nof_objects )]);
899 return 0;
903 int loadobj(char *filename) {
905 FILE *fp;
906 char tmp[64] = {""};
907 int i = 0, counter = 1;
909 //printf("\nLoading file %s...",filename); fflush(stdout);
911 if ((fp = fopen(filename,"rt")) == NULL) {
912 printf("\nERROR: wmCube object-file not found (%s).\n\n",filename);
913 exit(0);
916 fscanf(fp,"%s",tmp);
918 if (strcmp(tmp,"WMCUBE_COORDINATES") != 0) {
919 printf("\nError in objectfile: it must start with WMCUBE_COORDINATES\n\n");
920 fclose(fp);
921 exit(0);
924 fscanf(fp,"%s",tmp);
925 counter = atoi(tmp);
927 while ((strcmp(tmp,"WMCUBE_LINES") != 0) && (strcmp(tmp,"WMCUBE_PLANES") != 0)) {
929 matrix = (float **)realloc(matrix,(i+1)*sizeof(float *)); mem_alloc_error(matrix);
930 matrix[i] = (float *)malloc(3*sizeof(float)); mem_alloc_error(matrix[i]);
931 fscanf(fp,"%f %f %f",&matrix[i][0],&matrix[i][1],&matrix[i][2]);
932 //printf("\n%d: %f %f %f",atoi(tmp), matrix[i][0],matrix[i][1],matrix[i][2]);
934 if (atoi(tmp) != (++i)) {
936 printf("\nError in objectfile (WMCUBE_COORDINATES section):\n"
937 "the coordinates must be listed in order 1..n\n\n");
938 fclose(fp);
939 exit(0);
941 fscanf(fp,"%s",tmp);
943 if (feof(fp)) {
944 printf("\nError in objectfile: you must have a section WMCUBE_LINES or WMCUBE_PLANES\n\n");
945 fclose(fp);
946 exit(0);
950 nofcoords = i;
951 i = 0;
953 if (strcmp(tmp,"WMCUBE_LINES") == 0) {
955 planesORlines = 0;
956 while (1) {
958 cline = (int *)realloc(cline,(i+2)*sizeof(int)); mem_alloc_error(cline);
959 fscanf(fp,"%d %d",&cline[i++],&cline[i++]);
960 //printf("\n%d %d",cline[i-2],cline[i-1]);
961 if (feof(fp)) break;
963 if (cline[i-2] > nofcoords || cline[i-1] > nofcoords) {
964 printf("\nError in objectfile (WMCUBE_LINES section):\n"
965 "coordinates %d or/and %d doesnt exist\n\n",cline[i-2],cline[i-1]);
966 fclose(fp);
967 exit(0);
970 noflines = i-2;
972 else if (strcmp(tmp,"WMCUBE_PLANES") == 0) {
974 planesORlines = 1;
975 while (1) {
976 planes = (int **)realloc(planes,(i+1)*sizeof(int *)); mem_alloc_error(planes);
977 planes[i] = (int *)malloc(3*sizeof(int)); mem_alloc_error(planes[i]);
978 fscanf(fp,"%d %d %d",&planes[i][0],&planes[i][1],&planes[i][2]);
979 //printf("\n%d: %d %d %d",i,planes[i][0],planes[i][1],planes[i][2]);
981 planes[i][0]--; planes[i][1]--; planes[i][2]--;
982 //printf("\n%d: %d %d %d\n",i,planes[i][0],planes[i][1],planes[i][2]);
984 if (feof(fp)) break;
986 if (planes[i][0] > nofcoords || planes[i][1] > nofcoords || planes[i][2] > nofcoords) {
987 printf("\nError in objectfile (WMCUBE_PLANES section):\n"
988 "coordinates %d or/and %d or/and %d doesnt exist\n\n",planes[i][0],planes[i][1],planes[i][2]);
989 fclose(fp);
990 exit(0);
992 i++;
994 nofplanes = i;
995 plane_color = (int *)malloc(nofplanes*sizeof(int)); mem_alloc_error(plane_color);
996 zorder = (int *)malloc(nofplanes*sizeof(int)); mem_alloc_error(zorder);
997 for (i = 0; i < nofplanes; i++) zorder[i] = i;
999 } else {
1000 printf("\nError in objectfile: you must have a section WMCUBE_LINES or WMCUBE_PLANES\n\n");
1001 fclose(fp);
1002 exit(0);
1005 fclose(fp);
1006 return 1;
1009 void mem_alloc_error(void *block) {
1010 if (block == NULL) {
1011 printf("\nError allocating memory!\n\n");
1012 exit(0);
1017 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1018 * Begin System Specific Code. If you wish to port wmcube to a new platform,
1019 * you'll need to implement the following operations:
1021 * int init_calc_cpu();
1022 * Perform feature tests to determine whether wmcube can run, and set up
1023 * any files/data structures/etc. to gather statistics.
1025 * int calc_cpu_total();
1026 * return an integer reflecting the current CPU load
1029 #if defined LINUX
1032 * init_calc_cpu doesn't have much to do on Linux, but it can check to see if
1033 * /proc/stat is available; if the user selected to monitor a particular CPU,
1034 * it can check it's existence.
1036 int init_calc_cpu()
1038 FILE *fp;
1039 int i;
1040 char cpuid[6];
1041 char check_cpu[6];
1043 sprintf(check_cpu, "cpu%d", which_cpu);
1045 if ((fp = fopen("/proc/stat","rb")) == NULL) {
1046 perror("/proc/stat required for this system");
1047 return -1;
1050 if (which_cpu == -1)
1051 return 0;
1053 for (i = -2; i < which_cpu; i++) {
1054 fscanf(fp, "%s", cpuid);
1057 if (strcmp(check_cpu,cpuid) != 0) {
1058 fprintf(stderr, "ERROR: could not read cpu-load on %s. Are you "
1059 "sure you have an SMP system?\n",check_cpu);
1060 return -1;
1062 return (0);
1065 int calc_cpu_total() {
1066 int total, used, t=0, i;
1067 static int previous_total = 0, previous_used = 0;
1068 char cpuid[6];
1069 int cpu,nice,system,idle;
1070 FILE *fp;
1072 fp = fopen("/proc/stat","rt");
1074 for (i = -2; i < which_cpu; i++) {
1075 fscanf(fp,"%s %d %d %d %d",cpuid,&cpu,&nice,&system,&idle);
1078 fclose(fp);
1080 used = cpu + system + use_nice*nice;
1081 total = used + idle + (1-use_nice)*nice;
1083 t = 100 * (double)(used - previous_used) / (double)(total - previous_total);
1084 previous_total = total;
1085 previous_used = used;
1087 return t;
1090 #elif defined SOLARIS
1091 #include <sys/types.h>
1092 #include <sys/sysinfo.h>
1093 #include <kstat.h>
1095 static kstat_ctl_t *kc;
1096 static kstat_t **cpu_ksp_list;
1097 static kstat_t *the_cpu;
1098 static int ncpus;
1101 * The biggest subtlety of the Solaris port is that init_calc_cpu can be called
1102 * after the initial program setup. This occurs when a 'kstat state change'
1103 * occurs. Usually this means that a CPU has been taken on or off-line using
1104 * the psradm command. Another possibility is that on server systems, a new
1105 * CPU might have been hot-added to a running system.
1107 * As a result, init_calc_cpu frees any resources it might have setup if needed,
1108 * and reinitializes everything.
1110 int init_calc_cpu()
1112 kstat_t *ksp;
1113 int i = 0;
1115 if (kc == NULL) {
1116 if ((kc = kstat_open()) == NULL) {
1117 fprintf(stderr, "wmcube: can't open /dev/kstat\n");
1118 return -1;
1122 if (which_cpu != -1) {
1124 * User selected to monitor a particlur CPU. find it...
1126 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1127 if ((strcmp(ksp->ks_module, "cpu_stat") == 0) &&
1128 (ksp->ks_instance == which_cpu)) {
1129 the_cpu = ksp;
1130 break;
1133 if (the_cpu == NULL) {
1134 fprintf(stderr, "CPU %d not found\n", which_cpu);
1135 return -1;
1137 } else {
1139 * User selected to monitor all CPUs. First, count them.
1141 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1142 if (strcmp(ksp->ks_module, "cpu_stat") == 0)
1143 i++;
1146 if (cpu_ksp_list) {
1147 free(cpu_ksp_list);
1149 cpu_ksp_list = (kstat_t **) calloc(i * sizeof (kstat_t *), 1);
1150 ncpus = i;
1153 * stash the ksp for each CPU.
1155 i = 0;
1156 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1157 if (strcmp(ksp->ks_module, "cpu_stat") == 0) {
1158 cpu_ksp_list[i] = ksp;
1159 i++;
1163 return 0;
1166 int calc_cpu_total()
1168 int i;
1169 cpu_stat_t stat;
1170 static int previous_total = 0, previous_used = 0;
1171 int used, total, t, user = 0, wait = 0, kern = 0, idle = 0;
1174 * Read each cpu's data. If the kstat chain has changed (a state change
1175 * has happened, maybe a new cpu was added to the system or one went
1176 * away), then reinitialize everything with init_calc_cpu(). Finally,
1177 * recursively call calc_cpu_total.
1179 * We'll need to do a little better than this in the future, since we
1180 * could recurse too much in the pathological case here.
1182 if (which_cpu == -1) {
1183 for (i = 0; i < ncpus; i++) {
1184 if (kstat_read(kc, cpu_ksp_list[i],
1185 (void *)&stat) == -1) {
1186 if (init_calc_cpu() != 0) {
1187 fprintf(stderr, "failed to "
1188 "reinitialize following state "
1189 "change\n");
1190 return (-1);
1192 return (calc_cpu_total());
1194 user += stat.cpu_sysinfo.cpu[CPU_USER]; /* user */
1195 wait += stat.cpu_sysinfo.cpu[CPU_WAIT]; /* io wait */
1196 kern += stat.cpu_sysinfo.cpu[CPU_KERNEL]; /* sys */
1197 idle += stat.cpu_sysinfo.cpu[CPU_IDLE]; /*idle("free")*/
1199 } else {
1200 if (kstat_read(kc, the_cpu, (void *)&stat) == -1) {
1201 if (init_calc_cpu() != 0) {
1202 fprintf(stderr, "failed to reinitialize "
1203 "following state change\n");
1204 return (-1);
1206 return (calc_cpu_total());
1208 user += stat.cpu_sysinfo.cpu[CPU_USER]; /* user */
1209 wait += stat.cpu_sysinfo.cpu[CPU_WAIT]; /* io wait */
1210 kern += stat.cpu_sysinfo.cpu[CPU_KERNEL]; /* sys */
1211 idle += stat.cpu_sysinfo.cpu[CPU_IDLE]; /* idle("free") */
1214 used = user + wait + kern;
1215 total = used + idle;
1216 t = 100 * (double)(used - previous_used) /
1217 (double)(total - previous_total);
1218 previous_total = total;
1219 previous_used = used;
1220 return (t);
1223 #elif defined FREEBSD
1224 #include <nlist.h>
1225 #include <fcntl.h>
1226 #include <sys/dkstat.h>
1228 int init_calc_cpu()
1231 if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
1233 printf("\nError: unable to open kvm\n\n");
1234 exit(0);
1236 kvm_nlist(kd, nlst);
1237 if (nlst[0].n_type == 0)
1239 printf("\nError: unable to get nlist\n\n");
1240 exit(1);
1243 return 0;
1246 int calc_cpu_total() {
1247 int total, used, t=0;
1248 static int previous_total = 0, previous_used = 0;
1249 int cpu,nice,system,idle;
1250 unsigned long int cpu_time[CPUSTATES];
1252 if (kvm_read(kd, nlst[0].n_value, &cpu_time, sizeof(cpu_time))
1253 != sizeof(cpu_time))
1255 printf("\nError reading kvm\n\n");
1256 exit(0);
1259 cpu = cpu_time[CP_USER];
1260 nice = cpu_time[CP_NICE];
1261 system = cpu_time[CP_SYS];
1262 idle = cpu_time[CP_IDLE];
1264 used = cpu + system + use_nice*nice;
1265 total = used + idle + (1-use_nice)*nice;
1267 t = 100 * (double)(used - previous_used) / (double)(total - previous_total);
1268 previous_total = total;
1269 previous_used = used;
1271 return t;
1274 #elif defined OPENBSD
1276 int init_calc_cpu()
1278 return 0;
1281 int calc_cpu_total() {
1282 double avenrun[3];
1284 (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
1285 return(((5.0*avenrun[0] + 0.5) > 50) ? 50 : (5.0*avenrun[0] + 0.5))*2;
1289 #elif defined NETBSD /* END OPENBSD */
1290 #include <sys/sched.h>
1291 #include <sys/sysctl.h>
1293 int init_calc_cpu ()
1295 return 0;
1298 int calc_cpu_total ()
1300 static u_int64_t last_cp_time[CPUSTATES] = { 0, 0, 0, 0, 0 };
1301 u_int64_t curr_cp_time[CPUSTATES];
1302 u_int64_t total_time = 0, idle_time = 0;
1303 int mib[2];
1304 int i;
1305 size_t ssize;
1306 const int IDLE_TIME = 4;
1307 const int NICE_TIME = 1;
1309 ssize = sizeof ( curr_cp_time );
1310 mib[0] = CTL_KERN;
1311 mib[1] = KERN_CP_TIME;
1312 if ( sysctl ( mib, 2, curr_cp_time, &ssize, NULL, 0 ) ) {
1313 fprintf ( stderr, "wmcube: unable to read CP_TIME from sysctl()\n" );
1314 exit ( 0 );
1316 if ( !use_nice )
1317 curr_cp_time[NICE_TIME] = 0;
1319 /* NetBSD gives 5 CPUSTATES -
1320 * User, Nice, System, Interrupt, Idle
1322 idle_time = curr_cp_time[IDLE_TIME] - last_cp_time[IDLE_TIME];
1323 for ( i = 0; i < CPUSTATES; i++ ) {
1324 total_time += ( curr_cp_time[i] - last_cp_time[i] );
1325 last_cp_time[i] = curr_cp_time[i];
1328 /* Calculate the % CPU usage as the User+Nice+System+Interrupt/Total
1329 * for the interval
1331 return ( 100 * (int) ( total_time - idle_time ) / total_time );
1335 #else /* END NETBSD */
1338 * This is a stub which will compile for platforms other than LINUX or SOLARIS.
1339 * Use these to start your port to a new platform.
1341 int init_calc_cpu()
1343 return 0;
1346 int calc_cpu_total()
1348 return 0;
1351 #endif /* OS SPECIFIC CODE */