Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions compat/configure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,14 @@ int main(void){return round(0);}
check '' round $lm > /dev/null &
round_pid=$!

printf '%s' "\
#include <math.h>
int main(void){return trunc(0);}
" > tmp/trunc.c

check '' trunc $lm > /dev/null &
trunc_pid=$!

printf '%s' "\
#include <math.h>
int main(void){return log2(1);}
Expand Down Expand Up @@ -356,6 +364,14 @@ int main(void){return roundf(0);}
check '' roundf $lm > /dev/null &
roundf_pid=$!

printf '%s' "\
#include <math.h>
int main(void){return truncf(0);}
" > tmp/truncf.c

check '' truncf $lm > /dev/null &
truncf_pid=$!

printf '%s' "\
#include <math.h>
int main(void){return isinf(0.0);}
Expand Down Expand Up @@ -469,6 +485,10 @@ if ! checkend 'for round' "$round_pid"; then
define 'NO_ROUND'
fi

if ! checkend 'for trunc' "$truncf_pid"; then
define 'NO_TRUNC'
fi

if ! checkend 'for log2' "$log2_pid"; then
define 'NO_LOG2'
fi
Expand Down Expand Up @@ -505,6 +525,10 @@ if ! checkend 'for roundf' "$roundf_pid"; then
define 'NO_ROUNDF'
fi

if ! checkend 'for truncf' "$truncf_pid"; then
define 'NO_TRUNCF'
fi

