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) 2004 Steven Solie
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 #include "platform/agg_platform_support.h"
27 #include "util/agg_color_conv_rgb8.h"
28 
29 #include <sys/time.h>
30 #include <cstring>
31 
32 #include <classes/requester.h>
33 #include <classes/window.h>
34 #include <datatypes/pictureclass.h>
35 #include <proto/exec.h>
36 #include <proto/datatypes.h>
37 #include <proto/dos.h>
38 #include <proto/graphics.h>
39 #include <proto/intuition.h>
40 #include <proto/keymap.h>
41 #include <proto/Picasso96API.h>
42 #include <proto/utility.h>
43 
44 Library* DataTypesBase = 0;
45 Library* GraphicsBase = 0;
46 Library* IntuitionBase = 0;
47 Library* KeymapBase = 0;
48 Library* P96Base = 0;
49 
50 DataTypesIFace* IDataTypes = 0;
51 GraphicsIFace* IGraphics = 0;
52 IntuitionIFace* IIntuition = 0;
53 KeymapIFace* IKeymap = 0;
54 P96IFace* IP96 = 0;
55 
56 Class* RequesterClass = 0;
57 Class* WindowClass = 0;
58 
59 
60 namespace agg
61 {
62 	void handle_idcmp(Hook* hook, APTR win, IntuiMessage* msg);
63 
64 	//------------------------------------------------------------------------
65 	class platform_specific
66 	{
67 	public:
68 		platform_specific(platform_support& support, pix_format_e format,
69 			bool flip_y);
70 		~platform_specific();
71 		bool handle_input();
72 		bool load_img(const char* file, unsigned idx, rendering_buffer* rbuf);
73 		bool create_img(unsigned idx, rendering_buffer* rbuf, unsigned width,
74 			unsigned height);
75 		bool make_bitmap();
76 	public:
77 		platform_support& m_support;
78 		RGBFTYPE m_ftype;
79 		pix_format_e m_format;
80 		unsigned m_bpp;
81 		BitMap* m_bitmap;
82 		bool m_flip_y;
83 		uint16 m_width;
84 		uint16 m_height;
85 		APTR m_window_obj;
86 		Window* m_window;
87 		Hook* m_idcmp_hook;
88 		unsigned m_input_flags;
89 		bool m_dragging;
90 		double m_start_time;
91 		uint16 m_last_key;
92 		BitMap* m_img_bitmaps[platform_support::max_images];
93 	};
94 
95 	//------------------------------------------------------------------------
platform_specific(platform_support & support,pix_format_e format,bool flip_y)96 	platform_specific::platform_specific(platform_support& support,
97 		pix_format_e format, bool flip_y) :
98 		m_support(support),
99 		m_ftype(RGBFB_NONE),
100 		m_format(format),
101 		m_bpp(0),
102 		m_bitmap(0),
103 		m_flip_y(flip_y),
104 		m_width(0),
105 		m_height(0),
106 		m_window_obj(0),
107 		m_window(0),
108 		m_idcmp_hook(0),
109 		m_input_flags(0),
110 		m_dragging(false),
111 		m_start_time(0.0),
112 		m_last_key(0)
113 	{
114 		switch ( format )
115 		{
116 		case pix_format_gray8:
117 			// Not supported.
118 			break;
119 		case pix_format_rgb555:
120 			m_ftype = RGBFB_R5G5B5;
121 			m_bpp = 15;
122 			break;
123 		case pix_format_rgb565:
124 			m_ftype = RGBFB_R5G6B5;
125 			m_bpp = 16;
126 			break;
127 		case pix_format_rgb24:
128 			m_ftype = RGBFB_R8G8B8;
129 			m_bpp = 24;
130 			break;
131 		case pix_format_bgr24:
132 			m_ftype = RGBFB_B8G8R8;
133 			m_bpp = 24;
134 			break;
135 		case pix_format_bgra32:
136 			m_ftype = RGBFB_B8G8R8A8;
137 			m_bpp = 32;
138 			break;
139 		case pix_format_abgr32:
140 			m_ftype = RGBFB_A8B8G8R8;
141 			m_bpp = 32;
142 			break;
143 		case pix_format_argb32:
144 			m_ftype = RGBFB_A8R8G8B8;
145 			m_bpp = 32;
146 			break;
147         case pix_format_rgba32:
148 			m_ftype = RGBFB_R8G8B8A8;
149 			m_bpp = 32;
150 			break;
151 		}
152 
153 		for ( unsigned i = 0; i < platform_support::max_images; ++i )
154 		{
155 			m_img_bitmaps[i] = 0;
156 		}
157 	}
158 
159 	//------------------------------------------------------------------------
~platform_specific()160 	platform_specific::~platform_specific()
161 	{
162 		IIntuition->DisposeObject(m_window_obj);
163 
164 		IP96->p96FreeBitMap(m_bitmap);
165 
166 		for ( unsigned i = 0; i < platform_support::max_images; ++i )
167 		{
168 			IP96->p96FreeBitMap(m_img_bitmaps[i]);
169 		}
170 
171 		if ( m_idcmp_hook != 0 )
172 		{
173 			IExec->FreeSysObject(ASOT_HOOK, m_idcmp_hook);
174 		}
175 	}
176 
177 	//------------------------------------------------------------------------
handle_input()178 	bool platform_specific::handle_input()
179 	{
180 		int16 code = 0;
181 		uint32 result = 0;
182 		Object* obj = reinterpret_cast<Object*>(m_window_obj);
183 
184 		while ( (result = IIntuition->IDoMethod(obj, WM_HANDLEINPUT,
185 				&code)) != WMHI_LASTMSG )
186 		{
187 			switch ( result & WMHI_CLASSMASK )
188 			{
189 			case WMHI_CLOSEWINDOW:
190 				return true;
191 				break;
192 			case WMHI_INTUITICK:
193 				if ( !m_support.wait_mode() )
194 				{
195 					m_support.on_idle();
196 				}
197 				break;
198 			case WMHI_NEWSIZE:
199 				if ( make_bitmap() )
200 				{
201 					m_support.trans_affine_resizing(m_width, m_height);
202 					m_support.on_resize(m_width, m_height);
203 					m_support.force_redraw();
204 				}
205 				break;
206 			}
207 		}
208 
209 		return false;
210 	}
211 
212 	//------------------------------------------------------------------------
load_img(const char * file,unsigned idx,rendering_buffer * rbuf)213 	bool platform_specific::load_img(const char* file, unsigned idx,
214 		rendering_buffer* rbuf)
215 	{
216 		if ( m_img_bitmaps[idx] != 0 )
217 		{
218 			IP96->p96FreeBitMap(m_img_bitmaps[idx]);
219 			m_img_bitmaps[idx] = 0;
220 		}
221 
222 		bool result = false;
223 
224 		Object* picture = IDataTypes->NewDTObject(const_cast<STRPTR>(file),
225 			DTA_GroupID, GID_PICTURE,
226 			PDTA_DestMode, PMODE_V43,
227 			PDTA_Remap, FALSE,
228 			TAG_END);
229 		if ( picture != 0 )
230 		{
231 			gpLayout layout;
232 			layout.MethodID = DTM_PROCLAYOUT;
233 			layout.gpl_GInfo = 0;
234 			layout.gpl_Initial = 1;
235 			ULONG loaded = IDataTypes->DoDTMethodA(picture, 0, 0,
236 				reinterpret_cast<Msg>(&layout));
237 			if ( loaded != 0 )
238 			{
239 				BitMap* src_bitmap = 0;
240 				IDataTypes->GetDTAttrs(picture,
241 					PDTA_ClassBitMap, &src_bitmap,
242 					TAG_END);
243 
244 				bool supported = false;
245 
246 				RGBFTYPE ftype = static_cast<RGBFTYPE>(IP96->p96GetBitMapAttr(
247 					src_bitmap, P96BMA_RGBFORMAT));
248 
249 				switch ( ftype )
250 				{
251 				case RGBFB_R8G8B8:
252 					supported = true;
253 					break;
254 				default:
255 					m_support.message("File uses unsupported graphics mode.");
256 					break;
257 				}
258 
259 				if ( supported )  {
260 					uint16 width = IP96->p96GetBitMapAttr(src_bitmap,
261 						P96BMA_WIDTH);
262 					uint16 height = IP96->p96GetBitMapAttr(src_bitmap,
263 						P96BMA_HEIGHT);
264 
265 					m_img_bitmaps[idx] = IP96->p96AllocBitMap(width, height,
266 						m_bpp, BMF_USERPRIVATE, 0, m_ftype);
267 					if ( m_img_bitmaps[idx] != 0 )
268 					{
269 						int8u* buf = reinterpret_cast<int8u*>(
270 							IP96->p96GetBitMapAttr(m_img_bitmaps[idx],
271 							P96BMA_MEMORY));
272 						int bpr = IP96->p96GetBitMapAttr(m_img_bitmaps[idx],
273 							P96BMA_BYTESPERROW);
274 						int stride = (m_flip_y) ? -bpr : bpr;
275 						rbuf->attach(buf, width, height, stride);
276 
277 						// P96 sets the alpha to zero so it can't be used to
278 						// color convert true color modes.
279 						if ( m_bpp == 32 )
280 						{
281 							RenderInfo ri;
282 							int32 lock = IP96->p96LockBitMap(src_bitmap,
283 								reinterpret_cast<uint8*>(&ri),
284 								sizeof(RenderInfo));
285 
286 							rendering_buffer rbuf_src;
287 							rbuf_src.attach(
288 								reinterpret_cast<int8u*>(ri.Memory),
289 								width, height, (m_flip_y) ?
290 									-ri.BytesPerRow : ri.BytesPerRow);
291 
292 							switch ( m_format )
293 							{
294 							case pix_format_bgra32:
295 								color_conv(rbuf, &rbuf_src,
296 									color_conv_rgb24_to_bgra32());
297 								break;
298 							case pix_format_abgr32:
299 								color_conv(rbuf, &rbuf_src,
300 									color_conv_rgb24_to_abgr32());
301 								break;
302 							case pix_format_argb32:
303 								color_conv(rbuf, &rbuf_src,
304 									color_conv_rgb24_to_argb32());
305 								break;
306 							case pix_format_rgba32:
307 								color_conv(rbuf, &rbuf_src,
308 									color_conv_rgb24_to_rgba32());
309 								break;
310 							}
311 
312 							IP96->p96UnlockBitMap(src_bitmap, lock);
313 						}
314 						else
315 						{
316 							IGraphics->BltBitMap(src_bitmap, 0, 0,
317 								m_img_bitmaps[idx], 0, 0, width, height,
318 								ABC|ABNC, 0xFF, 0);
319 						}
320 
321 						result = true;
322 					}
323 				}
324 			}
325 		}
326 
327 		IGraphics->WaitBlit();
328 		IDataTypes->DisposeDTObject(picture);
329 
330 		return result;
331 	}
332 
333 	//------------------------------------------------------------------------
create_img(unsigned idx,rendering_buffer * rbuf,unsigned width,unsigned height)334 	bool platform_specific::create_img(unsigned idx, rendering_buffer* rbuf,
335 		unsigned width, unsigned height)
336 	{
337 		if ( m_img_bitmaps[idx] != 0 )
338 		{
339 			IP96->p96FreeBitMap(m_img_bitmaps[idx]);
340 			m_img_bitmaps[idx] = 0;
341 		}
342 
343 		m_img_bitmaps[idx] = IP96->p96AllocBitMap(width, height,
344 			m_bpp, BMF_USERPRIVATE, m_bitmap, m_ftype);
345 		if ( m_img_bitmaps[idx] != 0 )
346 		{
347 			int8u* buf = reinterpret_cast<int8u*>(
348 				IP96->p96GetBitMapAttr(m_img_bitmaps[idx],
349 				P96BMA_MEMORY));
350 			int bpr = IP96->p96GetBitMapAttr(m_img_bitmaps[idx],
351 				P96BMA_BYTESPERROW);
352 			int stride = (m_flip_y) ? -bpr : bpr;
353 
354 			rbuf->attach(buf, width, height, stride);
355 
356 			return true;
357 		}
358 
359 		return false;
360 	}
361 
362 	//------------------------------------------------------------------------
make_bitmap()363 	bool platform_specific::make_bitmap()
364 	{
365 		uint32 width = 0;
366 		uint32 height = 0;
367 		IIntuition->GetWindowAttrs(m_window,
368 			WA_InnerWidth, &width,
369 			WA_InnerHeight, &height,
370 			TAG_END);
371 
372 		BitMap* bm = IP96->p96AllocBitMap(width, height, m_bpp,
373 			BMF_USERPRIVATE|BMF_CLEAR, 0, m_ftype);
374 		if ( bm == 0 )
375 		{
376 			return false;
377 		}
378 
379 		int8u* buf = reinterpret_cast<int8u*>(
380 			IP96->p96GetBitMapAttr(bm, P96BMA_MEMORY));
381 		int bpr = IP96->p96GetBitMapAttr(bm, P96BMA_BYTESPERROW);
382 		int stride = (m_flip_y) ? -bpr : bpr;
383 
384 		m_support.rbuf_window().attach(buf, width, height, stride);
385 
386 		if ( m_bitmap != 0 )
387 		{
388 			IP96->p96FreeBitMap(m_bitmap);
389 			m_bitmap = 0;
390 		}
391 
392 		m_bitmap = bm;
393 		m_width = width;
394 		m_height = height;
395 
396 		return true;
397 	}
398 
399 	//------------------------------------------------------------------------
platform_support(pix_format_e format,bool flip_y)400 	platform_support::platform_support(pix_format_e format, bool flip_y) :
401 		m_specific(new platform_specific(*this, format, flip_y)),
402 		m_format(format),
403 		m_bpp(m_specific->m_bpp),
404 		m_window_flags(0),
405 		m_wait_mode(true),
406 		m_flip_y(flip_y),
407 		m_initial_width(10),
408 		m_initial_height(10)
409 	{
410 		std::strncpy(m_caption, "Anti-Grain Geometry", 256);
411 	}
412 
413 	//------------------------------------------------------------------------
~platform_support()414 	platform_support::~platform_support()
415 	{
416 		delete m_specific;
417 	}
418 
419 	//------------------------------------------------------------------------
caption(const char * cap)420 	void platform_support::caption(const char* cap)
421 	{
422 		std::strncpy(m_caption, cap, 256);
423 		if ( m_specific->m_window != 0 )
424 		{
425 			const char* ignore = reinterpret_cast<const char*>(-1);
426 			IIntuition->SetWindowAttr(m_specific->m_window,
427 				WA_Title, m_caption, sizeof(char*));
428 		}
429 	}
430 
431 	//------------------------------------------------------------------------
start_timer()432 	void platform_support::start_timer()
433 	{
434 		timeval tv;
435 		gettimeofday(&tv, 0);
436 		m_specific->m_start_time = tv.tv_secs + tv.tv_micro/1e6;
437 	}
438 
439 	//------------------------------------------------------------------------
elapsed_time() const440 	double platform_support::elapsed_time() const
441 	{
442 		timeval tv;
443 		gettimeofday(&tv, 0);
444 		double end_time = tv.tv_secs + tv.tv_micro/1e6;
445 
446 		double elasped_seconds = end_time - m_specific->m_start_time;
447 		double elasped_millis = elasped_seconds*1e3;
448 
449 		return elasped_millis;
450 	}
451 
452 	//------------------------------------------------------------------------
raw_display_handler()453 	void* platform_support::raw_display_handler()
454 	{
455 		return 0;	// Not available.
456 	}
457 
458 	//------------------------------------------------------------------------
message(const char * msg)459 	void platform_support::message(const char* msg)
460 	{
461 		APTR req = IIntuition->NewObject(RequesterClass, 0,
462 			REQ_TitleText, "Anti-Grain Geometry",
463 			REQ_Image, REQIMAGE_INFO,
464 			REQ_BodyText, msg,
465 			REQ_GadgetText, "_Ok",
466 			TAG_END);
467 		if ( req == 0 )
468 		{
469 			IDOS->Printf("Message: %s\n", msg);
470 			return;
471 		}
472 
473 		orRequest reqmsg;
474 		reqmsg.MethodID = RM_OPENREQ;
475 		reqmsg.or_Attrs = 0;
476 		reqmsg.or_Window = m_specific->m_window;
477 		reqmsg.or_Screen = 0;
478 
479 		IIntuition->IDoMethodA(reinterpret_cast<Object*>(req),
480 			reinterpret_cast<Msg>(&reqmsg));
481 		IIntuition->DisposeObject(req);
482 	}
483 
484 	//------------------------------------------------------------------------
init(unsigned width,unsigned height,unsigned flags)485 	bool platform_support::init(unsigned width, unsigned height,
486 		unsigned flags)
487 	{
488 		if( m_specific->m_ftype == RGBFB_NONE )
489 		{
490 			message("Unsupported mode requested.");
491 			return false;
492 		}
493 
494 		m_window_flags = flags;
495 
496 		m_specific->m_idcmp_hook = reinterpret_cast<Hook*>(
497 			IExec->AllocSysObjectTags(ASOT_HOOK,
498 				ASOHOOK_Entry, handle_idcmp,
499 				ASOHOOK_Data, this,
500 				TAG_END));
501 		if ( m_specific->m_idcmp_hook == 0 )
502 		{
503 			return false;
504 		}
505 
506 		m_specific->m_window_obj = IIntuition->NewObject(WindowClass, 0,
507 				WA_Title, m_caption,
508 				WA_AutoAdjustDClip, TRUE,
509 				WA_InnerWidth, width,
510 				WA_InnerHeight, height,
511 				WA_Activate, TRUE,
512 				WA_SmartRefresh, TRUE,
513 				WA_NoCareRefresh, TRUE,
514 				WA_CloseGadget, TRUE,
515 				WA_DepthGadget, TRUE,
516 				WA_SizeGadget, (flags & agg::window_resize) ? TRUE : FALSE,
517 				WA_DragBar, TRUE,
518 				WA_AutoAdjust, TRUE,
519 				WA_ReportMouse, TRUE,
520 				WA_RMBTrap, TRUE,
521 				WA_MouseQueue, 1,
522 				WA_IDCMP,
523 					IDCMP_NEWSIZE |
524 					IDCMP_MOUSEBUTTONS |
525 					IDCMP_MOUSEMOVE |
526 					IDCMP_RAWKEY |
527 					IDCMP_INTUITICKS,
528 				WINDOW_IDCMPHook, m_specific->m_idcmp_hook,
529 				WINDOW_IDCMPHookBits,
530 					IDCMP_MOUSEBUTTONS |
531 					IDCMP_MOUSEMOVE |
532 					IDCMP_RAWKEY,
533 				TAG_END);
534 		if ( m_specific->m_window_obj == 0 )
535 		{
536 			return false;
537 		}
538 
539 		Object* obj = reinterpret_cast<Object*>(m_specific->m_window_obj);
540 		m_specific->m_window =
541 			reinterpret_cast<Window*>(IIntuition->IDoMethod(obj, WM_OPEN));
542 		if ( m_specific->m_window == 0 )
543 		{
544 			return false;
545 		}
546 
547 		RGBFTYPE ftype = static_cast<RGBFTYPE>(IP96->p96GetBitMapAttr(
548 			m_specific->m_window->RPort->BitMap, P96BMA_RGBFORMAT));
549 
550 		switch ( ftype )
551 		{
552 		case RGBFB_A8R8G8B8:
553 		case RGBFB_B8G8R8A8:
554 		case RGBFB_R5G6B5PC:
555 			break;
556 		default:
557 			message("Unsupported screen mode.\n");
558 			return false;
559 		}
560 
561 		if ( !m_specific->make_bitmap() )
562 		{
563 			return false;
564 		}
565 
566 		m_initial_width = width;
567 		m_initial_height = height;
568 
569 		on_init();
570 		on_resize(width, height);
571 		force_redraw();
572 
573 		return true;
574 	}
575 
576 	//------------------------------------------------------------------------
run()577 	int platform_support::run()
578 	{
579 		uint32 window_mask = 0;
580 		IIntuition->GetAttr(WINDOW_SigMask, m_specific->m_window_obj,
581 			&window_mask);
582 		uint32 wait_mask = window_mask | SIGBREAKF_CTRL_C;
583 
584 		bool done = false;
585 
586 		while ( !done )
587 		{
588 			uint32 sig_mask = IExec->Wait(wait_mask);
589 			if ( sig_mask & SIGBREAKF_CTRL_C )
590 			{
591 				done = true;
592 			}
593 			else
594 			{
595 				done = m_specific->handle_input();
596 			}
597 		}
598 
599 		return 0;
600 	}
601 
602 	//------------------------------------------------------------------------
img_ext() const603 	const char* platform_support::img_ext() const
604 	{
605 		return ".bmp";
606 	}
607 
608 	//------------------------------------------------------------------------
full_file_name(const char * file_name)609 	const char* platform_support::full_file_name(const char* file_name)
610 	{
611 		return file_name;
612 	}
613 
614 	//------------------------------------------------------------------------
load_img(unsigned idx,const char * file)615 	bool platform_support::load_img(unsigned idx, const char* file)
616 	{
617 		if ( idx < max_images )
618 		{
619 			static char fn[1024];
620 			std::strncpy(fn, file, 1024);
621 			int len = std::strlen(fn);
622 			if ( len < 4 || std::strcmp(fn + len - 4, ".bmp") != 0 )
623 			{
624 				std::strncat(fn, ".bmp", 1024);
625 			}
626 
627 			return m_specific->load_img(fn, idx, &m_rbuf_img[idx]);
628 		}
629 
630 		return false;
631 	}
632 
633 	//------------------------------------------------------------------------
save_img(unsigned idx,const char * file)634 	bool platform_support::save_img(unsigned idx, const char* file)
635 	{
636 		message("Not supported");
637 		return false;
638 	}
639 
640 	//------------------------------------------------------------------------
create_img(unsigned idx,unsigned width,unsigned height)641 	bool platform_support::create_img(unsigned idx, unsigned width,
642 		unsigned height)
643 	{
644 		if ( idx < max_images )
645 		{
646 			if ( width == 0 )
647 			{
648 				width = m_specific->m_width;
649 			}
650 
651 			if ( height == 0 )
652 			{
653 				height = m_specific->m_height;
654 			}
655 
656 			return m_specific->create_img(idx, &m_rbuf_img[idx], width,
657 				height);
658 		}
659 
660 		return false;
661 	}
662 
663 	//------------------------------------------------------------------------
force_redraw()664 	void platform_support::force_redraw()
665 	{
666 		on_draw();
667 		update_window();
668 	}
669 
670 	//------------------------------------------------------------------------
update_window()671 	void platform_support::update_window()
672 	{
673 		// Note this function does automatic color conversion.
674 		IGraphics->BltBitMapRastPort(m_specific->m_bitmap, 0, 0,
675 			m_specific->m_window->RPort, m_specific->m_window->BorderLeft,
676 			m_specific->m_window->BorderTop, m_specific->m_width,
677 			m_specific->m_height, ABC|ABNC);
678 	}
679 
680 	//------------------------------------------------------------------------
on_init()681 	void platform_support::on_init() {}
on_resize(int sx,int sy)682 	void platform_support::on_resize(int sx, int sy) {}
on_idle()683 	void platform_support::on_idle() {}
on_mouse_move(int x,int y,unsigned flags)684 	void platform_support::on_mouse_move(int x, int y, unsigned flags) {}
on_mouse_button_down(int x,int y,unsigned flags)685 	void platform_support::on_mouse_button_down(int x, int y, unsigned flags) {}
on_mouse_button_up(int x,int y,unsigned flags)686 	void platform_support::on_mouse_button_up(int x, int y, unsigned flags) {}
on_key(int x,int y,unsigned key,unsigned flags)687 	void platform_support::on_key(int x, int y, unsigned key, unsigned flags) {}
on_ctrl_change()688 	void platform_support::on_ctrl_change() {}
on_draw()689 	void platform_support::on_draw() {}
on_post_draw(void * raw_handler)690 	void platform_support::on_post_draw(void* raw_handler) {}
691 
692 	//------------------------------------------------------------------------
handle_idcmp(Hook * hook,APTR obj,IntuiMessage * msg)693 	void handle_idcmp(Hook* hook, APTR obj, IntuiMessage* msg)
694 	{
695 		platform_support* app =
696 			reinterpret_cast<platform_support*>(hook->h_Data);
697 		Window* window = app->m_specific->m_window;
698 
699 		int16 x = msg->MouseX - window->BorderLeft;
700 
701 		int16 y = 0;
702 		if ( app->flip_y() )
703 		{
704 			y = window->Height - window->BorderBottom - msg->MouseY;
705 		}
706 		else
707 		{
708 			y = msg->MouseY - window->BorderTop;
709 		}
710 
711 		switch ( msg->Class )
712 		{
713 		case IDCMP_MOUSEBUTTONS:
714 			if ( msg->Code & IECODE_UP_PREFIX )
715 			{
716 				if ( msg->Code == SELECTUP )
717 				{
718 					app->m_specific->m_input_flags = mouse_left;
719 					app->m_specific->m_dragging = false;
720 				}
721 				else if ( msg->Code == MENUUP )
722 				{
723 					app->m_specific->m_input_flags = mouse_right;
724 					app->m_specific->m_dragging = false;
725 				}
726 				else
727 				{
728 					return;
729 				}
730 
731 
732 				if ( app->m_ctrls.on_mouse_button_up(x, y) )
733 				{
734 					app->on_ctrl_change();
735 					app->force_redraw();
736 				}
737 
738 				app->on_mouse_button_up(x, y, app->m_specific->m_input_flags);
739 			}
740 			else
741 			{
742 				if ( msg->Code == SELECTDOWN )
743 				{
744 					app->m_specific->m_input_flags = mouse_left;
745 					app->m_specific->m_dragging = true;
746 				}
747 				else if ( msg->Code == MENUDOWN )
748 				{
749 					app->m_specific->m_input_flags = mouse_right;
750 					app->m_specific->m_dragging = true;
751 				}
752 				else
753 				{
754 					return;
755 				}
756 
757 				app->m_ctrls.set_cur(x, y);
758 				if ( app->m_ctrls.on_mouse_button_down(x, y) )
759 				{
760 					app->on_ctrl_change();
761 					app->force_redraw();
762 				}
763 				else
764 				{
765 					if ( app->m_ctrls.in_rect(x, y) )
766 					{
767 						if ( app->m_ctrls.set_cur(x, y) )
768 						{
769 							app->on_ctrl_change();
770 							app->force_redraw();
771 						}
772 					}
773 					else
774 					{
775 						app->on_mouse_button_down(x, y,
776 							app->m_specific->m_input_flags);
777 					}
778 				}
779 			}
780 			break;
781 		case IDCMP_MOUSEMOVE:
782 			if ( app->m_specific->m_dragging )  {
783 				if ( app->m_ctrls.on_mouse_move(x, y,
784 					 app->m_specific->m_input_flags & mouse_left) != 0 )
785 				{
786 					app->on_ctrl_change();
787 					app->force_redraw();
788 				}
789 				else
790 				{
791 					if ( !app->m_ctrls.in_rect(x, y) )
792 					{
793 						app->on_mouse_move(x, y,
794 							app->m_specific->m_input_flags);
795 					}
796 				}
797 			}
798 			break;
799 		case IDCMP_RAWKEY:
800 		{
801 			static InputEvent ie = { 0 };
802 			ie.ie_Class = IECLASS_RAWKEY;
803 			ie.ie_Code = msg->Code;
804 			ie.ie_Qualifier = msg->Qualifier;
805 
806 			static const unsigned BUF_SIZE = 16;
807 			static char key_buf[BUF_SIZE];
808 			int16 num_chars = IKeymap->MapRawKey(&ie, key_buf, BUF_SIZE, 0);
809 
810 			uint32 code = 0x00000000;
811 			switch ( num_chars )
812 			{
813 			case 1:
814 				code = key_buf[0];
815 				break;
816 			case 2:
817 				code = key_buf[0]<<8 | key_buf[1];
818 				break;
819 			case 3:
820 				code = key_buf[0]<<16 | key_buf[1]<<8 | key_buf[2];
821 				break;
822 			}
823 
824 			uint16 key_code = 0;
825 
826 			if ( num_chars == 1 )
827 			{
828 				if ( code >= IECODE_ASCII_FIRST && code <= IECODE_ASCII_LAST )
829 				{
830 					key_code = code;
831 				}
832 			}
833 
834 			if ( key_code == 0 )
835 			{
836 				switch ( code )
837 				{
838 				case 0x00000008: key_code = key_backspace;	break;
839 				case 0x00000009: key_code = key_tab;		break;
840 				case 0x0000000D: key_code = key_return;		break;
841 				case 0x0000001B: key_code = key_escape;		break;
842 				case 0x0000007F: key_code = key_delete;		break;
843 				case 0x00009B41:
844 				case 0x00009B54: key_code = key_up;			break;
845 				case 0x00009B42:
846 				case 0x00009B53: key_code = key_down;		break;
847 				case 0x00009B43:
848 				case 0x009B2040: key_code = key_right;		break;
849 				case 0x00009B44:
850 				case 0x009B2041: key_code = key_left;		break;
851 				case 0x009B307E: key_code = key_f1;			break;
852 				case 0x009B317E: key_code = key_f2;			break;
853 				case 0x009B327E: key_code = key_f3;			break;
854 				case 0x009B337E: key_code = key_f4;			break;
855 				case 0x009B347E: key_code = key_f5;			break;
856 				case 0x009B357E: key_code = key_f6;			break;
857 				case 0x009B367E: key_code = key_f7;			break;
858 				case 0x009B377E: key_code = key_f8;			break;
859 				case 0x009B387E: key_code = key_f9;			break;
860 				case 0x009B397E: key_code = key_f10;		break;
861 				case 0x009B3F7E: key_code = key_scrollock;	break;
862 				}
863 			}
864 
865 			if ( ie.ie_Code & IECODE_UP_PREFIX )
866 			{
867 				if ( app->m_specific->m_last_key != 0 )
868 				{
869 					bool left = (key_code == key_left) ? true : false;
870 					bool right = (key_code == key_right) ? true : false;
871 					bool down = (key_code == key_down) ? true : false;
872 					bool up = (key_code == key_up) ? true : false;
873 
874 					if ( app->m_ctrls.on_arrow_keys(left, right, down, up) )
875 					{
876 						app->on_ctrl_change();
877 						app->force_redraw();
878 					}
879 					else
880 					{
881 						app->on_key(x, y, app->m_specific->m_last_key, 0);
882 					}
883 
884 					app->m_specific->m_last_key = 0;
885 				}
886 			}
887 			else
888 			{
889 				app->m_specific->m_last_key = key_code;
890 			}
891 			break;
892 		}
893 		default:
894 			break;
895 		}
896 	}
897 }
898 
899 //----------------------------------------------------------------------------
900 int agg_main(int argc, char* argv[]);
901 bool open_libs();
902 void close_libs();
903 
904 //----------------------------------------------------------------------------
open_libs()905 bool open_libs()
906 {
907 	DataTypesBase = IExec->OpenLibrary("datatypes.library", 51);
908 	GraphicsBase = IExec->OpenLibrary("graphics.library", 51);
909 	IntuitionBase = IExec->OpenLibrary("intuition.library", 51);
910 	KeymapBase = IExec->OpenLibrary("keymap.library", 51);
911 	P96Base = IExec->OpenLibrary("Picasso96API.library", 2);
912 
913 	IDataTypes = reinterpret_cast<DataTypesIFace*>(
914 		IExec->GetInterface(DataTypesBase, "main", 1, 0));
915 	IGraphics = reinterpret_cast<GraphicsIFace*>(
916 		IExec->GetInterface(GraphicsBase, "main", 1, 0));
917 	IIntuition = reinterpret_cast<IntuitionIFace*>(
918 		IExec->GetInterface(IntuitionBase, "main", 1, 0));
919 	IKeymap = reinterpret_cast<KeymapIFace*>(
920 		IExec->GetInterface(KeymapBase, "main", 1, 0));
921 	IP96 = reinterpret_cast<P96IFace*>(
922 		IExec->GetInterface(P96Base, "main", 1, 0));
923 
924 	if ( IDataTypes == 0 ||
925 		 IGraphics == 0 ||
926 		 IIntuition == 0 ||
927 		 IKeymap == 0 ||
928 		 IP96 == 0 )
929 	{
930 		close_libs();
931 		return false;
932 	}
933 	else
934 	{
935 		return true;
936 	}
937 }
938 
939 //----------------------------------------------------------------------------
close_libs()940 void close_libs()
941 {
942 	IExec->DropInterface(reinterpret_cast<Interface*>(IP96));
943 	IExec->DropInterface(reinterpret_cast<Interface*>(IKeymap));
944 	IExec->DropInterface(reinterpret_cast<Interface*>(IIntuition));
945 	IExec->DropInterface(reinterpret_cast<Interface*>(IGraphics));
946 	IExec->DropInterface(reinterpret_cast<Interface*>(IDataTypes));
947 
948 	IExec->CloseLibrary(P96Base);
949 	IExec->CloseLibrary(KeymapBase);
950 	IExec->CloseLibrary(IntuitionBase);
951 	IExec->CloseLibrary(GraphicsBase);
952 	IExec->CloseLibrary(DataTypesBase);
953 }
954 
955 //----------------------------------------------------------------------------
main(int argc,char * argv[])956 int main(int argc, char* argv[])
957 {
958 	if ( !open_libs() )  {
959 		IDOS->Printf("Can't open libraries.\n");
960 		return -1;
961 	}
962 
963 	ClassLibrary* requester =
964 		IIntuition->OpenClass("requester.class", 51, &RequesterClass);
965 	ClassLibrary* window =
966 		IIntuition->OpenClass("window.class", 51, &WindowClass);
967 	if ( requester == 0 || window == 0 )
968 	{
969 		IDOS->Printf("Can't open classes.\n");
970 		IIntuition->CloseClass(requester);
971 		IIntuition->CloseClass(window);
972 		close_libs();
973 		return -1;
974 	}
975 
976 	int rc = agg_main(argc, argv);
977 
978 	IIntuition->CloseClass(window);
979 	IIntuition->CloseClass(requester);
980 	close_libs();
981 
982 	return rc;
983 }
984