#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
/*****************************************************************************
 * OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
 *
 * OpenRCT2 is the work of many authors, a full list can be found in contributors.md
 * For more information, visit https://github.com/OpenRCT2/OpenRCT2
 *
 * OpenRCT2 is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * A full copy of the GNU General Public License can be found in licence.txt
 *****************************************************************************/
#pragma endregion

#ifndef _DRAWING_H_
#define _DRAWING_H_

#include "../common.h"
#include "../interface/colour.h"
#include "font.h"

typedef struct SDL_Surface SDL_Surface;

// For g1 only enable packing when still relying on vanilla
#ifndef NO_RCT2
#pragma pack(push, 1)
#endif
// Size: 0x10
typedef struct rct_g1_element {
    uint8* offset;          // 0x00
    sint16 width;           // 0x04
    sint16 height;          // 0x06
    sint16 x_offset;        // 0x08
    sint16 y_offset;        // 0x0A
    uint16 flags;           // 0x0C
    uint16 zoomed_offset;   // 0x0E
} rct_g1_element;
#ifndef NO_RCT2
#ifdef PLATFORM_32BIT
assert_struct_size(rct_g1_element, 0x10);
#endif
#pragma pack(pop)
#endif

// Enable packing for remaining elements
#pragma pack(push, 1)
// Size: 0x10
typedef struct rct_drawpixelinfo {
    uint8* bits;        // 0x00
    sint16 x;           // 0x04
    sint16 y;           // 0x06
    sint16 width;       // 0x08
    sint16 height;      // 0x0A
    sint16 pitch;       // 0x0C         note: this is actually (pitch - width)
    uint16 zoom_level;  // 0x0E
} rct_drawpixelinfo;
#ifdef PLATFORM_32BIT
assert_struct_size(rct_drawpixelinfo, 0x10);
#endif

// Size: 0x10
typedef struct rct_g1_element_32bit {
    uint32 offset;                  // 0x00 note: uint32 always!
    sint16 width;                   // 0x04
    sint16 height;                  // 0x06
    sint16 x_offset;                // 0x08
    sint16 y_offset;                // 0x0A
    uint16 flags;                   // 0x0C
    uint16 zoomed_offset;           // 0x0E
} rct_g1_element_32bit;
assert_struct_size(rct_g1_element_32bit, 0x10);


enum {
    G1_FLAG_BMP             = (1 << 0), // Image data is encoded as raw pixels (no transparency)
    G1_FLAG_1               = (1 << 1),
    G1_FLAG_RLE_COMPRESSION = (1 << 2), // Image data is encoded using RCT2's form of run length encoding
    G1_FLAG_HAS_ZOOM_SPRITE = (1 << 4), // Use a different sprite for higher zoom levels
    G1_FLAG_NO_ZOOM_DRAW    = (1 << 5), // Does not get drawn at higher zoom levels (only zoom 0)
};

enum {
    IMAGE_TYPE_DEFAULT = 0,
    IMAGE_TYPE_REMAP = (1 << 29),
    IMAGE_TYPE_TRANSPARENT = (1 << 30),
    IMAGE_TYPE_REMAP_2_PLUS = (1u << 31)
    // REMAP_2_PLUS + REMAP = REMAP 2
    // REMAP_2_PLUS = REMAP 3
};

enum {
    INSET_RECT_FLAG_FILL_GREY = (1 << 2), // 0x04
    INSET_RECT_FLAG_BORDER_NONE = (1 << 3), // 0x08
    INSET_RECT_FLAG_FILL_NONE = (1 << 4), // 0x10
    INSET_RECT_FLAG_BORDER_INSET = (1 << 5), // 0x20
    INSET_RECT_FLAG_FILL_DONT_LIGHTEN = (1 << 6), // 0x40
    INSET_RECT_FLAG_FILL_MID_LIGHT = (1 << 7), // 0x80
};

