1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry (AGG) - Version 2.5
3 // A high quality rendering engine for C++
4 // Copyright (C) 2002-2006 Maxim Shemanarev
5 // Copyright (C) 2003 Hansruedi Baer (MacOS support, baer@karto.baug.eth.ch)
6 // Contact: mcseem@antigrain.com
7 //          mcseemagg@yahoo.com
8 //          http://antigrain.com
9 //
10 // AGG is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License
12 // as published by the Free Software Foundation; either version 2
13 // of the License, or (at your option) any later version.
14 //
15 // AGG is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with AGG; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 // MA 02110-1301, USA.
24 //----------------------------------------------------------------------------
25 //
26 // Note from Hansruedi Baer:
27 // I tried to retain the original structure for the Win32 platform as far
28 // as possible. Currently, not all features are implemented but the examples
29 // should work properly.
30 // HB
31 //----------------------------------------------------------------------------
32 
33 #include <Carbon.h>
34 #if defined(__MWERKS__)
35 #include "console.h"
36 #endif
37 #include <string.h>
38 #include <unistd.h>
39 #include "platform/agg_platform_support.h"
40 #include "platform/mac/agg_mac_pmap.h"
41 #include "util/agg_color_conv_rgb8.h"
42 
43 
44 namespace agg
45 {
46 
47 pascal OSStatus DoWindowClose (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData);
48 pascal OSStatus DoWindowDrawContent (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData);
49 pascal OSStatus DoAppQuit (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData);
50 pascal OSStatus DoMouseDown (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData);
51 pascal OSStatus DoMouseUp (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData);
52 pascal OSStatus DoMouseDragged (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData);
53 pascal OSStatus DoKeyDown (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData);
54 pascal OSStatus DoKeyUp (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData);
55 pascal void DoPeriodicTask (EventLoopTimerRef theTimer, void* userData);
56 
57 
58     //------------------------------------------------------------------------
59     class platform_specific
60     {
61     public:
62         platform_specific(pix_format_e format, bool flip_y);
63 
64         void create_pmap(unsigned width, unsigned height,
65                          rendering_buffer* wnd);
66 
67         void display_pmap(WindowRef window, const rendering_buffer* src);
68         bool load_pmap(const char* fn, unsigned idx,
69                        rendering_buffer* dst);
70 
71         bool save_pmap(const char* fn, unsigned idx,
72                        const rendering_buffer* src);
73 
74         unsigned translate(unsigned keycode);
75 
76         pix_format_e     m_format;
77         pix_format_e     m_sys_format;
78         bool             m_flip_y;
79         unsigned         m_bpp;
80         unsigned         m_sys_bpp;
81         WindowRef        m_window;
82         pixel_map   	 m_pmap_window;
83         pixel_map        m_pmap_img[platform_support::max_images];
84         unsigned         m_keymap[256];
85         unsigned         m_last_translated_key;
86         int              m_cur_x;
87         int              m_cur_y;
88         unsigned         m_input_flags;
89         bool             m_redraw_flag;
90         UnsignedWide     m_sw_freq;
91         UnsignedWide     m_sw_start;
92     };
93 
94 
95     //------------------------------------------------------------------------
platform_specific(pix_format_e format,bool flip_y)96     platform_specific::platform_specific(pix_format_e format, bool flip_y) :
97        	m_format(format),
98         m_sys_format(pix_format_undefined),
99         m_flip_y(flip_y),
100         m_bpp(0),
101         m_sys_bpp(0),
102         m_window(nil),
103         m_last_translated_key(0),
104         m_cur_x(0),
105         m_cur_y(0),
106         m_input_flags(0),
107         m_redraw_flag(true)
108     {
109         memset(m_keymap, 0, sizeof(m_keymap));
110 
111         //Keyboard input is not yet fully supported nor tested
112         //m_keymap[VK_PAUSE]       = key_pause;
113         m_keymap[kClearCharCode]      = key_clear;
114 
115         //m_keymap[VK_NUMPAD0]    = key_kp0;
116         //m_keymap[VK_NUMPAD1]    = key_kp1;
117         //m_keymap[VK_NUMPAD2]    = key_kp2;
118         //m_keymap[VK_NUMPAD3]    = key_kp3;
119         //m_keymap[VK_NUMPAD4]    = key_kp4;
120         //m_keymap[VK_NUMPAD5]    = key_kp5;
121         //m_keymap[VK_NUMPAD6]    = key_kp6;
122         //m_keymap[VK_NUMPAD7]    = key_kp7;
123         //m_keymap[VK_NUMPAD8]    = key_kp8;
124         //m_keymap[VK_NUMPAD9]    = key_kp9;
125         //m_keymap[VK_DECIMAL]    = key_kp_period;
126         //m_keymap[VK_DIVIDE]     = key_kp_divide;
127         //m_keymap[VK_MULTIPLY]   = key_kp_multiply;
128         //m_keymap[VK_SUBTRACT]   = key_kp_minus;
129         //m_keymap[VK_ADD]        = key_kp_plus;
130 
131         m_keymap[kUpArrowCharCode]    = key_up;
132         m_keymap[kDownArrowCharCode]  = key_down;
133         m_keymap[kRightArrowCharCode] = key_right;
134         m_keymap[kLeftArrowCharCode]  = key_left;
135         //m_keymap[VK_INSERT]     = key_insert;
136         m_keymap[kDeleteCharCode]     = key_delete;
137         m_keymap[kHomeCharCode]       = key_home;
138         m_keymap[kEndCharCode]        = key_end;
139         m_keymap[kPageUpCharCode]     = key_page_up;
140         m_keymap[kPageDownCharCode]   = key_page_down;
141 
142         //m_keymap[VK_F1]         = key_f1;
143         //m_keymap[VK_F2]         = key_f2;
144         //m_keymap[VK_F3]         = key_f3;
145         //m_keymap[VK_F4]         = key_f4;
146         //m_keymap[VK_F5]         = key_f5;
147         //m_keymap[VK_F6]         = key_f6;
148         //m_keymap[VK_F7]         = key_f7;
149         //m_keymap[VK_F8]         = key_f8;
150         //m_keymap[VK_F9]         = key_f9;
151         //m_keymap[VK_F10]        = key_f10;
152         //m_keymap[VK_F11]        = key_f11;
153         //m_keymap[VK_F12]        = key_f12;
154         //m_keymap[VK_F13]        = key_f13;
155         //m_keymap[VK_F14]        = key_f14;
156         //m_keymap[VK_F15]        = key_f15;
157 
158         //m_keymap[VK_NUMLOCK]    = key_numlock;
159         //m_keymap[VK_CAPITAL]    = key_capslock;
160         //m_keymap[VK_SCROLL]     = key_scrollock;
161 
162         switch(m_format)
163         {
164         case pix_format_gray8:
165             m_sys_format = pix_format_gray8;
166             m_bpp = 8;
167             m_sys_bpp = 8;
168             break;
169 
170         case pix_format_rgb565:
171         case pix_format_rgb555:
172             m_sys_format = pix_format_rgb555;
173             m_bpp = 16;
174             m_sys_bpp = 16;
175             break;
176 
177         case pix_format_rgb24:
178         case pix_format_bgr24:
179             m_sys_format = pix_format_rgb24;
180             m_bpp = 24;
181             m_sys_bpp = 24;
182             break;
183 
184         case pix_format_bgra32:
185         case pix_format_abgr32:
186         case pix_format_argb32:
187         case pix_format_rgba32:
188             m_sys_format = pix_format_argb32;
189             m_bpp = 32;
190             m_sys_bpp = 32;
191             break;
192         }
193         ::Microseconds(&m_sw_freq);
194         ::Microseconds(&m_sw_start);
195     }
196 
197 
198     //------------------------------------------------------------------------
create_pmap(unsigned width,unsigned height,rendering_buffer * wnd)199     void platform_specific::create_pmap(unsigned width,
200                                         unsigned height,
201                                         rendering_buffer* wnd)
202     {
203         m_pmap_window.create(width, height, org_e(m_bpp));
204         wnd->attach(m_pmap_window.buf(),
205                     m_pmap_window.width(),
206                     m_pmap_window.height(),
207                       m_flip_y ?
208                      -m_pmap_window.row_bytes() :
209                       m_pmap_window.row_bytes());
210     }
211 
212 
213     //------------------------------------------------------------------------
display_pmap(WindowRef window,const rendering_buffer * src)214     void platform_specific::display_pmap(WindowRef window, const rendering_buffer* src)
215     {
216         if(m_sys_format == m_format)
217         {
218             m_pmap_window.draw(window);
219         }
220         else
221         {
222             pixel_map pmap_tmp;
223             pmap_tmp.create(m_pmap_window.width(),
224                             m_pmap_window.height(),
225                             org_e(m_sys_bpp));
226 
227             rendering_buffer rbuf_tmp;
228             rbuf_tmp.attach(pmap_tmp.buf(),
229                             pmap_tmp.width(),
230                             pmap_tmp.height(),
231                             m_flip_y ?
232                              -pmap_tmp.row_bytes() :
233                               pmap_tmp.row_bytes());
234 
235             switch(m_format)
236             {
237             case pix_format_gray8:
238                 return;
239 
240             case pix_format_rgb565:
241                 color_conv(&rbuf_tmp, src, color_conv_rgb565_to_rgb555());
242                 break;
243 
244             case pix_format_bgr24:
245                 color_conv(&rbuf_tmp, src, color_conv_bgr24_to_rgb24());
246                 break;
247 
248             case pix_format_abgr32:
249                 color_conv(&rbuf_tmp, src, color_conv_abgr32_to_argb32());
250                 break;
251 
252             case pix_format_bgra32:
253                 color_conv(&rbuf_tmp, src, color_conv_bgra32_to_argb32());
254                 break;
255 
256             case pix_format_rgba32:
257                 color_conv(&rbuf_tmp, src, color_conv_rgba32_to_argb32());
258                 break;
259             }
260             pmap_tmp.draw(window);
261         }
262     }
263 
264 
265     //------------------------------------------------------------------------
save_pmap(const char * fn,unsigned idx,const rendering_buffer * src)266     bool platform_specific::save_pmap(const char* fn, unsigned idx,
267                                       const rendering_buffer* src)
268     {
269         if(m_sys_format == m_format)
270         {
271             return m_pmap_img[idx].save_as_qt(fn);
272         }
273         else
274         {
275             pixel_map pmap_tmp;
276             pmap_tmp.create(m_pmap_img[idx].width(),
277                             m_pmap_img[idx].height(),
278                             org_e(m_sys_bpp));
279 
280             rendering_buffer rbuf_tmp;
281             rbuf_tmp.attach(pmap_tmp.buf(),
282                             pmap_tmp.width(),
283                             pmap_tmp.height(),
284                             m_flip_y ?
285                              -pmap_tmp.row_bytes() :
286                               pmap_tmp.row_bytes());
287             switch(m_format)
288             {
289             case pix_format_gray8:
290                 return false;
291 
292             case pix_format_rgb565:
293                 color_conv(&rbuf_tmp, src, color_conv_rgb565_to_rgb555());
294                 break;
295 
296             case pix_format_rgb24:
297                 color_conv(&rbuf_tmp, src, color_conv_rgb24_to_bgr24());
298                 break;
299 
300             case pix_format_abgr32:
301                 color_conv(&rbuf_tmp, src, color_conv_abgr32_to_bgra32());
302                 break;
303 
304             case pix_format_argb32:
305                 color_conv(&rbuf_tmp, src, color_conv_argb32_to_bgra32());
306                 break;
307 
308             case pix_format_rgba32:
309                 color_conv(&rbuf_tmp, src, color_conv_rgba32_to_bgra32());
310                 break;
311             }
312             return pmap_tmp.save_as_qt(fn);
313         }
314         return true;
315     }
316 
317 
318 
319     //------------------------------------------------------------------------
load_pmap(const char * fn,unsigned idx,rendering_buffer * dst)320     bool platform_specific::load_pmap(const char* fn, unsigned idx,
321                                       rendering_buffer* dst)
322     {
323         pixel_map pmap_tmp;
324         if(!pmap_tmp.load_from_qt(fn)) return false;
325 
326         rendering_buffer rbuf_tmp;
327         rbuf_tmp.attach(pmap_tmp.buf(),
328                         pmap_tmp.width(),
329                         pmap_tmp.height(),
330                         m_flip_y ?
331                          -pmap_tmp.row_bytes() :
332                           pmap_tmp.row_bytes());
333 
334         m_pmap_img[idx].create(pmap_tmp.width(),
335                                pmap_tmp.height(),
336                                org_e(m_bpp),
337                                0);
338 
339         dst->attach(m_pmap_img[idx].buf(),
340                     m_pmap_img[idx].width(),
341                     m_pmap_img[idx].height(),
342                     m_flip_y ?
343                       -m_pmap_img[idx].row_bytes() :
344                        m_pmap_img[idx].row_bytes());
345 
346         switch(m_format)
347         {
348         case pix_format_gray8:
349             return false;
350             break;
351 
352         case pix_format_rgb555:
353             switch(pmap_tmp.bpp())
354             {
355             case 16: color_conv(dst, &rbuf_tmp, color_conv_rgb555_to_rgb555()); break;
356             case 24: color_conv(dst, &rbuf_tmp, color_conv_rgb24_to_rgb555()); break;
357             case 32: color_conv(dst, &rbuf_tmp, color_conv_argb32_to_rgb555()); break;
358             }
359             break;
360 
361         case pix_format_rgb565:
362             switch(pmap_tmp.bpp())
363             {
364             case 16: color_conv(dst, &rbuf_tmp, color_conv_rgb555_to_rgb565()); break;
365             case 24: color_conv(dst, &rbuf_tmp, color_conv_rgb24_to_rgb565()); break;
366             case 32: color_conv(dst, &rbuf_tmp, color_conv_argb32_to_rgb565()); break;
367             }
368             break;
369 
370         case pix_format_rgb24:
371             switch(pmap_tmp.bpp())
372             {
373             case 16: color_conv(dst, &rbuf_tmp, color_conv_rgb555_to_rgb24()); break;
374             case 24: color_conv(dst, &rbuf_tmp, color_conv_rgb24_to_rgb24()); break;
375             case 32: color_conv(dst, &rbuf_tmp, color_conv_argb32_to_rgb24()); break;
376             }
377             break;
378 
379         case pix_format_bgr24:
380             switch(pmap_tmp.bpp())
381             {
382             case 16: color_conv(dst, &rbuf_tmp, color_conv_rgb555_to_bgr24()); break;
383             case 24: color_conv(dst, &rbuf_tmp, color_conv_rgb24_to_bgr24()); break;
384             case 32: color_conv(dst, &rbuf_tmp, color_conv_argb32_to_bgr24()); break;
385             }
386             break;
387 
388         case pix_format_abgr32:
389             switch(pmap_tmp.bpp())
390             {
391             case 16: color_conv(dst, &rbuf_tmp, color_conv_rgb555_to_abgr32()); break;
392             case 24: color_conv(dst, &rbuf_tmp, color_conv_rgb24_to_abgr32()); break;
393             case 32: color_conv(dst, &rbuf_tmp, color_conv_argb32_to_abgr32()); break;
394             }
395             break;
396 
397         case pix_format_argb32:
398             switch(pmap_tmp.bpp())
399             {
400             case 16: color_conv(dst, &rbuf_tmp, color_conv_rgb555_to_argb32()); break;
401             case 24: color_conv(dst, &rbuf_tmp, color_conv_rgb24_to_argb32()); break;
402             case 32: color_conv(dst, &rbuf_tmp, color_conv_argb32_to_argb32()); break;
403             }
404             break;
405 
406         case pix_format_bgra32:
407             switch(pmap_tmp.bpp())
408             {
409             case 16: color_conv(dst, &rbuf_tmp, color_conv_rgb555_to_bgra32()); break;
410             case 24: color_conv(dst, &rbuf_tmp, color_conv_rgb24_to_bgra32()); break;
411             case 32: color_conv(dst, &rbuf_tmp, color_conv_argb32_to_bgra32()); break;
412             }
413             break;
414 
415         case pix_format_rgba32:
416             switch(pmap_tmp.bpp())
417             {
418             case 16: color_conv(dst, &rbuf_tmp, color_conv_rgb555_to_rgba32()); break;
419             case 24: color_conv(dst, &rbuf_tmp, color_conv_rgb24_to_rgba32()); break;
420             case 32: color_conv(dst, &rbuf_tmp, color_conv_argb32_to_rgba32()); break;
421             }
422             break;
423         }
424 
425         return true;
426     }
427 
428 
429 
430 
431 
432 
433 
434 
435     //------------------------------------------------------------------------
translate(unsigned keycode)436     unsigned platform_specific::translate(unsigned keycode)
437     {
438         return m_last_translated_key = (keycode > 255) ? 0 : m_keymap[keycode];
439     }
440 
441 
442 
443     //------------------------------------------------------------------------
platform_support(pix_format_e format,bool flip_y)444     platform_support::platform_support(pix_format_e format, bool flip_y) :
445         m_specific(new platform_specific(format, flip_y)),
446         m_format(format),
447         m_bpp(m_specific->m_bpp),
448         m_window_flags(0),
449         m_wait_mode(true),
450         m_flip_y(flip_y),
451         m_initial_width(10),
452         m_initial_height(10)
453     {
454         strcpy(m_caption, "Anti-Grain Geometry Application");
455     }
456 
457 
458     //------------------------------------------------------------------------
~platform_support()459     platform_support::~platform_support()
460     {
461         delete m_specific;
462     }
463 
464 
465 
466     //------------------------------------------------------------------------
caption(const char * cap)467     void platform_support::caption(const char* cap)
468     {
469         strcpy(m_caption, cap);
470         if(m_specific->m_window)
471         {
472         	SetWindowTitleWithCFString (m_specific->m_window, CFStringCreateWithCStringNoCopy (nil, cap, kCFStringEncodingASCII, nil));
473         }
474     }
475 
476 
477 
478     //------------------------------------------------------------------------
get_key_flags(UInt32 wflags)479     static unsigned get_key_flags(UInt32 wflags)
480     {
481         unsigned flags = 0;
482 
483          if(wflags & shiftKey)   flags |= kbd_shift;
484          if(wflags & controlKey) flags |= kbd_ctrl;
485 
486         return flags;
487     }
488 
489 
490     //------------------------------------------------------------------------
message(const char * msg)491     void platform_support::message(const char* msg)
492     {
493 		SInt16 item;
494 		Str255 p_msg;
495 
496 		::CopyCStringToPascal (msg, p_msg);
497 		::StandardAlert (kAlertPlainAlert, (const unsigned char*) "\013AGG Message", p_msg, NULL, &item);
498 		//::StandardAlert (kAlertPlainAlert, (const unsigned char*) "\pAGG Message", p_msg, NULL, &item);
499     }
500 
501 
502     //------------------------------------------------------------------------
start_timer()503     void platform_support::start_timer()
504     {
505 		::Microseconds (&(m_specific->m_sw_start));
506     }
507 
508 
509     //------------------------------------------------------------------------
elapsed_time() const510     double platform_support::elapsed_time() const
511     {
512         UnsignedWide stop;
513         ::Microseconds(&stop);
514         return double(stop.lo -
515                       m_specific->m_sw_start.lo) * 1e6 /
516                       double(m_specific->m_sw_freq.lo);
517     }
518 
519 
520     //------------------------------------------------------------------------
init(unsigned width,unsigned height,unsigned flags)521     bool platform_support::init(unsigned width, unsigned height, unsigned flags)
522     {
523         if(m_specific->m_sys_format == pix_format_undefined)
524         {
525             return false;
526         }
527 
528         m_window_flags = flags;
529 
530 		// application
531 		EventTypeSpec		eventType;
532 		EventHandlerUPP		handlerUPP;
533 
534 		eventType.eventClass = kEventClassApplication;
535 		eventType.eventKind = kEventAppQuit;
536 
537 		handlerUPP = NewEventHandlerUPP(DoAppQuit);
538 
539 		InstallApplicationEventHandler (handlerUPP, 1, &eventType, nil, nil);
540 
541 		eventType.eventClass = kEventClassMouse;
542 		eventType.eventKind = kEventMouseDown;
543 		handlerUPP = NewEventHandlerUPP(DoMouseDown);
544 		InstallApplicationEventHandler (handlerUPP, 1, &eventType, this, nil);
545 
546 		eventType.eventKind = kEventMouseUp;
547 		handlerUPP = NewEventHandlerUPP(DoMouseUp);
548 		InstallApplicationEventHandler (handlerUPP, 1, &eventType, this, nil);
549 
550 		eventType.eventKind = kEventMouseDragged;
551 		handlerUPP = NewEventHandlerUPP(DoMouseDragged);
552 		InstallApplicationEventHandler (handlerUPP, 1, &eventType, this, nil);
553 
554 		eventType.eventClass = kEventClassKeyboard;
555 		eventType.eventKind = kEventRawKeyDown;
556 		handlerUPP = NewEventHandlerUPP(DoKeyDown);
557 		InstallApplicationEventHandler (handlerUPP, 1, &eventType, this, nil);
558 
559 		eventType.eventKind = kEventRawKeyUp;
560 		handlerUPP = NewEventHandlerUPP(DoKeyUp);
561 		InstallApplicationEventHandler (handlerUPP, 1, &eventType, this, nil);
562 
563 		eventType.eventKind = kEventRawKeyRepeat;
564 		handlerUPP = NewEventHandlerUPP(DoKeyDown);		// 'key repeat' is translated to 'key down'
565 		InstallApplicationEventHandler (handlerUPP, 1, &eventType, this, nil);
566 
567 		WindowAttributes	windowAttrs;
568 		Rect				bounds;
569 
570 		// window
571 		windowAttrs = kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute;
572 		SetRect (&bounds, 0, 0, width, height);
573 		OffsetRect (&bounds, 100, 100);
574 		CreateNewWindow (kDocumentWindowClass, windowAttrs, &bounds, &m_specific->m_window);
575 
576         if(m_specific->m_window == nil)
577         {
578             return false;
579         }
580 
581 		// I assume the text is ASCII.
582 		// Change to kCFStringEncodingMacRoman, kCFStringEncodingISOLatin1, kCFStringEncodingUTF8 or what else you need.
583         SetWindowTitleWithCFString (m_specific->m_window, CFStringCreateWithCStringNoCopy (nil, m_caption, kCFStringEncodingASCII, nil));
584 
585 		eventType.eventClass = kEventClassWindow;
586 		eventType.eventKind = kEventWindowClose;
587 
588 		handlerUPP = NewEventHandlerUPP(DoWindowClose);
589 		InstallWindowEventHandler (m_specific->m_window, handlerUPP, 1, &eventType, this, NULL);
590 
591 		eventType.eventKind = kEventWindowDrawContent;
592 		handlerUPP = NewEventHandlerUPP(DoWindowDrawContent);
593 		InstallWindowEventHandler (m_specific->m_window, handlerUPP, 1, &eventType, this, NULL);
594 
595 		// Periodic task
596 		// Instead of an idle function I use the Carbon event timer.
597 		// You may decide to change the wait value which is currently 50 milliseconds.
598 		EventLoopRef		mainLoop;
599 		EventLoopTimerUPP	timerUPP;
600 		EventLoopTimerRef	theTimer;
601 
602 		mainLoop = GetMainEventLoop();
603 		timerUPP = NewEventLoopTimerUPP (DoPeriodicTask);
604 		InstallEventLoopTimer (mainLoop, 0, 50 * kEventDurationMillisecond, timerUPP, this, &theTimer);
605 
606         m_specific->create_pmap(width, height, &m_rbuf_window);
607         m_initial_width = width;
608         m_initial_height = height;
609         on_init();
610         on_resize(width, height);
611         m_specific->m_redraw_flag = true;
612 
613   		ShowWindow (m_specific->m_window);
614   		SetPortWindowPort (m_specific->m_window);
615 
616       return true;
617     }
618 
619 
620     //------------------------------------------------------------------------
run()621     int platform_support::run()
622     {
623 
624 		RunApplicationEventLoop ();
625         return true;
626     }
627 
628 
629     //------------------------------------------------------------------------
img_ext() const630     const char* platform_support::img_ext() const { return ".bmp"; }
631 
632     //------------------------------------------------------------------------
full_file_name(const char * file_name)633     const char* platform_support::full_file_name(const char* file_name)
634     {
635         return file_name;
636     }
637 
638     //------------------------------------------------------------------------
load_img(unsigned idx,const char * file)639     bool platform_support::load_img(unsigned idx, const char* file)
640     {
641         if(idx < max_images)
642         {
643             char fn[1024];
644             strcpy(fn, file);
645             int len = strlen(fn);
646 #if defined(__MWERKS__)
647             if(len < 4 || stricmp(fn + len - 4, ".BMP") != 0)
648 #else
649 	        if(len < 4 || strncasecmp(fn + len - 4, ".BMP", 4) != 0)
650 #endif
651             {
652                 strcat(fn, ".bmp");
653             }
654             return m_specific->load_pmap(fn, idx, &m_rbuf_img[idx]);
655         }
656         return true;
657     }
658 
659 
660 
661     //------------------------------------------------------------------------
save_img(unsigned idx,const char * file)662     bool platform_support::save_img(unsigned idx, const char* file)
663     {
664         if(idx < max_images)
665         {
666             char fn[1024];
667             strcpy(fn, file);
668             int len = strlen(fn);
669 #if defined(__MWERKS__)
670             if(len < 4 || stricmp(fn + len - 4, ".BMP") != 0)
671 #else
672 	        if(len < 4 || strncasecmp(fn + len - 4, ".BMP", 4) != 0)
673 #endif
674             {
675                 strcat(fn, ".bmp");
676             }
677             return m_specific->save_pmap(fn, idx, &m_rbuf_img[idx]);
678         }
679         return true;
680     }
681 
682 
683 
684     //------------------------------------------------------------------------
create_img(unsigned idx,unsigned width,unsigned height)685     bool platform_support::create_img(unsigned idx, unsigned width, unsigned height)
686     {
687         if(idx < max_images)
688         {
689             if(width  == 0) width  = m_specific->m_pmap_window.width();
690             if(height == 0) height = m_specific->m_pmap_window.height();
691             m_specific->m_pmap_img[idx].create(width, height, org_e(m_specific->m_bpp));
692             m_rbuf_img[idx].attach(m_specific->m_pmap_img[idx].buf(),
693                                    m_specific->m_pmap_img[idx].width(),
694                                    m_specific->m_pmap_img[idx].height(),
695                                    m_flip_y ?
696                                    -m_specific->m_pmap_img[idx].row_bytes() :
697                                     m_specific->m_pmap_img[idx].row_bytes());
698             return true;
699         }
700         return false;
701     }
702 
703 
704     //------------------------------------------------------------------------
force_redraw()705     void platform_support::force_redraw()
706     {
707     	Rect	bounds;
708 
709         m_specific->m_redraw_flag = true;
710         // on_ctrl_change ();
711 		on_draw();
712 
713     	SetRect(&bounds, 0, 0, m_rbuf_window.width(), m_rbuf_window.height());
714     	InvalWindowRect(m_specific->m_window, &bounds);
715     }
716 
717 
718 
719     //------------------------------------------------------------------------
update_window()720     void platform_support::update_window()
721     {
722         m_specific->display_pmap(m_specific->m_window, &m_rbuf_window);
723     }
724 
725 
726     //------------------------------------------------------------------------
on_init()727     void platform_support::on_init() {}
on_resize(int sx,int sy)728     void platform_support::on_resize(int sx, int sy) {}
on_idle()729     void platform_support::on_idle() {}
on_mouse_move(int x,int y,unsigned flags)730     void platform_support::on_mouse_move(int x, int y, unsigned flags) {}
on_mouse_button_down(int x,int y,unsigned flags)731     void platform_support::on_mouse_button_down(int x, int y, unsigned flags) {}
on_mouse_button_up(int x,int y,unsigned flags)732     void platform_support::on_mouse_button_up(int x, int y, unsigned flags) {}
on_key(int x,int y,unsigned key,unsigned flags)733     void platform_support::on_key(int x, int y, unsigned key, unsigned flags) {}
on_ctrl_change()734     void platform_support::on_ctrl_change() {}
on_draw()735     void platform_support::on_draw() {}
on_post_draw(void * raw_handler)736     void platform_support::on_post_draw(void* raw_handler) {}
737 
738 
739 //------------------------------------------------------------------------
DoWindowClose(EventHandlerCallRef nextHandler,EventRef theEvent,void * userData)740 pascal OSStatus DoWindowClose (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
741 {
742 	userData;
743 
744 	QuitApplicationEventLoop ();
745 
746 	return CallNextEventHandler (nextHandler, theEvent);
747 }
748 
749 
750 //------------------------------------------------------------------------
DoAppQuit(EventHandlerCallRef nextHandler,EventRef theEvent,void * userData)751 pascal OSStatus DoAppQuit (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
752 {
753 	userData;
754 
755 	return CallNextEventHandler (nextHandler, theEvent);
756 }
757 
758 
759 //------------------------------------------------------------------------
DoMouseDown(EventHandlerCallRef nextHandler,EventRef theEvent,void * userData)760 pascal OSStatus DoMouseDown (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
761 {
762 	Point wheresMyMouse;
763 	UInt32 modifier;
764 
765 	GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &wheresMyMouse);
766 	GlobalToLocal (&wheresMyMouse);
767 	GetEventParameter (theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifier);
768 
769     platform_support * app = reinterpret_cast<platform_support*>(userData);
770 
771     app->m_specific->m_cur_x = wheresMyMouse.h;
772     if(app->flip_y())
773     {
774         app->m_specific->m_cur_y = app->rbuf_window().height() - wheresMyMouse.v;
775     }
776     else
777     {
778         app->m_specific->m_cur_y = wheresMyMouse.v;
779     }
780     app->m_specific->m_input_flags = mouse_left | get_key_flags(modifier);
781 
782     app->m_ctrls.set_cur(app->m_specific->m_cur_x,
783                          app->m_specific->m_cur_y);
784     if(app->m_ctrls.on_mouse_button_down(app->m_specific->m_cur_x,
785                                          app->m_specific->m_cur_y))
786     {
787         app->on_ctrl_change();
788         app->force_redraw();
789     }
790     else
791     {
792         if(app->m_ctrls.in_rect(app->m_specific->m_cur_x,
793                                 app->m_specific->m_cur_y))
794         {
795             if(app->m_ctrls.set_cur(app->m_specific->m_cur_x,
796                                     app->m_specific->m_cur_y))
797             {
798                 app->on_ctrl_change();
799                 app->force_redraw();
800             }
801         }
802         else
803         {
804             app->on_mouse_button_down(app->m_specific->m_cur_x,
805                                       app->m_specific->m_cur_y,
806                                       app->m_specific->m_input_flags);
807         }
808     }
809 
810 	return CallNextEventHandler (nextHandler, theEvent);
811 }
812 
813 
814 //------------------------------------------------------------------------
DoMouseUp(EventHandlerCallRef nextHandler,EventRef theEvent,void * userData)815 pascal OSStatus DoMouseUp (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
816 {
817 	Point wheresMyMouse;
818 	UInt32 modifier;
819 
820 	GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &wheresMyMouse);
821 	GlobalToLocal (&wheresMyMouse);
822 	GetEventParameter (theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifier);
823 
824     platform_support * app = reinterpret_cast<platform_support*>(userData);
825 
826     app->m_specific->m_cur_x = wheresMyMouse.h;
827     if(app->flip_y())
828     {
829         app->m_specific->m_cur_y = app->rbuf_window().height() - wheresMyMouse.v;
830     }
831     else
832     {
833         app->m_specific->m_cur_y = wheresMyMouse.v;
834     }
835     app->m_specific->m_input_flags = mouse_left | get_key_flags(modifier);
836 
837     if(app->m_ctrls.on_mouse_button_up(app->m_specific->m_cur_x,
838                                        app->m_specific->m_cur_y))
839     {
840         app->on_ctrl_change();
841         app->force_redraw();
842     }
843     app->on_mouse_button_up(app->m_specific->m_cur_x,
844                             app->m_specific->m_cur_y,
845                             app->m_specific->m_input_flags);
846 
847 	return CallNextEventHandler (nextHandler, theEvent);
848 }
849 
850 
851 //------------------------------------------------------------------------
DoMouseDragged(EventHandlerCallRef nextHandler,EventRef theEvent,void * userData)852 pascal OSStatus DoMouseDragged (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
853 {
854 	Point wheresMyMouse;
855 	UInt32 modifier;
856 
857 	GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &wheresMyMouse);
858 	GlobalToLocal (&wheresMyMouse);
859 	GetEventParameter (theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifier);
860 
861     platform_support * app = reinterpret_cast<platform_support*>(userData);
862 
863     app->m_specific->m_cur_x = wheresMyMouse.h;
864     if(app->flip_y())
865     {
866         app->m_specific->m_cur_y = app->rbuf_window().height() - wheresMyMouse.v;
867     }
868     else
869     {
870         app->m_specific->m_cur_y = wheresMyMouse.v;
871     }
872     app->m_specific->m_input_flags = mouse_left | get_key_flags(modifier);
873 
874 
875     if(app->m_ctrls.on_mouse_move(
876         app->m_specific->m_cur_x,
877         app->m_specific->m_cur_y,
878         (app->m_specific->m_input_flags & mouse_left) != 0))
879     {
880         app->on_ctrl_change();
881         app->force_redraw();
882     }
883     else
884     {
885         app->on_mouse_move(app->m_specific->m_cur_x,
886                            app->m_specific->m_cur_y,
887                            app->m_specific->m_input_flags);
888     }
889 
890 	return CallNextEventHandler (nextHandler, theEvent);
891 }
892 
893 
894 //------------------------------------------------------------------------
DoKeyDown(EventHandlerCallRef nextHandler,EventRef theEvent,void * userData)895 pascal OSStatus DoKeyDown (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
896 {
897 	char key_code;
898 	UInt32 modifier;
899 
900 	GetEventParameter (theEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &key_code);
901 	GetEventParameter (theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifier);
902 
903 	platform_support * app = reinterpret_cast<platform_support*>(userData);
904 
905 	app->m_specific->m_last_translated_key = 0;
906     switch(modifier)
907     {
908         case controlKey:
909             app->m_specific->m_input_flags |= kbd_ctrl;
910             break;
911 
912         case shiftKey:
913             app->m_specific->m_input_flags |= kbd_shift;
914             break;
915 
916         default:
917             app->m_specific->translate(key_code);
918             break;
919     }
920 
921     if(app->m_specific->m_last_translated_key)
922     {
923         bool left  = false;
924         bool up    = false;
925         bool right = false;
926         bool down  = false;
927 
928         switch(app->m_specific->m_last_translated_key)
929         {
930         case key_left:
931             left = true;
932             break;
933 
934         case key_up:
935             up = true;
936             break;
937 
938         case key_right:
939             right = true;
940             break;
941 
942         case key_down:
943             down = true;
944             break;
945 
946 		//On a Mac, screenshots are handled by the system.
947         case key_f2:
948             app->copy_window_to_img(agg::platform_support::max_images - 1);
949             app->save_img(agg::platform_support::max_images - 1, "screenshot");
950             break;
951         }
952 
953 
954         if(app->m_ctrls.on_arrow_keys(left, right, down, up))
955         {
956             app->on_ctrl_change();
957             app->force_redraw();
958         }
959         else
960         {
961             app->on_key(app->m_specific->m_cur_x,
962                         app->m_specific->m_cur_y,
963                         app->m_specific->m_last_translated_key,
964                         app->m_specific->m_input_flags);
965         }
966     }
967 
968 	return CallNextEventHandler (nextHandler, theEvent);
969 }
970 
971 
972 //------------------------------------------------------------------------
DoKeyUp(EventHandlerCallRef nextHandler,EventRef theEvent,void * userData)973 pascal OSStatus DoKeyUp (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
974 {
975 	char key_code;
976 	UInt32 modifier;
977 
978 	GetEventParameter (theEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &key_code);
979 	GetEventParameter (theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifier);
980 
981 	platform_support * app = reinterpret_cast<platform_support*>(userData);
982 
983     app->m_specific->m_last_translated_key = 0;
984     switch(modifier)
985     {
986         case controlKey:
987             app->m_specific->m_input_flags &= ~kbd_ctrl;
988             break;
989 
990         case shiftKey:
991             app->m_specific->m_input_flags &= ~kbd_shift;
992             break;
993     }
994 
995 	return CallNextEventHandler (nextHandler, theEvent);
996 }
997 
998 
999 //------------------------------------------------------------------------
DoWindowDrawContent(EventHandlerCallRef nextHandler,EventRef theEvent,void * userData)1000 pascal OSStatus DoWindowDrawContent (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
1001 {
1002     platform_support * app = reinterpret_cast<platform_support*>(userData);
1003 
1004     if(app)
1005     {
1006         if(app->m_specific->m_redraw_flag)
1007         {
1008             app->on_draw();
1009             app->m_specific->m_redraw_flag = false;
1010         }
1011         app->m_specific->display_pmap(app->m_specific->m_window, &app->rbuf_window());
1012     }
1013 
1014 	return CallNextEventHandler (nextHandler, theEvent);
1015 }
1016 
1017 
1018 //------------------------------------------------------------------------
DoPeriodicTask(EventLoopTimerRef theTimer,void * userData)1019 pascal void DoPeriodicTask (EventLoopTimerRef theTimer, void* userData)
1020 {
1021     platform_support * app = reinterpret_cast<platform_support*>(userData);
1022 
1023     if(!app->wait_mode())
1024 		app->on_idle();
1025 }
1026 
1027 
1028 }
1029 
1030 
1031 
1032 
1033 //----------------------------------------------------------------------------
1034 int agg_main(int argc, char* argv[]);
1035 
1036 
1037 // Hm. Classic MacOS does not know command line input.
1038 // CodeWarrior provides a way to mimic command line input.
1039 // The function 'ccommand' can be used to get the command
1040 // line arguments.
1041 //----------------------------------------------------------------------------
main(int argc,char * argv[])1042 int main(int argc, char* argv[])
1043 {
1044 #if defined(__MWERKS__)
1045 	// argc = ccommand (&argv);
1046 #endif
1047 
1048     // Check if we are launched by double-clicking under OSX
1049 	// Get rid of extra argument, this will confuse the standard argument parsing
1050 	// calls used in the examples to get the name of the image file to be used
1051     if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
1052         argc = 1;
1053     }
1054 
1055 launch:
1056     return agg_main(argc, argv);
1057 }