Lua Bitmap WIP

This commit is contained in:
Ilari Liusvaara 2012-03-03 11:27:26 +02:00
parent 0514dd989e
commit d8319ef4a9
5 changed files with 748 additions and 7 deletions

41
include/lua/bitmap.hpp Normal file
View file

@ -0,0 +1,41 @@
#ifndef _lua__bitmap__hpp__included__
#define _lua__bitmap__hpp__included__
#include <vector>
#include <string>
#include <cstdint>
#include "core/render.hpp"
struct lua_bitmap
{
lua_bitmap(uint32_t w, uint32_t h);
size_t width;
size_t height;
std::vector<uint16_t> pixels;
};
struct lua_dbitmap
{
lua_dbitmap(uint32_t w, uint32_t h);
size_t width;
size_t height;
std::vector<premultiplied_color> pixels;
};
struct lua_palette
{
std::vector<premultiplied_color> colors;
};
struct lua_loaded_bitmap
{
size_t w;
size_t h;
bool d;
std::vector<int64_t> bitmap;
std::vector<int64_t> palette;
static struct lua_loaded_bitmap load(const std::string& name);
};
#endif

View file

@ -2346,6 +2346,229 @@ border: Border color (default is 0xFFFFFF (white))
fill: Fill color (default is -1 (transparent)).
\end_layout
\begin_layout Subsubsection
gui.bitmap_draw(number x, number y, bitmap bitmap, palette palette)
\end_layout
\begin_layout Standard
Draw a bitmap on screen with specified palette.
Parameters:
\end_layout
\begin_layout Itemize
x: X-coordinate of left edge.
\end_layout
\begin_layout Itemize
y: Y-coordinate of top edge.
\end_layout
\begin_layout Itemize
bitmap: The bitmap to draw
\end_layout
\begin_layout Itemize
palette: The palette to draw the bitmap using.
\end_layout
\begin_layout Subsubsection
gui.bitmap_draw(number x, number y, dbitmap bitmap)
\end_layout
\begin_layout Standard
Draw a bitmap on screen.
Parameters:
\end_layout
\begin_layout Itemize
x: X-coordinate of left edge.
\end_layout
\begin_layout Itemize
y: Y-coordinate of top edge.
\end_layout
\begin_layout Itemize
bitmap: The bitmap to draw
\end_layout
\begin_layout Subsubsection
gui.palette_new()
\end_layout
\begin_layout Standard
Returns a new palette (initially all transparent).
Can be used anywhere.
\end_layout
\begin_layout Subsubsection
gui.bitmap_new(number w, number h, boolean direct)
\end_layout
\begin_layout Standard
Returns a new bitmap/dbitmap.
Can be used anywhere.
Parameters:
\end_layout
\begin_layout Itemize
w: The width of new bitmap
\end_layout
\begin_layout Itemize
h: The height of new bitmap
\end_layout
\begin_layout Itemize
direct: If true, the returned bitmap is dbitmap, otherwise bitmap.
\end_layout
\begin_layout Subsubsection
gui.bitmap_load(string file)
\end_layout
\begin_layout Standard
Returns loaded bitmap/dbitmap (if bitmap, the second return value is palette
for bitmap).
Can be used anywhere.
Parameters:
\end_layout
\begin_layout Itemize
file: The name of file to load.
\end_layout
\begin_layout Subsubsection
gui.palette_set(palette palette, number index, number color)
\end_layout
\begin_layout Standard
Sets color in palette.
Can be used anywhere.
Parameters:
\end_layout
\begin_layout Itemize
palette: The palette to manipulate
\end_layout
\begin_layout Itemize
index: Index of color (0-65535).
\end_layout
\begin_layout Itemize
color: The color value.
\end_layout
\begin_layout Subsubsection
gui.bitmap_pset(bitmap/dbitmap bitmap, number x, number y, number color)
\end_layout
\begin_layout Standard
Sets specified pixel in bitmap.
Can be used anywhere.
Parameters:
\end_layout
\begin_layout Itemize
bitmap: The bitmap to manipulate
\end_layout
\begin_layout Itemize
x: The x-coordinate of the pixel.
\end_layout
\begin_layout Itemize
y: The y-coordinate of the pixel.
\end_layout
\begin_layout Itemize
color: If bitmap is a bitmap, color index (0-65535).
Otherwise color value.
\end_layout
\begin_layout Subsubsection
gui.bitmap_size(bitmap/dbitmap bitmap)
\end_layout
\begin_layout Standard
Get size of bitmap.
Can be used anywhere.
Parameters:
\end_layout
\begin_layout Itemize
bitmap: The bitmap to query.
\end_layout
\begin_layout Standard
The first return is the width, the second is the height.
\end_layout
\begin_layout Subsubsection
gui.bitmap_blit(bitmap/dbitmap dest, number dx, number dy, bitmap/dbitmap
src, number sx, number sy, number w, number h[, number ck])
\end_layout
\begin_layout Standard
Blit a part of bitmap to another.
Can be used anywhere.
Parameters:
\end_layout
\begin_layout Itemize
dest: Destination to blit to.
\end_layout
\begin_layout Itemize
dx: left edge of target
\end_layout
\begin_layout Itemize
dy: Top edge of target
\end_layout
\begin_layout Itemize
src: The source to blit from.
Must be of the same type as destination.
\end_layout
\begin_layout Itemize
sx: left edge of source
\end_layout
\begin_layout Itemize
sy: Top edge of source
\end_layout
\begin_layout Itemize
w: Width of region
\end_layout
\begin_layout Itemize
h: Height of region.
\end_layout
\begin_layout Itemize
ck: Color key.
Pixels of this color are not blitted.
\end_layout
\begin_deeper
\begin_layout Itemize
If bitmaps are bitmaps, this is color index of colorkey.
Values outside range 0-65535 cause no key to be used as colorkey.
\end_layout
\begin_layout Itemize
If bitmaps are dbitmaps, this color value of colorkey.
\end_layout
\begin_layout Itemize
May be absent or nil for no colorkey blit.
\end_layout
\end_deeper
\begin_layout Subsubsection
gui.repaint()
\end_layout