if ! checkend 'for isinf' "$isinf_pid"; then
define 'NO_ISINF'
fi
Expand Down
21 changes: 21 additions & 0 deletions src/math_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ static GMLReal GMLReal_round(GMLReal x) {

#endif

#ifdef NO_TRUNC

#undef GMLReal_trunc
static GMLReal GMLReal_trunc(GMLReal x) {
if (x >= 9007199254740992.0 || x <= -9007199254740992.0) return x;
if (x >= 0.0) return (GMLReal)((int64_t)x);
else return (GMLReal)((int64_t)x);
}

#endif

#ifdef NO_LOG2

#undef GMLReal_log2
Expand Down Expand Up @@ -112,6 +123,16 @@ static float roundf(float x) {

#endif

#ifdef NO_TRUNCF

static float truncf(float x) {
if (x >= 2147483648.0f || x <= -2147483648.0f) return x;
if (x >= 0.0f) return (float)((int32_t)x);
else return (float)((int32_t)x);
}

#endif

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
Expand Down
2 changes: 2 additions & 0 deletions src/real_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ typedef float GMLReal;
#define GMLReal_floor floorf
#define GMLReal_ceil ceilf
#define GMLReal_round roundf
#define GMLReal_trunc truncf
#define GMLReal_pow powf
#define GMLReal_log2 log2f
#define GMLReal_fmax fmaxf
Expand All @@ -58,6 +59,7 @@ typedef double GMLReal;
#define GMLReal_floor floor
#define GMLReal_ceil ceil
#define GMLReal_round round
#define GMLReal_trunc trunc
#define GMLReal_pow pow
#define GMLReal_log2 log2
#define GMLReal_fmax fmax
Expand Down
13 changes: 9 additions & 4 deletions src/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1553,12 +1553,17 @@ static void handleDiv(VMContext* ctx, uint32_t instr) {
static void handleRem(VMContext* ctx, uint32_t instr) {
RValue b = stackPop(ctx);
RValue a = stackPop(ctx);
int64_t divisor = RValue_toInt64(b);
requireMessageFormatted(__FILE__, __LINE__, divisor != 0, "VM: [%s] DoRem :: Divide by zero", ctx->currentCodeName);
int64_t result = RValue_toInt64(a) / divisor;
uint8_t type1 = instrType1(instr);
uint8_t type2 = instrType2(instr);
GMLReal divisor = RValue_toReal(b);
// Ditto
if ((type1 == GML_TYPE_INT32 || type1 == GML_TYPE_INT64) && (type2 == GML_TYPE_INT32 || type2 == GML_TYPE_INT64)) {
requireMessageFormatted(__FILE__, __LINE__, divisor != 0.0, "VM: [%s] DoRem :: Divide by zero", ctx->currentCodeName);
}
GMLReal result = GMLReal_trunc(RValue_toReal(a) / divisor);
RValue_free(&a);
RValue_free(&b);
stackPushTyped(ctx, RValue_makeInt64(result), instrType2(instr));
stackPushTyped(ctx, RValue_makeReal(result), instrType2(instr));
}

static void handleMod(VMContext* ctx, uint32_t instr) {
Expand Down
55 changes: 52 additions & 3 deletions src/vm_builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -7967,6 +7967,12 @@ static RValue builtin_window_get_cursor(VMContext* ctx, MAYBE_UNUSED RValue* arg
return RValue_makeReal(runner->currentCursor);
}

// ===[ Date Functions ]===
static RValue builtin_date_current_datetime(VMContext* ctx, MAYBE_UNUSED RValue* args, MAYBE_UNUSED int32_t argCount) {
time_t now = time(NULL);
return RValue_makeReal((GMLReal)now / (GMLReal)86400 + (GMLReal)25569);
}

// ===[ Game State Functions ]===
static RValue builtin_game_restart(VMContext* ctx, MAYBE_UNUSED RValue* args, MAYBE_UNUSED int32_t argCount) {
ctx->runner->pendingRoom = ROOM_RESTARTGAME;
Expand Down Expand Up @@ -13754,9 +13760,8 @@ static RValue builtin_layer_tile_visible(VMContext* ctx, RValue* args, MAYBE_UNU
}

static bool isValidLayerSpriteElement(RuntimeLayerElement* element) {
bool isValid = element != nullptr && element->type == RuntimeLayerElementType_Sprite;
requireNotNull(element->spriteElement); // If this crashes then something went DEEPLY wrong
return isValid;
return element != nullptr && element->spriteElement != nullptr && \
element->type == RuntimeLayerElementType_Sprite;
}

static RValue builtin_layer_sprite_get_id(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) {
Expand Down Expand Up @@ -14592,6 +14597,46 @@ static GamePath* getPath(Runner* runner, int32_t pathIdx) {
return &runner->dataWin->path.paths[pathIdx];
}

// draw_path(index, x, y, absolute) - draws a path outline using the current draw color/alpha
static RValue builtin_draw_path(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) {
Runner* runner = ctx->runner;
if (runner->renderer == nullptr) return RValue_makeUndefined();

int32_t index = RValue_toInt32(args[0]);
GMLReal x = RValue_toReal(args[1]);
GMLReal y = RValue_toReal(args[2]);
bool absolute = RValue_toBool(args[3]);

GamePath* path = getPath(runner, index);
if (path == nullptr) return RValue_makeUndefined();

PathPositionResult origin = GamePath_getPosition(path, 0.0f);

float xoff = absolute ? 0.0f : x - origin.x;
float yoff = absolute ? 0.0f : y - origin.y;

if (runner->applyOffsetForPrimitives) {
xoff += 1.0f;
yoff += 1.0f;
}

int maxsteps = (int) roundf(path->length / 4.0f);
if (maxsteps <= 0) return RValue_makeUndefined();

PathPositionResult prev = GamePath_getPosition(path, 0.0f);
for (int i = 1; i <= maxsteps; i++) {
float t = (float) i / (float) maxsteps;
PathPositionResult cur = GamePath_getPosition(path, t);
runner->renderer->vtable->drawLine(runner->renderer,
xoff + prev.x, yoff + prev.y,
xoff + cur.x, yoff + cur.y,
1.0f, runner->renderer->drawColor, runner->renderer->drawAlpha);
prev = cur;
}

return RValue_makeUndefined();
}

// path_exists(path)
static RValue builtin_path_exists(VMContext* ctx, RValue* args, int32_t argCount) {
if (1 > argCount) return RValue_makeBool(false);
Expand Down Expand Up @@ -17357,6 +17402,9 @@ void VMBuiltins_registerAll(VMContext* ctx) {
VM_registerBuiltin(ctx, "window_set_cursor", builtin_window_set_cursor);
VM_registerBuiltin(ctx, "window_get_cursor", builtin_window_get_cursor);

// Date
VM_registerBuiltin(ctx, "date_current_datetime", builtin_date_current_datetime);

// Game
VM_registerBuiltin(ctx, "game_restart", builtin_game_restart);
VM_registerBuiltin(ctx, "game_end", builtin_game_end);
Expand Down Expand Up @@ -17529,6 +17577,7 @@ void VMBuiltins_registerAll(VMContext* ctx) {
VM_registerBuiltin(ctx, "draw_ellipse_color", builtin_draw_ellipse_color);
VM_registerBuiltin(ctx, "draw_set_circle_precision", builtin_draw_set_circle_precision);
VM_registerBuiltin(ctx, "draw_get_circle_precision", builtin_draw_get_circle_precision);
VM_registerBuiltin(ctx, "draw_path", builtin_draw_path);
VM_registerBuiltin(ctx, "draw_set_colour", builtin_draw_set_colour);
VM_registerBuiltin(ctx, "draw_get_colour", builtin_draw_get_colour);
VM_registerBuiltin(ctx, "draw_get_color", builtin_draw_get_color);
Expand Down
Loading