typedef enum {
    PALETTE_WATER = 32,

    PALETTE_34 = 34,

    PALETTE_45 = 45, // Decolourise + lighten

    PALETTE_DARKEN_3 = 47,

    PALETTE_DARKEN_1 = 49,
    PALETTE_DARKEN_2 = 50,
    PALETTE_51 = 51, // Decolourise + darken
    PALETTE_TRANSLUCENT_GREY = 52,
    PALETTE_TRANSLUCENT_GREY_HIGHLIGHT = 53,
    PALETTE_TRANSLUCENT_GREY_SHADOW = 54,
    PALETTE_TRANSLUCENT_LIGHT_BLUE = 55,
    PALETTE_TRANSLUCENT_LIGHT_BLUE_HIGHLIGHT = 56,
    PALETTE_TRANSLUCENT_LIGHT_BLUE_SHADOW = 57,
    PALETTE_TRANSLUCENT_BORDEAUX_RED = 58,
    PALETTE_TRANSLUCENT_BORDEAUX_RED_HIGHLIGHT = 59,
    PALETTE_TRANSLUCENT_BORDEAUX_RED_SHADOW = 60,
    PALETTE_TRANSLUCENT_DARK_GREEN = 61,
    PALETTE_TRANSLUCENT_DARK_GREEN_HIGHLIGHT = 62,
    PALETTE_TRANSLUCENT_DARK_GREEN_SHADOW = 63,
    PALETTE_TRANSLUCENT_LIGHT_PURPLE = 64,
    PALETTE_TRANSLUCENT_LIGHT_PURPLE_HIGHLIGHT = 65,
    PALETTE_TRANSLUCENT_LIGHT_PURPLE_SHADOW = 66,
    PALETTE_TRANSLUCENT_DARK_OLIVE_GREEN = 67,
    PALETTE_TRANSLUCENT_DARK_OLIVE_GREEN_HIGHLIGHT = 68,
    PALETTE_TRANSLUCENT_DARK_OLIVE_GREEN_SHADOW = 69,
    PALETTE_TRANSLUCENT_LIGHT_BROWN = 70,
    PALETTE_TRANSLUCENT_LIGHT_BROWN_HIGHLIGHT = 71,
    PALETTE_TRANSLUCENT_LIGHT_BROWN_SHADOW = 72,
    PALETTE_TRANSLUCENT_YELLOW = 73,
    PALETTE_TRANSLUCENT_YELLOW_HIGHLIGHT = 74,
    PALETTE_TRANSLUCENT_YELLOW_SHADOW = 75,
    PALETTE_TRANSLUCENT_MOSS_GREEN = 76,
    PALETTE_TRANSLUCENT_MOSS_GREEN_HIGHLIGHT = 77,
    PALETTE_TRANSLUCENT_MOSS_GREEN_SHADOW = 78,
    PALETTE_TRANSLUCENT_OLIVE_GREEN = 79,
    PALETTE_TRANSLUCENT_OLIVE_GREEN_HIGHLIGHT = 80,
    PALETTE_TRANSLUCENT_OLIVE_GREEN_SHADOW = 81,
    PALETTE_TRANSLUCENT_BRIGHT_GREEN = 82,
    PALETTE_TRANSLUCENT_BRIGHT_GREEN_HIGHLIGHT = 83,
    PALETTE_TRANSLUCENT_BRIGHT_GREEN_SHADOW = 84,
    PALETTE_TRANSLUCENT_SALMON_PINK = 85,
    PALETTE_TRANSLUCENT_SALMON_PINK_HIGHLIGHT = 86,
    PALETTE_TRANSLUCENT_SALMON_PINK_SHADOW = 87,
    PALETTE_TRANSLUCENT_BRIGHT_PURPLE = 88,
    PALETTE_TRANSLUCENT_BRIGHT_PURPLE_HIGHLIGHT = 89,
    PALETTE_TRANSLUCENT_BRIGHT_PURPLE_SHADOW = 90,
    PALETTE_TRANSLUCENT_BRIGHT_RED = 91,
    PALETTE_TRANSLUCENT_BRIGHT_RED_HIGHLIGHT = 92,
    PALETTE_TRANSLUCENT_BRIGHT_RED_SHADOW = 93,
    PALETTE_TRANSLUCENT_LIGHT_ORANGE = 94,
    PALETTE_TRANSLUCENT_LIGHT_ORANGE_HIGHLIGHT = 95,
    PALETTE_TRANSLUCENT_LIGHT_ORANGE_SHADOW = 96,
    PALETTE_TRANSLUCENT_TEAL = 97,
    PALETTE_TRANSLUCENT_TEAL_HIGHLIGHT = 98,
    PALETTE_TRANSLUCENT_TEAL_SHADOW = 99,
    PALETTE_TRANSLUCENT_BRIGHT_PINK = 100,
    PALETTE_TRANSLUCENT_BRIGHT_PINK_HIGHLIGHT = 101,
    PALETTE_TRANSLUCENT_BRIGHT_PINK_SHADOW = 102,
    PALETTE_TRANSLUCENT_DARK_BROWN = 103,
    PALETTE_TRANSLUCENT_DARK_BROWN_HIGHLIGHT = 104,
    PALETTE_TRANSLUCENT_DARK_BROWN_SHADOW = 105,
    PALETTE_TRANSLUCENT_LIGHT_PINK = 106,
    PALETTE_TRANSLUCENT_LIGHT_PINK_HIGHLIGHT = 107,
    PALETTE_TRANSLUCENT_LIGHT_PINK_SHADOW = 108,
    PALETTE_TRANSLUCENT_WHITE = 109,
    PALETTE_TRANSLUCENT_WHITE_HIGHLIGHT = 110,
    PALETTE_TRANSLUCENT_WHITE_SHADOW = 111,
    PALETTE_GLASS_BLACK             = 112 + COLOUR_BLACK,
    PALETTE_GLASS_GREY              = 112 + COLOUR_GREY,
    PALETTE_GLASS_WHITE             = 112 + COLOUR_WHITE,
    PALETTE_GLASS_DARK_PURPLE       = 112 + COLOUR_DARK_PURPLE,
    PALETTE_GLASS_LIGHT_PURPLE      = 112 + COLOUR_LIGHT_PURPLE,
    PALETTE_GLASS_BRIGHT_PURPLE     = 112 + COLOUR_BRIGHT_PURPLE,
    PALETTE_GLASS_DARK_BLUE         = 112 + COLOUR_DARK_BLUE,
    PALETTE_GLASS_LIGHT_BLUE        = 112 + COLOUR_LIGHT_BLUE,
    PALETTE_GLASS_ICY_BLUE          = 112 + COLOUR_ICY_BLUE,
    PALETTE_GLASS_TEAL              = 112 + COLOUR_TEAL,
    PALETTE_GLASS_AQUAMARINE        = 112 + COLOUR_AQUAMARINE,
    PALETTE_GLASS_SATURATED_GREEN   = 112 + COLOUR_SATURATED_GREEN,
    PALETTE_GLASS_DARK_GREEN        = 112 + COLOUR_DARK_GREEN,
    PALETTE_GLASS_MOSS_GREEN        = 112 + COLOUR_MOSS_GREEN,
    PALETTE_GLASS_BRIGHT_GREEN      = 112 + COLOUR_BRIGHT_GREEN,
    PALETTE_GLASS_OLIVE_GREEN       = 112 + COLOUR_OLIVE_GREEN,
    PALETTE_GLASS_DARK_OLIVE_GREEN  = 112 + COLOUR_DARK_OLIVE_GREEN,
    PALETTE_GLASS_BRIGHT_YELLOW     = 112 + COLOUR_BRIGHT_YELLOW,
    PALETTE_GLASS_YELLOW            = 112 + COLOUR_YELLOW,
    PALETTE_GLASS_DARK_YELLOW       = 112 + COLOUR_DARK_YELLOW,
    PALETTE_GLASS_LIGHT_ORANGE      = 112 + COLOUR_LIGHT_ORANGE,
    PALETTE_GLASS_DARK_ORANGE       = 112 + COLOUR_DARK_ORANGE,
    PALETTE_GLASS_LIGHT_BROWN       = 112 + COLOUR_LIGHT_BROWN,
    PALETTE_GLASS_SATURATED_BROWN   = 112 + COLOUR_SATURATED_BROWN,
    PALETTE_GLASS_DARK_BROWN        = 112 + COLOUR_DARK_BROWN,
    PALETTE_GLASS_SALMON_PINK       = 112 + COLOUR_SALMON_PINK,
    PALETTE_GLASS_BORDEAUX_RED      = 112 + COLOUR_BORDEAUX_RED,
    PALETTE_GLASS_SATURATED_RED     = 112 + COLOUR_SATURATED_RED,
    PALETTE_GLASS_BRIGHT_RED        = 112 + COLOUR_BRIGHT_RED,
    PALETTE_GLASS_DARK_PINK         = 112 + COLOUR_DARK_PINK,
    PALETTE_GLASS_BRIGHT_PINK       = 112 + COLOUR_BRIGHT_PINK,
    PALETTE_GLASS_LIGHT_PINK        = 112 + COLOUR_LIGHT_PINK,
} FILTER_PALETTE_ID;

