Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions src/core/scripting.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#include <mgba/core/serialize.h>
#ifdef M_CORE_GBA
#include <mgba/gba/interface.h>
#include <mgba/internal/gba/gba.h>
#endif
#ifdef M_CORE_GB
#include <mgba/internal/gb/gb.h>
#endif
#include <mgba/script/base.h>
#include <mgba/script/context.h>
Expand Down Expand Up @@ -411,6 +415,75 @@ static void _mScriptCoreWriteRegister(struct mCore* core, const char* regName, i
core->writeRegister(core, regName, &in);
}

static uint16_t _mScriptCoreReadPalette(struct mCore* core, uint32_t index) {
const uint16_t* palette;
uint32_t count;

switch (core->platform(core)) {
#ifdef M_CORE_GBA
case mPLATFORM_GBA:
struct GBA* gba = (struct GBA*) core->board;
palette = gba->video.palette;
count = 512;
break;
#endif
#ifdef M_CORE_GB
case mPLATFORM_GB:
struct GB* gb = (struct GB*) core->board;
palette = gb->video.palette;
count = 64;
break;
#endif
default:
return 0x8000;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the logic behind returning 0x8000 here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my knowledge and testing, the highest bit is ignored, so I figured it would make a good error marker since readPalette cannot return a nil anymore.

}

if (index >= count) {
return 0x8000;
}

uint16_t color;
LOAD_16LE(color, 2 * index, palette);

return color;
}

static void _mScriptCoreWritePalette(struct mCore* core, uint32_t index, uint16_t color) {
uint16_t* palette;
switch (core->platform(core)) {
#ifdef M_CORE_GBA
case mPLATFORM_GBA:
if (index >= 512) {
return;
}
struct GBA* gba = (struct GBA*) core->board;
palette = gba->video.palette;

STORE_16LE(color, 2 * index, palette);

struct GBAVideoRenderer* gbaRenderer = gba->video.renderer;
gbaRenderer->writePalette(gbaRenderer, index, palette[index]);
break;
#endif
#ifdef M_CORE_GB
case mPLATFORM_GB:
if (index >= 64) {
return;
}
struct GB* gb = (struct GB*) core->board;
palette = gb->video.palette;

STORE_16LE(color, 2 * index, palette);

struct GBVideoRenderer* gbRenderer = gb->video.renderer;
gbRenderer->writePalette(gbRenderer, index, palette[index]);
break;
#endif
default:
break;
}
}

static struct mScriptValue* _mScriptCoreSaveState(struct mCore* core, int32_t flags) {
struct VFile* vf = VFileMemChunk(NULL, 0);
if (!mCoreSaveStateNamed(core, vf, flags)) {
Expand Down Expand Up @@ -532,6 +605,10 @@ mSCRIPT_DECLARE_STRUCT_VOID_D_METHOD(mCore, busWrite32, 2, U32, address, U32, va
mSCRIPT_DECLARE_STRUCT_METHOD(mCore, WRAPPER, readRegister, _mScriptCoreReadRegister, 1, CHARP, regName);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mCore, writeRegister, _mScriptCoreWriteRegister, 2, CHARP, regName, S32, value);

// Palette functions
mSCRIPT_DECLARE_STRUCT_METHOD(mCore, U16, readPalette, _mScriptCoreReadPalette, 1, U32, index);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mCore, writePalette, _mScriptCoreWritePalette, 2, U32, index, U16, color);

// Savestate functions
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, WSTR, saveStateBuffer, _mScriptCoreSaveState, 1, S32, flags);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, BOOL, loadStateBuffer, _mScriptCoreLoadState, 2, STR, buffer, S32, flags);
Expand Down Expand Up @@ -619,6 +696,11 @@ mSCRIPT_DEFINE_STRUCT(mCore)
mSCRIPT_DEFINE_DOCSTRING("Write the value of the register with the given name")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, writeRegister)

mSCRIPT_DEFINE_DOCSTRING("Read a 16-bit value encoding the RGB channels in 5 bits each from the given palette index (0-indexed). See util.unpackColor")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, readPalette)
mSCRIPT_DEFINE_DOCSTRING("Write a 16-bit value encoding the RGB channels in 5 bits each to the given palette index (0-indexed). See util.packColor")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, writePalette)

