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                         GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
272                         int x, y;
273                         GHOST_ScreenToClient(mw->win, cd->x, cd->y, &x, &y);
274                         mainwindow_do_move(mw, x, mw->size[1] - y - 1);
275                         break;
276                 }
277                 case GHOST_kEventButtonDown:
278                 case GHOST_kEventButtonUp: {
279                         GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
280                         mainwindow_do_button(mw, bd->button, (type == GHOST_kEventButtonDown));
281                         break;
282                 }
283                 case GHOST_kEventKeyDown:
284                 case GHOST_kEventKeyUp: {
285                         GHOST_TEventKeyData *kd = GHOST_GetEventData(evt);
286                         mainwindow_do_key(mw, kd->key, (type == GHOST_kEventKeyDown));
287                         break;
288                 }
289
290                 case GHOST_kEventWindowUpdate:
291                         mainwindow_do_draw(mw);
292                         break;
293                 case GHOST_kEventWindowSize:
294                         mainwindow_do_reshape(mw);
295                         break;
296         }
297 }
298
299 /**/
300
301 static void mainwindow_timer_proc(GHOST_TimerTaskHandle task, GHOST_TUns64 time)
302 {
303         MainWindow *mw = GHOST_GetTimerTaskUserData(task);
304         char buf[64];
305         
306         sprintf(buf, "timer: %6.2f", (double) ((GHOST_TInt64) time) / 1000);
307         mainwindow_log(mw, buf);
308 }
309
310 MainWindow *mainwindow_new(MultiTestApp *app) {
311         GHOST_SystemHandle sys = multitestapp_get_system(app);
312         GHOST_WindowHandle win;
313         
314         win = GHOST_CreateWindow(sys, "MultiTest:Main", 40, 40, 400, 400,
315                                  GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL,
316                                  FALSE, FALSE);
317         
318         if (win) {
319                 MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new");
320                 mw->app = app;
321                 mw->win = win;
322                 
323                 GHOST_SetWindowUserData(mw->win, windowdata_new(mw, mainwindow_handle));
324                 
325                 GHOST_InstallTimer(sys, 1000, 10000, mainwindow_timer_proc, mw);
326                 
327                 return mw;
328         }
329         else {
330                 return NULL;
331         }
332 }
333
334 void mainwindow_free(MainWindow *mw)
335 {
336         GHOST_SystemHandle sys = multitestapp_get_system(mw->app);
337
338         windowdata_free(GHOST_GetWindowUserData(mw->win));
339         GHOST_DisposeWindow(sys, mw->win);
340         MEM_freeN(mw);
341 }
342
343 /*
344  * LoggerWindow
345  */
346
347 struct _LoggerWindow {
348         MultiTestApp        *app;
349
350         GHOST_WindowHandle win;
351
352 #ifdef USE_BMF  
353         BMF_Font    *font;
354 #else
355         int font;
356 #endif
357         int fonttexid;
358         int fontheight;
359         
360         int size[2];
361         
362         int ndisplines;
363         int textarea[2][2];
364         ScrollBar   *scroll;
365         
366         char        **loglines;
367         int nloglines, logsize;
368         
369         int lmbut[3];
370         int lmouse[2];
371 };
372
373 #define SCROLLBAR_PAD 2
374 #define SCROLLBAR_WIDTH 14
375 #define TEXTAREA_PAD 2
376 static void loggerwindow_recalc_regions(LoggerWindow *lw)
377 {
378         int nscroll[2][2];
379         
380         nscroll[0][0] = SCROLLBAR_PAD;
381         nscroll[0][1] = SCROLLBAR_PAD;
382         nscroll[1][0] = nscroll[0][0] + SCROLLBAR_WIDTH;
383         nscroll[1][1] = lw->size[1] - SCROLLBAR_PAD - 1;
384
385         lw->textarea[0][0] = nscroll[1][0] + TEXTAREA_PAD;
386         lw->textarea[0][1] = TEXTAREA_PAD;
387         lw->textarea[1][0] = lw->size[0] - TEXTAREA_PAD - 1;
388         lw->textarea[1][1] = lw->size[1] - TEXTAREA_PAD - 1;
389
390         lw->ndisplines = (lw->textarea[1][1] - lw->textarea[0][1]) / lw->fontheight;
391
392         scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines / lw->nloglines);
393         scrollbar_set_rect(lw->scroll, nscroll);
394 }
395
396 static void loggerwindow_setup_window_gl(LoggerWindow *lw)
397 {
398         glViewport(0, 0, lw->size[0], lw->size[1]);
399
400         glMatrixMode(GL_PROJECTION);
401         glLoadIdentity();
402         glOrtho(0, lw->size[0], 0, lw->size[1], -1, 1);
403         glTranslatef(0.375, 0.375, 0.0);
404
405         glMatrixMode(GL_MODELVIEW);
406         glLoadIdentity();
407 }
408
409 static void loggerwindow_do_reshape(LoggerWindow *lw)
410 {
411         GHOST_RectangleHandle bounds = GHOST_GetClientBounds(lw->win);
412
413         GHOST_ActivateWindowDrawingContext(lw->win);
414         
415         lw->size[0] = GHOST_GetWidthRectangle(bounds);
416         lw->size[1] = GHOST_GetHeightRectangle(bounds);
417         
418         loggerwindow_recalc_regions(lw);
419         loggerwindow_setup_window_gl(lw);
420 }
421
422 static void loggerwindow_do_draw(LoggerWindow *lw)
423 {
424         int i, ndisplines, startline;
425         int sb_rect[2][2], sb_thumb[2][2];
426                 
427         GHOST_ActivateWindowDrawingContext(lw->win);
428         
429         glClearColor(1, 1, 1, 1);
430         glClear(GL_COLOR_BUFFER_BIT);
431
432         glColor3f(0.8, 0.8, 0.8);
433         rect_bevel_smooth(lw->textarea, 4);
434         
435         scrollbar_get_rect(lw->scroll, sb_rect);
436         scrollbar_get_thumb(lw->scroll, sb_thumb);
437         
438         glColor3f(0.6, 0.6, 0.6);
439         rect_bevel_smooth(sb_rect, 1);
440         
441         if (scrollbar_is_scrolling(lw->scroll)) {
442                 glColor3f(0.6, 0.7, 0.5);
443         }
444         else {
445                 glColor3f(0.9, 0.9, 0.92);
446         }
447         rect_bevel_smooth(sb_thumb, 1);
448         
449         startline = scrollbar_get_thumbpos(lw->scroll) * (lw->nloglines - 1);
450         ndisplines = min_i(lw->ndisplines, lw->nloglines - startline);
451
452         if (lw->fonttexid != -1) {
453                 glBindTexture(GL_TEXTURE_2D, lw->fonttexid);
454                 
455                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
456                 glEnable(GL_BLEND);
457                 glEnable(GL_TEXTURE_2D);                
458         }
459         glColor3f(0, 0, 0);
460         for (i = 0; i < ndisplines; i++) {
461                 /* stored in reverse order */
462                 char *line = lw->loglines[(lw->nloglines - 1) - (i + startline)];
463                 int x_pos = lw->textarea[0][0] + 4;
464                 int y_pos = lw->textarea[0][1] + 4 + i * lw->fontheight;
465
466 #ifdef USE_BMF          
467                 if (lw->fonttexid == -1) {
468                         glRasterPos2i(x_pos, y_pos);
469                         BMF_DrawString(lw->font, line);
470                 }
471                 else {
472                         BMF_DrawStringTexture(lw->font, line, x_pos, y_pos, 0.0);
473                 }
474 #else
475                 BLF_position(lw->font, x_pos, y_pos, 0.0);
476                 BLF_draw(lw->font, line, 256); // XXX
477 #endif
478         }
479
480 #ifdef USE_BMF
481         if (lw->fonttexid != -1) {
482                 glDisable(GL_TEXTURE_2D);               
483                 glDisable(GL_BLEND);
484         }
485 #endif
486
487         GHOST_SwapWindowBuffers(lw->win);
488 }
489
490 static void loggerwindow_do_move(LoggerWindow *lw, int x, int y)
491 {
492         lw->lmouse[0] = x, lw->lmouse[1] = y;
493         
494         if (scrollbar_is_scrolling(lw->scroll)) {
495                 scrollbar_keep_scrolling(lw->scroll, y);
496                 GHOST_InvalidateWindow(lw->win);
497         }
498 }
499
500 static void loggerwindow_do_button(LoggerWindow *lw, int which, int press)
501 {
502         if (which == GHOST_kButtonMaskLeft) {
503                 lw->lmbut[0] = press;
504                 
505                 if (press) {
506                         if (scrollbar_contains_pt(lw->scroll, lw->lmouse)) {
507                                 scrollbar_start_scrolling(lw->scroll, lw->lmouse[1]);                           
508                                 GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorUpDown);
509                                 GHOST_InvalidateWindow(lw->win);
510                         }
511                 }
512                 else {
513                         if (scrollbar_is_scrolling(lw->scroll)) {
514                                 scrollbar_stop_scrolling(lw->scroll);
515                                 GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorDefault);
516                                 GHOST_InvalidateWindow(lw->win);
517                         }
518                 }
519         }
520         else if (which == GHOST_kButtonMaskMiddle) {
521                 lw->lmbut[1] = press;
522         }
523         else if (which == GHOST_kButtonMaskRight) {
524                 lw->lmbut[2] = press;
525         }
526 }
527
528 static void loggerwindow_do_key(LoggerWindow *lw, GHOST_TKey key, int press)
529 {
530         switch (key) {
531                 case GHOST_kKeyQ:
532                         if (press)
533                                 multitestapp_exit(lw->app);
534                         break;
535         }
536 }
537
538 static void loggerwindow_handle(void *priv, GHOST_EventHandle evt)
539 {
540         LoggerWindow *lw = priv;
541         GHOST_TEventType type = GHOST_GetEventType(evt);
542         
543         switch (type) {
544                 case GHOST_kEventCursorMove: {
545                         GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
546                         int x, y;
547                         GHOST_ScreenToClient(lw->win, cd->x, cd->y, &x, &y);
548                         loggerwindow_do_move(lw, x, lw->size[1] - y - 1);
549                         break;
550                 }
551                 case GHOST_kEventButtonDown:
552                 case GHOST_kEventButtonUp: {
553                         GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
554                         loggerwindow_do_button(lw, bd->button, (type == GHOST_kEventButtonDown));
555                         break;
556                 }
557                 case GHOST_kEventKeyDown:
558                 case GHOST_kEventKeyUp: {
559                         GHOST_TEventKeyData *kd = GHOST_GetEventData(evt);
560                         loggerwindow_do_key(lw, kd->key, (type == GHOST_kEventKeyDown));
561                         break;
562                 }
563
564                 case GHOST_kEventWindowUpdate:
565                         loggerwindow_do_draw(lw);
566                         break;
567                 case GHOST_kEventWindowSize:
568                         loggerwindow_do_reshape(lw);
569                         break;
570         }
571 }
572
573 /**/
574
575 LoggerWindow *loggerwindow_new(MultiTestApp *app) {
576         GHOST_SystemHandle sys = multitestapp_get_system(app);
577         GHOST_TUns32 screensize[2];
578         GHOST_WindowHandle win;
579         
580         GHOST_GetMainDisplayDimensions(sys, &screensize[0], &screensize[1]);
581         win = GHOST_CreateWindow(sys, "MultiTest:Logger", 40, screensize[1] - 432,
582                                  800, 300, GHOST_kWindowStateNormal,
583                                  GHOST_kDrawingContextTypeOpenGL, FALSE, FALSE);
584         
585         if (win) {
586                 LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new");
587                 int bbox[2][2];
588                 lw->app = app;
589                 lw->win = win;
590
591 #ifdef USE_BMF
592                 lw->font = BMF_GetFont(BMF_kScreen12);
593                 lw->fonttexid = BMF_GetFontTexture(lw->font);
594
595                 BMF_GetBoundingBox(lw->font, &bbox[0][0], &bbox[0][1], &bbox[1][0], &bbox[1][1]);
596                 lw->fontheight = rect_height(bbox);
597 #else
598                 lw->font = BLF_load_mem("default", (unsigned char *)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
599                 BLF_size(lw->font, 11, 72);
600                 lw->fontheight = BLF_height(lw->font, "A_");
601 #endif
602                 
603                 lw->nloglines = lw->logsize = 0;
604                 lw->loglines = MEM_mallocN(sizeof(*lw->loglines) * lw->nloglines, "loglines");
605                 
606                 lw->scroll = scrollbar_new(2, 40);
607                 
608                 GHOST_SetWindowUserData(lw->win, windowdata_new(lw, loggerwindow_handle));
609
610                 loggerwindow_do_reshape(lw);
611
612                 return lw;
613         }
614         else {
615                 return NULL;
616         }
617 }
618
619 void loggerwindow_log(LoggerWindow *lw, char *line)
620 {
621         if (lw->nloglines == lw->logsize) {
622                 lw->loglines = memdbl(lw->loglines, &lw->logsize, sizeof(*lw->loglines));
623         }
624         
625         lw->loglines[lw->nloglines++] = string_dup(line);
626         scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines / lw->nloglines);
627         
628         GHOST_InvalidateWindow(lw->win);
629 }
630
631 void loggerwindow_free(LoggerWindow *lw)
632 {
633         GHOST_SystemHandle sys = multitestapp_get_system(lw->app);
634         int i;
635
636         for (i = 0; i < lw->nloglines; i++) {
637                 MEM_freeN(lw->loglines[i]);
638         }
639         MEM_freeN(lw->loglines);
640         
641         windowdata_free(GHOST_GetWindowUserData(lw->win));
642         GHOST_DisposeWindow(sys, lw->win);
643         MEM_freeN(lw);
644 }
645
646 /*
647  * ExtraWindow
648  */
649
650
651 typedef struct {
652         MultiTestApp        *app;
653
654         GHOST_WindowHandle win;
655         
656         int size[2];
657 } ExtraWindow;
658
659 static void extrawindow_do_draw(ExtraWindow *ew) {
660         GHOST_ActivateWindowDrawingContext(ew->win);
661
662         glClearColor(1, 1, 1, 1);
663         glClear(GL_COLOR_BUFFER_BIT);
664         
665         glColor3f(0.8, 0.8, 0.8);
666         glRecti(10, 10, ew->size[0] - 10, ew->size[1] - 10);
667         
668         GHOST_SwapWindowBuffers(ew->win);
669 }
670
671 static void extrawindow_do_reshape(ExtraWindow *ew) {
672         GHOST_RectangleHandle bounds = GHOST_GetClientBounds(ew->win);
673
674         GHOST_ActivateWindowDrawingContext(ew->win);
675
676         ew->size[0] = GHOST_GetWidthRectangle(bounds);
677         ew->size[1] = GHOST_GetHeightRectangle(bounds);
678         
679         glViewport(0, 0, ew->size[0], ew->size[1]);
680
681         glMatrixMode(GL_PROJECTION);
682         glLoadIdentity();
683         glOrtho(0, ew->size[0], 0, ew->size[1], -1, 1);
684         glTranslatef(0.375, 0.375, 0.0);
685
686         glMatrixMode(GL_MODELVIEW);
687         glLoadIdentity();
688 }
689
690 static void extrawindow_do_key(ExtraWindow *ew, GHOST_TKey key, int press) {
691         switch (key) {
692                 case GHOST_kKeyE:
693                         if (press)
694                                 multitestapp_toggle_extra_window(ew->app);
695                         break;
696         }
697 }
698
699 static void extrawindow_spin_cursor(ExtraWindow *ew, GHOST_TUns64 time) {
700         GHOST_TUns8 bitmap[16][2];
701         GHOST_TUns8 mask[16][2];
702         double ftime = (double) ((GHOST_TInt64) time) / 1000;
703         float angle = fmod(ftime, 1.0) * 3.1415 * 2;
704         int i;
705         
706         memset(&bitmap, 0, sizeof(bitmap));
707         memset(&mask, 0, sizeof(mask));
708         
709         bitmap[0][0] |= mask[0][0] |= 0xF;
710         bitmap[1][0] |= mask[1][0] |= 0xF;
711         bitmap[2][0] |= mask[2][0] |= 0xF;
712         bitmap[3][0] |= mask[3][0] |= 0xF;
713         
714         for (i = 0; i < 7; i++) {
715                 int x = 7 + cos(angle) * i;
716                 int y = 7 + sin(angle) * i;
717
718                 mask[y][x / 8] |= (1 << (x % 8));
719         }
720         for (i = 0; i < 64; i++) {
721                 float v = (i / 63.0) * 3.1415 * 2;
722                 int x = 7 + cos(v) * 7;
723                 int y = 7 + sin(v) * 7;
724                 
725                 mask[y][x / 8] |= (1 << (x % 8));
726         }
727         
728         GHOST_SetCustomCursorShape(ew->win, bitmap, mask, 0, 0);
729 }
730
731 static void extrawindow_handle(void *priv, GHOST_EventHandle evt) {
732         ExtraWindow *ew = priv;
733         GHOST_TEventType type = GHOST_GetEventType(evt);
734         char buf[256];
735         
736         event_to_buf(evt, buf);
737         loggerwindow_log(multitestapp_get_logger(ew->app), buf);
738         
739         switch (type) {
740                 case GHOST_kEventKeyDown:
741                 case GHOST_kEventKeyUp: {
742                         GHOST_TEventKeyData *kd = GHOST_GetEventData(evt);
743                         extrawindow_do_key(ew, kd->key, (type == GHOST_kEventKeyDown));
744                         break;
745                 }
746
747                 case GHOST_kEventCursorMove: {
748                         extrawindow_spin_cursor(ew, GHOST_GetEventTime(evt));
749                         break;
750                 }
751
752                 case GHOST_kEventWindowClose:
753                         multitestapp_free_extrawindow(ew->app);
754                         break;
755                 case GHOST_kEventWindowUpdate:
756                         extrawindow_do_draw(ew);
757                         break;
758                 case GHOST_kEventWindowSize:
759                         extrawindow_do_reshape(ew);
760                         break;
761         }
762 }
763
764 /**/
765
766 ExtraWindow *extrawindow_new(MultiTestApp *app) {
767         GHOST_SystemHandle sys = multitestapp_get_system(app);
768         GHOST_WindowHandle win;
769         
770         win = GHOST_CreateWindow(sys, "MultiTest:Extra", 500, 40, 400, 400,
771                                  GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL,
772                                  FALSE, FALSE);
773         
774         if (win) {
775                 ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new");
776                 ew->app = app;
777                 ew->win = win;
778                 
779                 GHOST_SetWindowUserData(ew->win, windowdata_new(ew, extrawindow_handle));
780                 
781                 return ew;
782         }
783         else {
784                 return NULL;
785         }
786 }
787
788 void extrawindow_free(ExtraWindow *ew) {
789         GHOST_SystemHandle sys = multitestapp_get_system(ew->app);
790
791         windowdata_free(GHOST_GetWindowUserData(ew->win));
792         GHOST_DisposeWindow(sys, ew->win);
793         MEM_freeN(ew);
794 }
795
796 /*
797  * MultiTestApp
798  */
799         
800 struct _MultiTestApp {
801         GHOST_SystemHandle sys;
802         MainWindow          *main;
803         LoggerWindow        *logger;
804         ExtraWindow         *extra;
805         
806         int exit;
807 };
808
809 static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr data) {
810         MultiTestApp *app = data;
811         GHOST_WindowHandle win;
812         
813         win = GHOST_GetEventWindow(evt);
814         if (win && !GHOST_ValidWindow(app->sys, win)) {
815                 loggerwindow_log(app->logger, "WARNING: bad event, non-valid window\n");
816                 return 1;
817         }
818                 
819         if (win) {
820                 WindowData *wb = GHOST_GetWindowUserData(win);
821                 
822                 windowdata_handle(wb, evt);
823         }
824         else {
825                 GHOST_TEventType type = GHOST_GetEventType(evt);
826                         
827                 /* GHOST_kEventQuit are the only 'system' events,
828                  * that is, events without a window.
829                  */
830                 switch (type) {
831                         case GHOST_kEventQuit:
832                                 app->exit = 1;
833                                 break;
834
835                         default:
836                                 fatal("Unhandled system event: %d (%s)\n", type, eventtype_to_string(type));
837                                 break;
838                 }
839         }
840         
841         return 1;
842 }
843
844 /**/
845
846 MultiTestApp *multitestapp_new(void) {
847         MultiTestApp *app = MEM_mallocN(sizeof(*app), "multitestapp_new");
848         GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(multitest_event_handler, app);
849
850         app->sys = GHOST_CreateSystem();
851         if (!app->sys)
852                 fatal("Unable to create ghost system");
853
854         if (!GHOST_AddEventConsumer(app->sys, consumer))        
855                 fatal("Unable to add multitest event consumer ");
856                 
857         app->main = mainwindow_new(app);
858         if (!app->main) 
859                 fatal("Unable to create main window");
860                 
861         app->logger = loggerwindow_new(app);
862         if (!app->logger)
863                 fatal("Unable to create logger window");
864
865         app->extra = NULL;
866         app->exit = 0;
867         
868         return app;
869 }
870
871 LoggerWindow *multitestapp_get_logger(MultiTestApp *app) {
872         return app->logger;     
873 }
874
875 GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app) {
876         return app->sys;
877 }
878
879 void multitestapp_free_extrawindow(MultiTestApp *app) {
880         extrawindow_free(app->extra);
881         app->extra = NULL;
882 }
883
884 void multitestapp_toggle_extra_window(MultiTestApp *app) {
885         if (app->extra) {
886                 multitestapp_free_extrawindow(app);
887         }
888         else {
889                 app->extra = extrawindow_new(app);
890         }
891 }
892
893 void multitestapp_exit(MultiTestApp *app)
894 {
895         app->exit = 1;
896 }
897
898 void multitestapp_run(MultiTestApp *app)
899 {
900         while (!app->exit) {
901                 GHOST_ProcessEvents(app->sys, 1);
902                 GHOST_DispatchEvents(app->sys);
903         }
904 }
905
906 void multitestapp_free(MultiTestApp *app)
907 {
908         mainwindow_free(app->main);
909         loggerwindow_free(app->logger);
910         GHOST_DisposeSystem(app->sys);
911         MEM_freeN(app);
912 }
913
914 /***/
915         
916 int main(int argc, char **argv)
917 {
918 #ifndef USE_BMF
919         BLF_init(11, 72);
920 #endif
921
922         MultiTestApp *app = multitestapp_new();
923         
924         multitestapp_run(app);
925         multitestapp_free(app);
926         
927         return 0;
928 }