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