242 lines
6.5 KiB
C++
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;
|
||
|
}
|