11218
|
1 #include <assert.h>
|
|
2 #include <GL/gl.h>
|
|
3 #include <GL/glu.h>
|
|
4 #include "cc_interface.h"
|
|
5 #include "crazychat.h"
|
|
6
|
|
7 #include "Utilities.h"
|
|
8 #include "QTUtilities.h"
|
|
9 #include "camdata.h"
|
|
10 #include "camproc.h"
|
|
11 #include "util.h"
|
|
12 #include <unistd.h>
|
|
13
|
|
14
|
|
15 #ifdef __APPLE_CC__
|
|
16 #include <Carbon/Carbon.h>
|
|
17 #else
|
|
18 #include <Carbon.h>
|
|
19 #endif
|
|
20
|
|
21 /* temporarily including for development testing */
|
|
22 #include "cc_gtk_gl.h"
|
|
23
|
|
24 /* hard coding the webcam dimensions: BAD, but we're not probing hardware yet */
|
|
25
|
|
26 #define WEBCAM_X 644 /* webcam's x dim */
|
|
27 #define WEBCAM_Y 480 /* webcam's y dim */
|
|
28
|
|
29 /* default webcam timer callback delay */
|
|
30 #define WEBCAM_CALLBACK_DELAY 40 /* in ms */
|
|
31
|
|
32 int x_click, y_click;
|
|
33 int mode_change=0;
|
|
34
|
|
35 struct input_instance input_data;
|
|
36
|
|
37 /* move this to input_instance eventually */
|
|
38 /*
|
|
39 UInt32 colorBuf[WEBCAM_Y][WEBCAM_X];
|
|
40 */
|
|
41 unsigned int (*colorBuf)[640];
|
|
42 int detection_mode=0;
|
|
43 int draw_mode=0; //0=pixels, 1=face
|
|
44 int easter_count;
|
|
45 static void *kickstart(void *data);
|
|
46 static void *facefind(void *data);
|
|
47
|
|
48 /**
|
|
49 * Resets the OpenGL viewport stuff on widget reconfiguration (resize,
|
|
50 * reposition)
|
|
51 * @param widget widget that got reconfigured
|
|
52 * @param event the configuration event
|
|
53 * @param data unused
|
|
54 * @return TRUE ( i don't know what FALSE would do )
|
|
55 */
|
|
56 static gboolean config_wrapper(GtkWidget *widget, GdkEventConfigure *event,
|
|
57 void *data);
|
|
58
|
|
59 /**
|
|
60 * Debug features test. Draws pixels directly to the frame buffer.
|
|
61 * @param widget widget that we're drawing
|
|
62 * @param event the draw event
|
|
63 * @param data array of pixels
|
|
64 * @return DUNNO
|
|
65 */
|
|
66 static gboolean mydraw(GtkWidget *widget, GdkEventExpose *event,
|
|
67 void *data);
|
|
68
|
|
69 /**
|
|
70 * Periodically querys the webcam for more data.
|
|
71 * @param instance webcam input instance data
|
|
72 * @return TRUE to stop other handler, FALSE to continue
|
|
73 */
|
|
74 static gboolean webcam_cb(struct input_instance *instance);
|
|
75
|
|
76 /**
|
|
77 * Init window code, adding our click callback.
|
|
78 * @param widget the window we clicked in
|
|
79 * @param instance webcam input instance data
|
|
80 */
|
|
81 static void init_cb(GtkWidget *widget, struct input_instance *instance);
|
|
82
|
|
83 /**
|
|
84 * Click callback
|
|
85 * @param widget the window we clicked in
|
|
86 * @param event the button click event structure
|
|
87 * @param instance input instance data
|
|
88 * @return TRUE to stop other handler, FALSE to continue
|
|
89 */
|
|
90 static gboolean click_cb(GtkWidget *widget, GdkEventButton *event,
|
|
91 struct input_instance *instance);
|
|
92
|
|
93 /**
|
|
94 * Button callback
|
|
95 * @param button the button we clicked on
|
|
96 * @param instance input instance data
|
|
97 */
|
|
98 static void button_cb(GtkWidget *button, struct input_instance *instance);
|
|
99
|
|
100 /**
|
|
101 * Destroy callback. Called when the input processing window is destroyed.
|
|
102 * @param widget the window we clicked in
|
|
103 * @param cc crazychat global data structure
|
|
104 */
|
|
105 static void destroy_cb(GtkWidget *widget, struct crazychat *cc);
|
|
106
|
|
107 /**
|
|
108 * Set feature material.
|
|
109 * @param entry model selector combo box entry
|
|
110 * @param material pointer to material we're setting
|
|
111 */
|
|
112 static void material_set(GtkWidget *entry, guint8 *material);
|
|
113
|
|
114 struct input_instance *init_input(struct crazychat *cc)
|
|
115 {
|
|
116
|
|
117 pthread_t userinput_t; // should we put this in a nicer wrapper?
|
|
118 struct draw_info *info;
|
|
119 struct input_instance *instance;
|
|
120 info = (struct draw_info*)malloc(sizeof(*info));
|
|
121 assert(info);
|
|
122 memset(info, 0, sizeof(*info));
|
|
123 info->timeout = TRUE;
|
|
124 info->delay_ms = DEFAULT_FRAME_DELAY;
|
|
125 info->data = &input_data;
|
|
126 instance = (struct input_instance*)info->data;
|
|
127 memset(instance, 0, sizeof(*instance));
|
|
128 instance->output.features = &instance->face;
|
|
129 EnterMovies();
|
|
130 filter_bank *bank;
|
|
131 bank = Filter_Initialize();
|
|
132 assert(CamProc(instance, bank) == noErr); // change this prototype-> no windows
|
|
133 instance->timer_id = g_timeout_add(WEBCAM_CALLBACK_DELAY,
|
|
134 (GSourceFunc)webcam_cb, instance);
|
|
135 // THREAD_CREATE(&userinput_t, facefind, instance); // is this being created correctly?
|
|
136 struct window_box ret;
|
|
137 cc_new_gl_window(init_cb, config_wrapper, mydraw,
|
|
138 info, &ret);
|
|
139 instance->widget = ret.window;
|
|
140 gtk_window_set_title(GTK_WINDOW(ret.window), "Local User");
|
|
141 instance->box = ret.vbox;
|
|
142 GtkWidget *label = gtk_label_new("Click your face");
|
|
143 instance->label = label;
|
|
144 gtk_box_pack_start(GTK_BOX(ret.vbox), label, FALSE, FALSE, 0);
|
|
145 gtk_box_reorder_child(GTK_BOX(ret.vbox), label, 0);
|
|
146 gtk_widget_show(label);
|
|
147 GtkWidget *button = gtk_button_new_with_label("Confirm");
|
|
148 gtk_box_pack_start(GTK_BOX(ret.vbox), button, FALSE, FALSE, 0);
|
|
149 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_cb),
|
|
150 instance);
|
|
151 instance->button = button;
|
|
152 gtk_widget_show(button);
|
|
153
|
|
154 GtkWidget *hbox = gtk_hbox_new(TRUE, 0);
|
|
155 gtk_box_pack_start(GTK_BOX(ret.vbox), hbox, FALSE, FALSE, 0);
|
|
156 gtk_widget_show(hbox);
|
|
157
|
|
158 GtkWidget *model_combo = gtk_combo_new();
|
|
159 GList *glist = NULL;
|
|
160
|
|
161 glist = g_list_append(glist, "Dog");
|
|
162 glist = g_list_append(glist, "Shark");
|
|
163 gtk_combo_set_popdown_strings(GTK_COMBO(model_combo), glist);
|
|
164 g_list_free(glist);
|
|
165 //gtk_combo_box_set_column_span_column(GTK_COMBO(model_combo),
|
|
166 // 10);
|
|
167 gtk_box_pack_start(GTK_BOX(hbox), model_combo, TRUE, TRUE, 0);
|
|
168 gtk_widget_show(model_combo);
|
|
169 instance->model = model_combo;
|
|
170
|
|
171 GtkWidget *head_material_combo = gtk_combo_new();
|
|
172 glist = NULL;
|
|
173 glist = g_list_append(glist, "Red");
|
|
174 glist = g_list_append(glist, "Dark Brown");
|
|
175 glist = g_list_append(glist, "Light Brown");
|
|
176 glist = g_list_append(glist, "White");
|
|
177 glist = g_list_append(glist, "Green");
|
|
178 glist = g_list_append(glist, "Black");
|
|
179 gtk_combo_set_popdown_strings(GTK_COMBO(head_material_combo), glist);
|
|
180 g_list_free(glist);
|
|
181 //gtk_combo_box_set_column_span_column(GTK_COMBO(head_material_combo),
|
|
182 // 10);
|
|
183 gtk_box_pack_start(GTK_BOX(hbox), head_material_combo, TRUE, TRUE, 0);
|
|
184 gtk_widget_show(head_material_combo);
|
|
185 instance->head = head_material_combo;
|
|
186
|
|
187 GtkWidget *appendage_material_combo = gtk_combo_new();
|
|
188 glist = NULL;
|
|
189 glist = g_list_append(glist, "Red");
|
|
190 glist = g_list_append(glist, "Dark Brown");
|
|
191 glist = g_list_append(glist, "Light Brown");
|
|
192 glist = g_list_append(glist, "White");
|
|
193 glist = g_list_append(glist, "Green");
|
|
194 glist = g_list_append(glist, "Black");
|
|
195 gtk_combo_set_popdown_strings(GTK_COMBO(appendage_material_combo),
|
|
196 glist);
|
|
197 g_list_free(glist);
|
|
198 //gtk_combo_box_set_column_span_column(GTK_COMBO(appendage_material_combo), 10);
|
|
199 gtk_box_pack_start(GTK_BOX(hbox), appendage_material_combo,
|
|
200 TRUE, TRUE, 0);
|
|
201 gtk_widget_show(appendage_material_combo);
|
|
202 instance->appendage = appendage_material_combo;
|
|
203
|
|
204 hbox = gtk_hbox_new(TRUE, 0);
|
|
205 gtk_box_pack_start(GTK_BOX(ret.vbox), hbox, FALSE, FALSE, 0);
|
|
206 gtk_widget_show(hbox);
|
|
207
|
|
208 GtkWidget *lids_material_combo = gtk_combo_new();
|
|
209 glist = NULL;
|
|
210 glist = g_list_append(glist, "Red");
|
|
211 glist = g_list_append(glist, "Dark Brown");
|
|
212 glist = g_list_append(glist, "Light Brown");
|
|
213 glist = g_list_append(glist, "White");
|
|
214 glist = g_list_append(glist, "Green");
|
|
215 glist = g_list_append(glist, "Black");
|
|
216 gtk_combo_set_popdown_strings(GTK_COMBO(lids_material_combo), glist);
|
|
217 g_list_free(glist);
|
|
218 //gtk_combo_box_set_column_span_column(GTK_COMBO(lids_material_combo), 10);
|
|
219 gtk_box_pack_start(GTK_BOX(hbox), lids_material_combo, TRUE, TRUE, 0);
|
|
220 gtk_widget_show(lids_material_combo);
|
|
221 instance->lid = lids_material_combo;
|
|
222
|
|
223 GtkWidget *left_iris_material_combo = gtk_combo_new();
|
|
224 glist = NULL;
|
|
225 glist = g_list_append(glist, "Red");
|
|
226 glist = g_list_append(glist, "Dark Brown");
|
|
227 glist = g_list_append(glist, "Light Brown");
|
|
228 glist = g_list_append(glist, "White");
|
|
229 glist = g_list_append(glist, "Green");
|
|
230 glist = g_list_append(glist, "Black");
|
|
231 gtk_combo_set_popdown_strings(GTK_COMBO(left_iris_material_combo),
|
|
232 glist);
|
|
233 g_list_free(glist);
|
|
234 //gtk_combo_box_set_column_span_column(GTK_COMBO(left_iris_material_combo), 10);
|
|
235 gtk_box_pack_start(GTK_BOX(hbox), left_iris_material_combo,
|
|
236 TRUE, TRUE, 0);
|
|
237 gtk_widget_show(left_iris_material_combo);
|
|
238 instance->left_iris = left_iris_material_combo;
|
|
239
|
|
240 /*
|
|
241 GtkWidget *right_iris_material_combo = gtk_combo_new();
|
|
242 glist = NULL;
|
|
243 glist = g_list_append(glist, "Red");
|
|
244 glist = g_list_append(glist, "Dark Brown");
|
|
245 glist = g_list_append(glist, "Light Brown");
|
|
246 glist = g_list_append(glist, "White");
|
|
247 glist = g_list_append(glist, "Green");
|
|
248 glist = g_list_append(glist, "Black");
|
|
249 gtk_combo_set_popdown_strings(GTK_COMBO(right_iris_material_combo),
|
|
250 glist);
|
|
251 g_list_free(glist);
|
|
252 //gtk_combo_box_set_column_span_column(GTK_COMBO(right_iris_material_combo), 10);
|
|
253 gtk_box_pack_start(GTK_BOX(hbox), right_iris_material_combo,
|
|
254 TRUE, TRUE, 0);
|
|
255 gtk_widget_show(right_iris_material_combo);
|
|
256 instance->right_iris = right_iris_material_combo;
|
|
257 */
|
|
258 gtk_widget_add_events(ret.draw_area, GDK_BUTTON_PRESS_MASK);
|
|
259 g_signal_connect(G_OBJECT(ret.draw_area), "button_press_event",
|
|
260 G_CALLBACK(click_cb), instance);
|
|
261 g_signal_connect(G_OBJECT(ret.window), "destroy",
|
|
262 G_CALLBACK(destroy_cb), cc);
|
|
263 // gtk_widget_set_size_request(window, 640, 480);
|
|
264 gtk_window_set_default_size(GTK_WINDOW(ret.window),320,300);
|
|
265
|
|
266
|
|
267 GdkGeometry hints;
|
|
268 hints.max_width = 640;
|
|
269 hints.max_height = 480;
|
|
270
|
|
271 gtk_window_set_geometry_hints (GTK_WINDOW(ret.window),
|
|
272 NULL,
|
|
273 &hints,
|
|
274 GDK_HINT_MAX_SIZE);
|
|
275 gtk_widget_show(ret.window);
|
|
276 return instance;
|
|
277 }
|
|
278
|
|
279 static gboolean webcam_cb(struct input_instance *instance)
|
|
280 {
|
|
281 assert(instance);
|
|
282 QueryCam();
|
|
283 return TRUE;
|
|
284 }
|
|
285
|
|
286 static void *facefind(void *data)
|
|
287 {
|
|
288 fprintf(stderr, "waiting\n");
|
|
289 getchar();
|
|
290 fprintf(stderr,"got you");
|
|
291 detection_mode=1;
|
|
292 return;
|
|
293 }
|
|
294
|
|
295 void destroy_input(struct input_instance *instance)
|
|
296 {
|
|
297 extern filter_bank *bank;
|
|
298 assert(instance);
|
|
299 Filter_Destroy(bank);
|
|
300 g_source_remove(instance->timer_id);
|
|
301 Die();
|
|
302 ExitMovies();
|
|
303 }
|
|
304
|
|
305 static gboolean config_wrapper(GtkWidget *widget, GdkEventConfigure *event,
|
|
306 void *data)
|
|
307 {
|
|
308
|
|
309
|
|
310 GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
|
|
311 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
|
|
312
|
|
313 GLfloat w = widget->allocation.width;
|
|
314 GLfloat h = widget->allocation.height;
|
|
315 GLfloat aspect;
|
|
316
|
|
317 // fprintf(stderr,"Homicide %f %f %d\n", w,h,draw_mode);
|
|
318
|
|
319 if (draw_mode==1){
|
|
320 // fprintf(stderr, "Bad place to be- actually not so bad\n");
|
|
321 return configure(widget, event, data);
|
|
322 }
|
|
323
|
|
324 /*** OpenGL BEGIN ***/
|
|
325 if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
|
|
326 return FALSE;
|
|
327
|
|
328
|
|
329 /* Undo all of the Model lighting here*/
|
|
330
|
|
331 // glDisable(GL_LIGHTING);
|
|
332 glDisable(GL_DEPTH_TEST);
|
|
333 // glDisable(GL_CULL_FACE);
|
|
334 // glDisable(GL_LIGHT0);
|
|
335 // glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
336 /* */
|
|
337
|
|
338
|
|
339 glViewport(0,-(h/14),w*2,h*2);
|
|
340
|
|
341 glMatrixMode(GL_PROJECTION);
|
|
342 glLoadIdentity();
|
|
343 gluOrtho2D(0,0,640,640);
|
|
344 glRasterPos2i(0,0);
|
|
345 glPixelZoom(-w/(1*640),(-h/(1*480)));
|
|
346 glMatrixMode(GL_MODELVIEW);
|
|
347 glLoadIdentity();
|
|
348
|
|
349
|
|
350
|
|
351
|
|
352 gdk_gl_drawable_gl_end(gldrawable);
|
|
353 /*** OpenGL END ***/
|
|
354
|
|
355 return TRUE;
|
|
356 }
|
|
357
|
|
358 static gboolean mydraw(GtkWidget *widget, GdkEventExpose *event,
|
|
359 void *data)
|
|
360 {
|
|
361 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
|
|
362 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
|
|
363 struct input_instance *instance = (struct input_instance*)data;
|
|
364 unsigned int *boo;
|
|
365 struct cc_features *features = &instance->face;
|
|
366
|
|
367 char *string = gtk_entry_get_text(GTK_COMBO(instance->model)->entry);
|
|
368 if (!strcmp(string, "Dog")) {
|
|
369 features->kind = 0;
|
|
370 } else if (!strcmp(string, "Shark")) {
|
|
371 features->kind = 1;
|
|
372 }
|
|
373
|
|
374 material_set(GTK_ENTRY(GTK_COMBO(instance->head)->entry),
|
|
375 &features->head_color);
|
|
376 material_set(GTK_ENTRY(GTK_COMBO(instance->appendage)->entry),
|
|
377 &features->appendage_color);
|
|
378 material_set(GTK_ENTRY(GTK_COMBO(instance->lid)->entry),
|
|
379 &features->lid_color);
|
|
380 material_set(GTK_ENTRY(GTK_COMBO(instance->left_iris)->entry),
|
|
381 &features->left_iris_color);
|
|
382 material_set(GTK_ENTRY(GTK_COMBO(instance->left_iris)->entry),
|
|
383 &features->right_iris_color);
|
|
384
|
|
385 if (easter_count>0) {
|
|
386 easter_count--;
|
|
387 } else {
|
|
388 instance->face.mode = 0;
|
|
389 }
|
|
390
|
|
391 if (mode_change>0){
|
|
392 mode_change--;
|
|
393 config_wrapper(widget, event, data);
|
|
394 }
|
|
395
|
|
396 if (draw_mode==1){
|
|
397 instance->output.my_output=LOCAL;
|
|
398 return draw(widget,event,&instance->output);
|
|
399 }
|
|
400
|
|
401
|
|
402 boo = (unsigned int*)colorBuf;
|
|
403
|
|
404 assert(instance);
|
|
405 assert(gtk_widget_is_gl_capable(widget));
|
|
406
|
|
407 /*** OpenGL BEGIN ***/
|
|
408
|
|
409 if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) {
|
|
410 // fprintf(stderr, "We're fucked this time.\n");
|
|
411 return FALSE;
|
|
412 }
|
|
413
|
|
414 glClearColor(0.0, 0.0, 0.0, 0.0);
|
|
415 glClear(GL_COLOR_BUFFER_BIT);
|
|
416
|
|
417 glDrawPixels(WEBCAM_X, WEBCAM_Y-70, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, boo);
|
|
418
|
|
419 if (gdk_gl_drawable_is_double_buffered(gldrawable))
|
|
420 gdk_gl_drawable_swap_buffers(gldrawable);
|
|
421 else
|
|
422 glFlush();
|
|
423
|
|
424 gdk_gl_drawable_gl_end(gldrawable);
|
|
425
|
|
426 /*** OpenGL END ***/
|
|
427
|
|
428 return TRUE;
|
|
429 }
|
|
430
|
|
431 static void init_cb(GtkWidget *widget, struct input_instance *instance)
|
|
432 {
|
|
433 setupDrawlists(LOCAL);
|
|
434 // fprintf(stderr,"init_cb\n");
|
|
435 }
|
|
436
|
|
437 static gboolean click_cb(GtkWidget *widget, GdkEventButton *event,
|
|
438 struct input_instance *instance)
|
|
439 {
|
|
440
|
|
441 GLfloat w = widget->allocation.width;
|
|
442 GLfloat h = widget->allocation.height;
|
|
443 GLfloat aspect;
|
|
444
|
|
445 if (draw_mode==1) {
|
|
446 switch (event->button) {
|
|
447 case 1:
|
|
448 Debug("F U!\n");
|
|
449 instance->face.mode = 1;
|
|
450 easter_count = 5;
|
|
451 break;
|
|
452 case 3:
|
|
453 Debug("should never get here\n");
|
|
454 instance->face.mode = 2;
|
|
455 easter_count = 5;
|
|
456 break;
|
|
457 default:
|
|
458 instance->face.mode = 0;
|
|
459 break;
|
|
460 }
|
|
461 return FALSE;
|
|
462 }
|
|
463
|
|
464 x_click=(event->x*(640/w));
|
|
465 x_click=640-x_click;
|
|
466 y_click=(event->y-(h/14))*(480/(h-(h/14)));
|
|
467 detection_mode=1;
|
|
468 //Debug("@@@ x:%d y:%d\n", x_click, y_click);
|
|
469
|
|
470 gtk_label_set_text(instance->label,
|
|
471 "Put on the box, then press confirm.");
|
|
472 if (x_click <= 10) x_click=10;
|
|
473 if (x_click >= WEBCAM_X-10) x_click=WEBCAM_X-60;
|
|
474 if (y_click <= 10) y_click=10;
|
|
475 if (y_click >= WEBCAM_Y-10) y_click=WEBCAM_Y-60;
|
|
476
|
|
477 return FALSE;
|
|
478 }
|
|
479
|
|
480 static void button_cb(GtkWidget *button, struct input_instance *instance)
|
|
481 {
|
|
482 if (!draw_mode) { /* transition to face mode */
|
|
483 if (detection_mode == 0) { /* ignore confirm if no calibrate */
|
|
484 return;
|
|
485 }
|
|
486 setupLighting(instance->widget);
|
|
487 mode_change = 1;
|
|
488 gtk_button_set_label(GTK_BUTTON(button), "Calibrate");
|
|
489 gtk_label_set_label(instance->label,
|
|
490 "If things get too crazy, click Calibrate.");
|
|
491 } else { /* transition to calibration mode */
|
|
492 gtk_label_set_label(instance->label, "Click your face");
|
|
493 mode_change = 2;
|
|
494 gtk_button_set_label(GTK_BUTTON(button), "Confirm");
|
|
495 }
|
|
496 draw_mode = !draw_mode;
|
|
497 }
|
|
498
|
|
499 static void destroy_cb(GtkWidget *widget, struct crazychat *cc)
|
|
500 {
|
|
501 cc->features_state = 0;
|
|
502 destroy_input(cc->input_data);
|
|
503 cc->input_data = NULL;
|
|
504 }
|
|
505
|
|
506 static void material_set(GtkWidget *entry, guint8 *material)
|
|
507 {
|
|
508 char *string = gtk_entry_get_text(GTK_ENTRY(entry));
|
|
509 if (!strcmp(string, "Red")) {
|
|
510 *material = 0;
|
|
511 } else if (!strcmp(string, "Dark Brown")) {
|
|
512 *material = 1;
|
|
513 } else if (!strcmp(string, "Light Brown")) {
|
|
514 *material = 2;
|
|
515 } else if (!strcmp(string, "White")) {
|
|
516 *material = 3;
|
|
517 } else if (!strcmp(string, "Green")) {
|
|
518 *material = 4;
|
|
519 } else if (!strcmp(string, "Black")) {
|
|
520 *material = 5;
|
|
521 }
|
|
522 }
|