View file

@ -1150,29 +1150,142 @@ Draw a circle. Parameters.
• fill: Fill color (default is -1 (transparent)).
8.3.12 gui.repaint()
8.3.12 gui.bitmap_draw(number x, number y, bitmap bitmap, palette
palette)
Draw a bitmap on screen with specified palette. Parameters:
• x: X-coordinate of left edge.
• y: Y-coordinate of top edge.
• bitmap: The bitmap to draw
• palette: The palette to draw the bitmap using.
8.3.13 gui.bitmap_draw(number x, number y, dbitmap bitmap)
Draw a bitmap on screen. Parameters:
• x: X-coordinate of left edge.
• y: Y-coordinate of top edge.
• bitmap: The bitmap to draw
8.3.14 gui.palette_new()
Returns a new palette (initially all transparent). Can be used
anywhere.
8.3.15 gui.bitmap_new(number w, number h, boolean direct)
Returns a new bitmap/dbitmap. Can be used anywhere. Parameters:
• w: The width of new bitmap
• h: The height of new bitmap
• direct: If true, the returned bitmap is dbitmap, otherwise
bitmap.
8.3.16 gui.bitmap_load(string file)
Returns loaded bitmap/dbitmap (if bitmap, the second return value
is palette for bitmap). Can be used anywhere. Parameters:
• file: The name of file to load.
8.3.17 gui.palette_set(palette palette, number index, number
color)
Sets color in palette. Can be used anywhere. Parameters:
• palette: The palette to manipulate
• index: Index of color (0-65535).
• color: The color value.
8.3.18 gui.bitmap_pset(bitmap/dbitmap bitmap, number x, number y,
number color)
Sets specified pixel in bitmap. Can be used anywhere. Parameters:
• bitmap: The bitmap to manipulate
• x: The x-coordinate of the pixel.
• y: The y-coordinate of the pixel.
• color: If bitmap is a bitmap, color index (0-65535). Otherwise
color value.
8.3.19 gui.bitmap_size(bitmap/dbitmap bitmap)
Get size of bitmap. Can be used anywhere. Parameters:
• bitmap: The bitmap to query.
The first return is the width, the second is the height.
8.3.20 gui.bitmap_blit(bitmap/dbitmap dest, number dx, number dy,
bitmap/dbitmap src, number sx, number sy, number w, number h[,
number ck])
Blit a part of bitmap to another. Can be used anywhere.
Parameters:
• dest: Destination to blit to.
• dx: left edge of target
• dy: Top edge of target
• src: The source to blit from. Must be of the same type as
destination.
• sx: left edge of source
• sy: Top edge of source
• w: Width of region
• h: Height of region.
• ck: Color key. Pixels of this color are not blitted.
If bitmaps are bitmaps, this is color index of colorkey.
Values outside range 0-65535 cause no key to be used as
colorkey.
If bitmaps are dbitmaps, this color value of colorkey.
May be absent or nil for no colorkey blit.
8.3.21 gui.repaint()
Request on_repaint() to happen as soon as possible. Can be used
anywhere.
8.3.13 gui.subframe_update(boolean on)
8.3.22 gui.subframe_update(boolean on)
Request subframe updates (calling on_paint() on subframes) to
happen (on=true) or not happen (on=false). Can be used anywhere.
8.3.14 gui.screenshot(string filename)
8.3.23 gui.screenshot(string filename)
Write PNG screenshot of the current frame (no drawings) to
specified file. Can be used anywhere.
8.3.15 gui.color(number r, number g, number b[, number a])
8.3.24 gui.color(number r, number g, number b[, number a])
Returns color (in notation Lua scripts use) corresponding to
color (r,g,b), each component in scale 0-255. If a is specified,
that is alpha (0 is fully transparent, 256(sic) is fully opaque).
The default alpha is 256.
8.3.16 gui.status(string name, string value)
8.3.25 gui.status(string name, string value)
Set status field “L[<name>]” to <value> in status area. Can be
used anywhere.
@ -2662,7 +2775,8 @@ set-axis joystick0axis19 disabled
• Try to autodetect if ROM is headered.
• Only bring up ROM patching screen if specifically requested.
• Wxwidgets: Only bring up ROM patching screen if specifically
requested.
• Allow configuring some (200+) hotkeys.
• Allow configuring some hotkeys.

