From 1f631a8ad00d53df4688c52500be1880285b7cbf Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Wed, 20 Jun 2012 17:40:27 +0300 Subject: [PATCH] Librarify screen rendering --- include/core/advdumper.hpp | 8 +- include/core/dispatch.hpp | 12 +- include/core/framebuffer.hpp | 14 +- include/core/render.hpp | 435 ------------- include/core/window.hpp | 2 +- include/library/framebuffer.hpp | 585 ++++++++++++++++++ include/library/pixfmt-lrgb.hpp | 30 + include/library/pixfmt-rgb15.hpp | 32 + include/library/pixfmt-rgb16.hpp | 32 + include/library/pixfmt-rgb24.hpp | 32 + include/library/pixfmt-rgb32.hpp | 30 + include/{core => library}/png.hpp | 0 include/library/serialization.hpp | 34 +- include/library/utf8.hpp | 30 + include/lua/bitmap.hpp | 2 +- include/lua/lua.hpp | 2 +- src/core/advdumper.cpp | 26 +- src/core/dispatch.cpp | 8 +- src/core/framebuffer.cpp | 73 ++- src/core/mainloop.cpp | 18 +- src/core/moviedata.cpp | 2 +- src/core/render.cpp | 668 -------------------- src/core/window.cpp | 15 +- src/fonts/Makefile | 6 +- src/fonts/wrapper.cpp | 15 + src/library/framebuffer.cpp | 844 ++++++++++++++++++++++++++ src/library/pixfmt-lrgb.cpp | 90 +++ src/library/pixfmt-rgb15.cpp | 100 +++ src/library/pixfmt-rgb16.cpp | 99 +++ src/library/pixfmt-rgb24.cpp | 85 +++ src/library/pixfmt-rgb32.cpp | 71 +++ src/{core => library}/png.cpp | 2 +- src/library/utf8.cpp | 182 ++++++ src/lua/gui-bitmap.cpp | 18 +- src/lua/gui-box.cpp | 18 +- src/lua/gui-circle.cpp | 18 +- src/lua/gui-crosshair.cpp | 18 +- src/lua/gui-line.cpp | 48 +- src/lua/gui-pixel.cpp | 16 +- src/lua/gui-rectangle.cpp | 18 +- src/lua/gui-text.cpp | 11 +- src/platform/portaudio/sound.cpp | 2 +- src/platform/sdl/sound.cpp | 2 +- src/platform/wxwidgets/mainwindow.cpp | 16 +- src/util/lsnes-dumpavi.cpp | 2 +- src/video/avi.cpp | 10 +- src/video/jmd.cpp | 6 +- src/video/raw.cpp | 22 +- 48 files changed, 2506 insertions(+), 1303 deletions(-) delete mode 100644 include/core/render.hpp create mode 100644 include/library/framebuffer.hpp create mode 100644 include/library/pixfmt-lrgb.hpp create mode 100644 include/library/pixfmt-rgb15.hpp create mode 100644 include/library/pixfmt-rgb16.hpp create mode 100644 include/library/pixfmt-rgb24.hpp create mode 100644 include/library/pixfmt-rgb32.hpp rename include/{core => library}/png.hpp (100%) create mode 100644 include/library/utf8.hpp delete mode 100644 src/core/render.cpp create mode 100644 src/fonts/wrapper.cpp create mode 100644 src/library/framebuffer.cpp create mode 100644 src/library/pixfmt-lrgb.cpp create mode 100644 src/library/pixfmt-rgb15.cpp create mode 100644 src/library/pixfmt-rgb16.cpp create mode 100644 src/library/pixfmt-rgb24.cpp create mode 100644 src/library/pixfmt-rgb32.cpp rename src/{core => library}/png.cpp (99%) create mode 100644 src/library/utf8.cpp diff --git a/include/core/advdumper.hpp b/include/core/advdumper.hpp index a06574fd..e913e4fb 100644 --- a/include/core/advdumper.hpp +++ b/include/core/advdumper.hpp @@ -5,7 +5,7 @@ #include #include -#include "core/render.hpp" +#include "library/framebuffer.hpp" class adv_dumper { @@ -110,8 +110,8 @@ private: * Parameter bgap: Bottom gap. * Parameter fn: Function to call between running lua hooks and actually rendering. */ -template void render_video_hud(struct screen& target, struct lcscreen& source, uint32_t hscl, uint32_t vscl, - uint32_t roffset, uint32_t goffset, uint32_t boffset, uint32_t lgap, uint32_t tgap, uint32_t rgap, - uint32_t bgap, void(*fn)()); +template void render_video_hud(struct framebuffer& target, struct framebuffer_raw& source, uint32_t hscl, + uint32_t vscl, uint32_t roffset, uint32_t goffset, uint32_t boffset, uint32_t lgap, uint32_t tgap, + uint32_t rgap, uint32_t bgap, void(*fn)()); #endif diff --git a/include/core/dispatch.hpp b/include/core/dispatch.hpp index 0ad3ac14..3d08b5ac 100644 --- a/include/core/dispatch.hpp +++ b/include/core/dispatch.hpp @@ -1,8 +1,8 @@ #ifndef _dispatch__hpp__included__ #define _dispatch__hpp__included__ -#include "render.hpp" -#include "keymapper.hpp" +#include "core/keymapper.hpp" +#include "library/framebuffer.hpp" #include #include @@ -224,13 +224,13 @@ public: * Parameter fps_n: Numerator of current video fps. * Parameter fps_d: Denominator of current video fps. */ - virtual void on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d); + virtual void on_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d); /** * Call all on_frame() handlers. * * Calls on_new_dumper() on dumpers that had that not yet called. */ - static void do_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) throw(); + static void do_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d) throw(); /** * A sample has been received. * @@ -378,11 +378,11 @@ public: * * parameter scr: The render buffer object. */ - virtual void on_set_screen(screen& scr); + virtual void on_set_screen(framebuffer& scr); /** * Call on_set_screen on all objects. */ - static void do_set_screen(screen& scr) throw(); + static void do_set_screen(framebuffer& scr) throw(); /** * Notify that new frame is available. * diff --git a/include/core/framebuffer.hpp b/include/core/framebuffer.hpp index 632053bc..8f693ae6 100644 --- a/include/core/framebuffer.hpp +++ b/include/core/framebuffer.hpp @@ -1,8 +1,8 @@ #ifndef _framebuffer__hpp__included__ #define _framebuffer__hpp__included__ -#include "core/render.hpp" #include "core/window.hpp" +#include "library/framebuffer.hpp" #include @@ -54,19 +54,19 @@ private: /** * The main framebuffer. */ -extern lcscreen framebuffer; +extern framebuffer_raw main_framebuffer; /** * Special screen: "NO SIGNAL". */ -extern lcscreen screen_nosignal; +extern framebuffer_raw screen_nosignal; /** * Special screen: "SYSTEM STATE CORRUPT". */ -extern lcscreen screen_corrupt; +extern framebuffer_raw screen_corrupt; /** * The main screen to draw on. */ -extern screen main_screen; +extern framebuffer main_screen; /** * Initialize special screens. * @@ -76,7 +76,7 @@ void init_special_screens() throw(std::bad_alloc); /** * Copy framebuffer to backing store, running Lua hooks if any. */ -void redraw_framebuffer(lcscreen& torender, bool no_lua = false, bool spontaneous = false); +void redraw_framebuffer(framebuffer_raw& torender, bool no_lua = false, bool spontaneous = false); /** * Redraw the framebuffer, reusing contents from last redraw. Runs lua hooks if last redraw ran them. */ @@ -84,7 +84,7 @@ void redraw_framebuffer(); /** * Return last complete framebuffer. */ -lcscreen get_framebuffer() throw(std::bad_alloc); +framebuffer_raw get_framebuffer() throw(std::bad_alloc); /** * Render framebuffer to main screen. */ diff --git a/include/core/render.hpp b/include/core/render.hpp deleted file mode 100644 index 08461c9a..00000000 --- a/include/core/render.hpp +++ /dev/null @@ -1,435 +0,0 @@ -#ifndef _render__hpp__included__ -#define _render__hpp__included__ - - -#include -#include -#include -#include -#include -#include -#include - -/** - * Low color (32768 colors) screen from buffer. - */ -struct lcscreen -{ -/** - * Create new screen from bsnes output data. - * - * parameter mem The output buffer from bsnes. - * parameter hires True if in hires mode (512-wide lines instead of 256-wide). - * parameter interlace True if in interlace mode. - * parameter overscan True if overscan is enabled. - * parameter region True if PAL, false if NTSC. - */ - lcscreen(const uint32_t* mem, bool hires, bool interlace, bool overscan, bool region) throw(); - -/** - * Create new memory-backed screen. The resulting screen can be written to. - */ - lcscreen() throw(); -/** - * Create new screen with specified contents and size. - * - * parameter mem: Memory to use as frame data. 1 element per pixel. Left-to-Right, top-to-bottom order. - * parameter _width: Width of the screen to create. - * parameter _height: Height of the screen to create. - */ - lcscreen(const uint32_t* mem, uint32_t _width, uint32_t _height) throw(); -/** - * Copy the screen. - * - * The assigned copy is always writable. - * - * parameter ls: The source screen. - * throws std::bad_alloc: Not enough memory. - */ - lcscreen(const lcscreen& ls) throw(std::bad_alloc); -/** - * Assign the screen. - * - * parameter ls: The source screen. - * returns: Reference to target screen. - * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: The target screen is not writable. - */ - lcscreen& operator=(const lcscreen& ls) throw(std::bad_alloc, std::runtime_error); -/** - * Load contents of screen. - * - * parameter data: The data to load. - * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: The target screen is not writable. - */ - void load(const std::vector& data) throw(std::bad_alloc, std::runtime_error); -/** - * Save contents of screen. - * - * parameter data: The vector to write the data to (in format compatible with load()). - * throws std::bad_alloc: Not enough memory. - */ - void save(std::vector& data) throw(std::bad_alloc); -/** - * Save contents of screen as a PNG. - * - * parameter file: The filename to save to. - * throws std::bad_alloc: Not enough memory. - * throws std::runtime_error: Can't save the PNG. - */ - void save_png(const std::string& file) throw(std::bad_alloc, std::runtime_error); - -/** - * Destructor. - */ - ~lcscreen(); - -/** - * True if memory is allocated by new[] and should be freed by the destructor., false otherwise. Also signals - * writablity. - */ - bool user_memory; - -/** - * Memory, 1 element per pixel in left-to-right, top-to-bottom order, 15 low bits of each element used. - */ - const uint32_t* memory; - -/** - * Number of elements (not bytes) between two successive scanlines. - */ - uint32_t pitch; - -/** - * Width of image. - */ - uint32_t width; - -/** - * Height of image. - */ - uint32_t height; - -/** - * Image allocated size (only valid for user_memory=true). - */ - size_t allocated; -}; - -template struct screenelem {}; -template<> struct screenelem { typedef uint32_t t; }; -template<> struct screenelem { typedef uint64_t t; }; - -/** - * Hicolor modifiable screen. - */ -template -struct screen -{ - typedef typename screenelem::t element_t; -/** - * Creates screen. The screen dimensions are initially 0x0. - */ - screen() throw(); - -/** - * Destructor. - */ - ~screen() throw(); - -/** - * Sets the backing memory for screen. The specified memory is not freed if screen is reallocated or destroyed. - * - * parameter _memory: The memory buffer. - * parameter _width: Width of screen. - * parameter _height: Height of screen. - * parameter _pitch: Distance in bytes between successive scanlines. - */ - void set(element_t* _memory, uint32_t _width, uint32_t _height, uint32_t _pitch) throw(); - -/** - * Sets the size of the screen. The memory is freed if screen is reallocated or destroyed. - * - * parameter _width: Width of screen. - * parameter _height: Height of screen. - * parameter upside_down: If true, image is upside down in memory. - * throws std::bad_alloc: Not enough memory. - */ - void reallocate(uint32_t _width, uint32_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(uint32_t _originx, uint32_t _originy) throw(); - -/** - * Paints low-color screen into screen. 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 screen to paint. - * parameter hscale Horizontal scale factor. - * parameter vscale Vertical scale factor. - */ - void copy_from(lcscreen& scr, uint32_t hscale, uint32_t vscale) throw(); - -/** - * Get pointer into specified row. - * - * parameter row: Number of row (must be less than height). - */ - element_t* rowptr(uint32_t row) 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); - -/** - * Active palette - */ - element_t* palette; - uint32_t palette_r; - uint32_t palette_g; - uint32_t palette_b; - -/** - * Backing memory for this screen. - */ - element_t* memory; - -/** - * True if memory is given by user and must not be freed. - */ - bool user_memory; - -/** - * Width of screen. - */ - uint32_t width; - -/** - * Height of screen. - */ - uint32_t height; - -/** - * Distance between lines in bytes. - */ - size_t pitch; - -/** - * True if image is upside down in memory. - */ - bool flipped; - -/** - * X-coordinate of origin. - */ - uint32_t originx; - -/** - * Y-coordinate of origin. - */ - uint32_t originy; -private: - screen(const screen&); - screen& operator=(const screen&); -}; - -/** - * Base class for objects to render. - */ -struct render_object -{ -/** - * Destructor. - */ - virtual ~render_object() throw(); - -/** - * Draw the object. - * - * parameter scr: The screen to draw it on. - */ - virtual void operator()(struct screen& scr) throw() = 0; - virtual void operator()(struct screen& scr) throw() = 0; -}; - - - -/** - * Premultiplied color. - */ -struct premultiplied_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; - - premultiplied_color() throw() - { - hi = lo = 0; - hiHI = loHI = 0; - orig = 0; - origa = 0; - inv = 256; - invHI = 65536; - } - - premultiplied_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(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 void set_palette(struct screen& s) throw() - { - set_palette(s.palette_r, s.palette_g, s.palette_b, 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); - } -}; - -#define RENDER_PAGE_SIZE 65500 - -/** - * Queue of render operations. - */ -struct render_queue -{ -/** - * Applies all objects in the queue in order. - * - * parameter scr: The screen to apply queue to. - */ - template void run(struct screen& scr) throw(); - -/** - * Frees all objects in the queue without applying them. - */ - void clear() throw(); - -/** - * Get memory from internal allocator. - */ - void* alloc(size_t block) throw(std::bad_alloc); - -/** - * Call object constructor on internal memory. - */ - template void create_add(U... args) - { - add(*new(alloc(sizeof(T))) T(args...)); - } - -/** - * Constructor. - */ - render_queue() throw(); -/** - * Destructor. - */ - ~render_queue() throw(); -private: - void add(struct render_object& obj) throw(std::bad_alloc); - struct node { struct render_object* obj; struct node* next; }; - struct page { char content[RENDER_PAGE_SIZE]; }; - struct node* queue_head; - struct node* queue_tail; - size_t memory_allocated; - size_t pages; - std::map 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(); - -/** - * Initialize font data. - */ -void do_init_font(); - -/** - * Read font data for glyph. - * - * parameter codepoint: Code point of glyph. - * parameter x: X position to render into. - * parameter y: Y position to render into. - * parameter orig_x: X position at start of row. - * parameter next_x: X position for next glyph is written here. - * parameter next_y: Y position for next glyph is written here. - * returns: Two components: First is width of character, second is pointer to font data (NULL if blank glyph). - */ -std::pair find_glyph(uint32_t codepoint, int32_t x, int32_t y, int32_t orig_x, - int32_t& next_x, int32_t& next_y, bool hdbl = false, bool vdbl = false) throw(); - -/** - * Render text into screen. - * - * parameter _x: The x position to render to (relative to origin). - * parameter _y: The y position to render to (relative to origin). - * parameter _text: The text to render (UTF-8). - * parameter _fg: Foreground color. - * parameter _bg: Background color. - * parameter _hdbl: If true, draw text using double width. - * parameter _vdbl: If true, draw text using double height. - * throws std::bad_alloc: Not enough memory. - */ -template void render_text(struct screen& scr, int32_t _x, int32_t _y, const std::string& _text, - premultiplied_color _fg, premultiplied_color _bg, bool _hdbl = false, bool _vdbl = false) - throw(std::bad_alloc); - -#endif diff --git a/include/core/window.hpp b/include/core/window.hpp index 65909dcb..b1edddae 100644 --- a/include/core/window.hpp +++ b/include/core/window.hpp @@ -3,8 +3,8 @@ #include "core/keymapper.hpp" #include "core/messagebuffer.hpp" -#include "core/render.hpp" #include "core/status.hpp" +#include "library/framebuffer.hpp" #include #include #include diff --git a/include/library/framebuffer.hpp b/include/library/framebuffer.hpp new file mode 100644 index 00000000..47e97083 --- /dev/null +++ b/include/library/framebuffer.hpp @@ -0,0 +1,585 @@ +#ifndef _library__framebuffer__hpp__included__ +#define _library__framebuffer__hpp__included__ + +#include +#include +#include +#include + +template struct framebufferelem {}; +template<> struct framebufferelem { typedef uint32_t t; }; +template<> struct framebufferelem { typedef uint64_t t; }; + +/** + * Pixel format auxillary palette. + */ +template +struct pixel_format_aux_palette +{ + typedef typename framebufferelem::t element_t; + uint8_t rshift; //Red shift. + uint8_t gshift; //Green shift. + uint8_t bshift; //Blue shift. + std::vector pcache; //Palette cache. +}; + +/** + * Pixel format. + */ +class pixel_format +{ +public: + virtual ~pixel_format() throw(); +/** + * Register the pixel format. + */ + pixel_format() throw(std::bad_alloc); +/** + * Decode pixel format data into RGB24 data (R, G, B). + */ + virtual void decode(uint8_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 pixel_format_aux_palette& 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 pixel_format_aux_palette& auxp) throw() = 0; +/** + * Create aux palette. + */ + virtual void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) = 0; +/** + * Create aux palette. + */ + virtual void set_palette(pixel_format_aux_palette& 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 framebuffer_info +{ +/** + * Pixel format of framebuffer. + */ + pixel_format* 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 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 framebuffer_raw +{ +/** + * Create a new framebuffer backed by temporary buffer. + * + * The resulting framebuffer is read-only. + * + * Parameter info: The framebuffer info. + */ + framebuffer_raw(const framebuffer_info& info) throw(std::bad_alloc); +/** + * Create a new framebuffer backed by memory buffer. + * + * The resulting framebuffer can be written to. + */ + framebuffer_raw() throw(std::bad_alloc); +/** + * Copy a framebuffer. + * + * The resulting copy is writable. + * + * Parameter f: The framebuffer. + */ + framebuffer_raw(const framebuffer_raw& f) throw(std::bad_alloc); +/** + * Assign a framebuffer. + * + * Parameter f: The framebuffer. + * Throws std::runtime_error: The target framebuffer is not writable. + */ + framebuffer_raw& operator=(const framebuffer_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& 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& 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(); +/** + * Destructor. + */ + ~framebuffer_raw(); +private: + bool user_memory; //True if allocated in user memory, false if aliases framebuffer. + char* addr; //Address of framebuffer start. + pixel_format* 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 friend class framebuffer; +}; + + +struct premultiplied_color; + +/** + * Rendered framebuffer. + * + * This framebuffer is in RGB32/RGB64 format, and is always backed by memory buffer. + */ +template +struct framebuffer +{ + typedef typename framebufferelem::t element_t; +/** + * Creates framebuffer. The framebuffer dimensions are initially 0x0. + */ + framebuffer() throw(); + +/** + * Destructor. + */ + ~framebuffer() 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(framebuffer_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 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: + framebuffer(const framebuffer& f); + framebuffer& operator=(const framebuffer& 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. + element_t* mem; //The memory of framebuffer. + pixel_format* current_fmt; //Current format of framebuffer. + pixel_format_aux_palette 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 premultiplied_color; +}; + +/** + * Base class for objects to render. + */ +struct render_object +{ +/** + * Destructor. + */ + virtual ~render_object() throw(); + +/** + * Draw the object. + * + * parameter scr: The screen to draw it on. + */ + virtual void operator()(struct framebuffer& scr) throw() = 0; + virtual void operator()(struct framebuffer& scr) throw() = 0; +}; + + + +/** + * Premultiplied color. + */ +struct premultiplied_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; + + premultiplied_color() throw() + { + hi = lo = 0; + hiHI = loHI = 0; + orig = 0; + origa = 0; + inv = 256; + invHI = 65536; + } + + premultiplied_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(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 void set_palette(struct framebuffer& 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 bitmap_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. + */ + bitmap_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 get_metrics(const std::string& string) throw(); +/** + * Layout a string. + * + * Parameter string: The string to get layout of. + * Returns: String layout. + */ + std::vector dolayout(const std::string& string) throw(std::bad_alloc); +/** + * 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 void render(struct framebuffer& scr, int32_t x, int32_t y, const std::string& text, + premultiplied_color fg, premultiplied_color bg, bool hdbl, bool vdbl) throw(); +private: + glyph bad_glyph; + uint32_t bad_glyph_data[4]; + std::map glyphs; + size_t tabstop; + std::vector 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 render_queue +{ +/** + * Applies all objects in the queue in order. + * + * parameter scr: The screen to apply queue to. + */ + template void run(struct framebuffer& scr) throw(); + +/** + * Frees all objects in the queue without applying them. + */ + void clear() throw(); + +/** + * Get memory from internal allocator. + */ + void* alloc(size_t block) throw(std::bad_alloc); + +/** + * Call object constructor on internal memory. + */ + template void create_add(U... args) + { + add(*new(alloc(sizeof(T))) T(args...)); + } + +/** + * Constructor. + */ + render_queue() throw(); +/** + * Destructor. + */ + ~render_queue() throw(); +private: + void add(struct render_object& obj) throw(std::bad_alloc); + struct node { struct render_object* obj; struct node* next; }; + struct page { char content[RENDER_PAGE_SIZE]; }; + struct node* queue_head; + struct node* queue_tail; + size_t memory_allocated; + size_t pages; + std::map 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 diff --git a/include/library/pixfmt-lrgb.hpp b/include/library/pixfmt-lrgb.hpp new file mode 100644 index 00000000..d7724510 --- /dev/null +++ b/include/library/pixfmt-lrgb.hpp @@ -0,0 +1,30 @@ +#ifndef _pixfmt_lrgb__hpp__included__ +#define _pixfmt_lrgb__hpp__included__ + +#include "framebuffer.hpp" + +/** + * Pixel format LRGB (bsnes). + */ +class pixel_format_lrgb : public pixel_format +{ +public: + ~pixel_format_lrgb() throw(); + void decode(uint8_t* target, const uint8_t* src, size_t width) + throw(); + void decode(uint32_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw(); + void decode(uint64_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw(); + void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc); + void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc); + uint8_t get_bpp() throw(); + uint8_t get_ss_bpp() throw(); + uint32_t get_magic() throw(); +}; + +extern pixel_format_lrgb _pixel_format_lrgb; + +#endif diff --git a/include/library/pixfmt-rgb15.hpp b/include/library/pixfmt-rgb15.hpp new file mode 100644 index 00000000..3047d5db --- /dev/null +++ b/include/library/pixfmt-rgb15.hpp @@ -0,0 +1,32 @@ +#ifndef _pixfmt_rgb15__hpp__included__ +#define _pixfmt_rgb15__hpp__included__ + +#include "framebuffer.hpp" + +/** + * Pixel format RGB15 (5:5:5). + */ +template +class pixel_format_rgb15 : public pixel_format +{ +public: + ~pixel_format_rgb15() throw(); + void decode(uint8_t* target, const uint8_t* src, size_t width) + throw(); + void decode(uint32_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw(); + void decode(uint64_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw(); + void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc); + void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc); + uint8_t get_bpp() throw(); + uint8_t get_ss_bpp() throw(); + uint32_t get_magic() throw(); +}; + +extern pixel_format_rgb15 _pixel_format_rgb15; +extern pixel_format_rgb15 _pixel_format_bgr15; + +#endif diff --git a/include/library/pixfmt-rgb16.hpp b/include/library/pixfmt-rgb16.hpp new file mode 100644 index 00000000..dd53351b --- /dev/null +++ b/include/library/pixfmt-rgb16.hpp @@ -0,0 +1,32 @@ +#ifndef _pixfmt_rgb16__hpp__included__ +#define _pixfmt_rgb16__hpp__included__ + +#include "framebuffer.hpp" + +/** + * Pixel format RGB16 (5:6:5). + */ +template +class pixel_format_rgb16 : public pixel_format +{ +public: + ~pixel_format_rgb16() throw(); + void decode(uint8_t* target, const uint8_t* src, size_t width) + throw(); + void decode(uint32_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw(); + void decode(uint64_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw(); + void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc); + void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc); + uint8_t get_bpp() throw(); + uint8_t get_ss_bpp() throw(); + uint32_t get_magic() throw(); +}; + +extern pixel_format_rgb16 _pixel_format_rgb16; +extern pixel_format_rgb16 _pixel_format_bgr16; + +#endif diff --git a/include/library/pixfmt-rgb24.hpp b/include/library/pixfmt-rgb24.hpp new file mode 100644 index 00000000..89a8dced --- /dev/null +++ b/include/library/pixfmt-rgb24.hpp @@ -0,0 +1,32 @@ +#ifndef _pixfmt_rgb24__hpp__included__ +#define _pixfmt_rgb24__hpp__included__ + +#include "framebuffer.hpp" + +/** + * Pixel format RGB24. + */ +template +class pixel_format_rgb24 : public pixel_format +{ +public: + ~pixel_format_rgb24() throw(); + void decode(uint8_t* target, const uint8_t* src, size_t width) + throw(); + void decode(uint32_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw(); + void decode(uint64_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw(); + void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc); + void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc); + uint8_t get_bpp() throw(); + uint8_t get_ss_bpp() throw(); + uint32_t get_magic() throw(); +}; + +extern pixel_format_rgb24 _pixel_format_rgb24; +extern pixel_format_rgb24 _pixel_format_bgr24; + +#endif diff --git a/include/library/pixfmt-rgb32.hpp b/include/library/pixfmt-rgb32.hpp new file mode 100644 index 00000000..d70992a2 --- /dev/null +++ b/include/library/pixfmt-rgb32.hpp @@ -0,0 +1,30 @@ +#ifndef _pixfmt_rgb32__hpp__included__ +#define _pixfmt_rgb32__hpp__included__ + +#include "framebuffer.hpp" + +/** + * Pixel format RGB32. + */ +class pixel_format_rgb32 : public pixel_format +{ +public: + ~pixel_format_rgb32() throw(); + void decode(uint8_t* target, const uint8_t* src, size_t width) + throw(); + void decode(uint32_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw(); + void decode(uint64_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw(); + void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc); + void set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc); + uint8_t get_bpp() throw(); + uint8_t get_ss_bpp() throw(); + uint32_t get_magic() throw(); +}; + +extern pixel_format_rgb32 _pixel_format_rgb32; + +#endif diff --git a/include/core/png.hpp b/include/library/png.hpp similarity index 100% rename from include/core/png.hpp rename to include/library/png.hpp diff --git a/include/library/serialization.hpp b/include/library/serialization.hpp index 4385b7e0..81cbd240 100644 --- a/include/library/serialization.hpp +++ b/include/library/serialization.hpp @@ -12,7 +12,7 @@ void _write_common(unsigned char* target, T1 value) } template -T1 _read_common(unsigned char* source) +T1 _read_common(const unsigned char* source) { T2 value = 0; for(size_t i = 0; i < ssize; i++) @@ -39,22 +39,22 @@ T1 _read_common(unsigned char* source) #define write64sle(t, v) _write_common< int64_t, uint64_t, 8, false>(reinterpret_cast(t), (v)); #define write64ube(t, v) _write_common(reinterpret_cast(t), (v)); #define write64ule(t, v) _write_common(reinterpret_cast(t), (v)); -#define read8sbe(t) _read_common< int8_t, uint8_t, 1, true>(reinterpret_cast(t)); -#define read8sle(t) _read_common< int8_t, uint8_t, 1, false>(reinterpret_cast(t)); -#define read8ube(t) _read_common< uint8_t, uint8_t, 1, true>(reinterpret_cast(t)); -#define read8ule(t) _read_common< uint8_t, uint8_t, 1, false>(reinterpret_cast(t)); -#define read16sbe(t) _read_common< int16_t, uint16_t, 2, true>(reinterpret_cast(t)); -#define read16sle(t) _read_common< int16_t, uint16_t, 2, false>(reinterpret_cast(t)); -#define read16ube(t) _read_common(reinterpret_cast(t)); -#define read16ule(t) _read_common(reinterpret_cast(t)); -#define read32sbe(t) _read_common< int32_t, uint32_t, 4, true>(reinterpret_cast(t)); -#define read32sle(t) _read_common< int32_t, uint32_t, 4, false>(reinterpret_cast(t)); -#define read32ube(t) _read_common(reinterpret_cast(t)); -#define read32ule(t) _read_common(reinterpret_cast(t)); -#define read64sbe(t) _read_common< int64_t, uint64_t, 8, true>(reinterpret_cast(t)); -#define read64sle(t) _read_common< int64_t, uint64_t, 8, false>(reinterpret_cast(t)); -#define read64ube(t) _read_common(reinterpret_cast(t)); -#define read64ule(t) _read_common(reinterpret_cast(t)); +#define read8sbe(t) _read_common< int8_t, uint8_t, 1, true>(reinterpret_cast(t)); +#define read8sle(t) _read_common< int8_t, uint8_t, 1, false>(reinterpret_cast(t)); +#define read8ube(t) _read_common< uint8_t, uint8_t, 1, true>(reinterpret_cast(t)); +#define read8ule(t) _read_common< uint8_t, uint8_t, 1, false>(reinterpret_cast(t)); +#define read16sbe(t) _read_common< int16_t, uint16_t, 2, true>(reinterpret_cast(t)); +#define read16sle(t) _read_common< int16_t, uint16_t, 2, false>(reinterpret_cast(t)); +#define read16ube(t) _read_common(reinterpret_cast(t)); +#define read16ule(t) _read_common(reinterpret_cast(t)); +#define read32sbe(t) _read_common< int32_t, uint32_t, 4, true>(reinterpret_cast(t)); +#define read32sle(t) _read_common< int32_t, uint32_t, 4, false>(reinterpret_cast(t)); +#define read32ube(t) _read_common(reinterpret_cast(t)); +#define read32ule(t) _read_common(reinterpret_cast(t)); +#define read64sbe(t) _read_common< int64_t, uint64_t, 8, true>(reinterpret_cast(t)); +#define read64sle(t) _read_common< int64_t, uint64_t, 8, false>(reinterpret_cast(t)); +#define read64ube(t) _read_common(reinterpret_cast(t)); +#define read64ule(t) _read_common(reinterpret_cast(t)); diff --git a/include/library/utf8.hpp b/include/library/utf8.hpp new file mode 100644 index 00000000..1b8fb25e --- /dev/null +++ b/include/library/utf8.hpp @@ -0,0 +1,30 @@ +#ifndef _utf8__hpp__included__ +#define _utf8__hpp__included__ + +#include +#include +#include + +/** + * Initial state for UTF-8 parser. + */ +extern const uint16_t utf8_initial_state; +/** + * Parse a byte. + * + * Parameter ch: The character to parse. -1 for end of string. + * Parameter state: The state. Mutated. + * Returns: The codepoint, or -1 if no codepoint emitted. + * + * Note: When called with EOF, max 1 codepoint can be emitted. + */ +int32_t utf8_parse_byte(int ch, uint16_t& state) throw(); +/** + * Return length of string in UTF-8 codepoints. + * + * Parameter str: The string. + * Returns: The length in codepoints. + */ +size_t utf8_strlen(const std::string& str) throw(); + +#endif diff --git a/include/lua/bitmap.hpp b/include/lua/bitmap.hpp index 9b2341e7..5e0ad635 100644 --- a/include/lua/bitmap.hpp +++ b/include/lua/bitmap.hpp @@ -4,8 +4,8 @@ #include #include #include -#include "core/render.hpp" #include "core/window.hpp" +#include "library/framebuffer.hpp" struct lua_bitmap { diff --git a/include/lua/lua.hpp b/include/lua/lua.hpp index 2a9ae868..5d60baef 100644 --- a/include/lua/lua.hpp +++ b/include/lua/lua.hpp @@ -3,8 +3,8 @@ #include "core/controllerframe.hpp" #include "core/keymapper.hpp" -#include "core/render.hpp" #include "core/movie.hpp" +#include "library/framebuffer.hpp" struct lua_State; diff --git a/src/core/advdumper.cpp b/src/core/advdumper.cpp index 90c7446e..def7eed0 100644 --- a/src/core/advdumper.cpp +++ b/src/core/advdumper.cpp @@ -121,9 +121,9 @@ unsigned adv_dumper::target_type_file = 0; unsigned adv_dumper::target_type_prefix = 1; unsigned adv_dumper::target_type_special = 2; -template void render_video_hud(struct screen& target, struct lcscreen& source, uint32_t hscl, uint32_t vscl, - uint32_t roffset, uint32_t goffset, uint32_t boffset, uint32_t lgap, uint32_t tgap, uint32_t rgap, - uint32_t bgap, void(*fn)()) +template void render_video_hud(struct framebuffer& target, struct framebuffer_raw& source, uint32_t hscl, + uint32_t vscl, uint32_t roffset, uint32_t goffset, uint32_t boffset, uint32_t lgap, uint32_t tgap, + uint32_t rgap, uint32_t bgap, void(*fn)()) { struct lua_render_context lrc; render_queue rq; @@ -132,22 +132,22 @@ template void render_video_hud(struct screen& target, struct lcscreen lrc.bottom_gap = bgap; lrc.top_gap = tgap; lrc.queue = &rq; - lrc.width = source.width; - lrc.height = source.height; + lrc.width = source.get_width(); + lrc.height = source.get_height(); lua_callback_do_video(&lrc); if(fn) fn(); target.set_palette(roffset, goffset, boffset); - target.reallocate(lrc.left_gap + source.width * hscl + lrc.right_gap, lrc.top_gap + - source.height * vscl + lrc.bottom_gap, false); + target.reallocate(lrc.left_gap + source.get_width() * hscl + lrc.right_gap, lrc.top_gap + + source.get_height() * vscl + lrc.bottom_gap, false); target.set_origin(lrc.left_gap, lrc.top_gap); target.copy_from(source, hscl, vscl); rq.run(target); } -template void render_video_hud(struct screen& target, struct lcscreen& source, uint32_t hscl, uint32_t vscl, - uint32_t roffset, uint32_t goffset, uint32_t boffset, uint32_t lgap, uint32_t tgap, uint32_t rgap, - uint32_t bgap, void(*fn)()); -template void render_video_hud(struct screen& target, struct lcscreen& source, uint32_t hscl, uint32_t vscl, - uint32_t roffset, uint32_t goffset, uint32_t boffset, uint32_t lgap, uint32_t tgap, uint32_t rgap, - uint32_t bgap, void(*fn)()); +template void render_video_hud(struct framebuffer& target, struct framebuffer_raw& source, uint32_t hscl, + uint32_t vscl, uint32_t roffset, uint32_t goffset, uint32_t boffset, uint32_t lgap, uint32_t tgap, + uint32_t rgap, uint32_t bgap, void(*fn)()); +template void render_video_hud(struct framebuffer& target, struct framebuffer_raw& source, uint32_t hscl, + uint32_t vscl, uint32_t roffset, uint32_t goffset, uint32_t boffset, uint32_t lgap, uint32_t tgap, + uint32_t rgap, uint32_t bgap, void(*fn)()); diff --git a/src/core/dispatch.cpp b/src/core/dispatch.cpp index 89657801..5f944d21 100644 --- a/src/core/dispatch.cpp +++ b/src/core/dispatch.cpp @@ -262,12 +262,12 @@ void information_dispatch::do_raw_frame(const uint32_t* raw, bool hires, bool in } } -void information_dispatch::on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) +void information_dispatch::on_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d) { //Do nothing. } -void information_dispatch::do_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) throw() +void information_dispatch::do_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d) throw() { update_dumpers(); for(auto& i : dispatch()) { @@ -476,12 +476,12 @@ void information_dispatch::update_dumpers(bool nocalls) throw() } } -void information_dispatch::on_set_screen(screen& scr) +void information_dispatch::on_set_screen(framebuffer& scr) { //Do nothing. } -void information_dispatch::do_set_screen(screen& scr) throw() +void information_dispatch::do_set_screen(framebuffer& scr) throw() { for(auto& i : dispatch()) { START_EH_BLOCK diff --git a/src/core/framebuffer.cpp b/src/core/framebuffer.cpp index 42803bae..acf6d78d 100644 --- a/src/core/framebuffer.cpp +++ b/src/core/framebuffer.cpp @@ -3,17 +3,19 @@ #include "core/framebuffer.hpp" #include "lua/lua.hpp" #include "core/misc.hpp" -#include "core/render.hpp" #include "core/window.hpp" +#include "fonts/wrapper.hpp" +#include "library/framebuffer.hpp" +#include "library/pixfmt-lrgb.hpp" -lcscreen screen_nosignal; -lcscreen screen_corrupt; +framebuffer_raw screen_nosignal; +framebuffer_raw screen_corrupt; namespace { struct render_info { - lcscreen fbuf; + framebuffer_raw fbuf; render_queue rq; uint32_t hscl; uint32_t vscl; @@ -103,13 +105,11 @@ namespace void draw_special_screen(uint32_t* target, struct render_list_entry* rlist) { while(rlist->scale) { - int32_t x; - int32_t y; - auto g = find_glyph(rlist->codepoint, 0, 0, 0, x, y); + auto g = main_font.get_glyph(rlist->codepoint); for(uint32_t j = 0; j < 16; j++) { - for(uint32_t i = 0; i < 8; i++) { - uint32_t slice = g.second[j / 4]; - uint32_t bit = 31 - ((j % 4) * 8 + i); + for(uint32_t i = 0; i < (g.wide ? 16 : 8); i++) { + uint32_t slice = g.data[j / (g.wide ? 2 : 4)]; + uint32_t bit = 31 - ((j % (g.wide ? 2 : 4)) * (g.wide ? 16 : 8) + i); uint32_t value = (slice >> bit) & 1; if(value) { uint32_t basex = rlist->x + rlist->scale * i; @@ -148,7 +148,7 @@ namespace bool last_redraw_no_lua = true; } -screen main_screen; +framebuffer main_screen; void take_screenshot(const std::string& file) throw(std::bad_alloc, std::runtime_error) { @@ -162,16 +162,29 @@ void init_special_screens() throw(std::bad_alloc) { std::vector buf; buf.resize(512*448); + + framebuffer_info inf; + inf.type = &_pixel_format_lrgb; + inf.mem = reinterpret_cast(&buf[0]); + inf.physwidth = 512; + inf.physheight = 448; + inf.physstride = 2048; + inf.width = 512; + inf.height = 448; + inf.stride = 2048; + inf.offset_x = 0; + inf.offset_y = 0; + draw_nosignal(&buf[0]); - screen_nosignal = lcscreen(&buf[0], 512, 448); + screen_nosignal = framebuffer_raw(inf); draw_corrupt(&buf[0]); - screen_corrupt = lcscreen(&buf[0], 512, 448); + screen_corrupt = framebuffer_raw(inf); } -void redraw_framebuffer(lcscreen& todraw, bool no_lua, bool spontaneous) +void redraw_framebuffer(framebuffer_raw& todraw, bool no_lua, bool spontaneous) { uint32_t hscl, vscl; - auto g = get_scale_factors(todraw.width, todraw.height); + auto g = get_scale_factors(todraw.get_width(), todraw.get_height()); hscl = g.first; vscl = g.second; render_info& ri = get_write_buffer(); @@ -182,8 +195,8 @@ void redraw_framebuffer(lcscreen& todraw, bool no_lua, bool spontaneous) lrc.bottom_gap = 0; lrc.top_gap = 0; lrc.queue = &ri.rq; - lrc.width = todraw.width * hscl; - lrc.height = todraw.height * vscl; + lrc.width = todraw.get_width() * hscl; + lrc.height = todraw.get_height() * vscl; if(!no_lua) lua_callback_do_paint(&lrc, spontaneous); ri.fbuf = todraw; @@ -201,7 +214,7 @@ void redraw_framebuffer(lcscreen& todraw, bool no_lua, bool spontaneous) void redraw_framebuffer() { render_info& ri = get_read_buffer(); - lcscreen copy = ri.fbuf; + framebuffer_raw copy = ri.fbuf; buffering.end_read(); //Redraws are never spontaneous redraw_framebuffer(copy, last_redraw_no_lua, false); @@ -213,8 +226,8 @@ void render_framebuffer() static uint32_t val1, val2, val3, val4; uint32_t nval1, nval2, nval3, nval4; render_info& ri = get_read_buffer(); - main_screen.reallocate(ri.fbuf.width * ri.hscl + ri.lgap + ri.rgap, ri.fbuf.height * ri.vscl + ri.tgap + - ri.bgap); + main_screen.reallocate(ri.fbuf.get_width() * ri.hscl + ri.lgap + ri.rgap, ri.fbuf.get_height() * ri.vscl + + ri.tgap + ri.bgap); main_screen.set_origin(ri.lgap, ri.tgap); main_screen.copy_from(ri.fbuf, ri.hscl, ri.vscl); ri.rq.run(main_screen); @@ -224,14 +237,14 @@ void render_framebuffer() keygroup* mouse_y = keygroup::lookup_by_name("mouse_y"); nval1 = ri.lgap; nval2 = ri.tgap; - nval3 = ri.fbuf.width * ri.hscl + ri.rgap; - nval4 = ri.fbuf.height * ri.vscl + ri.bgap; + nval3 = ri.fbuf.get_width() * ri.hscl + ri.rgap; + nval4 = ri.fbuf.get_height() * ri.vscl + ri.bgap; if(mouse_x && (nval1 != val1 || nval3 != val3)) - mouse_x->change_calibration(-static_cast(ri.lgap), ri.lgap, ri.fbuf.width * ri.hscl + ri.rgap, - 0.5); + mouse_x->change_calibration(-static_cast(ri.lgap), ri.lgap, ri.fbuf.get_width() * ri.hscl + + ri.rgap, 0.5); if(mouse_y && (nval2 != val2 || nval4 != val4)) - mouse_y->change_calibration(-static_cast(ri.tgap), ri.tgap, ri.fbuf.height * ri.vscl + ri.bgap, - 0.5); + mouse_y->change_calibration(-static_cast(ri.tgap), ri.tgap, ri.fbuf.get_height() * ri.vscl + + ri.bgap, 0.5); val1 = nval1; val2 = nval2; val3 = nval3; @@ -243,16 +256,16 @@ std::pair get_framebuffer_size() { uint32_t v, h; render_info& ri = get_read_buffer(); - v = ri.fbuf.width; - h = ri.fbuf.height; + v = ri.fbuf.get_width(); + h = ri.fbuf.get_height(); buffering.end_read(); return std::make_pair(h, v); } -lcscreen get_framebuffer() throw(std::bad_alloc) +framebuffer_raw get_framebuffer() throw(std::bad_alloc) { render_info& ri = get_read_buffer(); - lcscreen copy = ri.fbuf; + framebuffer_raw copy = ri.fbuf; buffering.end_read(); return copy; } diff --git a/src/core/mainloop.cpp b/src/core/mainloop.cpp index da7a5ff4..af6c1af9 100644 --- a/src/core/mainloop.cpp +++ b/src/core/mainloop.cpp @@ -13,11 +13,12 @@ #include "core/moviefile.hpp" #include "core/memorymanip.hpp" #include "core/memorywatch.hpp" -#include "core/render.hpp" #include "core/rom.hpp" #include "core/rrdata.hpp" #include "core/settings.hpp" #include "core/window.hpp" +#include "library/framebuffer.hpp" +#include "library/pixfmt-lrgb.hpp" #include #include @@ -356,7 +357,20 @@ class my_interface : public SNES::Interface //std::cerr << "Frame: interlace flag is " << (interlace ? " " : "un") << "set." << std::endl; //std::cerr << "Frame: overscan flag is " << (overscan ? " " : "un") << "set." << std::endl; //std::cerr << "Frame: region flag is " << (region ? " " : "un") << "set." << std::endl; - lcscreen ls(data, hires, interlace, overscan, region); + + framebuffer_info inf; + inf.type = &_pixel_format_lrgb; + inf.mem = const_cast(reinterpret_cast(data)); + inf.physwidth = 512; + inf.physheight = 512; + inf.physstride = 2048; + inf.width = hires ? 512 : 256; + inf.height = (region ? 239 : 224) * (interlace ? 2 : 1); + inf.stride = interlace ? 2048 : 4096; + inf.offset_x = 0; + inf.offset_y = (region ? (overscan ? 9 : 1) : (overscan ? 16 : 9)) * 2; + + framebuffer_raw ls(inf); location_special = SPECIAL_FRAME_VIDEO; update_movie_state(); redraw_framebuffer(ls, false, true); diff --git a/src/core/moviedata.cpp b/src/core/moviedata.cpp index b9b2f3fb..83c501c0 100644 --- a/src/core/moviedata.cpp +++ b/src/core/moviedata.cpp @@ -393,7 +393,7 @@ void do_load_state(struct moviefile& _movie, int lmode) movb.get_movie() = newmovie; //Paint the screen. { - lcscreen tmp; + framebuffer_raw tmp; if(will_load_state) { tmp.load(_movie.screenshot); redraw_framebuffer(tmp); diff --git a/src/core/render.cpp b/src/core/render.cpp deleted file mode 100644 index 9a26d596..00000000 --- a/src/core/render.cpp +++ /dev/null @@ -1,668 +0,0 @@ -#include "lsnes.hpp" -#include - -#include "core/misc.hpp" -#include "core/png.hpp" -#include "core/render.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#define TAG_ZEROWIDTH 0 -#define TAG_NARROW 1 -#define TAG_WIDE 2 -#define TAG_TABULATION 3 -#define TAG_WIDTH_MASK 3 -#define TAG_LINECHANGE 4 - -extern const char* font_hex_data; - -namespace -{ - std::vector font_glyph_data; - std::map font_glyph_offsets; - - uint32_t parse_word(const char* x) - { - char buf[9] = {0}; - char* end; - memcpy(buf, x, 8); - unsigned long v = strtoul(buf, &end, 16); - if(end != buf + 8) - v = 0xFFFFFFFFUL; - //std::cerr << "Parse word " << buf << std::endl; - return v; - } - - void init_font() - { - static bool iflag = false; - if(iflag) - return; - //Special glyph data. - font_glyph_data.resize(7); - //Space & Unknown. - font_glyph_data[0] = TAG_NARROW; - font_glyph_data[1] = 0; - font_glyph_data[2] = 0; - font_glyph_data[3] = 0; - font_glyph_data[4] = 0; - //Tabulation. - font_glyph_data[5] = TAG_TABULATION; - //Linefeed. - font_glyph_data[6] = TAG_ZEROWIDTH | TAG_LINECHANGE; - - size_t lsptr = 0; - uint32_t lc = 1; - for(size_t i = 0;; i++) { - //Skip spaces. - switch(font_hex_data[i]) { - case ' ': - case '\t': - //Skip spaces at start of line. - if(lsptr == i) - lsptr++; - case '\r': - case '\n': - case '\0': { - char* end; - uint32_t cp; - size_t fdatastart; - //Is this a comment? - if(lsptr == i || font_hex_data[lsptr] == '#') - goto skip_line; - cp = strtoul(font_hex_data + lsptr, &end, 16); - if(*end != ':') { - messages << "Malformed line " << lc << " in font data" << std::endl; - goto skip_line; - } - fdatastart = end - font_hex_data + 1; - if(i - fdatastart == 32) { - //Narrow glyph. - font_glyph_offsets[cp] = font_glyph_data.size(); - font_glyph_data.push_back(TAG_NARROW); - for(uint32_t k = 0; k < 4; k++) - font_glyph_data.push_back(parse_word(end + 1 + 8 * k)); - } else if(i - fdatastart == 64) { - //Wide glyph. - font_glyph_offsets[cp] = font_glyph_data.size(); - font_glyph_data.push_back(TAG_WIDE); - for(uint32_t k = 0; k < 8; k++) - font_glyph_data.push_back(parse_word(end + 1 + 8 * k)); - } else { - messages << "Malformed line " << lc << " in font data" << std::endl; - goto skip_line; - } -skip_line: - if(font_hex_data[i] != '\r' || font_hex_data[i + 1] != '\n') - lc++; - lsptr = i + 1; - } - }; - if(!font_hex_data[i]) - break; - } - - //Special characters. - font_glyph_offsets[9] = 5; - font_glyph_offsets[10] = 6; - font_glyph_offsets[32] = 0; - - uint32_t glyphs = 0; - uint32_t glyphs_narrow = 0; - uint32_t glyphs_wide = 0; - uint32_t glyphs_special = 0; - for(auto i : font_glyph_offsets) { - if(font_glyph_data[i.second] == TAG_NARROW) - glyphs_narrow++; - else if(font_glyph_data[i.second] == TAG_WIDE) - glyphs_wide++; - else - glyphs_special++; - glyphs++; - } - messages << "Loaded font data: " << glyphs << " glyphs (" << glyphs_narrow << " narrow, " << - glyphs_wide << " wide, " << glyphs_special << " special)." << std::endl; - iflag = true; - } - - inline uint32_t find_font_glyph_offset(uint32_t cp) - { - return font_glyph_offsets.count(cp) ? font_glyph_offsets[cp] : 0; - } - - inline uint32_t process_tag(uint32_t tag, int32_t& x, int32_t& y, int32_t orig_x, bool hdbl, bool vdbl) - { - uint32_t dwidth; - switch(tag & TAG_WIDTH_MASK) { - case TAG_ZEROWIDTH: - dwidth = 0; - break; - case TAG_NARROW: - dwidth = 8; - break; - case TAG_WIDE: - dwidth = 16; - break; - case TAG_TABULATION: - dwidth = 0x40 - (x & 0x3F); - break; - } - x += dwidth * (hdbl ? 2 : 1); - if(tag & TAG_LINECHANGE) { - y += 16 * (vdbl ? 2 : 1); - x = orig_x; - } - return dwidth; - } - - inline bool is_visible(uint32_t tag) - { - return ((tag & TAG_WIDTH_MASK) == TAG_NARROW || (tag & TAG_WIDTH_MASK) == TAG_WIDE); - } -} - -void premultiplied_color::set_palette(unsigned rshift, unsigned gshift, unsigned bshift, bool X) throw() -{ - if(X) { - uint64_t r = ((orig >> 16) & 0xFF) * 257; - uint64_t g = ((orig >> 8) & 0xFF) * 257; - uint64_t b = (orig & 0xFF) * 257; - uint64_t color = (r << rshift) | (g << gshift) | (b << bshift); - hiHI = color & 0xFFFF0000FFFFULL; - loHI = (color & 0xFFFF0000FFFF0000ULL) >> 16; - hiHI *= (static_cast(origa) * 256); - loHI *= (static_cast(origa) * 256); - } else { - uint32_t r = (orig >> 16) & 0xFF; - uint32_t g = (orig >> 8) & 0xFF; - uint32_t b = orig & 0xFF; - uint32_t color = (r << rshift) | (g << gshift) | (b << bshift); - hi = color & 0xFF00FF; - lo = (color & 0xFF00FF00) >> 8; - hi *= origa; - lo *= origa; - } -} - -void do_init_font() -{ - init_font(); -} - -std::pair find_glyph(uint32_t codepoint, int32_t x, int32_t y, int32_t orig_x, - int32_t& next_x, int32_t& next_y, bool hdbl, bool vdbl) throw() -{ - init_font(); - next_x = x; - next_y = y; - uint32_t offset = find_font_glyph_offset(codepoint); - uint32_t tag = font_glyph_data[offset]; - uint32_t dwidth = process_tag(tag, next_x, next_y, orig_x, hdbl, vdbl); - bool visible = is_visible(tag); - return std::pair(dwidth, visible ? &font_glyph_data[offset + 1] : NULL); -} - -render_object::~render_object() throw() -{ -} - -template void render_text(struct screen& scr, int32_t x, int32_t y, const std::string& text, - premultiplied_color fg, premultiplied_color bg, bool hdbl, bool vdbl) throw(std::bad_alloc) -{ - int32_t orig_x = x; - uint32_t unicode_code = 0; - uint8_t unicode_left = 0; - for(size_t i = 0; i < text.length(); i++) { - uint8_t ch = text[i]; - if(ch < 128) - unicode_code = text[i]; - else if(ch < 192) { - if(!unicode_left) - continue; - unicode_code = 64 * unicode_code + ch - 128; - if(--unicode_left) - continue; - } else if(ch < 224) { - unicode_code = ch - 192; - unicode_left = 1; - continue; - } else if(ch < 240) { - unicode_code = ch - 224; - unicode_left = 2; - continue; - } else if(ch < 248) { - unicode_code = ch - 240; - unicode_left = 3; - continue; - } else - continue; - int32_t next_x, next_y; - auto p = find_glyph(unicode_code, x, y, orig_x, next_x, next_y, hdbl, vdbl); - uint32_t dx = 0; - uint32_t dw = p.first * (hdbl ? 2 : 1); - uint32_t dy = 0; - uint32_t dh = 16 * (vdbl ? 2 : 1); - uint32_t cx = static_cast(static_cast(scr.originx) + x); - uint32_t cy = static_cast(static_cast(scr.originy) + y); - while(cx > scr.width && dw > 0) { - dx++; - dw--; - cx++; - } - while(cy > scr.height && dh > 0) { - dy++; - dh--; - cy++; - } - while(cx + dw > scr.width && dw > 0) - dw--; - while(cy + dh > scr.height && dh > 0) - dh--; - if(!dw || !dh) - continue; //Outside screen. - - uint32_t rshift = (p.first == 16) ? (vdbl ? 2 : 1) : (vdbl ? 3 : 2); - uint32_t rishift = (p.first == 16) ? 4 : 3; - uint32_t xshift = hdbl ? 1 : 0; - uint32_t yshift = vdbl ? 1 : 0; - uint32_t b = dx & 1; - - if(p.second == NULL) { - //Blank glyph. - for(uint32_t j = 0; j < dh; j++) { - typename screen::element_t* base = scr.rowptr(cy + j) + cx; - for(uint32_t i = 0; i < dw; i++) - bg.apply(base[i]); - } - } else { - for(uint32_t j = 0; j < dh; j++) { - uint32_t dataword = p.second[(dy + j) >> rshift]; - typename screen::element_t* base = scr.rowptr(cy + j) + cx; - uint32_t rbit = (~((dy + j) >> yshift << rishift) & 31) - (dx >> xshift); - if(hdbl) { - for(uint32_t i = 0; i < dw; i++) - if((dataword >> (rbit - ((i + b) >> 1))) & 1) - fg.apply(base[i]); - else - bg.apply(base[i]); - } else { - for(uint32_t i = 0; i < dw; i++) - if((dataword >> (rbit - i)) & 1) - fg.apply(base[i]); - else - bg.apply(base[i]); - } - } - } - x = next_x; - y = next_y; - } -} - -void render_queue::add(struct render_object& obj) throw(std::bad_alloc) -{ - struct node* n = reinterpret_cast(alloc(sizeof(node))); - n->obj = &obj; - n->next = NULL; - if(queue_tail) - queue_tail = queue_tail->next = n; - else - queue_head = queue_tail = n; -} - -template void render_queue::run(struct screen& scr) throw() -{ - struct node* tmp = queue_head; - while(tmp) { - try { - (*(tmp->obj))(scr); - tmp = tmp->next; - } catch(...) { - } - } -} - -void render_queue::clear() throw() -{ - while(queue_head) { - queue_head->obj->~render_object(); - queue_head = queue_head->next; - } - //Release all memory for reuse. - memory_allocated = 0; - pages = 0; - queue_tail = NULL; -} - -void* render_queue::alloc(size_t block) throw(std::bad_alloc) -{ - block = (block + 15) / 16 * 16; - if(block > RENDER_PAGE_SIZE) - throw std::bad_alloc(); - if(pages == 0 || memory_allocated + block > pages * RENDER_PAGE_SIZE) { - memory_allocated = pages * RENDER_PAGE_SIZE; - memory[pages++]; - } - void* mem = memory[memory_allocated / RENDER_PAGE_SIZE].content + (memory_allocated % RENDER_PAGE_SIZE); - memory_allocated += block; - return mem; -} - -render_queue::render_queue() throw() -{ - queue_head = NULL; - queue_tail = NULL; - memory_allocated = 0; - pages = 0; -} - -render_queue::~render_queue() throw() -{ - clear(); -} - -lcscreen::lcscreen(const uint32_t* mem, bool hires, bool interlace, bool overscan, bool region) throw() -{ - uint32_t dataoffset = 0; - width = hires ? 512 : 256; - height = 0; - if(region) { - //PAL. - height = 239; - dataoffset = overscan ? 9 : 1; - } else { - //presumably NTSC. - height = 224; - dataoffset = overscan ? 16 : 9; - } - if(interlace) - height <<= 1; - memory = mem + dataoffset * 1024; - pitch = interlace ? 512 : 1024; - user_memory = false; -} - -lcscreen::lcscreen(const uint32_t* mem, uint32_t _width, uint32_t _height) throw() -{ - width = _width; - height = _height; - memory = mem; - pitch = width; - user_memory = false; -} - -lcscreen::lcscreen() throw() -{ - width = 0; - height = 0; - memory = NULL; - user_memory = true; - pitch = 0; - allocated = 0; -} - -lcscreen::lcscreen(const lcscreen& ls) throw(std::bad_alloc) -{ - width = ls.width; - height = ls.height; - pitch = width; - user_memory = true; - allocated = static_cast(width) * height; - memory = new uint32_t[allocated]; - for(size_t l = 0; l < height; l++) - memcpy(const_cast(memory + l * width), ls.memory + l * ls.pitch, 4 * width); -} - -lcscreen& lcscreen::operator=(const lcscreen& ls) throw(std::bad_alloc, std::runtime_error) -{ - if(!user_memory) - throw std::runtime_error("Can't copy to non-user memory"); - if(this == &ls) - return *this; - if(allocated < static_cast(ls.width) * ls.height) { - size_t p_allocated = static_cast(ls.width) * ls.height; - memory = new uint32_t[p_allocated]; - allocated = p_allocated; - } - width = ls.width; - height = ls.height; - pitch = width; - for(size_t l = 0; l < height; l++) - memcpy(const_cast(memory + l * width), ls.memory + l * ls.pitch, 4 * width); - return *this; -} - -lcscreen::~lcscreen() -{ - if(user_memory) - delete[] const_cast(memory); -} - -void lcscreen::load(const std::vector& data) throw(std::bad_alloc, std::runtime_error) -{ - if(!user_memory) - throw std::runtime_error("Can't load to non-user memory"); - const uint8_t* data2 = reinterpret_cast(&data[0]); - if(data.size() < 2) - throw std::runtime_error("Corrupt saved screenshot data"); - uint32_t _width = static_cast(data2[0]) * 256 + static_cast(data2[1]); - if(_width > 1 && data.size() % (3 * _width) != 2) - throw std::runtime_error("Corrupt saved screenshot data"); - uint32_t _height = (data.size() - 2) / (3 * _width); - if(allocated < static_cast(_width) * _height) { - size_t p_allocated = static_cast(_width) * _height; - memory = new uint32_t[p_allocated]; - allocated = p_allocated; - } - uint32_t* mem = const_cast(memory); - width = _width; - height = _height; - pitch = width; - for(size_t i = 0; i < (data.size() - 2) / 3; i++) - mem[i] = static_cast(data2[2 + 3 * i]) * 65536 + - static_cast(data2[2 + 3 * i + 1]) * 256 + - static_cast(data2[2 + 3 * i + 2]); -} - -void lcscreen::save(std::vector& data) throw(std::bad_alloc) -{ - data.resize(2 + 3 * static_cast(width) * height); - uint8_t* data2 = reinterpret_cast(&data[0]); - data2[0] = (width >> 8); - data2[1] = width; - for(size_t i = 0; i < (data.size() - 2) / 3; i++) { - data[2 + 3 * i] = memory[(i / width) * pitch + (i % width)] >> 16; - data[2 + 3 * i + 1] = memory[(i / width) * pitch + (i % width)] >> 8; - data[2 + 3 * i + 2] = memory[(i / width) * pitch + (i % width)]; - } -} - -void lcscreen::save_png(const std::string& file) throw(std::bad_alloc, std::runtime_error) -{ - uint8_t* buffer = new uint8_t[3 * static_cast(width) * height]; - for(uint32_t j = 0; j < height; j++) - for(uint32_t i = 0; i < width; i++) { - uint32_t word = memory[pitch * j + i]; - uint32_t l = 1 + ((word >> 15) & 0xF); - uint32_t r = l * ((word >> 0) & 0x1F); - uint32_t g = l * ((word >> 5) & 0x1F); - uint32_t b = l * ((word >> 10) & 0x1F); - buffer[3 * static_cast(width) * j + 3 * i + 0] = r * 255 / 496; - buffer[3 * static_cast(width) * j + 3 * i + 1] = g * 255 / 496; - buffer[3 * static_cast(width) * j + 3 * i + 2] = b * 255 / 496; - } - try { - save_png_data(file, buffer, width, height); - delete[] buffer; - } catch(...) { - delete[] buffer; - throw; - } -} - -template void screen::copy_from(lcscreen& scr, uint32_t hscale, uint32_t vscale) throw() -{ - if(width < originx || height < originy) { - //Just clear the screen. - for(uint32_t y = 0; y < height; y++) - memset(rowptr(y), 0, sizeof(typename screen::element_t) * width); - return; - } - uint32_t copyable_width = 0, copyable_height = 0; - if(hscale) - copyable_width = (width - originx) / hscale; - if(vscale) - copyable_height = (height - originy) / vscale; - copyable_width = (copyable_width > scr.width) ? scr.width : copyable_width; - copyable_height = (copyable_height > scr.height) ? scr.height : copyable_height; - for(uint32_t y = 0; y < height; y++) - memset(rowptr(y), 0, sizeof(typename screen::element_t) * width); - for(uint32_t y = 0; y < copyable_height; y++) { - uint32_t line = y * vscale + originy; - typename screen::element_t* ptr = rowptr(line) + originx; - const uint32_t* sbase = scr.memory + y * scr.pitch; - for(uint32_t x = 0; x < copyable_width; x++) { - typename screen::element_t c = palette[sbase[x] & 0x7FFFF]; - for(uint32_t i = 0; i < hscale; i++) - *(ptr++) = c; - } - for(uint32_t j = 1; j < vscale; j++) - memcpy(rowptr(line + j) + originx, rowptr(line) + originx, - sizeof(typename screen::element_t) * hscale * copyable_width); - } -} - -template void screen::reallocate(uint32_t _width, uint32_t _height, bool upside_down) throw(std::bad_alloc) -{ - if(_width == width && _height == height) - return; - if(!_width || !_height) { - width = height = originx = originy = pitch = 0; - if(memory && !user_memory) - delete[] memory; - memory = NULL; - user_memory = false; - flipped = upside_down; - return; - } - typename screen::element_t* newmem = new typename screen::element_t[_width * _height]; - width = _width; - height = _height; - pitch = sizeof(typename screen::element_t) * _width; - if(memory && !user_memory) - delete[] memory; - memory = newmem; - user_memory = false; - flipped = upside_down; -} - -template void screen::set(typename screen::element_t* _memory, uint32_t _width, uint32_t _height, - uint32_t _pitch) throw() -{ - if(memory && !user_memory) - delete[] memory; - width = _width; - height = _height; - pitch = _pitch; - user_memory = true; - memory = _memory; - flipped = false; -} - -template void screen::set_origin(uint32_t _originx, uint32_t _originy) throw() -{ - originx = _originx; - originy = _originy; -} - -template typename screen::element_t* screen::rowptr(uint32_t row) throw() -{ - if(flipped) - row = height - row - 1; - return reinterpret_cast::element_t*>(reinterpret_cast(memory) + row * pitch); -} - -template screen::screen() throw() -{ - memory = NULL; - width = height = originx = originy = pitch = 0; - user_memory = false; - flipped = false; - palette = NULL; - set_palette(16, 8, 0); -} - -template screen::~screen() throw() -{ - if(memory && !user_memory) - delete[] memory; - delete[] palette; -} - -void clip_range(uint32_t origin, uint32_t size, int32_t base, int32_t& minc, int32_t& maxc) throw() -{ - int64_t _origin = origin; - int64_t _size = size; - int64_t _base = base; - int64_t _minc = minc; - int64_t _maxc = maxc; - int64_t mincoordinate = _base + _origin + _minc; - int64_t maxcoordinate = _base + _origin + _maxc; - if(mincoordinate < 0) - _minc = _minc - mincoordinate; - if(maxcoordinate > _size) - _maxc = _maxc - (maxcoordinate - _size); - if(_minc >= maxc) { - minc = 0; - maxc = 0; - } else { - minc = _minc; - maxc = _maxc; - } -} - -template void screen::set_palette(uint32_t r, uint32_t g, uint32_t b) -{ - if(!palette) - palette = new element_t[0x80000]; - else if(r == palette_r && g == palette_g && b == palette_b) - return; - for(size_t i = 0; i < static_cast(width) * height; i++) { - uint32_t word = memory[i]; - uint32_t R = (word >> palette_r) & (X ? 0xFFFF : 0xFF); - uint32_t G = (word >> palette_g) & (X ? 0xFFFF : 0xFF); - uint32_t B = (word >> palette_b) & (X ? 0xFFFF : 0xFF); - memory[i] = (R << r) | (G << g) | (B << b); - } - for(unsigned i = 0; i < 0x80000; i++) { - unsigned l = 1 + ((i >> 15) & 0xF); - element_t R = (i >> 0) & 0x1F; - element_t G = (i >> 5) & 0x1F; - element_t B = (i >> 10) & 0x1F; - double _l = static_cast(l); - double m = (X ? 65535.0 : 255.0) / 496.0; - R = floor(m * R * _l + 0.5); - G = floor(m * G * _l + 0.5); - B = floor(m * B * _l + 0.5); - palette[i] = (R << r) | (G << g) | (B << b); - } - palette_r = r; - palette_g = g; - palette_b = b; -} - - -template struct screen; -template struct screen; -template void render_queue::run(screen&); -template void render_queue::run(screen&); -template void render_text(struct screen& scr, int32_t x, int32_t y, const std::string& text, - premultiplied_color fg, premultiplied_color bg, bool hdbl, bool vdbl) throw(std::bad_alloc); -template void render_text(struct screen& scr, int32_t x, int32_t y, const std::string& text, - premultiplied_color fg, premultiplied_color bg, bool hdbl, bool vdbl) throw(std::bad_alloc); diff --git a/src/core/window.cpp b/src/core/window.cpp index 1dd6e615..acfd6db2 100644 --- a/src/core/window.cpp +++ b/src/core/window.cpp @@ -3,8 +3,9 @@ #include "core/framerate.hpp" #include "lua/lua.hpp" #include "core/misc.hpp" -#include "core/render.hpp" #include "core/window.hpp" +#include "fonts/wrapper.hpp" +#include "library/framebuffer.hpp" #include "library/string.hpp" #include "library/minmax.hpp" @@ -617,19 +618,19 @@ void platform::run_queues() throw() namespace { mutex* _msgbuf_lock; - screen* our_screen; + framebuffer* our_screen; struct painter_listener : public information_dispatch { painter_listener(); - void on_set_screen(screen& scr); + void on_set_screen(framebuffer& scr); void on_screen_update(); void on_status_update(); } x; painter_listener::painter_listener() : information_dispatch("painter-listener") {} - void painter_listener::on_set_screen(screen& scr) + void painter_listener::on_set_screen(framebuffer& scr) { our_screen = &scr; } @@ -660,9 +661,9 @@ void platform::screen_set_palette(unsigned rshift, unsigned gshift, unsigned bsh { if(!our_screen) return; - if(our_screen->palette_r == rshift && - our_screen->palette_g == gshift && - our_screen->palette_b == bshift) + if(our_screen->get_palette_r() == rshift && + our_screen->get_palette_g() == gshift && + our_screen->get_palette_b() == bshift) return; our_screen->set_palette(rshift, gshift, bshift); graphics_plugin::notify_screen(); diff --git a/src/fonts/Makefile b/src/fonts/Makefile index 49ba1f95..a86ced67 100644 --- a/src/fonts/Makefile +++ b/src/fonts/Makefile @@ -1,4 +1,4 @@ -OBJECTS=font.$(OBJECT_SUFFIX) +OBJECTS=font.$(OBJECT_SUFFIX) wrapper.$(OBJECT_SUFFIX) .PRECIOUS: %.$(OBJECT_SUFFIX) @@ -8,8 +8,8 @@ __all__.$(OBJECT_SUFFIX): $(OBJECTS) .PRECIOUS: font.$(OBJECT_SUFFIX) font.cpp -font.$(OBJECT_SUFFIX): font.cpp - $(REALCC) $(CORE_CFLAGS) -c -o $@ font.cpp +%.$(OBJECT_SUFFIX): %.cpp + $(REALCC) $(CFLAGS) -c -o $@ $< -I../../include font.cpp : $(FONT_SRC) echo "extern const char* font_hex_data = " >font.cpp diff --git a/src/fonts/wrapper.cpp b/src/fonts/wrapper.cpp new file mode 100644 index 00000000..20890d64 --- /dev/null +++ b/src/fonts/wrapper.cpp @@ -0,0 +1,15 @@ +#include "library/framebuffer.hpp" + +#include + +extern const char* font_hex_data; +bitmap_font main_font; + +void do_init_font() +{ + static bool flag = false; + if(flag) + return; + main_font.load_hex(font_hex_data, strlen(font_hex_data)); + flag = true; +} diff --git a/src/library/framebuffer.cpp b/src/library/framebuffer.cpp new file mode 100644 index 00000000..03eab899 --- /dev/null +++ b/src/library/framebuffer.cpp @@ -0,0 +1,844 @@ +#include "library/framebuffer.hpp" +#include "library/png.hpp" +#include "library/serialization.hpp" +#include "library/string.hpp" +#include "library/utf8.hpp" +#include +#include +#include + +#define TABSTOPS 64 +#define SCREENSHOT_RGB_MAGIC 0x74212536U + +namespace +{ + std::list& pixel_formats() + { + static std::list x; + return x; + } + + template void decode_words(uint8_t* target, const uint8_t* src, size_t srcsize) + { + if(c == 1 || c == 2 || c == 3 || c == 4) + srcsize /= c; + else + srcsize /= 3; + if(c == 1) { + for(size_t i = 0; i < srcsize; i++) + target[i] = src[i]; + } else if(c == 2) { + uint16_t* _target = reinterpret_cast(target); + for(size_t i = 0; i < srcsize; i++) { + _target[i] = static_cast(src[2 * i + 0]) << 8; + _target[i] |= static_cast(src[2 * i + 1]); + } + } else if(c == 3) { + for(size_t i = 0; i < srcsize; i++) { + target[3 * i + 0] = src[3 * i + 0]; + target[3 * i + 1] = src[3 * i + 1]; + target[3 * i + 2] = src[3 * i + 2]; + } + } else if(c == 4) { + uint32_t* _target = reinterpret_cast(target); + for(size_t i = 0; i < srcsize; i++) { + _target[i] = static_cast(src[4 * i + 0]) << 24; + _target[i] |= static_cast(src[4 * i + 1]) << 16; + _target[i] |= static_cast(src[4 * i + 2]) << 8; + _target[i] |= static_cast(src[4 * i + 3]); + } + } else if(c == 5) { + uint32_t* _target = reinterpret_cast(target); + for(size_t i = 0; i < srcsize; i++) { + _target[i] = (static_cast(src[3 * i + 0]) << 16); + _target[i] |= (static_cast(src[3 * i + 1]) << 8); + _target[i] |= (static_cast(src[3 * i + 2])); + } + } + } + + template void encode_words(uint8_t* target, const uint8_t* src, size_t elts) + { + if(c == 1) + for(size_t i = 0; i < elts; i++) + target[i] = src[i]; + else if(c == 2) { + const uint16_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < elts; i++) { + target[2 * i + 0] = _src[i] >> 8; + target[2 * i + 1] = _src[i]; + } + } else if(c == 3) { + for(size_t i = 0; i < elts; i++) { + target[3 * i + 0] = src[3 * i + 0]; + target[3 * i + 1] = src[3 * i + 1]; + target[3 * i + 2] = src[3 * i + 2]; + } + } else if(c == 4) { + const uint32_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < elts; i++) { + target[4 * i + 0] = _src[i] >> 24; + target[4 * i + 1] = _src[i] >> 16; + target[4 * i + 2] = _src[i] >> 8; + target[4 * i + 3] = _src[i]; + } + } else if(c == 5) { + const uint32_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < elts; i++) { + target[3 * i + 0] = _src[i] >> 16; + target[3 * i + 1] = _src[i] >> 8; + target[3 * i + 2] = _src[i]; + } + } + } +} + +pixel_format::pixel_format() throw(std::bad_alloc) +{ + pixel_formats().push_back(this); +} + +pixel_format::~pixel_format() throw() +{ + for(auto i = pixel_formats().begin(); i != pixel_formats().end(); i++) + if(*i == this) { + pixel_formats().erase(i); + break; + } +} + +framebuffer_raw::framebuffer_raw(const framebuffer_info& info) throw(std::bad_alloc) +{ + size_t unit = info.type->get_bpp(); + size_t pixel_offset = info.offset_y * info.physstride + unit * info.offset_x; + user_memory = false; + addr = info.mem + pixel_offset; + fmt = info.type; + width = info.width; + height = info.height; + stride = info.stride; + allocated = 0; +} + +framebuffer_raw::framebuffer_raw() throw(std::bad_alloc) +{ + user_memory = true; + fmt = NULL; + addr = NULL; + width = 0; + height = 0; + stride = 0; + allocated = 0; +} + +framebuffer_raw::framebuffer_raw(const framebuffer_raw& f) throw(std::bad_alloc) +{ + user_memory = true; + fmt = f.fmt; + width = f.width; + height = f.height; + size_t unit = f.fmt->get_bpp(); + stride = f.width * unit; + allocated = unit * width * height; + addr = new char[allocated]; + for(size_t i = 0; i < height; i++) + memcpy(addr + stride * i, f.addr + f.stride * i, unit * width); +} + +framebuffer_raw& framebuffer_raw::operator=(const framebuffer_raw& f) throw(std::bad_alloc, std::runtime_error) +{ + if(!user_memory) + throw std::runtime_error("Target framebuffer is not writable"); + if(this == &f) + return *this; + size_t unit = f.fmt->get_bpp(); + size_t newallocated = unit * f.width * f.height; + if(newallocated > allocated) { + char* newaddr = new char[newallocated]; + delete[] addr; + addr = newaddr; + allocated = newallocated; + } + fmt = f.fmt; + width = f.width; + height = f.height; + stride = f.width * unit; + for(size_t i = 0; i < height; i++) + memcpy(addr + stride * i, f.addr + f.stride * i, unit * width); + return *this; +} + +framebuffer_raw::~framebuffer_raw() +{ + if(user_memory) + delete[] addr; +} + +void framebuffer_raw::load(const std::vector& data) throw(std::bad_alloc, std::runtime_error) +{ + if(data.size() < 2) + throw std::runtime_error("Bad screenshot data"); + if(!user_memory) + throw std::runtime_error("Target framebuffer is not writable"); + pixel_format* nfmt = NULL; + const uint8_t* data2 = reinterpret_cast(&data[0]); + size_t legacy_width = read16ube(data2); + size_t dataoffset; + size_t _width; + size_t _height; + + if(legacy_width > 0 && data.size() % (3 * legacy_width) == 2) { + //Legacy screenshot. + for(pixel_format* f : pixel_formats()) + if(f->get_magic() == 0) + nfmt = f; + if(!nfmt) + throw std::runtime_error("Unknown screenshot format"); + _width = legacy_width; + _height = (data.size() - 2) / (3 * legacy_width); + dataoffset = 2; + } else { + //New format. + if(data.size() < 8) + throw std::runtime_error("Bad screenshot data"); + dataoffset = 8; + uint32_t magic = read32ube(data2 + 2); + for(pixel_format* f : pixel_formats()) + if(f->get_magic() == magic) + nfmt = f; + if(!nfmt) + throw std::runtime_error("Unknown screenshot format"); + _width = read16ube(data2 + 6); + _height = (data.size() - 8) / (nfmt->get_ss_bpp() * _width); + } + if(data.size() < dataoffset + nfmt->get_ss_bpp() * _width * _height) + throw std::runtime_error("Bad screenshot data"); + + size_t bpp = nfmt->get_bpp(); + size_t sbpp = nfmt->get_ss_bpp(); + if(allocated < bpp * _width * _height) { + //Allocate more memory. + size_t newalloc = bpp * _width * _height; + char* addr2 = new char[newalloc]; + delete[] addr; + addr = addr2; + allocated = newalloc; + } + fmt = nfmt; + width = _width; + height = _height; + stride = _width * bpp; + if(bpp == 1) + decode_words<1>(reinterpret_cast(addr), data2 + dataoffset, data.size() - dataoffset); + else if(bpp == 2) + decode_words<2>(reinterpret_cast(addr), data2 + dataoffset, data.size() - dataoffset); + else if(bpp == 3) + decode_words<3>(reinterpret_cast(addr), data2 + dataoffset, data.size() - dataoffset); + else if(bpp == 4 && sbpp == 3) + decode_words<5>(reinterpret_cast(addr), data2 + dataoffset, data.size() - dataoffset); + else if(bpp == 4 && sbpp == 4) + decode_words<4>(reinterpret_cast(addr), data2 + dataoffset, data.size() - dataoffset); +} + +void framebuffer_raw::save(std::vector& data) throw(std::bad_alloc) +{ + uint8_t* memory = reinterpret_cast(addr); + unsigned m; + size_t bpp = fmt->get_bpp(); + size_t sbpp = fmt->get_ss_bpp(); + size_t offset; + uint8_t* data2; + uint32_t magic = fmt->get_magic(); + switch(magic) { + case 0: + //Save in legacy format. + offset = 2; + data.resize(offset + sbpp * static_cast(width) * height); + data2 = reinterpret_cast(&data[0]); + write16ube(&data[0], width); + break; + default: + //Choose the first two bytes so that screenshot is bad in legacy format. + m = 2; + while(width * height % m == 0) + m++; + offset = 8; + data.resize(offset + sbpp * static_cast(width) * height); + write16ube(&data[0], m); + write32ube(&data[2], magic); + write16ube(&data[6], width); + break; + } + data2 = reinterpret_cast(&data[0]); + for(size_t i = 0; i < height; i++) { + if(bpp == 1) + encode_words<1>(data2 + offset + sbpp * width * i, memory + stride * i, width); + else if(bpp == 2) + encode_words<2>(data2 + offset + sbpp * width * i, memory + stride * i, width); + else if(bpp == 3) + encode_words<3>(data2 + offset + sbpp * width * i, memory + stride * i, width); + else if(bpp == 4 && sbpp == 3) + encode_words<5>(data2 + offset + sbpp * width * i, memory + stride * i, width); + else if(bpp == 4 && sbpp == 4) + encode_words<4>(data2 + offset + sbpp * width * i, memory + stride * i, width); + } +} + +void framebuffer_raw::save_png(const std::string& file) throw(std::bad_alloc, std::runtime_error) +{ + uint8_t* memory = reinterpret_cast(addr); + uint8_t* buffer = new uint8_t[3 * static_cast(width) * height]; + for(size_t i = 0; i < height; i++) + fmt->decode(buffer + 3 * width * i, memory + stride * i, width); + try { + save_png_data(file, buffer, width, height); + delete[] buffer; + } catch(...) { + delete[] buffer; + throw; + } +} + +template +framebuffer::framebuffer() throw() +{ + width = 0; + height = 0; + stride = 0; + offset_x = 0; + offset_y = 0; + mem = NULL; + user_mem = false; + upside_down = false; + current_fmt = NULL; + active_rshift = (X ? 32 : 16); + active_gshift = (X ? 16 : 8); + active_bshift = 0; +} + + +template +framebuffer::~framebuffer() throw() +{ + if(user_mem) + delete[] mem; +} + +#define DECBUF_SIZE 1024 + +template +void framebuffer::copy_from(framebuffer_raw& scr, size_t hscale, size_t vscale) throw() +{ + typename framebuffer::element_t decbuf[DECBUF_SIZE]; + + if(!scr.fmt) + throw std::runtime_error("Source screen has invalid pixel format"); + if(scr.fmt != current_fmt || active_rshift != auxpal.rshift || active_gshift != auxpal.gshift || + active_bshift != auxpal.bshift) { + scr.fmt->set_palette(auxpal, active_rshift, active_gshift, active_bshift); + current_fmt = scr.fmt; + } + + for(size_t y = 0; y < height; y++) + memset(rowptr(y), 0, sizeof(typename framebuffer::element_t) * width); + if(width < offset_x || height < offset_y) { + //Just clear the screen. + return; + } + size_t copyable_width = 0, copyable_height = 0; + if(hscale) + copyable_width = (width - offset_x) / hscale; + if(vscale) + copyable_height = (height - offset_y) / vscale; + copyable_width = (copyable_width > scr.width) ? scr.width : copyable_width; + copyable_height = (copyable_height > scr.height) ? scr.height : copyable_height; + + for(size_t y = 0; y < copyable_height; y++) { + size_t line = y * vscale + offset_y; + const uint8_t* sbase = reinterpret_cast(scr.addr) + y * scr.stride; + typename framebuffer::element_t* ptr = rowptr(line) + offset_x; + size_t bpp = scr.fmt->get_bpp(); + size_t xptr = 0; + while(copyable_width > DECBUF_SIZE) { + scr.fmt->decode(decbuf, sbase + xptr * bpp, DECBUF_SIZE, auxpal); + for(size_t k = 0; k < DECBUF_SIZE; k++) + for(size_t i = 0; i < hscale; i++) + *(ptr++) = decbuf[k]; + xptr += DECBUF_SIZE; + copyable_width -= DECBUF_SIZE; + } + scr.fmt->decode(decbuf, sbase + xptr * bpp, copyable_width, auxpal); + for(size_t k = 0; k < copyable_width; k++) + for(size_t i = 0; i < hscale; i++) + *(ptr++) = decbuf[k]; + for(size_t j = 1; j < vscale; j++) + memcpy(rowptr(line + j) + offset_x, rowptr(line) + offset_x, + sizeof(typename framebuffer::element_t) * hscale * copyable_width); + }; +} + +template +void framebuffer::set_palette(uint32_t r, uint32_t g, uint32_t b) throw(std::bad_alloc) +{ + typename framebuffer::element_t R, G, B; + if(r == active_rshift && g == active_gshift && b == active_bshift) + return; + for(size_t i = 0; i < static_cast(width) * height; i++) { + typename framebuffer::element_t word = mem[i]; + R = (word >> active_rshift) & (X ? 0xFFFF : 0xFF); + G = (word >> active_gshift) & (X ? 0xFFFF : 0xFF); + B = (word >> active_bshift) & (X ? 0xFFFF : 0xFF); + mem[i] = (R << r) | (G << g) | (B << b); + } + active_rshift = r; + active_gshift = g; + active_bshift = b; +} + +template +void framebuffer::set(element_t* _memory, size_t _width, size_t _height, size_t _pitch) throw() +{ + if(user_mem && mem) + delete[] mem; + mem = _memory; + width = _width; + height = _height; + stride = _pitch; + user_mem = false; + upside_down = false; +} + +template +void framebuffer::reallocate(size_t _width, size_t _height, bool _upside_down) throw(std::bad_alloc) +{ + if(width != _width || height != _height) { + if(user_mem) { + element_t* newmem = new element_t[_width * _height]; + delete[] mem; + mem = newmem; + } else + mem = new element_t[_width * _height]; + } + memset(mem, 0, sizeof(element_t) * _width * _height); + width = _width; + height = _height; + stride = _width; + upside_down = _upside_down; + user_mem = true; +} + +template +void framebuffer::set_origin(size_t _offset_x, size_t _offset_y) throw() +{ + offset_x = _offset_x; + offset_y = _offset_y; +} + +template +size_t framebuffer::get_width() const throw() +{ + return width; +} + +template +size_t framebuffer::get_height() const throw() +{ + return height; +} + +template +typename framebuffer::element_t* framebuffer::rowptr(size_t row) throw() +{ + if(upside_down) + row = height - row - 1; + return mem + stride * row; +} + +template +const typename framebuffer::element_t* framebuffer::rowptr(size_t row) const throw() +{ + if(upside_down) + row = height - row - 1; + return mem + stride * row; +} + +template uint8_t framebuffer::get_palette_r() const throw() { return auxpal.rshift; } +template uint8_t framebuffer::get_palette_g() const throw() { return auxpal.gshift; } +template uint8_t framebuffer::get_palette_b() const throw() { return auxpal.bshift; } + +size_t framebuffer_raw::get_width() const throw() { return width; } +size_t framebuffer_raw::get_height() const throw() { return height; } +template size_t framebuffer::get_origin_x() const throw() { return offset_x; } +template size_t framebuffer::get_origin_y() const throw() { return offset_y; } + +void clip_range(uint32_t origin, uint32_t size, int32_t base, int32_t& minc, int32_t& maxc) throw() +{ + int64_t _origin = origin; + int64_t _size = size; + int64_t _base = base; + int64_t _minc = minc; + int64_t _maxc = maxc; + int64_t mincoordinate = _base + _origin + _minc; + int64_t maxcoordinate = _base + _origin + _maxc; + if(mincoordinate < 0) + _minc = _minc - mincoordinate; + if(maxcoordinate > _size) + _maxc = _maxc - (maxcoordinate - _size); + if(_minc >= maxc) { + minc = 0; + maxc = 0; + } else { + minc = _minc; + maxc = _maxc; + } +} + +void render_queue::add(struct render_object& obj) throw(std::bad_alloc) +{ + struct node* n = reinterpret_cast(alloc(sizeof(node))); + n->obj = &obj; + n->next = NULL; + if(queue_tail) + queue_tail = queue_tail->next = n; + else + queue_head = queue_tail = n; +} + +template void render_queue::run(struct framebuffer& scr) throw() +{ + struct node* tmp = queue_head; + while(tmp) { + try { + (*(tmp->obj))(scr); + tmp = tmp->next; + } catch(...) { + } + } +} + +void render_queue::clear() throw() +{ + while(queue_head) { + queue_head->obj->~render_object(); + queue_head = queue_head->next; + } + //Release all memory for reuse. + memory_allocated = 0; + pages = 0; + queue_tail = NULL; +} + +void* render_queue::alloc(size_t block) throw(std::bad_alloc) +{ + block = (block + 15) / 16 * 16; + if(block > RENDER_PAGE_SIZE) + throw std::bad_alloc(); + if(pages == 0 || memory_allocated + block > pages * RENDER_PAGE_SIZE) { + memory_allocated = pages * RENDER_PAGE_SIZE; + memory[pages++]; + } + void* mem = memory[memory_allocated / RENDER_PAGE_SIZE].content + (memory_allocated % RENDER_PAGE_SIZE); + memory_allocated += block; + return mem; +} + +render_queue::render_queue() throw() +{ + queue_head = NULL; + queue_tail = NULL; + memory_allocated = 0; + pages = 0; +} + +render_queue::~render_queue() throw() +{ + clear(); +} + +render_object::~render_object() throw() +{ +} + +bitmap_font::bitmap_font() throw(std::bad_alloc) +{ + bad_glyph_data[0] = 0x018001AAU; + bad_glyph_data[1] = 0x01800180U; + bad_glyph_data[2] = 0x01800180U; + bad_glyph_data[3] = 0x55800180U; + bad_glyph.wide = false; + bad_glyph.data = bad_glyph_data; +} + +void bitmap_font::load_hex_glyph(const char* data, size_t size) throw(std::bad_alloc, std::runtime_error) +{ + char buf2[8]; + std::string line(data, data + size); + regex_results r; + if(r = regex("([0-9A-Fa-f]+):([0-9A-Fa-f]{32})", line)) { + } else if(r = regex("([0-9A-Fa-f]+):([0-9A-Fa-f]{64})", line)) { + } else + (stringfmt() << "Invalid line '" << line << "'").throwex(); + std::string codepoint = r[1]; + std::string cdata = r[2]; + if(codepoint.length() > 7) + (stringfmt() << "Invalid line '" << line << "'").throwex(); + strcpy(buf2, codepoint.c_str()); + char* end2; + unsigned long cp = strtoul(buf2, &end2, 16); + if(*end2 || cp > 0x10FFFF) + (stringfmt() << "Invalid line '" << line << "'").throwex(); + glyphs[cp].wide = (cdata.length() == 64); + size_t p = memory.size(); + for(size_t i = 0; i < cdata.length(); i += 8) { + char buf[9] = {0}; + char* end; + for(size_t j = 0; j < 8; j++) + buf[j] = cdata[i + j]; + memory.push_back(strtoul(buf, &end, 16)); + } + glyphs[cp].offset = p; +} + +void bitmap_font::load_hex(const char* data, size_t size) throw(std::bad_alloc, std::runtime_error) +{ + const char* enddata = data + size; + uint32_t lineno = 0; + while(data != enddata) { + size_t linesize = 0; + while(data + linesize != enddata && data[linesize] != '\n' && data[linesize] != '\r') + linesize++; + if(linesize && data[0] != '#') + load_hex_glyph(data, linesize); + data += linesize; + if(data != enddata) + data++; + } + memory.push_back(0); + memory.push_back(0); + memory.push_back(0); + memory.push_back(0); + glyphs[32].wide = false; + glyphs[32].offset = memory.size() - 4; + for(auto& i : glyphs) + i.second.data = &memory[i.second.offset]; + + glyph gt = glyphs['N']; + std::cerr << "N is located at " << gt.data << std::endl; + for(size_t i = 0; i < 4; i++) { + for(size_t j = 0; j < 32; j++) { + std::cerr << (((gt.data[i] >> j) & 1) ? '*' : ' '); + if((j & 7) == 7) + std::cerr << std::endl; + } + } +} + +const bitmap_font::glyph& bitmap_font::get_glyph(uint32_t glyph) throw() +{ + if(glyphs.count(glyph)) + return glyphs[glyph]; + else + return bad_glyph; +} + +std::pair bitmap_font::get_metrics(const std::string& string) throw() +{ + size_t commit_width = 0; + size_t commit_height = 0; + int32_t lineminy = 0; + int32_t linemaxy = 0; + size_t linelength = 0; + uint16_t utfstate = utf8_initial_state; + size_t itr = 0; + size_t maxitr = string.length(); + while(true) { + int ch = (itr < maxitr) ? static_cast(string[itr++]) : -1; + int32_t cp = utf8_parse_byte(ch, utfstate); + if(cp < 0 && ch < 0) { + //The end. + commit_width = (commit_width < linelength) ? linelength : commit_width; + commit_height += (linemaxy - lineminy + 1); + break; + } + if(cp < 0) + continue; + const glyph& g = get_glyph(cp); + switch(cp) { + case 9: + linelength = (linelength + TABSTOPS) / TABSTOPS * TABSTOPS; + break; + case 10: + commit_width = (commit_width < linelength) ? linelength : commit_width; + commit_height += 16; + break; + default: + linelength = linelength + (g.wide ? 16 : 8); + break; + }; + } + return std::make_pair(commit_width, commit_height); +} + +std::vector bitmap_font::dolayout(const std::string& string) throw(std::bad_alloc) +{ + //First, calculate the number of glyphs to draw. + uint16_t utfstate = utf8_initial_state; + size_t itr = 0; + size_t maxitr = string.length(); + size_t chars = 0; + while(true) { + int ch = (itr < maxitr) ? static_cast(string[itr++]) : -1; + int32_t cp = utf8_parse_byte(ch, utfstate); + if(cp < 0 && ch < 0) + break; + if(cp != 9 && cp != 10) + chars++; + } + //Allocate space. + std::vector l; + l.resize(chars); + itr = 0; + size_t gtr = 0; + size_t layout_x = 0; + size_t layout_y = 0; + utfstate = utf8_initial_state; + while(true) { + int ch = (itr < maxitr) ? static_cast(string[itr++]) : -1; + int32_t cp = utf8_parse_byte(ch, utfstate); + if(cp < 0 && ch < 0) + break; + const glyph& g = get_glyph(cp); + switch(cp) { + case 9: + layout_x = (layout_x + TABSTOPS) / TABSTOPS * TABSTOPS; + break; + case 10: + layout_x = 0; + layout_y = layout_y + 16; + break; + default: + l[gtr].x = layout_x; + l[gtr].y = layout_y; + l[gtr++].dglyph = &g; + layout_x = layout_x + (g.wide ? 16 : 8);; + } + } + return l; +} + +template void bitmap_font::render(struct framebuffer& scr, int32_t x, int32_t y, const std::string& text, + premultiplied_color fg, premultiplied_color bg, bool hdbl, bool vdbl) throw() +{ + x += scr.get_origin_x(); + y += scr.get_origin_y(); + uint16_t utfstate = utf8_initial_state; + size_t itr = 0; + size_t maxitr = text.length(); + size_t layout_x = 0; + size_t layout_y = 0; + size_t swidth = scr.get_width(); + size_t sheight = scr.get_width(); + while(true) { + int ch = (itr < maxitr) ? static_cast(text[itr++]) : -1; + int32_t cp = utf8_parse_byte(ch, utfstate); + if(cp < 0 && ch < 0) + break; + const glyph& g = get_glyph(cp); + switch(cp) { + case 9: + layout_x = (layout_x + TABSTOPS) / TABSTOPS * TABSTOPS; + break; + case 10: + layout_x = 0; + layout_y = layout_y + (vdbl ? 32 : 16); + break; + default: + //Render this glyph at x + layout_x, y + layout_y. + int32_t gx = x + layout_x; + int32_t gy = y + layout_y; + //Don't draw characters completely off-screen. + if(gy <= (vdbl ? -32 : -16) || gy >= sheight) + break; + if(gx <= -(hdbl ? 2 : 1) * (g.wide ? 16 : 8) || gx >= swidth) + break; + //Compute the bounding box. + uint32_t xstart = 0; + uint32_t ystart = 0; + uint32_t xlength = (hdbl ? 2 : 1) * (g.wide ? 16 : 8); + uint32_t ylength = (vdbl ? 32 : 16); + if(gx < 0) xstart = -gx; + if(gy < 0) ystart = -gy; + xlength -= xstart; + ylength -= ystart; + if(gx + xlength > swidth) xlength = swidth - gx; + if(gy + ylength > sheight) ylength = sheight - gy; + if(g.data) + for(size_t i = 0; i < ylength; i++) { + typename framebuffer::element_t* r = scr.rowptr(gy + ystart + i) + + (gx + xstart); + uint32_t _y = (i + ystart) >> (vdbl ? 1 : 0); + uint32_t d = g.data[_y >> (g.wide ? 1 : 2)]; + if(g.wide) + d >>= 16 - ((_y & 1) << 4); + else + d >>= 24 - ((_y & 3) << 3); + if(hdbl) + for(size_t j = 0; j < xlength; j++) { + uint32_t b = (g.wide ? 15 : 7) - ((j + xstart) >> 1); + if(((d >> b) & 1) != 0) + fg.apply(r[j]); + else + bg.apply(r[j]); + } + else + for(size_t j = 0; j < xlength; j++) { + uint32_t b = (g.wide ? 15 : 7) - (j + xstart); + if(((d >> b) & 1) != 0) + fg.apply(r[j]); + else + bg.apply(r[j]); + } + } + else + for(size_t i = 0; i < ylength; i++) { + typename framebuffer::element_t* r = scr.rowptr(gy + ystart + i) + + (gx + xstart); + for(size_t j = 0; j < xlength; j++) + bg.apply(r[j]); + } + layout_x += (hdbl ? 2 : 1) * (g.wide ? 16 : 8); + } + } +} + +void premultiplied_color::set_palette(unsigned rshift, unsigned gshift, unsigned bshift, bool X) throw() +{ + if(X) { + uint64_t r = ((orig >> 16) & 0xFF) * 257; + uint64_t g = ((orig >> 8) & 0xFF) * 257; + uint64_t b = (orig & 0xFF) * 257; + uint64_t color = (r << rshift) | (g << gshift) | (b << bshift); + hiHI = color & 0xFFFF0000FFFFULL; + loHI = (color & 0xFFFF0000FFFF0000ULL) >> 16; + hiHI *= (static_cast(origa) * 256); + loHI *= (static_cast(origa) * 256); + } else { + uint32_t r = (orig >> 16) & 0xFF; + uint32_t g = (orig >> 8) & 0xFF; + uint32_t b = orig & 0xFF; + uint32_t color = (r << rshift) | (g << gshift) | (b << bshift); + hi = color & 0xFF00FF; + lo = (color & 0xFF00FF00) >> 8; + hi *= origa; + lo *= origa; + } +} + +template class framebuffer; +template class framebuffer; +template void render_queue::run(struct framebuffer&); +template void render_queue::run(struct framebuffer&); +template void bitmap_font::render(struct framebuffer& scr, int32_t x, int32_t y, const std::string& text, + premultiplied_color fg, premultiplied_color bg, bool hdbl, bool vdbl) throw(); +template void bitmap_font::render(struct framebuffer& scr, int32_t x, int32_t y, const std::string& text, + premultiplied_color fg, premultiplied_color bg, bool hdbl, bool vdbl) throw(); diff --git a/src/library/pixfmt-lrgb.cpp b/src/library/pixfmt-lrgb.cpp new file mode 100644 index 00000000..98cc2741 --- /dev/null +++ b/src/library/pixfmt-lrgb.cpp @@ -0,0 +1,90 @@ +#include "library/pixfmt-lrgb.hpp" + +pixel_format_lrgb::~pixel_format_lrgb() throw() +{ +} + +void pixel_format_lrgb::decode(uint8_t* target, const uint8_t* src, size_t width) + throw() +{ + const uint32_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) { + uint32_t word = _src[i]; + uint32_t l = 1 + ((word >> 15) & 0xF); + uint32_t r = l * ((word >> 0) & 0x1F); + uint32_t g = l * ((word >> 5) & 0x1F); + uint32_t b = l * ((word >> 10) & 0x1F); + target[3 * i + 0] = ((r << 8) - r + 248) / 496; + target[3 * i + 1] = ((g << 8) - g + 248) / 496; + target[3 * i + 2] = ((b << 8) - b + 248) / 496; + } +} + +void pixel_format_lrgb::decode(uint32_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw() +{ + const uint32_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) + target[i] = auxp.pcache[_src[i] & 0x7FFFF]; +} + +void pixel_format_lrgb::decode(uint64_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw() +{ + const uint32_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) + target[i] = auxp.pcache[_src[i] & 0x7FFFF]; +} + +void pixel_format_lrgb::set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) +{ + auxp.pcache.resize(0x80000); + for(size_t i = 0; i < 0x80000; i++) { + uint32_t l = 1 + ((i >> 15) & 0xF); + uint32_t r = l * ((i >> 0) & 0x1F); + uint32_t g = l * ((i >> 5) & 0x1F); + uint32_t b = l * ((i >> 10) & 0x1F); + auxp.pcache[i] = (((r << 8) - r + 248) / 496) << rshift; + auxp.pcache[i] += (((g << 8) - g + 248) / 496) << gshift; + auxp.pcache[i] += (((b << 8) - b + 248) / 496) << bshift; + } + auxp.rshift = rshift; + auxp.gshift = gshift; + auxp.bshift = bshift; +} + +void pixel_format_lrgb::set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) +{ + auxp.pcache.resize(0x80000); + for(size_t i = 0; i < 0x80000; i++) { + uint64_t l = 1 + ((i >> 15) & 0xF); + uint64_t r = l * ((i >> 0) & 0x1F); + uint64_t g = l * ((i >> 5) & 0x1F); + uint64_t b = l * ((i >> 10) & 0x1F); + auxp.pcache[i] = (((r << 16) - r + 248) / 496) << rshift; + auxp.pcache[i] += (((g << 16) - g + 248) / 496) << gshift; + auxp.pcache[i] += (((b << 16) - b + 248) / 496) << bshift; + } + auxp.rshift = rshift; + auxp.gshift = gshift; + auxp.bshift = bshift; +} + +uint8_t pixel_format_lrgb::get_bpp() throw() +{ + return 4; +} + +uint8_t pixel_format_lrgb::get_ss_bpp() throw() +{ + return 3; +} + +uint32_t pixel_format_lrgb::get_magic() throw() +{ + return 0; +} + +pixel_format_lrgb _pixel_format_lrgb; diff --git a/src/library/pixfmt-rgb15.cpp b/src/library/pixfmt-rgb15.cpp new file mode 100644 index 00000000..0bb311e5 --- /dev/null +++ b/src/library/pixfmt-rgb15.cpp @@ -0,0 +1,100 @@ +#include "library/pixfmt-rgb15.hpp" + +template +pixel_format_rgb15::~pixel_format_rgb15() throw() +{ +} + +template +void pixel_format_rgb15::decode(uint8_t* target, const uint8_t* src, size_t width) + throw() +{ + const uint16_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) { + uint32_t word = _src[i]; + uint64_t r = ((word >> (uvswap ? 10 : 0)) & 0x1F); + uint64_t g = ((word >> 5) & 0x1F); + uint64_t b = ((word >> (uvswap ? 0 : 10)) & 0x1F); + target[3 * i + 0] = ((r << 8) - r + 15) / 31; + target[3 * i + 1] = ((g << 8) - g + 15) / 31; + target[3 * i + 2] = ((b << 8) - b + 15) / 31; + } +} + +template +void pixel_format_rgb15::decode(uint32_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw() +{ + const uint16_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) + target[i] = auxp.pcache[_src[i] & 0x7FFF]; +} + +template +void pixel_format_rgb15::decode(uint64_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw() +{ + const uint16_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) + target[i] = auxp.pcache[_src[i] & 0x7FFF]; +} + +template +void pixel_format_rgb15::set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) +{ + auxp.pcache.resize(0x8000); + for(size_t i = 0; i < 0x8000; i++) { + uint32_t r = ((i >> (uvswap ? 10 : 0)) & 0x1F); + uint32_t g = ((i >> 5) & 0x1F); + uint32_t b = ((i >> (uvswap ? 0 : 10)) & 0x1F); + auxp.pcache[i] = (((r << 8) - r + 15) / 31) << rshift; + auxp.pcache[i] += (((g << 8) - g + 15) / 31) << gshift; + auxp.pcache[i] += (((b << 8) - b + 15) / 31) << bshift; + } + auxp.rshift = rshift; + auxp.gshift = gshift; + auxp.bshift = bshift; +} + +template +void pixel_format_rgb15::set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) +{ + auxp.pcache.resize(0x8000); + for(size_t i = 0; i < 0x8000; i++) { + uint64_t r = ((i >> (uvswap ? 10 : 0)) & 0x1F); + uint64_t g = ((i >> 5) & 0x1F); + uint64_t b = ((i >> (uvswap ? 0 : 10)) & 0x1F); + auxp.pcache[i] = (((r << 16) - r + 15) / 31) << rshift; + auxp.pcache[i] += (((g << 16) - g + 15) / 31) << gshift; + auxp.pcache[i] += (((b << 16) - b + 15) / 31) << bshift; + } + auxp.rshift = rshift; + auxp.gshift = gshift; + auxp.bshift = bshift; +} + +template +uint8_t pixel_format_rgb15::get_bpp() throw() +{ + return 2; +} + +template +uint8_t pixel_format_rgb15::get_ss_bpp() throw() +{ + return 2; +} + +template +uint32_t pixel_format_rgb15::get_magic() throw() +{ + if(uvswap) + return 0x16326322; + else + return 0x74324563; +} + +pixel_format_rgb15 _pixel_format_rgb15; +pixel_format_rgb15 _pixel_format_bgr15; diff --git a/src/library/pixfmt-rgb16.cpp b/src/library/pixfmt-rgb16.cpp new file mode 100644 index 00000000..73c37e08 --- /dev/null +++ b/src/library/pixfmt-rgb16.cpp @@ -0,0 +1,99 @@ +#include "library/pixfmt-rgb16.hpp" + +template +pixel_format_rgb16::~pixel_format_rgb16() throw() +{ +} + +template +void pixel_format_rgb16::decode(uint8_t* target, const uint8_t* src, size_t width) throw() +{ + const uint16_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) { + uint32_t word = _src[i]; + uint64_t r = ((word >> (uvswap ? 11 : 0)) & 0x1F); + uint64_t g = ((word >> 5) & 0x3F); + uint64_t b = ((word >> (uvswap ? 0 : 11)) & 0x1F); + target[3 * i + 0] = ((r << 8) - r + 15) / 31; + target[3 * i + 1] = ((g << 8) - g + 31) / 63; + target[3 * i + 2] = ((b << 8) - b + 15) / 31; + } +} + +template +void pixel_format_rgb16::decode(uint32_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw() +{ + const uint16_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) + target[i] = auxp.pcache[_src[i]]; +} + +template +void pixel_format_rgb16::decode(uint64_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw() +{ + const uint16_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) + target[i] = auxp.pcache[_src[i]]; +} + +template +void pixel_format_rgb16::set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) +{ + auxp.pcache.resize(0x10000); + for(size_t i = 0; i < 0x10000; i++) { + uint32_t r = ((i >> (uvswap ? 11 : 0)) & 0x1F); + uint32_t g = ((i >> 5) & 0x3F); + uint32_t b = ((i >> (uvswap ? 0 : 11)) & 0x1F); + auxp.pcache[i] = (((r << 8) - r + 15) / 31) << rshift; + auxp.pcache[i] += (((g << 8) - g + 31) / 63) << gshift; + auxp.pcache[i] += (((b << 8) - b + 15) / 31) << bshift; + } + auxp.rshift = rshift; + auxp.gshift = gshift; + auxp.bshift = bshift; +} + +template +void pixel_format_rgb16::set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) +{ + auxp.pcache.resize(0x10000); + for(size_t i = 0; i < 0x10000; i++) { + uint64_t r = ((i >> (uvswap ? 11 : 0)) & 0x1F); + uint64_t g = ((i >> 5) & 0x3F); + uint64_t b = ((i >> (uvswap ? 0 : 11)) & 0x1F); + auxp.pcache[i] = (((r << 16) - r + 15) / 31) << rshift; + auxp.pcache[i] += (((g << 16) - g + 31) / 63) << gshift; + auxp.pcache[i] += (((b << 16) - b + 15) / 31) << bshift; + } + auxp.rshift = rshift; + auxp.gshift = gshift; + auxp.bshift = bshift; +} + +template +uint8_t pixel_format_rgb16::get_bpp() throw() +{ + return 2; +} + +template +uint8_t pixel_format_rgb16::get_ss_bpp() throw() +{ + return 2; +} + +template +uint32_t pixel_format_rgb16::get_magic() throw() +{ + if(uvswap) + return 0x74234643; + else + return 0x32642474; +} + +pixel_format_rgb16 _pixel_format_rgb16; +pixel_format_rgb16 _pixel_format_bgr16; diff --git a/src/library/pixfmt-rgb24.cpp b/src/library/pixfmt-rgb24.cpp new file mode 100644 index 00000000..d47d49b5 --- /dev/null +++ b/src/library/pixfmt-rgb24.cpp @@ -0,0 +1,85 @@ +#include "library/pixfmt-rgb24.hpp" +#include + +template +pixel_format_rgb24::~pixel_format_rgb24() throw() {} + +template +void pixel_format_rgb24::decode(uint8_t* target, const uint8_t* src, size_t width) throw() +{ + if(uvswap) { + for(size_t i = 0; i < width; i++) { + target[3 * i + 0] = src[3 * i + 2]; + target[3 * i + 1] = src[3 * i + 1]; + target[3 * i + 2] = src[3 * i + 0]; + } + } else + memcpy(target, src, 3 * width); +} + +template +void pixel_format_rgb24::decode(uint32_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw() +{ + for(size_t i = 0; i < width; i++) { + target[i] = static_cast(src[3 * i + (uvswap ? 2 : 0)]) << auxp.rshift; + target[i] |= static_cast(src[3 * i + 1]) << auxp.gshift; + target[i] |= static_cast(src[3 * i + (uvswap ? 0 : 2)]) << auxp.bshift; + } +} + +template +void pixel_format_rgb24::decode(uint64_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw() +{ + for(size_t i = 0; i < width; i++) { + target[i] = static_cast(src[3 * i + (uvswap ? 2 : 0)]) << auxp.rshift; + target[i] |= static_cast(src[3 * i + 1]) << auxp.gshift; + target[i] |= static_cast(src[3 * i + (uvswap ? 0 : 2)]) << auxp.bshift; + target[i] += (target[i] << 8); + } +} + +template +void pixel_format_rgb24::set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) +{ + auxp.rshift = rshift; + auxp.gshift = gshift; + auxp.bshift = bshift; + auxp.pcache.clear(); +} + +template +void pixel_format_rgb24::set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) +{ + auxp.rshift = rshift; + auxp.gshift = gshift; + auxp.bshift = bshift; + auxp.pcache.clear(); +} + +template +uint8_t pixel_format_rgb24::get_bpp() throw() +{ + return 3; +} + +template +uint8_t pixel_format_rgb24::get_ss_bpp() throw() +{ + return 3; +} + +template +uint32_t pixel_format_rgb24::get_magic() throw() +{ + if(uvswap) + return 0x25642332U; + else + return 0x85433684U; +} + +pixel_format_rgb24 _pixel_format_rgb24; +pixel_format_rgb24 _pixel_format_bgr24; diff --git a/src/library/pixfmt-rgb32.cpp b/src/library/pixfmt-rgb32.cpp new file mode 100644 index 00000000..20e40a52 --- /dev/null +++ b/src/library/pixfmt-rgb32.cpp @@ -0,0 +1,71 @@ +#include "library/pixfmt-rgb32.hpp" + +pixel_format_rgb32::~pixel_format_rgb32() throw() {} + +void pixel_format_rgb32::decode(uint8_t* target, const uint8_t* src, size_t width) throw() +{ + const uint32_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) { + target[3 * i + 0] = _src[i] >> 16; + target[3 * i + 1] = _src[i] >> 8; + target[3 * i + 2] = _src[i]; + } +} + +void pixel_format_rgb32::decode(uint32_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw() +{ + const uint32_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) { + target[i] = ((_src[i] >> 16) & 0xFF) << auxp.rshift; + target[i] |= ((_src[i] >> 8) & 0xFF) << auxp.gshift; + target[i] |= (_src[i] & 0xFF) << auxp.bshift; + } +} + +void pixel_format_rgb32::decode(uint64_t* target, const uint8_t* src, size_t width, + const pixel_format_aux_palette& auxp) throw() +{ + const uint32_t* _src = reinterpret_cast(src); + for(size_t i = 0; i < width; i++) { + target[i] = static_cast((_src[i] >> 16) & 0xFF) << auxp.rshift; + target[i] |= static_cast((_src[i] >> 8) & 0xFF) << auxp.gshift; + target[i] |= static_cast(_src[i] & 0xFF) << auxp.bshift; + target[i] += (target[i] << 8); + } +} + +void pixel_format_rgb32::set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) +{ + auxp.rshift = rshift; + auxp.gshift = gshift; + auxp.bshift = bshift; + auxp.pcache.clear(); +} + +void pixel_format_rgb32::set_palette(pixel_format_aux_palette& auxp, uint8_t rshift, uint8_t gshift, + uint8_t bshift) throw(std::bad_alloc) +{ + auxp.rshift = rshift; + auxp.gshift = gshift; + auxp.bshift = bshift; + auxp.pcache.clear(); +} + +uint8_t pixel_format_rgb32::get_bpp() throw() +{ + return 4; +} + +uint8_t pixel_format_rgb32::get_ss_bpp() throw() +{ + return 3; +} + +uint32_t pixel_format_rgb32::get_magic() throw() +{ + return 0x74212536U; +} + +pixel_format_rgb32 _pixel_format_rgb32; diff --git a/src/core/png.cpp b/src/library/png.cpp similarity index 99% rename from src/core/png.cpp rename to src/library/png.cpp index 426f02ff..2e556fed 100644 --- a/src/core/png.cpp +++ b/src/library/png.cpp @@ -1,4 +1,4 @@ -#include "core/png.hpp" +#include "library/png.hpp" #include #include diff --git a/src/library/utf8.cpp b/src/library/utf8.cpp new file mode 100644 index 00000000..6bdf304e --- /dev/null +++ b/src/library/utf8.cpp @@ -0,0 +1,182 @@ +#include "library/utf8.hpp" + +namespace +{ + //First nibble values: + //0 => INITIAL + //1 => S_2_2 + //2 => S_2_3 + //3 => S_2_4 + //4 => S_3_3 + //5 => S_3_4 + //6 => INIT_RE + //7 => (unused) + //8 => S_4_4 + //Second nibble values: + //0 => Return NO CHARACTER and transition to another state with substate 0. + //1 => Return the character and transition to another state with substate 0. + //2 => Return invalid character and transition to another state with substate 0. + //3 => Memorize character minus 192, return NO CHARACTER and transition to another state. + //4 => Memorize character minus 224, return NO CHARACTER and transition to another state. + //5 => Memorize character minus 240, return NO CHARACTER and transition to another state. + //6 => Memorize byte, return invalid character and transition to another state. + //7 => Return 2-byte value and transition to another state. + //8 => Combine memorized, return NO CHARACTER and transition to another state. + //9 => Return 3-byte value and transition to another state. + //A => Return 4-byte value and transition to another state. + //B => Handle memorized character and EOF. + //C => Handle memorized character and continuation. + const unsigned char transitions[] = { + //E //1 //C //2 //3 //4 //I + 0x00, 0x01, 0x02, 0x13, 0x24, 0x35, 0x02, //INITIAL + 0x01, 0x66, 0x07, 0x66, 0x66, 0x66, 0x66, //S_2_2 + 0x01, 0x66, 0x48, 0x66, 0x66, 0x66, 0x66, //S_2_3 + 0x01, 0x66, 0x58, 0x66, 0x66, 0x66, 0x66, //S_2_4 + 0x01, 0x66, 0x09, 0x66, 0x66, 0x66, 0x66, //S_3_3 + 0x01, 0x66, 0x88, 0x66, 0x66, 0x66, 0x66, //S_3_4 + 0x0B, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, //INIT_RE + 0x01, 0x66, 0x0A, 0x66, 0x66, 0x66, 0x66 //S_4_4 + }; +} + +extern const uint16_t utf8_initial_state = 0; + +int32_t utf8_parse_byte(int ch, uint16_t& state) throw() +{ + unsigned char mch = (ch < 248) ? ch : 248; + uint32_t astate = state >> 12; + uint32_t iclass; + uint32_t tmp; + if(astate > 7) astate = 7; + if(ch < 0) iclass = 0; + else if(ch < 128) iclass = 1; + else if(ch < 192) iclass = 2; + else if(ch < 224) iclass = 3; + else if(ch < 240) iclass = 4; + else if(ch < 248) iclass = 5; + else iclass = 6; + unsigned char ctrl = transitions[astate * 7 + iclass]; + + switch(ctrl & 0xF) { + case 0x0: + state = (ctrl & 0xF0) * 256; + return -1; + case 0x1: + state = (ctrl & 0xF0) * 256; + return ch; + case 0x2: + state = (ctrl & 0xF0) * 256; + return 0xFFFD; + case 0x3: + state = (ctrl & 0xF0) * 256 + ch - 192; + return -1; + case 0x4: + state = (ctrl & 0xF0) * 256 + ch - 224; + return -1; + case 0x5: + state = (ctrl & 0xF0) * 256 + ch - 240; + return -1; + case 0x6: + state = (ctrl & 0xF0) * 256 + mch; + return 0xFFFD; + case 0x7: + tmp = (state & 0xFFF) * 64 + ch - 128; + if(tmp < 0x80) + tmp = 0xFFFD; + state = (ctrl & 0xF0) * 256; + return tmp; + case 0x8: + state = (ctrl & 0xF0) * 256 + (state & 0xFFF) * 64 + ch - 128; + return -1; + case 0x9: + tmp = (state & 0xFFF) * 64 + ch - 128; + if(tmp < 0x800 || (tmp & 0xF800) == 0xD800 || (tmp & 0xFFFE) == 0xFFFE) + tmp = 0xFFFD; + state = (ctrl & 0xF0) * 256; + return tmp; + case 0xA: + tmp = (state & 0x7FFF) * 64 + ch - 128; + if(tmp < 0x10000 || tmp > 0x10FFFD || (tmp & 0xFFFE) == 0xFFFE) + tmp = 0xFFFD; + state = (ctrl & 0xF0) * 256; + return tmp; + case 0xB: + if(state & 0x80) + tmp = 0xFFFD; + else + tmp = state & 0x7F; + state = (ctrl & 0xF0) * 256; + return tmp; + case 0xC: + //This is nasty. + if((state & 0x80) == 0) { + tmp = state & 0x7F; + state = 0x6000 + mch; + return tmp; + } else if((state & 0xF8) == 0xF8 || (state & 0xF8) == 0x80) { + //Continuation or invalid. + state = 0x6000 + mch; + return 0xFFFD; + } else if(iclass == 0) { + //Incomplete. + state = 0; + return 0xFFFD; + } else if(iclass != 2) { + //Bad sequence. + state = 0x6000 + mch; + return 0xFFFD; + } else if((state & 0xE0) == 0xC0) { + //Complete 2-byte sequence. + tmp = (state & 0x1F) * 64 + (ch & 0x3F); + state = 0; + if(tmp < 0x80) + tmp = 0xFFFD; + return tmp; + } else if((state & 0xF0) == 0xE0) { + //First 2 bytes of 3-byte sequence. + state = 0x4000 + (state & 0x0F) * 64 + (ch & 0x3F); + return -1; + } else if((state & 0xF8) == 0xF0) { + //First 2 bytes of 4-byte sequence. + state = 0x5000 + (state & 0x07) * 64 + (ch & 0x3F); + return -1; + } + }; +} + +size_t utf8_strlen(const std::string& str) throw() +{ + uint16_t s = utf8_initial_state; + size_t r = 0; + for(size_t i = 0; i < str.length(); i++) + if(utf8_parse_byte(static_cast(str[i]), s) >= 0) + r++; + if(utf8_parse_byte(-1, s) >= 0) + r++; + return r; +} + +#ifdef TEST_UTF8 +#include +char* format_dword(uint16_t s) +{ + static char buf[32]; + sprintf(buf, "%04X", s); + return buf; +} + +int main() +{ + uint16_t s = utf8_initial_state; + while(true) { + int c; + int32_t d; + std::cin >> c; + d = utf8_parse_byte(c, s); + std::cout << "> " << d << " (status word=" << format_dword(s) << ")" << std::endl; + if(c == -1 && d == -1) + return 0; + } + return 0; +} +#endif diff --git a/src/lua/gui-bitmap.cpp b/src/lua/gui-bitmap.cpp index 1550d8f2..75cfa94e 100644 --- a/src/lua/gui-bitmap.cpp +++ b/src/lua/gui-bitmap.cpp @@ -1,5 +1,5 @@ #include "lua/internal.hpp" -#include "core/render.hpp" +#include "library/framebuffer.hpp" #include "lua/bitmap.hpp" #include @@ -58,10 +58,12 @@ namespace delete p; } - template void composite_op(struct screen& scr) throw() + template void composite_op(struct framebuffer& scr) throw() { if(p) p->object()->palette_mutex->lock(); + uint32_t originx = scr.get_origin_x(); + uint32_t originy = scr.get_origin_y(); size_t pallim = 0; size_t w, h; premultiplied_color* palette; @@ -83,11 +85,11 @@ namespace int32_t xmax = w; int32_t ymin = 0; int32_t ymax = h; - clip_range(scr.originx, scr.width, x, xmin, xmax); - clip_range(scr.originy, scr.height, y, ymin, ymax); + clip_range(originx, scr.get_width(), x, xmin, xmax); + clip_range(originy, scr.get_height(), y, ymin, ymax); for(int32_t r = ymin; r < ymax; r++) { - typename screen::element_t* rptr = scr.rowptr(y + r + scr.originy); - size_t eptr = x + xmin + scr.originx; + typename framebuffer::element_t* rptr = scr.rowptr(y + r + originy); + size_t eptr = x + xmin + originx; if(b) for(int32_t c = xmin; c < xmax; c++, eptr++) { uint16_t i = b->object()->pixels[r * b->object()->width + c]; @@ -101,8 +103,8 @@ namespace if(p) p->object()->palette_mutex->unlock(); } - void operator()(struct screen& x) throw() { composite_op(x); } - void operator()(struct screen& x) throw() { composite_op(x); } + void operator()(struct framebuffer& x) throw() { composite_op(x); } + void operator()(struct framebuffer& x) throw() { composite_op(x); } private: int32_t x; int32_t y; diff --git a/src/lua/gui-box.cpp b/src/lua/gui-box.cpp index 1e049ef4..79c076fa 100644 --- a/src/lua/gui-box.cpp +++ b/src/lua/gui-box.cpp @@ -1,5 +1,5 @@ #include "lua/internal.hpp" -#include "core/render.hpp" +#include "library/framebuffer.hpp" namespace { @@ -11,20 +11,22 @@ namespace : x(_x), y(_y), width(_width), height(_height), outline1(_outline1), outline2(_outline2), fill(_fill), thickness(_thickness) {} ~render_object_box() throw() {} - template void op(struct screen& scr) throw() + template void op(struct framebuffer& scr) throw() { outline1.set_palette(scr); outline2.set_palette(scr); fill.set_palette(scr); + uint32_t originx = scr.get_origin_x(); + uint32_t originy = scr.get_origin_y(); int32_t xmin = 0; int32_t xmax = width; int32_t ymin = 0; int32_t ymax = height; - clip_range(scr.originx, scr.width, x, xmin, xmax); - clip_range(scr.originy, scr.height, y, ymin, ymax); + clip_range(originx, scr.get_width(), x, xmin, xmax); + clip_range(originy, scr.get_height(), y, ymin, ymax); for(int32_t r = ymin; r < ymax; r++) { - typename screen::element_t* rptr = scr.rowptr(y + r + scr.originy); - size_t eptr = x + xmin + scr.originx; + typename framebuffer::element_t* rptr = scr.rowptr(y + r + originy); + size_t eptr = x + xmin + originx; for(int32_t c = xmin; c < xmax; c++, eptr++) if((r < thickness && r <= (width - c)) || (c < thickness && c < (height - r))) outline1.apply(rptr[eptr]); @@ -35,8 +37,8 @@ namespace fill.apply(rptr[eptr]); } } - void operator()(struct screen& scr) throw() { op(scr); } - void operator()(struct screen& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } private: int32_t x; int32_t y; diff --git a/src/lua/gui-circle.cpp b/src/lua/gui-circle.cpp index 0419980d..ce03c46b 100644 --- a/src/lua/gui-circle.cpp +++ b/src/lua/gui-circle.cpp @@ -1,5 +1,5 @@ #include "lua/internal.hpp" -#include "core/render.hpp" +#include "library/framebuffer.hpp" namespace { @@ -18,20 +18,22 @@ namespace (_radius - _thickness); } ~render_object_circle() throw() {} - template void op(struct screen& scr) throw() + template void op(struct framebuffer& scr) throw() { outline.set_palette(scr); fill.set_palette(scr); + uint32_t originx = scr.get_origin_x(); + uint32_t originy = scr.get_origin_y(); int32_t xmin = -radius; int32_t xmax = radius; int32_t ymin = -radius; int32_t ymax = radius; - clip_range(scr.originx, scr.width, x, xmin, xmax); - clip_range(scr.originy, scr.height, y, ymin, ymax); + clip_range(originx, scr.get_width(), x, xmin, xmax); + clip_range(originy, scr.get_height(), y, ymin, ymax); for(int32_t r = ymin; r < ymax; r++) { uint64_t pd2 = static_cast(r) * r; - typename screen::element_t* rptr = scr.rowptr(y + r + scr.originy); - size_t eptr = x + xmin + scr.originx; + typename framebuffer::element_t* rptr = scr.rowptr(y + r + originy); + size_t eptr = x + xmin + originx; for(int32_t c = xmin; c < xmax; c++, eptr++) { uint64_t fd2 = pd2 + static_cast(c) * c; if(fd2 > radius2) @@ -43,8 +45,8 @@ namespace } } } - void operator()(struct screen& scr) throw() { op(scr); } - void operator()(struct screen& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } private: int32_t x; int32_t y; diff --git a/src/lua/gui-crosshair.cpp b/src/lua/gui-crosshair.cpp index 0d27940b..12137431 100644 --- a/src/lua/gui-crosshair.cpp +++ b/src/lua/gui-crosshair.cpp @@ -1,5 +1,5 @@ #include "lua/internal.hpp" -#include "core/render.hpp" +#include "library/framebuffer.hpp" namespace { @@ -8,24 +8,26 @@ namespace render_object_crosshair(int32_t _x, int32_t _y, premultiplied_color _color, uint32_t _length) throw() : x(_x), y(_y), color(_color), length(_length) {} ~render_object_crosshair() throw() {} - template void op(struct screen& scr) throw() + template void op(struct framebuffer& scr) throw() { color.set_palette(scr); + uint32_t originx = scr.get_origin_x(); + uint32_t originy = scr.get_origin_y(); int32_t xmin = -static_cast(length); int32_t xmax = static_cast(length + 1); int32_t ymin = -static_cast(length); int32_t ymax = static_cast(length + 1); - clip_range(scr.originx, scr.width, x, xmin, xmax); - clip_range(scr.originy, scr.height, y, ymin, ymax); + clip_range(originx, scr.get_width(), x, xmin, xmax); + clip_range(originy, scr.get_height(), y, ymin, ymax); if(xmin <= 0 && xmax > 0) for(int32_t r = ymin; r < ymax; r++) - color.apply(scr.rowptr(y + r + scr.originy)[x + scr.originx]); + color.apply(scr.rowptr(y + r + originy)[x + originx]); if(ymin <= 0 && ymax > 0) for(int32_t r = xmin; r < xmax; r++) - color.apply(scr.rowptr(y + scr.originy)[x + r + scr.originx]); + color.apply(scr.rowptr(y + originy)[x + r + originx]); } - void operator()(struct screen& scr) throw() { op(scr); } - void operator()(struct screen& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } private: int32_t x; int32_t y; diff --git a/src/lua/gui-line.cpp b/src/lua/gui-line.cpp index 63a32a34..09b881d8 100644 --- a/src/lua/gui-line.cpp +++ b/src/lua/gui-line.cpp @@ -1,5 +1,5 @@ #include "lua/internal.hpp" -#include "core/render.hpp" +#include "library/framebuffer.hpp" namespace { @@ -9,11 +9,17 @@ namespace throw() : x1(_x1), y1(_y1), x2(_x2), y2(_y2), color(_color) {} ~render_object_line() throw() {} - template void op(struct screen& scr) throw() + template void op(struct framebuffer& scr) throw() { + size_t swidth = scr.get_width(); + size_t sheight = scr.get_height(); + int32_t _x1 = x1 + scr.get_origin_x(); + int32_t _x2 = x2 + scr.get_origin_x(); + int32_t _y1 = y1 + scr.get_origin_y(); + int32_t _y2 = y2 + scr.get_origin_y(); color.set_palette(scr); - int32_t xdiff = x2 - x1; - int32_t ydiff = y2 - y1; + int32_t xdiff = _x2 - _x1; + int32_t ydiff = _y2 - _y1; if(xdiff < 0) xdiff = -xdiff; if(ydiff < 0) @@ -22,23 +28,23 @@ namespace //X-major line. if(x2 < x1) { //Swap points so that x1 < x2. - std::swap(x1, x2); - std::swap(y1, y2); + std::swap(_x1, _x2); + std::swap(_y1, _y2); } //The slope of the line is (y2 - y1) / (x2 - x1) = +-ydiff / xdiff - int32_t y = y1; + int32_t y = _y1; int32_t ysub = 0; - for(int32_t x = x1; x <= x2; x++) { - if(x < 0 || static_cast(x) >= scr.width) + for(int32_t x = _x1; x <= _x2; x++) { + if(x < 0 || static_cast(x) >= swidth) goto nodraw1; - if(y < 0 || static_cast(y) >= scr.height) + if(y < 0 || static_cast(y) >= sheight) goto nodraw1; color.apply(scr.rowptr(y)[x]); nodraw1: ysub += ydiff; if(ysub >= xdiff) { ysub -= xdiff; - if(y2 > y1) + if(_y2 > _y1) y++; else y--; @@ -46,25 +52,25 @@ nodraw1: } } else { //Y-major line. - if(x2 < x1) { + if(_x2 < _x1) { //Swap points so that y1 < y2. - std::swap(x1, x2); - std::swap(y1, y2); + std::swap(_x1, _x2); + std::swap(_y1, _y2); } //The slope of the line is (x2 - x1) / (y2 - y1) = +-xdiff / ydiff - int32_t x = x1; + int32_t x = _x1; int32_t xsub = 0; - for(int32_t y = y1; y <= y2; y++) { - if(x < 0 || static_cast(x) >= scr.width) + for(int32_t y = _y1; y <= _y2; y++) { + if(x < 0 || static_cast(x) >= swidth) goto nodraw2; - if(y < 0 || static_cast(y) >= scr.height) + if(y < 0 || static_cast(y) >= sheight) goto nodraw2; color.apply(scr.rowptr(y)[x]); nodraw2: xsub += xdiff; if(xsub >= ydiff) { xsub -= ydiff; - if(x2 > x1) + if(_x2 > _x1) x++; else x--; @@ -72,8 +78,8 @@ nodraw2: } } } - void operator()(struct screen& scr) throw() { op(scr); } - void operator()(struct screen& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } private: int32_t x1; int32_t y1; diff --git a/src/lua/gui-pixel.cpp b/src/lua/gui-pixel.cpp index 0a398e68..d9d0bc5e 100644 --- a/src/lua/gui-pixel.cpp +++ b/src/lua/gui-pixel.cpp @@ -1,5 +1,5 @@ #include "lua/internal.hpp" -#include "core/render.hpp" +#include "library/framebuffer.hpp" namespace { @@ -8,19 +8,19 @@ namespace render_object_pixel(int32_t _x, int32_t _y, premultiplied_color _color) throw() : x(_x), y(_y), color(_color) {} ~render_object_pixel() throw() {} - template void op(struct screen& scr) throw() + template void op(struct framebuffer& scr) throw() { color.set_palette(scr); - int32_t _x = x + scr.originx; - int32_t _y = y + scr.originy; - if(_x < 0 || static_cast(_x) >= scr.width) + int32_t _x = x + scr.get_origin_x(); + int32_t _y = y + scr.get_origin_y(); + if(_x < 0 || static_cast(_x) >= scr.get_width()) return; - if(_y < 0 || static_cast(_y) >= scr.height) + if(_y < 0 || static_cast(_y) >= scr.get_height()) return; color.apply(scr.rowptr(_y)[_x]); } - void operator()(struct screen& scr) throw() { op(scr); } - void operator()(struct screen& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } private: int32_t x; int32_t y; diff --git a/src/lua/gui-rectangle.cpp b/src/lua/gui-rectangle.cpp index e395cad9..081ec72c 100644 --- a/src/lua/gui-rectangle.cpp +++ b/src/lua/gui-rectangle.cpp @@ -1,5 +1,5 @@ #include "lua/internal.hpp" -#include "core/render.hpp" +#include "library/framebuffer.hpp" namespace { @@ -10,19 +10,21 @@ namespace : x(_x), y(_y), width(_width), height(_height), outline(_outline), fill(_fill), thickness(_thickness) {} ~render_object_rectangle() throw() {} - template void op(struct screen& scr) throw() + template void op(struct framebuffer& scr) throw() { outline.set_palette(scr); fill.set_palette(scr); + uint32_t originx = scr.get_origin_x(); + uint32_t originy = scr.get_origin_y(); int32_t xmin = 0; int32_t xmax = width; int32_t ymin = 0; int32_t ymax = height; - clip_range(scr.originx, scr.width, x, xmin, xmax); - clip_range(scr.originy, scr.height, y, ymin, ymax); + clip_range(originx, scr.get_width(), x, xmin, xmax); + clip_range(originy, scr.get_height(), y, ymin, ymax); for(int32_t r = ymin; r < ymax; r++) { - typename screen::element_t* rptr = scr.rowptr(y + r + scr.originy); - size_t eptr = x + xmin + scr.originx; + typename framebuffer::element_t* rptr = scr.rowptr(y + r + originy); + size_t eptr = x + xmin + originx; for(int32_t c = xmin; c < xmax; c++, eptr++) if(r < thickness || c < thickness || r >= height - thickness || c >= width - thickness) @@ -31,8 +33,8 @@ namespace fill.apply(rptr[eptr]); } } - void operator()(struct screen& scr) throw() { op(scr); } - void operator()(struct screen& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } private: int32_t x; int32_t y; diff --git a/src/lua/gui-text.cpp b/src/lua/gui-text.cpp index 9fd8f375..ce33c1ec 100644 --- a/src/lua/gui-text.cpp +++ b/src/lua/gui-text.cpp @@ -1,5 +1,6 @@ #include "lua/internal.hpp" -#include "core/render.hpp" +#include "fonts/wrapper.hpp" +#include "library/framebuffer.hpp" namespace { @@ -9,14 +10,14 @@ namespace premultiplied_color _bg, bool _hdbl = false, bool _vdbl = false) throw() : x(_x), y(_y), text(_text), fg(_fg), bg(_bg), hdbl(_hdbl), vdbl(_vdbl) {} ~render_object_text() throw() {} - template void op(struct screen& scr) throw() + template void op(struct framebuffer& scr) throw() { fg.set_palette(scr); bg.set_palette(scr); - render_text(scr, x, y, text, fg, bg, hdbl, vdbl); + main_font.render(scr, x, y, text, fg, bg, hdbl, vdbl); } - void operator()(struct screen& scr) throw() { op(scr); } - void operator()(struct screen& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } + void operator()(struct framebuffer& scr) throw() { op(scr); } private: int32_t x; int32_t y; diff --git a/src/platform/portaudio/sound.cpp b/src/platform/portaudio/sound.cpp index 45673928..25115e14 100644 --- a/src/platform/portaudio/sound.cpp +++ b/src/platform/portaudio/sound.cpp @@ -6,9 +6,9 @@ #include "core/misc.hpp" #include "core/framerate.hpp" #include "core/keymapper.hpp" -#include "core/render.hpp" #include "core/settings.hpp" #include "core/window.hpp" +#include "library/framebuffer.hpp" #include #include diff --git a/src/platform/sdl/sound.cpp b/src/platform/sdl/sound.cpp index dac2a051..8b5c3700 100644 --- a/src/platform/sdl/sound.cpp +++ b/src/platform/sdl/sound.cpp @@ -5,9 +5,9 @@ #include "core/framerate.hpp" #include "core/keymapper.hpp" #include "core/misc.hpp" -#include "core/render.hpp" #include "core/settings.hpp" #include "core/window.hpp" +#include "library/framebuffer.hpp" #include #include diff --git a/src/platform/wxwidgets/mainwindow.cpp b/src/platform/wxwidgets/mainwindow.cpp index ff4ece90..51bac629 100644 --- a/src/platform/wxwidgets/mainwindow.cpp +++ b/src/platform/wxwidgets/mainwindow.cpp @@ -584,16 +584,16 @@ void wxwin_mainwindow::panel::on_paint(wxPaintEvent& e) uint8_t* dstp[1]; int dsts[1]; wxPaintDC dc(this); - uint32_t tw = main_screen.width * horizontal_scale_factor + 0.5; - uint32_t th = main_screen.height * vertical_scale_factor + 0.5; + uint32_t tw = main_screen.get_width() * horizontal_scale_factor + 0.5; + uint32_t th = main_screen.get_height() * vertical_scale_factor + 0.5; if(!screen_buffer || tw != old_width || th != old_height || scaling_flags != old_flags) { if(screen_buffer) delete[] screen_buffer; old_height = th; old_width = tw; old_flags = scaling_flags; - uint32_t w = main_screen.width; - uint32_t h = main_screen.height; + uint32_t w = main_screen.get_width(); + uint32_t h = main_screen.get_height(); if(w && h) ctx = sws_getCachedContext(ctx, w, h, PIX_FMT_RGBA, tw, th, PIX_FMT_BGR24, scaling_flags, NULL, NULL, NULL); @@ -603,13 +603,13 @@ void wxwin_mainwindow::panel::on_paint(wxPaintEvent& e) SetMinSize(wxSize(tw, th)); signal_resize_needed(); } - srcs[0] = 4 * main_screen.width; + srcs[0] = 4 * main_screen.get_width(); dsts[0] = 3 * tw; - srcp[0] = reinterpret_cast(main_screen.memory); + srcp[0] = reinterpret_cast(main_screen.rowptr(0)); dstp[0] = screen_buffer; memset(screen_buffer, 0, tw * th * 3); - if(main_screen.width && main_screen.height) - sws_scale(ctx, srcp, srcs, 0, main_screen.height, dstp, dsts); + if(main_screen.get_width() && main_screen.get_height()) + sws_scale(ctx, srcp, srcs, 0, main_screen.get_height(), dstp, dsts); wxBitmap bmp(wxImage(tw, th, screen_buffer, true)); dc.DrawBitmap(bmp, 0, 0, false); main_window_dirty = false; diff --git a/src/util/lsnes-dumpavi.cpp b/src/util/lsnes-dumpavi.cpp index c37fbfc2..a76e0d90 100644 --- a/src/util/lsnes-dumpavi.cpp +++ b/src/util/lsnes-dumpavi.cpp @@ -34,7 +34,7 @@ namespace { } - void on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) + void on_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d) { frames_dumped++; if(frames_dumped % 100 == 0) { diff --git a/src/video/avi.cpp b/src/video/avi.cpp index f29835aa..34f912dc 100644 --- a/src/video/avi.cpp +++ b/src/video/avi.cpp @@ -326,16 +326,16 @@ again: delete soxdumper; } - void on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) + void on_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d) { uint32_t hscl = 1; uint32_t vscl = 1; - if(dump_large && _frame.width < 400) + if(dump_large && _frame.get_width() < 400) hscl = 2; - if(dump_large && _frame.height < 400) + if(dump_large && _frame.get_height() < 400) vscl = 2; render_video_hud(dscr, _frame, hscl, vscl, 0, 8, 16, dlb, dtb, drb, dbb, waitfn); - worker->queue_video(dscr.memory, dscr.width, dscr.height, fps_n, fps_d); + worker->queue_video(dscr.rowptr(0), dscr.get_width(), dscr.get_height(), fps_n, fps_d); have_dumped_frame = true; } @@ -390,7 +390,7 @@ again: resample_worker* resampler_w; private: sox_dumper* soxdumper; - screen dscr; + framebuffer dscr; unsigned dcounter; bool have_dumped_frame; std::pair soundrate; diff --git a/src/video/jmd.cpp b/src/video/jmd.cpp index d840f124..3d3a6d1e 100644 --- a/src/video/jmd.cpp +++ b/src/video/jmd.cpp @@ -87,14 +87,14 @@ namespace } } - void on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) + void on_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d) { render_video_hud(dscr, _frame, 1, 1, 0, 8, 16, 0, 0, 0, 0, NULL); frame_buffer f; f.ts = get_next_video_ts(fps_n, fps_d); size_t fsize = 0; //We'll compress the frame here. - f.data = compress_frame(dscr.memory, dscr.width, dscr.height); + f.data = compress_frame(dscr.rowptr(0), dscr.get_width(), dscr.get_height()); frames.push_back(f); flush_buffers(false); have_dumped_frame = true; @@ -175,7 +175,7 @@ namespace return ret; } - screen dscr; + framebuffer dscr; unsigned dcounter; bool have_dumped_frame; uint64_t audio_w; diff --git a/src/video/raw.cpp b/src/video/raw.cpp index 3c7393a3..3c7cf285 100644 --- a/src/video/raw.cpp +++ b/src/video/raw.cpp @@ -73,7 +73,7 @@ namespace deleter(audio); } - void on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) + void on_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d) { if(!video) return; @@ -85,16 +85,20 @@ namespace unsigned r = (reinterpret_cast(&magic))[swap ? 2 : 0]; unsigned g = (reinterpret_cast(&magic))[1]; unsigned b = (reinterpret_cast(&magic))[swap ? 0 : 2]; - uint32_t hscl = (_frame.width < 400) ? 2 : 1; - uint32_t vscl = (_frame.height < 400) ? 2 : 1; + uint32_t hscl = (_frame.get_width() < 400) ? 2 : 1; + uint32_t vscl = (_frame.get_height() < 400) ? 2 : 1; if(bits64) { + size_t w = dscr2.get_width(); + size_t h = dscr2.get_height(); render_video_hud(dscr2, _frame, hscl, vscl, r, g, b, 0, 0, 0, 0, NULL); - for(size_t i = 0; i < dscr2.height; i++) - video->write(reinterpret_cast(dscr2.rowptr(i)), 8 * dscr2.width); + for(size_t i = 0; i < h; i++) + video->write(reinterpret_cast(dscr2.rowptr(i)), 8 * w); } else { + size_t w = dscr.get_width(); + size_t h = dscr.get_height(); render_video_hud(dscr, _frame, hscl, vscl, r, g, b, 0, 0, 0, 0, NULL); - for(size_t i = 0; i < dscr.height; i++) - video->write(reinterpret_cast(dscr.rowptr(i)), 4 * dscr.width); + for(size_t i = 0; i < h; i++) + video->write(reinterpret_cast(dscr.rowptr(i)), 4 * w); } if(!*video) messages << "Video write error" << std::endl; @@ -128,8 +132,8 @@ namespace std::ostream* video; void (*deleter)(void* f); bool have_dumped_frame; - struct screen dscr; - struct screen dscr2; + struct framebuffer dscr; + struct framebuffer dscr2; bool swap; bool bits64; };