project64/Source/Project64/UserInterface/Debugger/ScriptAPI/ScriptAPI_N64Image.cpp

242 lines
6.5 KiB
C++

#include <stdafx.h>
#include "ScriptAPI.h"
#include "N64Image.h"
#pragma warning(disable: 4702) // disable unreachable code warning
using namespace ScriptAPI;
static CN64Image* GetThisImage(duk_context* ctx)
{
duk_push_this(ctx);
duk_get_prop_string(ctx, -1, HS_n64ImagePtr);
CN64Image* image = (CN64Image*)duk_get_pointer(ctx, -1);
duk_pop_n(ctx, 2);
if (image == nullptr)
{
duk_push_error_object(ctx, DUK_ERR_ERROR, "internal image object is null");
return duk_throw(ctx);
}
return image;
}
void ScriptAPI::Define_N64Image(duk_context* ctx)
{
const DukPropListEntry prototype[] = {
{ "toPNG", DukCFunction(js_N64Image_toPNG) },
{ "update", DukCFunction(js_N64Image_update) },
{ nullptr}
};
const DukPropListEntry staticProps[] = {
{ "fromPNG", DukCFunction(js_N64Image_static_fromPNG) },
{ "format", DukCFunction(js_N64Image_static_format) },
{ "bpp", DukCFunction(js_N64Image_static_bpp) },
{ nullptr }
};
DefineGlobalClass(ctx, "N64Image", js_N64Image__constructor, prototype, staticProps);
}
static void InitImageObjectProps(duk_context* ctx, duk_idx_t idx, CN64Image* image)
{
idx = duk_normalize_index(ctx, idx);
duk_push_external_buffer(ctx);
duk_config_buffer(ctx, -1, image->PixelData().data(), image->PixelData().size());
duk_push_buffer_object(ctx, -1, 0, image->PixelData().size(), DUK_BUFOBJ_NODEJS_BUFFER);
duk_remove(ctx, -2);
duk_idx_t pixels_idx = duk_normalize_index(ctx, -1);
if (image->UsesPalette())
{
duk_push_external_buffer(ctx);
duk_config_buffer(ctx, -1, image->PaletteData().data(), image->PaletteData().size());
duk_push_buffer_object(ctx, -2, 0, image->PaletteData().size(), DUK_BUFOBJ_NODEJS_BUFFER);
duk_remove(ctx, -2);
}
else
{
duk_push_null(ctx);
}
duk_idx_t palette_idx = duk_normalize_index(ctx, -1);
const DukPropListEntry props[] = {
{ HS_n64ImagePtr, DukPointer(image) },
{ "pixels", DukDupIndex(pixels_idx) },
{ "palette", DukDupIndex(palette_idx) },
{ "width", DukUInt(image->Width()) },
{ "height", DukUInt(image->Height()) },
{ nullptr }
};
DukPutPropList(ctx, idx, props);
duk_pop_n(ctx, 2);
duk_push_c_function(ctx, ScriptAPI::js_N64Image__finalizer, 1);
duk_set_finalizer(ctx, idx);
}
duk_ret_t ScriptAPI::js_N64Image__constructor(duk_context* ctx)
{
CheckArgs(ctx, { Arg_Number, Arg_Number, Arg_OptNumber, Arg_OptBufferData, Arg_OptBufferData });
if (!duk_is_constructor_call(ctx))
{
return DUK_RET_ERROR;
}
size_t pixelDataSize = 0, paletteDataSize = 0;
size_t width = duk_get_uint(ctx, 0);
size_t height = duk_get_uint(ctx, 1);
int format = duk_get_int_default(ctx, 2, IMG_RGBA32);
void* pixelData = duk_get_buffer_data_default(ctx, 3, &pixelDataSize, nullptr, 0);
void* paletteData = duk_get_buffer_data_default(ctx, 4, &paletteDataSize, nullptr, 0);
CN64Image* image = new CN64Image();
int result = image->Init(format, width, height, pixelData, pixelDataSize, paletteData, paletteDataSize);
if (result != N64IMG_OK)
{
duk_push_error_object(ctx, DUK_ERR_ERROR, "failed to initialize image (%s)",
CN64Image::ResultCodeName(result));
return duk_throw(ctx);
}
duk_push_this(ctx);
InitImageObjectProps(ctx, -1, image);
return 0;
}
duk_ret_t ScriptAPI::js_N64Image__finalizer(duk_context* ctx)
{
duk_get_prop_string(ctx, 0, HS_n64ImagePtr);
CN64Image* image = (CN64Image*)duk_get_pointer(ctx, -1);
if (image == nullptr)
{
return 0;
}
delete image;
return 0;
}
duk_ret_t ScriptAPI::js_N64Image_static_fromPNG(duk_context* ctx)
{
CheckArgs(ctx, { Arg_BufferData, Arg_OptNumber });
int format = duk_get_int_default(ctx, 1, IMG_RGBA32);
if (CN64Image::BitsPerPixel(format) == 0)
{
duk_push_error_object(ctx, DUK_RET_TYPE_ERROR, "invalid format");
return duk_throw(ctx);
}
size_t pngSize;
uint8_t* pngData = (uint8_t*)duk_get_buffer_data(ctx, 0, &pngSize);
CN64Image* image = new CN64Image();
int result = image->Init(format, pngData, pngSize);
if (result != N64IMG_OK)
{
delete image;
duk_push_error_object(ctx, DUK_ERR_ERROR, "failed to initialize image (%s)",
CN64Image::ResultCodeName(result), result);
return duk_throw(ctx);
}
duk_push_object(ctx);
duk_get_global_string(ctx, "N64Image");
duk_get_prop_string(ctx, -1, "prototype");
duk_set_prototype(ctx, -3);
duk_pop(ctx);
InitImageObjectProps(ctx, -1, image);
return 1;
}
duk_ret_t ScriptAPI::js_N64Image_static_format(duk_context* ctx)
{
CheckArgs(ctx, { Arg_Number, Arg_Number, Arg_OptNumber });
duk_uint_t gbiFmt = duk_get_uint(ctx, 0);
duk_uint_t gbiSiz = duk_get_uint(ctx, 1);
duk_uint_t gbiTlutFmt = duk_get_uint_default(ctx, 2, G_TT_NONE);
int format = (gbiFmt << 3) | gbiSiz | gbiTlutFmt;
switch (format)
{
case IMG_RGBA16:
case IMG_RGBA32:
case IMG_CI4_RGBA16:
case IMG_CI4_IA16:
case IMG_CI8_RGBA16:
case IMG_CI8_IA16:
case IMG_IA4:
case IMG_IA8:
case IMG_IA16:
case IMG_I4:
case IMG_I8:
duk_push_number(ctx, format);
break;
default:
duk_push_number(ctx, -1);
}
return 1;
}
duk_ret_t ScriptAPI::js_N64Image_static_bpp(duk_context* ctx)
{
CheckArgs(ctx, { Arg_Number });
duk_uint_t format = duk_get_uint(ctx, 0);
int bpp = 0;
switch (format)
{
case G_IM_SIZ_4b: bpp = 4; break;
case G_IM_SIZ_8b: bpp = 8; break;
case G_IM_SIZ_16b: bpp = 16; break;
case G_IM_SIZ_32b: bpp = 32; break;
default: bpp = CN64Image::BitsPerPixel(format); break;
}
duk_push_number(ctx, bpp);
return 1;
}
duk_ret_t ScriptAPI::js_N64Image_toPNG(duk_context* ctx)
{
CN64Image* image = GetThisImage(ctx);
std::vector<uint8_t> png;
image->ToPNG(png);
void* pngCopy = duk_push_buffer(ctx, png.size(), false);
duk_push_buffer_object(ctx, -1, 0, png.size(), DUK_BUFOBJ_NODEJS_BUFFER);
memcpy(pngCopy, png.data(), png.size());
return 1;
}
duk_ret_t ScriptAPI::js_N64Image_update(duk_context* ctx)
{
CN64Image* image = GetThisImage(ctx);
int result = image->UpdateBitmap();
if (result != N64IMG_OK)
{
duk_push_error_object(ctx, DUK_ERR_ERROR, "bitmap update failed (%s)",
CN64Image::ResultCodeName(result));
}
return 0;
}