/*         ______   ___    ___ 
 *        /\  _  \ /\_ \  /\_ \ 
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Accelerated gfx routines for BeOS.
 *
 *      Based on similar functions for Windows/X, by Jason Wilkins
 *      and Angelo Mottola.
 *
 *      See readme.txt for copyright information.
 */

#include "bealleg.h"
#include "allegro/internal/aintern.h"
#include "allegro/platform/aintbeos.h"

#ifndef ALLEGRO_BEOS
#error something is wrong with the makefile
#endif



/* our hooks table */
HOOKS _be_hooks;

/* the sync function pointer */
int32 (*_be_sync_func)() = NULL;



/* software version pointers */
static void (*_orig_hline) (BITMAP *bmp, int x1, int y, int x2, int color);
static void (*_orig_vline) (BITMAP *bmp, int x, int y1, int y2, int color);
static void (*_orig_rectfill) (BITMAP *bmp, int x1, int y1, int x2, int y2, int color);


#define MAKE_HLINE(bpp)														\
static void be_gfx_accel_hline_##bpp(BITMAP *bmp, int x1, int y, int x2, int color)	\
{																			\
   if (_drawing_mode != DRAW_MODE_SOLID) {									\
      _orig_hline(bmp, x1, y, x2, color);									\
      return;																\
   }																		\
   																			\
   if (x1 > x2) {															\
      int tmp = x1;															\
      x1 = x2;																\
      x2 = tmp;																\
   }																		\
																			\
   if (bmp->clip) {															\
      if ((y < bmp->ct) || (y >= bmp->cb))									\
	 return;																\
																			\
      if (x1 < bmp->cl)														\
	 x1 = bmp->cl;															\
																			\
      if (x2 >= bmp->cr)													\
	 x2 = bmp->cr-1;														\
																			\
      if (x2 < x1)															\
	 return;																\
   }																		\
																			\
   x1 += bmp->x_ofs;														\
   y += bmp->y_ofs;															\
   x2 += bmp->x_ofs;														\
																			\
   if (_be_lock_count)														\
      _be_hooks.draw_rect_##bpp(x1, y, x2, y, color);						\
   else {																	\
      acquire_sem(_be_fullscreen_lock);										\
      _be_hooks.draw_rect_##bpp(x1, y, x2, y, color);						\
      release_sem(_be_fullscreen_lock);										\
   }																		\
   bmp->id &= ~(BMP_ID_LOCKED | BMP_ID_AUTOLOCK);							\
}



#define MAKE_VLINE(bpp)														\
static void be_gfx_accel_vline_##bpp(BITMAP *bmp, int x, int y1, int y2, int color) \
{																			\
   if (_drawing_mode != DRAW_MODE_SOLID) {									\
      _orig_vline(bmp, x, y1, y2, color);									\
      return;																\
   }																		\
																			\
   if (y1 > y2) {															\
      int tmp = y1;															\
      y1 = y2;																\
      y2 = tmp;																\
   }																		\
																			\
   if (bmp->clip) {															\
      if ((x < bmp->cl) || (x >= bmp->cr))									\
	 return;																\
																			\
      if (y1 < bmp->ct)														\
	 y1 = bmp->ct;															\
																			\
      if (y2 >= bmp->cb)													\
	 y2 = bmp->cb-1;														\
																			\
      if (y2 < y1)															\
	 return;																\
   }																		\
   																			\
   x += bmp->x_ofs;															\
   y1 += bmp->y_ofs;														\
   y2 += bmp->y_ofs;														\
																			\
   if (_be_lock_count)														\
      _be_hooks.draw_rect_##bpp(x, y1, x, y2, color);						\
   else {																	\
      acquire_sem(_be_fullscreen_lock);										\
      _be_hooks.draw_rect_##bpp(x, y1, x, y2, color);						\
      release_sem(_be_fullscreen_lock);										\
   }																		\
   bmp->id &= ~(BMP_ID_LOCKED | BMP_ID_AUTOLOCK);							\
}


#define MAKE_RECTFILL(bpp)													\
static void be_gfx_accel_rectfill_##bpp(BITMAP *bmp, int x1, int y1, int x2, int y2, int color) \
{																			\
   if (_drawing_mode != DRAW_MODE_SOLID) {									\
      _orig_rectfill(bmp, x1, y1, x2, y2, color);							\
      return;																\
   }																		\
																			\
   if (x2 < x1) {															\
      int tmp = x1;															\
      x1 = x2;																\
      x2 = tmp;																\
   }																		\
																			\
   if (y2 < y1) {															\
      int tmp = y1;															\
      y1 = y2;																\
      y2 = tmp;																\
   }																		\
																			\
   if (bmp->clip) {															\
      if (x1 < bmp->cl)														\
	 x1 = bmp->cl;															\
																			\
      if (x2 >= bmp->cr)													\
	 x2 = bmp->cr-1;														\
																			\
      if (x2 < x1)															\
	 return;																\
																			\
      if (y1 < bmp->ct)														\
	 y1 = bmp->ct;															\
																			\
      if (y2 >= bmp->cb)													\
	 y2 = bmp->cb-1;														\
																			\
      if (y2 < y1)															\
	 return;																\
   }																		\
   																			\
   x1 += bmp->x_ofs;														\
   y1 += bmp->y_ofs;														\
   x2 += bmp->x_ofs;														\
   y2 += bmp->y_ofs;														\
																			\
   if (_be_lock_count)														\
      _be_hooks.draw_rect_##bpp(x1, y1, x2, y2, color);						\
   else {																	\
      acquire_sem(_be_fullscreen_lock);										\
      _be_hooks.draw_rect_##bpp(x1, y1, x2, y2, color);						\
      release_sem(_be_fullscreen_lock);										\
   }																		\
   bmp->id &= ~(BMP_ID_LOCKED | BMP_ID_AUTOLOCK);							\
}


#define MAKE_CLEAR_TO_COLOR(bpp)											\
static void be_gfx_accel_clear_to_color_##bpp(BITMAP *bmp, int color)		\
{																			\
   int x1, y1, x2, y2;														\
																			\
   x1 = bmp->cl + bmp->x_ofs;												\
   y1 = bmp->ct + bmp->y_ofs;												\
   x2 = bmp->cr + bmp->x_ofs - 1;											\
   y2 = bmp->cb + bmp->y_ofs - 1;											\
																			\
   if (_be_lock_count)														\
      _be_hooks.draw_rect_##bpp(x1, y1, x2, y2, color);						\
   else {																	\
      acquire_sem(_be_fullscreen_lock);										\
      _be_hooks.draw_rect_##bpp(x1, y1, x2, y2, color);						\
      release_sem(_be_fullscreen_lock);										\
   }																		\
   bmp->id &= ~(BMP_ID_LOCKED | BMP_ID_AUTOLOCK);							\
}


MAKE_HLINE(8);
MAKE_HLINE(16);
MAKE_HLINE(32);

MAKE_VLINE(8);
MAKE_VLINE(16);
MAKE_VLINE(32);

MAKE_RECTFILL(8);
MAKE_RECTFILL(16);
MAKE_RECTFILL(32);

MAKE_CLEAR_TO_COLOR(8);
MAKE_CLEAR_TO_COLOR(16);
MAKE_CLEAR_TO_COLOR(32);



/* be_gfx_accel_blit_to_self:
 *
 */
static void be_gfx_accel_blit_to_self(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height)
{
   source_x += source->x_ofs;
   source_y += source->y_ofs;
   dest_x += dest->x_ofs;
   dest_y += dest->y_ofs;

   if (_be_lock_count)
      _be_hooks.blit(source_x, source_y, dest_x, dest_y, width - 1, height - 1);
   else {
      acquire_sem(_be_fullscreen_lock);
      _be_hooks.blit(source_x, source_y, dest_x, dest_y, width - 1, height - 1);
      release_sem(_be_fullscreen_lock);
   }
   dest->id &= ~(BMP_ID_LOCKED | BMP_ID_AUTOLOCK);
}



/* be_gfx_bwindowscreen_accelerate:
 *  Detects and initializes hardware accelerated gfx functions.
 */