typedef struct translucent_window_palette {
    FILTER_PALETTE_ID base;
    FILTER_PALETTE_ID highlight;
    FILTER_PALETTE_ID shadow;
} translucent_window_palette;

typedef struct rct_g1_header {
    uint32 num_entries;
    uint32 total_size;
} rct_g1_header;
assert_struct_size(rct_g1_header, 8);

typedef struct rct_gx {
    rct_g1_header header;
    rct_g1_element *elements;
    void *data;
} rct_gx;
#ifdef PLATFORM_32BIT
assert_struct_size(rct_gx, 16);
#endif

typedef struct rct_palette_entry {
    uint8 blue;
    uint8 green;
    uint8 red;
    uint8 alpha;
} rct_palette_entry;
assert_struct_size(rct_palette_entry, 4);

#pragma pack(pop)

typedef struct rct_palette {
    rct_palette_entry entries[256];
} rct_palette;

#define SPRITE_ID_PALETTE_COLOUR_1(colourId) (IMAGE_TYPE_REMAP | ((colourId) << 19))
#define SPRITE_ID_PALETTE_COLOUR_2(primaryId, secondaryId) (IMAGE_TYPE_REMAP_2_PLUS | IMAGE_TYPE_REMAP | ((primaryId << 19) | (scondaryId << 24)))
#define SPRITE_ID_PALETTE_COLOUR_3(primaryId, secondaryId) (IMAGE_TYPE_REMAP_2_PLUS | ((primaryId << 19) | (scondaryId << 24)))

#define PALETTE_TO_G1_OFFSET_COUNT 144

#define INSET_RECT_F_30 (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_NONE)
#define INSET_RECT_F_60 (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_DONT_LIGHTEN)
#define INSET_RECT_F_E0 (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_DONT_LIGHTEN | INSET_RECT_FLAG_FILL_MID_LIGHT)

#define MAX_SCROLLING_TEXT_MODES 38

extern sint16 gCurrentFontSpriteBase;
extern uint16 gCurrentFontFlags;

extern rct_palette_entry gPalette[256];
extern uint8 gGamePalette[256 * 4];
extern uint32 gPaletteEffectFrame;
extern const FILTER_PALETTE_ID GlassPaletteIds[COLOUR_COUNT];
extern const uint16 palette_to_g1_offset[];
extern uint8 gPeepPalette[256];
extern uint8 gOtherPalette[256];
extern uint8 text_palette[];
extern const translucent_window_palette TranslucentWindowPalettes[COLOUR_COUNT];

extern sint32 gLastDrawStringX;
extern sint32 gLastDrawStringY;

extern uint32 gPickupPeepImage;
extern sint32 gPickupPeepX;
extern sint32 gPickupPeepY;

extern rct_g1_element *g1Elements;

extern rct_drawpixelinfo gScreenDPI;
extern rct_drawpixelinfo gWindowDPI;

