style cleanup
[blender.git] / intern / ghost / test / multitest / MultiTest.c
1 /**
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27 #define FALSE 0
28
29 #ifdef WIN32
30
31 #pragma warning(disable: 4244 4305)
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <math.h>
38
39 #include "GL.h"
40
41 #include "MEM_guardedalloc.h"
42
43 #include "GHOST_C-api.h"
44
45 #ifdef USE_BMF
46 #  include "BMF_Api.h"
47 #else
48 #  include "BLF_api.h"
49 extern int datatoc_bfont_ttf_size;
50 extern char datatoc_bfont_ttf[];
51
52 /* cheat */
53 char U[1024] = {0};
54 #endif
55
56 #include "Util.h"
57 #include "Basic.h"
58 #include "ScrollBar.h"
59 #include "EventToBuf.h"
60
61 #include "WindowData.h"
62
63 /***/
64
65 typedef struct _MultiTestApp MultiTestApp;
66 typedef struct _LoggerWindow LoggerWindow;
67
68 void loggerwindow_log(LoggerWindow *lw, char *line);
69
70 void multitestapp_toggle_extra_window(MultiTestApp *app);
71 void multitestapp_free_extrawindow(MultiTestApp *app);
72 LoggerWindow *multitestapp_get_logger(MultiTestApp *app);
73 GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app);
74 void multitestapp_exit(MultiTestApp *app);
75
76 /**/
77
78 void rect_bevel_side(int rect[2][2], int side, float *lt, float *dk, float *col, int width)
79 {
80         int ltidx = (side / 2) % 4;
81         int dkidx = (ltidx + 1 + (side & 1)) % 4;
82         int i, corner;
83         
84         glBegin(GL_LINES);
85         for (i = 0; i < width; i++) {
86                 float ltf = pow(lt[i], 1.0 / 2.2), dkf = pow(dk[i], 1.0 / 2.2);
87                 float stf = (dkidx > ltidx) ? dkf : ltf;
88                 int lx = rect[1][0] - i - 1;
89                 int ly = rect[0][1] + i;
90
91                 glColor3f(col[0] * stf, col[1] * stf, col[2] * stf);
92                 for (corner = 0; corner < 4; corner++) {
93                         int x = (corner == 0 || corner == 1) ? (rect[0][0] + i) : (rect[1][0] - i - 1);
94                         int y = (corner == 0 || corner == 3) ? (rect[0][1] + i) : (rect[1][1] - i - 1);
95
96                         if (ltidx == corner)
97                                 glColor3f(col[0] * ltf, col[1] * ltf, col[2] * ltf);
98                         if (dkidx == corner)
99                                 glColor3f(col[0] * dkf, col[1] * dkf, col[2] * dkf);
100
101                         glVertex2i(lx, ly);
102                         glVertex2i(lx = x, ly = y);
103                 }
104         }
105         glEnd();
106         
107         glColor3fv(col);
108         glRecti(rect[0][0] + width, rect[0][1] + width, rect[1][0] - width, rect[1][1] - width);
109 }
110
111 void rect_bevel_smooth(int rect[2][2], int width)
112 {
113         float *lt = malloc(sizeof(*lt) * width);
114         float *dk = malloc(sizeof(*dk) * width);
115         float col[4];
116         int i;
117         
118         for (i = 0; i < width; i++) {
119                 float v = width - 1 ? ((float) i / (width - 1)) : 0;
120                 lt[i] = 1.2 + (1.0 - 1.2) * v;
121                 dk[i] = 0.2 + (1.0 - 0.2) * v;
122         }
123         
124         glGetFloatv(GL_CURRENT_COLOR, col);
125         
126         rect_bevel_side(rect, 3, lt, dk, col, width);
127         
128         free(lt);
129         free(dk);
130 }
131
132 /*
133  * MainWindow
134  */
135
136 typedef struct {
137         MultiTestApp        *app;
138
139         GHOST_WindowHandle win;
140         
141         int size[2];
142         
143         int lmouse[2], lmbut[3];
144         
145         int tmouse[2];
146 } MainWindow;
147
148 static void mainwindow_log(MainWindow *mw, char *str)
149 {
150         loggerwindow_log(multitestapp_get_logger(mw->app), str);
151 }
152
153 static void mainwindow_do_draw(MainWindow *mw)
154 {
155         GHOST_ActivateWindowDrawingContext(mw->win);
156         
157         if (mw->lmbut[0]) {
158                 glClearColor(0.5, 0.5, 0.5, 1);
159         }
160         else {
161                 glClearColor(1, 1, 1, 1);
162         }               
163         glClear(GL_COLOR_BUFFER_BIT);
164         
165         glColor3f(0.5, 0.6, 0.8);
166         glRecti(mw->tmouse[0] - 5, mw->tmouse[1] - 5, mw->tmouse[0] + 5, mw->tmouse[1] + 5);
167         
168         GHOST_SwapWindowBuffers(mw->win);
169 }
170
171 static void mainwindow_do_reshape(MainWindow *mw)
172 {
173         GHOST_RectangleHandle bounds = GHOST_GetClientBounds(mw->win);
174
175         GHOST_ActivateWindowDrawingContext(mw->win);
176
177         mw->size[0] = GHOST_GetWidthRectangle(bounds);
178         mw->size[1] = GHOST_GetHeightRectangle(bounds);
179         
180         glViewport(0, 0, mw->size[0], mw->size[1]);
181
182         glMatrixMode(GL_PROJECTION);
183         glLoadIdentity();
184         glOrtho(0, mw->size[0], 0, mw->size[1], -1, 1);
185         glTranslatef(0.375, 0.375, 0.0);
186
187         glMatrixMode(GL_MODELVIEW);
188         glLoadIdentity();
189 }
190
191 static void mainwindow_do_key(MainWindow *mw, GHOST_TKey key, int press)
192 {
193         switch (key) {
194                 case GHOST_kKeyC:
195                         if (press)
196                                 GHOST_SetCursorShape(mw->win, (GHOST_TStandardCursor) (rand() % (GHOST_kStandardCursorNumCursors)));
197                         break;
198                 case GHOST_kKeyLeftBracket:
199                         if (press)
200                                 GHOST_SetCursorVisibility(mw->win, 0);
201                         break;
202                 case GHOST_kKeyRightBracket:
203                         if (press)
204                                 GHOST_SetCursorVisibility(mw->win, 1);
205                         break;
206                 case GHOST_kKeyE:
207                         if (press)
208                                 multitestapp_toggle_extra_window(mw->app);
209                         break;
210                 case GHOST_kKeyQ:
211                         if (press)
212                                 multitestapp_exit(mw->app);
213                         break;
214                 case GHOST_kKeyT:
215                         if (press)
216                                 mainwindow_log(mw, "TextTest~|`hello`\"world\",<>/");
217                         break;
218                 case GHOST_kKeyR:
219                         if (press) {
220                                 int i;
221
222                                 mainwindow_log(mw, "Invalidating window 10 times");
223                                 for (i = 0; i < 10; i++)
224                                         GHOST_InvalidateWindow(mw->win);
225                         }
226                         break;
227                 case GHOST_kKeyF11:
228                         if (press) {
229                                 GHOST_SetWindowOrder(mw->win, GHOST_kWindowOrderBottom);
230                         }
231                         break;
232         }
233 }
234
235 static void mainwindow_do_move(MainWindow *mw, int x, int y)
236 {
237         mw->lmouse[0] = x, mw->lmouse[1] = y;
238         
239         if (mw->lmbut[0]) {
240                 mw->tmouse[0] = x, mw->tmouse[1] = y;
241                 GHOST_InvalidateWindow(mw->win);
242         }
243 }
244
245 static void mainwindow_do_button(MainWindow *mw, int which, int press)
246 {
247         if (which == GHOST_kButtonMaskLeft) {
248                 mw->lmbut[0] = press;
249                 mw->tmouse[0] = mw->lmouse[0], mw->tmouse[1] = mw->lmouse[1];
250                 GHOST_InvalidateWindow(mw->win);
251         }
252         else if (which == GHOST_kButtonMaskLeft) {
253                 mw->lmbut[1] = press;
254         }
255         else if (which == GHOST_kButtonMaskLeft) {
256                 mw->lmbut[2] = press;
257         }
258 }
259
260 static void mainwindow_handle(void *priv, GHOST_EventHandle evt)
261 {
262         MainWindow *mw = priv;
263         GHOST_TEventType type = GHOST_GetEventType(evt);
264         char buf[256];
265         
266         event_to_buf(evt, buf);
267         mainwindow_log(mw, buf);
268         
269         switch (type) {
270                 case GHOST_kEventCursorMove:
271                 {
272                         GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
273                         int x, y;
274                         GHOST_ScreenToClient(mw->win, cd->x, cd->y, &x, &y);
275                         mainwindow_do_move(mw, x, mw->size[1] - y - 1);
276                         break;
277                 }
278                 case GHOST_kEventButtonDown:
279                 case GHOST_kEventButtonUp:
280                 {
281                         GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
282                         mainwindow_do_button(mw, bd->button, (type == GHOST_kEventButtonDown));
283                         break;
284                 }
285                 case GHOST_kEventKeyDown:
286                 case GHOST_kEventKeyUp:
287                 {
288                         GHOST_TEventKeyData *kd = GHOST_GetEventData(evt);
289                         mainwindow_do_key(mw, kd->key, (type == GHOST_kEventKeyDown));
290                         break;
291                 }
292
293                 case GHOST_kEventWindowUpdate:
294                         mainwindow_do_draw(mw);
295                         break;
296                 case GHOST_kEventWindowSize:
297                         mainwindow_do_reshape(mw);
298                         break;
299         }
300 }
301
302 /**/
303
304 static void mainwindow_timer_proc(GHOST_TimerTaskHandle task, GHOST_TUns64 time)
305 {
306         MainWindow *mw = GHOST_GetTimerTaskUserData(task);
307         char buf[64];
308         
309         sprintf(buf, "timer: %6.2f", (double) ((GHOST_TInt64) time) / 1000);
310         mainwindow_log(mw, buf);
311 }
312
313 MainWindow *mainwindow_new(MultiTestApp *app) {
314         GHOST_SystemHandle sys = multitestapp_get_system(app);
315         GHOST_WindowHandle win;
316         
317         win = GHOST_CreateWindow(sys, "MultiTest:Main", 40, 40, 400, 400,
318                                  GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL,
319                                  FALSE, FALSE);
320         
321         if (win) {
322                 MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new");
323                 mw->app = app;
324                 mw->win = win;
325                 
326                 GHOST_SetWindowUserData(mw->win, windowdata_new(mw, mainwindow_handle));
327                 
328                 GHOST_InstallTimer(sys, 1000, 10000, mainwindow_timer_proc, mw);
329                 
330                 return mw;
331         }
332         else {
333                 return NULL;
334         }
335 }
336
337 void mainwindow_free(MainWindow *mw)
338 {
339         GHOST_SystemHandle sys = multitestapp_get_system(mw->app);
340
341         windowdata_free(GHOST_GetWindowUserData(mw->win));
342         GHOST_DisposeWindow(sys, mw->win);
343         MEM_freeN(mw);
344 }
345
346 /*
347  * LoggerWindow
348  */
349
350 struct _LoggerWindow {
351         MultiTestApp        *app;
352
353         GHOST_WindowHandle win;
354
355 #ifdef USE_BMF  
356         BMF_Font    *font;
357 #else
358         int font;
359 #endif
360         int fonttexid;
361         int fontheight;
362         
363         int size[2];
364         
365         int ndisplines;
366         int textarea[2][2];
367         ScrollBar   *scroll;
368         
369         char        **loglines;
370         int nloglines, logsize;
371         
372         int lmbut[3];
373         int lmouse[2];
374 };
375
376 #define SCROLLBAR_PAD 2
377 #define SCROLLBAR_WIDTH 14
378 #define TEXTAREA_PAD 2
379 static void loggerwindow_recalc_regions(LoggerWindow *lw)
380 {
381         int nscroll[2][2];
382         
383         nscroll[0][0] = SCROLLBAR_PAD;
384         nscroll[0][1] = SCROLLBAR_PAD;
385         nscroll[1][0] = nscroll[0][0] + SCROLLBAR_WIDTH;
386         nscroll[1][1] = lw->size[1] - SCROLLBAR_PAD - 1;
387
388         lw->textarea[0][0] = nscroll[1][0] + TEXTAREA_PAD;
389         lw->textarea[0][1] = TEXTAREA_PAD;
390         lw->textarea[1][0] = lw->size[0] - TEXTAREA_PAD - 1;
391         lw->textarea[1][1] = lw->size[1] - TEXTAREA_PAD - 1;
392
393         lw->ndisplines = (lw->textarea[1][1] - lw->textarea[0][1]) / lw->fontheight;
394
395         scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines / lw->nloglines);
396         scrollbar_set_rect(lw->scroll, nscroll);
397 }
398
399 static void loggerwindow_setup_window_gl(LoggerWindow *lw)
400 {
401         glViewport(0, 0, lw->size[0], lw->size[1]);
402
403         glMatrixMode(GL_PROJECTION);
404         glLoadIdentity();
405         glOrtho(0, lw->size[0], 0, lw->size[1], -1, 1);
406         glTranslatef(0.375, 0.375, 0.0);
407
408         glMatrixMode(GL_MODELVIEW);
409         glLoadIdentity();
410 }
411
412 static void loggerwindow_do_reshape(LoggerWindow *lw)
413 {
414         GHOST_RectangleHandle bounds = GHOST_GetClientBounds(lw->win);
415
416         GHOST_ActivateWindowDrawingContext(lw->win);
417         
418         lw->size[0] = GHOST_GetWidthRectangle(bounds);
419         lw->size[1] = GHOST_GetHeightRectangle(bounds);
420         
421         loggerwindow_recalc_regions(lw);
422         loggerwindow_setup_window_gl(lw);
423 }
424
425 static void loggerwindow_do_draw(LoggerWindow *lw)
426 {
427         int i, ndisplines, startline;
428         int sb_rect[2][2], sb_thumb[2][2];
429                 
430         GHOST_ActivateWindowDrawingContext(lw->win);
431         
432         glClearColor(1, 1, 1, 1);
433         glClear(GL_COLOR_BUFFER_BIT);
434
435         glColor3f(0.8, 0.8, 0.8);
436         rect_bevel_smooth(lw->textarea, 4);
437         
438         scrollbar_get_rect(lw->scroll, sb_rect);
439         scrollbar_get_thumb(lw->scroll, sb_thumb);
440         
441         glColor3f(0.6, 0.6, 0.6);
442         rect_bevel_smooth(sb_rect, 1);
443         
444         if (scrollbar_is_scrolling(lw->scroll)) {
445                 glColor3f(0.6, 0.7, 0.5);
446         }
447         else {
448                 glColor3f(0.9, 0.9, 0.92);
449         }
450         rect_bevel_smooth(sb_thumb, 1);
451         
452         startline = scrollbar_get_thumbpos(lw->scroll) * (lw->nloglines - 1);
453         ndisplines = min_i(lw->ndisplines, lw->nloglines - startline);
454
455         if (lw->fonttexid != -1) {
456                 glBindTexture(GL_TEXTURE_2D, lw->fonttexid);
457                 
458                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
459                 glEnable(GL_BLEND);
460                 glEnable(GL_TEXTURE_2D);                
461         }
462         glColor3f(0, 0, 0);
463         for (i = 0; i < ndisplines; i++) {
464                 /* stored in reverse order */
465                 char *line = lw->loglines[(lw->nloglines - 1) - (i + startline)];
466                 int x_pos = lw->textarea[0][0] + 4;
467                 int y_pos = lw->textarea[0][1] + 4 + i * lw->fontheight;
468
469 #ifdef USE_BMF          
470                 if (lw->fonttexid == -1) {
471                         glRasterPos2i(x_pos, y_pos);
472                         BMF_DrawString(lw->font, line);
473                 }
474                 else {
475                         BMF_DrawStringTexture(lw->font, line, x_pos, y_pos, 0.0);
476                 }
477 #else
478                 BLF_position(lw->font, x_pos, y_pos, 0.0);
479                 BLF_draw(lw->font, line, 256); // XXX
480 #endif
481         }
482
483 #ifdef USE_BMF
484         if (lw->fonttexid != -1) {
485                 glDisable(GL_TEXTURE_2D);               
486                 glDisable(GL_BLEND);
487         }
488 #endif
489
490         GHOST_SwapWindowBuffers(lw->win);
491 }
492
493 static void loggerwindow_do_move(LoggerWindow *lw, int x, int y)
494 {
495         lw->lmouse[0] = x, lw->lmouse[1] = y;
496         
497         if (scrollbar_is_scrolling(lw->scroll)) {
498                 scrollbar_keep_scrolling(lw->scroll, y);
499                 GHOST_InvalidateWindow(lw->win);
500         }
501 }
502
503 static void loggerwindow_do_button(LoggerWindow *lw, int which, int press)
504 {
505         if (which == GHOST_kButtonMaskLeft) {
506                 lw->lmbut[0] = press;
507                 
508                 if (press) {
509                         if (scrollbar_contains_pt(lw->scroll, lw->lmouse)) {
510                                 scrollbar_start_scrolling(lw->scroll, lw->lmouse[1]);                           
511                                 GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorUpDown);
512                                 GHOST_InvalidateWindow(lw->win);
513                         }
514                 }
515                 else {
516                         if (scrollbar_is_scrolling(lw->scroll)) {
517                                 scrollbar_stop_scrolling(lw->scroll);
518                                 GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorDefault);
519                                 GHOST_InvalidateWindow(lw->win);
520                         }
521                 }
522         }
523         else if (which == GHOST_kButtonMaskMiddle) {
524                 lw->lmbut[1] = press;
525         }
526         else if (which == GHOST_kButtonMaskRight) {
527                 lw->lmbut[2] = press;
528         }
529 }
530
531 static void loggerwindow_do_key(LoggerWindow *lw, GHOST_TKey key, int press)
532 {
533         switch (key) {
534                 case GHOST_kKeyQ:
535                         if (press)
536                                 multitestapp_exit(lw->app);
537                         break;
538         }
539 }
540
541 static void loggerwindow_handle(void *priv, GHOST_EventHandle evt)
542 {
543         LoggerWindow *lw = priv;
544         GHOST_TEventType type = GHOST_GetEventType(evt);
545         
546         switch (type) {
547                 case GHOST_kEventCursorMove:
548                 {
549                         GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
550                         int x, y;
551                         GHOST_ScreenToClient(lw->win, cd->x, cd->y, &x, &y);
552                         loggerwindow_do_move(lw, x, lw->size[1] - y - 1);
553                         break;
554                 }
555                 case GHOST_kEventButtonDown:
556                 case GHOST_kEventButtonUp:
557                 {
558                         GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
559                         loggerwindow_do_button(lw, bd->button, (type == GHOST_kEventButtonDown));
560                         break;
561                 }
562                 case GHOST_kEventKeyDown:
563                 case GHOST_kEventKeyUp:
564                 {
565                         GHOST_TEventKeyData *kd = GHOST_GetEventData(evt);
566                         loggerwindow_do_key(lw, kd->key, (type == GHOST_kEventKeyDown));
567                         break;
568                 }
569
570                 case GHOST_kEventWindowUpdate:
571                         loggerwindow_do_draw(lw);
572                         break;
573                 case GHOST_kEventWindowSize:
574                         loggerwindow_do_reshape(lw);
575                         break;
576         }
577 }
578
579 /**/
580
581 LoggerWindow *loggerwindow_new(MultiTestApp *app) {
582         GHOST_SystemHandle sys = multitestapp_get_system(app);
583         GHOST_TUns32 screensize[2];
584         GHOST_WindowHandle win;
585         
586         GHOST_GetMainDisplayDimensions(sys, &screensize[0], &screensize[1]);
587         win = GHOST_CreateWindow(sys, "MultiTest:Logger", 40, screensize[1] - 432,
588                                  800, 300, GHOST_kWindowStateNormal,
589                                  GHOST_kDrawingContextTypeOpenGL, FALSE, FALSE);
590         
591         if (win) {
592                 LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new");
593                 int bbox[2][2];
594                 lw->app = app;
595                 lw->win = win;
596
597 #ifdef USE_BMF
598                 lw->font = BMF_GetFont(BMF_kScreen12);
599                 lw->fonttexid = BMF_GetFontTexture(lw->font);
600
601                 BMF_GetBoundingBox(lw->font, &bbox[0][0], &bbox[0][1], &bbox[1][0], &bbox[1][1]);
602                 lw->fontheight = rect_height(bbox);
603 #else
604                 lw->font = BLF_load_mem("default", (unsigned char *)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
605                 BLF_size(lw->font, 11, 72);
606                 lw->fontheight = BLF_height(lw->font, "A_");
607 #endif
608                 
609                 lw->nloglines = lw->logsize = 0;
610                 lw->loglines = MEM_mallocN(sizeof(*lw->loglines) * lw->nloglines, "loglines");
611                 
612                 lw->scroll = scrollbar_new(2, 40);
613                 
614                 GHOST_SetWindowUserData(lw->win, windowdata_new(lw, loggerwindow_handle));
615
616                 loggerwindow_do_reshape(lw);
617
618                 return lw;
619         }
620         else {
621                 return NULL;
622         }
623 }
624
625 void loggerwindow_log(LoggerWindow *lw, char *line)
626 {
627         if (lw->nloglines == lw->logsize) {
628                 lw->loglines = memdbl(lw->loglines, &lw->logsize, sizeof(*lw->loglines));
629         }
630         
631         lw->loglines[lw->nloglines++] = string_dup(line);
632         scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines / lw->nloglines);
633         
634         GHOST_InvalidateWindow(lw->win);
635 }
636
637 void loggerwindow_free(LoggerWindow *lw)
638 {
639         GHOST_SystemHandle sys = multitestapp_get_system(lw->app);
640         int i;
641
642         for (i = 0; i < lw->nloglines; i++) {
643                 MEM_freeN(lw->loglines[i]);
644         }
645         MEM_freeN(lw->loglines);
646         
647         windowdata_free(GHOST_GetWindowUserData(lw->win));
648         GHOST_DisposeWindow(sys, lw->win);
649         MEM_freeN(lw);
650 }
651
652 /*
653  * ExtraWindow
654  */
655
656
657 typedef struct {
658         MultiTestApp        *app;
659
660         GHOST_WindowHandle win;
661         
662         int size[2];
663 } ExtraWindow;
664
665 static void extrawindow_do_draw(ExtraWindow *ew)
666 {
667         GHOST_ActivateWindowDrawingContext(ew->win);
668
669         glClearColor(1, 1, 1, 1);
670         glClear(GL_COLOR_BUFFER_BIT);
671         
672         glColor3f(0.8, 0.8, 0.8);
673         glRecti(10, 10, ew->size[0] - 10, ew->size[1] - 10);
674         
675         GHOST_SwapWindowBuffers(ew->win);
676 }
677
678 static void extrawindow_do_reshape(ExtraWindow *ew)
679 {
680         GHOST_RectangleHandle bounds = GHOST_GetClientBounds(ew->win);
681
682         GHOST_ActivateWindowDrawingContext(ew->win);
683
684         ew->size[0] = GHOST_GetWidthRectangle(bounds);
685         ew->size[1] = GHOST_GetHeightRectangle(bounds);
686         
687         glViewport(0, 0, ew->size[0], ew->size[1]);
688
689         glMatrixMode(GL_PROJECTION);
690         glLoadIdentity();
691         glOrtho(0, ew->size[0], 0, ew->size[1], -1, 1);
692         glTranslatef(0.375, 0.375, 0.0);
693
694         glMatrixMode(GL_MODELVIEW);
695         glLoadIdentity();
696 }
697
698 static void extrawindow_do_key(ExtraWindow *ew, GHOST_TKey key, int press)
699 {
700         switch (key) {
701                 case GHOST_kKeyE:
702                         if (press)
703                                 multitestapp_toggle_extra_window(ew->app);
704                         break;
705         }
706 }
707
708 static void extrawindow_spin_cursor(ExtraWindow *ew, GHOST_TUns64 time)
709 {
710         GHOST_TUns8 bitmap[16][2];
711         GHOST_TUns8 mask[16][2];
712         double ftime = (double) ((GHOST_TInt64) time) / 1000;
713         float angle = fmod(ftime, 1.0) * 3.1415 * 2;
714         int i;
715         
716         memset(&bitmap, 0, sizeof(bitmap));
717         memset(&mask, 0, sizeof(mask));
718         
719         bitmap[0][0] |= mask[0][0] |= 0xF;
720         bitmap[1][0] |= mask[1][0] |= 0xF;
721         bitmap[2][0] |= mask[2][0] |= 0xF;
722         bitmap[3][0] |= mask[3][0] |= 0xF;
723         
724         for (i = 0; i < 7; i++) {
725                 int x = 7 + cos(angle) * i;
726                 int y = 7 + sin(angle) * i;
727
728                 mask[y][x / 8] |= (1 << (x % 8));
729         }
730         for (i = 0; i < 64; i++) {
731                 float v = (i / 63.0) * 3.1415 * 2;
732                 int x = 7 + cos(v) * 7;
733                 int y = 7 + sin(v) * 7;
734                 
735                 mask[y][x / 8] |= (1 << (x % 8));
736         }
737         
738         GHOST_SetCustomCursorShape(ew->win, bitmap, mask, 0, 0);
739 }
740
741 static void extrawindow_handle(void *priv, GHOST_EventHandle evt)
742 {
743         ExtraWindow *ew = priv;
744         GHOST_TEventType type = GHOST_GetEventType(evt);
745         char buf[256];
746         
747         event_to_buf(evt, buf);
748         loggerwindow_log(multitestapp_get_logger(ew->app), buf);
749         
750         switch (type) {
751                 case GHOST_kEventKeyDown:
752                 case GHOST_kEventKeyUp:
753                 {
754                         GHOST_TEventKeyData *kd = GHOST_GetEventData(evt);
755                         extrawindow_do_key(ew, kd->key, (type == GHOST_kEventKeyDown));
756                         break;
757                 }
758
759                 case GHOST_kEventCursorMove:
760                 {
761                         extrawindow_spin_cursor(ew, GHOST_GetEventTime(evt));
762                         break;
763                 }
764
765                 case GHOST_kEventWindowClose:
766                         multitestapp_free_extrawindow(ew->app);
767                         break;
768                 case GHOST_kEventWindowUpdate:
769                         extrawindow_do_draw(ew);
770                         break;
771                 case GHOST_kEventWindowSize:
772                         extrawindow_do_reshape(ew);
773                         break;
774         }
775 }
776
777 /**/
778
779 ExtraWindow *extrawindow_new(MultiTestApp *app) {
780         GHOST_SystemHandle sys = multitestapp_get_system(app);
781         GHOST_WindowHandle win;
782         
783         win = GHOST_CreateWindow(sys, "MultiTest:Extra", 500, 40, 400, 400,
784                                  GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL,
785                                  FALSE, FALSE);
786         
787         if (win) {
788                 ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new");
789                 ew->app = app;
790                 ew->win = win;
791                 
792                 GHOST_SetWindowUserData(ew->win, windowdata_new(ew, extrawindow_handle));
793                 
794                 return ew;
795         }
796         else {
797                 return NULL;
798         }
799 }
800
801 void extrawindow_free(ExtraWindow *ew)
802 {
803         GHOST_SystemHandle sys = multitestapp_get_system(ew->app);
804
805         windowdata_free(GHOST_GetWindowUserData(ew->win));
806         GHOST_DisposeWindow(sys, ew->win);
807         MEM_freeN(ew);
808 }
809
810 /*
811  * MultiTestApp
812  */
813         
814 struct _MultiTestApp {
815         GHOST_SystemHandle sys;
816         MainWindow          *main;
817         LoggerWindow        *logger;
818         ExtraWindow         *extra;
819         
820         int exit;
821 };
822
823 static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr data)
824 {
825         MultiTestApp *app = data;
826         GHOST_WindowHandle win;
827         
828         win = GHOST_GetEventWindow(evt);
829         if (win && !GHOST_ValidWindow(app->sys, win)) {
830                 loggerwindow_log(app->logger, "WARNING: bad event, non-valid window\n");
831                 return 1;
832         }
833                 
834         if (win) {
835                 WindowData *wb = GHOST_GetWindowUserData(win);
836                 
837                 windowdata_handle(wb, evt);
838         }
839         else {
840                 GHOST_TEventType type = GHOST_GetEventType(evt);
841                         
842                 /* GHOST_kEventQuit are the only 'system' events,
843                  * that is, events without a window.
844                  */
845                 switch (type) {
846                         case GHOST_kEventQuit:
847                                 app->exit = 1;
848                                 break;
849
850                         default:
851                                 fatal("Unhandled system event: %d (%s)\n", type, eventtype_to_string(type));
852                                 break;
853                 }
854         }
855         
856         return 1;
857 }
858
859 /**/
860
861 MultiTestApp *multitestapp_new(void) {
862         MultiTestApp *app = MEM_mallocN(sizeof(*app), "multitestapp_new");
863         GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(multitest_event_handler, app);
864
865         app->sys = GHOST_CreateSystem();
866         if (!app->sys)
867                 fatal("Unable to create ghost system");
868
869         if (!GHOST_AddEventConsumer(app->sys, consumer))        
870                 fatal("Unable to add multitest event consumer ");
871                 
872         app->main = mainwindow_new(app);
873         if (!app->main) 
874                 fatal("Unable to create main window");
875                 
876         app->logger = loggerwindow_new(app);
877         if (!app->logger)
878                 fatal("Unable to create logger window");
879
880         app->extra = NULL;
881         app->exit = 0;
882         
883         return app;
884 }
885
886 LoggerWindow *multitestapp_get_logger(MultiTestApp *app) {
887         return app->logger;     
888 }
889
890 GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app) {
891         return app->sys;
892 }
893
894 void multitestapp_free_extrawindow(MultiTestApp *app)
895 {
896         extrawindow_free(app->extra);
897         app->extra = NULL;
898 }
899
900 void multitestapp_toggle_extra_window(MultiTestApp *app)
901 {
902         if (app->extra) {
903                 multitestapp_free_extrawindow(app);
904         }
905         else {
906                 app->extra = extrawindow_new(app);
907         }
908 }
909
910 void multitestapp_exit(MultiTestApp *app)
911 {
912         app->exit = 1;
913 }
914
915 void multitestapp_run(MultiTestApp *app)
916 {
917         while (!app->exit) {
918                 GHOST_ProcessEvents(app->sys, 1);
919                 GHOST_DispatchEvents(app->sys);
920         }
921 }
922
923 void multitestapp_free(MultiTestApp *app)
924 {
925         mainwindow_free(app->main);
926         loggerwindow_free(app->logger);
927         GHOST_DisposeSystem(app->sys);
928         MEM_freeN(app);
929 }
930
931 /***/
932         
933 int main(int argc, char **argv)
934 {
935 #ifndef USE_BMF
936         BLF_init(11, 72);
937 #endif
938
939         MultiTestApp *app = multitestapp_new();
940         
941         multitestapp_run(app);
942         multitestapp_free(app);
943         
944         return 0;
945 }