283
src/lua/gui-bitmap.cpp Normal file
View file

@ -0,0 +1,283 @@
#include "core/lua-int.hpp"
#include "core/render.hpp"
#include "lua/bitmap.hpp"
#include <vector>
lua_bitmap::lua_bitmap(uint32_t w, uint32_t h)
{
width = w;
height = h;
pixels.resize(width * height);
memset(&pixels[0], 0, width * height);
}
lua_dbitmap::lua_dbitmap(uint32_t w, uint32_t h)
{
width = w;
height = h;
pixels.resize(width * height);
}
namespace
{
struct render_object_bitmap : public render_object
{
render_object_bitmap(int32_t _x, int32_t _y, lua_obj_pin<lua_bitmap>* _bitmap,
lua_obj_pin<lua_palette>* _palette) throw()
{
x = _x;
y = _y;
b = _bitmap;
b2 = NULL;
p = _palette;
}
render_object_bitmap(int32_t _x, int32_t _y, lua_obj_pin<lua_dbitmap>* _bitmap) throw()
{
x = _x;
y = _y;
b = NULL;
b2 = _bitmap;
p = NULL;
}
~render_object_bitmap() throw()
{
delete b;
delete b2;
delete p;
}
void operator()(struct screen& scr) throw()
{
size_t pallim = 0;
size_t w, h;
premultiplied_color* palette;
if(b) {
palette = &p->object()->colors[0];
for(auto& c : p->object()->colors)
c.set_palette(scr);
pallim = p->object()->colors.size();
w = b->object()->width;
h = b->object()->height;
} else {
for(auto& c : b2->object()->pixels)
c.set_palette(scr);
w = b2->object()->width;
h = b2->object()->height;
}
int32_t xmin = 0;
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);
for(int32_t r = ymin; r < ymax; r++) {
uint32_t* rptr = scr.rowptr(y + r + scr.originy);
size_t eptr = x + xmin + scr.originx;
if(b)
for(int32_t c = xmin; c < xmax; c++, eptr++) {
uint16_t i = b->object()->pixels[r * b->object()->width + c];
if(i < pallim)
palette[i].apply(rptr[eptr]);
}
else
for(int32_t c = xmin; c < xmax; c++, eptr++)
b2->object()->pixels[r * b2->object()->width + c].apply(rptr[eptr]);
}
}
private:
int32_t x;
int32_t y;
lua_obj_pin<lua_bitmap>* b;
lua_obj_pin<lua_dbitmap>* b2;
lua_obj_pin<lua_palette>* p;
};
function_ptr_luafun gui_bitmap("gui.bitmap_draw", [](lua_State* LS, const std::string& fname) -> int {
if(!lua_render_ctx)
return 0;
int32_t x = get_numeric_argument<int32_t>(LS, 1, fname.c_str());
int32_t y = get_numeric_argument<int32_t>(LS, 2, fname.c_str());
if(lua_class<lua_bitmap>::is(LS, 3)) {
lua_class<lua_bitmap>::get(LS, 3, fname.c_str());
lua_class<lua_palette>::get(LS, 4, fname.c_str());
auto b = lua_class<lua_bitmap>::pin(LS, 3, fname.c_str());
auto p = lua_class<lua_palette>::pin(LS, 4, fname.c_str());
lua_render_ctx->queue->add(*new render_object_bitmap(x, y, b, p));
} else if(lua_class<lua_dbitmap>::is(LS, 3)) {
lua_class<lua_dbitmap>::get(LS, 3, fname.c_str());
auto b = lua_class<lua_dbitmap>::pin(LS, 3, fname.c_str());
lua_render_ctx->queue->add(*new render_object_bitmap(x, y, b));
} else {
lua_pushstring(LS, "Expected BITMAP or DBITMAP as argument 3 for gui.bitmap_draw.");
lua_error(LS);
}
return 0;
});
function_ptr_luafun gui_cpalette("gui.palette_new", [](lua_State* LS, const std::string& fname) -> int {
lua_class<lua_palette>::create(LS);
return 1;
});
function_ptr_luafun gui_cbitmap("gui.bitmap_new", [](lua_State* LS, const std::string& fname) -> int {
uint32_t w = get_numeric_argument<uint32_t>(LS, 1, fname.c_str());
uint32_t h = get_numeric_argument<uint32_t>(LS, 2, fname.c_str());
bool d = get_boolean_argument(LS, 3, fname.c_str());
if(d)
lua_class<lua_dbitmap>::create(LS, w, h);
else
lua_class<lua_bitmap>::create(LS, w, h);
return 1;
});
function_ptr_luafun gui_epalette("gui.palette_set", [](lua_State* LS, const std::string& fname) -> int {
lua_palette* p = lua_class<lua_palette>::get(LS, 1, fname.c_str());
uint16_t c = get_numeric_argument<uint16_t>(LS, 2, fname.c_str());
int64_t nval = get_numeric_argument<int64_t>(LS, 3, fname.c_str());
premultiplied_color nc(nval);
if(p->colors.size() <= c);
p->colors.resize(static_cast<uint32_t>(c) + 1);
p->colors[c] = nc;
return 0;
});
function_ptr_luafun pset_bitmap("gui.bitmap_pset", [](lua_State* LS, const std::string& fname) -> int {
uint32_t x = get_numeric_argument<uint32_t>(LS, 2, fname.c_str());
uint32_t y = get_numeric_argument<uint32_t>(LS, 3, fname.c_str());
if(lua_class<lua_bitmap>::is(LS, 1)) {
lua_bitmap* b = lua_class<lua_bitmap>::get(LS, 1, fname.c_str());
uint16_t c = get_numeric_argument<uint16_t>(LS, 4, fname.c_str());
if(x >= b->width || y >= b->height)
return 0;
b->pixels[y * b->width + x] = c;
} else if(lua_class<lua_dbitmap>::is(LS, 1)) {
lua_dbitmap* b = lua_class<lua_dbitmap>::get(LS, 1, fname.c_str());
int64_t c = get_numeric_argument<int64_t>(LS, 4, fname.c_str());
if(x >= b->width || y >= b->height)
return 0;
b->pixels[y * b->width + x] = premultiplied_color(c);
} else {
lua_pushstring(LS, "Expected BITMAP or DBITMAP as argument 1 for gui.bitmap_pset.");
lua_error(LS);
}
return 0;
});
function_ptr_luafun size_bitmap("gui.bitmap_size", [](lua_State* LS, const std::string& fname) -> int {
if(lua_class<lua_bitmap>::is(LS, 1)) {
lua_bitmap* b = lua_class<lua_bitmap>::get(LS, 1, fname.c_str());
lua_pushnumber(LS, b->width);
lua_pushnumber(LS, b->height);
} else if(lua_class<lua_dbitmap>::is(LS, 1)) {
lua_dbitmap* b = lua_class<lua_dbitmap>::get(LS, 1, fname.c_str());
lua_pushnumber(LS, b->width);
lua_pushnumber(LS, b->height);
} else {
lua_pushstring(LS, "Expected BITMAP or DBITMAP as argument 1 for gui.bitmap_size.");
lua_error(LS);
}
return 2;
});
function_ptr_luafun blit_bitmap("gui.bitmap_blit", [](lua_State* LS, const std::string& fname) -> int {
uint32_t dx = get_numeric_argument<uint32_t>(LS, 2, fname.c_str());
uint32_t dy = get_numeric_argument<uint32_t>(LS, 3, fname.c_str());
uint32_t sx = get_numeric_argument<uint32_t>(LS, 5, fname.c_str());
uint32_t sy = get_numeric_argument<uint32_t>(LS, 6, fname.c_str());
uint32_t w = get_numeric_argument<uint32_t>(LS, 7, fname.c_str());
uint32_t h = get_numeric_argument<uint32_t>(LS, 8, fname.c_str());
int64_t ck = 0x100000000ULL;
get_numeric_argument<int64_t>(LS, 9, ck, fname.c_str());
bool nck = false;
premultiplied_color pck(ck);
uint32_t ckorig = pck.orig;
uint16_t ckoriga = pck.origa;
if(ck == 0x100000000ULL)
nck = true;
if(lua_class<lua_bitmap>::is(LS, 1) && lua_class<lua_bitmap>::is(LS, 4)) {
lua_bitmap* db = lua_class<lua_bitmap>::get(LS, 1, fname.c_str());
lua_bitmap* sb = lua_class<lua_bitmap>::get(LS, 4, fname.c_str());
while((dx + w > db->width || sx + w > sb->width) && w > 0)
w--;
while((dy + h > db->height || sy + h > sb->height) && h > 0)
h--;
size_t sidx = sy * sb->width + sx;
size_t didx = dy * db->width + dx;
size_t srskip = sb->width - w;
size_t drskip = db->width - w;
for(uint32_t j = 0; j < h; j++) {
for(uint32_t i = 0; i < w; i++) {
uint16_t pix = sb->pixels[sidx];
if(pix != ck) //No need to check nck, as that value is out of range.
db->pixels[didx] = pix;
sidx++;
didx++;
}
sidx += srskip;
didx += drskip;
}
} else if(lua_class<lua_dbitmap>::is(LS, 1) && lua_class<lua_dbitmap>::is(LS, 1)) {
lua_dbitmap* db = lua_class<lua_dbitmap>::get(LS, 1, fname.c_str());
lua_dbitmap* sb = lua_class<lua_dbitmap>::get(LS, 4, fname.c_str());
while((dx + w > db->width || sx + w > sb->width) && w > 0)
w--;
while((dy + h > db->height || sy + h > sb->height) && h > 0)
h--;
size_t sidx = sy * sb->width + sx;
size_t didx = dy * db->width + dx;
size_t srskip = sb->width - w;
size_t drskip = db->width - w;
for(uint32_t j = 0; j < h; j++) {
for(uint32_t i = 0; i < w; i++) {
premultiplied_color pix = sb->pixels[sidx];
if(pix.orig != ckorig || pix.origa != ckoriga || nck)
db->pixels[didx] = pix;
sidx++;
didx++;
}
sidx += srskip;
didx += drskip;
}
} else {
lua_pushstring(LS, "Expected BITMAP or DBITMAP as arguments 1&4 for gui.bitmap_pset.");
lua_error(LS);
}
return 0;
});
function_ptr_luafun gui_loadbitmap("gui.bitmap_load", [](lua_State* LS, const std::string& fname) -> int {
std::string name = get_string_argument(LS, 1, fname.c_str());
uint32_t w, h;
auto bitmap = lua_loaded_bitmap::load(name);
if(bitmap.d) {
lua_dbitmap* b = lua_class<lua_dbitmap>::create(LS, bitmap.w, bitmap.h);
for(size_t i = 0; i < bitmap.w * bitmap.h; i++)
b->pixels[i] = premultiplied_color(bitmap.bitmap[i]);
return 1;
} else {
lua_bitmap* b = lua_class<lua_bitmap>::create(LS, bitmap.w, bitmap.h);
lua_palette* p = lua_class<lua_palette>::create(LS);
for(size_t i = 0; i < bitmap.w * bitmap.h; i++)
b->pixels[i] = bitmap.bitmap[i];
p->colors.resize(bitmap.palette.size());
for(size_t i = 0; i < bitmap.palette.size(); i++)
p->colors[i] = premultiplied_color(bitmap.palette[i]);
return 2;
}
});
function_ptr_luafun gui_dpalette("gui.palette_debug", [](lua_State* LS, const std::string& fname) -> int {
lua_palette* p = lua_class<lua_palette>::get(LS, 1, fname.c_str());
size_t i = 0;
for(auto c : p->colors)
messages << "Color #" << (i++) << ": " << c.orig << ":" << c.origa << std::endl;
return 0;
});
}
DECLARE_LUACLASS(lua_palette, "PALETTE");
DECLARE_LUACLASS(lua_bitmap, "BITMAP");
DECLARE_LUACLASS(lua_dbitmap, "DBITMAP");

