243 lines
6.5 KiB
C++
243 lines
6.5 KiB
C++
#include "stdafx.h"
|
|
|
|
#include "N64Image.h"
|
|
#include "ScriptAPI.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;
|
|
}
|