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