#ifndef GFD_P__H_
#define GFD_P__H_

#ifdef __cplusplus
extern "C" {
#endif

#define GFD_PIXEL_AT_(fb_, x_, y_) ((fb_)->buffer[x_+(y_)*((fb_)->pitch)])
#define GFD_PIXEL(x_) ((gfd_pixel_t)(x_))

#define GFD_CHECK_X(fb_, x_) ( ((x_)>=(fb_)->ox) && ((x_)<(fb_)->ex) )
#define GFD_CHECK_Y(fb_, y_) ( ((y_)>=(fb_)->oy) && ((y_)<(fb_)->ey) )

#define GFD_CHECK_X2(fb_, x_) ( ((x_)>=(fb_)->ox) && ((x_)<=(fb_)->ex) )
#define GFD_CHECK_Y2(fb_, y_) ( ((y_)>=(fb_)->oy) && ((y_)<=(fb_)->ey) )

#define GFD_CHECK_X3(fb_, x_) ( ((x_)>(fb_)->ox) && ((x_)<(fb_)->ex) )
#define GFD_CHECK_Y3(fb_, y_) ( ((y_)>(fb_)->oy) && ((y_)<(fb_)->ey) )

#ifdef GFD_CLIP_TEST_

#include <stdlib.h>

int gfd_clip_errors;

static void clip_check(const gfd_framebuffer_t* const fb, int x, int y)
{
  if (!GFD_CHECK_X(fb, x) || !GFD_CHECK_Y(fb, y))
  {
    ++gfd_clip_errors;
    abort();
  }
}

static void fb_set_pixel_no_clip(const gfd_framebuffer_t* const fb, int x, int y, int c)
{
  clip_check(fb, x, y);
  GFD_PIXEL_AT_(fb, x, y)=GFD_PIXEL(c);
}

static gfd_pixel_t* const fb_get_row(const gfd_framebuffer_t* const fb, int y)
{
  clip_check(fb, fb->ox, y);
  return &GFD_PIXEL_AT_(fb, 0, y);
}

static gfd_pixel_t* const fb_get_pixel_address(const gfd_framebuffer_t* const fb, int x, int y)
{
  clip_check(fb, x, y);
  return &GFD_PIXEL_AT_(fb, x, y);
}

static void fb_set_pixel_row_no_clip(const gfd_framebuffer_t* const fb, gfd_pixel_t* const p, int x, int c)
{
  clip_check(fb, x, fb->oy);
  p[x]=GFD_PIXEL(c);
}

static gfd_pixel_t fb_get_pixel_row_no_clip(const gfd_framebuffer_t* const fb, gfd_pixel_t* const p, int x)
{
  clip_check(fb, x, fb->oy);
  return p[x];
}

#else

#define fb_set_pixel_no_clip(fb_, x_, y_, c_) ((void)(GFD_PIXEL_AT_(fb_, x_, y_)=c_))
#define fb_get_row(fb_, y_) (&GFD_PIXEL_AT_(fb_, 0, y_))
#define fb_get_pixel_address(fb_, x_, y_) (&GFD_PIXEL_AT_(fb_, x_, y_))
#define fb_set_pixel_row_no_clip(fb_, p_, x_, c_) ((void)(p_[x_]=c_))
#define fb_get_pixel_row_no_clip(fb_, p_, x_) (p_[x_])

#endif

extern int gfd_fb_cohen_sutherland_line_clip(gfd_framebuffer_t* const fb, int* const x0, int* const y0, int* const x1, int* const y1);
extern int gfd_fb_liang_barsky_line_clip(gfd_framebuffer_t* const fb,  int* const ix0, int* const iy0, int* const ix1, int* const iy1);

#define gfd_line_clip gfd_fb_liang_barsky_line_clip


typedef void (*gfd_fb_draw_circle_bb_function_t)(gfd_framebuffer_t* const fb, const gfd_rect_t* const bb, int x0, int y0, int radius, int cc);
typedef void (*gfd_fb_draw_circle_bb_function_w2_occ_t)(gfd_framebuffer_t* const fb, const gfd_rect_t* const bb, int x0, int y0, int radius, int cc, int oc, bool occlusion, int cnt);

extern void gfd_fb_draw_arc179_func(gfd_fb_draw_circle_bb_function_t f, gfd_framebuffer_t* const fb, int x0, int y0, int radius, double angleStart, double angleStop, int color);
extern void gfd_fb_draw_arc179_func_w2_occ(gfd_fb_draw_circle_bb_function_w2_occ_t f, gfd_framebuffer_t* const fb, int x0, int y0, int radius, double angleStart, double angleStop, int color, int occolor, bool occlusion, int cnt);

#ifdef __cplusplus
}
#endif

#endif /*GFD_P__H_*/
