kuroko: bindings for sprites

This commit is contained in:
K. Lange 2021-01-24 21:47:50 +09:00
parent ec0fe9bb69
commit 5746592075

View File

@ -39,6 +39,14 @@ struct WindowClass {
yutani_window_t * window;
};
static KrkClass * YutaniSprite;
struct YutaniSprite {
KrkInstance inst;
gfx_context_t * ctx;
int doubleBuffered;
sprite_t sprite;
};
static KrkClass * Decorator;
/* no additional fields */
@ -48,7 +56,6 @@ struct YutaniColor {
uint32_t color;
};
/**
* Convenience wrapper to make a class and attach it to the module, while
* handling stack push/pop to keep things from being prematurely GC'd.
@ -325,9 +332,8 @@ static KrkValue _gfx_line(int argc, KrkValue argv[]) {
}
static KrkValue _gfx_rect(int argc, KrkValue argv[], int hasKw) {
CHECK_GFX();
if (hasKw) argc--;
CHECK_GFX();
if (argc != 6 ||
!IS_INTEGER(argv[1]) ||
@ -368,6 +374,93 @@ static KrkValue _gfx_rect(int argc, KrkValue argv[], int hasKw) {
return NONE_VAL();
}
static KrkValue _gfx_draw_sprite(int argc, KrkValue argv[], int hasKw) {
if (hasKw) argc--;
CHECK_GFX();
if (argc < 2 || !krk_isInstanceOf(argv[1], YutaniSprite))
return krk_runtimeError(vm.exceptions.typeError, "expected Sprite");
if (argc < 4 || !IS_INTEGER(argv[2]) || !IS_INTEGER(argv[3]))
return krk_runtimeError(vm.exceptions.typeError, "expected integer coordinate pair");
/* Potential kwargs: rotation:float, alpha:float, scale:(int,int)... */
KrkValue rotation = NONE_VAL(), alpha = NONE_VAL(), scale=NONE_VAL(), color=NONE_VAL();
if (hasKw) {
krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("alpha")), &alpha);
krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("rotation")), &rotation);
krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("scale")), &scale);
krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("color")), &color);
}
if (!IS_NONE(alpha) && !IS_FLOATING(alpha))
return krk_runtimeError(vm.exceptions.typeError, "alpha must be float");
if (!IS_NONE(rotation) && !IS_FLOATING(rotation))
return krk_runtimeError(vm.exceptions.typeError, "rotation must be float");
if (!IS_NONE(color) && !krk_isInstanceOf(color,YutaniColor))
return krk_runtimeError(vm.exceptions.typeError, "color must be color");
if (!IS_NONE(scale) && (!IS_TUPLE(scale) || AS_TUPLE(scale)->values.count != 2 ||
!IS_INTEGER(AS_TUPLE(scale)->values.values[0]) ||
!IS_INTEGER(AS_TUPLE(scale)->values.values[1])))
return krk_runtimeError(vm.exceptions.typeError, "scale must be 2-tuple of ints");
if (!IS_NONE(rotation) + !IS_NONE(scale) + !IS_NONE(color) > 1)
return krk_runtimeError(vm.exceptions.typeError, "can not combine rotation / scale / color");
if ((!IS_NONE(rotation) || !IS_NONE(color)) && IS_NONE(alpha))
alpha = FLOATING_VAL(1.0);
struct YutaniSprite * sprite = (struct YutaniSprite*)AS_INSTANCE(argv[1]);
int32_t x = AS_INTEGER(argv[2]);
int32_t y = AS_INTEGER(argv[3]);
if (!IS_NONE(scale)) {
int32_t width = AS_INTEGER(AS_TUPLE(scale)->values.values[0]);
int32_t height = AS_INTEGER(AS_TUPLE(scale)->values.values[1]);
if (IS_NONE(alpha)) {
draw_sprite_scaled(self->ctx, &sprite->sprite, x, y, width, height);
} else {
draw_sprite_scaled_alpha(self->ctx, &sprite->sprite, x, y, width, height, AS_FLOATING(alpha));
}
} else if (IS_NONE(alpha)) {
draw_sprite(self->ctx, &sprite->sprite, x, y);
} else if (!IS_NONE(color)) {
draw_sprite_alpha_paint(self->ctx, &sprite->sprite, x, y, AS_FLOATING(alpha), ((struct YutaniColor*)AS_INSTANCE(color))->color);
} else if (!IS_NONE(rotation)) {
draw_sprite_rotate(self->ctx, &sprite->sprite, x, y, AS_FLOATING(rotation), AS_FLOATING(alpha));
} else {
draw_sprite_alpha(self->ctx, &sprite->sprite, x, y, AS_FLOATING(alpha));
}
return NONE_VAL();
}
static void _sprite_sweep(KrkInstance * self) {
struct YutaniSprite * sprite = (struct YutaniSprite*)self;
if (sprite->sprite.masks) free(sprite->sprite.masks);
if (sprite->sprite.bitmap) free(sprite->sprite.bitmap);
if (sprite->ctx) free(sprite->ctx);
}
static KrkValue _sprite_init(int argc, KrkValue argv[]) {
if (argc < 1 || !krk_isInstanceOf(argv[0], YutaniSprite))
return krk_runtimeError(vm.exceptions.typeError, "expected sprite");
if (argc < 2 || !IS_STRING(argv[1]))
return krk_runtimeError(vm.exceptions.typeError, "Sprite() takes one str argument");
struct YutaniSprite * self = (struct YutaniSprite*)AS_INSTANCE(argv[0]);
int result = load_sprite(&self->sprite, AS_CSTRING(argv[1]));
if (result) {
return krk_runtimeError(vm.exceptions.ioError, "Sprite() could not be initialized");
}
self->ctx = init_graphics_sprite(&self->sprite);
return argv[0];
}
static KrkValue _window_init(int argc, KrkValue argv[], int hasKw) {
if (!yctxInstance) return krk_runtimeError(vm.exceptions.valueError, "Compositor is not initialized");
if (argc < 1 || !krk_isInstanceOf(argv[0], YutaniWindow))
@ -620,6 +713,7 @@ KrkValue krk_module_onload__yutani(void) {
krk_defineNative(&GraphicsContext->methods, ".blur", _gfx_blur);
krk_defineNative(&GraphicsContext->methods, ".line", _gfx_line);
krk_defineNative(&GraphicsContext->methods, ".rect", _gfx_rect);
krk_defineNative(&GraphicsContext->methods, ".draw_sprite", _gfx_draw_sprite);
krk_finalizeClass(GraphicsContext);
YutaniWindow = krk_createClass(module, "Window", GraphicsContext);
@ -633,6 +727,12 @@ KrkValue krk_module_onload__yutani(void) {
krk_defineNative(&YutaniWindow->methods, ":focused", _window_focused);
krk_finalizeClass(YutaniWindow);
YutaniSprite = krk_createClass(module, "Sprite", GraphicsContext);
YutaniSprite->allocSize = sizeof(struct YutaniSprite);
YutaniSprite->_ongcsweep = _sprite_sweep;
krk_defineNative(&YutaniSprite->methods, ".__init__", _sprite_init);
krk_finalizeClass(YutaniSprite);
Decorator = krk_createClass(module, "Decorator", NULL);
krk_defineNative(&Decorator->fields, "get_bounds", _decor_get_bounds);
krk_defineNative(&Decorator->fields, "render", _decor_render);