Merge the new framebuffer code

This commit is contained in:
Ilari Liusvaara 2012-06-30 21:27:49 +03:00
commit 9289d22b3e
50 changed files with 2511 additions and 1306 deletions

View file

@ -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

View file

@ -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.
*

View file

@ -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;

View file

@ -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.
*/

View file

@ -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

View file

@ -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>

View 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

View 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

View 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

View 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

View 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

View 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

View file

@ -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
View 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

View file

@ -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
{

View file

@ -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;

View file

@ -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)());

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -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
View 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
View 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();

View 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;

View 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;

View 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;

View 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;

View 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;

View file

@ -1,4 +1,4 @@
#include "core/png.hpp"
#include "library/png.hpp"
#include <fstream>
#include <iostream>

182
src/library/utf8.cpp Normal file
View 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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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>

View file

@ -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>

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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;
};