blob: 85c639c466294f0d7161d5af348b0b4d614165ed [file]
#pragma once
#include <functional>
#include <memory>
#include <vector>
#include <array>
#include <cstdint>
#include <string>
#ifdef WIN32
#define __attribute__(A)
#endif
#include "font.hpp"
#include "../types/rect.hpp"
#include "../types/size.hpp"
#include "../graphics/blend.hpp"
namespace blit {
struct SpriteSheet;
struct sprite_p;
#pragma pack(push, 1)
struct packed_image {
uint8_t type[8];
uint16_t byte_count;
uint16_t width;
uint16_t height;
uint16_t cols;
uint16_t rows;
uint8_t format;
uint8_t palette_entry_count;
};
#pragma pack(pop)
enum TextAlign {
left = 0b0000,
center_h = 0b0100,
right = 0b1000,
top = 0b0000,
center_v = 0b0001,
bottom = 0b0010,
// combinations of above
top_left = top | left,
center_left = center_v | left,
bottom_left = bottom | left,
top_center = top | center_h,
center_center = center_v | center_h,
bottom_center = bottom | center_h,
top_right = top | right,
center_right = center_v | right,
bottom_right = bottom | right,
};
enum class PixelFormat {
RGB = 0, // red, green, blue (8-bits per channel)
RGBA = 1, // red, green, blue, alpha (8-bits per channel)
P = 2, // palette entry (8-bits) into attached palette
M = 3 // mask (8-bits, single channel)
};
static const uint8_t pixel_format_stride[] = {
3, // RGB
4, // RGBA
1, // P
1, // M
};
#pragma pack(push, 1)
struct Pen {
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
uint8_t a = 0;
Pen() = default;
Pen(int a) : a(a) {}
Pen(float a) : a((uint8_t)(a * 255.0f)) {}
Pen(int r, int g, int b, int a = 255) : r(r), g(g), b(b), a(a) {}
Pen(float r, float g, float b, float a = 1.0f) : r((uint8_t)(r * 255.0f)), g((uint8_t)(g * 255.0f)), b((uint8_t)(b * 255.0f)), a((uint8_t)(a * 255.0f)) {}
};
#pragma pack(pop)
struct Surface {
uint8_t *data; // pointer to pixel data (for `rgba` format has pre-multiplied alpha)
Size bounds; // size of surface in pixels
Rect clip; // clipping rectangle for drawing operations
uint8_t alpha = 255; // global alpha for drawing operations
Pen pen; // current pen for drawing operations
PixelFormat format; // surface pixel format
uint8_t pixel_stride; // bytes per pixel
uint16_t row_stride; // bytes per row
Surface *mask = nullptr; // optional mask
Pen *palette = nullptr; // palette entries (for paletted images)
SpriteSheet *sprites = nullptr; // active spritesheet
uint8_t transparent_index = 0; // index of transparent colour (for paletted surfaces)
// blend functions
blit::PenBlendFunc pbf;
blit::BlitBlendFunc bbf;
std::vector<Surface *> mipmaps; // TODO: probably too niche/specific to attach directly to surface
private:
void init();
void load_from_packed(const packed_image *image);
public:
Surface(uint8_t *data, const PixelFormat &format, const Size &bounds);
Surface(uint8_t *data, const PixelFormat &format, const packed_image *image);
Surface *load(const packed_image *image);
// helpers to retrieve pointer to pixel
__attribute__((always_inline)) inline uint8_t* ptr(const Rect &r) { return data + r.x * pixel_stride + r.y * row_stride; }
__attribute__((always_inline)) inline uint8_t* ptr(const Point &p) { return data + p.x * pixel_stride + p.y * row_stride; }
__attribute__((always_inline)) inline uint8_t* ptr(const int32_t &x, const int32_t &y) { return data + x * pixel_stride + y * row_stride; }
__attribute__((always_inline)) inline uint32_t offset(const Rect &r) { return r.x + r.y * bounds.w; }
__attribute__((always_inline)) inline uint32_t offset(const Point &p) { return p.x + p.y * bounds.w; }
__attribute__((always_inline)) inline uint32_t offset(const int32_t &x, const int32_t &y) { return x + y * bounds.w; }
void generate_mipmaps(uint8_t depth);
void clear();
void pixel(const Point &p);
void v_span(Point p, int16_t c);
void h_span(Point p, int16_t c);
void rectangle(const Rect &r);
void circle(const Point &c, int32_t r);
void line(const Point&p1, const Point&p2);
void triangle(Point p1, Point p2, Point p3);
void polygon(std::vector<Point> p);
void text(const std::string &message, const Font &font, const Rect &r, bool variable = true, TextAlign align = TextAlign::top_left, Rect clip = Rect(0, 0, 1000, 1000));
void text(const std::string &message, const Font &font, const Point &p, bool variable = true, TextAlign align = TextAlign::top_left, Rect clip = Rect(0, 0, 1000, 1000));
Size measure_text(const std::string &message, const Font &font, bool variable = true);
std::string wrap_text(const std::string &message, int32_t width, const Font &font, bool variable = true, bool words = true);
/*void outline_circle(const point &c, int32_t r);
*/
void blit(Surface *src, Rect r, Point p, bool hflip = false);
void stretch_blit(Surface *src, Rect sr, Rect dr);
void stretch_blit_vspan(Surface *src, Point uv, uint16_t sc, Point p, int16_t dc);
void custom_blend(Surface *src, Rect r, Point p, std::function<void(uint8_t *psrc, uint8_t *pdest, int16_t c)> f);
void custom_modify(Rect r, std::function<void(uint8_t *p, int16_t c)> f);
void watermark();
// origin (optional - default 0, 0)
// span repeat x/y (optional - default 1, 1)
// scale (optional - default 1)
//void sprite(spritesheet &ss, uint16_t index, point pos, size span = size(1, 1), point origin = point(0, 0), float scale = 1.0f);
//void sprite(spritesheet &ss, point sprite, point position, sprite_p &properties);
void blit_sprite(const Rect &src, const Point &p, const uint8_t &t = 0);
void stretch_blit_sprite(const Rect&src, const Rect &r, const uint8_t &t = 0);
void sprite(const Rect &sprite, const Point &position, const uint8_t &transform = 0);
void sprite(const Point &sprite, const Point &position, const uint8_t &transform = 0);
void sprite(const uint16_t &sprite, const Point &position, const uint8_t &transform = 0);
void sprite(const Rect &sprite, const Point &position, const Point &origin, const uint8_t &transform = 0);
void sprite(const Point &sprite, const Point &position, const Point &origin, const uint8_t &transform = 0);
void sprite(const uint16_t &sprite, const Point &position, const Point &origin, const uint8_t &transform = 0);
void sprite(const Rect &sprite, const Point &position, const Point &origin, const Vec2 &scale, const uint8_t &transform = 0);
void sprite(const Point &sprite, const Point &position, const Point &origin, const Vec2 &scale, const uint8_t &transform = 0);
void sprite(const uint16_t &sprite, const Point &position, const Point &origin, const Vec2 &scale, const uint8_t &transform = 0);
void sprite(const Rect &sprite, const Point &position, const Point &origin, const float &scale, const uint8_t &transform = 0);
void sprite(const Point &sprite, const Point &position, const Point &origin, const float &scale, const uint8_t &transform = 0);
void sprite(const uint16_t &sprite, const Point &position, const Point &origin, const float &scale, const uint8_t &transform = 0);
//extern void texture_triangle(int32_t x1, int32_t y1, int32_t u1, int32_t v1, int32_t x2, int32_t y2, int32_t u2, int32_t v2, int32_t x3, int32_t y3, int32_t u3, int32_t v3);
/*
blitting methods
*/
//extern void blit(rgba *src, int16_t sx, int16_t sy, int16_t sw, int16_t w, int16_t h, int16_t dx, int16_t dy, bool hflip);
/* void blit(surface *src, rect from, const point &to, uint8_t flip = 0);
void vertical_scale_span_blit(const point &p, const uint16_t length, surface *texture, const point &st, const point &et);*/
};
}