C interface: render_text (version bump to v2)
Bump C interface version to 2, in order to add render_text (render text to bitmap, using system font
This commit is contained in:
parent
1dd52cc68b
commit
0f51ad0b16
2 changed files with 117 additions and 1 deletions
|
@ -198,6 +198,34 @@ struct lsnes_core_disassembler
|
|||
const char* (*fn)(uint64_t base, unsigned char(*fetch)(void* ctx), void* ctx);
|
||||
};
|
||||
|
||||
//Font rendering request.
|
||||
struct lsnes_core_fontrender_req
|
||||
{
|
||||
//Input: Context to pass to callbacks.
|
||||
void* cb_ctx;
|
||||
//Input: Allocate bitmap memory.
|
||||
//cb_ctx => cb_ctx from above.
|
||||
//mem_size => Number of bytes needed to allocate.
|
||||
//return buffer at least mem_size bytes. Or return NULL on error.
|
||||
void* (*alloc)(void* cb_ctx, size_t mem_size);
|
||||
//Input: Text to render (UTF-8).
|
||||
const char* text;
|
||||
//Input: Length of text in bytes. If negative, text is null-terminated.
|
||||
long text_len;
|
||||
//Input: Bytes per pixel to request. Can be 1, 2, 3 or 4.
|
||||
unsigned bytes_pp;
|
||||
//Input: Foreground color (native endian).
|
||||
unsigned fg_color;
|
||||
//Input: Background color (native endian).
|
||||
unsigned bg_color;
|
||||
//Output: The allocated bitmap (this comes from ->alloc). Not released on failure.
|
||||
void* bitmap;
|
||||
//Output: Width of the bitmap.
|
||||
size_t width;
|
||||
//Output: Height of the bitmap.
|
||||
size_t height;
|
||||
};
|
||||
|
||||
//Request 0: Initialize and enumerate cores.
|
||||
//Item: 0.
|
||||
//Default action: (required)
|
||||
|
@ -243,6 +271,8 @@ struct lsnes_core_enumerate_cores
|
|||
void* (*add_disasm)(struct lsnes_core_disassembler* disasm);
|
||||
//Input: Remove disassembler. Only available if emu_flags1>=1.
|
||||
void (*remove_disasm)(void* handle);
|
||||
//Input: Render text into bitmap. Returns 0 on success, -1 on failure. Only available if emu_flags>=2.
|
||||
int (*render_text)(struct lsnes_core_fontrender_req* req);
|
||||
};
|
||||
|
||||
//Request 1: Request information about core.
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "library/framebuffer-pixfmt-rgb24.hpp"
|
||||
#include "library/framebuffer-pixfmt-rgb32.hpp"
|
||||
#include "library/framebuffer-pixfmt-lrgb.hpp"
|
||||
#include "fonts/wrapper.hpp"
|
||||
#include "core/audioapi.hpp"
|
||||
#include "core/instance.hpp"
|
||||
#include "core/messages.hpp"
|
||||
|
@ -916,6 +917,90 @@ failed:
|
|||
delete reinterpret_cast<ccore_disasm*>(handle);
|
||||
}
|
||||
|
||||
struct utf8_strlen_iter
|
||||
{
|
||||
utf8_strlen_iter() { str_len = 0; }
|
||||
utf8_strlen_iter& operator++() { str_len++; return *this; }
|
||||
uint32_t& operator*() { return dummy; }
|
||||
size_t str_len;
|
||||
uint32_t dummy;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void callback_render_text2(struct lsnes_core_fontrender_req& req, const std::string& str)
|
||||
{
|
||||
auto size = main_font.get_metrics(str);
|
||||
auto layout = main_font.dolayout(str);
|
||||
size_t memreq = size.first * size.second * sizeof(T);
|
||||
if(!memreq) memreq = 1;
|
||||
if(size.first && memreq / size.first / sizeof(T) < size.second)
|
||||
throw std::bad_alloc(); //Not enough memory.
|
||||
req.bitmap = req.alloc(req.cb_ctx, memreq);
|
||||
if(!req.bitmap)
|
||||
throw std::bad_alloc(); //Not enough memory.
|
||||
T fg = (T)req.fg_color;
|
||||
T bg = (T)req.bg_color;
|
||||
T* bmp = (T*)req.bitmap;
|
||||
|
||||
for(auto i : layout) {
|
||||
auto& g = *i.dglyph;
|
||||
T* _bmp = bmp + (i.y * size.first + i.x);
|
||||
size_t w = g.wide ? 16 : 8;
|
||||
size_t skip = size.first - w;
|
||||
for(size_t _y = 0; _y < 16; _y++) {
|
||||
uint32_t d = g.data[_y >> (g.wide ? 1 : 2)];
|
||||
if(g.wide)
|
||||
d >>= 16 - ((_y & 1) << 4);
|
||||
else
|
||||
d >>= 24 - ((_y & 3) << 3);
|
||||
for(size_t _x = 0; _x < w; _x++, _bmp++) {
|
||||
uint32_t b = w - _x - 1;
|
||||
*_bmp = ((d >> b) & 1) ? fg : bg;
|
||||
}
|
||||
_bmp = _bmp + skip;
|
||||
}
|
||||
}
|
||||
req.width = size.first;
|
||||
req.height = size.second;
|
||||
}
|
||||
|
||||
void callback_render_text1(struct lsnes_core_fontrender_req& req, const std::string& str)
|
||||
{
|
||||
switch(req.bytes_pp) {
|
||||
case 1:
|
||||
callback_render_text2<uint8_t>(req, str);
|
||||
return;
|
||||
case 2:
|
||||
callback_render_text2<uint16_t>(req, str);
|
||||
return;
|
||||
case 3:
|
||||
callback_render_text2<ss_uint24_t>(req, str);
|
||||
return;
|
||||
case 4:
|
||||
callback_render_text2<uint32_t>(req, str);
|
||||
return;
|
||||
default:
|
||||
throw std::runtime_error("Invalid req.bytes_pp");
|
||||
}
|
||||
}
|
||||
|
||||
int callback_render_text(struct lsnes_core_fontrender_req* req)
|
||||
{
|
||||
req->bitmap = NULL;
|
||||
//If indeterminate length, make it determinate.
|
||||
if(req->text_len < 0)
|
||||
req->text_len = strlen(req->text);
|
||||
const char* text_start = req->text;
|
||||
const char* text_end = req->text + req->text_len;
|
||||
try {
|
||||
std::string str(text_start, text_end);
|
||||
callback_render_text1(*req, str);
|
||||
return 0;
|
||||
} catch(...) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
core_sysregion* create_sysregion(entrypoint_fn& entrypoint, std::map<unsigned, core_region*>& regions,
|
||||
std::map<unsigned, c_core_type*>& types, unsigned sysreg)
|
||||
{
|
||||
|
@ -1085,7 +1170,7 @@ no_parameters:
|
|||
//Enumerate what the thing supports.
|
||||
entrypoint_fn entrypoint(fn);
|
||||
lsnes_core_enumerate_cores r;
|
||||
r.emu_flags1 = 1;
|
||||
r.emu_flags1 = 2;
|
||||
r.message = callback_message;
|
||||
r.get_input = callback_get_input;
|
||||
r.notify_action_update = callback_notify_action_update;
|
||||
|
@ -1103,6 +1188,7 @@ no_parameters:
|
|||
r.submit_frame = callback_submit_frame;
|
||||
r.add_disasm = callback_add_disasm;
|
||||
r.remove_disasm = callback_remove_disasm;
|
||||
r.render_text = callback_render_text;
|
||||
entrypoint(0, r, [](const char* name, const char* err) {
|
||||
(stringfmt() << "LSNES_CORE_ENUMERATE_CORES(0) failed: " << err).throwex();
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue