1424 lines
42 KiB
C
1424 lines
42 KiB
C
|
// MIT License
|
|||
|
|
|||
|
// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com
|
|||
|
|
|||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|||
|
// of this software and associated documentation files (the "Software"), to deal
|
|||
|
// in the Software without restriction, including without limitation the rights
|
|||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
|
// copies of the Software, and to permit persons to whom the Software is
|
|||
|
// furnished to do so, subject to the following conditions:
|
|||
|
|
|||
|
// The above copyright notice and this permission notice shall be included in all
|
|||
|
// copies or substantial portions of the Software.
|
|||
|
|
|||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||
|
// SOFTWARE.
|
|||
|
|
|||
|
#include <stdlib.h>
|
|||
|
#include <string.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <ctype.h>
|
|||
|
|
|||
|
#include "machine.h"
|
|||
|
#include "tools.h"
|
|||
|
#include "wren.h"
|
|||
|
|
|||
|
static WrenHandle* game_class;
|
|||
|
static WrenHandle* new_handle;
|
|||
|
static WrenHandle* update_handle;
|
|||
|
static WrenHandle* scanline_handle;
|
|||
|
static WrenHandle* overlap_handle;
|
|||
|
|
|||
|
static bool loaded = false;
|
|||
|
|
|||
|
static char const* tic_wren_api = " \n"
|
|||
|
"class Tic { \n"
|
|||
|
" foreign static btn(id) \n"
|
|||
|
" foreign static btnp(id) \n"
|
|||
|
" foreign static btnp(id, hold, period) \n"
|
|||
|
" foreign static key(id) \n"
|
|||
|
" foreign static keyp(id) \n"
|
|||
|
" foreign static keyp(id, hold, period) \n"
|
|||
|
" foreign static mouse() \n"
|
|||
|
" foreign static font(text) \n"
|
|||
|
" foreign static font(text, x, y) \n"
|
|||
|
" foreign static font(text, x, y, alpha_color) \n"
|
|||
|
" foreign static font(text, x, y, alpha_color, w, h) \n"
|
|||
|
" foreign static font(text, x, y, alpha_color, w, h, fixed) \n"
|
|||
|
" foreign static font(text, x, y, alpha_color, w, h, fixed, scale) \n"
|
|||
|
" foreign static spr(id) \n"
|
|||
|
" foreign static spr(id, x, y) \n"
|
|||
|
" foreign static spr(id, x, y, alpha_color) \n"
|
|||
|
" foreign static spr(id, x, y, alpha_color, scale) \n"
|
|||
|
" foreign static spr(id, x, y, alpha_color, scale, flip) \n"
|
|||
|
" foreign static spr(id, x, y, alpha_color, scale, flip, rotate) \n"
|
|||
|
" foreign static spr(id, x, y, alpha_color, scale, flip, rotate, cell_width, cell_height) \n"
|
|||
|
" foreign static map(cell_x, cell_y) \n"
|
|||
|
" foreign static map(cell_x, cell_y, cell_w, cell_h) \n"
|
|||
|
" foreign static map(cell_x, cell_y, cell_w, cell_h, x, y) \n"
|
|||
|
" foreign static map(cell_x, cell_y, cell_w, cell_h, x, y, alpha_color) \n"
|
|||
|
" foreign static map(cell_x, cell_y, cell_w, cell_h, x, y, alpha_color, scale) \n"
|
|||
|
" foreign static mset(cell_x, cell_y) \n"
|
|||
|
" foreign static mset(cell_x, cell_y, index) \n"
|
|||
|
" foreign static mget(cell_x, cell_y) \n"
|
|||
|
" foreign static textri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3) \n"
|
|||
|
" foreign static textri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, use_map) \n"
|
|||
|
" foreign static textri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, use_map, alpha_color) \n"
|
|||
|
" foreign static pix(x, y) \n"
|
|||
|
" foreign static pix(x, y, color) \n"
|
|||
|
" foreign static line(x0, y0, x1, y1, color) \n"
|
|||
|
" foreign static circ(x, y, radius, color) \n"
|
|||
|
" foreign static circb(x, y, radius, color) \n"
|
|||
|
" foreign static rect(x, y, w, h, color) \n"
|
|||
|
" foreign static rectb(x, y, w, h, color) \n"
|
|||
|
" foreign static tri(x1, y1, x2, y2, x3, y3, color) \n"
|
|||
|
" foreign static cls() \n"
|
|||
|
" foreign static cls(color) \n"
|
|||
|
" foreign static clip() \n"
|
|||
|
" foreign static clip(x, y, w, h) \n"
|
|||
|
" foreign static peek(addr) \n"
|
|||
|
" foreign static poke(addr, val) \n"
|
|||
|
" foreign static peek4(addr) \n"
|
|||
|
" foreign static poke4(addr, val) \n"
|
|||
|
" foreign static memcpy(dst, src, size) \n"
|
|||
|
" foreign static memset(dst, src, size) \n"
|
|||
|
" foreign static pmem(index, val) \n"
|
|||
|
" foreign static sfx(id) \n"
|
|||
|
" foreign static sfx(id, note) \n"
|
|||
|
" foreign static sfx(id, note, duration) \n"
|
|||
|
" foreign static sfx(id, note, duration, channel) \n"
|
|||
|
" foreign static sfx(id, note, duration, channel, volume) \n"
|
|||
|
" foreign static sfx(id, note, duration, channel, volume, speed) \n"
|
|||
|
" foreign static music() \n"
|
|||
|
" foreign static music(track) \n"
|
|||
|
" foreign static music(track, frame) \n"
|
|||
|
" foreign static music(track, frame, loop) \n"
|
|||
|
" foreign static time() \n"
|
|||
|
" foreign static sync() \n"
|
|||
|
" foreign static sync(mask) \n"
|
|||
|
" foreign static sync(mask, bank) \n"
|
|||
|
" foreign static sync(mask, bank, tocart) \n"
|
|||
|
" foreign static reset() \n"
|
|||
|
" foreign static exit() \n"
|
|||
|
" foreign static map_width__ \n"
|
|||
|
" foreign static map_height__ \n"
|
|||
|
" foreign static spritesize__ \n"
|
|||
|
" foreign static print__(v, x, y, color, fixed, scale) \n"
|
|||
|
" foreign static trace__(msg, color) \n"
|
|||
|
" foreign static spr__(id, x, y, alpha_color, scale, flip, rotate) \n"
|
|||
|
" foreign static mgeti__(index) \n"
|
|||
|
" static print(v) { Tic.print__(v.toString, 0, 0, 15, false, 1) } \n"
|
|||
|
" static print(v,x,y) { Tic.print__(v.toString, x, y, 15, false, 1) } \n"
|
|||
|
" static print(v,x,y,color) { Tic.print__(v.toString, x, y, color, false, 1) } \n"
|
|||
|
" static print(v,x,y,color,fixed) { Tic.print__(v.toString, x, y, color, fixed, 1) } \n"
|
|||
|
" static print(v,x,y,color,fixed,scale) { Tic.print__(v.toString, x, y, color, fixed, scale) } \n"
|
|||
|
" static trace(v) { Tic.trace__(v.toString, 15) } \n"
|
|||
|
" static trace(v,color) { Tic.trace__(v.toString, color) } \n"
|
|||
|
" static map(cell_x, cell_y, cell_w, cell_h, x, y, alpha_color, scale, remap) { \n"
|
|||
|
" var map_w = Tic.map_width__ \n"
|
|||
|
" var map_h = Tic.map_height__ \n"
|
|||
|
" var size = Tic.spritesize__ * scale \n"
|
|||
|
" var jj = y \n"
|
|||
|
" var ii = x \n"
|
|||
|
" var flip = 0 \n"
|
|||
|
" var rotate = 0 \n"
|
|||
|
" for (j in cell_y...cell_y+cell_h) { \n"
|
|||
|
" ii = x \n"
|
|||
|
" for (i in cell_x...cell_x+cell_w) { \n"
|
|||
|
" var mi = i \n"
|
|||
|
" var mj = j \n"
|
|||
|
" while(mi < 0) mi = mi + map_w \n"
|
|||
|
" while(mj < 0) mj = mj + map_h \n"
|
|||
|
" while(mi >= map_w) mi = mi - map_w \n"
|
|||
|
" while(mj >= map_h) mj = mj - map_h \n"
|
|||
|
" var index = mi + mj * map_w \n"
|
|||
|
" var tile_index = Tic.mgeti__(index) \n"
|
|||
|
" var ret = remap.call(tile_index, mi, mj) \n"
|
|||
|
" if (ret.type == List) { \n"
|
|||
|
" tile_index = ret[0] \n"
|
|||
|
" flip = ret[1] \n"
|
|||
|
" rotate = ret[2] \n"
|
|||
|
" } else if (ret.type == Num) { \n"
|
|||
|
" tile_index = ret \n"
|
|||
|
" } \n"
|
|||
|
" Tic.spr__(tile_index, ii, jj, alpha_color, scale, flip, rotate) \n"
|
|||
|
" ii = ii + size \n"
|
|||
|
" } \n"
|
|||
|
" jj = jj + size \n"
|
|||
|
" } \n"
|
|||
|
" } \n"
|
|||
|
"} \n"
|
|||
|
"class Engine { \n"
|
|||
|
" update(){} \n"
|
|||
|
" scanline(row){} \n"
|
|||
|
" overlap(){} \n"
|
|||
|
"} \n"
|
|||
|
"";
|
|||
|
|
|||
|
static inline void wrenError(WrenVM* vm, const char* msg)
|
|||
|
{
|
|||
|
wrenEnsureSlots(vm, 1);
|
|||
|
wrenSetSlotString(vm, 0, msg);
|
|||
|
wrenAbortFiber(vm, 0);
|
|||
|
}
|
|||
|
|
|||
|
static inline s32 getWrenNumber(WrenVM* vm, s32 index)
|
|||
|
{
|
|||
|
return (s32)wrenGetSlotDouble(vm, index);
|
|||
|
}
|
|||
|
|
|||
|
static inline bool isNumber(WrenVM* vm, s32 index)
|
|||
|
{
|
|||
|
return wrenGetSlotType(vm, index) == WREN_TYPE_NUM;
|
|||
|
}
|
|||
|
|
|||
|
static inline bool isString(WrenVM* vm, s32 index)
|
|||
|
{
|
|||
|
return wrenGetSlotType(vm, index) == WREN_TYPE_STRING;
|
|||
|
}
|
|||
|
|
|||
|
static inline bool isList(WrenVM* vm, s32 index)
|
|||
|
{
|
|||
|
return wrenGetSlotType(vm, index) == WREN_TYPE_LIST;
|
|||
|
}
|
|||
|
|
|||
|
static void closeWren(tic_mem* tic)
|
|||
|
{
|
|||
|
tic_machine* machine = (tic_machine*)tic;
|
|||
|
if(machine->wren)
|
|||
|
{
|
|||
|
// release handles
|
|||
|
if (loaded)
|
|||
|
{
|
|||
|
wrenReleaseHandle(machine->wren, new_handle);
|
|||
|
wrenReleaseHandle(machine->wren, update_handle);
|
|||
|
wrenReleaseHandle(machine->wren, scanline_handle);
|
|||
|
wrenReleaseHandle(machine->wren, overlap_handle);
|
|||
|
if (game_class != NULL) {
|
|||
|
wrenReleaseHandle(machine->wren, game_class);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
wrenFreeVM(machine->wren);
|
|||
|
machine->wren = NULL;
|
|||
|
|
|||
|
}
|
|||
|
loaded = false;
|
|||
|
}
|
|||
|
|
|||
|
static tic_machine* getWrenMachine(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = wrenGetUserData(vm);
|
|||
|
|
|||
|
return machine;
|
|||
|
}
|
|||
|
|
|||
|
static void wren_map_width(WrenVM* vm)
|
|||
|
{
|
|||
|
wrenSetSlotDouble(vm, 0, TIC_MAP_WIDTH);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_map_height(WrenVM* vm)
|
|||
|
{
|
|||
|
wrenSetSlotDouble(vm, 0, TIC_MAP_HEIGHT);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_mgeti(WrenVM* vm)
|
|||
|
{
|
|||
|
|
|||
|
s32 index = getWrenNumber(vm, 1);
|
|||
|
|
|||
|
if(index < 0 || index >= TIC_MAP_WIDTH * TIC_MAP_HEIGHT) {
|
|||
|
wrenSetSlotDouble(vm, 0, 0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
wrenSetSlotDouble(vm, 0, *(memory->ram.map.data + index));
|
|||
|
}
|
|||
|
|
|||
|
static void wren_spritesize(WrenVM* vm)
|
|||
|
{
|
|||
|
wrenSetSlotDouble(vm, 0, TIC_SPRITESIZE);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_btn(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
if (top == 1)
|
|||
|
{
|
|||
|
wrenSetSlotBool(vm, 0, machine->memory.ram.input.gamepads.data);
|
|||
|
}
|
|||
|
else if (top == 2)
|
|||
|
{
|
|||
|
s32 index = getWrenNumber(vm, 1) & 0xf;
|
|||
|
wrenSetSlotBool(vm, 0, machine->memory.ram.input.gamepads.data & (1 << index));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
static void wren_btnp(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
tic_mem* memory = (tic_mem*)machine;
|
|||
|
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
if (top == 1)
|
|||
|
{
|
|||
|
wrenSetSlotBool(vm, 0, memory->api.btnp(memory, -1, -1, -1));
|
|||
|
}
|
|||
|
else if(top == 2)
|
|||
|
{
|
|||
|
s32 index = getWrenNumber(vm, 1) & 0xf;
|
|||
|
|
|||
|
wrenSetSlotBool(vm, 0, memory->api.btnp(memory, index, -1, -1));
|
|||
|
}
|
|||
|
else if (top == 4)
|
|||
|
{
|
|||
|
s32 index = getWrenNumber(vm, 1) & 0xf;
|
|||
|
u32 hold = getWrenNumber(vm, 2);
|
|||
|
u32 period = getWrenNumber(vm, 3);
|
|||
|
|
|||
|
wrenSetSlotBool(vm, 0, memory->api.btnp(memory, index, hold, period));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_key(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
tic_mem* tic = &machine->memory;
|
|||
|
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
if (top == 1)
|
|||
|
{
|
|||
|
wrenSetSlotBool(vm, 0, tic->api.key(tic, tic_key_unknown));
|
|||
|
}
|
|||
|
else if (top == 2)
|
|||
|
{
|
|||
|
tic_key key = getWrenNumber(vm, 1);
|
|||
|
|
|||
|
if(key < tic_keys_count)
|
|||
|
wrenSetSlotBool(vm, 0, tic->api.key(tic, key));
|
|||
|
else
|
|||
|
{
|
|||
|
wrenError(vm, "unknown keyboard code\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_keyp(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
tic_mem* tic = &machine->memory;
|
|||
|
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
if (top == 1)
|
|||
|
{
|
|||
|
wrenSetSlotBool(vm, 0, tic->api.keyp(tic, tic_key_unknown, -1, -1));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
tic_key key = getWrenNumber(vm, 1);
|
|||
|
|
|||
|
if(key >= tic_keys_count)
|
|||
|
{
|
|||
|
wrenError(vm, "unknown keyboard code\n");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if(top == 2)
|
|||
|
{
|
|||
|
wrenSetSlotBool(vm, 0, tic->api.keyp(tic, key, -1, -1));
|
|||
|
}
|
|||
|
else if(top == 4)
|
|||
|
{
|
|||
|
u32 hold = getWrenNumber(vm, 2);
|
|||
|
u32 period = getWrenNumber(vm, 3);
|
|||
|
|
|||
|
wrenSetSlotBool(vm, 0, tic->api.keyp(tic, key, hold, period));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static void wren_mouse(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
|
|||
|
const tic80_mouse* mouse = &machine->memory.ram.input.mouse;
|
|||
|
|
|||
|
wrenEnsureSlots(vm, 4);
|
|||
|
wrenSetSlotNewList(vm, 0);
|
|||
|
wrenSetSlotDouble(vm, 1, mouse->x);
|
|||
|
wrenInsertInList(vm, 0, 0, 1);
|
|||
|
wrenSetSlotDouble(vm, 1, mouse->y);
|
|||
|
wrenInsertInList(vm, 0, 1, 1);
|
|||
|
wrenSetSlotBool(vm, 1, mouse->left);
|
|||
|
wrenInsertInList(vm, 0, 2, 1);
|
|||
|
wrenSetSlotBool(vm, 1, mouse->middle);
|
|||
|
wrenInsertInList(vm, 0, 3, 1);
|
|||
|
wrenSetSlotBool(vm, 1, mouse->right);
|
|||
|
wrenInsertInList(vm, 0, 4, 1);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_print(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
const char* text = wrenGetSlotString(vm, 1);
|
|||
|
|
|||
|
s32 x = getWrenNumber(vm, 2);
|
|||
|
s32 y = getWrenNumber(vm, 3);
|
|||
|
|
|||
|
s32 color = getWrenNumber(vm, 4) % TIC_PALETTE_SIZE;
|
|||
|
|
|||
|
bool fixed = wrenGetSlotBool(vm, 5);
|
|||
|
|
|||
|
s32 scale = getWrenNumber(vm, 6);
|
|||
|
|
|||
|
if(scale == 0)
|
|||
|
{
|
|||
|
wrenSetSlotDouble(vm, 0, 0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
s32 size = memory->api.text_ex(memory, text, x, y, color, fixed, scale);
|
|||
|
|
|||
|
wrenSetSlotDouble(vm, 0, size);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_font(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
if(top > 1)
|
|||
|
{
|
|||
|
const char* text = NULL;
|
|||
|
if (isString(vm, 1))
|
|||
|
{
|
|||
|
text = wrenGetSlotString(vm, 1);
|
|||
|
}
|
|||
|
|
|||
|
s32 x = 0;
|
|||
|
s32 y = 0;
|
|||
|
s32 width = TIC_SPRITESIZE;
|
|||
|
s32 height = TIC_SPRITESIZE;
|
|||
|
u8 chromakey = 0;
|
|||
|
bool fixed = false;
|
|||
|
s32 scale = 1;
|
|||
|
|
|||
|
if(top > 3)
|
|||
|
{
|
|||
|
x = getWrenNumber(vm, 2);
|
|||
|
y = getWrenNumber(vm, 3);
|
|||
|
|
|||
|
if(top > 4)
|
|||
|
{
|
|||
|
chromakey = getWrenNumber(vm, 4);
|
|||
|
|
|||
|
if(top > 6)
|
|||
|
{
|
|||
|
width = getWrenNumber(vm, 5);
|
|||
|
height = getWrenNumber(vm, 6);
|
|||
|
|
|||
|
if(top > 7)
|
|||
|
{
|
|||
|
fixed = wrenGetSlotBool(vm, 7);
|
|||
|
|
|||
|
if(top > 8)
|
|||
|
{
|
|||
|
scale = getWrenNumber(vm, 8);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if(scale == 0)
|
|||
|
{
|
|||
|
wrenSetSlotDouble(vm, 0, 0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
s32 size = drawText(memory, text ? text : "null", x, y, width, height, chromakey, scale, fixed ? drawSpriteFont : drawFixedSpriteFont);
|
|||
|
wrenSetSlotDouble(vm, 0, size);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_trace(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
|
|||
|
const char* text = wrenGetSlotString(vm, 1);
|
|||
|
u8 color = (u8)getWrenNumber(vm, 2);
|
|||
|
|
|||
|
machine->data->trace(machine->data->data, text, color);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_spr(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
s32 index = 0;
|
|||
|
s32 x = 0;
|
|||
|
s32 y = 0;
|
|||
|
s32 w = 1;
|
|||
|
s32 h = 1;
|
|||
|
s32 scale = 1;
|
|||
|
tic_flip flip = tic_no_flip;
|
|||
|
tic_rotate rotate = tic_no_rotate;
|
|||
|
static u8 colors[TIC_PALETTE_SIZE];
|
|||
|
s32 count = 0;
|
|||
|
|
|||
|
if(top > 1)
|
|||
|
{
|
|||
|
index = getWrenNumber(vm, 1);
|
|||
|
|
|||
|
if(top > 3)
|
|||
|
{
|
|||
|
x = getWrenNumber(vm, 2);
|
|||
|
y = getWrenNumber(vm, 3);
|
|||
|
|
|||
|
if(top > 4)
|
|||
|
{
|
|||
|
if(isList(vm, 4))
|
|||
|
{
|
|||
|
for(s32 i = 0; i < TIC_PALETTE_SIZE; i++)
|
|||
|
{
|
|||
|
wrenGetListElement(vm, 4, i, 0); // todo, can be bug cause in slot 0 is object?
|
|||
|
if(isNumber(vm, 0))
|
|||
|
{
|
|||
|
colors[i] = getWrenNumber(vm, 0);
|
|||
|
count++;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
colors[0] = getWrenNumber(vm, 4);
|
|||
|
count = 1;
|
|||
|
}
|
|||
|
|
|||
|
if(top > 5)
|
|||
|
{
|
|||
|
scale = getWrenNumber(vm, 5);
|
|||
|
|
|||
|
if(top > 6)
|
|||
|
{
|
|||
|
flip = getWrenNumber(vm, 6);
|
|||
|
|
|||
|
if(top > 7)
|
|||
|
{
|
|||
|
rotate = getWrenNumber(vm, 7);
|
|||
|
|
|||
|
if(top > 9)
|
|||
|
{
|
|||
|
w = getWrenNumber(vm, 8);
|
|||
|
h = getWrenNumber(vm, 9);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.sprite_ex(memory, &memory->ram.tiles, index, x, y, w, h, colors, count, scale, flip, rotate);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_spr_internal(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 index = getWrenNumber(vm, 1);
|
|||
|
s32 x = getWrenNumber(vm, 2);
|
|||
|
s32 y = getWrenNumber(vm, 3);
|
|||
|
|
|||
|
static u8 colors[TIC_PALETTE_SIZE];
|
|||
|
s32 count = 0;
|
|||
|
|
|||
|
if(isList(vm, 4)) {
|
|||
|
for(s32 i = 0; i < TIC_PALETTE_SIZE; i++) {
|
|||
|
wrenGetListElement(vm, 4, i, 0); // todo, can be bug cause in slot 0 is object?
|
|||
|
if(isNumber(vm, 0)) {
|
|||
|
colors[i] = getWrenNumber(vm, 0);
|
|||
|
count++;
|
|||
|
} else {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
colors[0] = getWrenNumber(vm, 4);
|
|||
|
count = 1;
|
|||
|
}
|
|||
|
|
|||
|
s32 scale = getWrenNumber(vm, 5);
|
|||
|
s32 flip = getWrenNumber(vm, 6);
|
|||
|
s32 rotate = getWrenNumber(vm, 7);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.sprite_ex(memory, &memory->ram.tiles, index, x, y, 1, 1, colors, count, scale, flip, rotate);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_map(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 x = 0;
|
|||
|
s32 y = 0;
|
|||
|
s32 w = TIC_MAP_SCREEN_WIDTH;
|
|||
|
s32 h = TIC_MAP_SCREEN_HEIGHT;
|
|||
|
s32 sx = 0;
|
|||
|
s32 sy = 0;
|
|||
|
u8 chromakey = -1;
|
|||
|
s32 scale = 1;
|
|||
|
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
if(top > 2)
|
|||
|
{
|
|||
|
x = getWrenNumber(vm, 1);
|
|||
|
y = getWrenNumber(vm, 2);
|
|||
|
|
|||
|
if(top > 4)
|
|||
|
{
|
|||
|
w = getWrenNumber(vm, 3);
|
|||
|
h = getWrenNumber(vm, 4);
|
|||
|
|
|||
|
if(top > 6)
|
|||
|
{
|
|||
|
sx = getWrenNumber(vm, 5);
|
|||
|
sy = getWrenNumber(vm, 6);
|
|||
|
|
|||
|
if(top > 7)
|
|||
|
{
|
|||
|
chromakey = getWrenNumber(vm, 7);
|
|||
|
|
|||
|
if(top > 8)
|
|||
|
{
|
|||
|
scale = getWrenNumber(vm, 8);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.map(memory, &memory->ram.map, &memory->ram.tiles, x, y, w, h, sx, sy, chromakey, scale);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_mset(WrenVM* vm)
|
|||
|
{
|
|||
|
|
|||
|
s32 x = getWrenNumber(vm, 1);
|
|||
|
s32 y = getWrenNumber(vm, 2);
|
|||
|
u8 value = getWrenNumber(vm, 3);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.map_set(memory, &memory->ram.map, x, y, value);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_mget(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 x = getWrenNumber(vm, 1);
|
|||
|
s32 y = getWrenNumber(vm, 2);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
u8 value = memory->api.map_get(memory, &memory->ram.map, x, y);
|
|||
|
wrenSetSlotDouble(vm, 0, value);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_textri(WrenVM* vm)
|
|||
|
{
|
|||
|
int top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
float pt[12];
|
|||
|
|
|||
|
for (s32 i = 0; i < COUNT_OF(pt); i++){
|
|||
|
pt[i] = (float)getWrenNumber(vm, i + 1);
|
|||
|
}
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
u8 chroma = 0xff;
|
|||
|
bool use_map = false;
|
|||
|
|
|||
|
// check for use map
|
|||
|
if (top > 13){
|
|||
|
use_map = wrenGetSlotBool(vm, 13);
|
|||
|
}
|
|||
|
|
|||
|
// check for chroma
|
|||
|
if (top > 14){
|
|||
|
chroma = (u8)getWrenNumber(vm, 14);
|
|||
|
}
|
|||
|
|
|||
|
memory->api.textri(memory, pt[0], pt[1], // xy 1
|
|||
|
pt[2], pt[3], // xy 2
|
|||
|
pt[4], pt[5], // xy 3
|
|||
|
pt[6], pt[7], // uv 1
|
|||
|
pt[8], pt[9], // uv 2
|
|||
|
pt[10], pt[11], // uv 3
|
|||
|
use_map, // use map
|
|||
|
chroma); // chroma
|
|||
|
}
|
|||
|
|
|||
|
static void wren_pix(WrenVM* vm)
|
|||
|
{
|
|||
|
int top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
s32 x = getWrenNumber(vm, 1);
|
|||
|
s32 y = getWrenNumber(vm, 2);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
if(top > 3)
|
|||
|
{
|
|||
|
s32 color = getWrenNumber(vm, 3);
|
|||
|
memory->api.pixel(memory, x, y, color);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
wrenSetSlotDouble(vm, 0, memory->api.get_pixel(memory, x, y));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_line(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 x0 = getWrenNumber(vm, 1);
|
|||
|
s32 y0 = getWrenNumber(vm, 2);
|
|||
|
s32 x1 = getWrenNumber(vm, 3);
|
|||
|
s32 y1 = getWrenNumber(vm, 4);
|
|||
|
s32 color = getWrenNumber(vm, 5);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.line(memory, x0, y0, x1, y1, color);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_circ(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 radius = getWrenNumber(vm, 3);
|
|||
|
if(radius < 0) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
s32 x = getWrenNumber(vm, 1);
|
|||
|
s32 y = getWrenNumber(vm, 2);
|
|||
|
s32 color = getWrenNumber(vm, 4);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.circle(memory, x, y, radius, color);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_circb(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 radius = getWrenNumber(vm, 3);
|
|||
|
if(radius < 0) return;
|
|||
|
|
|||
|
s32 x = getWrenNumber(vm, 1);
|
|||
|
s32 y = getWrenNumber(vm, 2);
|
|||
|
s32 color = getWrenNumber(vm, 4);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.circle_border(memory, x, y, radius, color);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_rect(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 x = getWrenNumber(vm, 1);
|
|||
|
s32 y = getWrenNumber(vm, 2);
|
|||
|
s32 w = getWrenNumber(vm, 3);
|
|||
|
s32 h = getWrenNumber(vm, 4);
|
|||
|
s32 color = getWrenNumber(vm, 5);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.rect(memory, x, y, w, h, color);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_rectb(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 x = getWrenNumber(vm, 1);
|
|||
|
s32 y = getWrenNumber(vm, 2);
|
|||
|
s32 w = getWrenNumber(vm, 3);
|
|||
|
s32 h = getWrenNumber(vm, 4);
|
|||
|
s32 color = getWrenNumber(vm, 5);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.rect_border(memory, x, y, w, h, color);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_tri(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 pt[6];
|
|||
|
|
|||
|
for(s32 i = 0; i < COUNT_OF(pt); i++){
|
|||
|
pt[i] = getWrenNumber(vm, i+1);
|
|||
|
}
|
|||
|
|
|||
|
s32 color = getWrenNumber(vm, 7);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.tri(memory, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5], color);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_cls(WrenVM* vm)
|
|||
|
{
|
|||
|
int top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
memory->api.clear(memory, top == 1 ? 0 : getWrenNumber(vm, 1));
|
|||
|
}
|
|||
|
|
|||
|
static void wren_clip(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
if(top == 1)
|
|||
|
{
|
|||
|
memory->api.clip(memory, 0, 0, TIC80_WIDTH, TIC80_HEIGHT);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
s32 x = getWrenNumber(vm, 1);
|
|||
|
s32 y = getWrenNumber(vm, 2);
|
|||
|
s32 w = getWrenNumber(vm, 3);
|
|||
|
s32 h = getWrenNumber(vm, 4);
|
|||
|
|
|||
|
memory->api.clip(memory, x, y, w, h);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_peek(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
|
|||
|
s32 address = getWrenNumber(vm, 1);
|
|||
|
|
|||
|
if(address >= 0 && address < sizeof(tic_ram))
|
|||
|
{
|
|||
|
wrenSetSlotDouble(vm, 0, *((u8*)&machine->memory.ram + address));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_poke(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
|
|||
|
s32 address = getWrenNumber(vm, 1);
|
|||
|
u8 value = getWrenNumber(vm, 2) & 0xff;
|
|||
|
|
|||
|
if(address >= 0 && address < sizeof(tic_ram))
|
|||
|
{
|
|||
|
*((u8*)&machine->memory.ram + address) = value;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_peek4(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 address = getWrenNumber(vm, 1);
|
|||
|
|
|||
|
if(address >= 0 && address < sizeof(tic_ram)*2)
|
|||
|
{
|
|||
|
wrenSetSlotDouble(vm, 0, tic_tool_peek4((u8*)&getWrenMachine(vm)->memory.ram, address));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_poke4(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 address = getWrenNumber(vm, 1);
|
|||
|
u8 value = getWrenNumber(vm, 2);
|
|||
|
|
|||
|
if(address >= 0 && address < sizeof(tic_ram)*2)
|
|||
|
{
|
|||
|
tic_tool_poke4((u8*)&getWrenMachine(vm)->memory.ram, address, value);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_memcpy(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 dest = getWrenNumber(vm, 1);
|
|||
|
s32 src = getWrenNumber(vm, 2);
|
|||
|
s32 size = getWrenNumber(vm, 3);
|
|||
|
s32 bound = sizeof(tic_ram) - size;
|
|||
|
|
|||
|
if(size >= 0 && size <= sizeof(tic_ram) && dest >= 0 && src >= 0 && dest <= bound && src <= bound)
|
|||
|
{
|
|||
|
u8* base = (u8*)&getWrenMachine(vm)->memory;
|
|||
|
memcpy(base + dest, base + src, size);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_memset(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 dest = getWrenNumber(vm, 1);
|
|||
|
u8 value = getWrenNumber(vm, 2);
|
|||
|
s32 size = getWrenNumber(vm, 3);
|
|||
|
s32 bound = sizeof(tic_ram) - size;
|
|||
|
|
|||
|
if(size >= 0 && size <= sizeof(tic_ram) && dest >= 0 && dest <= bound)
|
|||
|
{
|
|||
|
u8* base = (u8*)&getWrenMachine(vm)->memory;
|
|||
|
memset(base + dest, value, size);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void wren_pmem(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
tic_mem* memory = &machine->memory;
|
|||
|
|
|||
|
u32 index = getWrenNumber(vm, 1);
|
|||
|
|
|||
|
if(index < TIC_PERSISTENT_SIZE)
|
|||
|
{
|
|||
|
s32 val = memory->persistent.data[index];
|
|||
|
|
|||
|
if(top > 2)
|
|||
|
{
|
|||
|
memory->persistent.data[index] = getWrenNumber(vm, 2);
|
|||
|
}
|
|||
|
|
|||
|
wrenSetSlotDouble(vm, 0, val);
|
|||
|
}
|
|||
|
else wrenError(vm, "invalid persistent memory index\n");
|
|||
|
}
|
|||
|
|
|||
|
static void wren_sfx(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
s32 index = getWrenNumber(vm, 1);
|
|||
|
|
|||
|
if(index < SFX_COUNT)
|
|||
|
{
|
|||
|
|
|||
|
s32 note = -1;
|
|||
|
s32 octave = -1;
|
|||
|
s32 duration = -1;
|
|||
|
s32 channel = 0;
|
|||
|
s32 volume = MAX_VOLUME;
|
|||
|
s32 speed = SFX_DEF_SPEED;
|
|||
|
|
|||
|
if (index >= 0)
|
|||
|
{
|
|||
|
tic_sample* effect = memory->ram.sfx.samples.data + index;
|
|||
|
|
|||
|
note = effect->note;
|
|||
|
octave = effect->octave;
|
|||
|
speed = effect->speed;
|
|||
|
}
|
|||
|
|
|||
|
if(top > 2)
|
|||
|
{
|
|||
|
if(isNumber(vm, 2))
|
|||
|
{
|
|||
|
s32 id = getWrenNumber(vm, 2);
|
|||
|
note = id % NOTES;
|
|||
|
octave = id / NOTES;
|
|||
|
}
|
|||
|
else if(isString(vm, 2))
|
|||
|
{
|
|||
|
const char* noteStr = wrenGetSlotString(vm, 2);
|
|||
|
|
|||
|
if(!tic_tool_parse_note(noteStr, ¬e, &octave))
|
|||
|
{
|
|||
|
wrenError(vm, "invalid note, should be like C#4\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if(top > 3)
|
|||
|
{
|
|||
|
duration = getWrenNumber(vm, 3);
|
|||
|
|
|||
|
if(top > 4)
|
|||
|
{
|
|||
|
channel = getWrenNumber(vm, 4);
|
|||
|
|
|||
|
if(top > 5)
|
|||
|
{
|
|||
|
volume = getWrenNumber(vm, 5);
|
|||
|
|
|||
|
if(top > 6)
|
|||
|
{
|
|||
|
speed = getWrenNumber(vm, 6);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (channel >= 0 && channel < TIC_SOUND_CHANNELS)
|
|||
|
{
|
|||
|
memory->api.sfx_stop(memory, channel);
|
|||
|
memory->api.sfx_ex(memory, index, note, octave, duration, channel, volume & 0xf, speed);
|
|||
|
}
|
|||
|
else wrenError(vm, "unknown channel\n");
|
|||
|
}
|
|||
|
else wrenError(vm, "unknown sfx index\n");
|
|||
|
}
|
|||
|
|
|||
|
static void wren_music(WrenVM* vm)
|
|||
|
{
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
s32 track = -1;
|
|||
|
s32 frame = -1;
|
|||
|
s32 row = -1;
|
|||
|
bool loop = true;
|
|||
|
|
|||
|
if(top > 1)
|
|||
|
{
|
|||
|
track = getWrenNumber(vm, 1);
|
|||
|
|
|||
|
if(top > 2)
|
|||
|
{
|
|||
|
frame = getWrenNumber(vm, 2);
|
|||
|
|
|||
|
if(top > 3)
|
|||
|
{
|
|||
|
row = getWrenNumber(vm, 3);
|
|||
|
|
|||
|
if(top > 4)
|
|||
|
{
|
|||
|
loop = wrenGetSlotBool(vm, 4);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
memory->api.music(memory, track, frame, row, loop);
|
|||
|
}
|
|||
|
|
|||
|
static void wren_time(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
wrenSetSlotDouble(vm, 0, memory->api.time(memory));
|
|||
|
}
|
|||
|
|
|||
|
static void wren_sync(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_mem* memory = (tic_mem*)getWrenMachine(vm);
|
|||
|
|
|||
|
bool toCart = true;
|
|||
|
u32 mask = 0;
|
|||
|
s32 bank = 0;
|
|||
|
|
|||
|
s32 top = wrenGetSlotCount(vm);
|
|||
|
|
|||
|
if(top > 1)
|
|||
|
{
|
|||
|
mask = getWrenNumber(vm, 1);
|
|||
|
|
|||
|
if(top > 2)
|
|||
|
{
|
|||
|
bank = getWrenNumber(vm, 2);
|
|||
|
|
|||
|
if(top > 3)
|
|||
|
{
|
|||
|
toCart = wrenGetSlotBool(vm, 3);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if(bank >= 0 && bank < TIC_BANKS)
|
|||
|
memory->api.sync(memory, mask, bank, toCart);
|
|||
|
else wrenError(vm, "sync() error, invalid bank");
|
|||
|
}
|
|||
|
|
|||
|
static void wren_reset(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
|
|||
|
machine->state.initialized = false;
|
|||
|
}
|
|||
|
|
|||
|
static void wren_exit(WrenVM* vm)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
|
|||
|
machine->data->exit(machine->data->data);
|
|||
|
}
|
|||
|
|
|||
|
static const char* const ApiKeywords[] = API_KEYWORDS;
|
|||
|
|
|||
|
WrenForeignMethodFn foreignTicMethods(const char* signature){
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.btn(_)" ) == 0) return wren_btn;
|
|||
|
if (strcmp(signature, "static Tic.btnp(_)" ) == 0) return wren_btnp;
|
|||
|
if (strcmp(signature, "static Tic.btnp(_,_,_)" ) == 0) return wren_btnp;
|
|||
|
if (strcmp(signature, "static Tic.key(_)" ) == 0) return wren_key;
|
|||
|
if (strcmp(signature, "static Tic.keyp(_)" ) == 0) return wren_keyp;
|
|||
|
if (strcmp(signature, "static Tic.keyp(_,_,_)" ) == 0) return wren_keyp;
|
|||
|
if (strcmp(signature, "static Tic.mouse()" ) == 0) return wren_mouse;
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.font(_)" ) == 0) return wren_font;
|
|||
|
if (strcmp(signature, "static Tic.font(_,_,_)" ) == 0) return wren_font;
|
|||
|
if (strcmp(signature, "static Tic.font(_,_,_,_)" ) == 0) return wren_font;
|
|||
|
if (strcmp(signature, "static Tic.font(_,_,_,_,_,_)" ) == 0) return wren_font;
|
|||
|
if (strcmp(signature, "static Tic.font(_,_,_,_,_,_,_)" ) == 0) return wren_font;
|
|||
|
if (strcmp(signature, "static Tic.font(_,_,_,_,_,_,_,_)" ) == 0) return wren_font;
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.spr(_)" ) == 0) return wren_spr;
|
|||
|
if (strcmp(signature, "static Tic.spr(_,_,_)" ) == 0) return wren_spr;
|
|||
|
if (strcmp(signature, "static Tic.spr(_,_,_,_)" ) == 0) return wren_spr;
|
|||
|
if (strcmp(signature, "static Tic.spr(_,_,_,_,_)" ) == 0) return wren_spr;
|
|||
|
if (strcmp(signature, "static Tic.spr(_,_,_,_,_,_)" ) == 0) return wren_spr;
|
|||
|
if (strcmp(signature, "static Tic.spr(_,_,_,_,_,_,_)" ) == 0) return wren_spr;
|
|||
|
if (strcmp(signature, "static Tic.spr(_,_,_,_,_,_,_,_,_)" ) == 0) return wren_spr;
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.map(_,_)" ) == 0) return wren_map;
|
|||
|
if (strcmp(signature, "static Tic.map(_,_,_,_)" ) == 0) return wren_map;
|
|||
|
if (strcmp(signature, "static Tic.map(_,_,_,_,_,_)" ) == 0) return wren_map;
|
|||
|
if (strcmp(signature, "static Tic.map(_,_,_,_,_,_,_)" ) == 0) return wren_map;
|
|||
|
if (strcmp(signature, "static Tic.map(_,_,_,_,_,_,_,_)" ) == 0) return wren_map;
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.mset(_,_)" ) == 0) return wren_mset;
|
|||
|
if (strcmp(signature, "static Tic.mset(_,_,_)" ) == 0) return wren_mset;
|
|||
|
if (strcmp(signature, "static Tic.mget(_,_)" ) == 0) return wren_mget;
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.textri(_,_,_,_,_,_,_,_,_,_,_,_)" ) == 0) return wren_textri;
|
|||
|
if (strcmp(signature, "static Tic.textri(_,_,_,_,_,_,_,_,_,_,_,_,_)" ) == 0) return wren_textri;
|
|||
|
if (strcmp(signature, "static Tic.textri(_,_,_,_,_,_,_,_,_,_,_,_,_,_)" ) == 0) return wren_textri;
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.pix(_,_)" ) == 0) return wren_pix;
|
|||
|
if (strcmp(signature, "static Tic.pix(_,_,_)" ) == 0) return wren_pix;
|
|||
|
if (strcmp(signature, "static Tic.line(_,_,_,_,_)" ) == 0) return wren_line;
|
|||
|
if (strcmp(signature, "static Tic.circ(_,_,_,_)" ) == 0) return wren_circ;
|
|||
|
if (strcmp(signature, "static Tic.circb(_,_,_,_)" ) == 0) return wren_circb;
|
|||
|
if (strcmp(signature, "static Tic.rect(_,_,_,_,_)" ) == 0) return wren_rect;
|
|||
|
if (strcmp(signature, "static Tic.rectb(_,_,_,_,_)" ) == 0) return wren_rectb;
|
|||
|
if (strcmp(signature, "static Tic.tri(_,_,_,_,_,_,_)" ) == 0) return wren_tri;
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.cls()" ) == 0) return wren_cls;
|
|||
|
if (strcmp(signature, "static Tic.cls(_)" ) == 0) return wren_cls;
|
|||
|
if (strcmp(signature, "static Tic.clip()" ) == 0) return wren_clip;
|
|||
|
if (strcmp(signature, "static Tic.clip(_,_,_,_)" ) == 0) return wren_clip;
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.peek(_)" ) == 0) return wren_peek;
|
|||
|
if (strcmp(signature, "static Tic.poke(_,_)" ) == 0) return wren_poke;
|
|||
|
if (strcmp(signature, "static Tic.peek4(_)" ) == 0) return wren_peek4;
|
|||
|
if (strcmp(signature, "static Tic.poke4(_,_)" ) == 0) return wren_poke4;
|
|||
|
if (strcmp(signature, "static Tic.memcpy(_,_,_)" ) == 0) return wren_memcpy;
|
|||
|
if (strcmp(signature, "static Tic.memset(_,_,_)" ) == 0) return wren_memset;
|
|||
|
if (strcmp(signature, "static Tic.pmem(_,_)" ) == 0) return wren_pmem;
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.sfx(_)" ) == 0) return wren_sfx;
|
|||
|
if (strcmp(signature, "static Tic.sfx(_,_)" ) == 0) return wren_sfx;
|
|||
|
if (strcmp(signature, "static Tic.sfx(_,_,_)" ) == 0) return wren_sfx;
|
|||
|
if (strcmp(signature, "static Tic.sfx(_,_,_,_)" ) == 0) return wren_sfx;
|
|||
|
if (strcmp(signature, "static Tic.sfx(_,_,_,_,_)" ) == 0) return wren_sfx;
|
|||
|
if (strcmp(signature, "static Tic.sfx(_,_,_,_,_,_)" ) == 0) return wren_sfx;
|
|||
|
if (strcmp(signature, "static Tic.music()" ) == 0) return wren_music;
|
|||
|
if (strcmp(signature, "static Tic.music(_)" ) == 0) return wren_music;
|
|||
|
if (strcmp(signature, "static Tic.music(_,_)" ) == 0) return wren_music;
|
|||
|
if (strcmp(signature, "static Tic.music(_,_,_)" ) == 0) return wren_music;
|
|||
|
|
|||
|
if (strcmp(signature, "static Tic.time()" ) == 0) return wren_time;
|
|||
|
if (strcmp(signature, "static Tic.sync()" ) == 0) return wren_sync;
|
|||
|
if (strcmp(signature, "static Tic.sync(_)" ) == 0) return wren_sync;
|
|||
|
if (strcmp(signature, "static Tic.sync(_,_)" ) == 0) return wren_sync;
|
|||
|
if (strcmp(signature, "static Tic.sync(_,_,_)" ) == 0) return wren_sync;
|
|||
|
if (strcmp(signature, "static Tic.reset()" ) == 0) return wren_reset;
|
|||
|
if (strcmp(signature, "static Tic.exit()" ) == 0) return wren_exit;
|
|||
|
|
|||
|
// internal functions
|
|||
|
if (strcmp(signature, "static Tic.map_width__" ) == 0) return wren_map_width;
|
|||
|
if (strcmp(signature, "static Tic.map_height__" ) == 0) return wren_map_height;
|
|||
|
if (strcmp(signature, "static Tic.spritesize__" ) == 0) return wren_spritesize;
|
|||
|
if (strcmp(signature, "static Tic.print__(_,_,_,_,_,_)" ) == 0) return wren_print;
|
|||
|
if (strcmp(signature, "static Tic.trace__(_,_)" ) == 0) return wren_trace;
|
|||
|
if (strcmp(signature, "static Tic.spr__(_,_,_,_,_,_,_)" ) == 0) return wren_spr_internal;
|
|||
|
if (strcmp(signature, "static Tic.mgeti__(_)" ) == 0) return wren_mgeti;
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
static WrenForeignMethodFn bindForeignMethod(
|
|||
|
WrenVM* vm, const char* module, const char* className,
|
|||
|
bool isStatic, const char* signature)
|
|||
|
{
|
|||
|
|
|||
|
if (strcmp(module, "main") != 0) return NULL;
|
|||
|
|
|||
|
// For convenience, concatenate all of the method qualifiers into a single
|
|||
|
// signature string.
|
|||
|
char fullName[256];
|
|||
|
fullName[0] = '\0';
|
|||
|
if (isStatic) {
|
|||
|
strcat(fullName, "static ");
|
|||
|
}
|
|||
|
|
|||
|
strcat(fullName, className);
|
|||
|
strcat(fullName, ".");
|
|||
|
strcat(fullName, signature);
|
|||
|
|
|||
|
WrenForeignMethodFn method = NULL;
|
|||
|
|
|||
|
method = foreignTicMethods(fullName);
|
|||
|
|
|||
|
return method;
|
|||
|
}
|
|||
|
|
|||
|
static void initAPI(tic_machine* machine)
|
|||
|
{
|
|||
|
wrenSetUserData(machine->wren, machine);
|
|||
|
|
|||
|
if (wrenInterpret(machine->wren, tic_wren_api) != WREN_RESULT_SUCCESS)
|
|||
|
{
|
|||
|
machine->data->error(machine->data->data, "can't load Tic wren api");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void reportError(WrenVM* vm, WrenErrorType type, const char* module, int line, const char* message)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
|
|||
|
char buffer[1024];
|
|||
|
|
|||
|
if (module)
|
|||
|
{
|
|||
|
snprintf(buffer, sizeof buffer, "\"%s\", %d ,\"%s\"",module, line, message);
|
|||
|
} else {
|
|||
|
snprintf(buffer, sizeof buffer, "%d, \"%s\"",line, message);
|
|||
|
}
|
|||
|
|
|||
|
machine->data->error(machine->data->data, buffer);
|
|||
|
}
|
|||
|
|
|||
|
static void writeFn(WrenVM* vm, const char* text)
|
|||
|
{
|
|||
|
tic_machine* machine = getWrenMachine(vm);
|
|||
|
u8 color = tic_color_blue;
|
|||
|
machine->data->trace(machine->data->data, text ? text : "null", color);
|
|||
|
}
|
|||
|
|
|||
|
static bool initWren(tic_mem* tic, const char* code)
|
|||
|
{
|
|||
|
tic_machine* machine = (tic_machine*)tic;
|
|||
|
closeWren(tic);
|
|||
|
|
|||
|
WrenConfiguration config;
|
|||
|
wrenInitConfiguration(&config);
|
|||
|
|
|||
|
config.bindForeignMethodFn = bindForeignMethod;
|
|||
|
|
|||
|
config.errorFn = reportError;
|
|||
|
config.writeFn = writeFn;
|
|||
|
|
|||
|
WrenVM* vm = machine->wren = wrenNewVM(&config);
|
|||
|
|
|||
|
initAPI(machine);
|
|||
|
|
|||
|
if (wrenInterpret(machine->wren, code) != WREN_RESULT_SUCCESS){
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
loaded = true;
|
|||
|
|
|||
|
// make handles
|
|||
|
wrenEnsureSlots(vm, 1);
|
|||
|
wrenGetVariable(vm, "main", "Game", 0);
|
|||
|
game_class = wrenGetSlotHandle(vm, 0); // handle from game class
|
|||
|
|
|||
|
new_handle = wrenMakeCallHandle(vm, "new()");
|
|||
|
update_handle = wrenMakeCallHandle(vm, "update()");
|
|||
|
scanline_handle = wrenMakeCallHandle(vm, "scanline(_)");
|
|||
|
overlap_handle = wrenMakeCallHandle(vm, "overlap()");
|
|||
|
|
|||
|
// create game class
|
|||
|
if (game_class)
|
|||
|
{
|
|||
|
wrenEnsureSlots(vm, 1);
|
|||
|
wrenSetSlotHandle(vm, 0, game_class);
|
|||
|
wrenCall(vm, new_handle);
|
|||
|
wrenReleaseHandle(machine->wren, game_class); // release game class handle
|
|||
|
game_class = NULL;
|
|||
|
if (wrenGetSlotCount(vm) == 0) {
|
|||
|
machine->data->error(machine->data->data, "Error in game class :(");
|
|||
|
return false;
|
|||
|
}
|
|||
|
game_class = wrenGetSlotHandle(vm, 0); // handle from game object
|
|||
|
} else {
|
|||
|
machine->data->error(machine->data->data, "'Game class' isn't found :(");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
static void callWrenTick(tic_mem* tic)
|
|||
|
{
|
|||
|
tic_machine* machine = (tic_machine*)tic;
|
|||
|
WrenVM* vm = machine->wren;
|
|||
|
|
|||
|
if(vm && game_class)
|
|||
|
{
|
|||
|
wrenEnsureSlots(vm, 1);
|
|||
|
wrenSetSlotHandle(vm, 0, game_class);
|
|||
|
wrenCall(vm, update_handle);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void callWrenScanline(tic_mem* memory, s32 row, void* data)
|
|||
|
{
|
|||
|
tic_machine* machine = (tic_machine*)memory;
|
|||
|
WrenVM* vm = machine->wren;
|
|||
|
|
|||
|
if(vm && game_class)
|
|||
|
{
|
|||
|
wrenEnsureSlots(vm, 2);
|
|||
|
wrenSetSlotHandle(vm, 0, game_class);
|
|||
|
wrenSetSlotDouble(vm, 1, row);
|
|||
|
wrenCall(vm, scanline_handle);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void callWrenOverlap(tic_mem* memory, void* data)
|
|||
|
{
|
|||
|
tic_machine* machine = (tic_machine*)memory;
|
|||
|
WrenVM* vm = machine->wren;
|
|||
|
|
|||
|
if (vm && game_class)
|
|||
|
{
|
|||
|
wrenEnsureSlots(vm, 1);
|
|||
|
wrenSetSlotHandle(vm, 0, game_class);
|
|||
|
wrenCall(vm, overlap_handle);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static const char* const WrenKeywords [] =
|
|||
|
{
|
|||
|
"false", "true", "null", "break", "class", "construct",
|
|||
|
"else", "for", "foreign", "if", "import", "in", "is",
|
|||
|
"return", "static", "super", "var", "while", "this"
|
|||
|
};
|
|||
|
|
|||
|
static inline bool isalnum_(char c) {return isalnum(c) || c == '_';}
|
|||
|
|
|||
|
static const tic_outline_item* getWrenOutline(const char* code, s32* size)
|
|||
|
{
|
|||
|
enum{Size = sizeof(tic_outline_item)};
|
|||
|
|
|||
|
*size = 0;
|
|||
|
|
|||
|
static tic_outline_item* items = NULL;
|
|||
|
|
|||
|
if(items)
|
|||
|
{
|
|||
|
free(items);
|
|||
|
items = NULL;
|
|||
|
}
|
|||
|
|
|||
|
const char* ptr = code;
|
|||
|
|
|||
|
while(true)
|
|||
|
{
|
|||
|
static const char FuncString[] = "function ";
|
|||
|
|
|||
|
ptr = strstr(ptr, FuncString);
|
|||
|
|
|||
|
if(ptr)
|
|||
|
{
|
|||
|
ptr += sizeof FuncString - 1;
|
|||
|
|
|||
|
const char* start = ptr;
|
|||
|
const char* end = start;
|
|||
|
|
|||
|
while(*ptr)
|
|||
|
{
|
|||
|
char c = *ptr;
|
|||
|
|
|||
|
if(isalnum_(c));
|
|||
|
else if(c == '(')
|
|||
|
{
|
|||
|
end = ptr;
|
|||
|
break;
|
|||
|
}
|
|||
|
else break;
|
|||
|
|
|||
|
ptr++;
|
|||
|
}
|
|||
|
|
|||
|
if(end > start)
|
|||
|
{
|
|||
|
items = items ? realloc(items, (*size + 1) * Size) : malloc(Size);
|
|||
|
|
|||
|
items[*size].pos = start - code;
|
|||
|
items[*size].size = end - start;
|
|||
|
|
|||
|
(*size)++;
|
|||
|
}
|
|||
|
}
|
|||
|
else break;
|
|||
|
}
|
|||
|
|
|||
|
return items;
|
|||
|
}
|
|||
|
|
|||
|
static const tic_script_config WrenSyntaxConfig =
|
|||
|
{
|
|||
|
.init = initWren,
|
|||
|
.close = closeWren,
|
|||
|
.tick = callWrenTick,
|
|||
|
.scanline = callWrenScanline,
|
|||
|
.overlap = callWrenOverlap,
|
|||
|
|
|||
|
.getOutline = getWrenOutline,
|
|||
|
.parse = parseCode,
|
|||
|
|
|||
|
.blockCommentStart = "/*",
|
|||
|
.blockCommentEnd = "*/",
|
|||
|
.blockStringStart = NULL,
|
|||
|
.blockStringEnd = NULL,
|
|||
|
.singleComment = "//",
|
|||
|
|
|||
|
.keywords = WrenKeywords,
|
|||
|
.keywordsCount = COUNT_OF(WrenKeywords),
|
|||
|
|
|||
|
.api = ApiKeywords,
|
|||
|
.apiCount = COUNT_OF(ApiKeywords),
|
|||
|
};
|
|||
|
|
|||
|
const tic_script_config* getWrenScriptConfig()
|
|||
|
{
|
|||
|
return &WrenSyntaxConfig;
|
|||
|
}
|