extern void *unk_9ABDA4;
extern void *unk_9E3CDC;
extern void *unk_9E3CE4[8];
#ifdef NO_RCT2
extern rct_drawpixelinfo *unk_140E9A8;
#else
#define unk_140E9A8 RCT2_GLOBAL(0x0140E9A8, rct_drawpixelinfo*)
#endif

//
bool clip_drawpixelinfo(rct_drawpixelinfo *dst, rct_drawpixelinfo *src, sint32 x, sint32 y, sint32 width, sint32 height);
void gfx_set_dirty_blocks(sint16 left, sint16 top, sint16 right, sint16 bottom);
void gfx_draw_all_dirty_blocks();
void gfx_invalidate_screen();

// palette
void gfx_transpose_palette(sint32 pal, uint8 product);
void load_palette();

// other
void gfx_clear(rct_drawpixelinfo *dpi, uint8 paletteIndex);
void gfx_draw_pixel(rct_drawpixelinfo *dpi, sint32 x, sint32 y, sint32 colour);
void gfx_filter_pixel(rct_drawpixelinfo *dpi, sint32 x, sint32 y, FILTER_PALETTE_ID palette);
void gfx_invalidate_pickedup_peep();
void gfx_draw_pickedup_peep(rct_drawpixelinfo *dpi);

// line
void gfx_draw_line(rct_drawpixelinfo *dpi, sint32 x1, sint32 y1, sint32 x2, sint32 y2, sint32 colour);
void gfx_draw_line_software(rct_drawpixelinfo *dpi, sint32 x1, sint32 y1, sint32 x2, sint32 y2, sint32 colour);

// rect
void gfx_fill_rect(rct_drawpixelinfo *dpi, sint32 left, sint32 top, sint32 right, sint32 bottom, sint32 colour);
void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, sint16 left, sint16 top, sint16 right, sint16 bottom, sint32 colour, uint8 flags);
void gfx_filter_rect(rct_drawpixelinfo *dpi, sint32 left, sint32 top, sint32 right, sint32 bottom, FILTER_PALETTE_ID palette);

// sprite
bool gfx_load_g1();
bool gfx_load_g2();
bool gfx_load_csg();
void gfx_unload_g1();
void gfx_unload_g2();
void gfx_unload_csg();
rct_g1_element* gfx_get_g1_element(sint32 image_id);
bool is_csg_loaded();
uint32 gfx_object_allocate_images(const rct_g1_element * images, uint32 count);
void gfx_object_free_images(uint32 baseImageId, uint32 count);
void gfx_object_check_all_images_freed();
void sub_68371D();
void FASTCALL gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, uint8* source_pointer, uint8* dest_pointer, rct_g1_element* source_image, rct_drawpixelinfo *dest_dpi, sint32 height, sint32 width, sint32 image_type);
void FASTCALL gfx_rle_sprite_to_buffer(const uint8* RESTRICT source_bits_pointer, uint8* RESTRICT dest_bits_pointer, const uint8* RESTRICT palette_pointer, const rct_drawpixelinfo * RESTRICT dpi, sint32 image_type, sint32 source_y_start, sint32 height, sint32 source_x_start, sint32 width);
void FASTCALL gfx_draw_sprite(rct_drawpixelinfo *dpi, sint32 image_id, sint32 x, sint32 y, uint32 tertiary_colour);
void FASTCALL gfx_draw_glpyh(rct_drawpixelinfo *dpi, sint32 image_id, sint32 x, sint32 y, uint8 * palette);
void FASTCALL gfx_draw_sprite_raw_masked(rct_drawpixelinfo *dpi, sint32 x, sint32 y, sint32 maskImage, sint32 colourImage);
void FASTCALL gfx_draw_sprite_solid(rct_drawpixelinfo * dpi, sint32 image, sint32 x, sint32 y, uint8 colour);