extern "C" void be_gfx_bwindowscreen_accelerate(int depth)
{
   _be_hooks.draw_line_8   = (LINE8_HOOK)  _be_allegro_screen->CardHookAt(LINE8_HOOK_NUM);
   _be_hooks.draw_line_16  = (LINE16_HOOK) _be_allegro_screen->CardHookAt(LINE16_HOOK_NUM);
   _be_hooks.draw_line_32  = (LINE32_HOOK) _be_allegro_screen->CardHookAt(LINE32_HOOK_NUM);
   _be_hooks.draw_array_8  = (ARRAY8_HOOK) _be_allegro_screen->CardHookAt(ARRAY8_HOOK_NUM);
   _be_hooks.draw_array_32 = (ARRAY32_HOOK)_be_allegro_screen->CardHookAt(ARRAY32_HOOK_NUM);
   _be_hooks.draw_rect_8   = (RECT8_HOOK)  _be_allegro_screen->CardHookAt(RECT8_HOOK_NUM);
   _be_hooks.draw_rect_16  = (RECT16_HOOK) _be_allegro_screen->CardHookAt(RECT16_HOOK_NUM);
   _be_hooks.draw_rect_32  = (RECT32_HOOK) _be_allegro_screen->CardHookAt(RECT32_HOOK_NUM);
   _be_hooks.invert_rect   = (INVERT_HOOK) _be_allegro_screen->CardHookAt(INVERT_HOOK_NUM);
   _be_hooks.blit          = (BLIT_HOOK)   _be_allegro_screen->CardHookAt(BLIT_HOOK_NUM);
   _be_hooks.sync          = (SYNC_HOOK)   _be_allegro_screen->CardHookAt(SYNC_HOOK_NUM);

   gfx_capabilities = 0;

   if (!_be_hooks.sync)
      return;
   
   _orig_hline = _screen_vtable.hline;
   _orig_vline = _screen_vtable.vline;
   _orig_rectfill = _screen_vtable.rectfill;
   
   switch (depth) {
      case 8:
         if ((_be_hooks.draw_line_8) || (_be_hooks.draw_rect_8)) {
            _screen_vtable.hline = be_gfx_accel_hline_8;
            _screen_vtable.vline = be_gfx_accel_vline_8;
         }
         if (_be_hooks.draw_line_8) {
            gfx_capabilities |= GFX_HW_LINE;
         }
         if (_be_hooks.draw_rect_8) {
            _screen_vtable.rectfill = be_gfx_accel_rectfill_8;
            _screen_vtable.clear_to_color = be_gfx_accel_clear_to_color_8;
            gfx_capabilities |= GFX_HW_FILL;
         }
         break;

      case 15:
      case 16:
         if ((_be_hooks.draw_line_16) || (_be_hooks.draw_rect_16)) {
            _screen_vtable.hline = be_gfx_accel_hline_16;
            _screen_vtable.vline = be_gfx_accel_vline_16;
         }
         if (_be_hooks.draw_line_16) {
            gfx_capabilities |= GFX_HW_LINE;
         }
         if (_be_hooks.draw_rect_16) {
            _screen_vtable.rectfill = be_gfx_accel_rectfill_16;
            _screen_vtable.clear_to_color = be_gfx_accel_clear_to_color_16;
            gfx_capabilities |= GFX_HW_FILL;
         }
         break;

      case 32:
         if ((_be_hooks.draw_line_32) || (_be_hooks.draw_rect_32)) {
            _screen_vtable.hline = be_gfx_accel_hline_32;
            _screen_vtable.vline = be_gfx_accel_vline_32;
         }
         if (_be_hooks.draw_line_32) {
            gfx_capabilities |= GFX_HW_LINE;
         }
         if (_be_hooks.draw_rect_32) {
            _screen_vtable.rectfill = be_gfx_accel_rectfill_32;
            _screen_vtable.clear_to_color = be_gfx_accel_clear_to_color_32;
            gfx_capabilities |= GFX_HW_FILL;
         }
         break;
   }
   if (_be_hooks.invert_rect)
      gfx_capabilities |= GFX_HW_FILL_XOR;
   if (_be_hooks.blit) {
      _screen_vtable.blit_to_self = be_gfx_accel_blit_to_self;
      _screen_vtable.blit_to_self_forward = be_gfx_accel_blit_to_self;
      _screen_vtable.blit_to_self_backward = be_gfx_accel_blit_to_self;
      gfx_capabilities |= GFX_HW_VRAM_BLIT;
   }
   _be_sync_func = _be_hooks.sync;
}

