Skip to content

Commit 001bdbe

Browse files
authored
Add all remaining sfall math functions (alexbatalov#187)
* Add all remaining sfall math functions * Fix op_round
1 parent 40471e5 commit 001bdbe

File tree

6 files changed

+170
-38
lines changed

6 files changed

+170
-38
lines changed

sfall_testing/gl_test_math.ssl

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include "test_utils.h"
2+
#include "sfall.h"
3+
4+
procedure start begin
5+
6+
display_msg("Testing math functions...");
7+
8+
call assertFloat("sin(0)", sin(0), 0.0);
9+
call assertFloat("sin(PI/2)", sin(1.5708), 1.0);
10+
call assertFloat("sin(PI)", sin(3.1416), 0.0);
11+
call assertFloat("sin(-PI/2)", sin(-1.5708), -1.0);
12+
13+
call assertFloat("cos(0)", cos(0), 1.0);
14+
call assertFloat("cos(PI/2)", cos(1.5708), 0.0);
15+
call assertFloat("cos(PI)", cos(3.1416), -1.0);
16+
call assertFloat("cos(-PI)", cos(-3.1416), -1.0);
17+
18+
call assertFloat("tan(0)", tan(0), 0.0);
19+
call assertFloat("tan(PI/4)", tan(0.7854), 1.0);
20+
call assertFloat("tan(-PI/4)", tan(-0.7854), -1.0);
21+
22+
call assertFloat("arctan(0, 1)", arctan(0, 1), 0.0);
23+
call assertFloat("arctan(1, 1)", arctan(1, 1), 0.7854);
24+
call assertFloat("arctan(-1, 1)", arctan(-1, 1), -0.7854);
25+
call assertFloat("arctan(1, 0)", arctan(1, 0), 1.5708);
26+
27+
call assertFloat("log(1)", log(1), 0.0);
28+
call assertFloat("log(e)", log(2.7183), 1.0);
29+
call assertFloat("log(10)", log(10), 2.3026);
30+
31+
call assertFloat("exponent(0)", exponent(0), 1.0);
32+
call assertFloat("exponent(1)", exponent(1), 2.7183);
33+
call assertFloat("exponent(2)", exponent(2), 7.3891);
34+
call assertFloat("exponent(-1)", exponent(-1), 0.3679);
35+
36+
call assertEquals("ceil(2.1)", ceil(2.1), 3);
37+
call assertEquals("ceil(2.0)", ceil(2.0), 2);
38+
call assertEquals("ceil(-2.1)", ceil(-2.1), -2);
39+
call assertEquals("ceil(-2.9)", ceil(-2.9), -2);
40+
41+
call assertEquals("floor2(2.1)", floor2(2.1), 2);
42+
call assertEquals("floor2(2.9)", floor2(2.9), 2);
43+
call assertEquals("floor2(-2.1)", floor2(-2.1), -3);
44+
call assertEquals("floor2(-2.9)", floor2(-2.9), -3);
45+
46+
call assertEquals("2^3", 2^3, 8);
47+
call assertEquals("4^2", 4^2, 16);
48+
call assertEquals("3^0", 3^0, 1);
49+
call assertFloat("2^-1", 2^-1, 0); // note: int truncation
50+
call assertFloat("2^-1", 2^-1.0, 0.5);
51+
call assertFloat("4^0.5", 4^0.5, 2.0);
52+
call assertFloat("8^(1/3)", 8^(1.0/3.0), 2.0);
53+
call assertFloat("2.5^2", 2.5^2, 6.25);
54+
55+
call assertEquals("round(2.3)", round(2.3), 2);
56+
call assertEquals("round(2.5)", round(2.5), 3);
57+
call assertEquals("round(2.7)", round(2.7), 3);
58+
call assertEquals("round(-2.3)", round(-2.3), -2);
59+
call assertEquals("round(-2.5)", round(-2.5), -3);
60+
call assertEquals("round(-2.7)", round(-2.7), -3);
61+
call assertEquals("round(0.0)", round(0.0), 0);
62+
call assertEquals("round(1.0)", round(1.0), 1);
63+
call assertEquals("round(<int>)", round(1), 1);
64+
65+
call assertFloat("sin(arctan(1, 1))", sin(arctan(1, 1)), 0.7071);
66+
call assertFloat("cos(arctan(1, 1))", cos(arctan(1, 1)), 0.7071);
67+
call assertFloat("log(ceil(2.7))", log(ceil(2.7)), 1.0986);
68+
call assertFloat("exponent(log(5))", exponent(log(5)), 5.0);
69+
70+
call report_test_results("math");
71+
end

sfall_testing/test_utils.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ procedure assertNotEquals(variable desc, variable a, variable b) begin
2929
end
3030
end
3131

32+
procedure assertFloat(variable desc, variable a, variable b, variable tolerance = 0.001) begin
33+
test_suite_assertions++;
34+
35+
variable diff := abs(a - b);
36+
if (diff > tolerance) then begin
37+
display_msg("Assertion failed \""+desc+"\": "+a+" != "+b+" (diff: "+diff+")");
38+
test_suite_errors ++;
39+
end else if (test_suite_verbose) then begin
40+
display_msg("Assert \""+desc+"\" ok");
41+
end
42+
end
43+
3244
procedure report_test_results(variable desc) begin
3345

3446
display_msg("DONE " + desc + " " +

src/interpreter.cc

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3183,15 +3183,6 @@ int programStackPopInteger(Program* program)
31833183
return programValue.integerValue;
31843184
}
31853185

3186-
float programStackPopFloat(Program* program)
3187-
{
3188-
ProgramValue programValue = programStackPopValue(program);
3189-
if (programValue.opcode != VALUE_TYPE_INT) {
3190-
programFatalError("float expected, got %x", programValue.opcode);
3191-
}
3192-
return programValue.floatValue;
3193-
}
3194-
31953186
char* programStackPopString(Program* program)
31963187
{
31973188
ProgramValue programValue = programStackPopValue(program);

src/interpreter.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,6 @@ void programStackPushPointer(Program* program, void* value);
230230

231231
ProgramValue programStackPopValue(Program* program);
232232
int programStackPopInteger(Program* program);
233-
float programStackPopFloat(Program* program);
234233
char* programStackPopString(Program* program);
235234
void* programStackPopPointer(Program* program);
236235

src/sfall_metarules.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "sfall_metarules.h"
22

33
#include <algorithm>
4+
#include <math.h>
45
#include <memory>
56
#include <string.h>
67
#include <string>
@@ -54,6 +55,7 @@ static void mf_string_compare(Program* program, int args);
5455
static void mf_string_find(Program* program, int args);
5556
static void mf_string_to_case(Program* program, int args);
5657
static void mf_string_format(Program* program, int args);
58+
static void mf_floor2(Program* program, int args);
5759

5860
// ref. https://github.com/sfall-team/sfall/blob/42556141127895c27476cd5242a73739cbb0fade/sfall/Modules/Scripting/Handlers/Metarule.cpp#L72
5961
constexpr MetaruleInfo kMetarules[] = {
@@ -74,7 +76,7 @@ constexpr MetaruleInfo kMetarules[] = {
7476
// {"draw_image", mf_draw_image, 1, 5, -1, {ARG_INTSTR, ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
7577
// {"draw_image_scaled", mf_draw_image_scaled, 1, 6, -1, {ARG_INTSTR, ARG_INT, ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
7678
// {"exec_map_update_scripts", mf_exec_map_update_scripts, 0, 0},
77-
// {"floor2", mf_floor2, 1, 1, 0, {ARG_NUMBER}},
79+
{ "floor2", mf_floor2, 1, 1 },
7880
// {"get_can_rest_on_map", mf_get_rest_on_map, 2, 2, -1, {ARG_INT, ARG_INT}},
7981
// {"get_combat_free_move", mf_get_combat_free_move, 0, 0},
8082
// {"get_current_inven_size", mf_get_current_inven_size, 1, 1, 0, {ARG_OBJECT}},
@@ -484,6 +486,12 @@ void mf_string_format(Program* program, int args)
484486
sprintf_lite(program, args, "string_format");
485487
}
486488

489+
void mf_floor2(Program* program, int args)
490+
{
491+
ProgramValue programValue = programStackPopValue(program);
492+
programStackPushInteger(program, static_cast<int>(floor(programValue.asFloat())));
493+
}
494+
487495
void sprintf_lite(Program* program, int args, const char* infoOpcodeName)
488496
{
489497
auto format = programStackPopString(program); // Pop the format string

src/sfall_opcodes.cc

Lines changed: 78 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "sfall_opcodes.h"
22

3+
#include <math.h>
34
#include <string.h>
45

56
#include "animation.h"
@@ -328,6 +329,73 @@ static void op_abs(Program* program)
328329
}
329330
}
330331

332+
// sin
333+
static void op_sin(Program* program)
334+
{
335+
ProgramValue programValue = programStackPopValue(program);
336+
programStackPushFloat(program, sinf(programValue.asFloat()));
337+
}
338+
339+
// cos
340+
static void op_cos(Program* program)
341+
{
342+
ProgramValue programValue = programStackPopValue(program);
343+
programStackPushFloat(program, cosf(programValue.asFloat()));
344+
}
345+
346+
// tan
347+
static void op_tan(Program* program)
348+
{
349+
ProgramValue programValue = programStackPopValue(program);
350+
programStackPushFloat(program, tanf(programValue.asFloat()));
351+
}
352+
353+
// arctan
354+
static void op_arctan(Program* program)
355+
{
356+
ProgramValue xValue = programStackPopValue(program);
357+
ProgramValue yValue = programStackPopValue(program);
358+
programStackPushFloat(program, atan2f(yValue.asFloat(), xValue.asFloat()));
359+
}
360+
361+
// pow (^)
362+
static void op_power(Program* program)
363+
{
364+
ProgramValue expValue = programStackPopValue(program);
365+
ProgramValue baseValue = programStackPopValue(program);
366+
367+
// CE: Implementation is slightly different, check.
368+
float result = powf(baseValue.asFloat(), expValue.asFloat());
369+
370+
if (baseValue.isInt() && expValue.isInt()) {
371+
// Note: this will truncate the result if power is negative. Keeping it to match sfall.
372+
programStackPushInteger(program, static_cast<int>(result));
373+
} else {
374+
programStackPushFloat(program, result);
375+
}
376+
}
377+
378+
// log
379+
static void op_log(Program* program)
380+
{
381+
ProgramValue programValue = programStackPopValue(program);
382+
programStackPushFloat(program, logf(programValue.asFloat()));
383+
}
384+
385+
// ceil
386+
static void op_ceil(Program* program)
387+
{
388+
ProgramValue programValue = programStackPopValue(program);
389+
programStackPushInteger(program, static_cast<int>(ceilf(programValue.asFloat())));
390+
}
391+
392+
// exp
393+
static void op_exponent(Program* program)
394+
{
395+
ProgramValue programValue = programStackPopValue(program);
396+
programStackPushFloat(program, expf(programValue.asFloat()));
397+
}
398+
331399
// get_script
332400
static void op_get_script(Program* program)
333401
{
@@ -774,22 +842,6 @@ static void op_explosions_metarule(Program* program)
774842
}
775843
}
776844

777-
// pow (^)
778-
static void op_power(Program* program)
779-
{
780-
ProgramValue expValue = programStackPopValue(program);
781-
ProgramValue baseValue = programStackPopValue(program);
782-
783-
// CE: Implementation is slightly different, check.
784-
float result = powf(baseValue.asFloat(), expValue.asFloat());
785-
786-
if (baseValue.isInt() && expValue.isInt()) {
787-
programStackPushInteger(program, static_cast<int>(result));
788-
} else {
789-
programStackPushFloat(program, result);
790-
}
791-
}
792-
793845
// message_str_game
794846
static void op_get_message(Program* program)
795847
{
@@ -942,13 +994,8 @@ static void op_type_of(Program* program)
942994
// round
943995
static void op_round(Program* program)
944996
{
945-
float floatValue = programStackPopFloat(program);
946-
int integerValue = static_cast<int>(floatValue);
947-
float mod = floatValue - static_cast<float>(integerValue);
948-
if (abs(mod) >= 0.5) {
949-
integerValue += mod > 0.0 ? 1 : -1;
950-
}
951-
programStackPushInteger(program, integerValue);
997+
float floatValue = programStackPopValue(program).asFloat();
998+
programStackPushInteger(program, lroundf(floatValue));
952999
}
9531000

9541001
enum BlockType {
@@ -1138,7 +1185,7 @@ void sfallOpcodesInit()
11381185
interpreterRegisterOpcode(0x819B, op_set_global_script_type);
11391186
interpreterRegisterOpcode(0x819D, op_set_sfall_global);
11401187
interpreterRegisterOpcode(0x819E, op_get_sfall_global_int);
1141-
// missing: get_sfall_global_float, skill_max, eax, npc_level, viewport, mod
1188+
// missing: get_sfall_global_float, skill_max, eax (deprecated), npc_level, viewport, mod
11421189
interpreterRegisterOpcode(0x81AC, op_get_ini_setting);
11431190
// missing: get_shader_version, get_shader_mode
11441191
interpreterRegisterOpcode(0x81AF, op_get_game_mode);
@@ -1159,7 +1206,10 @@ void sfallOpcodesInit()
11591206
interpreterRegisterOpcode(0x81EB, op_get_ini_string);
11601207
interpreterRegisterOpcode(0x81EC, op_sqrt);
11611208
interpreterRegisterOpcode(0x81ED, op_abs);
1162-
// missing: sin, cos, tan, atan
1209+
interpreterRegisterOpcode(0x81EE, op_sin);
1210+
interpreterRegisterOpcode(0x81EF, op_cos);
1211+
interpreterRegisterOpcode(0x81F0, op_tan);
1212+
interpreterRegisterOpcode(0x81F1, op_arctan);
11631213
// missing: set_palette
11641214
// missing: remove_script, set_script
11651215
interpreterRegisterOpcode(0x81F5, op_get_script);
@@ -1219,9 +1269,10 @@ void sfallOpcodesInit()
12191269
// missing: <reserved>x2, reg_anim_*
12201270
interpreterRegisterOpcode(0x8261, op_explosions_metarule);
12211271
// missing: register_hook_proc
1222-
// missing: log
12231272
interpreterRegisterOpcode(0x8263, op_power);
1224-
// missing: ceil
1273+
interpreterRegisterOpcode(0x8264, op_log);
1274+
interpreterRegisterOpcode(0x8265, op_exponent);
1275+
interpreterRegisterOpcode(0x8266, op_ceil);
12251276
interpreterRegisterOpcode(0x8267, op_round);
12261277
// 3 reserved opcodes
12271278
interpreterRegisterOpcode(0x826B, op_get_message);

0 commit comments

Comments
 (0)