80
src/lua/loadbitmap.cpp Normal file
View file

@ -0,0 +1,80 @@
#include "lua/bitmap.hpp"
#include "library/zip.hpp"
#include <limits>
namespace
{
inline uint64_t tocolor(unsigned r, unsigned g, unsigned b, unsigned a)
{
if(!a)
return -1;
else
return (static_cast<int64_t>(256 - a) << 24) | (static_cast<int64_t>(r) << 16) |
(static_cast<int64_t>(g) << 8) | static_cast<int64_t>(b);
}
}
struct lua_loaded_bitmap lua_loaded_bitmap::load(const std::string& name)
{
struct lua_loaded_bitmap b;
std::istream* file = NULL;
try {
std::string magic;
unsigned pcolors;
unsigned R;
unsigned G;
unsigned B;
unsigned A;
file = &open_file_relative(name, "");
*file >> magic;
if(magic != "LSNES-BITMAP")
throw std::runtime_error("Bitmap load: Wrong magic");
*file >> b.w;
*file >> b.h;
if(b.h >= std::numeric_limits<size_t>::max() / b.w)
throw std::runtime_error("Bitmap load: Bitmap too large");
b.bitmap.resize(b.w * b.h);
*file >> pcolors;
if(pcolors > 65536)
throw std::runtime_error("Bitmap load: Palette too big");
if(pcolors > 0) {
//Paletted.
b.d = false;
b.palette.resize(pcolors);
for(size_t i = 0; i < pcolors; i++) {
*file >> R;
*file >> G;
*file >> B;
*file >> A;
if(R > 255 || G > 255 || B > 255 || A > 256) //Yes, a can be 256.
throw std::runtime_error("Bitmap load: Palette entry out of range");
b.palette[i] = tocolor(R, G, B, A);
}
for(size_t i = 0; i < b.w * b.h; i++) {
*file >> R;
if(R >= pcolors)
throw std::runtime_error("Bitmap load: color index out of range");
b.bitmap[i] = R;
}
} else {
//Direct.
b.d = true;
for(size_t i = 0; i < b.w * b.h; i++) {
*file >> R;
*file >> G;
*file >> B;
*file >> A;
if(R > 255 || G > 255 || B > 255 || A > 256) //Yes, a can be 256.
throw std::runtime_error("Bitmap load: Color out of range");
b.bitmap[i] = tocolor(R, G, B, A);
}
}
if(!*file)
throw std::runtime_error("Bitmap load: Error reading bitmap");
} catch(...) {
delete file;
throw;
}
delete file;
return b;
}