#ifndef _RASTER_PIXMAP_H_
#define _RASTER_PIXMAP_H_

#include <sys/types.h>
#include <raster/geo.h>
#include <sys/cdefs.h>
#include <tt/lists.h>

/****************************************************************************************************************
 *
 * Pixmap operations
 *
 */
struct pixmap;
struct blitarea;

//
// Map to functions that are chosen depending on bit depth
//
struct pixmap_operations {
  // Clear screen
  void (*cls)(struct pixmap *pix, uint pixel);

  // Draw a single pixel
  void (*setpixel)(uint8 *line, int x, uint pixel);
  uint (*getpixel)(const uint8 *line, int x);
  void (*plot)(struct pixmap *pix, int x, int y, uint pixel);

  // Copying
  void (*blit_store)(const struct blitarea *bla);
  void (*blit_masked)(const struct blitarea *bla);
  void (*blit_alpha)(const struct blitarea *bla);

  // Color conversion
  uint (*rgb2pixel)(uint);			// Converts a color into a pixel value
  uint (*pixel2rgb)(uint);			// Converts a pixel value into a color
};

//
// Map to functions that are chosen depending on orientation
//
struct raster_operations {
  void (*blit)(struct pixmap *src, int sx, int sy, int width, int height, struct pixmap *dst, int dx, int dy);
  void (*plot)(struct pixmap *pm, int x, int y, uint pixel);
  uint (*getpixel)(struct pixmap *pm, int x, int y);
  void (*line)(struct pixmap *pix, int x1, int y1, int x2, int y2, uint pixel);
  void (*thick_line)(struct pixmap *pix, int x1, int y1, int x2, int y2, uint pixel, uint width);
  void (*box)(struct pixmap *pix, int x, int y, int w, int h, uint pixel);
  void (*fill)(struct pixmap *pix, int x, int y, int w, int h, uint pixel);
  void (*circle)(struct pixmap *pix, int x0, int y0, int radius, uint pixel);
  void (*fill_circle)(struct pixmap *pix, int x0, int y0, int radius, uint pixel);
};

/****************************************************************************************************************
 *
 * Pixmap
 *
 */
struct pixmap {
  // Logical properties
  uint   pm_width;				// Geometry
  uint   pm_height;
  uint32 pm_fgpixel;				// Foreground color (Pixel value)
  uint32 pm_bgpixel;				// Background color (Pixel value)
  uint8  pm_bpp;				// Bits per pixel
  uint8  pm_color;				// 1 if display has color
  uint8  pm_pixelformat;			// Pixel format (see below)
  uint8  pm_blit_mode;				// Helps selecting the fastest blitter
  uint8  pm_alpha_mode;				// Store or blend
  uint8  pm_orientation;			// Rotation by steps of 90 degrees
  uint8  pm_goner;                              // 1=Parent marked for deletion, 2=Marked for deletion
  uint8  pm_use_changelog;                      // Flag that changelog access has been enabled on this framebuffer
  uint8  pm_use_after_free;                     // Warning has been printed
  uint8  pm_tracelevel;                         // Debug level
  uint8  pm_double_buffer;                      // Flag indicating double buffer mode
  uint8  pm_buffer_index;                       // Flag indicating which buffer is current drawing surface

  // Physical properties
  uint pm_physical_width;			// * Geometry
  uint pm_physical_height;			// *
  uint32 pm_bytes_per_line;			// Bytes used by a single line
  uint32 pm_bytes_per_frame;			// Size of visible data buffer
  uint32 pm_bytes_per_buffer;			// Size of whole data buffer (Typically rounded up to page size re. pm_bytes_per_frame)
  uint32 pm_bytes_mapped;                       // Number of mapped bytes (When double buffering this is twice the buffer size)
  uint8 *pm_mapped;                             // mmapped framebuffer data

  int pm_fd;					// Framebuffer device file descriptor

  uint8 *pm_buffers[2];                         // Actual image bits (Supports double buffering)
  uint8 *pm_data;				// Actual image bits being painted to (When double buffering, currently selected buffer)
  uint8 *pm_alpha;				// Optional 8-bit alpha channel
  uint   pm_xoffset;				// For less than 8bpp: offset into byte.
  uint32 *pm_changelog;                         // Buffer with changed pages when using hardware change reporting

  // Drawing primitives
  struct pixmap_operations pm_pops;		// Drawing primitives depending on bit depth
  struct raster_operations pm_rops;             // Drawing on logical coordinates
  struct raster_operations pm_rops_dup;         // Nesting for use with auto double buffering

  // Pixmap tree
  uint pm_x0;					// Position relative to parent
  uint pm_y0;
  uint pm_original_width;			// Geometry
  uint pm_original_height;
  struct pixmap *pm_parent;			// Window tree
  list_head pm_peers;
  list_head pm_children;
};

/****************************************************************************************************************/
// pm_alpha_mode: Determines how pixels are written to the pixmap

#define ALPHA_BLEND	0	// Alpha data of source pixel is used to blend source with destination
#define ALPHA_STORE	1	// Alpha data of source pixel overwrites alpha data of destination

void pixmap_set_alpha_mode(struct pixmap *pm, int mode);

/****************************************************************************************************************/
// pm_blit_mode: Determines how blitter uses the alpha data of source pixels

#define BLIT_BLEND	0	// Full alpha blending
#define BLIT_STORE	1	// Alpha data of source pixel ignored
#define BLIT_MASK	2	// All source pixels with alpha >= 0x80 are skipped

void pixmap_set_blit_mode(struct pixmap *pm, int mode);

/****************************************************************************************************************/
// pm_orientation: Rotate in steps of 90°

void pixmap_set_orientation(struct pixmap *pm, int ori);

/****************************************************************************************************************/
// pm_double_buffer: Hardware double buffering

#define DOUBLE_BUFFER_OFF   0   // Double buffering off
#define DOUBLE_BUFFER_ON    1   // Double buffering enabled
#define DOUBLE_BUFFER_DUP   2   // Enabled, all functions automatically paint into both buffers (for GUI elements)

int pixmap_set_double_buffer_mode(struct pixmap *pm, uint mode);
int pixmap_set_double_buffer_output_index(struct pixmap *pm, uint index);
int pixmap_set_double_buffer_drawing_index(struct pixmap *pm, uint index);

int pixmap_enable_vertical_blank(struct pixmap *pm, uint enable);

/****************************************************************************************************************
 *
 * Animation
 *
 */
#define DISPOSAL_UNDEFINED		0	// Replace one full sized with another (ignore transparency?)
#define DISPOSAL_LEAVE			1	// Draw straight over, with transparency
#define DISPOSAL_RESTORE_BACKGROUND	2	// Restore to background
#define DISPOSAL_RESTORE_PREVIOUS	3	// Restore to previous state

struct animation_frame {
  uint16 afr_x;					// Offset from top left of animation (If frame is smaller)
  uint16 afr_y;
  uint16 afr_delay;				// Time (ms) this frame is shown
  uint8 afr_disposal;				// Disposal method (same as in GIF files)
  uint8 afr_pad;
  struct pixmap *afr_pm;
};

struct animation {
  struct size ani_size;				// Nominal size of animation
  uint ani_count;				// Number of animations
  struct animation_frame ani_frame[0];		// List of frames making up the animation
};

struct animation_player {
  struct animation *apl_ani;			// Animation being played
  struct pixmap *apl_dst;			// Destination pixmap we're playing on
  struct pixmap *apl_buf;			// Double buffering
  struct pixmap *apl_prev;			// Previous frame
  struct pixmap *apl_bs;			// Stores background
  struct point apl_org;				// Position this is played
  uint apl_last_delay;				// Need to reuse last delay if a frame comes up with delay=0
  uint apl_last;				// Frame that was painted last go (>= count if none)
  uint apl_next;				// Next frame coming up
};