void FASTCALL gfx_draw_sprite_software(rct_drawpixelinfo *dpi, sint32 image_id, sint32 x, sint32 y, uint32 tertiary_colour);
uint8* FASTCALL gfx_draw_sprite_get_palette(sint32 image_id, uint32 tertiary_colour);
void FASTCALL gfx_draw_sprite_palette_set_software(rct_drawpixelinfo *dpi, sint32 image_id, sint32 x, sint32 y, uint8* palette_pointer, uint8* unknown_pointer);
void FASTCALL gfx_draw_sprite_raw_masked_software(rct_drawpixelinfo *dpi, sint32 x, sint32 y, sint32 maskImage, sint32 colourImage);

// string
sint32 clip_text(char *buffer, sint32 width);
sint32 gfx_wrap_string(char* buffer, sint32 width, sint32* num_lines, sint32* font_height);
sint32 gfx_get_string_width(const utf8 * buffer);
sint32 gfx_get_string_width_new_lined(char* buffer);
void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, sint32 colour, sint32 x, sint32 y);
void gfx_draw_string_left(rct_drawpixelinfo *dpi, rct_string_id format, void *args, sint32 colour, sint32 x, sint32 y);
void gfx_draw_string_left_clipped(rct_drawpixelinfo *dpi, rct_string_id format, void *args, sint32 colour, sint32 x, sint32 y, sint32 width);
sint32 gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, sint32 x, sint32 y, sint32 width, rct_string_id format, sint32 colour);
void draw_string_left_underline(rct_drawpixelinfo *dpi, rct_string_id format, void *args, sint32 colour, sint32 x, sint32 y);
void gfx_draw_string_left_centred(rct_drawpixelinfo *dpi, rct_string_id format, void *args, sint32 colour, sint32 x, sint32 y);
void gfx_draw_string_centred(rct_drawpixelinfo *dpi, rct_string_id format, sint32 x, sint32 y, sint32 colour, void *args);
void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, rct_string_id format, void *args, sint32 colour, sint32 x, sint32 y, sint32 width);
void draw_string_centred_underline(rct_drawpixelinfo *dpi, rct_string_id format, void *args, sint32 colour, sint32 x, sint32 y);
sint32 gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, sint32 x, sint32 y, sint32 width, rct_string_id format, sint32 colour);
void draw_string_centred_raw(rct_drawpixelinfo *dpi, sint32 x, sint32 y, sint32 numLines, char *text);
void gfx_draw_string_right(rct_drawpixelinfo *dpi, rct_string_id format, void *args, sint32 colour, sint32 x, sint32 y);
void draw_string_right_underline(rct_drawpixelinfo *dpi, rct_string_id format, void *args, sint32 colour, sint32 x, sint32 y);
sint32 string_get_height_raw(char *buffer);
void gfx_draw_string_centred_wrapped_partial(rct_drawpixelinfo *dpi, sint32 x, sint32 y, sint32 width, sint32 colour, rct_string_id format, void *args, sint32 ticks);
void gfx_draw_string_with_y_offsets(rct_drawpixelinfo *dpi, const utf8 *text, sint32 colour, sint32 x, sint32 y, const sint8 *yOffsets, bool forceSpriteFont);
sint32 gfx_clip_string(char* buffer, sint32 width);
void shorten_path(utf8 *buffer, size_t bufferSize, const utf8 *path, sint32 availableWidth);
#ifndef NO_TTF
SDL_Surface *ttf_surface_cache_get_or_add(TTF_Font *font, const utf8 *text);
TTFFontDescriptor *ttf_get_font_from_sprite_base(uint16 spriteBase);
#endif // NO_TTF

bool ttf_initialise();
void ttf_dispose();

// scrolling text
void scrolling_text_initialise_bitmaps();
sint32 scrolling_text_setup(rct_string_id stringId, uint16 scroll, uint16 scrollingMode);

void rct2_draw(rct_drawpixelinfo *dpi);

#include "NewDrawing.h"

#endif
