Merge the new framebuffer code
This commit is contained in:
commit
9289d22b3e
50 changed files with 2511 additions and 1306 deletions
|
@ -5,7 +5,7 @@
|
|||
#include <set>
|
||||
#include <stdexcept>
|
||||
|
||||
#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<bool X> void render_video_hud(struct screen<X>& 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<bool X> void render_video_hud(struct framebuffer<X>& 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
|
||||
|
|
|
@ -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 <cstdint>
|
||||
#include <string>
|
||||
|
@ -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<false>& scr);
|
||||
virtual void on_set_screen(framebuffer<false>& scr);
|
||||
/**
|
||||
* Call on_set_screen on all objects.
|
||||
*/
|
||||
static void do_set_screen(screen<false>& scr) throw();
|
||||
static void do_set_screen(framebuffer<false>& scr) throw();
|
||||
/**
|
||||
* Notify that new frame is available.
|
||||
*
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "core/render.hpp"
|
||||
#include "library/framebuffer.hpp"
|
||||
|
||||
/**
|
||||
* Logical button IDs.
|
||||
|
@ -147,7 +147,7 @@ public:
|
|||
//Get random seed.
|
||||
virtual time_t get_randomseed() = 0;
|
||||
//Output frame.
|
||||
virtual void output_frame(lcscreen& screen, uint32_t fps_n, uint32_t fps_d) = 0;
|
||||
virtual void output_frame(framebuffer_raw& screen, uint32_t fps_n, uint32_t fps_d) = 0;
|
||||
};
|
||||
|
||||
extern struct emucore_callbacks* ecore_callbacks;
|
||||
|
|
|
@ -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 <stdexcept>
|
||||
|
||||
|
@ -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<false> main_screen;
|
||||
extern framebuffer<false> 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.
|
||||
*/
|
||||
|
|
|
@ -1,435 +0,0 @@
|
|||
#ifndef _render__hpp__included__
|
||||
#define _render__hpp__included__
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* 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<char>& 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<char>& 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<bool X> struct screenelem {};
|
||||
template<> struct screenelem<false> { typedef uint32_t t; };
|
||||
template<> struct screenelem<true> { typedef uint64_t t; };
|
||||
|
||||
/**
|
||||
* Hicolor modifiable screen.
|
||||
*/
|
||||
template<bool X>
|
||||
struct screen
|
||||
{
|
||||
typedef typename screenelem<X>::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<X>&);
|
||||
screen& operator=(const screen<X>&);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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<false>& scr) throw() = 0;
|
||||
virtual void operator()(struct screen<true>& 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<uint32_t>(inv);
|
||||
set_palette(16, 8, 0, false);
|
||||
set_palette(32, 16, 0, true);
|
||||
//std::cerr << "Color " << color << " -> hi=" << hi << " lo=" << lo << " inv=" << inv << std::endl;
|
||||
}
|
||||
void set_palette(unsigned rshift, unsigned gshift, unsigned bshift, bool X) throw();
|
||||
template<bool X> void set_palette(struct screen<X>& 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<bool X> void run(struct screen<X>& 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<class T, typename... U> 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<size_t, page> memory;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clip range inside another.
|
||||
*
|
||||
* parameter origin: Origin coordinate.
|
||||
* parameter size: Dimension size.
|
||||
* parameter base: Base coordinate.
|
||||
* parameter minc: Minimum coordinate relative to base. Updated.
|
||||
* parameter maxc: Maximum coordinate relative to base. Updated.
|
||||
*/
|
||||
void clip_range(uint32_t origin, uint32_t size, int32_t base, int32_t& minc, int32_t& maxc) throw();
|
||||
|
||||
/**
|
||||
* 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<uint32_t, const uint32_t*> 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<bool X> void render_text(struct screen<X>& 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
|
|
@ -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 <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
|
585
include/library/framebuffer.hpp
Normal file
585
include/library/framebuffer.hpp
Normal file
|
@ -0,0 +1,585 @@
|
|||
#ifndef _library__framebuffer__hpp__included__
|
||||
#define _library__framebuffer__hpp__included__
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
template<bool X> struct framebufferelem {};
|
||||
template<> struct framebufferelem<false> { typedef uint32_t t; };
|
||||
template<> struct framebufferelem<true> { typedef uint64_t t; };
|
||||
|
||||
/**
|
||||
* Pixel format auxillary palette.
|
||||
*/
|
||||
template<bool X>
|
||||
struct pixel_format_aux_palette
|
||||
{
|
||||
typedef typename framebufferelem<X>::t element_t;
|
||||
uint8_t rshift; //Red shift.
|
||||
uint8_t gshift; //Green shift.
|
||||
uint8_t bshift; //Blue shift.
|
||||
std::vector<element_t> pcache; //Palette cache.
|
||||
};
|
||||
|
||||
/**
|
||||
* Pixel format.
|
||||
*/
|
||||
class 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<false>& auxp) throw() = 0;
|
||||
/**
|
||||
* Decode pixel format data into RGB (with specified byte order).
|
||||
*/
|
||||
virtual void decode(uint64_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<true>& auxp) throw() = 0;
|
||||
/**
|
||||
* Create aux palette.
|
||||
*/
|
||||
virtual void set_palette(pixel_format_aux_palette<false>& 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<true>& auxp, uint8_t rshift, uint8_t gshift,
|
||||
uint8_t bshift) throw(std::bad_alloc) = 0;
|
||||
/**
|
||||
* Bytes per pixel in data.
|
||||
*/
|
||||
virtual uint8_t get_bpp() throw() = 0;
|
||||
/**
|
||||
* Bytes per pixel in ss data.
|
||||
*/
|
||||
virtual uint8_t get_ss_bpp() throw() = 0;
|
||||
/**
|
||||
* Screenshot magic (0 for the old format).
|
||||
*/
|
||||
virtual uint32_t get_magic() throw() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Game framebuffer information.
|
||||
*/
|
||||
struct 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<bool X> struct framebuffer;
|
||||
|
||||
/**
|
||||
* Raw framebuffer.
|
||||
*
|
||||
* This framebuffer is in system format, and can either be backed either by temporary buffer or memory buffer.
|
||||
*
|
||||
* Any copying only preserves the visible part.
|
||||
*/
|
||||
struct 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<char>& data) throw(std::bad_alloc, std::runtime_error);
|
||||
/**
|
||||
* Save contents of framebuffer.
|
||||
*
|
||||
* parameter data: The vector to write the data to (in format compatible with load()).
|
||||
*/
|
||||
void save(std::vector<char>& data) throw(std::bad_alloc);
|
||||
/**
|
||||
* Save contents of framebuffer as a PNG.
|
||||
*
|
||||
* parameter file: The filename to save to.
|
||||
* throws std::runtime_error: Can't save the PNG.
|
||||
*/
|
||||
void save_png(const std::string& file) throw(std::bad_alloc, std::runtime_error);
|
||||
/**
|
||||
* Get width.
|
||||
*
|
||||
* Returns: The width.
|
||||
*/
|
||||
size_t get_width() const throw();
|
||||
/**
|
||||
* Get height.
|
||||
*
|
||||
* Returns: The height.
|
||||
*/
|
||||
size_t get_height() const throw();
|
||||
/**
|
||||
* 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<bool X> friend class framebuffer;
|
||||
};
|
||||
|
||||
|
||||
struct premultiplied_color;
|
||||
|
||||
/**
|
||||
* Rendered framebuffer.
|
||||
*
|
||||
* This framebuffer is in RGB32/RGB64 format, and is always backed by memory buffer.
|
||||
*/
|
||||
template<bool X>
|
||||
struct framebuffer
|
||||
{
|
||||
typedef typename framebufferelem<X>::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<X> auxpal; //Aux palette.
|
||||
bool user_mem; //True if internal memory is used.
|
||||
bool upside_down; //Upside down flag.
|
||||
uint8_t active_rshift; //Red shift.
|
||||
uint8_t active_gshift; //Green shift.
|
||||
uint8_t active_bshift; //Blue shift.
|
||||
friend struct 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<false>& scr) throw() = 0;
|
||||
virtual void operator()(struct framebuffer<true>& 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<uint32_t>(inv);
|
||||
set_palette(16, 8, 0, false);
|
||||
set_palette(32, 16, 0, true);
|
||||
//std::cerr << "Color " << color << " -> hi=" << hi << " lo=" << lo << " inv=" << inv << std::endl;
|
||||
}
|
||||
void set_palette(unsigned rshift, unsigned gshift, unsigned bshift, bool X) throw();
|
||||
template<bool X> void set_palette(struct framebuffer<X>& s) throw()
|
||||
{
|
||||
set_palette(s.active_rshift, s.active_gshift, s.active_bshift, X);
|
||||
}
|
||||
uint32_t blend(uint32_t color) throw()
|
||||
{
|
||||
uint32_t a, b;
|
||||
a = color & 0xFF00FF;
|
||||
b = (color & 0xFF00FF00) >> 8;
|
||||
return (((a * inv + hi) >> 8) & 0xFF00FF) | ((b * inv + lo) & 0xFF00FF00);
|
||||
}
|
||||
void apply(uint32_t& x) throw()
|
||||
{
|
||||
x = blend(x);
|
||||
}
|
||||
uint64_t blend(uint64_t color) throw()
|
||||
{
|
||||
uint64_t a, b;
|
||||
a = color & 0xFFFF0000FFFFULL;
|
||||
b = (color & 0xFFFF0000FFFF0000ULL) >> 16;
|
||||
return (((a * invHI + hiHI) >> 16) & 0xFFFF0000FFFFULL) | ((b * invHI + loHI) & 0xFFFF0000FFFF0000ULL);
|
||||
}
|
||||
void apply(uint64_t& x) throw()
|
||||
{
|
||||
x = blend(x);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Bitmap font (8x16).
|
||||
*/
|
||||
struct 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<size_t, size_t> get_metrics(const std::string& string) throw();
|
||||
/**
|
||||
* Layout a string.
|
||||
*
|
||||
* Parameter string: The string to get layout of.
|
||||
* Returns: String layout.
|
||||
*/
|
||||
std::vector<layout> dolayout(const std::string& string) throw(std::bad_alloc);
|
||||
/**
|
||||
* Render string to framebuffer.
|
||||
*
|
||||
* Parameter framebuffer: The framebuffer to render on.
|
||||
* Parameter x: The x-coordinate to start from.
|
||||
* Parameter y: The y-coordinate to start from.
|
||||
* Parameter text: The text to render.
|
||||
* Parameter fg: The foreground color.
|
||||
* Parameter bg: The background color.
|
||||
* Parameter hdbl: If set, double width horizontally.
|
||||
* Parameter vdbl: If set, double height vertically.
|
||||
*/
|
||||
template<bool X> void render(struct framebuffer<X>& 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<uint32_t, glyph> glyphs;
|
||||
size_t tabstop;
|
||||
std::vector<uint32_t> memory;
|
||||
void load_hex_glyph(const char* data, size_t size) throw(std::bad_alloc, std::runtime_error);
|
||||
};
|
||||
|
||||
|
||||
#define RENDER_PAGE_SIZE 65500
|
||||
|
||||
/**
|
||||
* Queue of render operations.
|
||||
*/
|
||||
struct render_queue
|
||||
{
|
||||
/**
|
||||
* Applies all objects in the queue in order.
|
||||
*
|
||||
* parameter scr: The screen to apply queue to.
|
||||
*/
|
||||
template<bool X> void run(struct framebuffer<X>& 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<class T, typename... U> 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<size_t, page> memory;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clip range inside another.
|
||||
*
|
||||
* parameter origin: Origin coordinate.
|
||||
* parameter size: Dimension size.
|
||||
* parameter base: Base coordinate.
|
||||
* parameter minc: Minimum coordinate relative to base. Updated.
|
||||
* parameter maxc: Maximum coordinate relative to base. Updated.
|
||||
*/
|
||||
void clip_range(uint32_t origin, uint32_t size, int32_t base, int32_t& minc, int32_t& maxc) throw();
|
||||
|
||||
|
||||
#endif
|
30
include/library/pixfmt-lrgb.hpp
Normal file
30
include/library/pixfmt-lrgb.hpp
Normal file
|
@ -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<false>& auxp) throw();
|
||||
void decode(uint64_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<true>& auxp) throw();
|
||||
void set_palette(pixel_format_aux_palette<false>& auxp, uint8_t rshift, uint8_t gshift,
|
||||
uint8_t bshift) throw(std::bad_alloc);
|
||||
void set_palette(pixel_format_aux_palette<true>& 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
|
32
include/library/pixfmt-rgb15.hpp
Normal file
32
include/library/pixfmt-rgb15.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef _pixfmt_rgb15__hpp__included__
|
||||
#define _pixfmt_rgb15__hpp__included__
|
||||
|
||||
#include "framebuffer.hpp"
|
||||
|
||||
/**
|
||||
* Pixel format RGB15 (5:5:5).
|
||||
*/
|
||||
template<bool uvswap>
|
||||
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<false>& auxp) throw();
|
||||
void decode(uint64_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<true>& auxp) throw();
|
||||
void set_palette(pixel_format_aux_palette<false>& auxp, uint8_t rshift, uint8_t gshift,
|
||||
uint8_t bshift) throw(std::bad_alloc);
|
||||
void set_palette(pixel_format_aux_palette<true>& 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<false> _pixel_format_rgb15;
|
||||
extern pixel_format_rgb15<true> _pixel_format_bgr15;
|
||||
|
||||
#endif
|
32
include/library/pixfmt-rgb16.hpp
Normal file
32
include/library/pixfmt-rgb16.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef _pixfmt_rgb16__hpp__included__
|
||||
#define _pixfmt_rgb16__hpp__included__
|
||||
|
||||
#include "framebuffer.hpp"
|
||||
|
||||
/**
|
||||
* Pixel format RGB16 (5:6:5).
|
||||
*/
|
||||
template<bool uvswap>
|
||||
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<false>& auxp) throw();
|
||||
void decode(uint64_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<true>& auxp) throw();
|
||||
void set_palette(pixel_format_aux_palette<false>& auxp, uint8_t rshift, uint8_t gshift,
|
||||
uint8_t bshift) throw(std::bad_alloc);
|
||||
void set_palette(pixel_format_aux_palette<true>& 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<false> _pixel_format_rgb16;
|
||||
extern pixel_format_rgb16<true> _pixel_format_bgr16;
|
||||
|
||||
#endif
|
32
include/library/pixfmt-rgb24.hpp
Normal file
32
include/library/pixfmt-rgb24.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef _pixfmt_rgb24__hpp__included__
|
||||
#define _pixfmt_rgb24__hpp__included__
|
||||
|
||||
#include "framebuffer.hpp"
|
||||
|
||||
/**
|
||||
* Pixel format RGB24.
|
||||
*/
|
||||
template<bool uvswap>
|
||||
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<false>& auxp) throw();
|
||||
void decode(uint64_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<true>& auxp) throw();
|
||||
void set_palette(pixel_format_aux_palette<false>& auxp, uint8_t rshift, uint8_t gshift,
|
||||
uint8_t bshift) throw(std::bad_alloc);
|
||||
void set_palette(pixel_format_aux_palette<true>& 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<false> _pixel_format_rgb24;
|
||||
extern pixel_format_rgb24<true> _pixel_format_bgr24;
|
||||
|
||||
#endif
|
30
include/library/pixfmt-rgb32.hpp
Normal file
30
include/library/pixfmt-rgb32.hpp
Normal file
|
@ -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<false>& auxp) throw();
|
||||
void decode(uint64_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<true>& auxp) throw();
|
||||
void set_palette(pixel_format_aux_palette<false>& auxp, uint8_t rshift, uint8_t gshift,
|
||||
uint8_t bshift) throw(std::bad_alloc);
|
||||
void set_palette(pixel_format_aux_palette<true>& 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
|
|
@ -12,7 +12,7 @@ void _write_common(unsigned char* target, T1 value)
|
|||
}
|
||||
|
||||
template<typename T1, typename T2, size_t ssize, bool be>
|
||||
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<unsigned char*>(t), (v));
|
||||
#define write64ube(t, v) _write_common<uint64_t, uint64_t, 8, true>(reinterpret_cast<unsigned char*>(t), (v));
|
||||
#define write64ule(t, v) _write_common<uint64_t, uint64_t, 8, false>(reinterpret_cast<unsigned char*>(t), (v));
|
||||
#define read8sbe(t) _read_common< int8_t, uint8_t, 1, true>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read8sle(t) _read_common< int8_t, uint8_t, 1, false>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read8ube(t) _read_common< uint8_t, uint8_t, 1, true>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read8ule(t) _read_common< uint8_t, uint8_t, 1, false>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read16sbe(t) _read_common< int16_t, uint16_t, 2, true>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read16sle(t) _read_common< int16_t, uint16_t, 2, false>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read16ube(t) _read_common<uint16_t, uint16_t, 2, true>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read16ule(t) _read_common<uint16_t, uint16_t, 2, false>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read32sbe(t) _read_common< int32_t, uint32_t, 4, true>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read32sle(t) _read_common< int32_t, uint32_t, 4, false>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read32ube(t) _read_common<uint32_t, uint32_t, 4, true>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read32ule(t) _read_common<uint32_t, uint32_t, 4, false>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read64sbe(t) _read_common< int64_t, uint64_t, 8, true>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read64sle(t) _read_common< int64_t, uint64_t, 8, false>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read64ube(t) _read_common<uint64_t, uint64_t, 8, true>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read64ule(t) _read_common<uint64_t, uint64_t, 8, false>(reinterpret_cast<unsigned char*>(t));
|
||||
#define read8sbe(t) _read_common< int8_t, uint8_t, 1, true>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read8sle(t) _read_common< int8_t, uint8_t, 1, false>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read8ube(t) _read_common< uint8_t, uint8_t, 1, true>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read8ule(t) _read_common< uint8_t, uint8_t, 1, false>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read16sbe(t) _read_common< int16_t, uint16_t, 2, true>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read16sle(t) _read_common< int16_t, uint16_t, 2, false>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read16ube(t) _read_common<uint16_t, uint16_t, 2, true>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read16ule(t) _read_common<uint16_t, uint16_t, 2, false>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read32sbe(t) _read_common< int32_t, uint32_t, 4, true>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read32sle(t) _read_common< int32_t, uint32_t, 4, false>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read32ube(t) _read_common<uint32_t, uint32_t, 4, true>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read32ule(t) _read_common<uint32_t, uint32_t, 4, false>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read64sbe(t) _read_common< int64_t, uint64_t, 8, true>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read64sle(t) _read_common< int64_t, uint64_t, 8, false>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read64ube(t) _read_common<uint64_t, uint64_t, 8, true>(reinterpret_cast<const unsigned char*>(t));
|
||||
#define read64ule(t) _read_common<uint64_t, uint64_t, 8, false>(reinterpret_cast<const unsigned char*>(t));
|
||||
|
||||
|
||||
|
||||
|
|
30
include/library/utf8.hpp
Normal file
30
include/library/utf8.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef _utf8__hpp__included__
|
||||
#define _utf8__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* 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
|
|
@ -4,8 +4,8 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include "core/render.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "library/framebuffer.hpp"
|
||||
|
||||
struct lua_bitmap
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<bool X> void render_video_hud(struct screen<X>& 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<bool X> void render_video_hud(struct framebuffer<X>& 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<bool X> void render_video_hud(struct screen<X>& 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<false>& 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<true>& 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<false>& 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<true>& 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)());
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
#include "core/dispatch.hpp"
|
||||
#include "core/framebuffer.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "library/pixfmt-lrgb.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/framebuffer.hpp"
|
||||
#include <snes/snes.hpp>
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#ifdef BSNES_V087
|
||||
|
@ -201,7 +203,20 @@ namespace
|
|||
uint32_t g = gcd(fps_n, fps_d);
|
||||
fps_n /= g;
|
||||
fps_d /= g;
|
||||
lcscreen ls(data, hires, interlace, overscan, region);
|
||||
|
||||
framebuffer_info inf;
|
||||
inf.type = &_pixel_format_lrgb;
|
||||
inf.mem = const_cast<char*>(reinterpret_cast<const char*>(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);
|
||||
ecore_callbacks->output_frame(ls, fps_n, fps_d);
|
||||
information_dispatch::do_raw_frame(data, hires, interlace, overscan, region ?
|
||||
VIDEO_REGION_PAL : VIDEO_REGION_NTSC);
|
||||
|
|
|
@ -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<false>& scr)
|
||||
void information_dispatch::on_set_screen(framebuffer<false>& scr)
|
||||
{
|
||||
//Do nothing.
|
||||
}
|
||||
|
||||
void information_dispatch::do_set_screen(screen<false>& scr) throw()
|
||||
void information_dispatch::do_set_screen(framebuffer<false>& scr) throw()
|
||||
{
|
||||
for(auto& i : dispatch()) {
|
||||
START_EH_BLOCK
|
||||
|
|
|
@ -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<false> main_screen;
|
||||
framebuffer<false> 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<uint32_t> buf;
|
||||
buf.resize(512*448);
|
||||
|
||||
framebuffer_info inf;
|
||||
inf.type = &_pixel_format_lrgb;
|
||||
inf.mem = reinterpret_cast<char*>(&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<short>(ri.lgap), ri.lgap, ri.fbuf.width * ri.hscl + ri.rgap,
|
||||
0.5);
|
||||
mouse_x->change_calibration(-static_cast<short>(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<short>(ri.tgap), ri.tgap, ri.fbuf.height * ri.vscl + ri.bgap,
|
||||
0.5);
|
||||
mouse_y->change_calibration(-static_cast<short>(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<uint32_t, uint32_t> 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;
|
||||
}
|
||||
|
|
|
@ -15,11 +15,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 <iomanip>
|
||||
#include <cassert>
|
||||
|
@ -312,7 +313,7 @@ public:
|
|||
return random_seed_value;
|
||||
}
|
||||
|
||||
void output_frame(lcscreen& screen, uint32_t fps_n, uint32_t fps_d)
|
||||
void output_frame(framebuffer_raw& screen, uint32_t fps_n, uint32_t fps_d)
|
||||
{
|
||||
lua_callback_do_frame_emulated();
|
||||
location_special = SPECIAL_FRAME_VIDEO;
|
||||
|
|
|
@ -392,7 +392,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);
|
||||
|
|
|
@ -1,668 +0,0 @@
|
|||
#include "lsnes.hpp"
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#include "core/misc.hpp"
|
||||
#include "core/png.hpp"
|
||||
#include "core/render.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
#include <iomanip>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#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<uint32_t> font_glyph_data;
|
||||
std::map<uint32_t, uint32_t> 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<uint32_t>(origa) * 256);
|
||||
loHI *= (static_cast<uint32_t>(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<uint32_t, const uint32_t*> 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<uint32_t, const uint32_t*>(dwidth, visible ? &font_glyph_data[offset + 1] : NULL);
|
||||
}
|
||||
|
||||
render_object::~render_object() throw()
|
||||
{
|
||||
}
|
||||
|
||||
template<bool X> void render_text(struct screen<X>& 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<uint32_t>(static_cast<int32_t>(scr.originx) + x);
|
||||
uint32_t cy = static_cast<uint32_t>(static_cast<int32_t>(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<X>::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<X>::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<struct node*>(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<bool X> void render_queue::run(struct screen<X>& 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<size_t>(width) * height;
|
||||
memory = new uint32_t[allocated];
|
||||
for(size_t l = 0; l < height; l++)
|
||||
memcpy(const_cast<uint32_t*>(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<size_t>(ls.width) * ls.height) {
|
||||
size_t p_allocated = static_cast<size_t>(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<uint32_t*>(memory + l * width), ls.memory + l * ls.pitch, 4 * width);
|
||||
return *this;
|
||||
}
|
||||
|
||||
lcscreen::~lcscreen()
|
||||
{
|
||||
if(user_memory)
|
||||
delete[] const_cast<uint32_t*>(memory);
|
||||
}
|
||||
|
||||
void lcscreen::load(const std::vector<char>& 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<const uint8_t*>(&data[0]);
|
||||
if(data.size() < 2)
|
||||
throw std::runtime_error("Corrupt saved screenshot data");
|
||||
uint32_t _width = static_cast<uint32_t>(data2[0]) * 256 + static_cast<uint32_t>(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<size_t>(_width) * _height) {
|
||||
size_t p_allocated = static_cast<size_t>(_width) * _height;
|
||||
memory = new uint32_t[p_allocated];
|
||||
allocated = p_allocated;
|
||||
}
|
||||
uint32_t* mem = const_cast<uint32_t*>(memory);
|
||||
width = _width;
|
||||
height = _height;
|
||||
pitch = width;
|
||||
for(size_t i = 0; i < (data.size() - 2) / 3; i++)
|
||||
mem[i] = static_cast<uint32_t>(data2[2 + 3 * i]) * 65536 +
|
||||
static_cast<uint32_t>(data2[2 + 3 * i + 1]) * 256 +
|
||||
static_cast<uint32_t>(data2[2 + 3 * i + 2]);
|
||||
}
|
||||
|
||||
void lcscreen::save(std::vector<char>& data) throw(std::bad_alloc)
|
||||
{
|
||||
data.resize(2 + 3 * static_cast<size_t>(width) * height);
|
||||
uint8_t* data2 = reinterpret_cast<uint8_t*>(&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<size_t>(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<size_t>(width) * j + 3 * i + 0] = r * 255 / 496;
|
||||
buffer[3 * static_cast<size_t>(width) * j + 3 * i + 1] = g * 255 / 496;
|
||||
buffer[3 * static_cast<size_t>(width) * j + 3 * i + 2] = b * 255 / 496;
|
||||
}
|
||||
try {
|
||||
save_png_data(file, buffer, width, height);
|
||||
delete[] buffer;
|
||||
} catch(...) {
|
||||
delete[] buffer;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool X> void screen<X>::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<X>::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<X>::element_t) * width);
|
||||
for(uint32_t y = 0; y < copyable_height; y++) {
|
||||
uint32_t line = y * vscale + originy;
|
||||
typename screen<X>::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<X>::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<X>::element_t) * hscale * copyable_width);
|
||||
}
|
||||
}
|
||||
|
||||
template<bool X> void screen<X>::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<X>::element_t* newmem = new typename screen<X>::element_t[_width * _height];
|
||||
width = _width;
|
||||
height = _height;
|
||||
pitch = sizeof(typename screen<X>::element_t) * _width;
|
||||
if(memory && !user_memory)
|
||||
delete[] memory;
|
||||
memory = newmem;
|
||||
user_memory = false;
|
||||
flipped = upside_down;
|
||||
}
|
||||
|
||||
template<bool X> void screen<X>::set(typename screen<X>::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<bool X> void screen<X>::set_origin(uint32_t _originx, uint32_t _originy) throw()
|
||||
{
|
||||
originx = _originx;
|
||||
originy = _originy;
|
||||
}
|
||||
|
||||
template<bool X> typename screen<X>::element_t* screen<X>::rowptr(uint32_t row) throw()
|
||||
{
|
||||
if(flipped)
|
||||
row = height - row - 1;
|
||||
return reinterpret_cast<typename screen<X>::element_t*>(reinterpret_cast<uint8_t*>(memory) + row * pitch);
|
||||
}
|
||||
|
||||
template<bool X> screen<X>::screen() throw()
|
||||
{
|
||||
memory = NULL;
|
||||
width = height = originx = originy = pitch = 0;
|
||||
user_memory = false;
|
||||
flipped = false;
|
||||
palette = NULL;
|
||||
set_palette(16, 8, 0);
|
||||
}
|
||||
|
||||
template<bool X> screen<X>::~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<bool X> void screen<X>::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<size_t>(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<double>(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<false>;
|
||||
template struct screen<true>;
|
||||
template void render_queue::run(screen<false>&);
|
||||
template void render_queue::run(screen<true>&);
|
||||
template void render_text(struct screen<false>& 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<true>& 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);
|
|
@ -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<false>* our_screen;
|
||||
framebuffer<false>* our_screen;
|
||||
|
||||
struct painter_listener : public information_dispatch
|
||||
{
|
||||
painter_listener();
|
||||
void on_set_screen(screen<false>& scr);
|
||||
void on_set_screen(framebuffer<false>& 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<false>& scr)
|
||||
void painter_listener::on_set_screen(framebuffer<false>& 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();
|
||||
|
|
|
@ -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
|
||||
|
|
15
src/fonts/wrapper.cpp
Normal file
15
src/fonts/wrapper.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include "library/framebuffer.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
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;
|
||||
}
|
844
src/library/framebuffer.cpp
Normal file
844
src/library/framebuffer.cpp
Normal file
|
@ -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 <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#define TABSTOPS 64
|
||||
#define SCREENSHOT_RGB_MAGIC 0x74212536U
|
||||
|
||||
namespace
|
||||
{
|
||||
std::list<pixel_format*>& pixel_formats()
|
||||
{
|
||||
static std::list<pixel_format*> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
template<size_t c> 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<uint16_t*>(target);
|
||||
for(size_t i = 0; i < srcsize; i++) {
|
||||
_target[i] = static_cast<uint16_t>(src[2 * i + 0]) << 8;
|
||||
_target[i] |= static_cast<uint16_t>(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<uint32_t*>(target);
|
||||
for(size_t i = 0; i < srcsize; i++) {
|
||||
_target[i] = static_cast<uint32_t>(src[4 * i + 0]) << 24;
|
||||
_target[i] |= static_cast<uint32_t>(src[4 * i + 1]) << 16;
|
||||
_target[i] |= static_cast<uint32_t>(src[4 * i + 2]) << 8;
|
||||
_target[i] |= static_cast<uint32_t>(src[4 * i + 3]);
|
||||
}
|
||||
} else if(c == 5) {
|
||||
uint32_t* _target = reinterpret_cast<uint32_t*>(target);
|
||||
for(size_t i = 0; i < srcsize; i++) {
|
||||
_target[i] = (static_cast<uint32_t>(src[3 * i + 0]) << 16);
|
||||
_target[i] |= (static_cast<uint32_t>(src[3 * i + 1]) << 8);
|
||||
_target[i] |= (static_cast<uint32_t>(src[3 * i + 2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t c> 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<const uint16_t*>(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<const uint32_t*>(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<const uint32_t*>(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<char>& 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<const uint8_t*>(&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<uint8_t*>(addr), data2 + dataoffset, data.size() - dataoffset);
|
||||
else if(bpp == 2)
|
||||
decode_words<2>(reinterpret_cast<uint8_t*>(addr), data2 + dataoffset, data.size() - dataoffset);
|
||||
else if(bpp == 3)
|
||||
decode_words<3>(reinterpret_cast<uint8_t*>(addr), data2 + dataoffset, data.size() - dataoffset);
|
||||
else if(bpp == 4 && sbpp == 3)
|
||||
decode_words<5>(reinterpret_cast<uint8_t*>(addr), data2 + dataoffset, data.size() - dataoffset);
|
||||
else if(bpp == 4 && sbpp == 4)
|
||||
decode_words<4>(reinterpret_cast<uint8_t*>(addr), data2 + dataoffset, data.size() - dataoffset);
|
||||
}
|
||||
|
||||
void framebuffer_raw::save(std::vector<char>& data) throw(std::bad_alloc)
|
||||
{
|
||||
uint8_t* memory = reinterpret_cast<uint8_t*>(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<size_t>(width) * height);
|
||||
data2 = reinterpret_cast<uint8_t*>(&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<size_t>(width) * height);
|
||||
write16ube(&data[0], m);
|
||||
write32ube(&data[2], magic);
|
||||
write16ube(&data[6], width);
|
||||
break;
|
||||
}
|
||||
data2 = reinterpret_cast<uint8_t*>(&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<uint8_t*>(addr);
|
||||
uint8_t* buffer = new uint8_t[3 * static_cast<size_t>(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<bool X>
|
||||
framebuffer<X>::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<bool X>
|
||||
framebuffer<X>::~framebuffer() throw()
|
||||
{
|
||||
if(user_mem)
|
||||
delete[] mem;
|
||||
}
|
||||
|
||||
#define DECBUF_SIZE 1024
|
||||
|
||||
template<bool X>
|
||||
void framebuffer<X>::copy_from(framebuffer_raw& scr, size_t hscale, size_t vscale) throw()
|
||||
{
|
||||
typename framebuffer<X>::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<X>::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<uint8_t*>(scr.addr) + y * scr.stride;
|
||||
typename framebuffer<X>::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<X>::element_t) * hscale * copyable_width);
|
||||
};
|
||||
}
|
||||
|
||||
template<bool X>
|
||||
void framebuffer<X>::set_palette(uint32_t r, uint32_t g, uint32_t b) throw(std::bad_alloc)
|
||||
{
|
||||
typename framebuffer<X>::element_t R, G, B;
|
||||
if(r == active_rshift && g == active_gshift && b == active_bshift)
|
||||
return;
|
||||
for(size_t i = 0; i < static_cast<size_t>(width) * height; i++) {
|
||||
typename framebuffer<X>::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<bool X>
|
||||
void framebuffer<X>::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<bool X>
|
||||
void framebuffer<X>::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<bool X>
|
||||
void framebuffer<X>::set_origin(size_t _offset_x, size_t _offset_y) throw()
|
||||
{
|
||||
offset_x = _offset_x;
|
||||
offset_y = _offset_y;
|
||||
}
|
||||
|
||||
template<bool X>
|
||||
size_t framebuffer<X>::get_width() const throw()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
template<bool X>
|
||||
size_t framebuffer<X>::get_height() const throw()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
template<bool X>
|
||||
typename framebuffer<X>::element_t* framebuffer<X>::rowptr(size_t row) throw()
|
||||
{
|
||||
if(upside_down)
|
||||
row = height - row - 1;
|
||||
return mem + stride * row;
|
||||
}
|
||||
|
||||
template<bool X>
|
||||
const typename framebuffer<X>::element_t* framebuffer<X>::rowptr(size_t row) const throw()
|
||||
{
|
||||
if(upside_down)
|
||||
row = height - row - 1;
|
||||
return mem + stride * row;
|
||||
}
|
||||
|
||||
template<bool X> uint8_t framebuffer<X>::get_palette_r() const throw() { return auxpal.rshift; }
|
||||
template<bool X> uint8_t framebuffer<X>::get_palette_g() const throw() { return auxpal.gshift; }
|
||||
template<bool X> uint8_t framebuffer<X>::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<bool X> size_t framebuffer<X>::get_origin_x() const throw() { return offset_x; }
|
||||
template<bool X> size_t framebuffer<X>::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<struct node*>(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<bool X> void render_queue::run(struct framebuffer<X>& 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<size_t, size_t> 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<unsigned char>(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::layout> 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<unsigned char>(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<layout> 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<unsigned char>(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<bool X> void bitmap_font::render(struct framebuffer<X>& 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<unsigned char>(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<X>::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<X>::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<uint32_t>(origa) * 256);
|
||||
loHI *= (static_cast<uint32_t>(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<false>;
|
||||
template class framebuffer<true>;
|
||||
template void render_queue::run(struct framebuffer<false>&);
|
||||
template void render_queue::run(struct framebuffer<true>&);
|
||||
template void bitmap_font::render(struct framebuffer<false>& 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<true>& scr, int32_t x, int32_t y, const std::string& text,
|
||||
premultiplied_color fg, premultiplied_color bg, bool hdbl, bool vdbl) throw();
|
90
src/library/pixfmt-lrgb.cpp
Normal file
90
src/library/pixfmt-lrgb.cpp
Normal file
|
@ -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<const uint32_t*>(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<false>& auxp) throw()
|
||||
{
|
||||
const uint32_t* _src = reinterpret_cast<const uint32_t*>(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<true>& auxp) throw()
|
||||
{
|
||||
const uint32_t* _src = reinterpret_cast<const uint32_t*>(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<false>& 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<true>& 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;
|
100
src/library/pixfmt-rgb15.cpp
Normal file
100
src/library/pixfmt-rgb15.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
#include "library/pixfmt-rgb15.hpp"
|
||||
|
||||
template<bool uvswap>
|
||||
pixel_format_rgb15<uvswap>::~pixel_format_rgb15() throw()
|
||||
{
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
void pixel_format_rgb15<uvswap>::decode(uint8_t* target, const uint8_t* src, size_t width)
|
||||
throw()
|
||||
{
|
||||
const uint16_t* _src = reinterpret_cast<const uint16_t*>(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<bool uvswap>
|
||||
void pixel_format_rgb15<uvswap>::decode(uint32_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<false>& auxp) throw()
|
||||
{
|
||||
const uint16_t* _src = reinterpret_cast<const uint16_t*>(src);
|
||||
for(size_t i = 0; i < width; i++)
|
||||
target[i] = auxp.pcache[_src[i] & 0x7FFF];
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
void pixel_format_rgb15<uvswap>::decode(uint64_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<true>& auxp) throw()
|
||||
{
|
||||
const uint16_t* _src = reinterpret_cast<const uint16_t*>(src);
|
||||
for(size_t i = 0; i < width; i++)
|
||||
target[i] = auxp.pcache[_src[i] & 0x7FFF];
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
void pixel_format_rgb15<uvswap>::set_palette(pixel_format_aux_palette<false>& 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<bool uvswap>
|
||||
void pixel_format_rgb15<uvswap>::set_palette(pixel_format_aux_palette<true>& 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<bool uvswap>
|
||||
uint8_t pixel_format_rgb15<uvswap>::get_bpp() throw()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
uint8_t pixel_format_rgb15<uvswap>::get_ss_bpp() throw()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
uint32_t pixel_format_rgb15<uvswap>::get_magic() throw()
|
||||
{
|
||||
if(uvswap)
|
||||
return 0x16326322;
|
||||
else
|
||||
return 0x74324563;
|
||||
}
|
||||
|
||||
pixel_format_rgb15<false> _pixel_format_rgb15;
|
||||
pixel_format_rgb15<true> _pixel_format_bgr15;
|
99
src/library/pixfmt-rgb16.cpp
Normal file
99
src/library/pixfmt-rgb16.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
#include "library/pixfmt-rgb16.hpp"
|
||||
|
||||
template<bool uvswap>
|
||||
pixel_format_rgb16<uvswap>::~pixel_format_rgb16() throw()
|
||||
{
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
void pixel_format_rgb16<uvswap>::decode(uint8_t* target, const uint8_t* src, size_t width) throw()
|
||||
{
|
||||
const uint16_t* _src = reinterpret_cast<const uint16_t*>(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<bool uvswap>
|
||||
void pixel_format_rgb16<uvswap>::decode(uint32_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<false>& auxp) throw()
|
||||
{
|
||||
const uint16_t* _src = reinterpret_cast<const uint16_t*>(src);
|
||||
for(size_t i = 0; i < width; i++)
|
||||
target[i] = auxp.pcache[_src[i]];
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
void pixel_format_rgb16<uvswap>::decode(uint64_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<true>& auxp) throw()
|
||||
{
|
||||
const uint16_t* _src = reinterpret_cast<const uint16_t*>(src);
|
||||
for(size_t i = 0; i < width; i++)
|
||||
target[i] = auxp.pcache[_src[i]];
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
void pixel_format_rgb16<uvswap>::set_palette(pixel_format_aux_palette<false>& 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<bool uvswap>
|
||||
void pixel_format_rgb16<uvswap>::set_palette(pixel_format_aux_palette<true>& 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<bool uvswap>
|
||||
uint8_t pixel_format_rgb16<uvswap>::get_bpp() throw()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
uint8_t pixel_format_rgb16<uvswap>::get_ss_bpp() throw()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
uint32_t pixel_format_rgb16<uvswap>::get_magic() throw()
|
||||
{
|
||||
if(uvswap)
|
||||
return 0x74234643;
|
||||
else
|
||||
return 0x32642474;
|
||||
}
|
||||
|
||||
pixel_format_rgb16<false> _pixel_format_rgb16;
|
||||
pixel_format_rgb16<true> _pixel_format_bgr16;
|
85
src/library/pixfmt-rgb24.cpp
Normal file
85
src/library/pixfmt-rgb24.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
#include "library/pixfmt-rgb24.hpp"
|
||||
#include <cstring>
|
||||
|
||||
template<bool uvswap>
|
||||
pixel_format_rgb24<uvswap>::~pixel_format_rgb24() throw() {}
|
||||
|
||||
template<bool uvswap>
|
||||
void pixel_format_rgb24<uvswap>::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<bool uvswap>
|
||||
void pixel_format_rgb24<uvswap>::decode(uint32_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<false>& auxp) throw()
|
||||
{
|
||||
for(size_t i = 0; i < width; i++) {
|
||||
target[i] = static_cast<uint32_t>(src[3 * i + (uvswap ? 2 : 0)]) << auxp.rshift;
|
||||
target[i] |= static_cast<uint32_t>(src[3 * i + 1]) << auxp.gshift;
|
||||
target[i] |= static_cast<uint32_t>(src[3 * i + (uvswap ? 0 : 2)]) << auxp.bshift;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
void pixel_format_rgb24<uvswap>::decode(uint64_t* target, const uint8_t* src, size_t width,
|
||||
const pixel_format_aux_palette<true>& auxp) throw()
|
||||
{
|
||||
for(size_t i = 0; i < width; i++) {
|
||||
target[i] = static_cast<uint64_t>(src[3 * i + (uvswap ? 2 : 0)]) << auxp.rshift;
|
||||
target[i] |= static_cast<uint64_t>(src[3 * i + 1]) << auxp.gshift;
|
||||
target[i] |= static_cast<uint64_t>(src[3 * i + (uvswap ? 0 : 2)]) << auxp.bshift;
|
||||
target[i] += (target[i] << 8);
|
||||
}
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
void pixel_format_rgb24<uvswap>::set_palette(pixel_format_aux_palette<false>& 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<bool uvswap>
|
||||
void pixel_format_rgb24<uvswap>::set_palette(pixel_format_aux_palette<true>& 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<bool uvswap>
|
||||
uint8_t pixel_format_rgb24<uvswap>::get_bpp() throw()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
uint8_t pixel_format_rgb24<uvswap>::get_ss_bpp() throw()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
template<bool uvswap>
|
||||
uint32_t pixel_format_rgb24<uvswap>::get_magic() throw()
|
||||
{
|
||||
if(uvswap)
|
||||
return 0x25642332U;
|
||||
else
|
||||
return 0x85433684U;
|
||||
}
|
||||
|
||||
pixel_format_rgb24<false> _pixel_format_rgb24;
|
||||
pixel_format_rgb24<true> _pixel_format_bgr24;
|
71
src/library/pixfmt-rgb32.cpp
Normal file
71
src/library/pixfmt-rgb32.cpp
Normal file
|
@ -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<const uint32_t*>(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<false>& auxp) throw()
|
||||
{
|
||||
const uint32_t* _src = reinterpret_cast<const uint32_t*>(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<true>& auxp) throw()
|
||||
{
|
||||
const uint32_t* _src = reinterpret_cast<const uint32_t*>(src);
|
||||
for(size_t i = 0; i < width; i++) {
|
||||
target[i] = static_cast<uint64_t>((_src[i] >> 16) & 0xFF) << auxp.rshift;
|
||||
target[i] |= static_cast<uint64_t>((_src[i] >> 8) & 0xFF) << auxp.gshift;
|
||||
target[i] |= static_cast<uint64_t>(_src[i] & 0xFF) << auxp.bshift;
|
||||
target[i] += (target[i] << 8);
|
||||
}
|
||||
}
|
||||
|
||||
void pixel_format_rgb32::set_palette(pixel_format_aux_palette<false>& 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<true>& 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;
|
|
@ -1,4 +1,4 @@
|
|||
#include "core/png.hpp"
|
||||
#include "library/png.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
182
src/library/utf8.cpp
Normal file
182
src/library/utf8.cpp
Normal file
|
@ -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<uint8_t>(str[i]), s) >= 0)
|
||||
r++;
|
||||
if(utf8_parse_byte(-1, s) >= 0)
|
||||
r++;
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef TEST_UTF8
|
||||
#include <iostream>
|
||||
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
|
|
@ -1,5 +1,5 @@
|
|||
#include "lua/internal.hpp"
|
||||
#include "core/render.hpp"
|
||||
#include "library/framebuffer.hpp"
|
||||
#include "lua/bitmap.hpp"
|
||||
#include <vector>
|
||||
|
||||
|
@ -58,10 +58,12 @@ namespace
|
|||
delete p;
|
||||
}
|
||||
|
||||
template<bool T> void composite_op(struct screen<T>& scr) throw()
|
||||
template<bool T> void composite_op(struct framebuffer<T>& 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<T>::element_t* rptr = scr.rowptr(y + r + scr.originy);
|
||||
size_t eptr = x + xmin + scr.originx;
|
||||
typename framebuffer<T>::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<false>& x) throw() { composite_op(x); }
|
||||
void operator()(struct screen<true>& x) throw() { composite_op(x); }
|
||||
void operator()(struct framebuffer<false>& x) throw() { composite_op(x); }
|
||||
void operator()(struct framebuffer<true>& x) throw() { composite_op(x); }
|
||||
private:
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
|
|
@ -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<bool X> void op(struct screen<X>& scr) throw()
|
||||
template<bool X> void op(struct framebuffer<X>& 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<X>::element_t* rptr = scr.rowptr(y + r + scr.originy);
|
||||
size_t eptr = x + xmin + scr.originx;
|
||||
typename framebuffer<X>::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<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct screen<false>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<false>& scr) throw() { op(scr); }
|
||||
private:
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
|
|
@ -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<bool X> void op(struct screen<X>& scr) throw()
|
||||
template<bool X> void op(struct framebuffer<X>& 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<int64_t>(r) * r;
|
||||
typename screen<X>::element_t* rptr = scr.rowptr(y + r + scr.originy);
|
||||
size_t eptr = x + xmin + scr.originx;
|
||||
typename framebuffer<X>::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<int64_t>(c) * c;
|
||||
if(fd2 > radius2)
|
||||
|
@ -43,8 +45,8 @@ namespace
|
|||
}
|
||||
}
|
||||
}
|
||||
void operator()(struct screen<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct screen<false>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<false>& scr) throw() { op(scr); }
|
||||
private:
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
|
|
@ -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<bool X> void op(struct screen<X>& scr) throw()
|
||||
template<bool X> void op(struct framebuffer<X>& 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<int32_t>(length);
|
||||
int32_t xmax = static_cast<int32_t>(length + 1);
|
||||
int32_t ymin = -static_cast<int32_t>(length);
|
||||
int32_t ymax = static_cast<int32_t>(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<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct screen<false>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<false>& scr) throw() { op(scr); }
|
||||
private:
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
|
|
@ -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<bool X> void op(struct screen<X>& scr) throw()
|
||||
template<bool X> void op(struct framebuffer<X>& 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<uint32_t>(x) >= scr.width)
|
||||
for(int32_t x = _x1; x <= _x2; x++) {
|
||||
if(x < 0 || static_cast<uint32_t>(x) >= swidth)
|
||||
goto nodraw1;
|
||||
if(y < 0 || static_cast<uint32_t>(y) >= scr.height)
|
||||
if(y < 0 || static_cast<uint32_t>(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<uint32_t>(x) >= scr.width)
|
||||
for(int32_t y = _y1; y <= _y2; y++) {
|
||||
if(x < 0 || static_cast<uint32_t>(x) >= swidth)
|
||||
goto nodraw2;
|
||||
if(y < 0 || static_cast<uint32_t>(y) >= scr.height)
|
||||
if(y < 0 || static_cast<uint32_t>(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<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct screen<false>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<false>& scr) throw() { op(scr); }
|
||||
private:
|
||||
int32_t x1;
|
||||
int32_t y1;
|
||||
|
|
|
@ -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<bool X> void op(struct screen<X>& scr) throw()
|
||||
template<bool X> void op(struct framebuffer<X>& scr) throw()
|
||||
{
|
||||
color.set_palette(scr);
|
||||
int32_t _x = x + scr.originx;
|
||||
int32_t _y = y + scr.originy;
|
||||
if(_x < 0 || static_cast<uint32_t>(_x) >= scr.width)
|
||||
int32_t _x = x + scr.get_origin_x();
|
||||
int32_t _y = y + scr.get_origin_y();
|
||||
if(_x < 0 || static_cast<uint32_t>(_x) >= scr.get_width())
|
||||
return;
|
||||
if(_y < 0 || static_cast<uint32_t>(_y) >= scr.height)
|
||||
if(_y < 0 || static_cast<uint32_t>(_y) >= scr.get_height())
|
||||
return;
|
||||
color.apply(scr.rowptr(_y)[_x]);
|
||||
}
|
||||
void operator()(struct screen<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct screen<false>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<false>& scr) throw() { op(scr); }
|
||||
private:
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
|
|
@ -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<bool X> void op(struct screen<X>& scr) throw()
|
||||
template<bool X> void op(struct framebuffer<X>& 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<X>::element_t* rptr = scr.rowptr(y + r + scr.originy);
|
||||
size_t eptr = x + xmin + scr.originx;
|
||||
typename framebuffer<X>::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<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct screen<false>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<false>& scr) throw() { op(scr); }
|
||||
private:
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
|
|
@ -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<bool X> void op(struct screen<X>& scr) throw()
|
||||
template<bool X> void op(struct framebuffer<X>& 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<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct screen<false>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<true>& scr) throw() { op(scr); }
|
||||
void operator()(struct framebuffer<false>& scr) throw() { op(scr); }
|
||||
private:
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
|
|
@ -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 <cstring>
|
||||
#include <cstdlib>
|
||||
|
|
|
@ -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 <vector>
|
||||
#include <iostream>
|
||||
|
|
|
@ -586,16 +586,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);
|
||||
|
@ -605,13 +605,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<unsigned char*>(main_screen.memory);
|
||||
srcp[0] = reinterpret_cast<unsigned char*>(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;
|
||||
|
|
|
@ -35,7 +35,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) {
|
||||
|
|
|
@ -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<false> dscr;
|
||||
framebuffer<false> dscr;
|
||||
unsigned dcounter;
|
||||
bool have_dumped_frame;
|
||||
std::pair<uint32_t, uint32_t> soundrate;
|
||||
|
|
|
@ -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<false> dscr;
|
||||
framebuffer<false> dscr;
|
||||
unsigned dcounter;
|
||||
bool have_dumped_frame;
|
||||
uint64_t audio_w;
|
||||
|
|
|
@ -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<unsigned char*>(&magic))[swap ? 2 : 0];
|
||||
unsigned g = (reinterpret_cast<unsigned char*>(&magic))[1];
|
||||
unsigned b = (reinterpret_cast<unsigned char*>(&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<char*>(dscr2.rowptr(i)), 8 * dscr2.width);
|
||||
for(size_t i = 0; i < h; i++)
|
||||
video->write(reinterpret_cast<char*>(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<char*>(dscr.rowptr(i)), 4 * dscr.width);
|
||||
for(size_t i = 0; i < h; i++)
|
||||
video->write(reinterpret_cast<char*>(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<false> dscr;
|
||||
struct screen<true> dscr2;
|
||||
struct framebuffer<false> dscr;
|
||||
struct framebuffer<true> dscr2;
|
||||
bool swap;
|
||||
bool bits64;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue