1 //
2 //  Copyright (C) 2002 Brad Wasson <bard@systemtoolbox.com>
3 //
4 //  This file is part of 3ddesktop.
5 //
6 //  3ddesktop is free software; you can redistribute it and/or modify it
7 //  under the terms of the GNU General Public License as published by
8 //  the Free Software Foundation; either version 2, or (at your option)
9 //  any later version.
10 //
11 //  3ddesktop is distributed in the hope that it will be useful, but
12 //  WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with 3ddesktop; see the file COPYING.   If not, write to
18 //  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19 //
20 //  ------
21 //  This file is where I dump all the misc functions I don't know what
22 //  else to do with...
23 //
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/time.h>  // for gettimeofday
30 #include <time.h>
31 #include <fcntl.h>
32 #include <sys/ipc.h>
33 #include <sys/sem.h>
34 #include <sys/shm.h>
35 #include <stdarg.h>
36 #include <syslog.h>
37 
38 #ifndef _GNU_SOURCE
39 #define _GNU_SOURCE
40 #endif
41 #include <unistd.h>
42 #include <dirent.h>
43 
44 //#include <GL/glut.h> // GLUT support library.
45 
46 #include "util.h"
47 #include "config.hpp"
48 #include "message.hpp"
49 
50 extern Config *cfg;
51 
52 
msgout(int level,char * msg,...)53 void msgout (int level, char *msg, ...)
54 {
55     va_list ap;
56 
57     // FIXME: change if threads are added
58     static char buff[4096];
59     static FILE *logfp = stdout;
60 
61     if (level == DEBUG && !cfg->verbose)
62         return;
63 
64     if (cfg->options->daemonized) {
65         // only log to syslog
66         va_start (ap, msg);
67         vsnprintf (buff, 4096, msg, ap);
68         va_end (ap);
69 
70         syslog (LOG_ERR, buff);
71     } else {
72         // not daemonized meaning verbose is on (debugging)
73         va_start(ap, msg);
74         vfprintf (logfp, msg, ap);
75         va_end(ap);
76 
77         fflush(logfp);
78     }
79 }
80 
81 
82 void
convert_imlib_image_to_opengl_data(int texture_size,Imlib_Image imlib_img,unsigned char * out_buff)83 convert_imlib_image_to_opengl_data(int texture_size, Imlib_Image imlib_img, unsigned char *out_buff)
84 {
85     imlib_context_set_image(imlib_img);
86     Imlib_Image imgfinal = imlib_create_cropped_scaled_image(0, 0,
87                                             imlib_image_get_width(),
88                                             imlib_image_get_height(),
89                                             texture_size,
90                                             texture_size);
91 
92     imlib_context_set_image(imgfinal);
93     unsigned int *tmp = imlib_image_get_data();
94 
95     int w, h;
96     int x, y;
97     int offset;
98     int img_offset;
99 
100     w = h = texture_size;
101 
102     for (y = 0; y < h; y++) {
103         for (x = 0; x < w; x++) {
104             offset = (y * w + x) * 4;
105             img_offset = (y * w + x);
106 
107             out_buff[offset]     = (tmp[img_offset] >> 16) & 0xff;
108             out_buff[offset + 1] = (tmp[img_offset] >> 8) & 0xff;
109             out_buff[offset + 2] =  tmp[img_offset] & 0xff;
110             out_buff[offset + 3] = (tmp[img_offset] >> 24) & 0xff;
111         }
112     }
113     imlib_image_put_back_data(tmp);
114     imlib_free_image();
115 }
116 
117 
118 // quick and dirty bitmap loader...for 24 bit bitmaps with 1 plane only.
119 // See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/BMP.txt for more info.
load_image(char * filename,unsigned char * data,unsigned int * sizex,unsigned int * sizey,int add_alpha)120 int load_image(char *filename,
121                unsigned char *data,
122                unsigned int *sizex,
123                unsigned int *sizey,
124                int add_alpha)
125 {
126     FILE *file;
127     unsigned long size;                 // size of the image in bytes.
128     unsigned long i;                    // standard counter.
129     unsigned short int planes;          // number of planes in image (must be 1)
130     unsigned short int bpp;             // number of bits per pixel (must be 24)
131     unsigned int j;
132     unsigned int byte_multiplier = 3;
133 
134     unsigned char *working_buff = NULL;
135 
136     unsigned int size_x, size_y;
137 
138     // make sure the file is there.
139     if ((file = fopen(filename, "rb"))==NULL)
140     {
141         // don't print anything because we may be opening digit files
142         // or something that we don't care if they aren't there
143 
144 	//msgout(ERROR,"Could not open %s: %s\n",filename, strerror(errno));
145 	return 0;
146     }
147 
148     // seek through the bmp header, up to the width/height:
149     fseek(file, 18, SEEK_CUR);
150 
151     // read the width
152     if ((i = fread(&size_x, 4, 1, file)) != 1) {
153 	msgout(ERROR,"Error reading width from %s.\n", filename);
154 	return 0;
155     }
156 
157     // expected size is passed it - fail if its not as expected
158     if (size_x != *sizex) {
159         msgout(DEBUG,"Error: width of %s is %u not %u\n", filename, size_x, *sizex);
160         return 0;
161     }
162     *sizex = bswap_32(size_x);
163 
164     // read the height
165     if ((i = fread(&size_y, 4, 1, file)) != 1) {
166 	msgout(ERROR,"Error reading height from %s.\n", filename);
167 	return 0;
168     }
169 
170     // expected size is passed in - fail if its not as expected
171     if (size_y != *sizey) {
172         msgout(DEBUG,"Error: height of %s is %u not %u\n", filename, size_y, *sizey);
173         return 0;
174     }
175     *sizey = bswap_32(size_y);
176 
177     // read the planes
178     if ((fread(&planes, 2, 1, file)) != 1) {
179 	msgout(ERROR,"Error reading planes from %s.\n", filename);
180 	return 0;
181     }
182     planes = bswap_16(planes);
183 
184     if (planes != 1) {
185 	msgout(ERROR,"Planes from %s is not 1: %u\n", filename, planes);
186 	return 0;
187     }
188 
189     // read the bpp
190     if ((i = fread(&bpp, 2, 1, file)) != 1) {
191 	msgout(ERROR,"Error reading bpp from %s.\n", filename);
192 	return 0;
193     }
194     bpp = bswap_16(bpp);
195 
196     //msgout(DEBUG,"BPP from %s is %u\n", filename, bpp);
197 
198 
199     // 32 bits per pix is same as 24 (8 bits per color) except the
200     // last 8 bits are used for other stuff
201     if ( ! (bpp == 24 || bpp == 32)  ) {
202         msgout(ERROR,"Bpp from %s is not 24 or 32: %u\n", filename, bpp);
203         return 0;
204     }
205 
206     if (bpp == 24)
207         byte_multiplier = 3;
208     else if (bpp == 32)
209         byte_multiplier = 4;
210 
211     // calculate the size
212     size = (*sizex) * (*sizey) * byte_multiplier;
213 
214     // seek past the rest of the bitmap header.
215     fseek(file, 24, SEEK_CUR);
216 
217 
218     // allocate buff
219     working_buff = new unsigned char[(*sizex) * (*sizey) * 4];
220     if (working_buff == NULL) {
221         msgout(ERROR,"Out of memory\n");
222         exit (1);
223     }
224 
225 
226     if ((i = fread(working_buff, size, 1, file)) != 1) {
227 	msgout(ERROR,"Error reading image data from %s.\n", filename);
228 	return 0;
229     }
230 
231     // if the bpp is 32 we need to "squeeze" it down to 24bpp so j is
232     // the index at 24bpp
233     j = 0; //(*sizex) * (*sizey) * 3;
234 
235     int x,y;
236 
237     for (y = (*sizey) - 1; y >= 0; y--) {
238 
239         //for (x = (*sizex) - 1; x >= 0; x--) {
240         for (x = 0; x < (int)(*sizex); x++) {
241 
242             int offset = (y * (*sizey) + x) * byte_multiplier;
243 
244             //for (i = 0; i < size; i += byte_multiplier) {
245 
246             // reverse all of the colors. (bgr -> rgb)
247             data[j] = working_buff[offset + 2];
248             data[j + 1] = working_buff[offset + 1];
249             data[j + 2] = working_buff[offset];
250 
251             if (add_alpha)
252                 if (data[j] == 0 && data[j + 1] == 0 && data[j + 2] == 0)
253                     data[j + 3] = 0;  // black make transparent...
254                 else
255                     data[j + 3] = 1;
256 
257             j += add_alpha ? 4 : 3;
258         }
259     }
260 
261     delete working_buff;
262 
263     // we're done.
264     return 1;
265 }
266 
267 
clamp_degrees(float * value)268 void clamp_degrees (float *value)
269 {
270     //msgout (DEBUG,"clamp IN %f\n", *value);
271     while (*value > 360.0)
272         *value -= 360.0;
273     while (*value < -360.0)
274         *value += 360.0;
275     //msgout(DEBUG,"clamp OUT %f\n", *value);
276 }
277 
278 
get_randomf(double low,double high)279 double get_randomf (double low, double high)
280 {
281     return (low + ((high - low) * rand() / (RAND_MAX+1.0)));
282 }
283 
get_randomi(int low,int high)284 int get_randomi (int low, int high)
285 {
286     return ( (int)((double)low + ((double)(high-low+1) * rand() / (RAND_MAX+1.0))) );
287 }
288 
289 
context_switch(void)290 void context_switch(void)
291 {
292     struct timeval tm;
293 
294     // is there a better way to do this?
295     // sleep(0) doesn't seem to work
296 
297     tm.tv_sec = 0;
298     tm.tv_usec = 100;
299 
300     select (0, 0, 0, 0, &tm); /* sleep */
301 }
302 
get_milli_time(void)303 long get_milli_time (void)
304 {
305     struct timeval tv;
306     gettimeofday(&tv, NULL);
307     return ((tv.tv_sec * 1000) + (long)(tv.tv_usec / 1000.0));
308 } // END get_milli_time
309 
310 
sleep_ms(int ms)311 void sleep_ms (int ms )
312 {
313     struct timeval tm;
314 
315     tm.tv_sec = (time_t)floor(ms / 1000);
316     tm.tv_usec = (ms - (tm.tv_sec * 1000)) * 1000;
317 
318     select (0, 0, 0, 0, &tm); /* sleep */
319 }
320 
321 #if 0
322 
323 // uses a glut routine
324 void
325 ourPrintString(void *font, char *str)
326 {
327     int i,l=strlen(str);
328 
329     for(i=0;i<l;i++)
330         glutBitmapCharacter(font,*str++);
331 } // END ourPrintString
332 
333 #endif // if 0
334 
335 
336 #ifdef FILE_METHOD
337 static char running_file[200] = { 0, };
338 #endif
339 
check_if_i_am_running(void)340 int check_if_i_am_running(void)
341 {
342     // I like using a semaphore for this purpose because it will
343     // automatically be decremented for us when we exit - regardless
344     // of how the process was killed plus I have knowledge about this
345     // sys V crap ;)
346 
347     // btw can't use POSIX sem_init etc here because linux doesn't do
348     // inter-process apparently... :(   (whats the use?)
349 
350     union semun {
351         int val;                    /* value for SETVAL */
352         struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
353         unsigned short int *array;  /* array for GETALL, SETALL */
354         struct seminfo *__buf;      /* buffer for IPC_INFO */
355     } semstat;
356 
357     int rc;
358     key_t key = 0;
359     int semid = 0;
360 
361     key = ftok("/bin/sh", 99);
362     if (key < 0) {
363         msgout(ERROR,"ftok failed: %d: %s\n", errno, strerror(errno));
364         return 1;
365     }
366 
367     semid = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL );
368     if (semid < 0) {
369         // if the semaphore exists read it and if its non-zero fail
370         if (errno == EEXIST) {
371             //msgout (DEBUG,"EXISTS!\n");
372 
373             semid = semget(key, 1, 0666);
374             if (semid < 0) {
375                 msgout(ERROR,"semget (2) failed: %d: %s\n",
376                         errno, strerror(errno));
377                 return 1;
378             }
379 
380             if ( (rc = semctl (semid, 0, GETVAL, semstat )) < 0 )
381             {
382                 msgout (ERROR, "semctl GETVAL zero failed: %d: %s\n",
383                         errno, strerror(errno));
384                 return 1;
385             }
386             //msgout (DEBUG, "sem value == %d\n", rc);
387 
388             return (rc != 0);
389 
390         } else {
391             // semget failed for some weird reason
392             msgout(ERROR, "semget failed: %d: %s\n", errno, strerror(errno));
393             return 1;
394         }
395     } else {
396         //msgout (DEBUG, "CREATED!\n");
397 
398         // we must init to zero since there is no gaurantee of its
399         // initial value.  this is the fatal flaw of sysV ipc.
400         // Stevens provides an algorithm to make initialization
401         // safe (just initializing it is not technically safe) but
402         // this race is very unlikely (I hope!)
403         semstat.val = 0;
404         if ( semctl (semid, 0, SETVAL, semstat ) < 0 )
405         {
406             msgout (ERROR, "semctl SETVAL zero failed: %d: %s\n",
407                     errno, strerror(errno));
408             return 1;
409         }
410     }
411 
412     return 0;
413 }
414 
415 
flag_that_i_am_running(void)416 int flag_that_i_am_running(void)
417 {
418 
419     // I like using a semaphore for this purpose because it will
420     // automatically be decremented for us when we exit - regardless
421     // of how the process was killed plus I have knowledge about this
422     // sys V crap ;)
423 
424     // btw can't use POSIX sem_init etc here because linux doesn't do
425     // inter-process apparently... :(   (whats the use?)
426 
427     union semun {
428         int val;                    /* value for SETVAL */
429         struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
430         unsigned short int *array;  /* array for GETALL, SETALL */
431         struct seminfo *__buf;      /* buffer for IPC_INFO */
432     } semstat;
433 
434     int rc;
435     key_t key = 0;
436     int semid = 0;
437     struct sembuf chain_lock[2];
438 
439     key = ftok("/bin/sh", 99);
440     if (key < 0) {
441         msgout(ERROR,"ftok failed: %d: %s\n", errno, strerror(errno));
442         return 1;
443     }
444 
445 
446     semid = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL );
447     if (semid < 0) {
448         // if the semaphore exists read it and if its non-zero fail
449         if (errno == EEXIST) {
450             //msgout (DEBUG,"EXISTS!\n");
451 
452             semid = semget(key, 1, 0666);
453             if (semid < 0) {
454                 msgout(ERROR,"semget (2) failed: %d: %s\n",
455                         errno, strerror(errno));
456                 return 1;
457             }
458 
459         } else {
460             // semget failed for some weird reason
461             msgout(ERROR, "semget failed: %d: %s\n", errno, strerror(errno));
462             return 1;
463         }
464     } else {
465         // this should never happen since we created in
466         // check_if_i_am_running() above....
467 
468         //msgout (DEBUG, "CREATED!\n");
469 
470         // we must init to zero since there is no gaurantee of its
471         // initial value.  this is the fatal flaw of sysV ipc.
472         // Stevens provides an algorithm to make initialization
473         // safe (just initializing it is not technically safe) but
474         // this race is very unlikely (I hope!)
475         semstat.val = 0;
476         if ( semctl (semid, 0, SETVAL, semstat ) < 0 )
477         {
478             msgout (ERROR, "semctl SETVAL zero failed: %d: %s\n",
479                     errno, strerror(errno));
480             return 1;
481         }
482     }
483 
484 #if 0
485     if ( (rc = semctl (semid, 0, GETVAL, semstat )) < 0 )
486     {
487         msgout (ERROR, "semctl GETVAL zero failed: %d: %s\n",
488                 errno, strerror(errno));
489         return 1;
490     }
491     msgout (DEBUG, "sem value == %d\n", rc);
492 #endif
493 
494     // we either just created the semaphore or we got a handle to the
495     // existing one ... init it to 1 atomically and we're golden
496 
497     // check if its zero and if its zero increment to 1
498     // atomically - SEM_UNDO will reset when process dies
499     chain_lock[0].sem_num = 0;
500     chain_lock[0].sem_op  = 0;
501     chain_lock[0].sem_flg = IPC_NOWAIT;
502     chain_lock[1].sem_num = 0;
503     chain_lock[1].sem_op  = 1;
504     chain_lock[1].sem_flg = SEM_UNDO | IPC_NOWAIT;
505 
506     rc = semop(semid, &chain_lock[0], 2);
507     if ( rc < 0 ) {
508         if (errno == EAGAIN) {
509             // would block meaning the semaphore is non-zero
510             // so somebody else has it - return 1 :(
511             return 1;
512         } else {
513             msgout (ERROR, "semop failed: %d: %s\n", errno,
514                     strerror(errno));
515             return 1;
516         }
517     }
518 
519     // we successfully incremented to 1 - we're golden
520     return 0;
521 
522 #ifdef FILE_METHOD
523 
524     FILE *fp = NULL;
525     struct stat statbuf;
526 
527     sprintf(running_file, "%s/running", cfg->options->working_dir);
528 
529     if (stat(running_file, &statbuf) < 0) {
530         fp = fopen (running_file, "w");
531         if (fp == NULL) {
532             msgout (ERROR, "Could not create %s: %s\n", running_file, strerror(errno));
533             return 1;
534         }
535         fclose (fp);
536     } else {
537         // file exists so fail
538         return 1;
539     }
540 
541     return 0;
542 #endif
543 
544 }
545 
flag_that_i_am_NOT_running(void)546 int flag_that_i_am_NOT_running(void)
547 {
548 #ifdef FILE_METHOD
549     if (running_file[0] != 0)
550         // just delete the file
551         unlink (running_file);
552 #endif
553 
554     return 0;
555 }
556 
557 
558 
559 //-------------------------------------------------
560 //  Functions used by faceset.cpp
561 //-------------------------------------------------
562 
563 
564 
565 // calculates the points in an n-sided polygon
calculate_polypoints(int num,float side_len,polypoints_t * pp)566 void calculate_polypoints (int num, float side_len, polypoints_t *pp)
567 {
568     int i;
569     float side_angle = 360.0 / (float)num;
570 
571     float r = (side_len/2.0) / sin(deg_to_rad(side_angle/2.0));
572 
573     float theta = -side_angle/2.0 - 90.0;  // to start
574 
575     //msgout(DEBUG,"r = %lf, theta = %lf\n", r, theta);
576 
577     for (i = 0; i < num; i++) {
578         pp->x[i] = polar_to_x (r, theta);
579         pp->y[i] = polar_to_y (r, theta);
580 
581         theta += side_angle;
582     }
583 }
584 
585 
586 
translate(vertex_t v,float x,float y,float z)587 void translate (vertex_t v, float x, float y, float z)
588 {
589     v[0] += x;
590     v[1] += y;
591     v[2] += z;
592 }
593 
594 // multiply m times v and put result in v
multiply(matrix_t m,vertex_t v)595 static void multiply (matrix_t m, vertex_t v)
596 {
597     vertex_t r;
598     r[0] =  m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3];
599     r[1] =  m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3];
600     r[2] =  m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3];
601     r[3] =  m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3];
602     v[0] = r[0];
603     v[1] = r[1];
604     v[2] = r[2];
605     v[3] = r[3];
606 }
607 
608 
load_identity(matrix_t m)609 static void load_identity (matrix_t m)
610 {
611     memset(m, 0, sizeof(matrix_t));
612     m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0;
613 }
614 
615 
616 //      Rotation
617 
618 //         | 1      0        0   0 |
619 // Rx(A) = | 0  cos A   -sin A   0 |
620 //         | 0  sin A    cos A   0 |
621 //         | 0      0        0   1 |
622 
623 //         | cos A   0   sin A   0 |
624 // Ry(A) = |     0   1       0   0 |
625 //         | -sin A  0   cos A   0 |
626 //         |     0   0       0   1 |
627 
628 //         | cos A  -sin A   0   0 |
629 // Rz(A) = | sin A   cos A   0   0 |
630 //         |     0       0   1   0 |
631 //         |     0       0   0   1 |
632 
rotate_x(vertex_t v,float x)633 void rotate_x (vertex_t v, float x)
634 {
635     float xr = deg_to_rad(x);
636     float tmp;
637     matrix_t m;
638 
639     // x
640     load_identity (m);
641     tmp = cos(xr);
642     m[1][1] = tmp;
643     m[2][2] = tmp;
644     tmp = sin(xr);
645     m[1][2] = -tmp;
646     m[2][1] = tmp;
647 
648     multiply (m, v);
649 }
650 
rotate_y(vertex_t v,float y)651 void rotate_y (vertex_t v, float y)
652 {
653     float yr = deg_to_rad(y);
654     float tmp;
655     matrix_t m;
656 
657     // y
658     load_identity (m);
659     tmp = cos(yr);
660     m[0][0] = tmp;
661     m[2][2] = tmp;
662     tmp = sin(yr);
663     m[0][2] = tmp;
664     m[2][0] = -tmp;
665 
666 
667     multiply(m,v);
668 }
rotate_z(vertex_t v,float z)669 void rotate_z (vertex_t v, float z)
670 {
671     float zr = deg_to_rad(z);
672     float tmp;
673     matrix_t m;
674 
675     // z
676     load_identity (m);
677     tmp = cos(zr);
678     m[0][0] = tmp;
679     m[1][1] = tmp;
680     tmp = sin(zr);
681     m[0][1] = -tmp;
682     m[1][0] = tmp;
683 
684     multiply(m,v);
685 }
686 
687 
688 
daemon_init(void)689 int daemon_init (void)
690 {
691     pid_t pid;
692 
693     msgout (DEBUG, "daemon init\n");
694 
695     if ( (pid = fork()) < 0) {
696         msgout (ERROR, "daemon_init: fork failed: %s\n", strerror(errno));
697         return -1;
698     } else if (pid != 0) {
699         msgout (INFO, "Daemon started.  Run 3ddesk to activate.\n");
700         exit(0);  // bye parent
701     }
702 
703     // child continues
704 
705     setsid();
706 
707     chdir ("/");
708 
709     umask (0);
710 
711     return(0);
712 } // END daemon_init
713 
714 
715 
716 extern MessageManager msgmgr;
717 
718 
end_program(int rv)719 void end_program (int rv)
720 {
721     flag_that_i_am_NOT_running();
722 
723     if (cfg)
724         delete cfg;
725 
726     if (msgmgr.close() < 0)
727         msgout(ERROR, "Could not delete message queue: %s\n", strerror(errno));
728 
729     exit (rv);
730 }
731 
732 
733 
734