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