667 lines
15 KiB
C++
667 lines
15 KiB
C++
#ifndef _library__framebuffer__hpp__included__
|
|
#define _library__framebuffer__hpp__included__
|
|
|
|
#include <stdexcept>
|
|
#include <cstdlib>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <set>
|
|
|
|
namespace framebuffer
|
|
{
|
|
template<bool X> struct elem {};
|
|
template<> struct elem<false> { typedef uint32_t t; };
|
|
template<> struct elem<true> { typedef uint64_t t; };
|
|
|
|
/**
|
|
* Pixel format auxillary palette.
|
|
*/
|
|
template<bool X>
|
|
struct auxpalette
|
|
{
|
|
typedef typename elem<X>::t element_t;
|
|
uint8_t rshift; //Red shift.
|
|
uint8_t gshift; //Green shift.
|
|
uint8_t bshift; //Blue shift.
|
|
std::vector<element_t> pcache; //Palette cache.
|
|
};
|
|
|
|
/**
|
|
* Pixel format.
|
|
*/
|
|
class pixfmt
|
|
{
|
|
public:
|
|
virtual ~pixfmt() throw();
|
|
/**
|
|
* Register the pixel format.
|
|
*/
|
|
pixfmt() throw(std::bad_alloc);
|
|
/**
|
|
* Decode pixel format data into RGB data (0, R, G, B).
|
|
*/
|
|
virtual void decode(uint32_t* target, const uint8_t* src, size_t width)
|
|
throw() = 0;
|
|
/**
|
|
* Decode pixel format data into RGB (with specified byte order).
|
|
*/
|
|
virtual void decode(uint32_t* target, const uint8_t* src, size_t width,
|
|
const auxpalette<false>& auxp) throw() = 0;
|
|
/**
|
|
* Decode pixel format data into RGB (with specified byte order).
|
|
*/
|
|
virtual void decode(uint64_t* target, const uint8_t* src, size_t width,
|
|
const auxpalette<true>& auxp) throw() = 0;
|
|
/**
|
|
* Create aux palette.
|
|
*/
|
|
virtual void set_palette(auxpalette<false>& auxp, uint8_t rshift, uint8_t gshift,
|
|
uint8_t bshift) throw(std::bad_alloc) = 0;
|
|
/**
|
|
* Create aux palette.
|
|
*/
|
|
virtual void set_palette(auxpalette<true>& auxp, uint8_t rshift, uint8_t gshift,
|
|
uint8_t bshift) throw(std::bad_alloc) = 0;
|
|
/**
|
|
* Bytes per pixel in data.
|
|
*/
|
|
virtual uint8_t get_bpp() throw() = 0;
|
|
/**
|
|
* Bytes per pixel in ss data.
|
|
*/
|
|
virtual uint8_t get_ss_bpp() throw() = 0;
|
|
/**
|
|
* Screenshot magic (0 for the old format).
|
|
*/
|
|
virtual uint32_t get_magic() throw() = 0;
|
|
};
|
|
|
|
/**
|
|
* Game framebuffer information.
|
|
*/
|
|
struct info
|
|
{
|
|
/**
|
|
* Pixel format of framebuffer.
|
|
*/
|
|
pixfmt* type;
|
|
/**
|
|
* The physical memory backing the framebuffer.
|
|
*/
|
|
char* mem;
|
|
/**
|
|
* Physical width of framebuffer.
|
|
*/
|
|
size_t physwidth;
|
|
/**
|
|
* Physical height of framebuffer.
|
|
*/
|
|
size_t physheight;
|
|
/**
|
|
* Physical stride of framebuffer (in bytes).
|
|
*/
|
|
size_t physstride;
|
|
/**
|
|
* Visible width of framebuffer.
|
|
*/
|
|
size_t width;
|
|
/**
|
|
* Visible height of framebuffer.
|
|
*/
|
|
size_t height;
|
|
/**
|
|
* Visible stride of framebuffer (in bytes).
|
|
*/
|
|
size_t stride;
|
|
/**
|
|
* Visible X offset of framebuffer.
|
|
*/
|
|
size_t offset_x;
|
|
/**
|
|
* Visible Y offset of framebuffer.
|
|
*/
|
|
size_t offset_y;
|
|
};
|
|
|
|
template<bool X> struct framebuffer;
|
|
|
|
/**
|
|
* Raw framebuffer.
|
|
*
|
|
* This framebuffer is in system format, and can either be backed either by temporary buffer or memory buffer.
|
|
*
|
|
* Any copying only preserves the visible part.
|
|
*/
|
|
struct raw
|
|
{
|
|
/**
|
|
* Create a new framebuffer backed by temporary buffer.
|
|
*
|
|
* The resulting framebuffer is read-only.
|
|
*
|
|
* Parameter info: The framebuffer info.
|
|
*/
|
|
raw(const info& finfo) throw(std::bad_alloc);
|
|
/**
|
|
* Create a new framebuffer backed by memory buffer.
|
|
*
|
|
* The resulting framebuffer can be written to.
|
|
*/
|
|
raw() throw(std::bad_alloc);
|
|
/**
|
|
* Copy a framebuffer.
|
|
*
|
|
* The resulting copy is writable.
|
|
*
|
|
* Parameter f: The framebuffer.
|
|
*/
|
|
raw(const raw& f) throw(std::bad_alloc);
|
|
/**
|
|
* Assign a framebuffer.
|
|
*
|
|
* Parameter f: The framebuffer.
|
|
* Throws std::runtime_error: The target framebuffer is not writable.
|
|
*/
|
|
raw& operator=(const raw& f) throw(std::bad_alloc, std::runtime_error);
|
|
/**
|
|
* Load contents of framebuffer.
|
|
*
|
|
* parameter data: The data to load.
|
|
* throws std::runtime_error: The target framebuffer is not writable.
|
|
*/
|
|
void load(const std::vector<char>& data) throw(std::bad_alloc, std::runtime_error);
|
|
/**
|
|
* Save contents of framebuffer.
|
|
*
|
|
* parameter data: The vector to write the data to (in format compatible with load()).
|
|
*/
|
|
void save(std::vector<char>& data) throw(std::bad_alloc);
|
|
/**
|
|
* Save contents of framebuffer as a PNG.
|
|
*
|
|
* parameter file: The filename to save to.
|
|
* throws std::runtime_error: Can't save the PNG.
|
|
*/
|
|
void save_png(const std::string& file) throw(std::bad_alloc, std::runtime_error);
|
|
/**
|
|
* Get width.
|
|
*
|
|
* Returns: The width.
|
|
*/
|
|
size_t get_width() const throw();
|
|
/**
|
|
* Get height.
|
|
*
|
|
* Returns: The height.
|
|
*/
|
|
size_t get_height() const throw();
|
|
/**
|
|
* Get stride.
|
|
*/
|
|
size_t get_stride() const throw();
|
|
/**
|
|
* Get starting address.
|
|
*/
|
|
unsigned char* get_start() const throw();
|
|
/**
|
|
* Get pixel format.
|
|
*/
|
|
pixfmt* get_format() const throw();
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
~raw();
|
|
private:
|
|
bool user_memory; //True if allocated in user memory, false if aliases framebuffer.
|
|
char* addr; //Address of framebuffer start.
|
|
pixfmt* fmt; //Format of framebuffer.
|
|
size_t width; //Width of framebuffer.
|
|
size_t height; //Height of framebuffer.
|
|
size_t stride; //Stride in pixels.
|
|
size_t allocated; //Amount of memory allocated (only meaningful if user_memory=true).
|
|
template<bool X> friend class fb;
|
|
};
|
|
|
|
|
|
struct color;
|
|
|
|
/**
|
|
* Rendered framebuffer.
|
|
*
|
|
* This framebuffer is in RGB32/RGB64 format, and is always backed by memory buffer.
|
|
*/
|
|
template<bool X>
|
|
struct fb
|
|
{
|
|
typedef typename elem<X>::t element_t;
|
|
/**
|
|
* Creates framebuffer. The framebuffer dimensions are initially 0x0.
|
|
*/
|
|
fb() throw();
|
|
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
~fb() throw();
|
|
|
|
/**
|
|
* Sets the backing memory for framebuffer. The specified memory is not freed if framebuffer is reallocated or
|
|
* destroyed.
|
|
*
|
|
* parameter _memory: The memory buffer.
|
|
* parameter _width: Width of framebuffer.
|
|
* parameter _height: Height of framebuffer.
|
|
* parameter _pitch: Distance in bytes between successive scanlines (in pixels).
|
|
*/
|
|
void set(element_t* _memory, size_t _width, size_t _height, size_t _pitch) throw();
|
|
|
|
/**
|
|
* Sets the size of the framebuffer. The memory is freed if framebuffer is reallocated or destroyed.
|
|
*
|
|
* The pitch of resulting framebuffer is the smallest possible.
|
|
*
|
|
* parameter _width: Width of framebuffer.
|
|
* parameter _height: Height of framebuffer.
|
|
* parameter upside_down: If true, image is upside down in memory.
|
|
* throws std::bad_alloc: Not enough memory.
|
|
*/
|
|
void reallocate(size_t _width, size_t _height, bool upside_down = false) throw(std::bad_alloc);
|
|
|
|
/**
|
|
* Set origin
|
|
*
|
|
* parameter _originx: X coordinate for origin.
|
|
* parameter _originy: Y coordinate for origin.
|
|
*/
|
|
void set_origin(size_t _originx, size_t _originy) throw();
|
|
/**
|
|
* Get X origin.
|
|
*
|
|
* Returns: The X origin.
|
|
*/
|
|
size_t get_origin_x() const throw();
|
|
/**
|
|
* Get Y origin.
|
|
*
|
|
* Returns: The Y origin.
|
|
*/
|
|
size_t get_origin_y() const throw();
|
|
/**
|
|
* Paints raw framebuffer into framebuffer. The upper-left of image will be at origin. Scales the image by given
|
|
* factors. If the image does not fit with specified scale factors, it is clipped.
|
|
*
|
|
* parameter scr The framebuffer to paint.
|
|
* parameter hscale Horizontal scale factor.
|
|
* parameter vscale Vertical scale factor.
|
|
*/
|
|
void copy_from(raw& scr, size_t hscale, size_t vscale) throw();
|
|
|
|
/**
|
|
* Get pointer into specified row.
|
|
*
|
|
* parameter row: Number of row (must be less than height).
|
|
* Returns: Pointer into row data.
|
|
*/
|
|
element_t* rowptr(size_t row) throw();
|
|
/**
|
|
* Get pointer into specified row.
|
|
*
|
|
* parameter row: Number of row (must be less than height).
|
|
* Returns: Pointer into row data.
|
|
*/
|
|
const element_t* rowptr(size_t row) const throw();
|
|
/**
|
|
* Set palette. Also converts the image data.
|
|
*
|
|
* parameter r Shift for red component
|
|
* parameter g Shift for green component
|
|
* parameter b Shift for blue component
|
|
*/
|
|
void set_palette(uint32_t r, uint32_t g, uint32_t b) throw(std::bad_alloc);
|
|
/**
|
|
* Get width of image.
|
|
*
|
|
* Returns: The width.
|
|
*/
|
|
size_t get_width() const throw();
|
|
/**
|
|
* Get height of image.
|
|
*
|
|
* Returns: The height.
|
|
*/
|
|
size_t get_height() const throw();
|
|
/**
|
|
* Get last blit width
|
|
*
|
|
* Returns: The width.
|
|
*/
|
|
size_t get_last_blit_width() const throw();
|
|
/**
|
|
* Get last blit height
|
|
*
|
|
* Returns: The height.
|
|
*/
|
|
size_t get_last_blit_height() const throw();
|
|
/**
|
|
* Get R palette offset.
|
|
*/
|
|
uint8_t get_palette_r() const throw();
|
|
/**
|
|
* Get G palette offset.
|
|
*/
|
|
uint8_t get_palette_g() const throw();
|
|
/**
|
|
* Get B palette offset.
|
|
*/
|
|
uint8_t get_palette_b() const throw();
|
|
private:
|
|
fb(const fb& f);
|
|
fb& operator=(const fb& f);
|
|
size_t width; //Width of framebuffer.
|
|
size_t height; //Height of framebuffer.
|
|
size_t stride; //Stride in pixels.
|
|
size_t offset_x; //X offset.
|
|
size_t offset_y; //Y offset.
|
|
size_t last_blit_w; //Width of last blit.
|
|
size_t last_blit_h; //Height of last blit.
|
|
element_t* mem; //The memory of framebuffer.
|
|
pixfmt* current_fmt; //Current format of framebuffer.
|
|
auxpalette<X> auxpal; //Aux palette.
|
|
bool user_mem; //True if internal memory is used.
|
|
bool upside_down; //Upside down flag.
|
|
uint8_t active_rshift; //Red shift.
|
|
uint8_t active_gshift; //Green shift.
|
|
uint8_t active_bshift; //Blue shift.
|
|
friend struct color;
|
|
};
|
|
|
|
struct queue;
|
|
|
|
/**
|
|
* Base class for objects to render.
|
|
*/
|
|
struct object
|
|
{
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
object() throw();
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
virtual ~object() throw();
|
|
/**
|
|
* Kill object function. If it returns true, kill the request. Default is to return false.
|
|
*/
|
|
virtual bool kill_request(void* obj) throw();
|
|
/**
|
|
* Return true if myobj and killobj are equal and not NULL.
|
|
*/
|
|
bool kill_request_ifeq(void* myobj, void* killobj);
|
|
/**
|
|
* Draw the object.
|
|
*
|
|
* parameter scr: The screen to draw it on.
|
|
*/
|
|
virtual void operator()(struct fb<false>& scr) throw() = 0;
|
|
virtual void operator()(struct fb<true>& scr) throw() = 0;
|
|
/**
|
|
* Clone the object.
|
|
*/
|
|
virtual void clone(struct queue& q) const throw(std::bad_alloc) = 0;
|
|
};
|
|
|
|
/**
|
|
* Premultiplied color.
|
|
*/
|
|
struct color
|
|
{
|
|
uint32_t hi;
|
|
uint32_t lo;
|
|
uint64_t hiHI;
|
|
uint64_t loHI;
|
|
uint32_t orig;
|
|
uint16_t origa;
|
|
uint16_t inv;
|
|
uint32_t invHI;
|
|
|
|
operator bool() const throw() { return (origa != 0); }
|
|
bool operator!() const throw() { return (origa == 0); }
|
|
|
|
color() throw()
|
|
{
|
|
hi = lo = 0;
|
|
hiHI = loHI = 0;
|
|
orig = 0;
|
|
origa = 0;
|
|
inv = 256;
|
|
invHI = 65536;
|
|
}
|
|
|
|
color(int64_t color) throw()
|
|
{
|
|
if(color < 0) {
|
|
//Transparent.
|
|
orig = 0;
|
|
origa = 0;
|
|
inv = 256;
|
|
} else {
|
|
orig = color & 0xFFFFFF;
|
|
origa = 256 - ((color >> 24) & 0xFF);;
|
|
inv = 256 - origa;
|
|
}
|
|
invHI = 256 * static_cast<uint32_t>(inv);
|
|
set_palette(16, 8, 0, false);
|
|
set_palette(32, 16, 0, true);
|
|
//std::cerr << "Color " << color << " -> hi=" << hi << " lo=" << lo << " inv=" << inv << std::endl;
|
|
}
|
|
void set_palette(unsigned rshift, unsigned gshift, unsigned bshift, bool X) throw();
|
|
template<bool X> void set_palette(struct fb<X>& s) throw()
|
|
{
|
|
set_palette(s.active_rshift, s.active_gshift, s.active_bshift, X);
|
|
}
|
|
uint32_t blend(uint32_t color) throw()
|
|
{
|
|
uint32_t a, b;
|
|
a = color & 0xFF00FF;
|
|
b = (color & 0xFF00FF00) >> 8;
|
|
return (((a * inv + hi) >> 8) & 0xFF00FF) | ((b * inv + lo) & 0xFF00FF00);
|
|
}
|
|
void apply(uint32_t& x) throw()
|
|
{
|
|
x = blend(x);
|
|
}
|
|
uint64_t blend(uint64_t color) throw()
|
|
{
|
|
uint64_t a, b;
|
|
a = color & 0xFFFF0000FFFFULL;
|
|
b = (color & 0xFFFF0000FFFF0000ULL) >> 16;
|
|
return (((a * invHI + hiHI) >> 16) & 0xFFFF0000FFFFULL) | ((b * invHI + loHI) &
|
|
0xFFFF0000FFFF0000ULL);
|
|
}
|
|
void apply(uint64_t& x) throw()
|
|
{
|
|
x = blend(x);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Bitmap font (8x16).
|
|
*/
|
|
struct font
|
|
{
|
|
/**
|
|
* Bitmap font glyph.
|
|
*/
|
|
struct glyph
|
|
{
|
|
bool wide; //If set, 16 wide instead of 8.
|
|
uint32_t* data; //Glyph data. Bitpacked with element padding between rows.
|
|
size_t offset; //Glyph offset.
|
|
};
|
|
|
|
/**
|
|
* Bitmap font layout.
|
|
*/
|
|
struct layout
|
|
{
|
|
size_t x; //X position.
|
|
size_t y; //Y position.
|
|
const glyph* dglyph; //The glyph itself.
|
|
};
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
font() throw(std::bad_alloc);
|
|
/**
|
|
* Load a .hex format font.
|
|
*
|
|
* Parameter data: The font data.
|
|
* Parameter size: The font data size in bytes.
|
|
* Throws std::runtime_error: Bad font data.
|
|
*/
|
|
void load_hex(const char* data, size_t size) throw(std::bad_alloc, std::runtime_error);
|
|
/**
|
|
* Locate glyph.
|
|
*
|
|
* Parameter glyph: Number of glyph to locate.
|
|
* Returns: Glyph parameters.
|
|
*/
|
|
const glyph& get_glyph(uint32_t glyph) throw();
|
|
/**
|
|
* Get metrics of string.
|
|
*
|
|
* Parameter string: The string to get metrics of.
|
|
* Returns: A pair. First element is width of string, the second is height of string.
|
|
*/
|
|
std::pair<size_t, size_t> get_metrics(const std::string& string) throw();
|
|
/**
|
|
* Layout a string.
|
|
*
|
|
* Parameter string: The string to get layout of.
|
|
* Returns: String layout.
|
|
*/
|
|
std::vector<layout> dolayout(const std::string& string) throw(std::bad_alloc);
|
|
/**
|
|
* Get set of all glyph numbers.
|
|
*/
|
|
std::set<uint32_t> get_glyphs_set();
|
|
/**
|
|
* Get bad glyph.
|
|
*/
|
|
const glyph& get_bad_glyph() throw();
|
|
/**
|
|
* Render string to framebuffer.
|
|
*
|
|
* Parameter framebuffer: The framebuffer to render on.
|
|
* Parameter x: The x-coordinate to start from.
|
|
* Parameter y: The y-coordinate to start from.
|
|
* Parameter text: The text to render.
|
|
* Parameter fg: The foreground color.
|
|
* Parameter bg: The background color.
|
|
* Parameter hdbl: If set, double width horizontally.
|
|
* Parameter vdbl: If set, double height vertically.
|
|
*/
|
|
template<bool X> void render(struct fb<X>& scr, int32_t x, int32_t y, const std::string& text,
|
|
color fg, color bg, bool hdbl, bool vdbl) throw();
|
|
private:
|
|
glyph bad_glyph;
|
|
uint32_t bad_glyph_data[4];
|
|
std::map<uint32_t, glyph> glyphs;
|
|
size_t tabstop;
|
|
std::vector<uint32_t> memory;
|
|
void load_hex_glyph(const char* data, size_t size) throw(std::bad_alloc, std::runtime_error);
|
|
};
|
|
|
|
|
|
#define RENDER_PAGE_SIZE 65500
|
|
|
|
/**
|
|
* Queue of render operations.
|
|
*/
|
|
struct queue
|
|
{
|
|
/**
|
|
* Applies all objects in the queue in order.
|
|
*
|
|
* parameter scr: The screen to apply queue to.
|
|
*/
|
|
template<bool X> void run(struct fb<X>& scr) throw();
|
|
|
|
/**
|
|
* Frees all objects in the queue without applying them.
|
|
*/
|
|
void clear() throw();
|
|
/**
|
|
* Call kill_request on all objects in queue.
|
|
*/
|
|
void kill_request(void* obj) throw();
|
|
/**
|
|
* Get memory from internal allocator.
|
|
*/
|
|
void* alloc(size_t block) throw(std::bad_alloc);
|
|
|
|
/**
|
|
* Call object constructor on internal memory.
|
|
*/
|
|
template<class T, typename... U> void create_add(U... args)
|
|
{
|
|
add(*new(alloc(sizeof(T))) T(args...));
|
|
}
|
|
/**
|
|
* Copy objects from another render queue.
|
|
*/
|
|
void copy_from(queue& q) throw(std::bad_alloc);
|
|
/**
|
|
* Helper for clone.
|
|
*/
|
|
template<typename T> void clone_helper(const T* obj)
|
|
{
|
|
create_add<T>(*obj);
|
|
}
|
|
/**
|
|
* Get number of objects.
|
|
*/
|
|
size_t get_object_count()
|
|
{
|
|
size_t c = 0;
|
|
struct node* n = queue_head;
|
|
while(n != queue_tail) {
|
|
n = n->next;
|
|
c++;
|
|
}
|
|
return c;
|
|
}
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
queue() throw();
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
~queue() throw();
|
|
private:
|
|
void add(struct object& obj) throw(std::bad_alloc);
|
|
struct node { struct object* obj; struct node* next; bool killed; };
|
|
struct page { char content[RENDER_PAGE_SIZE]; };
|
|
struct node* queue_head;
|
|
struct node* queue_tail;
|
|
size_t memory_allocated;
|
|
size_t pages;
|
|
std::map<size_t, page> memory;
|
|
};
|
|
|
|
/**
|
|
* Clip range inside another.
|
|
*
|
|
* parameter origin: Origin coordinate.
|
|
* parameter size: Dimension size.
|
|
* parameter base: Base coordinate.
|
|
* parameter minc: Minimum coordinate relative to base. Updated.
|
|
* parameter maxc: Maximum coordinate relative to base. Updated.
|
|
*/
|
|
void clip_range(uint32_t origin, uint32_t size, int32_t base, int32_t& minc, int32_t& maxc) throw();
|
|
}
|
|
|
|
#endif
|