mSCRIPT_DEFINE_DOCSTRING("Save state and return as a buffer. See C.SAVESTATE for possible values for `flags`")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, saveStateBuffer)
mSCRIPT_DEFINE_DOCSTRING("Load state from a buffer. See C.SAVESTATE for possible values for `flags`")
Expand Down
75 changes: 75 additions & 0 deletions src/core/test/scripting.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "script/test.h"

#ifdef M_CORE_GBA
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/memory.h>
#define TEST_PLATFORM mPLATFORM_GBA
#define RAM_BASE GBA_BASE_IWRAM
Expand All @@ -25,6 +26,10 @@
#error "Need a valid platform for testing"
#endif

#ifdef M_CORE_GB
#include <mgba/internal/gb/gb.h>
#endif

struct mScriptTestLogger {
struct mLogger d;
char* log;
Expand Down Expand Up @@ -328,6 +333,74 @@ M_TEST_DEFINE(screenshot) {
TEARDOWN_CORE;
}

M_TEST_DEFINE(readPalette) {
SETUP_LUA;
CREATE_CORE;

uint16_t* palette = 0;

switch(core->platform(core)) {
#ifdef M_CORE_GBA
case mPLATFORM_GBA:
struct GBA* gba = (struct GBA*) core->board;
palette = gba->video.palette;
break;
#endif
#ifdef M_CORE_GB
case mPLATFORM_GB:
struct GB* gb = (struct GB*) core->board;
palette = gb->video.palette;
break;
#endif
default:
break;
}

if (palette != 0) {
palette[0] = 123;

TEST_PROGRAM("assert(emu.readPalette)")
TEST_PROGRAM("assert(emu:readPalette(0) == 123)")
}

mScriptContextDeinit(&context);
TEARDOWN_CORE;
}

M_TEST_DEFINE(writePalette) {
SETUP_LUA;
CREATE_CORE;

uint16_t* palette = 0;

switch(core->platform(core)) {
#if(TEST_PLATFORM == mPLATFORM_GBA)
case mPLATFORM_GBA:
struct GBA* gba = (struct GBA*) core->board;
palette = gba->video.palette;
break;
#endif
#if(TEST_PLATFORM == mPLATFORM_GB)
case mPLATFORM_GB:
struct GB* gb = (struct GB*) core->board;
palette = gb->video.palette;
break;
#endif
default:
break;
}

if (palette != 0) {
TEST_PROGRAM("assert(emu.writePalette)")
TEST_PROGRAM("emu:writePalette(0, 123)")

assert_true(palette[0] == 123);
}

mScriptContextDeinit(&context);
TEARDOWN_CORE;
}

#ifdef ENABLE_DEBUGGERS
void _setupBp(struct mCore* core) {
switch (core->platform(core)) {
Expand Down Expand Up @@ -860,6 +933,8 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptCore,
cmocka_unit_test(memoryWrite),
cmocka_unit_test(logging),
cmocka_unit_test(screenshot),
cmocka_unit_test(readPalette),
cmocka_unit_test(writePalette),
#ifdef ENABLE_DEBUGGERS
#ifdef M_CORE_GBA
cmocka_unit_test(basicBreakpointGBA),
Expand Down
29 changes: 29 additions & 0 deletions src/script/stdlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,31 @@ static struct mScriptValue* mScriptExpandBitmask(uint64_t mask) {
mSCRIPT_BIND_FUNCTION(mScriptMakeBitmask_Binding, U64, mScriptMakeBitmask, 1, LIST, bits);
mSCRIPT_BIND_FUNCTION(mScriptExpandBitmask_Binding, WLIST, mScriptExpandBitmask, 1, U64, mask);

static uint16_t mScriptPackColor(uint8_t red, uint8_t green, uint8_t blue) {
return (uint16_t) (((blue & 31) << 10) | ((green & 31) << 5) | (red & 31));
}

static struct mScriptValue* mScriptUnpackColor(uint16_t color) {
struct mScriptValue* tbl = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE);

char* keys[3] = {"red", "green", "blue"};

for (size_t i = 0; i < 3; ++i) {
uint16_t part = (color >> 5*i) & 31;
struct mScriptValue* ikey = mScriptValueCreateFromUInt(i + 1);
struct mScriptValue* skey = mScriptStringCreateFromASCII(keys[i]);
struct mScriptValue* val = mScriptValueCreateFromUInt(part);

mScriptTableInsert(tbl, ikey, val);
mScriptTableInsert(tbl, skey, val);
}

return tbl;
}

mSCRIPT_BIND_FUNCTION(mScriptPackColor_Binding, U16, mScriptPackColor, 3, U8, red, U8, green, U8, blue);
mSCRIPT_BIND_FUNCTION(mScriptUnpackColor_Binding, WTABLE, mScriptUnpackColor, 1, U16, color);

mSCRIPT_DEFINE_STRUCT(mScriptCallbackManager)
mSCRIPT_DEFINE_CLASS_DOCSTRING(
"A global singleton object `callbacks` used for managing callbacks. The following callbacks are defined:\n\n"
Expand Down Expand Up @@ -272,13 +297,17 @@ void mScriptContextAttachStdlib(struct mScriptContext* context) {
mScriptContextExportNamespace(context, "util", (struct mScriptKVPair[]) {
mSCRIPT_KV_PAIR(makeBitmask, &mScriptMakeBitmask_Binding),
mSCRIPT_KV_PAIR(expandBitmask, &mScriptExpandBitmask_Binding),
mSCRIPT_KV_PAIR(packColor, &mScriptPackColor_Binding),
mSCRIPT_KV_PAIR(unpackColor, &mScriptUnpackColor_Binding),
mSCRIPT_KV_PAIR(newRectangle, &mRectangleNew_Binding),
mSCRIPT_KV_PAIR(newSize, &mSizeNew_Binding),
mSCRIPT_KV_SENTINEL
});
mScriptContextSetDocstring(context, "util", "Basic utility library");
mScriptContextSetDocstring(context, "util.makeBitmask", "Compile a list of bit indices into a bitmask");
mScriptContextSetDocstring(context, "util.expandBitmask", "Expand a bitmask into a list of bit indices");
mScriptContextSetDocstring(context, "util.packColor", "Pack three RGB channels (0-31) into a 16-bit value.");
mScriptContextSetDocstring(context, "util.unpackColor", "Split a color in a 16-bit value into a table of red, blue and green channels (indexed by name or integer) from 0 to 31.");
mScriptContextSetDocstring(context, "util.newRectangle", "Create a new mRectangle");
mScriptContextSetDocstring(context, "util.newSize", "Create a new mSize");

Expand Down
27 changes: 27 additions & 0 deletions src/script/test/stdlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,31 @@ M_TEST_DEFINE(bitUnmask) {
mScriptContextDeinit(&context);
}

M_TEST_DEFINE(packColor) {
SETUP_LUA;

TEST_PROGRAM("assert(util)");
TEST_PROGRAM("assert(util.packColor)");
TEST_PROGRAM("assert(util.packColor(31, 16, 3) == 3615)");

mScriptContextDeinit(&context);
}

M_TEST_DEFINE(unpackColor) {
SETUP_LUA;

TEST_PROGRAM("assert(util)");
TEST_PROGRAM("assert(util.unpackColor)");
TEST_PROGRAM("assert(util.unpackColor(3615).red == 31)");
TEST_PROGRAM("assert(util.unpackColor(3615)[1] == 31)");
TEST_PROGRAM("assert(util.unpackColor(3615).green == 16)");
TEST_PROGRAM("assert(util.unpackColor(3615)[2] == 16)");
TEST_PROGRAM("assert(util.unpackColor(3615).blue == 3)");
TEST_PROGRAM("assert(util.unpackColor(3615)[3] == 3)");

mScriptContextDeinit(&context);
}

M_TEST_DEFINE(callbacks) {
SETUP_LUA;

Expand Down Expand Up @@ -260,6 +285,8 @@ M_TEST_DEFINE(size) {
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptStdlib,
cmocka_unit_test(bitMask),
cmocka_unit_test(bitUnmask),
cmocka_unit_test(packColor),
cmocka_unit_test(unpackColor),
cmocka_unit_test(callbacks),
cmocka_unit_test(oneshot),
cmocka_unit_test(callbackWeakref),
Expand Down