/****************************************************************************************************************/

struct pixel_format {
  uint8 red_max;
  uint8 green_max;
  uint8 blue_max;
  uint8 red_shift;
  uint8 green_shift;
  uint8 blue_shift;
};

/****************************************************************************************************************/
//
// Pixel format
//
// Note:
//   Blitter code assumes that 16bpp modes are organized such: BAAAAABBBBBCCCCC
//   In 24 and 32 bit modes, blitter assumes xxxxxxxxAAAAAAAABBBBBBBBCCCCCCCC
//   Where A, B & C denote one of the colors R, G & B, order is not important.
//
#define PXRGB_STRAIGHT		0x00	// Color
#define PXRGB_8BPP		0x01
#define PXRGB_16BPP_ATMEL_BGR	0x02
#define PXRGB_24BPP_ATMEL_BGR	0x03
#define PXRGB_16BPP_ATMEL_RGB	0x04

#define PXRGB_18BPP_SHIFTED	0x05	// 18 bits per pixel, 666, use bits 0..5 per byte

#define PXRGB_1BPP		0x40	// Monochrome or Grayscale
#define PXRGB_2BPP_GRAY		0x41
#define PXRGB_4BPP_GRAY		0x42

#define PXRGB_MONOCHROME_FLAG	0x40

// As parameter to pixmap_alloc(), auto decide from bits-per-pixel
#define PXRGB_AUTO		 ~0U

/****************************************************************************************************************/
//
// Pixmap creation
//
__BEGIN_DECLS
struct pixmap *pixmap_alloc(int width, int height, uint bpp, uint format, uint with_mask);
struct pixmap *pixmap_alloc_like_parent(struct pixmap *parent, int width, int height, uint with_mask);
struct pixmap *pixmap_window(struct pixmap *parent, int x, int y, int width, int height);

void pixmap_init(struct pixmap *pm);
void pixmap_free(struct pixmap *pm);

const struct pixel_format *pixmap_pixel_format(struct pixmap *pm);
__END_DECLS

/****************************************************************************************************************/
//
// Pixmap on hardware framebuffer
//
__BEGIN_DECLS
struct pixmap *pixmap_open(const char *dev);
struct pixmap *pixmap_fdopen(int fd);
int pixmap_resize(struct pixmap *pm, int width, int height, int bpp);
int pixmap_setup(struct pixmap *pm, unsigned int display_id);
int pixmap_move(struct pixmap *pm, uint x, uint y);
int pixmap_move_point(struct pixmap *pm, struct point *pt);
int pixmap_reinit(struct pixmap *pm);
int pixmap_query_changes(struct pixmap *pm, uint32 **buf_p, size_t *count_p);

struct framebuffer_output;
struct fbdev_modeline;
struct fbdev_edid;
struct fbdev_backplane_version;

int pixmap_get_viewport(struct pixmap *pm, struct framebuffer_output *fo);
int pixmap_set_viewport(struct pixmap *pm, const struct framebuffer_output *fo);
int pixmap_get_modeline(struct pixmap *pm, struct fbdev_modeline *ml);
int pixmap_set_modeline(struct pixmap *pm, const struct fbdev_modeline *ml);
int pixmap_get_state(struct pixmap *pm, uint *state);
int pixmap_set_state(struct pixmap *pm, uint state);
int pixmap_get_edid(struct pixmap *pm, struct fbdev_edid *edid);
int pixmap_get_edid_raw(struct pixmap *pm, void *buf, size_t bufsize);
int pixmap_get_backplane_version(struct pixmap *pm, struct fbdev_backplane_version *bpv);

// True if pixmap is on a physical device
static inline __attribute__((always_inline)) int pixmap_is_physical(struct pixmap *pm) { return pm->pm_fd >= 0; }

// Flush data cache, need to call on hardware framebuffer after major screen updates.
void pixmap_flush(struct pixmap *pm);
void pixmap_fdflush(int fd);
__END_DECLS

