duk_ret_t nsp_texture_set_pixel(duk_context *ctx) { int x = duk_require_int(ctx, 0); int y = duk_require_int(ctx, 1); uint16_t color = duk_require_int(ctx, 2); duk_push_this(ctx); duk_get_prop_string(ctx, -1, "width"); int w = duk_require_int(ctx, -1); duk_pop(ctx); duk_get_prop_string(ctx, -1, "height"); int h = duk_require_int(ctx, -1); duk_pop(ctx); if (w <= 0 || h <= 0) { duk_push_error_object(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive"); duk_throw(ctx); } duk_get_prop_string(ctx, -1, "bitmap"); size_t size; uint16_t *bitmap = duk_get_buffer(ctx, -1, &size); if (bitmap == NULL) { duk_push_error_object(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL"); duk_throw(ctx); } if (0 <= x && x < w && 0 <= y && y < h && size >= (size_t)(w * h * 2)) { bitmap[w * y + x] = (uint16_t)color; return 0; } else { duk_push_error_object(ctx, DUK_ERR_RANGE_ERROR, "coordinates out of range"); duk_throw(ctx); } }
static duk_ret_t js_Font_drawZoomedText(duk_context* ctx) { int x = duk_require_int(ctx, 0); int y = duk_require_int(ctx, 1); float scale = duk_require_number(ctx, 2); const char* text = duk_to_string(ctx, 3); ALLEGRO_BITMAP* bitmap; font_t* font; color_t mask; int text_w, text_h; duk_push_this(ctx); font = duk_require_sphere_obj(ctx, -1, "Font"); duk_get_prop_string(ctx, -1, "\xFF" "color_mask"); mask = duk_require_sphere_color(ctx, -1); duk_pop(ctx); duk_pop(ctx); if (!screen_is_skipframe(g_screen)) { text_w = get_text_width(font, text); text_h = get_font_line_height(font); bitmap = al_create_bitmap(text_w, text_h); al_set_target_bitmap(bitmap); draw_text(font, mask, 0, 0, TEXT_ALIGN_LEFT, text); al_set_target_backbuffer(screen_display(g_screen)); al_draw_scaled_bitmap(bitmap, 0, 0, text_w, text_h, x, y, text_w * scale, text_h * scale, 0x0); al_destroy_bitmap(bitmap); } return 0; }
static duk_ret_t nsp_texture_constructor(duk_context *ctx) { int width = duk_require_int(ctx, 0); int height = duk_require_int(ctx, 1); if (width < 1 || height < 1) { duk_push_error_object(ctx, DUK_ERR_RANGE_ERROR, "Width and height must be positive"); duk_throw(ctx); } bool has_transparency; uint16_t transparent_color; if ((has_transparency = duk_is_number(ctx, 2))) { transparent_color = (uint16_t)duk_get_int(ctx, 2); } duk_push_this(ctx); duk_push_fixed_buffer(ctx, width * height * 2); duk_put_prop_string(ctx, -2, "bitmap"); duk_push_int(ctx, width); duk_put_prop_string(ctx, -2, "width"); duk_push_int(ctx, height); duk_put_prop_string(ctx, -2, "height"); if (has_transparency) { duk_push_int(ctx, transparent_color); } else { duk_push_null(ctx); } duk_put_prop_string(ctx, -2, "transparentColor"); return 0; }
int js_getplayer(duk_context* c) { int index = duk_require_int(c, -1); int off = duk_require_int(c, -2); const char* str = duk_require_string(c, -3); printf("-1 = %d\n", index); printf("-2 = %d\n", off); printf("-3 = %s\n", str); ENTITY* ent = game->getEntity(index); if(ent) { int v; ent->get(off, &v, sizeof(v)); duk_push_int(c,v); } else { duk_push_int(c,-1); } /*if(!strcmp(str, "int")) { printf("off = %d\n", *(int*)off); duk_push_int(ctx, *(int*)off); } else if(!strcmp(str, "float")) { duk_push_number(ctx, *(float*)off); } else if(!strcmp(str, "string")) { duk_push_string(ctx, (const char*)off); } else if(!strcmp(str, "byte")) { duk_push_int(ctx, *(byte*)off); }*/ return 1; }
static duk_ret_t js_PointSeries(duk_context* ctx) { duk_require_object_coercible(ctx, 0); color_t color = duk_require_sphere_color(ctx, 1); size_t num_points; int x, y; ALLEGRO_VERTEX* vertices; ALLEGRO_COLOR vtx_color; size_t i; if (!duk_is_array(ctx, 0)) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "PointSeries(): First argument must be an array"); duk_get_prop_string(ctx, 0, "length"); num_points = duk_get_uint(ctx, 0); duk_pop(ctx); if (num_points < 1) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "PointSeries(): One or more vertices required"); if (num_points > INT_MAX) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "PointSeries(): Too many vertices"); if ((vertices = calloc(num_points, sizeof(ALLEGRO_VERTEX))) == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "PointSeries(): Failed to allocate vertex buffer"); vtx_color = nativecolor(color); for (i = 0; i < num_points; ++i) { duk_get_prop_index(ctx, 0, (duk_uarridx_t)i); duk_get_prop_string(ctx, 0, "x"); x = duk_require_int(ctx, -1); duk_pop(ctx); duk_get_prop_string(ctx, 0, "y"); y = duk_require_int(ctx, -1); duk_pop(ctx); duk_pop(ctx); vertices[i].x = x + 0.5; vertices[i].y = y + 0.5; vertices[i].color = vtx_color; } al_draw_prim(vertices, NULL, NULL, 0, (int)num_points, ALLEGRO_PRIM_POINT_LIST); free(vertices); return 0; }
/* * Read data from a fd. Args: * - 0: fd * - 1: nread * TODO: * - use buffers */ static duk_ret_t io_read(duk_context* ctx) { int fd; ssize_t r; size_t nread; char* buf; fd = duk_require_int(ctx, 0); nread = duk_require_int(ctx, 1); buf = malloc(nread); if (!buf) { SJS_THROW_ERRNO_ERROR2(ENOMEM); return -42; /* control never returns here */ } r = read(fd, buf, nread); if (r < 0) { SJS_THROW_ERRNO_ERROR(); return -42; /* control never returns here */ } else if (r == 0) { /* EOF */ duk_push_string(ctx, ""); } else { duk_push_lstring(ctx, buf, r); } return 1; }
int js_setint(duk_context* c) { int* ptr = (int*)duk_require_pointer(c, -1); int off = duk_require_int(c, -2); int value = duk_require_int(c, -3); ptr+=off; *ptr = value; return 0; }
static int NativeIoSpi(duk_context* ctx) { uint32_t mosi, miso, cs, clk, clock; uint8_t master; uint8_t cpol, cpha, data; void* spiCtx; AJ_Status status; int idx; mosi = GetPinId(ctx, 0, AJS_IO_FUNCTION_SPI_MOSI); miso = GetPinId(ctx, 1, AJS_IO_FUNCTION_SPI_MISO); cs = GetPinId(ctx, 2, AJS_IO_FUNCTION_SPI_SS); clk = GetPinId(ctx, 3, AJS_IO_FUNCTION_SPI_SCK); duk_get_prop_string(ctx, 4, "clock"); clock = duk_require_int(ctx, -1); duk_get_prop_string(ctx, 4, "master"); if (duk_get_boolean(ctx, -1)) { master = TRUE; } else { master = FALSE; } duk_get_prop_string(ctx, 4, "cpol"); cpol = duk_require_int(ctx, -1); duk_get_prop_string(ctx, 4, "cpha"); cpha = duk_require_int(ctx, -1); duk_get_prop_string(ctx, 4, "data"); data = duk_require_int(ctx, -1); duk_pop(ctx); // Clock polarity must be high (1) or low (0) if (cpol != 0 && cpol != 1) { duk_error(ctx, DUK_ERR_INTERNAL_ERROR, "cpol must be 0 or 1; you gave %u", cpol); } // Clock edge phase must be one edge (0) or two edge (1) if (cpha != 0 && cpha != 1) { duk_error(ctx, DUK_ERR_INTERNAL_ERROR, "cpha must be 0 or 1; you gave %u", cpha); } // Data bits must be 8, 16, or 32 if (data != 8 && data != 16 && data != 32) { duk_error(ctx, DUK_ERR_INTERNAL_ERROR, "data bits must be 8, 16 or 32; you gave %u", data); } status = AJS_TargetIO_SpiOpen(mosi, miso, cs, clk, clock, master, cpol, cpha, data, &spiCtx); if (status != AJ_OK) { duk_error(ctx, DUK_ERR_INTERNAL_ERROR, "Failed to open SPI device"); } idx = NewIOObject(ctx, spiCtx, AJS_IO_FUNCTION_SPI, NativeSpiFinalizer); duk_push_c_lightfunc(ctx, NativeSpiRead, 1, 0, 0); duk_put_prop_string(ctx, idx, "read"); duk_push_c_lightfunc(ctx, NativeSpiWrite, 1, 0, 0); duk_put_prop_string(ctx, idx, "write"); return 1; }
int js_setentint(duk_context* c) { int index = duk_require_int(c,-1); int offset = duk_require_int(c,-2); int value = duk_require_int(c,-3); ENTITY* ent = game->getEntity(index); if(ent) { ent->set(offset, &value, sizeof(value)); } return 0; }
static duk_ret_t js_Point(duk_context* ctx) { float x = duk_require_int(ctx, 0) + 0.5; float y = duk_require_int(ctx, 1) + 0.5; color_t color = duk_require_sphere_color(ctx, 2); if (!is_skipped_frame()) al_draw_pixel(x, y, nativecolor(color)); return 0; }
static duk_ret_t js_SetClippingRectangle(duk_context* ctx) { int x = duk_require_int(ctx, 0); int y = duk_require_int(ctx, 1); int width = duk_require_int(ctx, 2); int height = duk_require_int(ctx, 3); set_clip_rectangle(new_rect(x, y, x + width, y + height)); return 0; }
static duk_ret_t js_Rectangle(duk_context* ctx) { int x = duk_require_int(ctx, 0); int y = duk_require_int(ctx, 1); int w = duk_require_int(ctx, 2); int h = duk_require_int(ctx, 3); color_t color = duk_require_sphere_color(ctx, 4); if (!is_skipped_frame()) al_draw_filled_rectangle(x, y, x + w, y + h, nativecolor(color)); return 0; }
static duk_ret_t js_Line(duk_context* ctx) { int x1 = duk_require_int(ctx, 0); int y1 = duk_require_int(ctx, 1); int x2 = duk_require_int(ctx, 2); int y2 = duk_require_int(ctx, 3); color_t color = duk_require_sphere_color(ctx, 4); if (!is_skipped_frame()) al_draw_line(x1, y1, x2, y2, nativecolor(color), 1); return 0; }
int js_setplayer(duk_context* c) { int player = duk_require_int(c, -1); int duk_off = duk_require_int(c, -2); int off = (gentities + GENTITY_SIZE * player) + duk_off; const char* str = duk_require_string(c, -3); if(!strcmp(str, "int")) { *(int*)off = duk_require_int(c,-4); } else if(!strcmp(str, "float")) { *(float*)off = duk_require_number(c,-4); } else if(!strcmp(str, "byte")) { *(byte*)off=duk_require_int(c,-4); } return 0; }
static duk_ret_t native_prime_check(duk_context *ctx) { int val = duk_require_int(ctx, 0); int lim = duk_require_int(ctx, 1); int i; for (i = 2; i <= lim; i++) { if (val % i == 0) { duk_push_false(ctx); return 1; } } duk_push_true(ctx); return 1; }
static int set_timer(duk_context *duk, int repeat) { es_context_t *ec = es_get(duk); es_timer_t *et = es_resource_create(ec, &es_resource_timer, 1); int val = duk_require_int(duk, 1); es_root_register(duk, 0, et); et->et_interval = val * repeat; int64_t now = arch_get_ts(); et->et_expire = now + val * 1000LL; hts_mutex_lock(&timer_mutex); if(thread_running == 0) { thread_running = 1; hts_thread_create_detached("estimer", timer_thread, NULL, THREAD_PRIO_MODEL); } else { hts_cond_signal(&timer_cond); } LIST_INSERT_SORTED(&timers, et, et_link, estimercmp, es_timer_t); hts_mutex_unlock(&timer_mutex); es_resource_push(duk, &et->super); return 1; }
static duk_ret_t js_Font_wordWrapString(duk_context* ctx) { const char* text = duk_to_string(ctx, 0); int width = duk_require_int(ctx, 1); font_t* font; int num_lines; wraptext_t* wraptext; int i; duk_push_this(ctx); font = duk_require_sphere_obj(ctx, -1, "Font"); duk_pop(ctx); wraptext = word_wrap_text(font, text, width); num_lines = get_wraptext_line_count(wraptext); duk_push_array(ctx); for (i = 0; i < num_lines; ++i) { duk_push_string(ctx, get_wraptext_line(wraptext, i)); duk_put_prop_index(ctx, -2, i); } free_wraptext(wraptext); return 1; }
static duk_ret_t js_OutlinedRoundRectangle(duk_context* ctx) { int n_args = duk_get_top(ctx); float x = duk_require_int(ctx, 0) + 0.5; float y = duk_require_int(ctx, 1) + 0.5; int w = duk_require_int(ctx, 2); int h = duk_require_int(ctx, 3); float radius = duk_require_number(ctx, 4); color_t color = duk_require_sphere_color(ctx, 5); int thickness = n_args >= 7 ? duk_require_int(ctx, 6) : 1; if (!is_skipped_frame()) al_draw_rounded_rectangle(x, y, x + w - 1, y + h - 1, radius, radius, nativecolor(color), thickness); return 0; }
static duk_ret_t js_RawFile_read(duk_context* ctx) { int n_args = duk_get_top(ctx); long num_bytes = n_args >= 1 ? duk_require_int(ctx, 0) : 0; bytearray_t* array; FILE* file; long pos; void* read_buffer; duk_push_this(ctx); file = duk_require_sphere_obj(ctx, -1, "RawFile"); duk_pop(ctx); if (file == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:read(): File has been closed"); if (n_args < 1) { // if no arguments, read entire file back to front pos = ftell(file); num_bytes = (fseek(file, 0, SEEK_END), ftell(file)); fseek(file, 0, SEEK_SET); } if (num_bytes <= 0) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "RawFile:read(): Read size out of range (%u)", num_bytes); if (!(read_buffer = malloc(num_bytes))) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:read(): Failed to allocate buffer for file read"); num_bytes = (long)fread(read_buffer, 1, num_bytes, file); if (n_args < 1) // reset file position after whole-file read fseek(file, pos, SEEK_SET); if (!(array = bytearray_from_buffer(read_buffer, (int)num_bytes))) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:read(): Failed to create byte array"); duk_push_sphere_bytearray(ctx, array); return 1; }
/* * Set buffering type for file object. Args: * - 0: FILE * - 1: mode (0 is unbuffered, 1 is line buffered) */ static duk_ret_t io_setvbuf(duk_context* ctx) { FILE* f; int mode; size_t size; f = duk_require_pointer(ctx, 0); mode = duk_require_int(ctx, 1); if (mode == 0) { mode = _IONBF; size = 0; } else if (mode == 1) { mode = _IOLBF; size = BUFSIZ; } else { abort(); } /* * Ignore erros. According to the man page: "It may set errno on failure.". Sigh. */ (void) setvbuf(f, NULL, mode, size); duk_push_undefined(ctx); return 1; }
static int NativeI2cTransfer(duk_context* ctx) { AJ_Status status; uint8_t addr = duk_require_int(ctx, 0); uint8_t* txBuf = NULL; uint8_t* rxBuf = NULL; duk_size_t txLen = 0; duk_size_t rxLen = 0; uint8_t rxBytes = 0; if (duk_is_undefined(ctx, 2)) { duk_push_undefined(ctx); } else { rxLen = duk_require_uint(ctx, 2); rxBuf = duk_push_dynamic_buffer(ctx, rxLen); } if (duk_is_null(ctx, 1)) { duk_push_undefined(ctx); } else { txBuf = SerializeToBuffer(ctx, 1, &txLen); } status = AJS_TargetIO_I2cTransfer(PinCtxPtr(ctx), addr, txBuf, txLen, rxBuf, rxLen, &rxBytes); if (status != AJ_OK) { duk_error(ctx, DUK_ERR_INTERNAL_ERROR, "I2C transfer failed %s\n", AJ_StatusText(status)); } duk_pop(ctx); if (rxLen) { duk_resize_buffer(ctx, -1, rxBytes); } return 1; }
static int NativeSpiRead(duk_context* ctx) { int size = duk_require_int(ctx, -1); void* ptr = duk_push_fixed_buffer(ctx, size); AJS_TargetIO_SpiRead(PinCtxPtr(ctx), size, ptr); return 1; }
int js_getint(duk_context* c) { int* ptr = (int*)duk_require_pointer(c, -1); int off = duk_require_int(c,-2); ptr+=off; duk_push_int(c,*ptr); return 1; }
/* * Returns the pid id for a pin object. Also checks that the pin supports the requested function. */ static uint32_t GetPinId(duk_context* ctx, int idx, uint32_t function) { uint32_t id; if (!duk_is_object(ctx, idx)) { duk_error(ctx, DUK_ERR_TYPE_ERROR, "Requires a pin object"); } /* * Get pin id */ duk_get_prop_string(ctx, idx, "id"); id = duk_require_int(ctx, -1); duk_pop(ctx); /* * Check that the required I/O function is supported */ if (function) { const AJS_IO_Info* info = AJS_TargetIO_GetInfo(id); if (!info) { duk_error(ctx, DUK_ERR_INTERNAL_ERROR, "Undefined I/O pin%d", id); return 0; } if (!(info->functions & function)) { duk_error(ctx, DUK_ERR_TYPE_ERROR, "I/O function %s not supported on pin%d", AJS_IO_FunctionName(function), id); } } return id; }
static int NativePWM(duk_context* ctx) { AJ_Status status; double dutyCycle = duk_require_number(ctx, 0); uint32_t freq = 0; if (dutyCycle > 1.0 || dutyCycle < 0.0) { duk_error(ctx, DUK_ERR_RANGE_ERROR, "Duty cycle must be in the range 0.0 to 1.0"); } /* * Frequency is optional. If not specified zero is passed into the target code and the default * target PWM frequency is used. */ if (!duk_is_undefined(ctx, 1)) { freq = duk_require_int(ctx, 1); if (freq == 0) { duk_error(ctx, DUK_ERR_RANGE_ERROR, "Frequency cannot be zero Hz"); } } status = AJS_TargetIO_PinPWM(PinCtxPtr(ctx), dutyCycle, freq); if (status != AJ_OK) { if (status == AJ_ERR_RESOURCES) { duk_error(ctx, DUK_ERR_RANGE_ERROR, "Too many PWM pins"); } else { duk_error(ctx, DUK_ERR_INTERNAL_ERROR, "Error setting PWM %s", AJ_StatusText(status)); } } return 0; }
static int NativeUartRead(duk_context* ctx) { duk_size_t len = duk_require_int(ctx, 0); len = AJS_TargetIO_UartRead(PinCtxPtr(ctx), duk_push_dynamic_buffer(ctx, len), len); duk_resize_buffer(ctx, -1, len); return 1; }
static duk_ret_t js_Font_drawText(duk_context* ctx) { int x = duk_require_int(ctx, 0); int y = duk_require_int(ctx, 1); const char* text = duk_to_string(ctx, 2); font_t* font; color_t mask; duk_push_this(ctx); duk_get_prop_string(ctx, -1, "\xFF" "ptr"); font = duk_get_pointer(ctx, -1); duk_pop(ctx); duk_get_prop_string(ctx, -1, "\xFF" "color_mask"); mask = duk_require_sphere_color(ctx, -1); duk_pop(ctx); duk_pop(ctx); if (!is_skipped_frame()) draw_text(font, mask, x, y, TEXT_ALIGN_LEFT, text); return 0; }
duk_ret_t nsp_texture_fill_polygon(duk_context *ctx) { duk_require_object_coercible(ctx, 0); int* xys = getIntArray(ctx,0); int nbPts = duk_require_int(ctx, 1); uint16_t color = duk_require_int(ctx, 2); duk_push_this(ctx); duk_get_prop_string(ctx, -1, "width"); int w = duk_require_int(ctx, -1); duk_pop(ctx); duk_get_prop_string(ctx, -1, "height"); int h = duk_require_int(ctx, -1); duk_pop(ctx); if (w <= 0 || h <= 0) { duk_push_error_object(ctx, DUK_ERR_RANGE_ERROR, "width and height must be positive"); duk_throw(ctx); } duk_get_prop_string(ctx, -1, "bitmap"); size_t size; uint16_t *bitmap = duk_get_buffer(ctx, -1, &size); if (bitmap == NULL) { duk_push_error_object(ctx, DUK_ERR_ERROR, "bitmap pointer is NULL"); duk_throw(ctx); } FbDev* fb = (FbDev*)malloc( 1 * sizeof(FbDev) ); fb->width = w; fb->height = h; fb->fb_size = w * h; fb->fb = bitmap; fillPolygon( xys, nbPts, color, fb ); free(fb); return 0; }
static int NativePinSetTrigger(duk_context* ctx) { uint32_t debounce = 0; AJS_IO_PinTriggerCondition condition = (AJS_IO_PinTriggerCondition)duk_require_int(ctx, 0); if (condition & AJS_IO_PIN_TRIGGER_ON_BOTH) { if (duk_is_number(ctx, 2)) { debounce = duk_get_int(ctx, 2); debounce = min(255, debounce); } } return SetTriggerCallback(ctx, AJS_IO_FUNCTION_DIGITAL_IN, debounce); }
static duk_ret_t pwd_getpwuid(duk_context* ctx) { uid_t uid; long initsize; char* buf; size_t bufsize; struct passwd pw; struct passwd* rpw; int r; uid = duk_require_int(ctx, 0); initsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (initsize <= 0) { bufsize = 4096; } else { bufsize = (size_t) initsize; } buf = NULL; for (;;) { free(buf); buf = malloc(bufsize); if (buf == NULL) { SJS_THROW_ERRNO_ERROR2(ENOMEM); return -42; /* control never returns here */ } r = getpwuid_r(uid, &pw, buf, bufsize, &rpw); if (r != ERANGE) { break; } bufsize *= 2; } if (r != 0) { SJS_THROW_ERRNO_ERROR2(r); return -42; /* control never returns here */ } if (rpw == NULL) { free(buf); duk_push_null(ctx); return 1; } else { passwd2obj(ctx, &pw); return 1; } }