/****************************************************************************************************************/

struct imageinfo {
  uint   width;				// Image size
  uint   height;
  uint16 palette_size;			// Number of palette entries
  uint16 flags;				// Properties of image
  uint8  bpp;				// Bits per pixel
  uint8  filetype;			// Type of file image is loaded from
};

#define IMGFILE_NONE		0
#define IMGFILE_BMP		1
#define IMGFILE_GIF		2
#define IMGFILE_PNG		3
#define IMGFILE_JPG		4

#define IMGFLAG_TRANSPARENCY	1	// File format supports a transparent color
#define IMGFLAG_ALPHA		2	// File format supports an alpha channel

/****************************************************************************************************************/
//
// Image file loading
//
#define TRANSPARENCY_FROM_IMAGE	(-2)		// Determine transparency from image
#define TRANSPARENCY_NONE	(-1)		// Do not load transparency information

__BEGIN_DECLS
// Load info about an image from a file
int raster_load_info(struct imageinfo *iif, const char *filename);

// Load image from a file into <pm> at <x>,<y>, Pixel with RGB color <transparent> is considered transparent.
int raster_load(struct pixmap *pm, const char *filename, int x, int y, uint transparent);

// Load image from a file into newly allocated pixmap that has organization like <parent> (bpp, pixelformat).
struct pixmap *raster_load_pixmap(struct pixmap *parent, const char *filename, int transparent);

//
// Animation
//

// Load animation sequence from a file
struct animation *ani_load(struct pixmap *parent, const char *filename, int transparent);

// Free resources
void ani_free(struct animation *ani);

//
// Animation player
//

// Init playback
struct animation_player *apl_init(struct animation *ani, struct pixmap *dst, uint x, uint y);

// Play a frame
int apl_next(struct animation_player *apl);

// Remove animation and restore save under
void apl_restore(struct animation_player *apl);

// "Stop" animation -- Restore playfield if not already stopped
void apl_stop(struct animation_player *apl);

// Drop a player
void apl_free(struct animation_player *apl);

__END_DECLS

/****************************************************************************************************************/
//
// Image file saving
//
__BEGIN_DECLS

typedef int (raster_save_t)(void *data, const void *savedata, size_t savelen);

struct raster_save {
  const char *type;			// Image type

  raster_save_t *saver;			// Callback for writing data
  void *saver_data;

  int x, y, w, h;			// Range. If w or h is zero, use full size instead.

  uint32 args[4];			// Type dependent arguments
  const char *strargs[4];               // Type dependent arguments
};

int raster_save(struct raster_save *rs, struct pixmap *pm);
int raster_save_file(struct raster_save *rs, struct pixmap *pm, const char *filename);
int raster_save_fd(struct raster_save *rs, struct pixmap *pm, int fd);

__END_DECLS

/****************************************************************************************************************/

#include <raster/primitives.h>

/****************************************************************************************************************/

static inline uint pixmap_rgb2pixel(struct pixmap *pm, uint rgb) __attribute__((always_inline));
static inline uint pixmap_rgb2pixel(struct pixmap *pm, uint rgb) {
  return pm->pm_pops.rgb2pixel(rgb);
}

/****************************************************************************************************************/

static inline uint pixmap_pixel2rgb(struct pixmap *pm, uint rgb) __attribute__((always_inline));
static inline uint pixmap_pixel2rgb(struct pixmap *pm, uint rgb) {
  return pm->pm_pops.pixel2rgb(rgb);
}

/****************************************************************************************************************/
//
// The grayscale is mixed using factors taken from PAL: R=0.299 G=0.587 B=0.114
// Together with the initial ranges of RGB, the result is 0..0xFFFFFF
//
static inline uint pixmap_rgb2gray(uint rgb) {
  return ((rgb & 0xFF) * 19672) + (((rgb >> 8) & 0xFF) * 38621) + (((rgb >> 16) & 0xFF) * 7500);
}

/****************************************************************************************************************/
#endif
