├── .gitignore ├── .vscode └── tasks.json ├── GmlCppExtFuncs.hxproj ├── GmlCppExtFuncsJS.hxproj ├── GmlCppExtFuncsNET.hxproj ├── Package.bat ├── README.md ├── Run.bat ├── bin ├── index.html └── test.cpp ├── build.hxml ├── export ├── interop_test.dmd ├── interop_test.html ├── pack-legacy.bat ├── thumb.svg └── thumbs.bat ├── extraParams.hxml ├── haxelib.json ├── interop_test.gmx ├── Configs │ └── Default.config.gmx ├── extensions │ ├── interop_test.extension.gmx │ └── interop_test │ │ ├── autogen.gml │ │ └── interop_test.gml ├── fonts │ ├── fnt_test.font.gmx │ └── fnt_test.png ├── interop_test.project.gmx ├── objects │ └── obj_test.object.gmx ├── rooms │ └── rm_test.room.gmx └── scripts │ └── trace.gml ├── interop_test.sln ├── interop_test ├── README.md ├── YYRunnerInterface.h ├── autogen.cpp ├── dllmain.cpp ├── gml_ext.h ├── gml_extm.h ├── interop_test.APS ├── interop_test.h ├── interop_test.rc ├── interop_test.vcxproj ├── interop_test.vcxproj.filters ├── interop_test.vcxproj.user ├── postBuild.bat ├── preBuild.bat ├── resource1.h ├── stdafx.cpp ├── stdafx.h ├── targetver.h ├── test_basics.cpp ├── test_buffer.cpp ├── test_gml_id.cpp ├── test_gml_ptr.cpp ├── test_inout.cpp ├── test_struct.cpp ├── test_tuple.cpp ├── test_vector.cpp └── test_yyri.cpp ├── interop_test_23 ├── #config │ └── properties.json ├── extensions │ └── interop_test │ │ ├── autogen.gml │ │ ├── interop_test.gml │ │ └── interop_test.yy ├── fonts │ └── fnt_test │ │ ├── fnt_test.png │ │ └── fnt_test.yy ├── interop_test_23.yyp ├── objects │ └── obj_test │ │ ├── Create_0.gml │ │ ├── Draw_0.gml │ │ ├── Step_0.gml │ │ └── obj_test.yy ├── options │ ├── amazonfire │ │ └── options_amazonfire.yy │ ├── android │ │ └── options_android.yy │ ├── extensions │ │ └── interop_test.json │ ├── html5 │ │ └── options_html5.yy │ ├── ios │ │ └── options_ios.yy │ ├── linux │ │ └── options_linux.yy │ ├── mac │ │ └── options_mac.yy │ ├── main │ │ ├── inherited │ │ │ └── options_main.inherited.yy │ │ └── options_main.yy │ ├── operagx │ │ └── options_operagx.yy │ ├── tvos │ │ └── options_tvos.yy │ └── windows │ │ └── options_windows.yy ├── rooms │ └── rm_test │ │ └── rm_test.yy └── scripts │ ├── assert │ ├── assert.gml │ └── assert.yy │ ├── interop_test_23 │ ├── interop_test_23.gml │ └── interop_test_23.yy │ ├── is_equal │ ├── is_equal.gml │ └── is_equal.yy │ ├── scr_test │ ├── scr_test.gml │ └── scr_test.yy │ ├── scr_test_basics │ ├── scr_test_basics.gml │ └── scr_test_basics.yy │ ├── scr_test_buffer │ ├── scr_test_buffer.gml │ └── scr_test_buffer.yy │ ├── scr_test_gml_id │ ├── scr_test_gml_id.gml │ └── scr_test_gml_id.yy │ ├── scr_test_gml_ptr │ ├── scr_test_gml_ptr.gml │ └── scr_test_gml_ptr.yy │ ├── scr_test_inout │ ├── scr_test_inout.gml │ └── scr_test_inout.yy │ ├── scr_test_struct │ ├── scr_test_struct.gml │ └── scr_test_struct.yy │ ├── scr_test_tuple │ ├── scr_test_tuple.gml │ └── scr_test_tuple.yy │ ├── scr_test_vector │ ├── scr_test_vector.gml │ └── scr_test_vector.yy │ ├── scr_test_yyri │ ├── scr_test_yyri.gml │ └── scr_test_yyri.yy │ ├── sfmt │ ├── sfmt.gml │ └── sfmt.yy │ └── trace │ ├── trace.gml │ └── trace.yy ├── interop_test_yy ├── extensions │ └── interop_test │ │ ├── autogen.gml │ │ ├── interop_test.gml │ │ └── interop_test.yy ├── fonts │ └── fnt_test │ │ ├── fnt_test.gms1.png │ │ ├── fnt_test.gms1.yy │ │ ├── fnt_test.png │ │ └── fnt_test.yy ├── interop_test.yyp ├── objects │ └── obj_test │ │ ├── Create_0.gml │ │ ├── Draw_0.gml │ │ ├── Step_0.gml │ │ └── obj_test.yy ├── options │ ├── amazonfire │ │ └── options_amazonfire.yy │ ├── android │ │ └── options_android.yy │ ├── html5 │ │ └── options_html5.yy │ ├── ios │ │ └── options_ios.yy │ ├── linux │ │ └── options_linux.yy │ ├── mac │ │ └── options_mac.yy │ ├── main │ │ └── inherited │ │ │ └── options_main.inherited.yy │ ├── switch │ │ └── options_switch.yy │ ├── tvos │ │ └── options_tvos.yy │ └── windows │ │ └── options_windows.yy ├── rooms │ └── rm_test │ │ └── rm_test.yy ├── scripts │ └── trace │ │ ├── trace.gml │ │ └── trace.yy └── views │ ├── 1a1012ca-9702-4cd0-870a-3101ca12fddb.yy │ ├── 4f96784b-1ebd-4fc6-8c5b-10ee426a2840.yy │ ├── 504c1931-39ad-4f48-b783-4eb537b963d6.yy │ ├── 690caa00-bb5f-4c7f-b921-6fd3330a6bc3.yy │ ├── 6e9a4a1b-fa39-4f06-94c9-1a7f8822216a.yy │ ├── 81be6123-f045-42c2-ad8f-dd97676ed387.yy │ ├── 8c638ff8-1abe-4e11-bc32-7ef6af8b7b4f.yy │ ├── 9878a9d0-ce0a-4455-91a7-89de6e4976a2.yy │ ├── 9fdcc299-adf8-4729-b2f3-076ababf81ed.yy │ ├── c583b9bc-76c2-490f-a077-1eeafac7f5ec.yy │ ├── c9dcc6e5-46f1-4578-8543-9af4f6a4f7de.yy │ ├── e5b1e8fe-f417-43e8-b65f-8a518d723aea.yy │ ├── e5bc0382-83e6-4bfa-b68f-c702a7545129.yy │ ├── f2ec9b0e-c3fe-4297-a78d-fa6f418fd827.yy │ ├── f664cd6f-a19b-470a-8b94-844b0367b313.yy │ └── f8edfe34-8789-4236-b7e4-741b59e181b8.yy └── src ├── CppConfig.hx ├── CppGen.hx ├── CppGenParser.hx ├── CppType.hx ├── CppTypeHelper.hx ├── CppTypeMacroHelper.hx ├── GmlExtMacro.hx ├── func ├── CppFunc.hx ├── CppFuncArg.hx ├── CppFuncGmlDoc.hx ├── CppFuncMangled.hx └── CppFuncReader.hx ├── misc └── GmlConstructor.hx ├── proc ├── CppTypeProc.hx ├── CppTypeProcAssetIndexOf.hx ├── CppTypeProcCond.hx ├── CppTypeProcCustom.hx ├── CppTypeProcEnum.hx ├── CppTypeProcError.hx ├── CppTypeProcGameHwnd.hx ├── CppTypeProcGmlBuffer.hx ├── CppTypeProcGmlInOut.hx ├── CppTypeProcGmlInOutVector.hx ├── CppTypeProcGmlPointer.hx ├── CppTypeProcOptional.hx ├── CppTypeProcSimple.hx ├── CppTypeProcString.hx ├── CppTypeProcStruct.hx ├── CppTypeProcTuple.hx └── CppTypeProcVector.hx ├── struct ├── CppStruct.hx ├── CppStructField.hx ├── CppStructIO.hx └── GmlStructIO.hx └── tools ├── CharCode.hx ├── CppBuf.hx ├── CppReader.hx ├── GmkGen.hx └── GmlConditionalComments.hx /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | */#backups/* 3 | */Configs/*/* 4 | 5 | */extensions/*/*.cpp 6 | */extensions/*/*.dll 7 | */datafiles/interop_test.html 8 | 9 | */Debug/ 10 | */Release/ 11 | Debug/ 12 | Release/ 13 | bin/ 14 | export/*.gmz 15 | export/*.gmez 16 | export/*.yymp 17 | export/*.yymps 18 | export/*.png 19 | export/*.zip 20 | *.sdf 21 | help.rtf 22 | /bin/GmlCppExtFuncs.n 23 | /bin/GmlCppExtFuncs.exe 24 | /bin/GmlCppExtFuncs.zip 25 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Rebuild Haxe", 6 | "command": "haxe", 7 | "args": [ 8 | "build.hxml" 9 | ], 10 | "problemMatcher": [ 11 | "$haxe" 12 | ] 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /GmlCppExtFuncs.hxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /GmlCppExtFuncsJS.hxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /GmlCppExtFuncsNET.hxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | DEBUG: cmd /C copy bin\cs\bin\CppGen-Debug.exe bin\GmlCppExtFuncs.exe 46 | 47 | 48 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Package.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cd bin 3 | echo Creating standalone command line executable... 4 | nekotools boot GmlCppExtFuncs.n 5 | cmd /C 7z a GmlCppExtFuncs.zip GmlCppExtFuncs.n GmlCppExtFuncs.exe 6 | pause 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # GmlCppExtFuncs (working title) 3 | By default, GameMaker's extension interop has some limitations - since you can only pass around reals (64-bit floating point values) and pointers (to strings or binary buffers), many things are a bother to do - for example, if you want a function that computes a sum of int64 values in an array, you have to do 4 | ```cpp 5 | dllexport double get_sum_raw(int64_t* values, double count) { 6 | int64_t sum = 0; 7 | for (int i = 0; i < count; i++) sum += values[i]; 8 | values[0] = sum; 9 | return 1; 10 | } 11 | ``` 12 | and then a wrapper GML script: 13 | ```gml 14 | #define get_sum 15 | /// get_sum(values:array)->int 16 | var b = global.reusable_grow_buffer; 17 | buffer_seek(b, buffer_seek_start, 0); 18 | var arr = argument0; 19 | var len = array_length(arr); 20 | for (var i = 0; i < len; i++) buffer_write(b, buffer_u64, arr[i]); 21 | if (get_sum_raw(buffer_get_address(b), len)) { 22 | return buffer_peek(b, 0, buffer_u64); 23 | } else { 24 | // extension failed to load 25 | } 26 | ``` 27 | With help of this tool, however, you can write just 28 | ```cpp 29 | dllg int64_t get_sum(vector values) { 30 | int64_t sum = 0; 31 | for each (auto val in arr) sum += val; 32 | return sum; 33 | } 34 | ``` 35 | and the tool will generate the rest (a wrapper C++ function and a GML script that'll call it). 36 | 37 | Combined with [GmxGen](https://github.com/YAL-GameMaker-Tools/GmxGen), this means that you can write your C++ functions like normal and have them become available in GM automatically. 38 | 39 | ## Compiling 40 | ```bat 41 | haxe -cp src -neko GmlCppExtFuncs.n -main CppGen 42 | nekotools boot GmlCppExtFuncs.n 43 | ``` 44 | 45 | ## Setting up 46 | 47 | * Add a new .cpp file to your C++ project 48 | * Add [gml_ext.h](https://github.com/YAL-GameMaker-Tools/GmlCppExtFuncs/blob/master/interop_test/gml_ext.h) to your C++ project 49 | * Add a blank GML file to your GameMaker extension (using GM IDE) 50 | * Add [interop_test.gml](https://github.com/YAL-GameMaker-Tools/GmlCppExtFuncs/blob/master/interop_test_23/extensions/interop_test/interop_test.gml) to your GameMaker extension 51 | * Prepend your C++ functions of interest with the macro (default: `dllg`) 52 | 53 | ## Using 54 | 55 | The general syntax is as following: 56 | ``` 57 | GmlCppExtFuncs --cpp autogenerated_file.cpp --gml autogenerated_file.gml ...files [...options] 58 | ``` 59 | 60 | For a practical example, suppose you wanted to do this for the project in this repository. 61 | 62 | You could do so by calling 63 | ``` 64 | GmlCppExtFuncs -cpp interop_test/autogen.cpp -gml interop_test_23/extensions/interop_test/autogen.gml --prefix itr_test interop_test/interop_test.cpp 65 | ``` 66 | 67 | When using Visual Studio, you can use Build Events -> Pre-Build Event to automatically run the command before you compile. 68 | 69 | ## Further reading 70 | 71 | * [Command-line arguments](https://github.com/YAL-GameMaker-Tools/GmlCppExtFuncs/wiki/Command-line-arguments) 72 | * [Supported types](https://github.com/YAL-GameMaker-Tools/GmlCppExtFuncs/wiki/Supported-types) 73 | * [Documentation tags](https://github.com/YAL-GameMaker-Tools/GmlCppExtFuncs/wiki/Documentation-tags) 74 | 75 | ## TODOs 76 | 77 | * Generate inline "serialization" code on C++ side as well so that data types can be nested arbitrarily 78 | * Support returning pointers 79 | 80 | ## Limitations 81 | * Since the tool relies on parsing C++ code, it may fail on code that looks deceptively (e.g. because it's full of C++ macros) - feel free to preprocess your files (via `-E` in GCC or `/P` in MSVC) before feeding the files to the tool if you rely heavily on generating functions through macros. 82 | -------------------------------------------------------------------------------- /Run.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | neko bin/GmlCppExtFuncs.n^ 3 | --prefix itr_test^ 4 | --cpp interop_test/autogen.cpp^ 5 | --gml interop_test_23/extensions/interop_test/autogen.gml^ 6 | interop_test/interop_test.cpp^ 7 | interop_test/interop_test_m.cpp 8 | pause 9 | -------------------------------------------------------------------------------- /bin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /bin/test.cpp: -------------------------------------------------------------------------------- 1 | 2 | struct Test { 3 | int a0; 4 | int a1[2]; 5 | int a2[3][2]; 6 | } 7 | 8 | struct Inner { 9 | int a; 10 | } 11 | struct Outer { 12 | Inner a; 13 | int b; 14 | } 15 | 16 | dllw Test getTest(Test q) { 17 | Test t; 18 | t.a = q.a + 1; 19 | t.b = 1; 20 | return t; 21 | } 22 | 23 | dllw void testLayered(Outer a) { 24 | 25 | } 26 | 27 | /* 28 | dllw void no_ret(int64 i, int k) { 29 | 30 | } 31 | 32 | dllw int int64_to_int(int64 i) { 33 | return (int)i; 34 | } 35 | 36 | dllw int64 int64_to_int64(int64 i) { 37 | return i; 38 | } 39 | 40 | dllw int64 test(int64 i) { 41 | return i + 1; 42 | } 43 | 44 | dllw int64 test2(int64 i, int64 k = 0) { 45 | return i + k; 46 | } 47 | 48 | dllw int64 test2(int64 i, int64 k = 0, int64 j = 1) { 49 | return i + k; 50 | } 51 | 52 | dllw Test getTest() { 53 | Test t; 54 | t.a = 4; 55 | t.b = "hi!"; 56 | return t; 57 | } -------------------------------------------------------------------------------- /build.hxml: -------------------------------------------------------------------------------- 1 | -cp src 2 | -neko bin/GmlCppExtFuncs.n 3 | -main CppGen 4 | --cmd cmd /C interop_test\preBuild.bat dll .\ interop_test\ x64 default -------------------------------------------------------------------------------- /export/interop_test.dmd: -------------------------------------------------------------------------------- 1 | ```set template default.html``` 2 | ```set title interop_test cheat sheet``` 3 | ```set autoapi ext``` 4 | ```set intro 5 | This is a "cheat sheet" for "interop_test" extension by YellowAfterlife. 6 | The extension can be found on [itch.io](https://yellowafterlife.itch.io/gamemaker-interop_test). 7 | ``` -------------------------------------------------------------------------------- /export/interop_test.html: -------------------------------------------------------------------------------- 1 | .vs/ 2 | */#backups/* 3 | */Configs/*/* 4 | */extensions/*/*.cpp 5 | */extensions/*/*.dll 6 | */Release/ 7 | Release/ 8 | export/*.gmez 9 | export/*.png 10 | export/*.gmz 11 | *.sdf 12 | help.rtf -------------------------------------------------------------------------------- /export/pack-legacy.bat: -------------------------------------------------------------------------------- 1 | cd legacy 2 | cmd /C 7z a "../interop_test-for-GM8.1-or-older.zip" * 3 | pause -------------------------------------------------------------------------------- /export/thumb.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 30 | 34 | 38 | 39 | 40 | 71 | 75 | 83 | 84 | 86 | 87 | 89 | image/svg+xml 90 | 92 | 93 | 94 | 95 | 96 | 101 | interop_test 112 | 119 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /export/thumbs.bat: -------------------------------------------------------------------------------- 1 | magick thumb.png -background #889ec5 -gravity center -extent 315x250 thumb-itch.png 2 | magick thumb.png -background #889ec5 -gravity center -extent 560x240 thumb-twitter.png 3 | magick thumb.png -background #889ec5 -gravity center -extent 540x240 thumb-tumblr.png -------------------------------------------------------------------------------- /extraParams.hxml: -------------------------------------------------------------------------------- 1 | --macro GmlExtMacro.macroMain() -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GmlCppExtFuncs", 3 | "url": "https://github.com/YAL-GameMaker-Tools/GmlCppExtFuncs", 4 | "license": "MIT", 5 | "classPath": "src/", 6 | "tags": [ 7 | "cpp", "gamemaker" 8 | ], 9 | "description": "", 10 | "contributors": ["YellowAfterlife"], 11 | "releasenote": "", 12 | "version": "1.0.0", 13 | "dependencies": { } 14 | } 15 | -------------------------------------------------------------------------------- /interop_test.gmx/extensions/interop_test/interop_test.gml: -------------------------------------------------------------------------------- 1 | #define itr_test_init 2 | global.__iq_use_structs = false; 3 | global.__ptrt_iq_thing = ["iq_thing"]; 4 | 5 | #define itr_test_prepare_buffer 6 | /// (size:int)->buffer~ 7 | var _size = argument0; 8 | gml_pragma("global", "global.__itr_test_buffer = undefined"); 9 | var _buf = global.__itr_test_buffer; 10 | if (_buf == undefined) { 11 | _buf = buffer_create(_size, buffer_grow, 1); 12 | global.__itr_test_buffer = _buf; 13 | } else if (buffer_get_size(_buf) < _size) { 14 | buffer_resize(_buf, _size); 15 | } 16 | buffer_seek(_buf, buffer_seek_start, 0); 17 | return _buf; 18 | 19 | #define itr_test_read_chars 20 | /// (buffer:buffer, len:int)->string~ 21 | var _buf = argument0, _len = argument1; 22 | gml_pragma("global", "global.__itr_test_string_buffer = undefined"); 23 | var _tmp = global.__itr_test_string_buffer; 24 | if (_tmp == undefined) { 25 | _tmp = buffer_create(_len + 1, buffer_grow, 1); 26 | global.__itr_test_string_buffer = _tmp; 27 | } else if (buffer_get_size(_tmp) <= _len) { 28 | buffer_resize(_tmp, _len + 1); 29 | } 30 | buffer_copy(_buf, buffer_tell(_buf), _len, _tmp, 0); 31 | buffer_seek(_buf, buffer_seek_relative, _len); 32 | buffer_poke(_tmp, _len, buffer_u8, 0); 33 | buffer_seek(_tmp, buffer_seek_start, 0); 34 | return buffer_read(_tmp, buffer_string); 35 | 36 | #define itr_test_write_chars 37 | /// (buffer:buffer, str:string, len:int)~ 38 | var _buf = argument0, _str = argument1, _len = argument2; 39 | var _tmp = global.__itr_test_string_buffer; 40 | if (_tmp == undefined) { 41 | _tmp = buffer_create(_len + 1, buffer_grow, 1); 42 | global.__itr_test_string_buffer = _tmp; 43 | } 44 | buffer_seek(_tmp, buffer_seek_start, 0); 45 | buffer_write(_tmp, buffer_text, _str); 46 | var _pos = buffer_tell(_tmp); 47 | if (_pos < _len) buffer_fill(_tmp, _pos, buffer_u8, 0, _len - _pos); 48 | buffer_copy(_tmp, 0, _len, _buf, buffer_tell(_buf)); 49 | buffer_seek(_buf, buffer_seek_relative, _len); -------------------------------------------------------------------------------- /interop_test.gmx/fonts/fnt_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YAL-GameMaker-Tools/GmlCppExtFuncs/5293a574efac244853219eecb3f745ca4e062c86/interop_test.gmx/fonts/fnt_test.png -------------------------------------------------------------------------------- /interop_test.gmx/interop_test.project.gmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Configs\Default 5 | 6 | 7 | 8 | extensions\interop_test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | fonts\fnt_test 19 | 20 | 21 | objects\obj_test 22 | 23 | 24 | rooms\rm_test 25 | 26 | 27 | help.rtf 28 | 29 | 30 | 0 31 | 32 | 0 33 | 34 | 35 | -------------------------------------------------------------------------------- /interop_test.gmx/objects/obj_test.object.gmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | <undefined> 4 | 0 5 | -1 6 | 0 7 | 0 8 | <undefined> 9 | <undefined> 10 | 11 | 12 | 13 | 1 14 | 603 15 | 7 16 | 0 17 | 0 18 | -1 19 | 2 20 | 21 | 22 | self 23 | 0 24 | 0 25 | 26 | 27 | 1 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 1 36 | 603 37 | 7 38 | 0 39 | 0 40 | -1 41 | 2 42 | 43 | 44 | self 45 | 0 46 | 0 47 | 48 | 49 | 1 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 1 58 | 603 59 | 7 60 | 0 61 | 0 62 | -1 63 | 2 64 | 65 | 66 | self 67 | 0 68 | 0 69 | 70 | 71 | 1 72 | draw_set_font(fnt_test); 73 | draw_set_color(c_white); 74 | 75 | 76 | 77 | 78 | 79 | 80 | 0 81 | 0 82 | 0 83 | 0.5 84 | 0.100000001490116 85 | 0 86 | 0.100000001490116 87 | 0.100000001490116 88 | 0.200000002980232 89 | -1 90 | 0 91 | 92 | 93 | -------------------------------------------------------------------------------- /interop_test.gmx/rooms/rm_test.room.gmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 480 5 | 272 6 | 32 7 | 32 8 | 0 9 | 30 10 | 0 11 | 12951176 12 | -1 13 | 14 | 0 15 | -1 16 | -1 17 | 18 | -1 19 | 1024 20 | 600 21 | -1 22 | -1 23 | -1 24 | -1 25 | -1 26 | 0 27 | 0 28 | -1 29 | 4 30 | 0 31 | 0 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 0 58 | 0 59 | 0 60 | 1024 61 | 768 62 | 0 63 | 10 64 | 0.100000001490116 65 | 66 | -------------------------------------------------------------------------------- /interop_test.gmx/scripts/trace.gml: -------------------------------------------------------------------------------- 1 | /// trace(...) 2 | var r = string(argument[0]); 3 | for (var i = 1; i < argument_count; i++) { 4 | r += " " + string(argument[i]); 5 | } 6 | show_debug_message(r); 7 | -------------------------------------------------------------------------------- /interop_test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29424.173 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "interop_test", "interop_test\interop_test.vcxproj", "{C09F7563-35EB-439B-ABF2-0E72F829A515}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {C09F7563-35EB-439B-ABF2-0E72F829A515}.Debug|x64.ActiveCfg = Debug|x64 17 | {C09F7563-35EB-439B-ABF2-0E72F829A515}.Debug|x64.Build.0 = Debug|x64 18 | {C09F7563-35EB-439B-ABF2-0E72F829A515}.Debug|x86.ActiveCfg = Debug|Win32 19 | {C09F7563-35EB-439B-ABF2-0E72F829A515}.Debug|x86.Build.0 = Debug|Win32 20 | {C09F7563-35EB-439B-ABF2-0E72F829A515}.Release|x64.ActiveCfg = Release|x64 21 | {C09F7563-35EB-439B-ABF2-0E72F829A515}.Release|x64.Build.0 = Release|x64 22 | {C09F7563-35EB-439B-ABF2-0E72F829A515}.Release|x86.ActiveCfg = Release|Win32 23 | {C09F7563-35EB-439B-ABF2-0E72F829A515}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {964197C3-1C90-46BA-B404-E8C40EA7C1F4} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /interop_test/README.md: -------------------------------------------------------------------------------- 1 | # interop_test 2 | 3 | 4 | 5 | ## Installing 6 | 7 | 12 | - **GameMaker: Studio:** 13 | Import the GMEZ by right-clicking Extensions folder in resource tree and picking "Import extension" 14 | - **GameMaker Studio 2** 15 | Import the YYMP by drag and dropping it onto your workspace or picking menu:Tools➜Import Local Package 16 | 17 | ## Meta 18 | 19 | **Author:** [YellowAfterlife](https://github.com/YellowAfterlife) 20 | **License:** MIT -------------------------------------------------------------------------------- /interop_test/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "stdafx.h" 3 | 4 | BOOL APIENTRY DllMain( HMODULE hModule, 5 | DWORD ul_reason_for_call, 6 | LPVOID lpReserved 7 | ) 8 | { 9 | switch (ul_reason_for_call) 10 | { 11 | case DLL_PROCESS_ATTACH: 12 | case DLL_THREAD_ATTACH: 13 | case DLL_THREAD_DETACH: 14 | case DLL_PROCESS_DETACH: 15 | break; 16 | } 17 | return TRUE; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /interop_test/gml_ext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) 4 | #include 5 | #endif 6 | #include 7 | #include 8 | #include 9 | 10 | #define dllg /* tag */ 11 | #define dllgm /* tag;mangled */ 12 | 13 | #if defined(_WINDOWS) 14 | #define dllx extern "C" __declspec(dllexport) 15 | #define dllm __declspec(dllexport) 16 | #elif defined(GNUC) 17 | #define dllx extern "C" __attribute__ ((visibility("default"))) 18 | #define dllm __attribute__ ((visibility("default"))) 19 | #else 20 | #define dllx extern "C" 21 | #define dllm /* */ 22 | #endif 23 | 24 | #ifdef _WINDEF_ 25 | /// auto-generates a window_handle() on GML side 26 | typedef HWND GAME_HWND; 27 | #endif 28 | 29 | /// auto-generates an asset_get_index("argument_name") on GML side 30 | typedef int gml_asset_index_of; 31 | /// Wraps a C++ pointer for GML. 32 | template using gml_ptr = T*; 33 | /// Passes a modified struct back to GML 34 | template using gml_inout = T&; 35 | /// Modifies an array of values that GML passed in 36 | template using gml_inout_vector = std::vector&; 37 | 38 | /// Same as gml_ptr, but replaces the GML-side pointer by a nullptr after passing it to C++ 39 | template using gml_ptr_destroy = T*; 40 | /// Wraps any ID (or anything that casts to int64, really) for GML. 41 | template using gml_id = T; 42 | /// Same as gml_id, but replaces the GML-side ID by a 0 after passing it to C++ 43 | template using gml_id_destroy = T; 44 | 45 | class gml_buffer { 46 | private: 47 | uint8_t* _data; 48 | int32_t _size; 49 | int32_t _tell; 50 | public: 51 | gml_buffer() : _data(nullptr), _tell(0), _size(0) {} 52 | gml_buffer(uint8_t* data, int32_t size, int32_t tell) : _data(data), _size(size), _tell(tell) {} 53 | 54 | inline uint8_t* data() { return _data; } 55 | inline int32_t tell() { return _tell; } 56 | inline int32_t size() { return _size; } 57 | }; 58 | 59 | class gml_istream { 60 | uint8_t* pos; 61 | uint8_t* start; 62 | public: 63 | gml_istream(void* origin) : pos((uint8_t*)origin), start((uint8_t*)origin) {} 64 | 65 | template T read() { 66 | static_assert(std::is_trivially_copyable_v, "T must be trivially copyable to be read"); 67 | T result{}; 68 | std::memcpy(&result, pos, sizeof(T)); 69 | pos += sizeof(T); 70 | return result; 71 | } 72 | 73 | char* read_string() { 74 | char* r = (char*)pos; 75 | while (*pos != 0) pos++; 76 | pos++; 77 | return r; 78 | } 79 | 80 | gml_buffer read_gml_buffer() { 81 | auto _data = (uint8_t*)read(); 82 | auto _size = read(); 83 | auto _tell = read(); 84 | return gml_buffer(_data, _size, _tell); 85 | } 86 | }; 87 | 88 | class gml_ostream { 89 | uint8_t* pos; 90 | uint8_t* start; 91 | public: 92 | gml_ostream(void* origin) : pos((uint8_t*)origin), start((uint8_t*)origin) {} 93 | 94 | template void write(T val) { 95 | static_assert(std::is_trivially_copyable_v, "T must be trivially copyable to be write"); 96 | memcpy(pos, &val, sizeof(T)); 97 | pos += sizeof(T); 98 | } 99 | 100 | void write_string(const char* s) { 101 | for (int i = 0; s[i] != 0; i++) write(s[i]); 102 | write(0); 103 | } 104 | }; 105 | 106 | class gmk_buffer { 107 | uint8_t* buf = 0; 108 | int pos = 0; 109 | int len = 0; 110 | public: 111 | gmk_buffer() {} 112 | uint8_t* prepare(int size) { 113 | if (len < size) { 114 | auto nb = (uint8_t*)realloc(buf, size); 115 | if (nb == nullptr) { 116 | show_error("Failed to reallocate %u bytes in gmk_buffer::prepare", size); 117 | return nullptr; 118 | } 119 | len = size; 120 | buf = nb; 121 | } 122 | pos = 0; 123 | return buf; 124 | } 125 | void init() { 126 | buf = 0; 127 | pos = 0; 128 | len = 0; 129 | } 130 | void rewind() { pos = 0; } 131 | inline uint8_t* data() { return buf; } 132 | // 133 | template void write(T val) { 134 | static_assert(std::is_trivially_copyable_v, "T must be trivially copyable to be write"); 135 | int next = pos + sizeof(T); 136 | if (next > len) { 137 | auto nl = len; 138 | while (nl < next) nl *= 2; 139 | auto nb = (uint8_t*)realloc(buf, nl); 140 | if (nb == nullptr) { 141 | show_error("Failed to reallocate %u bytes in gmk_buffer::write", nl); 142 | return; 143 | } 144 | len = nl; 145 | buf = nb; 146 | } 147 | memcpy(buf + pos, &val, sizeof(T)); 148 | pos = next; 149 | } 150 | template T read() { 151 | static_assert(std::is_trivially_copyable_v, "T must be trivially copyable to be read"); 152 | int next = pos + sizeof(T); 153 | T result{}; 154 | if (next > len) return result; 155 | memcpy(&result, buf + pos, sizeof(T)); 156 | pos = next; 157 | return result; 158 | } 159 | }; 160 | -------------------------------------------------------------------------------- /interop_test/interop_test.APS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YAL-GameMaker-Tools/GmlCppExtFuncs/5293a574efac244853219eecb3f745ca4e062c86/interop_test/interop_test.APS -------------------------------------------------------------------------------- /interop_test/interop_test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | using iq_id = int; 3 | -------------------------------------------------------------------------------- /interop_test/interop_test.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YAL-GameMaker-Tools/GmlCppExtFuncs/5293a574efac244853219eecb3f745ca4e062c86/interop_test/interop_test.rc -------------------------------------------------------------------------------- /interop_test/interop_test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {01f53200-1d0b-4f7a-845b-8bc07fccd020} 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | Source Files 76 | 77 | 78 | Source Files 79 | 80 | 81 | 82 | 83 | Resource Files 84 | 85 | 86 | 87 | 88 | Build scripts 89 | 90 | 91 | Build scripts 92 | 93 | 94 | -------------------------------------------------------------------------------- /interop_test/interop_test.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Default 5 | 6 | -------------------------------------------------------------------------------- /interop_test/postBuild.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set dllPath=%~1 3 | set solutionDir=%~2 4 | set projectDir=%~3 5 | set arch=%~4 6 | set config=%~5 7 | 8 | echo Running post-build for %config% 9 | 10 | set extName=interop_test 11 | set dllName=interop_test 12 | set gmlDir14=%solutionDir%interop_test.gmx 13 | set gmlDir22=%solutionDir%interop_test_yy 14 | set gmlDir23=%solutionDir%interop_test_23 15 | set ext14=%gmlDir14%\extensions\%extName% 16 | set ext22=%gmlDir22%\extensions\%extName% 17 | set ext23=%gmlDir23%\extensions\%extName% 18 | set dllRel=%dllName%.dll 19 | set cppRel=%dllName%.cpp 20 | set cppPath=%ext23%\%cppRel% 21 | set gmlPath=%ext23%\*.gml 22 | set docName=%extName%.html 23 | set docPath=%solutionDir%export\%docName% 24 | 25 | echo Copying documentation... 26 | copy /Y %docPath% %gmlDir23%\datafiles\%docName% 27 | copy /Y %docPath% %gmlDir22%\datafiles\%docName% 28 | copy /Y %docPath% %gmlDir14%\datafiles\%docName% 29 | 30 | where /q gmxgen 31 | if %ERRORLEVEL% EQU 0 ( 32 | 33 | echo Combining the source files... 34 | type "%projectDir%*.h" "%projectDir%*.cpp" >"%cppPath%" 2>nul 35 | 36 | echo Running GmxGen... 37 | 38 | gmxgen "%ext23%\%extName%.yy" ^ 39 | --copy "%dllPath%" "%dllRel%:%arch%" 40 | 41 | gmxgen "%ext22%\%extName%.yy" ^ 42 | --copy "%dllPath%" "%dllRel%:%arch%" ^ 43 | --copy "%cppPath%" "%cppRel%" ^ 44 | --copy "%gmlPath%" "*.gml" 45 | 46 | gmxgen "%ext14%.extension.gmx" ^ 47 | --copy "%dllPath%" "%dllRel%:%arch%" ^ 48 | --copy "%cppPath%" "%cppRel%" ^ 49 | --copy "%gmlPath%" "*.gml" 50 | 51 | ) else ( 52 | 53 | echo Copying DLLs... 54 | if "%arch%" EQU "x64" ( 55 | copy /Y "%dllPath%" "%ext23%\%dllName%_x64.dll" 56 | ) else ( 57 | copy /Y "%dllPath%" "%ext22%\%dllRel%" 58 | copy /Y "%dllPath%" "%ext23%\%dllRel%" 59 | copy /Y "%dllPath%" "%ext14%\%dllRel%" 60 | ) 61 | 62 | echo Copying GML files... 63 | robocopy %ext23% %ext22% *.gml /L >nul 64 | robocopy %ext23% %ext14% *.gml /L >nul 65 | 66 | echo postBuild.bat: Warning N/A: Could not find GmxGen - extensions will not be updated automatically. See https://github.com/YAL-GameMaker-Tools/GmxGen for setup. 67 | ) -------------------------------------------------------------------------------- /interop_test/preBuild.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set dllPath=%~1 3 | set solutionDir=%~2 4 | set projectDir=%~3 5 | set arch=%~4 6 | set config=%~5 7 | 8 | echo Running pre-build for %config% 9 | 10 | where /q GmlCppExtFuncs 11 | if %ERRORLEVEL% EQU 0 ( 12 | echo Running GmlCppExtFuncs... 13 | 14 | GmlCppExtFuncs ^ 15 | --prefix itr_test^ 16 | --cpp "%projectDir%autogen.cpp"^ 17 | --gml "%solutionDir%interop_test_23/extensions/interop_test/autogen.gml"^ 18 | --include interop_test.h^ 19 | --struct iq_use_structs^ 20 | %projectDir%test*.cpp 21 | ) -------------------------------------------------------------------------------- /interop_test/resource1.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by interop_test.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /interop_test/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // interop_test.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /interop_test/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #ifdef _WINDOWS 9 | #include "targetver.h" 10 | 11 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 12 | #include 13 | #endif 14 | 15 | #define trace(...) { printf("[interop_test] "); printf(__VA_ARGS__); printf("\n"); fflush(stdout); } 16 | 17 | // TODO: reference additional headers your program requires here 18 | #include "interop_test.h" 19 | #include "gml_ext.h" 20 | -------------------------------------------------------------------------------- /interop_test/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /interop_test/test_basics.cpp: -------------------------------------------------------------------------------- 1 | /// @author YellowAfterlife 2 | 3 | #include "stdafx.h" 4 | 5 | // @dllg:cond 0 6 | dllg void iq_never() {} 7 | // @dllg:cond 8 | 9 | dllg int iq_get_int() { 10 | return 1; 11 | } 12 | dllg int64_t iq_get_int64() { 13 | return 0x123456789ABCDEFi64; 14 | } 15 | dllg const char* iq_get_string() { 16 | return "hi!"; 17 | } 18 | 19 | dllg int64_t iq_add_int64(int64_t a, int64_t b = 0) { 20 | return a + b; 21 | } 22 | 23 | dllg std::optional iq_inc_opt_int(std::optional i) { 24 | if (i.has_value()) { 25 | return i.value() + 1; 26 | } else return {}; 27 | } 28 | 29 | // @dllg:defValue -3 30 | dllg int iq_def_ret_int() { 31 | return 3; 32 | } 33 | 34 | // @dllg:defValue "DLL is not loaded" 35 | dllg const char* iq_def_ret_string() { 36 | return "OK!"; 37 | } 38 | 39 | dllg int iq_add_strlens(const char* a, const char* b, const char* c, const char* d) { 40 | return strlen(a) + strlen(b) + strlen(c) + strlen(d); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /interop_test/test_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | dllg int iq_get_buffer_sum(gml_buffer buf) { 4 | int sum = 0; 5 | int till = buf.tell(); 6 | auto data = buf.data(); 7 | for (int i = 0; i < till; i++) { 8 | sum += data[i]; 9 | } 10 | return sum; 11 | } -------------------------------------------------------------------------------- /interop_test/test_gml_id.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | int _next_id = 0; 4 | dllg gml_id iq_id_create() { 5 | return ++_next_id; 6 | } 7 | dllg int iq_id_value(gml_id id) { 8 | return id; 9 | } 10 | dllg void iq_id_destroy(gml_id_destroy id) { 11 | // 12 | } -------------------------------------------------------------------------------- /interop_test/test_gml_ptr.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | struct iq_thing { 4 | int count; 5 | }; 6 | dllg gml_ptr iq_thing_create(int count) { 7 | auto thing = new iq_thing(); 8 | thing->count = count; 9 | return thing; 10 | } 11 | dllg void iq_thing_destroy(gml_ptr_destroy thing) { 12 | delete thing; 13 | } 14 | dllg int iq_thing_get_count(gml_ptr thing) { 15 | return thing->count; 16 | } 17 | dllg void iq_thing_set_count(gml_ptr thing, int count) { 18 | thing->count = count; 19 | } 20 | -------------------------------------------------------------------------------- /interop_test/test_inout.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | dllg void iq_test_inout_box(gml_inout q) { 4 | q += 1; 5 | } 6 | struct iq_inoutish { 7 | int a, b; 8 | char text[32]; 9 | }; 10 | dllg void iq_test_inout_struct(gml_inout q) { 11 | q.a += 1; 12 | strncpy(q.text, "Yeah!", std::size(q.text)); 13 | } 14 | dllg void iq_test_inout_int_vector(gml_inout_vector v) { 15 | for (auto i = 0u; i < v.size(); i++) { 16 | v[i] += 1; 17 | } 18 | } 19 | dllg void iq_test_inout_struct_vector(gml_inout_vector v) { 20 | for (auto i = 0u; i < v.size(); i++) { 21 | v[i].a += 1; 22 | } 23 | } -------------------------------------------------------------------------------- /interop_test/test_struct.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | struct _iq_get_struct_vec { 4 | int ind; 5 | char name[4]; 6 | }; 7 | dllg std::vector<_iq_get_struct_vec> iq_get_struct_vec() { 8 | std::vector<_iq_get_struct_vec> vec; 9 | vec.push_back({ 1, "one" }); 10 | _iq_get_struct_vec two = { 2, "two" }; 11 | two.name[3] = '-'; // non-NUL-terminated 12 | vec.push_back(two); 13 | vec.push_back({ 3, "tri" }); 14 | return vec; 15 | } 16 | 17 | struct mixed_sub { 18 | int a, b; 19 | }; 20 | struct mixed { 21 | int num; 22 | const char* str; 23 | uint8_t grid[3][3]; 24 | mixed_sub sub[2]; 25 | }; 26 | 27 | dllg mixed iq_mixed(mixed q) { 28 | return q; 29 | } -------------------------------------------------------------------------------- /interop_test/test_tuple.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | dllg std::tuple iq_get_int64_pair() { 4 | return { 1i64, 2i64 }; 5 | } 6 | 7 | dllg int64_t iq_int64_pair_sum(std::tuple pair) { 8 | return std::get<0>(pair) + std::get<1>(pair); 9 | } 10 | 11 | dllg std::tuple iq_int64_pair_swap(std::tuple pair) { 12 | return { std::get<1>(pair), std::get<0>(pair) }; 13 | } 14 | 15 | dllg std::tuple iq_get_int64_pair_vec_sum(std::vector> arr) { 16 | int64_t sum1 = 0, sum2 = 0; 17 | for each (auto val in arr) { 18 | sum1 += std::get<0>(val); 19 | sum2 += std::get<1>(val); 20 | } 21 | return { sum1, sum2 }; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /interop_test/test_vector.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | dllg std::vector iq_get_vec() { 4 | std::vector vec{}; 5 | for (int i = 1; i <= 3; i++) vec.push_back(i); 6 | return vec; 7 | } 8 | 9 | dllg std::optional> iq_get_opt_vec(bool ret) { 10 | std::vector vec{}; 11 | for (int i = 1; i <= 3; i++) vec.push_back(i); 12 | if (!ret) return {}; 13 | return vec; 14 | } 15 | 16 | dllg int64_t iq_get_int64_vec_sum(std::vector arr) { 17 | int64_t sum = 0; 18 | for each (auto val in arr) { 19 | sum += val; 20 | } 21 | return sum; 22 | } 23 | 24 | dllg int iq_get_length_of_strings(std::vector strings) { 25 | int sum = 0; 26 | for each (auto str in strings) { 27 | sum += (int)strlen(str); 28 | } 29 | return sum; 30 | } -------------------------------------------------------------------------------- /interop_test/test_yyri.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "gml_ext.h" 3 | #include "gml_extm.h" 4 | 5 | #define trace(...) { printf("[interop_test:%d] ", __LINE__); printf(__VA_ARGS__); printf("\n"); fflush(stdout); } 6 | 7 | static YYRunnerInterface g_YYRunnerInterface{}; 8 | YYRunnerInterface* g_pYYRunnerInterface; 9 | dllm void YYExtensionInitialise(const struct YYRunnerInterface* _struct, size_t _size) { 10 | if (_size < sizeof(YYRunnerInterface)) { 11 | memcpy(&g_YYRunnerInterface, _struct, _size); 12 | } else { 13 | memcpy(&g_YYRunnerInterface, _struct, sizeof(YYRunnerInterface)); 14 | } 15 | g_pYYRunnerInterface = &g_YYRunnerInterface; 16 | } 17 | 18 | dllgm int im_get_int() { 19 | return 1; 20 | } 21 | dllgm const char* im_get_string() { 22 | return "wow"; 23 | } 24 | dllgm void im_get_result(YYResult& result) { 25 | YYCreateString(&result, "result"); 26 | } 27 | 28 | dllgm int im_add_ints(int a, int b) { 29 | return a + b; 30 | } 31 | dllgm int im_add_rest(YYRest values) { 32 | auto result = 0; 33 | for (int i = 0; i < values.length; i++) { 34 | int v; if (values[i].tryGetInt(v)) result += v; 35 | } 36 | return result; 37 | } 38 | 39 | dllgm int64_t im_ptr_to_int64(void* ptr) { 40 | return (int64_t)ptr; 41 | } 42 | 43 | dllgm int im_string_length(const char* str) { 44 | return (int)strlen(str); 45 | } 46 | 47 | dllgm const char* im_typeof(RValue* val) { 48 | return KIND_NAME_RValue(val); 49 | } -------------------------------------------------------------------------------- /interop_test_23/#config/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "linterPrefs": { 3 | 4 | }, 5 | "templateStringScript": "sfmt" 6 | } -------------------------------------------------------------------------------- /interop_test_23/extensions/interop_test/interop_test.gml: -------------------------------------------------------------------------------- 1 | #define itr_test_init 2 | global.__iq_use_structs = false; 3 | global.__ptrt_iq_thing = ["iq_thing"]; 4 | 5 | #define itr_test_prepare_buffer 6 | /// (size:int)->buffer~ 7 | var _size = argument0; 8 | gml_pragma("global", "global.__itr_test_buffer = undefined"); 9 | var _buf = global.__itr_test_buffer; 10 | if (_buf == undefined) { 11 | _buf = buffer_create(_size, buffer_grow, 1); 12 | global.__itr_test_buffer = _buf; 13 | } else if (buffer_get_size(_buf) < _size) { 14 | buffer_resize(_buf, _size); 15 | } 16 | buffer_seek(_buf, buffer_seek_start, 0); 17 | return _buf; 18 | 19 | #define itr_test_read_chars 20 | /// (buffer:buffer, len:int)->string~ 21 | var _buf = argument0, _len = argument1; 22 | gml_pragma("global", "global.__itr_test_string_buffer = undefined"); 23 | var _tmp = global.__itr_test_string_buffer; 24 | if (_tmp == undefined) { 25 | _tmp = buffer_create(_len + 1, buffer_grow, 1); 26 | global.__itr_test_string_buffer = _tmp; 27 | } else if (buffer_get_size(_tmp) <= _len) { 28 | buffer_resize(_tmp, _len + 1); 29 | } 30 | buffer_copy(_buf, buffer_tell(_buf), _len, _tmp, 0); 31 | buffer_seek(_buf, buffer_seek_relative, _len); 32 | buffer_poke(_tmp, _len, buffer_u8, 0); 33 | buffer_seek(_tmp, buffer_seek_start, 0); 34 | return buffer_read(_tmp, buffer_string); 35 | 36 | #define itr_test_write_chars 37 | /// (buffer:buffer, str:string, len:int)~ 38 | var _buf = argument0, _str = argument1, _len = argument2; 39 | var _tmp = global.__itr_test_string_buffer; 40 | if (_tmp == undefined) { 41 | _tmp = buffer_create(_len + 1, buffer_grow, 1); 42 | global.__itr_test_string_buffer = _tmp; 43 | } else if (buffer_get_size(_tmp) <= _len) { 44 | buffer_resize(_tmp, _len + 1); 45 | } 46 | buffer_seek(_tmp, buffer_seek_start, 0); 47 | buffer_write(_tmp, buffer_text, _str); 48 | var _pos = buffer_tell(_tmp); 49 | if (_pos < _len) buffer_fill(_tmp, _pos, buffer_u8, 0, _len - _pos); 50 | buffer_copy(_tmp, 0, _len, _buf, buffer_tell(_buf)); 51 | buffer_seek(_buf, buffer_seek_relative, _len); -------------------------------------------------------------------------------- /interop_test_23/fonts/fnt_test/fnt_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YAL-GameMaker-Tools/GmlCppExtFuncs/5293a574efac244853219eecb3f745ca4e062c86/interop_test_23/fonts/fnt_test/fnt_test.png -------------------------------------------------------------------------------- /interop_test_23/interop_test_23.yyp: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMProject", 3 | "resourceVersion": "1.6", 4 | "name": "interop_test_23", 5 | "resources": [ 6 | {"id":{"name":"trace","path":"scripts/trace/trace.yy",},"order":1,}, 7 | {"id":{"name":"fnt_test","path":"fonts/fnt_test/fnt_test.yy",},"order":1,}, 8 | {"id":{"name":"obj_test","path":"objects/obj_test/obj_test.yy",},"order":1,}, 9 | {"id":{"name":"rm_test","path":"rooms/rm_test/rm_test.yy",},"order":1,}, 10 | {"id":{"name":"interop_test","path":"extensions/interop_test/interop_test.yy",},"order":1,}, 11 | {"id":{"name":"scr_test_buffer","path":"scripts/scr_test_buffer/scr_test_buffer.yy",},"order":5,}, 12 | {"id":{"name":"scr_test_struct","path":"scripts/scr_test_struct/scr_test_struct.yy",},"order":8,}, 13 | {"id":{"name":"scr_test_vector","path":"scripts/scr_test_vector/scr_test_vector.yy",},"order":3,}, 14 | {"id":{"name":"scr_test","path":"scripts/scr_test/scr_test.yy",},"order":0,}, 15 | {"id":{"name":"assert","path":"scripts/assert/assert.yy",},"order":3,}, 16 | {"id":{"name":"sfmt","path":"scripts/sfmt/sfmt.yy",},"order":1,}, 17 | {"id":{"name":"scr_test_basics","path":"scripts/scr_test_basics/scr_test_basics.yy",},"order":1,}, 18 | {"id":{"name":"scr_test_gml_id","path":"scripts/scr_test_gml_id/scr_test_gml_id.yy",},"order":7,}, 19 | {"id":{"name":"is_equal","path":"scripts/is_equal/is_equal.yy",},"order":2,}, 20 | {"id":{"name":"scr_test_inout","path":"scripts/scr_test_inout/scr_test_inout.yy",},"order":9,}, 21 | {"id":{"name":"interop_test_23","path":"scripts/interop_test_23/interop_test_23.yy",},"order":1,}, 22 | {"id":{"name":"scr_test_tuple","path":"scripts/scr_test_tuple/scr_test_tuple.yy",},"order":4,}, 23 | {"id":{"name":"scr_test_gml_ptr","path":"scripts/scr_test_gml_ptr/scr_test_gml_ptr.yy",},"order":6,}, 24 | {"id":{"name":"scr_test_yyri","path":"scripts/scr_test_yyri/scr_test_yyri.yy",},"order":2,}, 25 | ], 26 | "Options": [ 27 | {"name":"Amazon Fire","path":"options/amazonfire/options_amazonfire.yy",}, 28 | {"name":"Android","path":"options/android/options_android.yy",}, 29 | {"name":"HTML5","path":"options/html5/options_html5.yy",}, 30 | {"name":"iOS","path":"options/ios/options_ios.yy",}, 31 | {"name":"Linux","path":"options/linux/options_linux.yy",}, 32 | {"name":"macOS","path":"options/mac/options_mac.yy",}, 33 | {"name":"tvOS","path":"options/tvos/options_tvos.yy",}, 34 | {"name":"Windows","path":"options/windows/options_windows.yy",}, 35 | {"name":"operagx","path":"options/operagx/options_operagx.yy",}, 36 | {"name":"Main","path":"options/main/options_main.yy",}, 37 | ], 38 | "defaultScriptType": 1, 39 | "isEcma": false, 40 | "configs": { 41 | "name": "Default", 42 | "children": [], 43 | }, 44 | "RoomOrderNodes": [ 45 | {"roomId":{"name":"rm_test","path":"rooms/rm_test/rm_test.yy",},}, 46 | ], 47 | "Folders": [ 48 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Animation Curves","folderPath":"folders/Animation Curves.yy","order":1,}, 49 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Extensions","folderPath":"folders/Extensions.yy","order":23,}, 50 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Fonts","folderPath":"folders/Fonts.yy","order":13,}, 51 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Notes","folderPath":"folders/Notes.yy","order":21,}, 52 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Objects","folderPath":"folders/Objects.yy","order":17,}, 53 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Paths","folderPath":"folders/Paths.yy","order":7,}, 54 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Rooms","folderPath":"folders/Rooms.yy","order":19,}, 55 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Scripts","folderPath":"folders/Scripts.yy","order":9,}, 56 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Sequences","folderPath":"folders/Sequences.yy","order":1,}, 57 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Shaders","folderPath":"folders/Shaders.yy","order":11,}, 58 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Sounds","folderPath":"folders/Sounds.yy","order":5,}, 59 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Sprites","folderPath":"folders/Sprites.yy","order":1,}, 60 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Tile Sets","folderPath":"folders/Tile Sets.yy","order":3,}, 61 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"Timelines","folderPath":"folders/Timelines.yy","order":15,}, 62 | {"resourceType":"GMFolder","resourceVersion":"1.0","name":"tests","folderPath":"folders/Scripts/tests.yy","order":4,"tags":[],}, 63 | ], 64 | "AudioGroups": [ 65 | {"resourceType":"GMAudioGroup","resourceVersion":"1.3","name":"audiogroup_default","targets":-1,}, 66 | ], 67 | "TextureGroups": [ 68 | {"resourceType":"GMTextureGroup","resourceVersion":"1.3","name":"Default","isScaled":true,"compressFormat":"bz2","loadType":"default","directory":"","autocrop":true,"border":2,"mipsToGenerate":0,"groupParent":null,"targets":-1,}, 69 | ], 70 | "IncludedFiles": [ 71 | {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"interop_test.html","CopyToMask":-1,"filePath":"datafiles",}, 72 | ], 73 | "MetaData": { 74 | "IDEVersion": "2022.11.1.56", 75 | }, 76 | } -------------------------------------------------------------------------------- /interop_test_23/objects/obj_test/Create_0.gml: -------------------------------------------------------------------------------- 1 | //show_message("!"); 2 | scr_test(false); 3 | scr_test(true); 4 | scr_test_yyri(); 5 | -------------------------------------------------------------------------------- /interop_test_23/objects/obj_test/Draw_0.gml: -------------------------------------------------------------------------------- 1 | draw_set_font(fnt_test); 2 | draw_set_color(c_white); 3 | 4 | -------------------------------------------------------------------------------- /interop_test_23/objects/obj_test/Step_0.gml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /interop_test_23/objects/obj_test/obj_test.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMObject", 3 | "resourceVersion": "1.0", 4 | "name": "obj_test", 5 | "spriteId": null, 6 | "solid": false, 7 | "visible": true, 8 | "managed": true, 9 | "spriteMaskId": null, 10 | "persistent": false, 11 | "parentObjectId": null, 12 | "physicsObject": false, 13 | "physicsSensor": false, 14 | "physicsShape": 0, 15 | "physicsGroup": 0, 16 | "physicsDensity": 0.5, 17 | "physicsRestitution": 0.1, 18 | "physicsLinearDamping": 0.1, 19 | "physicsAngularDamping": 0.1, 20 | "physicsFriction": 0.2, 21 | "physicsStartAwake": true, 22 | "physicsKinematic": false, 23 | "physicsShapePoints": [], 24 | "eventList": [ 25 | {"resourceType":"GMEvent","resourceVersion":"1.0","name":"","isDnD":false,"eventNum":0,"eventType":0,"collisionObjectId":null,}, 26 | {"resourceType":"GMEvent","resourceVersion":"1.0","name":"","isDnD":false,"eventNum":0,"eventType":3,"collisionObjectId":null,}, 27 | {"resourceType":"GMEvent","resourceVersion":"1.0","name":"","isDnD":false,"eventNum":0,"eventType":8,"collisionObjectId":null,}, 28 | ], 29 | "properties": [], 30 | "overriddenProperties": [], 31 | "parent": { 32 | "name": "Objects", 33 | "path": "folders/Objects.yy", 34 | }, 35 | } -------------------------------------------------------------------------------- /interop_test_23/options/amazonfire/options_amazonfire.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_amazonfire_sync_android": false, 3 | "option_amazonfire_display_name": "Created with GameMaker Studio 2", 4 | "option_amazonfire_version": "1.0.0.0", 5 | "option_amazonfire_tools_from_version": false, 6 | "option_amazonfire_build_tools": "", 7 | "option_amazonfire_support_lib": "", 8 | "option_amazonfire_target_sdk": "", 9 | "option_amazonfire_minimum_sdk": "", 10 | "option_amazonfire_compile_sdk": "", 11 | "option_amazonfire_package_domain": "com", 12 | "option_amazonfire_package_company": "company", 13 | "option_amazonfire_package_product": "game", 14 | "option_amazonfire_orient_portrait": true, 15 | "option_amazonfire_orient_portrait_flipped": true, 16 | "option_amazonfire_orient_landscape": true, 17 | "option_amazonfire_orient_landscape_flipped": true, 18 | "option_amazonfire_gamepad_support": true, 19 | "option_amazonfire_lint": false, 20 | "option_amazonfire_install_location": 0, 21 | "option_amazonfire_sleep_margin": 4, 22 | "option_amazonfire_splash_screens_landscape": "${base_options_dir}/amazonfire/splash/landscape.png", 23 | "option_amazonfire_splash_screens_portrait": "${base_options_dir}/amazonfire/splash/portrait.png", 24 | "option_amazonfire_splash_time": 0, 25 | "option_amazonfire_launchscreen_fill": 0, 26 | "option_amazonfire_splashscreen_background_colour": 255, 27 | "option_amazonfire_tv_banner": "${base_options_dir}/amazonfire/tv_banner.png", 28 | "option_amazonfire_interpolate_pixels": false, 29 | "option_amazonfire_screen_depth": 0, 30 | "option_amazonfire_scale": 0, 31 | "option_amazonfire_texture_page": "2048x2048", 32 | "option_amazonfire_icon_ldpi": "${base_options_dir}/android/icons/ldpi.png", 33 | "option_amazonfire_icon_mdpi": "${base_options_dir}/android/icons/mdpi.png", 34 | "option_amazonfire_icon_hdpi": "${base_options_dir}/android/icons/hdpi.png", 35 | "option_amazonfire_icon_xhdpi": "${base_options_dir}/android/icons/xhdpi.png", 36 | "option_amazonfire_icon_xxhdpi": "${base_options_dir}/android/icons/xxhdpi.png", 37 | "option_amazonfire_icon_xxxhdpi": "${base_options_dir}/android/icons/xxxhdpi.png", 38 | "option_amazonfire_permission_write_external_storage": false, 39 | "option_amazonfire_permission_read_phone_state": false, 40 | "option_amazonfire_permission_network_state": false, 41 | "option_amazonfire_permission_internet": true, 42 | "option_amazonfire_permission_bluetooth": true, 43 | "option_amazonfire_permission_record_audio": false, 44 | "option_amazonfire_application_tag_inject": "", 45 | "resourceVersion": "1.0", 46 | "name": "Amazon Fire", 47 | "tags": [], 48 | "resourceType": "GMAmazonFireOptions", 49 | } -------------------------------------------------------------------------------- /interop_test_23/options/android/options_android.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_android_sync_amazon": false, 3 | "option_android_display_name": "Made in GameMaker Studio 2", 4 | "option_android_version": "1.0.0.0", 5 | "option_android_tools_from_version": false, 6 | "option_android_build_tools": "", 7 | "option_android_support_lib": "", 8 | "option_android_target_sdk": "", 9 | "option_android_minimum_sdk": "", 10 | "option_android_compile_sdk": "", 11 | "option_android_package_domain": "com", 12 | "option_android_package_company": "company", 13 | "option_android_package_product": "game", 14 | "option_android_arch_armv7": true, 15 | "option_android_arch_x86": false, 16 | "option_android_arch_arm64": false, 17 | "option_android_arch_x86_64": false, 18 | "option_android_orient_portrait": true, 19 | "option_android_orient_portrait_flipped": true, 20 | "option_android_orient_landscape": true, 21 | "option_android_orient_landscape_flipped": true, 22 | "option_android_gamepad_support": true, 23 | "option_android_lint": false, 24 | "option_android_install_location": 0, 25 | "option_android_sleep_margin": 4, 26 | "option_android_splash_screens_landscape": "${base_options_dir}/android/splash/landscape.png", 27 | "option_android_splash_screens_portrait": "${base_options_dir}/android/splash/portrait.png", 28 | "option_android_splash_time": 0, 29 | "option_android_launchscreen_fill": 0, 30 | "option_android_splashscreen_background_colour": 4294967295, 31 | "option_android_tv_banner": "${base_options_dir}/android/tv_banner.png", 32 | "option_android_interpolate_pixels": false, 33 | "option_android_screen_depth": 0, 34 | "option_android_device_support": 0, 35 | "option_android_scale": 0, 36 | "option_android_texture_page": "2048x2048", 37 | "option_android_icon_ldpi": "${base_options_dir}/android/icons/ldpi.png", 38 | "option_android_icon_mdpi": "${base_options_dir}/android/icons/mdpi.png", 39 | "option_android_icon_hdpi": "${base_options_dir}/android/icons/hdpi.png", 40 | "option_android_icon_xhdpi": "${base_options_dir}/android/icons/xhdpi.png", 41 | "option_android_icon_xxhdpi": "${base_options_dir}/android/icons/xxhdpi.png", 42 | "option_android_icon_xxxhdpi": "${base_options_dir}/android/icons/xxxhdpi.png", 43 | "option_android_icon_adaptive_generate": false, 44 | "option_android_icon_adaptive_ldpi": "${base_options_dir}/android/icons_adaptive/ldpi.png", 45 | "option_android_icon_adaptive_mdpi": "${base_options_dir}/android/icons_adaptive/mdpi.png", 46 | "option_android_icon_adaptive_hdpi": "${base_options_dir}/android/icons_adaptive/hdpi.png", 47 | "option_android_icon_adaptive_xhdpi": "${base_options_dir}/android/icons_adaptive/xhdpi.png", 48 | "option_android_icon_adaptive_xxhdpi": "${base_options_dir}/android/icons_adaptive/xxhdpi.png", 49 | "option_android_icon_adaptive_xxxhdpi": "${base_options_dir}/android/icons_adaptive/xxxhdpi.png", 50 | "option_android_icon_adaptivebg_ldpi": "${base_options_dir}/android/icons_adaptivebg/ldpi.png", 51 | "option_android_icon_adaptivebg_mdpi": "${base_options_dir}/android/icons_adaptivebg/mdpi.png", 52 | "option_android_icon_adaptivebg_hdpi": "${base_options_dir}/android/icons_adaptivebg/hdpi.png", 53 | "option_android_icon_adaptivebg_xhdpi": "${base_options_dir}/android/icons_adaptivebg/xhdpi.png", 54 | "option_android_icon_adaptivebg_xxhdpi": "${base_options_dir}/android/icons_adaptivebg/xxhdpi.png", 55 | "option_android_icon_adaptivebg_xxxhdpi": "${base_options_dir}/android/icons_adaptivebg/xxxhdpi.png", 56 | "option_android_use_facebook": false, 57 | "option_android_facebook_id": "", 58 | "option_android_facebook_app_display_name": "", 59 | "option_android_google_cloud_saving": false, 60 | "option_android_google_services_app_id": "", 61 | "option_android_permission_write_external_storage": false, 62 | "option_android_permission_read_phone_state": false, 63 | "option_android_permission_network_state": false, 64 | "option_android_permission_internet": true, 65 | "option_android_permission_bluetooth": false, 66 | "option_android_permission_record_audio": false, 67 | "option_android_application_tag_inject": null, 68 | "option_android_google_apk_expansion": false, 69 | "option_android_google_dynamic_asset_delivery": false, 70 | "option_android_google_licensing_public_key": "", 71 | "option_android_tv_isgame": true, 72 | "resourceVersion": "1.0", 73 | "name": "Android", 74 | "tags": [], 75 | "resourceType": "GMAndroidOptions", 76 | } -------------------------------------------------------------------------------- /interop_test_23/options/extensions/interop_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionId": null, 3 | "resourceVersion": "1.0", 4 | "resourceType": "GMExtensionConfigSet", 5 | "configurables": null 6 | } -------------------------------------------------------------------------------- /interop_test_23/options/html5/options_html5.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_html5_browser_title": "Made in GameMaker Studio 2", 3 | "option_html5_version": "1.0.0.0", 4 | "option_html5_foldername": "html5game", 5 | "option_html5_outputname": "index.html", 6 | "option_html5_splash_png": "${base_options_dir}/html5/splash.png", 7 | "option_html5_usesplash": false, 8 | "option_html5_outputdebugtoconsole": true, 9 | "option_html5_display_cursor": true, 10 | "option_html5_localrunalert": true, 11 | "option_html5_index": "", 12 | "option_html5_loadingbar": "", 13 | "option_html5_jsprepend": "", 14 | "option_html5_icon": "${base_options_dir}/html5/fav.ico", 15 | "option_html5_allow_fullscreen": true, 16 | "option_html5_interpolate_pixels": false, 17 | "option_html5_centregame": false, 18 | "option_html5_usebuiltinparticles": true, 19 | "option_html5_usebuiltinfont": true, 20 | "option_html5_webgl": 2, 21 | "option_html5_scale": 0, 22 | "option_html5_texture_page": "2048x2048", 23 | "option_html5_use_facebook": false, 24 | "option_html5_facebook_id": "", 25 | "option_html5_facebook_app_display_name": "", 26 | "option_html5_flurry_enable": false, 27 | "option_html5_flurry_id": "", 28 | "option_html5_google_analytics_enable": false, 29 | "option_html5_google_tracking_id": "", 30 | "resourceVersion": "1.0", 31 | "name": "HTML5", 32 | "tags": [], 33 | "resourceType": "GMHtml5Options", 34 | } -------------------------------------------------------------------------------- /interop_test_23/options/ios/options_ios.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_ios_display_name": "Made in GameMaker Studio 2", 3 | "option_ios_bundle_name": "com.company.game", 4 | "option_ios_version": "1.0.0.0", 5 | "option_ios_output_dir": "~/GameMakerStudio2/iOS", 6 | "option_ios_team_id": "", 7 | "option_ios_orientation_portrait": true, 8 | "option_ios_orientation_portrait_flipped": true, 9 | "option_ios_orientation_landscape": true, 10 | "option_ios_orientation_landscape_flipped": true, 11 | "option_ios_devices": 2, 12 | "option_ios_defer_home_indicator": false, 13 | "option_ios_icon_iphone_app_120": "${base_options_dir}/ios/icons/app/iphone_120.png", 14 | "option_ios_icon_iphone_app_180": "${base_options_dir}/ios/icons/app/iphone_180.png", 15 | "option_ios_icon_ipad_app_76": "${base_options_dir}/ios/icons/app/ipad_76.png", 16 | "option_ios_icon_ipad_app_152": "${base_options_dir}/ios/icons/app/ipad_152.png", 17 | "option_ios_icon_ipad_pro_app_167": "${base_options_dir}/ios/icons/app/ipad_pro_167.png", 18 | "option_ios_icon_iphone_notification_40": "${base_options_dir}/ios/icons/notification/iphone_40.png", 19 | "option_ios_icon_iphone_notification_60": "${base_options_dir}/ios/icons/notification/iphone_60.png", 20 | "option_ios_icon_ipad_notification_20": "${base_options_dir}/ios/icons/notification/ipad_20.png", 21 | "option_ios_icon_ipad_notification_40": "${base_options_dir}/ios/icons/notification/ipad_40.png", 22 | "option_ios_icon_iphone_spotlight_80": "${base_options_dir}/ios/icons/spotlight/iphone_80.png", 23 | "option_ios_icon_iphone_spotlight_120": "${base_options_dir}/ios/icons/spotlight/iphone_120.png", 24 | "option_ios_icon_ipad_spotlight_40": "${base_options_dir}/ios/icons/spotlight/ipad_40.png", 25 | "option_ios_icon_ipad_spotlight_80": "${base_options_dir}/ios/icons/spotlight/ipad_80.png", 26 | "option_ios_icon_iphone_settings_58": "${base_options_dir}/ios/icons/settings/iphone_58.png", 27 | "option_ios_icon_iphone_settings_87": "${base_options_dir}/ios/icons/settings/iphone_87.png", 28 | "option_ios_icon_ipad_settings_29": "${base_options_dir}/ios/icons/settings/ipad_29.png", 29 | "option_ios_icon_ipad_settings_58": "${base_options_dir}/ios/icons/settings/ipad_58.png", 30 | "option_ios_icon_itunes_artwork_1024": "${base_options_dir}/ios/icons/itunes/itunes_1024.png", 31 | "option_ios_splashscreen_background_colour": 4294967295, 32 | "option_ios_launchscreen_image": "${base_options_dir}/ios/splash/launchscreen.png", 33 | "option_ios_launchscreen_image_landscape": "${base_options_dir}/ios/splash/launchscreen-landscape.png", 34 | "option_ios_launchscreen_fill": 0, 35 | "option_ios_interpolate_pixels": false, 36 | "option_ios_half_ipad1_textures": false, 37 | "option_ios_scale": 0, 38 | "option_ios_texture_page": "2048x2048", 39 | "option_ios_use_facebook": false, 40 | "option_ios_facebook_id": "", 41 | "option_ios_facebook_app_display_name": "", 42 | "option_ios_push_notifications": false, 43 | "option_ios_apple_sign_in": false, 44 | "option_ios_podfile_path": "${options_dir}/ios/Podfile", 45 | "option_ios_podfile_lock_path": "${options_dir}/ios/Podfile.lock", 46 | "resourceVersion": "1.3", 47 | "name": "iOS", 48 | "tags": [], 49 | "resourceType": "GMiOSOptions", 50 | } -------------------------------------------------------------------------------- /interop_test_23/options/linux/options_linux.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_linux_display_name": "Made in GameMaker Studio 2", 3 | "option_linux_version": "1.0.0.0", 4 | "option_linux_maintainer_email": "", 5 | "option_linux_homepage": "http://www.yoyogames.com", 6 | "option_linux_short_desc": "", 7 | "option_linux_long_desc": "", 8 | "option_linux_splash_screen": "${base_options_dir}/linux/splash/splash.png", 9 | "option_linux_display_splash": false, 10 | "option_linux_icon": "${base_options_dir}/linux/icons/64.png", 11 | "option_linux_start_fullscreen": false, 12 | "option_linux_allow_fullscreen": false, 13 | "option_linux_interpolate_pixels": false, 14 | "option_linux_display_cursor": true, 15 | "option_linux_sync": false, 16 | "option_linux_resize_window": false, 17 | "option_linux_scale": 0, 18 | "option_linux_texture_page": "2048x2048", 19 | "option_linux_enable_steam": false, 20 | "option_linux_disable_sandbox": false, 21 | "resourceVersion": "1.0", 22 | "name": "Linux", 23 | "tags": [], 24 | "resourceType": "GMLinuxOptions", 25 | } -------------------------------------------------------------------------------- /interop_test_23/options/mac/options_mac.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_mac_display_name": "Made in GameMaker Studio 2", 3 | "option_mac_app_id": "com.company.game", 4 | "option_mac_version": "1.0.0.0", 5 | "option_mac_output_dir": "~/GameMakerStudio2/Mac", 6 | "option_mac_team_id": null, 7 | "option_mac_signing_identity": "Developer ID Application:", 8 | "option_mac_copyright": "(c) 2018 CompanyName", 9 | "option_mac_splash_png": "${base_options_dir}/mac/splash/splash.png", 10 | "option_mac_icon_png": "${base_options_dir}/mac/icons/1024.png", 11 | "option_mac_menu_dock": false, 12 | "option_mac_display_cursor": true, 13 | "option_mac_start_fullscreen": false, 14 | "option_mac_allow_fullscreen": false, 15 | "option_mac_interpolate_pixels": false, 16 | "option_mac_vsync": false, 17 | "option_mac_resize_window": false, 18 | "option_mac_enable_retina": false, 19 | "option_mac_scale": 0, 20 | "option_mac_texture_page": "2048x2048", 21 | "option_mac_build_app_store": false, 22 | "option_mac_allow_incoming_network": false, 23 | "option_mac_allow_outgoing_network": false, 24 | "option_mac_app_category": "Games", 25 | "option_mac_enable_steam": false, 26 | "option_mac_disable_sandbox": false, 27 | "option_mac_apple_sign_in": false, 28 | "resourceVersion": "1.0", 29 | "name": "macOS", 30 | "tags": [], 31 | "resourceType": "GMMacOptions", 32 | } -------------------------------------------------------------------------------- /interop_test_23/options/main/inherited/options_main.inherited.yy: -------------------------------------------------------------------------------- 1 | 1.0.0←ed6a955d-5826-4f98-a450-10b414266c27←ed6a955d-5826-4f98-a450-10b414266c27|{ 2 | "option_game_speed": 30, 3 | "option_gameguid": "caab8cc1-112a-417f-aa89-bf8f42e48583" 4 | }←1225f6b0-ac20-43bd-a82e-be73fa0b6f4f|{ 5 | "targets": 461609314234257646 6 | }←7b2c4976-1e09-44e5-8256-c527145e03bb|{ 7 | "targets": 461609314234257646 8 | } -------------------------------------------------------------------------------- /interop_test_23/options/main/options_main.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMMainOptions", 3 | "resourceVersion": "1.4", 4 | "name": "Main", 5 | "option_gameguid": "caab8cc1-112a-417f-aa89-bf8f42e48583", 6 | "option_gameid": "0", 7 | "option_game_speed": 30, 8 | "option_mips_for_3d_textures": false, 9 | "option_draw_colour": 4294967295, 10 | "option_window_colour": 255, 11 | "option_steam_app_id": "0", 12 | "option_sci_usesci": false, 13 | "option_author": "", 14 | "option_collision_compatibility": true, 15 | "option_copy_on_write_enabled": true, 16 | "option_spine_licence": false, 17 | "option_template_image": "${base_options_dir}/main/template_image.png", 18 | "option_template_icon": "${base_options_dir}/main/template_icon.png", 19 | "option_template_description": null, 20 | } -------------------------------------------------------------------------------- /interop_test_23/options/operagx/options_operagx.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMOperaGXOptions", 3 | "resourceVersion": "1.0", 4 | "name": "operagx", 5 | "option_operagx_version": "1.0.0.0", 6 | "option_operagx_next_version": "1.0.0.0", 7 | "option_operagx_game_name": "${project_name}", 8 | "option_operagx_interpolate_pixels": true, 9 | "option_operagx_scale": 0, 10 | "option_operagx_texture_page": "2048x2048", 11 | "option_operagx_display_cursor": true, 12 | "option_operagx_guid": "", 13 | "option_operagx_team_name": "", 14 | "option_operagx_team_id": "", 15 | "option_operagx_editUrl": "", 16 | "option_operagx_internalShareUrl": "", 17 | "option_operagx_publicShareUrl": "", 18 | } -------------------------------------------------------------------------------- /interop_test_23/options/tvos/options_tvos.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_tvos_display_name": "Made in GameMaker Studio 2", 3 | "option_tvos_bundle_name": "com.company.game", 4 | "option_tvos_version": "1.0.0.0", 5 | "option_tvos_output_dir": "~/GameMakerStudio2/tvOS", 6 | "option_tvos_team_id": "", 7 | "option_tvos_icon_400": "${base_options_dir}/tvos/icons/400.png", 8 | "option_tvos_icon_400_2x": "${base_options_dir}/tvos/icons/400_2x.png", 9 | "option_tvos_icon_1280": "${base_options_dir}/tvos/icons/1280.png", 10 | "option_tvos_topshelf": "${base_options_dir}/tvos/topshelf/topshelf.png", 11 | "option_tvos_topshelf_2x": "${base_options_dir}/tvos/topshelf/topshelf_2x.png", 12 | "option_tvos_topshelf_wide": "${base_options_dir}/tvos/topshelf/topshelf_wide.png", 13 | "option_tvos_topshelf_wide_2x": "${base_options_dir}/tvos/topshelf/topshelf_wide_2x.png", 14 | "option_tvos_splashscreen": "${base_options_dir}/tvos/splash/splash.png", 15 | "option_tvos_splashscreen_2x": "${base_options_dir}/tvos/splash/splash_2x.png", 16 | "option_tvos_splash_time": 10, 17 | "option_tvos_interpolate_pixels": true, 18 | "option_tvos_scale": 0, 19 | "option_tvos_texture_page": "2048x2048", 20 | "option_tvos_display_cursor": false, 21 | "option_tvos_push_notifications": false, 22 | "option_tvos_apple_sign_in": false, 23 | "option_tvos_podfile_path": "${options_dir}\\tvos\\Podfile", 24 | "option_tvos_podfile_lock_path": "${options_dir}\\tvos\\Podfile.lock", 25 | "resourceVersion": "1.3", 26 | "name": "tvOS", 27 | "tags": [], 28 | "resourceType": "GMtvOSOptions", 29 | } -------------------------------------------------------------------------------- /interop_test_23/options/windows/options_windows.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_windows_display_name": "interop_test by YellowAfterlife", 3 | "option_windows_executable_name": "${project_name}", 4 | "option_windows_version": "1.0.0.0", 5 | "option_windows_company_info": "", 6 | "option_windows_product_info": "interop_test", 7 | "option_windows_copyright_info": "(c) YellowAfterlife", 8 | "option_windows_description_info": "", 9 | "option_windows_display_cursor": true, 10 | "option_windows_icon": "${base_options_dir}/windows/icons/icon.ico", 11 | "option_windows_save_location": 0, 12 | "option_windows_splash_screen": "${base_options_dir}/windows/splash/splash.png", 13 | "option_windows_use_splash": false, 14 | "option_windows_start_fullscreen": false, 15 | "option_windows_allow_fullscreen_switching": false, 16 | "option_windows_interpolate_pixels": false, 17 | "option_windows_vsync": false, 18 | "option_windows_resize_window": false, 19 | "option_windows_borderless": false, 20 | "option_windows_scale": 0, 21 | "option_windows_copy_exe_to_dest": false, 22 | "option_windows_sleep_margin": 10, 23 | "option_windows_texture_page": "2048x2048", 24 | "option_windows_installer_finished": "${base_options_dir}/windows/installer/finished.bmp", 25 | "option_windows_installer_header": "${base_options_dir}/windows/installer/header.bmp", 26 | "option_windows_license": "${base_options_dir}/windows/installer/license.txt", 27 | "option_windows_nsis_file": "${base_options_dir}/windows/installer/nsis_script.nsi", 28 | "option_windows_enable_steam": false, 29 | "option_windows_disable_sandbox": false, 30 | "option_windows_steam_use_alternative_launcher": true, 31 | "option_windows_use_x64": false, 32 | "resourceVersion": "1.1", 33 | "name": "Windows", 34 | "tags": [], 35 | "resourceType": "GMWindowsOptions", 36 | } -------------------------------------------------------------------------------- /interop_test_23/rooms/rm_test/rm_test.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnd": false, 3 | "volume": 1.0, 4 | "parentRoom": null, 5 | "views": [ 6 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1024,"hview":768,"xport":0,"yport":0,"wport":1024,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 7 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1024,"hview":768,"xport":0,"yport":0,"wport":1024,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 8 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1024,"hview":768,"xport":0,"yport":0,"wport":1024,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 9 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1024,"hview":768,"xport":0,"yport":0,"wport":1024,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 10 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1024,"hview":768,"xport":0,"yport":0,"wport":1024,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 11 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1024,"hview":768,"xport":0,"yport":0,"wport":1024,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 12 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1024,"hview":768,"xport":0,"yport":0,"wport":1024,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 13 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1024,"hview":768,"xport":0,"yport":0,"wport":1024,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 14 | ], 15 | "layers": [ 16 | {"instances":[ 17 | {"properties":[],"isDnd":false,"objectId":{"name":"obj_test","path":"objects/obj_test/obj_test.yy",},"inheritCode":false,"hasCreationCode":false,"colour":4294967295,"rotation":0.0,"scaleX":1.0,"scaleY":1.0,"imageIndex":0,"imageSpeed":1.0,"inheritedItemId":null,"frozen":false,"ignore":false,"inheritItemSettings":false,"x":0.0,"y":0.0,"resourceVersion":"1.0","name":"inst_F55A924E","tags":[],"resourceType":"GMRInstance",}, 18 | ],"visible":true,"depth":0,"userdefinedDepth":true,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Compatibility_Instances_Depth_0","tags":[],"resourceType":"GMRInstanceLayer",}, 19 | {"spriteId":null,"colour":4291141256,"x":0,"y":0,"htiled":false,"vtiled":false,"hspeed":0.0,"vspeed":0.0,"stretch":false,"animationFPS":15.0,"animationSpeedType":0,"userdefinedAnimFPS":false,"visible":true,"depth":2147483600,"userdefinedDepth":true,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Compatibility_Colour","tags":[],"resourceType":"GMRBackgroundLayer",}, 20 | ], 21 | "inheritLayers": false, 22 | "creationCodeFile": "", 23 | "inheritCode": false, 24 | "instanceCreationOrder": [ 25 | {"name":"inst_F55A924E","path":"rooms/rm_test/rm_test.yy",}, 26 | ], 27 | "inheritCreationOrder": false, 28 | "sequenceId": null, 29 | "roomSettings": { 30 | "inheritRoomSettings": false, 31 | "Width": 480, 32 | "Height": 272, 33 | "persistent": false, 34 | }, 35 | "viewSettings": { 36 | "inheritViewSettings": false, 37 | "enableViews": false, 38 | "clearViewBackground": true, 39 | "clearDisplayBuffer": true, 40 | }, 41 | "physicsSettings": { 42 | "inheritPhysicsSettings": false, 43 | "PhysicsWorld": false, 44 | "PhysicsWorldGravityX": 0.0, 45 | "PhysicsWorldGravityY": 10.0, 46 | "PhysicsWorldPixToMetres": 0.1, 47 | }, 48 | "parent": { 49 | "name": "Rooms", 50 | "path": "folders/Rooms.yy", 51 | }, 52 | "resourceVersion": "1.0", 53 | "name": "rm_test", 54 | "tags": [], 55 | "resourceType": "GMRoom", 56 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/assert/assert.gml: -------------------------------------------------------------------------------- 1 | /// @param value 2 | /// @param want 3 | /// @param ?label 4 | function assert(_val, _want, _label) { 5 | if (_label == undefined) _label = "unnamed"; 6 | if (!is_equal(_val, _want)) { 7 | show_error( 8 | "Want " + string(_want) + "\n" + 9 | "Have " + string(_val) + "\n" + 10 | "for " + string(_label) 11 | , 1) 12 | } 13 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/assert/assert.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnD": false, 3 | "isCompatibility": false, 4 | "parent": { 5 | "name": "Scripts", 6 | "path": "folders/Scripts.yy", 7 | }, 8 | "resourceVersion": "1.0", 9 | "name": "assert", 10 | "tags": [], 11 | "resourceType": "GMScript", 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/interop_test_23/interop_test_23.gml: -------------------------------------------------------------------------------- 1 | global.__ptrt_iq_thing = ["iq_thing"] 2 | function iq_thing(_ptr) constructor { 3 | __ptr__ = _ptr; 4 | static toString = function() /*=>*/ {return "iq_thing(0x" + string(__ptr__) + ")"}; 5 | } 6 | 7 | global.__ptrt_iq_id = ["iq_id"] 8 | function iq_id(_id) constructor { 9 | __id__ = _id; 10 | static toString = function() /*=>*/ {return "iq_id(" + string(__id__) + ")"}; 11 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/interop_test_23/interop_test_23.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnD": false, 3 | "isCompatibility": false, 4 | "parent": { 5 | "name": "Extensions", 6 | "path": "folders/Extensions.yy", 7 | }, 8 | "resourceVersion": "1.0", 9 | "name": "interop_test_23", 10 | "tags": [], 11 | "resourceType": "GMScript", 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/is_equal/is_equal.gml: -------------------------------------------------------------------------------- 1 | function is_equal(a, b, _depth = 0) { 2 | _depth += 1; 3 | if (is_array(a) && is_array(b)) { 4 | var n = array_length(a); 5 | if (n != array_length(b)) return false; 6 | for (var i = 0; i < n; i++) { 7 | if (!is_equal(a[i], b[i], _depth)) return false; 8 | } 9 | return true; 10 | } 11 | if (is_struct(a) && is_struct(b)) { 12 | var keys = variable_struct_get_names(a); 13 | var n = array_length(keys); 14 | if (n != array_length(variable_struct_get_names(b))) return false; 15 | for (var i = 0; i < n; i++) { 16 | var key = keys[i]; 17 | if (!variable_struct_exists(b, key)) return false; 18 | if (!is_equal(a[$ key], b[$ key], _depth)) return false; 19 | } 20 | return true; 21 | } 22 | return a == b; 23 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/is_equal/is_equal.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnD": false, 3 | "isCompatibility": false, 4 | "parent": { 5 | "name": "Scripts", 6 | "path": "folders/Scripts.yy", 7 | }, 8 | "resourceVersion": "1.0", 9 | "name": "is_equal", 10 | "tags": [], 11 | "resourceType": "GMScript", 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test/scr_test.gml: -------------------------------------------------------------------------------- 1 | globalvar iq_use_structs; 2 | function scr_test(_use_structs) { 3 | iq_use_structs = _use_structs; 4 | scr_test_basics(); 5 | scr_test_vector(); 6 | scr_test_tuple(); 7 | scr_test_buffer(); 8 | scr_test_gml_ptr(); 9 | scr_test_gml_id(); 10 | scr_test_struct(); 11 | scr_test_inout(); 12 | 13 | trace(sfmt("Test OK! (use_structs=%)",_use_structs)); 14 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test/scr_test.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnD": false, 3 | "isCompatibility": false, 4 | "parent": { 5 | "name": "tests", 6 | "path": "folders/Scripts/tests.yy", 7 | }, 8 | "resourceVersion": "1.0", 9 | "name": "scr_test", 10 | "tags": [], 11 | "resourceType": "GMScript", 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_basics/scr_test_basics.gml: -------------------------------------------------------------------------------- 1 | function scr_test_basics() { 2 | assert(iq_get_int(), 1); 3 | 4 | assert(iq_get_int64(), 0x123456789ABCDEF); 5 | 6 | assert(iq_get_string(), "hi!"); 7 | 8 | var a = 0x123456789; 9 | var b = 0x987654321; 10 | assert(iq_add_int64(a, b), a + b); 11 | 12 | assert(iq_inc_opt_int(3), 4); 13 | assert(iq_inc_opt_int(undefined), undefined); 14 | 15 | assert(iq_def_ret_int(), 3); 16 | 17 | assert(iq_def_ret_string(), "OK!"); 18 | 19 | assert(iq_add_strlens("a", "bb", "ccc", "dddd"), 10); 20 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_basics/scr_test_basics.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMScript", 3 | "resourceVersion": "1.0", 4 | "name": "scr_test_basics", 5 | "isDnD": false, 6 | "isCompatibility": false, 7 | "parent": { 8 | "name": "tests", 9 | "path": "folders/Scripts/tests.yy", 10 | }, 11 | "tags": [], 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_buffer/scr_test_buffer.gml: -------------------------------------------------------------------------------- 1 | function scr_test_buffer() { 2 | var buf = buffer_create(16, buffer_fixed, 1); 3 | buffer_fill(buf, 0, buffer_u8, 0xFF, 16); 4 | for (var i = 1; i <= 4; i++) buffer_write(buf, buffer_u8, i); 5 | assert(iq_get_buffer_sum(buf), 10); 6 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_buffer/scr_test_buffer.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMScript", 3 | "resourceVersion": "1.0", 4 | "name": "scr_test_buffer", 5 | "isDnD": false, 6 | "isCompatibility": false, 7 | "parent": { 8 | "name": "tests", 9 | "path": "folders/Scripts/tests.yy", 10 | }, 11 | "tags": [], 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_gml_id/scr_test_gml_id.gml: -------------------------------------------------------------------------------- 1 | function scr_test_gml_id() { 2 | var _id = iq_id_create(); 3 | assert(_id != undefined, true); 4 | assert(iq_id_value(_id) != 0, true); 5 | iq_id_destroy(_id); 6 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_gml_id/scr_test_gml_id.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMScript", 3 | "resourceVersion": "1.0", 4 | "name": "scr_test_gml_id", 5 | "isDnD": false, 6 | "isCompatibility": false, 7 | "parent": { 8 | "name": "tests", 9 | "path": "folders/Scripts/tests.yy", 10 | }, 11 | "tags": [], 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_gml_ptr/scr_test_gml_ptr.gml: -------------------------------------------------------------------------------- 1 | function scr_test_gml_ptr() { 2 | var th = iq_thing_create(3); 3 | assert(iq_thing_get_count(th), 3); 4 | iq_thing_set_count(th, 5); 5 | assert(iq_thing_get_count(th), 5); 6 | iq_thing_destroy(th); 7 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_gml_ptr/scr_test_gml_ptr.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMScript", 3 | "resourceVersion": "1.0", 4 | "name": "scr_test_gml_ptr", 5 | "isDnD": false, 6 | "isCompatibility": false, 7 | "parent": { 8 | "name": "tests", 9 | "path": "folders/Scripts/tests.yy", 10 | }, 11 | "tags": [], 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_inout/scr_test_inout.gml: -------------------------------------------------------------------------------- 1 | function scr_test_inout() { 2 | var box = [3]; 3 | iq_test_inout_box(box); 4 | assert(box[0], 4); 5 | // 6 | if (iq_use_structs) { 7 | var one = { 8 | a: 1, b: 3, 9 | text: "Hello!" 10 | } 11 | iq_test_inout_struct(one); 12 | assert(one.a, 2); 13 | assert(one.text, "Yeah!"); 14 | } else { 15 | var one = [ 16 | 1, 3, 17 | "Hello!" 18 | ]; 19 | iq_test_inout_struct(one); 20 | assert(one[0], 2); 21 | assert(one[2], "Yeah!"); 22 | } 23 | // 24 | var arr = [1, 2, 3]; 25 | iq_test_inout_int_vector(arr); 26 | assert(arr, [2, 3, 4]); 27 | // 28 | if (iq_use_structs) { 29 | var arr = [ 30 | { a: 1, b: 3, text: "A" }, 31 | { a: 2, b: 4, text: "B" }, 32 | ]; 33 | iq_test_inout_struct_vector(arr); 34 | } 35 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_inout/scr_test_inout.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMScript", 3 | "resourceVersion": "1.0", 4 | "name": "scr_test_inout", 5 | "isDnD": false, 6 | "isCompatibility": false, 7 | "parent": { 8 | "name": "tests", 9 | "path": "folders/Scripts/tests.yy", 10 | }, 11 | "tags": [], 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_struct/scr_test_struct.gml: -------------------------------------------------------------------------------- 1 | function scr_test_struct() { 2 | if (iq_use_structs) { 3 | assert(iq_get_struct_vec(), [ 4 | { ind: 1, name: "one" }, 5 | { ind: 2, name: "two-" }, 6 | { ind: 3, name: "tri" }, 7 | ]); 8 | } else { 9 | assert(iq_get_struct_vec(), [ 10 | [1, "one"], 11 | [2, "two-"], 12 | [3, "tri"], 13 | ]); 14 | } 15 | 16 | if (iq_use_structs) { 17 | var m1 = { 18 | num: 3, 19 | str: "hi!", 20 | grid: [ 21 | [1, 2, 3], 22 | [4, 5, 6], 23 | [7, 8, 9], 24 | ], 25 | sub: [ 26 | { a: 1, b: 2 }, 27 | { a: 3, b: 4 }, 28 | ] 29 | } 30 | var m2 = iq_mixed(m1); 31 | assert(m2, m1, "mixed"); 32 | } 33 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_struct/scr_test_struct.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMScript", 3 | "resourceVersion": "1.0", 4 | "name": "scr_test_struct", 5 | "isDnD": false, 6 | "isCompatibility": false, 7 | "parent": { 8 | "name": "tests", 9 | "path": "folders/Scripts/tests.yy", 10 | }, 11 | "tags": [], 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_tuple/scr_test_tuple.gml: -------------------------------------------------------------------------------- 1 | function scr_test_tuple() { 2 | assert(iq_get_int64_pair(), [1, 2]); 3 | 4 | assert(iq_int64_pair_sum([2, 3]), 5); 5 | 6 | assert(iq_int64_pair_swap([3, 4]), [4, 3]); 7 | 8 | assert(iq_get_int64_pair_vec_sum([ 9 | [1, 2], 10 | [3, 4], 11 | ]), [4, 6]); 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_tuple/scr_test_tuple.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMScript", 3 | "resourceVersion": "1.0", 4 | "name": "scr_test_tuple", 5 | "isDnD": false, 6 | "isCompatibility": false, 7 | "parent": { 8 | "name": "tests", 9 | "path": "folders/Scripts/tests.yy", 10 | }, 11 | "tags": [], 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_vector/scr_test_vector.gml: -------------------------------------------------------------------------------- 1 | function scr_test_vector() { 2 | assert(iq_get_vec(), [1, 2, 3]); 3 | 4 | assert(iq_get_opt_vec(true), [1, 2, 3]); 5 | assert(iq_get_opt_vec(false), undefined); 6 | 7 | assert(iq_get_int64_vec_sum([1, 2, 3]), 6); 8 | 9 | assert(iq_get_length_of_strings(["A", "B", "CD"]), 4); 10 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_vector/scr_test_vector.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMScript", 3 | "resourceVersion": "1.0", 4 | "name": "scr_test_vector", 5 | "isDnD": false, 6 | "isCompatibility": false, 7 | "parent": { 8 | "name": "tests", 9 | "path": "folders/Scripts/tests.yy", 10 | }, 11 | "tags": [], 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_yyri/scr_test_yyri.gml: -------------------------------------------------------------------------------- 1 | function scr_test_yyri() { 2 | assert(im_get_int(), 1); 3 | assert(im_get_string(), "wow"); 4 | assert(im_get_result(), "result"); 5 | assert(im_add_ints(1, 4), 5); 6 | assert(im_add_rest(1, 2, 3), 6); 7 | assert(im_string_length("hello"), 5); 8 | assert(im_typeof(""), "string"); 9 | 10 | trace(sfmt("Mangled test OK!")); 11 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/scr_test_yyri/scr_test_yyri.yy: -------------------------------------------------------------------------------- 1 | { 2 | "resourceType": "GMScript", 3 | "resourceVersion": "1.0", 4 | "name": "scr_test_yyri", 5 | "isDnD": false, 6 | "isCompatibility": false, 7 | "parent": { 8 | "name": "tests", 9 | "path": "folders/Scripts/tests.yy", 10 | }, 11 | "tags": [], 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/sfmt/sfmt.gml: -------------------------------------------------------------------------------- 1 | global.sfmt_buf = buffer_create(1024, buffer_grow, 1); 2 | global.sfmt_map = ds_map_create(); 3 | global.sfmt_warn = ds_map_create(); 4 | 5 | /// @description sfmt(format, ...values) 6 | /// @param format 7 | /// @param ...values 8 | function sfmt() { 9 | // sfmt("%/% hp", 1, 2) -> "1/2 hp" 10 | var f = argument[0]; 11 | var w = global.sfmt_map[?f], i, n; 12 | if (w == undefined) { 13 | w[0] = ""; 14 | global.sfmt_map[?f] = w; 15 | i = string_pos("%", f); 16 | n = 0; 17 | while (i) { 18 | w[n++] = string_copy(f, 1, i - 1); 19 | f = string_delete(f, 1, i); 20 | i = string_pos("%", f); 21 | } 22 | w[n++] = f; 23 | } else n = array_length_1d(w); 24 | // 25 | var b = global.sfmt_buf; 26 | buffer_seek(b, buffer_seek_start, 0); 27 | buffer_write(b, buffer_text, w[0]); 28 | var m = argument_count; 29 | for (i = 1; i < n; i++) { 30 | if (i < m) { 31 | f = string(argument[i]); 32 | if (f != "") buffer_write(b, buffer_text, f); 33 | } 34 | f = w[i]; 35 | if (f != "") buffer_write(b, buffer_text, f); 36 | } 37 | buffer_write(b, buffer_u8, 0); 38 | buffer_seek(b, buffer_seek_start, 0); 39 | return buffer_read(b, buffer_string); 40 | } 41 | -------------------------------------------------------------------------------- /interop_test_23/scripts/sfmt/sfmt.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnD": false, 3 | "isCompatibility": false, 4 | "parent": { 5 | "name": "Scripts", 6 | "path": "folders/Scripts.yy", 7 | }, 8 | "resourceVersion": "1.0", 9 | "name": "sfmt", 10 | "tags": [], 11 | "resourceType": "GMScript", 12 | } -------------------------------------------------------------------------------- /interop_test_23/scripts/trace/trace.gml: -------------------------------------------------------------------------------- 1 | /// @description trace(...) 2 | /// @param ... 3 | function trace() { 4 | var r = string(argument[0]); 5 | for (var i = 1; i < argument_count; i++) { 6 | r += " " + string(argument[i]); 7 | } 8 | show_debug_message(r); 9 | 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /interop_test_23/scripts/trace/trace.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnD": false, 3 | "isCompatibility": false, 4 | "parent": { 5 | "name": "Scripts", 6 | "path": "folders/Scripts.yy", 7 | }, 8 | "resourceVersion": "1.0", 9 | "name": "trace", 10 | "tags": [], 11 | "resourceType": "GMScript", 12 | } -------------------------------------------------------------------------------- /interop_test_yy/extensions/interop_test/interop_test.gml: -------------------------------------------------------------------------------- 1 | #define itr_test_init 2 | global.__iq_use_structs = false; 3 | global.__ptrt_iq_thing = ["iq_thing"]; 4 | 5 | #define itr_test_prepare_buffer 6 | /// (size:int)->buffer~ 7 | var _size = argument0; 8 | gml_pragma("global", "global.__itr_test_buffer = undefined"); 9 | var _buf = global.__itr_test_buffer; 10 | if (_buf == undefined) { 11 | _buf = buffer_create(_size, buffer_grow, 1); 12 | global.__itr_test_buffer = _buf; 13 | } else if (buffer_get_size(_buf) < _size) { 14 | buffer_resize(_buf, _size); 15 | } 16 | buffer_seek(_buf, buffer_seek_start, 0); 17 | return _buf; 18 | 19 | #define itr_test_read_chars 20 | /// (buffer:buffer, len:int)->string~ 21 | var _buf = argument0, _len = argument1; 22 | gml_pragma("global", "global.__itr_test_string_buffer = undefined"); 23 | var _tmp = global.__itr_test_string_buffer; 24 | if (_tmp == undefined) { 25 | _tmp = buffer_create(_len + 1, buffer_grow, 1); 26 | global.__itr_test_string_buffer = _tmp; 27 | } else if (buffer_get_size(_tmp) <= _len) { 28 | buffer_resize(_tmp, _len + 1); 29 | } 30 | buffer_copy(_buf, buffer_tell(_buf), _len, _tmp, 0); 31 | buffer_seek(_buf, buffer_seek_relative, _len); 32 | buffer_poke(_tmp, _len, buffer_u8, 0); 33 | buffer_seek(_tmp, buffer_seek_start, 0); 34 | return buffer_read(_tmp, buffer_string); 35 | 36 | #define itr_test_write_chars 37 | /// (buffer:buffer, str:string, len:int)~ 38 | var _buf = argument0, _str = argument1, _len = argument2; 39 | var _tmp = global.__itr_test_string_buffer; 40 | if (_tmp == undefined) { 41 | _tmp = buffer_create(_len + 1, buffer_grow, 1); 42 | global.__itr_test_string_buffer = _tmp; 43 | } 44 | buffer_seek(_tmp, buffer_seek_start, 0); 45 | buffer_write(_tmp, buffer_text, _str); 46 | var _pos = buffer_tell(_tmp); 47 | if (_pos < _len) buffer_fill(_tmp, _pos, buffer_u8, 0, _len - _pos); 48 | buffer_copy(_tmp, 0, _len, _buf, buffer_tell(_buf)); 49 | buffer_seek(_buf, buffer_seek_relative, _len); -------------------------------------------------------------------------------- /interop_test_yy/fonts/fnt_test/fnt_test.gms1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YAL-GameMaker-Tools/GmlCppExtFuncs/5293a574efac244853219eecb3f745ca4e062c86/interop_test_yy/fonts/fnt_test/fnt_test.gms1.png -------------------------------------------------------------------------------- /interop_test_yy/fonts/fnt_test/fnt_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YAL-GameMaker-Tools/GmlCppExtFuncs/5293a574efac244853219eecb3f745ca4e062c86/interop_test_yy/fonts/fnt_test/fnt_test.png -------------------------------------------------------------------------------- /interop_test_yy/objects/obj_test/Create_0.gml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /interop_test_yy/objects/obj_test/Draw_0.gml: -------------------------------------------------------------------------------- 1 | draw_set_font(fnt_test); 2 | draw_set_color(c_white); 3 | 4 | -------------------------------------------------------------------------------- /interop_test_yy/objects/obj_test/Step_0.gml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /interop_test_yy/objects/obj_test/obj_test.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "9a74872b-1d34-4b7c-8038-1116e4426c86", 3 | "modelName": "GMObject", 4 | "mvc": "1.0", 5 | "name": "obj_test", 6 | "eventList": [ 7 | { 8 | "id": "f93557ac-a01c-475b-a656-4fbd2ebcf2fb", 9 | "modelName": "GMEvent", 10 | "mvc": "1.0", 11 | "IsDnD": false, 12 | "collisionObjectId": "00000000-0000-0000-0000-000000000000", 13 | "enumb": 0, 14 | "eventtype": 0, 15 | "m_owner": "9a74872b-1d34-4b7c-8038-1116e4426c86" 16 | }, 17 | { 18 | "id": "9f151821-c696-4aef-b011-948071008f29", 19 | "modelName": "GMEvent", 20 | "mvc": "1.0", 21 | "IsDnD": false, 22 | "collisionObjectId": "00000000-0000-0000-0000-000000000000", 23 | "enumb": 0, 24 | "eventtype": 3, 25 | "m_owner": "9a74872b-1d34-4b7c-8038-1116e4426c86" 26 | }, 27 | { 28 | "id": "6ef8ae5e-f16b-4a4b-8d63-5453f3f747bb", 29 | "modelName": "GMEvent", 30 | "mvc": "1.0", 31 | "IsDnD": false, 32 | "collisionObjectId": "00000000-0000-0000-0000-000000000000", 33 | "enumb": 0, 34 | "eventtype": 8, 35 | "m_owner": "9a74872b-1d34-4b7c-8038-1116e4426c86" 36 | } 37 | ], 38 | "maskSpriteId": "00000000-0000-0000-0000-000000000000", 39 | "overriddenProperties": null, 40 | "parentObjectId": "00000000-0000-0000-0000-000000000000", 41 | "persistent": false, 42 | "physicsAngularDamping": 0.1, 43 | "physicsDensity": 0.5, 44 | "physicsFriction": 0.2, 45 | "physicsGroup": 0, 46 | "physicsKinematic": false, 47 | "physicsLinearDamping": 0.1, 48 | "physicsObject": false, 49 | "physicsRestitution": 0.1, 50 | "physicsSensor": false, 51 | "physicsShape": 0, 52 | "physicsShapePoints": [ 53 | 54 | ], 55 | "physicsStartAwake": true, 56 | "properties": null, 57 | "solid": false, 58 | "spriteId": "00000000-0000-0000-0000-000000000000", 59 | "visible": true 60 | } -------------------------------------------------------------------------------- /interop_test_yy/options/amazonfire/options_amazonfire.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "a128950b-5063-4876-b4a6-b99dbd2ea6d1", 3 | "modelName": "GMAmazonFireOptions", 4 | "mvc": "1.0", 5 | "name": "Amazon Fire", 6 | "option_amazonfire_application_tag_inject": null, 7 | "option_amazonfire_build_tools": "", 8 | "option_amazonfire_compile_sdk": "", 9 | "option_amazonfire_display_name": "Made in GameMaker Studio 2", 10 | "option_amazonfire_gamepad_support": true, 11 | "option_amazonfire_icon_hdpi": "${base_options_dir}\\amazonfire\\icons\\hdpi.png", 12 | "option_amazonfire_icon_ldpi": "${base_options_dir}\\amazonfire\\icons\\ldpi.png", 13 | "option_amazonfire_icon_mdpi": "${base_options_dir}\\amazonfire\\icons\\mdpi.png", 14 | "option_amazonfire_icon_xhdpi": "${base_options_dir}\\amazonfire\\icons\\xhdpi.png", 15 | "option_amazonfire_icon_xxhdpi": "${base_options_dir}\\amazonfire\\icons\\xxhdpi.png", 16 | "option_amazonfire_icon_xxxhdpi": "${base_options_dir}\\amazonfire\\icons\\xxxhdpi.png", 17 | "option_amazonfire_install_location": 0, 18 | "option_amazonfire_interpolate_pixels": false, 19 | "option_amazonfire_lint": false, 20 | "option_amazonfire_minimum_sdk": "", 21 | "option_amazonfire_orient_landscape": true, 22 | "option_amazonfire_orient_landscape_flipped": true, 23 | "option_amazonfire_orient_portrait": true, 24 | "option_amazonfire_orient_portrait_flipped": true, 25 | "option_amazonfire_package_company": "company", 26 | "option_amazonfire_package_domain": "com", 27 | "option_amazonfire_package_product": "game", 28 | "option_amazonfire_permission_bluetooth": false, 29 | "option_amazonfire_permission_internet": true, 30 | "option_amazonfire_permission_network_state": false, 31 | "option_amazonfire_permission_read_phone_state": false, 32 | "option_amazonfire_permission_record_audio": false, 33 | "option_amazonfire_permission_write_external_storage": false, 34 | "option_amazonfire_scale": 0, 35 | "option_amazonfire_screen_depth": 0, 36 | "option_amazonfire_sleep_margin": 4, 37 | "option_amazonfire_splash_screens_landscape": "${base_options_dir}\\amazonfire\\splash\\landscape.png", 38 | "option_amazonfire_splash_screens_portrait": "${base_options_dir}\\amazonfire\\splash\\portrait.png", 39 | "option_amazonfire_splash_time": 0, 40 | "option_amazonfire_support_lib": "", 41 | "option_amazonfire_sync_android": false, 42 | "option_amazonfire_target_sdk": "", 43 | "option_amazonfire_texture_page": "2048x2048", 44 | "option_amazonfire_tools_from_version": false, 45 | "option_amazonfire_tv_banner": "${base_options_dir}\\amazonfire\\tv_banner.png", 46 | "option_amazonfire_version": { 47 | "build": 0, 48 | "major": 1, 49 | "minor": 0, 50 | "revision": 0 51 | } 52 | } -------------------------------------------------------------------------------- /interop_test_yy/options/android/options_android.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "e42bf5cc-3f46-4d67-a6d0-a4885a11ac3f", 3 | "modelName": "GMAndroidOptions", 4 | "mvc": "1.0", 5 | "name": "Android", 6 | "option_android_application_tag_inject": null, 7 | "option_android_arch_arm64": false, 8 | "option_android_arch_armv7": true, 9 | "option_android_arch_x86": false, 10 | "option_android_arch_x86_64": false, 11 | "option_android_build_tools": "", 12 | "option_android_compile_sdk": "", 13 | "option_android_device_support": 0, 14 | "option_android_display_name": "Made in GameMaker Studio 2", 15 | "option_android_facebook_app_display_name": "", 16 | "option_android_facebook_id": "", 17 | "option_android_gamepad_support": true, 18 | "option_android_google_apk_expansion": false, 19 | "option_android_google_cloud_saving": false, 20 | "option_android_google_licensing_public_key": "", 21 | "option_android_google_services_app_id": "", 22 | "option_android_icon_adaptive_generate": false, 23 | "option_android_icon_adaptive_hdpi": "${base_options_dir}\/android\/icons_adaptive\/hdpi.png", 24 | "option_android_icon_adaptive_ldpi": "${base_options_dir}\/android\/icons_adaptive\/ldpi.png", 25 | "option_android_icon_adaptive_mdpi": "${base_options_dir}\/android\/icons_adaptive\/mdpi.png", 26 | "option_android_icon_adaptive_xhdpi": "${base_options_dir}\/android\/icons_adaptive\/xhdpi.png", 27 | "option_android_icon_adaptive_xxhdpi": "${base_options_dir}\/android\/icons_adaptive\/xxhdpi.png", 28 | "option_android_icon_adaptive_xxxhdpi": "${base_options_dir}\/android\/icons_adaptive\/xxxhdpi.png", 29 | "option_android_icon_adaptivebg_hdpi": "${base_options_dir}\/android\/icons_adaptivebg\/hdpi.png", 30 | "option_android_icon_adaptivebg_ldpi": "${base_options_dir}\/android\/icons_adaptivebg\/ldpi.png", 31 | "option_android_icon_adaptivebg_mdpi": "${base_options_dir}\/android\/icons_adaptivebg\/mdpi.png", 32 | "option_android_icon_adaptivebg_xhdpi": "${base_options_dir}\/android\/icons_adaptivebg\/xhdpi.png", 33 | "option_android_icon_adaptivebg_xxhdpi": "${base_options_dir}\/android\/icons_adaptivebg\/xxhdpi.png", 34 | "option_android_icon_adaptivebg_xxxhdpi": "${base_options_dir}\/android\/icons_adaptivebg\/xxxhdpi.png", 35 | "option_android_icon_hdpi": "${base_options_dir}\/android\/icons\/hdpi.png", 36 | "option_android_icon_ldpi": "${base_options_dir}\/android\/icons\/ldpi.png", 37 | "option_android_icon_mdpi": "${base_options_dir}\/android\/icons\/mdpi.png", 38 | "option_android_icon_xhdpi": "${base_options_dir}\/android\/icons\/xhdpi.png", 39 | "option_android_icon_xxhdpi": "${base_options_dir}\/android\/icons\/xxhdpi.png", 40 | "option_android_icon_xxxhdpi": "${base_options_dir}\/android\/icons\/xxxhdpi.png", 41 | "option_android_install_location": 0, 42 | "option_android_interpolate_pixels": false, 43 | "option_android_lint": false, 44 | "option_android_minimum_sdk": "", 45 | "option_android_orient_landscape": true, 46 | "option_android_orient_landscape_flipped": true, 47 | "option_android_orient_portrait": true, 48 | "option_android_orient_portrait_flipped": true, 49 | "option_android_package_company": "company", 50 | "option_android_package_domain": "com", 51 | "option_android_package_product": "game", 52 | "option_android_permission_bluetooth": false, 53 | "option_android_permission_internet": true, 54 | "option_android_permission_network_state": false, 55 | "option_android_permission_read_phone_state": false, 56 | "option_android_permission_record_audio": false, 57 | "option_android_permission_write_external_storage": false, 58 | "option_android_scale": 0, 59 | "option_android_screen_depth": 0, 60 | "option_android_sleep_margin": 4, 61 | "option_android_splash_screens_landscape": "${base_options_dir}\/android\/splash\/landscape.png", 62 | "option_android_splash_screens_portrait": "${base_options_dir}\/android\/splash\/portrait.png", 63 | "option_android_splash_time": 0, 64 | "option_android_support_lib": "", 65 | "option_android_sync_amazon": false, 66 | "option_android_target_sdk": "", 67 | "option_android_texture_page": "2048x2048", 68 | "option_android_tools_from_version": false, 69 | "option_android_tv_banner": "${base_options_dir}\\android\\tv_banner.png", 70 | "option_android_tv_isgame": true, 71 | "option_android_use_facebook": false, 72 | "option_android_version": { 73 | "build": 0, 74 | "major": 1, 75 | "minor": 0, 76 | "revision": 0 77 | } 78 | } -------------------------------------------------------------------------------- /interop_test_yy/options/html5/options_html5.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "75ac291e-7061-4bcb-8e8a-3b3545332d41", 3 | "modelName": "GMHtml5Options", 4 | "mvc": "1.0", 5 | "name": "HTML5", 6 | "option_html5_allow_fullscreen": true, 7 | "option_html5_browser_title": "Made in GameMaker Studio 2", 8 | "option_html5_centregame": false, 9 | "option_html5_display_cursor": true, 10 | "option_html5_facebook_app_display_name": "", 11 | "option_html5_facebook_id": "", 12 | "option_html5_flurry_enable": false, 13 | "option_html5_flurry_id": "", 14 | "option_html5_foldername": "html5game", 15 | "option_html5_google_analytics_enable": false, 16 | "option_html5_google_tracking_id": "", 17 | "option_html5_icon": "${base_options_dir}\/html5\/fav.ico", 18 | "option_html5_index": "", 19 | "option_html5_interpolate_pixels": false, 20 | "option_html5_jsprepend": "", 21 | "option_html5_loadingbar": "", 22 | "option_html5_localrunalert": true, 23 | "option_html5_outputdebugtoconsole": true, 24 | "option_html5_outputname": "index.html", 25 | "option_html5_scale": 0, 26 | "option_html5_splash_png": "${base_options_dir}\/html5\/splash.png", 27 | "option_html5_texture_page": "2048x2048", 28 | "option_html5_use_facebook": false, 29 | "option_html5_usebuiltinfont": true, 30 | "option_html5_usebuiltinparticles": true, 31 | "option_html5_usesplash": false, 32 | "option_html5_version": { 33 | "build": 0, 34 | "major": 1, 35 | "minor": 0, 36 | "revision": 0 37 | }, 38 | "option_html5_webgl": 2 39 | } -------------------------------------------------------------------------------- /interop_test_yy/options/linux/options_linux.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "a9188620-a624-4a5a-83ae-a1b53faf038b", 3 | "modelName": "GMLinuxOptions", 4 | "mvc": "1.0", 5 | "name": "Linux", 6 | "option_linux_allow_fullscreen": false, 7 | "option_linux_disable_sandbox": false, 8 | "option_linux_display_cursor": true, 9 | "option_linux_display_name": "Made in GameMaker Studio 2", 10 | "option_linux_display_splash": false, 11 | "option_linux_enable_steam": false, 12 | "option_linux_homepage": "http:\/\/www.yoyogames.com", 13 | "option_linux_icon": "${base_options_dir}\/linux\/icons\/64.png", 14 | "option_linux_interpolate_pixels": false, 15 | "option_linux_long_desc": "", 16 | "option_linux_maintainer_email": "", 17 | "option_linux_resize_window": false, 18 | "option_linux_scale": 0, 19 | "option_linux_short_desc": "", 20 | "option_linux_splash_screen": "${base_options_dir}\/linux\/splash\/splash.png", 21 | "option_linux_start_fullscreen": false, 22 | "option_linux_sync": false, 23 | "option_linux_texture_page": "2048x2048", 24 | "option_linux_version": { 25 | "build": 0, 26 | "major": 1, 27 | "minor": 0, 28 | "revision": 0 29 | } 30 | } -------------------------------------------------------------------------------- /interop_test_yy/options/mac/options_mac.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "f418569b-3bdd-4706-a0e4-364317f54032", 3 | "modelName": "GMMacOptions", 4 | "mvc": "1.0", 5 | "name": "macOS", 6 | "option_mac_allow_fullscreen": false, 7 | "option_mac_allow_incoming_network": false, 8 | "option_mac_allow_outgoing_network": false, 9 | "option_mac_app_category": "Games", 10 | "option_mac_app_id": "com.company.game", 11 | "option_mac_apple_sign_in": false, 12 | "option_mac_build_app_store": false, 13 | "option_mac_copyright": "(c) 2018 CompanyName", 14 | "option_mac_disable_sandbox": false, 15 | "option_mac_display_cursor": true, 16 | "option_mac_display_name": "Made in GameMaker Studio 2", 17 | "option_mac_enable_retina": false, 18 | "option_mac_enable_steam": false, 19 | "option_mac_icon_png": "${base_options_dir}\/mac\/icons\/1024.png", 20 | "option_mac_interpolate_pixels": false, 21 | "option_mac_menu_dock": false, 22 | "option_mac_output_dir": "~\/GameMakerStudio2\/Mac", 23 | "option_mac_resize_window": false, 24 | "option_mac_scale": 0, 25 | "option_mac_signing_identity": "Developer ID Application:", 26 | "option_mac_splash_png": "${base_options_dir}\/mac\/splash\/splash.png", 27 | "option_mac_start_fullscreen": false, 28 | "option_mac_team_id": null, 29 | "option_mac_texture_page": "2048x2048", 30 | "option_mac_version": { 31 | "build": 0, 32 | "major": 1, 33 | "minor": 0, 34 | "revision": 0 35 | }, 36 | "option_mac_vsync": false 37 | } -------------------------------------------------------------------------------- /interop_test_yy/options/main/inherited/options_main.inherited.yy: -------------------------------------------------------------------------------- 1 | 1.0.0←ed6a955d-5826-4f98-a450-10b414266c27←ed6a955d-5826-4f98-a450-10b414266c27|{ 2 | "option_game_speed": 30, 3 | "option_gameguid": "caab8cc1-112a-417f-aa89-bf8f42e48583" 4 | }←1225f6b0-ac20-43bd-a82e-be73fa0b6f4f|{ 5 | "targets": 461609314234257646 6 | }←7b2c4976-1e09-44e5-8256-c527145e03bb|{ 7 | "targets": 461609314234257646 8 | } -------------------------------------------------------------------------------- /interop_test_yy/options/switch/options_switch.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "3a5af38c-757d-41ae-98c0-5d4b09e14e6a", 3 | "modelName": "GMSwitchOptions", 4 | "mvc": "1.0", 5 | "name": "Switch", 6 | "option_switch_allow_debug_output": false, 7 | "option_switch_check_nsp_publish_errors": true, 8 | "option_switch_enable_fileaccess_checking": true, 9 | "option_switch_enable_nex_libraries": false, 10 | "option_switch_interpolate_pixels": true, 11 | "option_switch_project_nmeta": "${options_dir}\/switch\/application.nmeta", 12 | "option_switch_scale": 0, 13 | "option_switch_splash_screen": "${options_dir}\\switch\\splash.png", 14 | "option_switch_texture_page": "2048x2048", 15 | "option_switch_use_splash": true 16 | } -------------------------------------------------------------------------------- /interop_test_yy/options/tvos/options_tvos.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "93566aad-c3b3-48a9-8fa7-9c5ee19f74ac", 3 | "modelName": "GMtvOSOptions", 4 | "mvc": "1.0", 5 | "name": "tvOS", 6 | "option_tvos_apple_sign_in": false, 7 | "option_tvos_bundle_name": "com.company.game", 8 | "option_tvos_display_cursor": false, 9 | "option_tvos_display_name": "Made in GameMaker Studio 2", 10 | "option_tvos_icon_1280": "${base_options_dir}\\tvos\\icons\\1280.png", 11 | "option_tvos_icon_400": "${base_options_dir}\\tvos\\icons\\400.png", 12 | "option_tvos_icon_400_2x": "${base_options_dir}\\tvos\\icons\\400_2x.png", 13 | "option_tvos_interpolate_pixels": true, 14 | "option_tvos_output_dir": "~\/GameMakerStudio2\/tvOS", 15 | "option_tvos_push_notifications": false, 16 | "option_tvos_scale": 0, 17 | "option_tvos_splash_time": 10, 18 | "option_tvos_splashscreen": "${base_options_dir}\\tvos\\splash\\splash.png", 19 | "option_tvos_splashscreen_2x": "${base_options_dir}\\tvos\\splash\\splash_2x.png", 20 | "option_tvos_team_id": "", 21 | "option_tvos_texture_page": "2048x2048", 22 | "option_tvos_topshelf": "${base_options_dir}\\tvos\\topshelf\\topshelf.png", 23 | "option_tvos_topshelf_2x": "${base_options_dir}\\tvos\\topshelf\\topshelf_2x.png", 24 | "option_tvos_topshelf_wide": "${base_options_dir}\\tvos\\topshelf\\topshelf_wide.png", 25 | "option_tvos_topshelf_wide_2x": "${base_options_dir}\\tvos\\topshelf\\topshelf_wide_2x.png", 26 | "option_tvos_version": { 27 | "build": 0, 28 | "major": 1, 29 | "minor": 0, 30 | "revision": 0 31 | } 32 | } -------------------------------------------------------------------------------- /interop_test_yy/options/windows/options_windows.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "cc98d028-7bdd-4680-85f3-c87a7baa481e", 3 | "modelName": "GMWindowsOptions", 4 | "mvc": "1.0", 5 | "name": "Windows", 6 | "option_windows_allow_fullscreen_switching": false, 7 | "option_windows_borderless": false, 8 | "option_windows_company_info": "", 9 | "option_windows_copy_exe_to_dest": false, 10 | "option_windows_copyright_info": "(c) YellowAfterlife", 11 | "option_windows_description_info": "", 12 | "option_windows_disable_sandbox": false, 13 | "option_windows_display_cursor": true, 14 | "option_windows_display_name": "interop_test by YellowAfterlife", 15 | "option_windows_enable_steam": false, 16 | "option_windows_executable_name": "${project_name}", 17 | "option_windows_icon": "${base_options_dir}\\windows\\icons\\icon.ico", 18 | "option_windows_installer_finished": "${base_options_dir}\\windows\\installer\\finished.bmp", 19 | "option_windows_installer_header": "${base_options_dir}\\windows\\installer\\header.bmp", 20 | "option_windows_interpolate_pixels": false, 21 | "option_windows_license": "${base_options_dir}\\windows\\installer\\license.txt", 22 | "option_windows_nsis_file": "${base_options_dir}\\windows\\installer\\nsis_script.nsi", 23 | "option_windows_product_info": "interop_test", 24 | "option_windows_resize_window": false, 25 | "option_windows_save_location": 0, 26 | "option_windows_scale": 0, 27 | "option_windows_sleep_margin": 10, 28 | "option_windows_splash_screen": "${base_options_dir}\\windows\\splash\\splash.png", 29 | "option_windows_start_fullscreen": false, 30 | "option_windows_steam_use_alternative_launcher": true, 31 | "option_windows_texture_page": "2048x2048", 32 | "option_windows_use_splash": false, 33 | "option_windows_version": { 34 | "build": 0, 35 | "major": 1, 36 | "minor": 0, 37 | "revision": 0 38 | }, 39 | "option_windows_vsync": false 40 | } -------------------------------------------------------------------------------- /interop_test_yy/scripts/trace/trace.gml: -------------------------------------------------------------------------------- 1 | /// @description trace(...) 2 | /// @param ... 3 | var r = string(argument[0]); 4 | for (var i = 1; i < argument_count; i++) { 5 | r += " " + string(argument[i]); 6 | } 7 | show_debug_message(r); 8 | -------------------------------------------------------------------------------- /interop_test_yy/scripts/trace/trace.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "b0dd5a43-c44b-402e-b40f-a394287a9e3e", 3 | "modelName": "GMScript", 4 | "mvc": "1.0", 5 | "name": "trace", 6 | "IsCompatibility": false, 7 | "IsDnD": false 8 | } -------------------------------------------------------------------------------- /interop_test_yy/views/1a1012ca-9702-4cd0-870a-3101ca12fddb.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "1a1012ca-9702-4cd0-870a-3101ca12fddb", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "1a1012ca-9702-4cd0-870a-3101ca12fddb", 6 | "children": [ 7 | 8 | ], 9 | "filterType": "GMSprite", 10 | "folderName": "sprites", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Sprites" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/4f96784b-1ebd-4fc6-8c5b-10ee426a2840.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "4f96784b-1ebd-4fc6-8c5b-10ee426a2840", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "4f96784b-1ebd-4fc6-8c5b-10ee426a2840", 6 | "children": [ 7 | "1a1012ca-9702-4cd0-870a-3101ca12fddb", 8 | "9fdcc299-adf8-4729-b2f3-076ababf81ed", 9 | "9878a9d0-ce0a-4455-91a7-89de6e4976a2", 10 | "e5b1e8fe-f417-43e8-b65f-8a518d723aea", 11 | "c9dcc6e5-46f1-4578-8543-9af4f6a4f7de", 12 | "f664cd6f-a19b-470a-8b94-844b0367b313", 13 | "f2ec9b0e-c3fe-4297-a78d-fa6f418fd827", 14 | "c583b9bc-76c2-490f-a077-1eeafac7f5ec", 15 | "e5bc0382-83e6-4bfa-b68f-c702a7545129", 16 | "504c1931-39ad-4f48-b783-4eb537b963d6", 17 | "f8edfe34-8789-4236-b7e4-741b59e181b8", 18 | "690caa00-bb5f-4c7f-b921-6fd3330a6bc3", 19 | "6e9a4a1b-fa39-4f06-94c9-1a7f8822216a", 20 | "8c638ff8-1abe-4e11-bc32-7ef6af8b7b4f", 21 | "81be6123-f045-42c2-ad8f-dd97676ed387" 22 | ], 23 | "filterType": "root", 24 | "folderName": "Default", 25 | "isDefaultView": true, 26 | "localisedFolderName": "" 27 | } -------------------------------------------------------------------------------- /interop_test_yy/views/504c1931-39ad-4f48-b783-4eb537b963d6.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "504c1931-39ad-4f48-b783-4eb537b963d6", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "504c1931-39ad-4f48-b783-4eb537b963d6", 6 | "children": [ 7 | "ce213238-b114-4f2b-bed8-b066f6e9de72" 8 | ], 9 | "filterType": "GMRoom", 10 | "folderName": "rooms", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Rooms" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/690caa00-bb5f-4c7f-b921-6fd3330a6bc3.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "690caa00-bb5f-4c7f-b921-6fd3330a6bc3", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "690caa00-bb5f-4c7f-b921-6fd3330a6bc3", 6 | "children": [ 7 | 8 | ], 9 | "filterType": "GMIncludedFile", 10 | "folderName": "datafiles", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_IncludedFiles" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/6e9a4a1b-fa39-4f06-94c9-1a7f8822216a.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "6e9a4a1b-fa39-4f06-94c9-1a7f8822216a", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "6e9a4a1b-fa39-4f06-94c9-1a7f8822216a", 6 | "children": [ 7 | "9fa1a0e1-7fc5-429a-b8c2-75333f34fd29" 8 | ], 9 | "filterType": "GMExtension", 10 | "folderName": "extensions", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Extensions" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/81be6123-f045-42c2-ad8f-dd97676ed387.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "81be6123-f045-42c2-ad8f-dd97676ed387", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "81be6123-f045-42c2-ad8f-dd97676ed387", 6 | "children": [ 7 | 8 | ], 9 | "filterType": "GMConfig", 10 | "folderName": "configs", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Configs" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/8c638ff8-1abe-4e11-bc32-7ef6af8b7b4f.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "8c638ff8-1abe-4e11-bc32-7ef6af8b7b4f", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "8c638ff8-1abe-4e11-bc32-7ef6af8b7b4f", 6 | "children": [ 7 | "ed6a955d-5826-4f98-a450-10b414266c27", 8 | "f418569b-3bdd-4706-a0e4-364317f54032", 9 | "a9188620-a624-4a5a-83ae-a1b53faf038b", 10 | "cc98d028-7bdd-4680-85f3-c87a7baa481e", 11 | "3a5af38c-757d-41ae-98c0-5d4b09e14e6a" 12 | ], 13 | "filterType": "GMOptions", 14 | "folderName": "options", 15 | "isDefaultView": false, 16 | "localisedFolderName": "ResourceTree_Options" 17 | } -------------------------------------------------------------------------------- /interop_test_yy/views/9878a9d0-ce0a-4455-91a7-89de6e4976a2.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "9878a9d0-ce0a-4455-91a7-89de6e4976a2", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "9878a9d0-ce0a-4455-91a7-89de6e4976a2", 6 | "children": [ 7 | 8 | ], 9 | "filterType": "GMSound", 10 | "folderName": "sounds", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Sounds" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/9fdcc299-adf8-4729-b2f3-076ababf81ed.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "9fdcc299-adf8-4729-b2f3-076ababf81ed", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "9fdcc299-adf8-4729-b2f3-076ababf81ed", 6 | "children": [ 7 | 8 | ], 9 | "filterType": "GMTileSet", 10 | "folderName": "tilesets", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Tilesets" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/c583b9bc-76c2-490f-a077-1eeafac7f5ec.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "c583b9bc-76c2-490f-a077-1eeafac7f5ec", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "c583b9bc-76c2-490f-a077-1eeafac7f5ec", 6 | "children": [ 7 | 8 | ], 9 | "filterType": "GMTimeline", 10 | "folderName": "timelines", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Timelines" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/c9dcc6e5-46f1-4578-8543-9af4f6a4f7de.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "c9dcc6e5-46f1-4578-8543-9af4f6a4f7de", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "c9dcc6e5-46f1-4578-8543-9af4f6a4f7de", 6 | "children": [ 7 | "b0dd5a43-c44b-402e-b40f-a394287a9e3e" 8 | ], 9 | "filterType": "GMScript", 10 | "folderName": "scripts", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Scripts" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/e5b1e8fe-f417-43e8-b65f-8a518d723aea.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "e5b1e8fe-f417-43e8-b65f-8a518d723aea", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "e5b1e8fe-f417-43e8-b65f-8a518d723aea", 6 | "children": [ 7 | 8 | ], 9 | "filterType": "GMPath", 10 | "folderName": "paths", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Paths" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/e5bc0382-83e6-4bfa-b68f-c702a7545129.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "e5bc0382-83e6-4bfa-b68f-c702a7545129", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "e5bc0382-83e6-4bfa-b68f-c702a7545129", 6 | "children": [ 7 | "9a74872b-1d34-4b7c-8038-1116e4426c86" 8 | ], 9 | "filterType": "GMObject", 10 | "folderName": "objects", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Objects" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/f2ec9b0e-c3fe-4297-a78d-fa6f418fd827.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "f2ec9b0e-c3fe-4297-a78d-fa6f418fd827", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "f2ec9b0e-c3fe-4297-a78d-fa6f418fd827", 6 | "children": [ 7 | "7a21cc3d-d166-41e9-b51a-ecd396e706aa" 8 | ], 9 | "filterType": "GMFont", 10 | "folderName": "fonts", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Fonts" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/f664cd6f-a19b-470a-8b94-844b0367b313.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "f664cd6f-a19b-470a-8b94-844b0367b313", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "f664cd6f-a19b-470a-8b94-844b0367b313", 6 | "children": [ 7 | 8 | ], 9 | "filterType": "GMShader", 10 | "folderName": "shaders", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Shaders" 13 | } -------------------------------------------------------------------------------- /interop_test_yy/views/f8edfe34-8789-4236-b7e4-741b59e181b8.yy: -------------------------------------------------------------------------------- 1 | { 2 | "id": "f8edfe34-8789-4236-b7e4-741b59e181b8", 3 | "modelName": "GMFolder", 4 | "mvc": "1.1", 5 | "name": "f8edfe34-8789-4236-b7e4-741b59e181b8", 6 | "children": [ 7 | 8 | ], 9 | "filterType": "GMNotes", 10 | "folderName": "notes", 11 | "isDefaultView": false, 12 | "localisedFolderName": "ResourceTree_Notes" 13 | } -------------------------------------------------------------------------------- /src/CppGen.hx: -------------------------------------------------------------------------------- 1 | package ; 2 | import misc.GmlConstructor; 3 | import tools.GmkGen; 4 | import func.CppFunc; 5 | import func.CppFuncMangled; 6 | import haxe.io.Path; 7 | #if sys 8 | import sys.io.File; 9 | import sys.FileSystem; 10 | #end 11 | import struct.CppStruct; 12 | import tools.CppReader; 13 | import tools.CppBuf; 14 | using StringTools; 15 | 16 | /** 17 | * ... 18 | * @author YellowAfterlife 19 | */ 20 | class CppGen { 21 | public static var config:CppConfig = new CppConfig(); 22 | 23 | public static var outCppPath:String = null; 24 | public static var outGmlPath:String = null; 25 | public static var outGmlExtrasPath:String = null; 26 | public static var outGmkPath:String = null; 27 | public static var hasGmkPath(get, never):Bool; 28 | static function get_hasGmkPath(){ 29 | return outGmkPath != null; 30 | } 31 | 32 | public static inline function procFile(path:String, cpp:String, indexStructs:Bool) { 33 | CppGenParser.procFile(path, cpp, indexStructs); 34 | } 35 | 36 | public static function warn(text:String) { 37 | #if js 38 | js.Browser.console.warn(text); 39 | #else 40 | Sys.println("GmlCppExtFuncs: warning #: " + text); 41 | #end 42 | } 43 | 44 | static function writeIfNotSame(path:String, text:String) { 45 | #if sys 46 | if (!FileSystem.exists(path)) { 47 | File.saveContent(path, text); 48 | } else { 49 | var curr = try { 50 | File.getContent(path); 51 | } catch (x:Dynamic) null; 52 | if (curr != text) File.saveContent(path, text); 53 | } 54 | #else 55 | trace(path); 56 | trace(text); 57 | #end 58 | } 59 | 60 | public static function finish() { 61 | var gml = new CppBuf(); 62 | var cpp = new CppBuf(); 63 | 64 | for (line in config.prepend) { 65 | cpp.addFormat("%s%|", line); 66 | } 67 | for (fn in CppFunc.list) if (fn.isMangled) { 68 | config.includes.insert(1, "gml_extm.h"); 69 | break; 70 | } 71 | for (inc in config.includes) { 72 | cpp.addFormat('#include "%s"%|', inc); 73 | } 74 | 75 | if (outGmkPath != null) { 76 | cpp.addFormat("gmk_buffer %s;%|", GmkGen.argBuffer); 77 | } 78 | 79 | if (CppStruct.list.length > 0) { 80 | var prefix = false; 81 | for (struct in CppStruct.list) if (struct.shouldForwardDeclare) { 82 | var byval = CppType.useMap[struct.name]; 83 | if (byval == null) continue; 84 | if (!prefix) { 85 | prefix = true; 86 | cpp.addFormat("// Struct forward declarations:%|"); 87 | } 88 | cpp.addFormat("// from %s:%|", struct.origin); 89 | if (byval > 0) { 90 | cpp.addFormat("%s;%|", struct.impl); 91 | } else cpp.addFormat("struct %s;%|", struct.name); 92 | } 93 | } 94 | 95 | var fnCond = ""; 96 | for (fn in func.CppFunc.list) { 97 | #if !sys 98 | trace(fn); 99 | #end 100 | if (fnCond != fn.condition) { 101 | if (fnCond != "") cpp.addFormat("#endif // %s%|%|", fnCond); 102 | fnCond = fn.condition; 103 | if (fnCond != "") cpp.addFormat("#if %s%|%|", fnCond); 104 | } 105 | fn.print(gml, cpp); 106 | } 107 | if (fnCond != "") cpp.addFormat("#endif // %s%|", fnCond); 108 | 109 | for (line in config.append) cpp.addFormat("%|%s", line); 110 | 111 | var gmlCode = gml.toString(); 112 | var cppCode = cpp.toString(); 113 | if (outGmkPath != null) { 114 | cppCode = tools.GmkGen.run(gmlCode, cppCode); 115 | } 116 | writeIfNotSame(outGmlPath, gmlCode); 117 | writeIfNotSame(outCppPath, cppCode); 118 | // 119 | var extras = new CppBuf(); 120 | GmlConstructor.print(extras); 121 | if (extras.length == 0) { 122 | // OK! 123 | } else if (outGmlExtrasPath == null) { 124 | CppGen.warn('Constructors are used but no --gml-extras path is set'); 125 | } else { 126 | writeIfNotSame(outGmlExtrasPath, extras.toString()); 127 | } 128 | } 129 | #if sys 130 | public static function procArg(full:String, indexStructs:Bool) { 131 | var rel = Path.withoutDirectory(full); 132 | if (rel.indexOf("*") >= 0) { 133 | var rs = new EReg("([.*+?^${}()|[\\]\\/\\\\])", "g").replace(rel, "\\$1"); 134 | rs = StringTools.replace(rs, "\\*", ".*?"); 135 | var rx = try { 136 | new EReg("^" + rs + "$", ""); 137 | } catch (x:Dynamic) { 138 | Sys.println("Couldn't make a regex for " + rel); 139 | return; 140 | } 141 | var dir = Path.normalize(Path.directory(full)); 142 | var normCpp = Path.normalize(outCppPath); 143 | for (relx in FileSystem.readDirectory(dir)) { 144 | if (rx.match(relx)) { 145 | var fullx = dir + "/" + relx; 146 | if (fullx == normCpp) continue; 147 | procFile(fullx, File.getContent(fullx), indexStructs); 148 | } 149 | } 150 | } else procFile(full, File.getContent(full), indexStructs); 151 | } 152 | #end 153 | static function main() { 154 | #if sys 155 | var args = Sys.args(); 156 | if (args.length == 0 157 | || args.length == 1 && (args[0] == "--help" || args[0] == "/?") 158 | ) { 159 | config.showHelp(false); 160 | return; 161 | } 162 | //Sys.println("cwd: " + Sys.getCwd()); 163 | config.handleArgs(args); 164 | var trouble = null; 165 | if (args.length == 0) { 166 | trouble = "No paths provided!"; 167 | } else if (outGmlPath == null) { 168 | trouble = "No output GML path provided!"; 169 | } else if (outCppPath == null) { 170 | trouble = "No output C++ path provided!"; 171 | } 172 | if (trouble != null) { 173 | Sys.println(trouble); 174 | Sys.stdin().readLine(); 175 | return; 176 | } 177 | for (full in args) { 178 | procArg(full, true); 179 | } 180 | finish(); 181 | #else 182 | var h = new haxe.Http("test.cpp?v=" + Date.now().getTime()); 183 | h.onData = function(cpp) { 184 | procFile("test.cpp", cpp, true); 185 | finish(); 186 | } 187 | h.request(); 188 | #end 189 | } 190 | } -------------------------------------------------------------------------------- /src/CppTypeHelper.hx: -------------------------------------------------------------------------------- 1 | package ; 2 | import proc.*; 3 | import proc.CppTypeProcSimple; 4 | import proc.CppTypeProcVector; 5 | import proc.CppTypeProcOptional; 6 | 7 | /** 8 | * ... 9 | * @author YellowAfterlife 10 | */ 11 | class CppTypeHelper { 12 | public static var map:Map = (function() { 13 | inline function simple(name:String, docName:String, size:Int) { 14 | return new CppTypeProcSimple(name, docName, size); 15 | } 16 | var bool = simple("buffer_bool", "bool", 1); 17 | var s8 = new CppTypeProcSimpleChar("buffer_s8", "int", 1); 18 | var u8 = simple("buffer_u8", "int", 1); 19 | var s16 = simple("buffer_s16", "int", 2); 20 | var u16 = simple("buffer_u16", "int", 2); 21 | var s32 = simple("buffer_s32", "int", 4); 22 | var u32 = simple("buffer_u32", "int", 4); 23 | var s64 = simple("buffer_u64", "int", 8); 24 | var u64 = simple("buffer_u64", "int", 8); 25 | var f32 = simple("buffer_f32", "number", 4); 26 | var f64 = simple("buffer_f64", "number", 8); 27 | var str = new CppTypeProcString(); 28 | var intPtr = new CppTypeProcSimpleIntPtr(); 29 | var gmlPtr = new CppTypeProcGmlPointer(false); 30 | var gmlID = new CppTypeProcGmlPointer(true); 31 | 32 | return [ 33 | // 1-byte: 34 | "bool" => (bool:CppTypeProc), 35 | "char" => s8, "unsigned char" => u8, 36 | "int8" => s8, "int8_t" => s8, 37 | "uint8" => u8, "uint8_t" => u8, 38 | // 2-byte: 39 | "short" => s16, "unsigned short" => u16, 40 | "int16" => s16, "int16_t" => s16, 41 | "uint16" => u16, "uint16_t" => u16, 42 | // 4-byte: 43 | "int" => s32, "unsigned int" => u32, 44 | "int32" => s32, "int32_t" => s32, 45 | "uint32" => u32, "uint32_t" => u32, 46 | "long" => s32, "unsigned long" => u32, 47 | // 8-byte: 48 | "long long" => s64, 49 | "int64" => s64, "int64_t" => s64, 50 | "uint64" => u64, "uint64_t" => u64, 51 | // floating-point: 52 | "float" => f32, "double" => f64, 53 | // pointerish: 54 | "intptr_t" => intPtr, "uintptr_t" => intPtr, 55 | // special cases: 56 | "char*" => str, 57 | "gml_ptr" => gmlPtr, 58 | "gml_ptr_destroy" => gmlPtr, 59 | "gml_id" => gmlID, 60 | "gml_id_destroy" => gmlID, 61 | "vector" => new CppTypeProcVector(), 62 | "tiny_array" => new CppTypeProcTinyArray(), 63 | "tiny_const_array" => new CppTypeProcTinyConstArray(), 64 | "tuple" => new CppTypeProcTuple(), 65 | "optional" => new CppTypeProcOptional(), 66 | "tiny_optional" => new CppTypeProcTinyOptional(), 67 | "gml_buffer" => new CppTypeProcGmlBuffer(), 68 | "GAME_HWND" => new CppTypeProcGameHwnd(), 69 | "gml_asset_index_of" => new CppTypeProcAssetIndexOf(), 70 | "gml_inout" => new CppTypeProcGmlInOut(), 71 | "gml_inout_vector" => new CppTypeProcGmlInOutVector(), 72 | ]; 73 | })(); 74 | 75 | public static function find(t:CppType):CppTypeProc { 76 | var tp = map[t.toKey()]; 77 | if (tp != null) return tp; 78 | tp = map[t.name]; 79 | if (tp != null) return tp; 80 | CppGen.warn('Couldn\'t find type ${t.toString()}' 81 | //+ haxe.CallStack.toString(haxe.CallStack.callStack()) 82 | ); 83 | return new CppTypeProcError(t.toString()); 84 | } 85 | public static function isSugar(t:CppType):Bool { 86 | var p = find(t); 87 | return (p is CppTypeProcGmlPointer); 88 | } 89 | } -------------------------------------------------------------------------------- /src/CppTypeMacroHelper.hx: -------------------------------------------------------------------------------- 1 | package ; 2 | import haxe.macro.Expr; 3 | import haxe.macro.Type; 4 | 5 | /** 6 | * ... 7 | * @author YellowAfterlife 8 | */ 9 | class CppTypeMacroHelper { 10 | public static function fromComplexType(t:ComplexType):CppType { 11 | if (t == null) return null; 12 | var r:CppType; 13 | switch (t) { 14 | case TPath(p): 15 | if (p.pack.length == 0) { 16 | switch (p.name) { 17 | case "Int": return new CppType("int"); 18 | case "Float": return new CppType("double"); 19 | case "Void": return new CppType("void"); 20 | case "String": 21 | r = new CppType("char"); 22 | r.isConst = true; 23 | r.ptrCount = 1; 24 | return r; 25 | } 26 | } 27 | switch (p.name) { 28 | case "Int8": return new CppType("int8_t"); 29 | case "Int16": return new CppType("int16_t"); 30 | case "Int32": return new CppType("int32_t"); 31 | case "Int64": return new CppType("int64_t"); 32 | case "UInt8": return new CppType("uint8_t"); 33 | case "UInt16": return new CppType("uint16_t"); 34 | case "UInt32": return new CppType("uint32_t"); 35 | case "UInt64": return new CppType("uint64_t"); 36 | case "Pointer": 37 | r = switch (p.params[0]) { 38 | case TPType(_ct): fromComplexType(_ct); 39 | default: return null; 40 | } 41 | r.ptrCount++; 42 | return r; 43 | } 44 | default: 45 | } 46 | trace(t); 47 | return null; 48 | } 49 | } -------------------------------------------------------------------------------- /src/GmlExtMacro.hx: -------------------------------------------------------------------------------- 1 | package ; 2 | import func.CppFunc; 3 | import func.CppFuncArg; 4 | import haxe.macro.Compiler; 5 | import haxe.macro.ComplexTypeTools; 6 | import haxe.macro.Context; 7 | import haxe.macro.Expr; 8 | import haxe.macro.Type; 9 | import sys.FileSystem; 10 | import sys.io.File; 11 | import tools.CppBuf; 12 | 13 | /** 14 | * ... 15 | * @author YellowAfterlife 16 | */ 17 | class GmlExtMacro { 18 | static var isFirstClass:Bool = false; 19 | static var initFunc:String; 20 | static var gmlAutogen:CppBuf; 21 | static var cppAutogen:CppBuf; 22 | public static function build():Array { 23 | var localClass:ClassType = { 24 | var r_class = Context.getLocalClass(); 25 | if (r_class == null) { 26 | Context.error("Should be applied to a class", Context.currentPos()); 27 | return null; 28 | } 29 | r_class.get(); 30 | } 31 | 32 | var cppAutogen = new CppBuf(); 33 | 34 | var fields = Context.getBuildFields(); 35 | for (field in fields) { 36 | if (field.meta == null) continue; 37 | 38 | var dllExport = field.meta.filter(m -> m.name == ":dllExport")[0]; 39 | if (dllExport == null) continue; 40 | 41 | var mf = switch (field.kind) { 42 | case FFun(f): f; 43 | default: 44 | Context.error("@:dllExport should be applied to a function.", field.pos); 45 | continue; 46 | } 47 | 48 | var fname = field.name; 49 | var exportName = fname; 50 | if (dllExport.params != null) switch (dllExport.params[0]) { 51 | case null: 52 | case { expr: EConst(CString(_name)) }: exportName = _name; 53 | default: 54 | } 55 | 56 | var cf = new CppFunc(exportName); 57 | cf.cppFuncName = localClass.pack.concat([localClass.name + "_obj", fname]).join("::"); 58 | cf.retType = CppTypeMacroHelper.fromComplexType(mf.ret); 59 | cf.generateFuncExtern = false; 60 | if (cf.retType == null) { 61 | Context.error("Couldn't convert return type for " + field.name 62 | + " (" + ComplexTypeTools.toString(mf.ret) + ")", field.pos); 63 | continue; 64 | } 65 | for (arg in mf.args) { 66 | var cargType = CppTypeMacroHelper.fromComplexType(arg.type); 67 | if (cargType == null) { 68 | Context.error("Couldn't convert type for " + field.name 69 | + " argument " + arg.name 70 | + " (" + ComplexTypeTools.toString(arg.type) + ")", field.pos); 71 | continue; 72 | } 73 | var carg = new CppFuncArg(cargType, arg.name); 74 | cf.args.push(carg); 75 | } 76 | cf.print(gmlAutogen, cppAutogen); 77 | } 78 | 79 | var cppFileCodeStr = cppAutogen.toString(); 80 | if (isFirstClass) { 81 | isFirstClass = false; 82 | cppFileCodeStr = [ 83 | 'extern "C" const char *hxRunLibrary();', 84 | 'extern "C" void hxcpp_set_top_of_stack();', 85 | 'dllx const char* $initFunc() {', 86 | '\t' + 'hxcpp_set_top_of_stack();', 87 | '\t' + 'const char* result = hxRunLibrary();', 88 | '\t' + 'return result ? result : "OK!";', 89 | '}', 90 | cppFileCodeStr 91 | ].join("\n"); 92 | } 93 | GmlExtMacro.cppAutogen.add(cppFileCodeStr); 94 | 95 | cppFileCodeStr = '#include \n' + cppFileCodeStr; 96 | var cppFileCodeMeta = localClass.meta.extract(":cppFileCode")[0]; 97 | if (cppFileCodeMeta != null) { 98 | if (cppFileCodeMeta.params != null) { 99 | switch (cppFileCodeMeta.params[0]) { 100 | case null: 101 | case { expr: EConst(CString(_code)) }: 102 | cppFileCodeStr = _code + "\n" + cppFileCodeStr; 103 | default: 104 | } 105 | } 106 | localClass.meta.remove(":cppFileCode"); 107 | } 108 | localClass.meta.add(":cppFileCode", [macro $v{cppFileCodeStr}], localClass.pos); 109 | 110 | return fields; 111 | } 112 | public static function macroMain() { 113 | var outdir = Compiler.getOutput(); 114 | var incdir = outdir + "/include"; 115 | try { 116 | if (!FileSystem.exists(outdir)) FileSystem.createDirectory(outdir); 117 | if (!FileSystem.exists(incdir)) FileSystem.createDirectory(incdir); 118 | } catch (x:Dynamic) { 119 | trace("Error validating directories: ", x); 120 | } 121 | var gml_ext = Context.resolvePath("include/gml_ext.h"); 122 | if (gml_ext != null) File.copy(gml_ext, incdir + "/gml_ext.h"); 123 | 124 | var name = Context.definedValue("HAXE_OUTPUT_FILE"); 125 | if (name == null) { 126 | name = Context.definedValue("autogen_main"); 127 | if (name == null) name = "Main"; 128 | } 129 | CppGen.config.helperPrefix = name; 130 | 131 | isFirstClass = true; 132 | initFunc = Context.definedValue("autogen_init"); 133 | if (initFunc == null) { 134 | initFunc = name + "_init_raw"; 135 | } 136 | 137 | gmlAutogen = new CppBuf(); 138 | cppAutogen = new CppBuf(); 139 | cppAutogen.add("#include \n"); 140 | var gmlAutogenPath = Context.definedValue("autogen_gml"); 141 | var cppAutogenPath = Context.definedValue("autogen_cpp"); 142 | Context.onAfterGenerate(function() { 143 | File.saveContent(gmlAutogenPath, gmlAutogen.toString()); 144 | File.saveContent(cppAutogenPath, cppAutogen.toString()); 145 | 146 | if (Sys.systemName() == "Windows") { 147 | var dllPath = Compiler.getOutput() + "\\" + name; 148 | #if debug 149 | dllPath += "-debug"; 150 | #end 151 | dllPath += ".dll"; 152 | 153 | var projectDir = Sys.getCwd(); 154 | projectDir = StringTools.replace(projectDir, "/", "\\"); 155 | 156 | var arch = "x86"; 157 | #if HXCPP_M64 158 | arch = "x64"; 159 | #end 160 | 161 | var config = "Release"; 162 | #if debug 163 | config = "Debug"; 164 | #end 165 | 166 | Sys.command("cmd", [ 167 | "/C", "postBuild.bat", 168 | dllPath, 169 | projectDir + "..\\", 170 | projectDir, 171 | arch, 172 | config, 173 | ]); 174 | } 175 | }); 176 | //trace("hi!", autogenPath); 177 | } 178 | } -------------------------------------------------------------------------------- /src/func/CppFuncArg.hx: -------------------------------------------------------------------------------- 1 | package func ; 2 | 3 | /** 4 | * ... 5 | * @author YellowAfterlife 6 | */ 7 | class CppFuncArg { 8 | public var index:Int; 9 | public var type:CppType; 10 | public var name:String; 11 | /** default value (if omitted) **/ 12 | public var value:String = null; 13 | /** like `double` or `const char*`. If it's null, it goes in the buffer **/ 14 | public var exportType:String; 15 | /** but also we'll put things in the buffer if we're out of argument space **/ 16 | public var putInBuffer = true; 17 | public var isSelf = false; 18 | public var gmlArgument:String = null; 19 | public var gmlUnpacked:String = null; 20 | public var gmlUnpackedPerVersion:Map = new Map(); 21 | public static var current:CppFuncArg = null; 22 | public function new(index:Int, type:CppType, name:String) { 23 | this.index = index; 24 | this.type = type; 25 | this.name = name; 26 | } 27 | public function isOut() { 28 | return type.proc.isOut(); 29 | } 30 | } -------------------------------------------------------------------------------- /src/func/CppFuncGmlDoc.hx: -------------------------------------------------------------------------------- 1 | package func; 2 | 3 | import proc.CppTypeProc; 4 | import tools.CppBuf; 5 | using StringTools; 6 | 7 | class CppFuncGmlDoc { 8 | public static function print(fn:CppFunc, gml:CppBuf, hasReturn:Bool, retTypeProc:CppTypeProc, jsDoc:Bool) { 9 | var metaComment = fn.metaComment; 10 | if (metaComment != null && metaComment.startsWith("(")) { 11 | // function is preceded by `/// (...args)->` 12 | gml.addFormat("%|/// %s%s%|", fn.name, fn.metaComment); 13 | return; 14 | } 15 | if (!jsDoc) gml.addFormat("%|/// %s(", fn.name); 16 | var sep = false; 17 | for (arg in fn.args) { 18 | if (!arg.type.proc.useGmlArgument()) continue; 19 | if (jsDoc && !fn.gmlStatic && !sep) { 20 | // first arg is self 21 | sep = true; 22 | continue; 23 | } 24 | CppFuncArg.current = arg; 25 | if (!jsDoc) { 26 | if (sep) gml.add(", "); else sep = true; 27 | } 28 | // 29 | var argValue = arg.value; 30 | var isOpt = argValue == "{}"; 31 | // 32 | if (jsDoc) { 33 | gml.addFormat("/// @param"); 34 | if (arg.type != null) { 35 | var docType = arg.type.proc.getGmlDocTypeEx(arg.type); 36 | gml.addFormat(" {%s}", docType); 37 | } 38 | gml.addFormat(" %s%s", argValue != null ? "?" : "", arg.name); 39 | gml.addLine(); 40 | } else { 41 | if (isOpt) { 42 | gml.addString("?"); 43 | argValue = null; 44 | } 45 | gml.addFormat("%s", arg.name); 46 | if (arg.type != null) { 47 | var docType = arg.type.proc.getGmlDocTypeEx(arg.type); 48 | if (docType != null) gml.addFormat(":%s", docType); 49 | } 50 | if (argValue != null) gml.addFormat(" = %s", argValue.trim()); 51 | } 52 | } 53 | if (jsDoc) { 54 | if (hasReturn && retTypeProc != null) { 55 | var docType = retTypeProc.getGmlDocTypeEx(fn.retType); 56 | if (docType != null) gml.addFormat("/// @returns {%s}%|", docType); 57 | } 58 | } else { 59 | gml.add(")"); 60 | if (metaComment != null && metaComment.startsWith("->")) { 61 | gml.addFormat("%s%|", metaComment); 62 | return; 63 | } 64 | if (hasReturn && retTypeProc != null) { 65 | gml.add("->"); 66 | var docType = retTypeProc.getGmlDocTypeEx(fn.retType); 67 | if (docType != null) gml.addString(docType); 68 | } 69 | if (metaComment != null) gml.addFormat(" %s", metaComment); 70 | gml.addLine(); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/func/CppFuncMangled.hx: -------------------------------------------------------------------------------- 1 | package func; 2 | import tools.CppBuf; 3 | using StringTools; 4 | 5 | /** 6 | * ... 7 | * @author 8 | */ 9 | class CppFuncMangled { 10 | public static var isUsed = false; 11 | public static function print(fn:CppFunc, cpp:CppBuf) { 12 | isUsed = true; 13 | var retCppType = fn.retType.toCppType(); 14 | var retVoid = retCppType == "void"; 15 | fn.printExtern(cpp, retCppType, false); 16 | var config = CppGen.config; 17 | 18 | var argDoc:CppBuf = new CppBuf(); 19 | var argDecl:CppBuf = new CppBuf(); argDecl.indent = cpp.indent + 1; 20 | var argCall:CppBuf = new CppBuf(); 21 | var argi = 0; 22 | var hasResult = false, hasRest = false; 23 | var minArgs = -1; 24 | var sep = false; 25 | for (arg in fn.args) { 26 | var t = arg.type; 27 | if (retVoid && t.name == "YYResult" && ((t.ptrCount == 1) /*xor*/!= (t.isRef))) { 28 | hasResult = true; 29 | if (argCall.length > 0) argCall.addString(", "); 30 | if (t.isRef) { 31 | argCall.addString("result"); 32 | } else argCall.addString("&result"); 33 | continue; 34 | } 35 | if (t.name == "YYSelf" || t.name == "YYOther") { 36 | var isSelf = t.name == "YYSelf"; 37 | if (argCall.length > 0) argCall.addString(", "); 38 | argCall.addString(isSelf ? "self" : "other"); 39 | continue; 40 | } 41 | 42 | var isOpt = arg.value != null; 43 | if (argDoc.length > 0) argDoc.addString(", "); 44 | if (t.name == "YYRest") { 45 | hasRest = true; 46 | argDoc.addString("..."); 47 | } else if (isOpt) argDoc.addString("?"); 48 | 49 | argDoc.addString(arg.name); 50 | var varName = "_arg_" + arg.name; 51 | argDecl.addFormat("%s %s;", t.toCppType(), varName); 52 | if (isOpt) { 53 | if (minArgs < 0) minArgs = argi; 54 | argDecl.addFormat("%|if (argc > %d) {%+", argi); 55 | } else argDecl.addString(" "); 56 | argDecl.addFormat('__YYArg_%s("%s", %s, %d);', 57 | t.toCppMacroType(), arg.name, varName, argi); 58 | if (isOpt) { 59 | argDecl.addFormat("%-} else %s = %s;", varName, arg.value); 60 | } 61 | argDecl.addLine(); 62 | 63 | if (argCall.length > 0) argCall.addString(", "); 64 | argCall.addString(varName); 65 | 66 | if (hasRest) break; 67 | argi += 1; 68 | } 69 | 70 | cpp.addFormat("/// %s(%b)%s\n", fn.name, argDoc, retVoid && !hasResult ? "" : "->"); 71 | var cppName = config.cppNameMangled.replace("$", fn.name); 72 | cpp.addFormat("%s ", config.exportPrefixM); 73 | cpp.addFormat("void %s", cppName); 74 | cpp.addString("(RValue& result, CInstance* self, CInstance* other, int argc, RValue* arg)"); 75 | cpp.addFormat(" {%+"); 76 | cpp.addFormat('#define __YYFUNCNAME__ "%s"%|', fn.name); 77 | var maxArgs = argi; 78 | if (minArgs < 0) minArgs = maxArgs; 79 | if (hasRest && minArgs == 0) { 80 | cpp.addFormat("__YYArgCheck_any;"); 81 | } else if (hasRest) { 82 | cpp.addFormat("__YYArgCheck_rest(%d);", minArgs); 83 | } else if (minArgs != maxArgs) { 84 | cpp.addFormat("__YYArgCheck_range(%d, %d);", minArgs, maxArgs); 85 | } else { 86 | cpp.addFormat("__YYArgCheck(%d);", minArgs); 87 | } 88 | cpp.addLine(); 89 | cpp.addBuffer(argDecl); 90 | if (!retVoid) { 91 | cpp.addFormat("%s _result = ", retCppType); 92 | } 93 | cpp.addFormat("%s(%b);%|", fn.name, argCall); 94 | if (!retVoid) { 95 | cpp.addFormat("__YYResult_%s(%s);%|", fn.retType.toCppMacroType(), "_result"); 96 | } 97 | cpp.addFormat('#undef __YYFUNCNAME__'); 98 | cpp.addFormat("%-}%|%|"); 99 | } 100 | } -------------------------------------------------------------------------------- /src/func/CppFuncReader.hx: -------------------------------------------------------------------------------- 1 | package func; 2 | import tools.CppReader; 3 | using StringTools; 4 | 5 | /** 6 | * ... 7 | * @author YellowAfterlife 8 | */ 9 | class CppFuncReader { 10 | public static function read(q:CppReader):CppFunc { 11 | var fnStart = q.pos; 12 | // 13 | var retType = CppType.read(q); 14 | var fnName = q.readSpIdent(); 15 | q.skipSpaces(); 16 | if (!q.skipIfEqu("(".code)) return null; 17 | // 18 | var fn = new CppFunc(fnName); 19 | fn.retType = retType; 20 | CppFunc.list.push(fn); 21 | // 22 | var readArg = true; 23 | var depth = 1; 24 | var args = []; 25 | while (q.loop) { 26 | var c = q.read(); 27 | switch (c) { 28 | case "(".code: depth++; 29 | case ")".code: if (--depth <= 0) break; 30 | case ",".code if (depth == 1): 31 | readArg = true; 32 | case _ if (c.isIdent0()): 33 | var w = q.readIdent(true); 34 | if (readArg) { 35 | readArg = false; 36 | var argType = CppType.read(q, w); 37 | var argName = q.readSpIdent(); 38 | if (argName == "") continue; 39 | var arg = new func.CppFuncArg(fn.args.length, argType, argName); 40 | fn.args.push(arg); 41 | q.skipSpaces(); 42 | if (q.skipIfEqu("=".code)) { 43 | q.skipSpaces(); 44 | var valStart = q.pos; 45 | var comma = false; 46 | while (q.loop) { 47 | c = q.read(); 48 | switch (c) { 49 | case "(".code: depth++; 50 | case ")".code: if (--depth <= 1) break; 51 | case ",".code: 52 | if (depth <= 1) { 53 | comma = true; 54 | break; 55 | } 56 | } 57 | } 58 | arg.value = q.substring(valStart, q.pos - 1).ltrim(); 59 | if (comma) q.back(); 60 | if (depth <= 0) break; 61 | } 62 | } 63 | } 64 | } 65 | // 66 | var lineStart = q.str.lastIndexOf("\n", fnStart); 67 | if (lineStart >= 0) { 68 | var prevLineStart = q.str.lastIndexOf("\n", lineStart - 1); 69 | if (prevLineStart < 0) prevLineStart = 0; 70 | var prevLine = q.str.substring(prevLineStart, lineStart); 71 | var prevLineCmtStart = prevLine.lastIndexOf("///"); 72 | if (prevLineCmtStart >= 0) { 73 | fn.metaComment = prevLine.substring(prevLineCmtStart + 3).trim(); 74 | } 75 | } 76 | // 77 | return fn; 78 | } 79 | } -------------------------------------------------------------------------------- /src/misc/GmlConstructor.hx: -------------------------------------------------------------------------------- 1 | package misc; 2 | import tools.CppBuf; 3 | using StringTools; 4 | 5 | /** 6 | * ... 7 | * @author YellowAfterlife 8 | */ 9 | class GmlConstructor { 10 | public static var map:Map = new Map(); 11 | public static var list:Array = []; 12 | // 13 | public var name:String; 14 | public var cppType:String = null; 15 | public var isID:Null = null; 16 | public var bufMethods:CppBuf = new CppBuf(); 17 | public var bufStatics:CppBuf = new CppBuf(); 18 | public var templateStart:String = null; 19 | public var templateEnd:String = null; 20 | public function new(name:String) { 21 | this.name = name; 22 | bufMethods.indent = 1; 23 | bufStatics.indent = 1; 24 | } 25 | public function setTemplate(tpl:String) { 26 | static var rxCode = ~/\$code\b/; 27 | if (templateStart != null) { 28 | CppGen.warn('Constructor $name already has a template!'); 29 | } 30 | if (rxCode.match(tpl)) { 31 | templateStart = rxCode.matchedLeft().rtrim(); 32 | templateEnd = rxCode.matchedRight(); 33 | } else { 34 | templateStart = tpl; 35 | } 36 | } 37 | public static function find(name:String) { 38 | var ctr = map[name]; 39 | if (ctr == null) { 40 | ctr = new GmlConstructor(name); 41 | list.push(ctr); 42 | map[name] = ctr; 43 | } 44 | return ctr; 45 | } 46 | public static function print(out:CppBuf) { 47 | if (list.length == 0) return; 48 | out.addFormat("// auto-generated!"); 49 | for (ctr in list) { 50 | out.addFormat("%|%|"); 51 | var param = ctr.isID ? "_id" : "_ptr"; 52 | if (ctr.templateStart != null) { 53 | out.addString(ctr.templateStart); 54 | } else { 55 | out.addFormat("function %s(%s) constructor %{", ctr.name, param); 56 | out.addFormat("%|%s = %s;", ctr.isID ? "__id__" : "__ptr__", param); 57 | } 58 | out.addBuffer(ctr.bufStatics); 59 | out.addBuffer(ctr.bufMethods); 60 | if (ctr.templateEnd != null) { 61 | out.addString(ctr.templateEnd); 62 | } else { 63 | out.addFormat("%-}"); 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProc.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import tools.CppBuf; 3 | 4 | /** 5 | * ... 6 | * @author YellowAfterlife 7 | */ 8 | class CppTypeProc { 9 | public function new() { 10 | 11 | } 12 | 13 | /** 14 | Should return a snip of GML code to read a value (that was written by C++) from `_buf`. 15 | 16 | GML code can be appended into `gml` if additional logic is necessary. 17 | 18 | When doing so, each line should be followed by a linebreak (or addFormat("...%|")) 19 | 20 | @param gml (code buffer) 21 | @param type Value type 22 | @param depth (for generating non-conflicting local variable names) 23 | @return GML code for use as a final value 24 | **/ 25 | public function gmlRead(gml:CppBuf, type:CppType, depth:Int):String { 26 | throw "todo"; 27 | } 28 | 29 | public function gmlReadOut(gml:CppBuf, type:CppType, depth:Int, out:String) { 30 | var val = gmlRead(gml, type, depth); 31 | gml.addFormat("%|%s = %s;", out, val); 32 | } 33 | 34 | /** 35 | * Should append GML code to write a value for use by C++ to `_buf`. 36 | * @param gml (code buffer) 37 | * @param type Value type 38 | * @param depth (for generating non-conflicting local variable names) 39 | * @param val Value as a GML expression string 40 | */ 41 | public function gmlWrite(gml:CppBuf, type:CppType, depth:Int, val:String):Void { 42 | throw "todo"; 43 | } 44 | 45 | /** 46 | If this is a struct/array with something that we're going to pass as-is, 47 | this should unpack the value and return it. 48 | **/ 49 | public function gmlUnpack(gml:CppBuf, type:CppType, depth:Int, val:String):String { 50 | return val; 51 | } 52 | 53 | public function gmlCleanup(gml:CppBuf, type:CppType, depth:Int, val:String):Void { 54 | 55 | } 56 | 57 | /** 58 | * Should append C++ code to read a value written by GML from `_in`. 59 | * @param cpp (code buffer) 60 | * @param type Value type 61 | * @return C++ code to use as a final value 62 | */ 63 | public function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 64 | var ts = type.toCppType_mutable(); 65 | return '_in.read<$ts>()'; 66 | } 67 | 68 | /** 69 | * Should append C++ code to write a value for use by GML to `_out`. 70 | * @param cpp (code buffer) 71 | * @param type Value type 72 | * @param val Value as a C++ expression string 73 | */ 74 | public function cppWrite(cpp:CppBuf, type:CppType, prefix:String, val:String):Void { 75 | cpp.addFormat('%|_out.write<%s>(%s);', type.toCppType(), val); 76 | } 77 | 78 | /** 79 | * Should return the size of a value for the given type(+parameters). 80 | * This is used to ensure that a GML buffer is large enough for function arguments/return value 81 | * to be written to it without going out-of-bounds. 82 | * 83 | * Vectors are an exception from this behaviour due to their size depending on value. 84 | * @param type 85 | * @return 86 | */ 87 | public function getSize(type:CppType):Int { 88 | return 8; 89 | } 90 | 91 | static function hasDynSize_seeker(t:CppType) { 92 | return t.proc.hasDynSize(t); 93 | } 94 | public function hasDynSize(type:CppType) { 95 | return seekRec(type, hasDynSize_seeker); 96 | } 97 | 98 | /** 99 | Can do `cpp.addFormat("%s += ...", result);` and return non-dynamic size for this type 100 | **/ 101 | public function cppDynSize(cpp:CppBuf, type:CppType, prefix:String, val:String, result:String):Int { 102 | return getSize(type); 103 | } 104 | 105 | /** 106 | Should iterate sub-types, run fn() on them, and return whether 107 | **/ 108 | public function seekRec(type:CppType, fn:(CppType) -> Bool):Bool { 109 | return false; 110 | } 111 | 112 | public function getGmlDocType(type:CppType):String { 113 | return null; 114 | } 115 | public function getGmlDocTypeEx(type:CppType):String { 116 | var t = CppType.docNames[type.docKey]; 117 | if (t == null) t = CppType.docNames[type.docKeyFull]; 118 | return t != null ? t : getGmlDocType(type); 119 | } 120 | public function toGmlJSDocType(type:CppType):String { 121 | var t = getGmlDocTypeEx(type); 122 | return switch (t) { 123 | case "int", "number": "real"; 124 | default: t; 125 | } 126 | } 127 | 128 | /** Does this use structs? (and might need a conditional block) */ 129 | public function usesStructs(type:CppType):Bool { 130 | return seekRec(type, usesStructs_seeker); 131 | } 132 | static function usesStructs_seeker(t:CppType) return t.proc.usesStructs(t); 133 | 134 | /** Does this use GM<=8.1 logic? (and might need another conditional block) */ 135 | public function usesGmkSpec(type:CppType):Bool { 136 | return seekRec(type, usesGmkSpec_seeker); 137 | } 138 | static function usesGmkSpec_seeker(t:CppType) return t.proc.usesGmkSpec(t); 139 | 140 | public function isOut() { 141 | return false; 142 | } 143 | 144 | /** Some things (such as GameHwnd) are passed to C++, but are not passed to the GML wrapper **/ 145 | public function useGmlArgument():Bool { 146 | return true; 147 | } 148 | public function keepGmlArgVar(type:CppType):Bool { 149 | return false; 150 | } 151 | public function isMap(type:CppType) { 152 | return false; 153 | } 154 | public function isList(type:CppType) { 155 | return false; 156 | } 157 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcAssetIndexOf.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import tools.CppBuf; 3 | import func.CppFuncArg; 4 | import proc.CppTypeProc; 5 | 6 | /** 7 | * Looks up an asset ID based on argument name 8 | * @author YellowAfterlife 9 | */ 10 | class CppTypeProcAssetIndexOf extends CppTypeProc { 11 | override public function gmlWrite(gml:CppBuf, type:CppType, z:Int, val:String):Void { 12 | var name = CppFuncArg.current.name; 13 | gml.addFormat('%|%bw;', "s32", 'asset_get_index("$name")'); 14 | } 15 | override public function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 16 | var ts = type.toCppType(); 17 | return '($ts)_in.read()'; 18 | } 19 | override public function useGmlArgument():Bool { 20 | return false; 21 | } 22 | override public function getSize(type:CppType):Int { 23 | return 4; 24 | } 25 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcCond.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import CppConfig; 3 | import tools.CppBuf; 4 | 5 | /** 6 | * ... 7 | * @author YellowAfterlife 8 | */ 9 | class CppTypeProcCond { 10 | public static function run( 11 | gml:CppBuf, 12 | func:Void->Void, 13 | useStructs:Void->Bool, 14 | useGmkSpec:Void->Bool, 15 | ) { 16 | var config = CppGen.config; 17 | var structMode = config.structMode; 18 | var structModeVal = config.structModeVal; 19 | var structModeCond = structMode != "auto"; 20 | var gmkSpec = CppGen.hasGmkPath && useGmkSpec(); 21 | var gmkBox = GmlBoxMode.BmGrid; 22 | inline function addElseGmk(elseif:Bool) { 23 | if (elseif) { 24 | gml.addFormat("%|//*/"); 25 | gml.addFormat("%|/* GMS < 1:"); 26 | } else gml.addFormat("%|/*/"); 27 | } 28 | // 29 | function proc(ver:Int, sm:GmlStorageMode, bm:GmlBoxMode, vm:GmlVectorMode, gmk = false) { 30 | var _gmlVersion = config.gmlVersion; 31 | var _storageMode = config.storageMode; 32 | var _vectorMode = config.vectorMode; 33 | var _boxMode = config.boxMode; 34 | var _isGMK = config.isGMK; 35 | // 36 | config.gmlVersion = ver; 37 | config.storageMode = sm; 38 | config.vectorMode = vm; 39 | config.boxMode = bm; 40 | config.isGMK = gmk; 41 | // 42 | func(); 43 | // 44 | config.gmlVersion = _gmlVersion; 45 | config.storageMode = _storageMode; 46 | config.vectorMode = _vectorMode; 47 | config.boxMode = _boxMode; 48 | config.isGMK = _isGMK; 49 | } 50 | inline function procGMS23() { 51 | proc(23, SmStruct, BmStruct, VmArray); 52 | } 53 | inline function procGMS1() { 54 | if (config.preferDS) { 55 | proc(14, SmMap, BmArray, VmList); 56 | } else { 57 | proc(14, SmArray, BmArray, VmArray); 58 | } 59 | } 60 | 61 | if (structModeVal != null) { 62 | // e.g. forced array mode for GMS 2.3 63 | if (gmkSpec) gml.addFormat("%|// GMS >= 1:"); 64 | 65 | if (structModeVal) { 66 | procGMS23(); 67 | } else procGMS1(); 68 | 69 | if (gmkSpec) { 70 | addElseGmk(false); 71 | proc(8, structModeVal ? SmMap : SmList, gmkBox, VmList, true); 72 | gml.addFormat("%|//*/"); 73 | } 74 | return; 75 | } 76 | 77 | if (!useStructs()) { 78 | // no structs, but don't get too excited 79 | if (gmkSpec) gml.addFormat("%|// GMS >= 1:"); 80 | procGMS1(); 81 | if (gmkSpec) { 82 | addElseGmk(false); 83 | proc(8, SmList, gmkBox, VmList, true); 84 | gml.addFormat("%|//*/"); 85 | } 86 | return; 87 | } 88 | 89 | gml.addFormat("%|// GMS >= 2.3:"); 90 | if (structModeCond) { 91 | gml.addFormat("%|if (%s) %{", structMode); 92 | } 93 | 94 | procGMS23(); 95 | 96 | if (structModeCond) { 97 | gml.addFormat("%-} else //*/"); 98 | gml.addFormat("%|%{"); 99 | if (gmkSpec) { 100 | gml.addFormat("%|// GMS >= 1:"); 101 | } 102 | } else if (!gmkSpec) { 103 | // >=2.3 / else 104 | gml.addFormat("%|/*/"); 105 | } else { 106 | // >=2.3 / >=1 / gmk 107 | gml.addFormat("%|//*/"); 108 | gml.addFormat("%|/* GMS >= 1 && GMS < 2.3:"); 109 | } 110 | 111 | procGMS1(); 112 | 113 | if (gmkSpec) { 114 | addElseGmk(true); 115 | if (structModeCond) { 116 | // a condition to select which of two workarounds you'd prefer? 117 | gml.addFormat("%|if (%s) %{", structMode); 118 | proc(8, SmMap, gmkBox, VmList, true); 119 | gml.addFormat("%-} else %{"); 120 | proc(7, SmList, gmkBox, VmList, true); // so that it doesn't clash with above 121 | gml.addFormat("%-}"); 122 | } else { 123 | // if you're going to have to free it anyway, might as well 124 | // make it something with readable keys, you know? 125 | proc(8, SmMap, gmkBox, VmList, true); 126 | } 127 | } 128 | 129 | if (structModeCond) { 130 | gml.addFormat("%-}"); 131 | } else { 132 | gml.addFormat("%|//*/"); 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcCustom.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | 3 | import tools.CppBuf; 4 | using StringTools; 5 | 6 | class CppTypeProcCustom extends CppTypeProc { 7 | public var custom = new CppTypeProcCustomValues(); 8 | public static var rxValue = ~/\$value\b/g; 9 | public static var rxDepth = ~/\$depth\b/g; 10 | public static var rxReturn = ~/^return\b\s*(.+?);?$/; 11 | 12 | static function patch(buf:CppBuf, snip:String, ?depth:Int, ?val:String) { 13 | if (snip == null) return null; 14 | if (val != null) snip = rxValue.replace(snip, val); 15 | if (depth != null) snip = rxDepth.replace(snip, "" + depth); 16 | 17 | if (buf != null) { 18 | var lines = snip.split("\n"); 19 | var expr = lines.pop().trim(); 20 | if (rxReturn.match(expr)) { 21 | expr = rxReturn.matched(1); 22 | } 23 | for (line in lines) buf.addFormat("%|%s", line); 24 | return expr; 25 | } else return snip; 26 | } 27 | 28 | override function gmlRead(gml:CppBuf, type:CppType, depth:Int):String { 29 | return patch(gml, custom.gmlRead, depth); 30 | } 31 | override function gmlWrite(gml:CppBuf, type:CppType, depth:Int, val:String) { 32 | if (custom.gmlWrite != null) { 33 | gml.addFormat("%|%s", patch(gml, custom.gmlWrite, depth, val)); 34 | } 35 | } 36 | override function gmlCleanup(gml:CppBuf, type:CppType, depth:Int, val:String) { 37 | if (custom.gmlCleanup == null) return; 38 | gml.addFormat("%|%s", patch(gml, custom.gmlCleanup, depth, val)); 39 | } 40 | 41 | override function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 42 | if (custom.cppRead != null) { 43 | return patch(cpp, custom.cppRead, null); 44 | } else { 45 | return super.cppRead(cpp, type, null); 46 | } 47 | } 48 | override function cppWrite(cpp:CppBuf, type:CppType, prefix:String, val:String) { 49 | if (custom.cppWrite != null) { 50 | cpp.addFormat("%|%s", patch(cpp, custom.cppWrite, null, val)); 51 | } else { 52 | super.cppWrite(cpp, type, null, val); 53 | } 54 | } 55 | 56 | override function getSize(type:CppType):Int { 57 | if (custom.size != null) return custom.size; 58 | return super.getSize(type); 59 | } 60 | override function hasDynSize(type:CppType):Bool { 61 | return custom.dynSize != null; 62 | } 63 | override function cppDynSize(cpp:CppBuf, type:CppType, prefix:String, val:String, result:String):Int { 64 | if (custom.dynSize != null) { 65 | cpp.addFormat("%|%s", patch(null, custom.dynSize, null, val)); 66 | } 67 | return getSize(type); 68 | } 69 | override function usesStructs(type:CppType):Bool { 70 | return custom.usesStructs; 71 | } 72 | 73 | override function useGmlArgument():Bool { 74 | return custom.useGmlArgument; 75 | } 76 | override function keepGmlArgVar(type):Bool { 77 | return custom.keepGmlArgVar; 78 | } 79 | 80 | public static function parse(snip:String) { 81 | static var rxStart = ~/^(\w+)[ \t]*\n(\s*)([\s\S]+)/; 82 | //trace('"' + snip + '"'); 83 | if (!rxStart.match(snip)) { 84 | CppGen.warn("@dllg:type should start with typename"); 85 | return; 86 | } 87 | var typename = rxStart.matched(1); 88 | var indent = rxStart.matched(2); 89 | snip = rxStart.matched(3); 90 | 91 | static var rxMeta = ~/^\s*@(\w+)\s*(.+)?/; 92 | var tp = new CppTypeProcCustom(); 93 | var tc = tp.custom; 94 | var metaName:String = null; 95 | var metaLines = []; 96 | function flush() { 97 | if (metaName == null) return; 98 | var metaText = metaLines.join("\n"); 99 | switch (metaName.toLowerCase()) { 100 | case "gmlread": tc.gmlRead = metaText; 101 | case "gmlwrite": tc.gmlWrite = metaText; 102 | case "gmlcleanup": tc.gmlCleanup = metaText; 103 | case "cppread": tc.cppRead = metaText; 104 | case "cppwrite": tc.cppWrite = metaText; 105 | // 106 | case "size": tc.size = Std.parseInt(metaText); 107 | case "dynsize": tc.dynSize = metaText; 108 | // 109 | case "struct": tc.usesStructs = true; 110 | case "gmlargvar": tc.keepGmlArgVar = true; 111 | // 112 | default: CppGen.warn('Unknown meta @${metaName} in type ${typename}'); 113 | } 114 | } 115 | for (line in snip.split("\n")) { 116 | if (line.startsWith(indent)) line = line.substr(indent.length); 117 | 118 | if (rxMeta.match(line)) { 119 | flush(); 120 | metaName = rxMeta.matched(1); 121 | metaLines = []; 122 | var first = rxMeta.matched(2); 123 | if (first != null) metaLines.push(first); 124 | } else metaLines.push(line); 125 | } 126 | flush(); 127 | CppType.typedefs.remove(typename); 128 | CppTypeHelper.map[typename] = tp; 129 | } 130 | } 131 | class CppTypeProcCustomValues { 132 | public var gmlRead:String = null; 133 | public var gmlWrite:String = null; 134 | public var gmlCleanup:String = null; 135 | // 136 | public var cppRead:String = null; 137 | public var cppWrite:String = null; 138 | // 139 | public var size:Null = null; 140 | public var dynSize:String = null; 141 | public var usesStructs = false; 142 | public var useGmlArgument = true; 143 | public var keepGmlArgVar = false; 144 | // 145 | public function new() {} 146 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcEnum.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | 3 | import tools.CppBuf; 4 | 5 | class CppTypeProcEnum extends CppTypeProcSimple { 6 | public var ename:String; 7 | public var baseType = "int"; 8 | public function new(ename:String) { 9 | this.ename = ename; 10 | super("buffer_s32", baseType, 4); 11 | } 12 | override function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 13 | return '($ename)_in.read<$baseType>()'; 14 | } 15 | override function cppWrite(cpp:CppBuf, type:CppType, prefix:String, val:String) { 16 | cpp.addFormat('%|_out.write<%s>(%s);', baseType, '($baseType)' + val); 17 | } 18 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcError.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import proc.CppTypeProc; 3 | import tools.CppBuf; 4 | 5 | /** 6 | * ... 7 | * @author YellowAfterlife 8 | */ 9 | class CppTypeProcError extends CppTypeProc { 10 | private var name:String; 11 | public function new(name:String) { 12 | super(); 13 | this.name = name; 14 | } 15 | override public function gmlRead(gml:CppBuf, type:CppType, z:Int):String { 16 | return 'show_error("Unsupported type $name", true)'; 17 | } 18 | override public function gmlWrite(gml:CppBuf, type:CppType, z:Int, val:String):Void { 19 | gml.addFormat('%|show_error("Unsupported type %s", true)', name); 20 | } 21 | override public function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 22 | return 'void/* Unsupported type $name */'; 23 | } 24 | override public function cppWrite(cpp:CppBuf, type:CppType, prefix:String, val:String):Void { 25 | cpp.addFormat("%|#error Unsupported type %s", name); 26 | } 27 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcGameHwnd.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import tools.CppBuf; 3 | 4 | /** 5 | * ... 6 | * @author YellowAfterlife 7 | */ 8 | class CppTypeProcGameHwnd extends CppTypeProc { 9 | override public function gmlWrite(gml:CppBuf, type:CppType, z:Int, val:String):Void { 10 | var x = CppGen.config.gmlWindowHandle; 11 | if (CppGen.config.isGMK) { 12 | gml.addFormat('%|%bw;', 'ptr', x); 13 | } else { 14 | gml.addFormat('%|%bw;', 'u64', 'int64($x)'); 15 | } 16 | } 17 | override public function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 18 | var ts = type.toCppType(); 19 | return '($ts)_in.read()'; 20 | } 21 | override public function useGmlArgument():Bool { 22 | return false; 23 | } 24 | override public function getSize(type:CppType):Int { 25 | return 8; 26 | } 27 | override public function usesGmkSpec(type:CppType):Bool { 28 | return true; 29 | } 30 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcGmlBuffer.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import func.CppFuncArg; 3 | import tools.CppBuf; 4 | 5 | /** 6 | * ... 7 | * @author YellowAfterlife 8 | */ 9 | class CppTypeProcGmlBuffer extends CppTypeProc { 10 | override public function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 11 | return '_in.read_gml_buffer()'; 12 | } 13 | override public function cppWrite(cpp:CppBuf, type:CppType, prefix:String, val:String):Void { 14 | cpp.addFormat("%|#error You may not return GML buffers at this time"); 15 | } 16 | 17 | static var rxInOut:EReg = ~/^_*([iI]n_*)?([oO]ut)?[_A-Z]/i; 18 | function getArgUses() { 19 | var name = CppFuncArg.current.name; 20 | var _in = true, _out = false; 21 | if (rxInOut.match(name)) { 22 | _in = rxInOut.matched(1) != null; 23 | _out = rxInOut.matched(2) != null; 24 | if (_out == false) _in = true; 25 | } 26 | return { isInput: _in, isOutput: _out }; 27 | } 28 | 29 | override public function gmlWrite(gml:CppBuf, type:CppType, z:Int, val:String):Void { 30 | var v = '_val_$z'; 31 | var wasm = CppGen.config.useWASM; 32 | var vwb = '_wb_$z'; 33 | gml.addFormat("%|var %s = %s;", v, val); 34 | if (wasm) gml.addFormat("%|var %s;", vwb); 35 | gml.addFormat("%|if (buffer_exists(%s)) %{", v); 36 | if (wasm) { 37 | var pfx = CppGen.config.helperPrefix; 38 | var vlen = '_len_$z'; 39 | gml.addFormat("%|if (%(s)_is_js) %{", pfx); 40 | gml.addFormat("%|var %s = buffer_get_size(%s);", vlen, v); 41 | gml.addFormat("%|%s = %(s)_wasm_alloc(%s", vwb, pfx, vlen); 42 | if (getArgUses().isInput) gml.addFormat(", buffer_get_address(%s)", v); 43 | gml.addString(");"); 44 | gml.addFormat('%|%bw;', 'u64', vwb); 45 | gml.addFormat('%|%bw;', 's32', vlen); 46 | gml.addFormat('%|%bw;', 's32', 'buffer_tell($v)'); 47 | gml.addFormat("%-} else %{"); 48 | } 49 | 50 | // native: 51 | gml.addFormat('%|%bw;', 'u64', 'int64(buffer_get_address($v))'); 52 | gml.addFormat('%|%bw;', 's32', 'buffer_get_size($v)'); 53 | gml.addFormat('%|%bw;', 's32', 'buffer_tell($v)'); 54 | if (wasm) gml.addFormat("%-}"); // closes if-js-else 55 | 56 | // no buffer: 57 | gml.addFormat("%-} else %{"); 58 | if (wasm) gml.addFormat("%|%s = undefined;", vwb); 59 | gml.addFormat('%|%bw;', 'u64', '0'); 60 | gml.addFormat('%|%bw;', 's32', '0'); 61 | gml.addFormat('%|%bw;', 's32', '0'); 62 | gml.addFormat("%-}"); 63 | } 64 | override public function gmlCleanup(gml:CppBuf, type:CppType, z:Int, val:String):Void { 65 | if (CppGen.config.useWASM) { 66 | var pfx = CppGen.config.helperPrefix; 67 | // todo: this wouldn't work right for vector of buffers/etc. 68 | gml.addFormat("%|if (%(s)_is_js) ", pfx); 69 | gml.addFormat("%(s)_wasm_free(%s", pfx, '_wb_$z'); 70 | if (getArgUses().isOutput) { 71 | var v = '_val_$z'; 72 | gml.addFormat(", buffer_get_address(%s), buffer_get_size(%s)", v, v); 73 | } 74 | gml.addString(");"); 75 | } 76 | } 77 | override public function gmlRead(gml:CppBuf, type:CppType, z:Int):String { 78 | return 'show_error("Unsupported type gml_buffer", true)'; 79 | } 80 | override public function getGmlDocType(type:CppType):String { 81 | return "buffer"; 82 | } 83 | override public function getSize(type:CppType):Int { 84 | return 16; 85 | } 86 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcGmlInOut.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | 3 | import struct.CppStructIO; 4 | import struct.GmlStructIO; 5 | import tools.CppBuf; 6 | 7 | class CppTypeProcGmlInOut extends CppTypeProc { 8 | static function unpack(type:CppType) { 9 | var t = type.params[0]; 10 | if (t == null) throw "gml_inout requires a type param"; 11 | var sp:CppTypeProcStruct; 12 | sp = (t.proc is CppTypeProcStruct) ? cast t.proc : null; 13 | return { 14 | type: t, 15 | proc: t.proc, 16 | sp: sp, 17 | }; 18 | } 19 | override function gmlRead(gml:CppBuf, type:CppType, depth:Int):String { 20 | return unpack(type).type.gmlRead(gml, depth); 21 | } 22 | override function gmlWrite(gml:CppBuf, type:CppType, depth:Int, val:String) { 23 | var p = unpack(type); 24 | var vp = (p.sp != null ? '_struct_' : '_box_') + depth; 25 | var isGMK = CppGen.config.isGMK; 26 | gml.addFormat("%|%vdp = %s;", vp, val); 27 | gml.addFormat("%|if ("); 28 | if (p.sp == null) { 29 | if (isGMK) { 30 | gml.addFormat("!ds_list_empty(%s)", vp); 31 | } else { 32 | gml.addFormat("array_length_1d(%s)", vp); 33 | } 34 | } else switch (CppGen.config.storageMode) { 35 | case SmStruct: gml.addFormat('variable_struct_names_count(%s) != 0', vp); 36 | case SmArray: gml.addFormat('array_length_1d(%s) != 0', vp); 37 | case SmMap: gml.addFormat('!ds_map_empty(%s)', vp); 38 | case SmList: gml.addFormat('!ds_list_empty(%s)', vp); 39 | } 40 | gml.addFormat(") %{"); 41 | gml.addFormat("%|buffer_write(_buf, buffer_bool, true);"); 42 | if (p.sp == null) { 43 | var item = isGMK ? 'ds_list_find_value($vp)' : '$vp[0]'; 44 | p.type.gmlWrite(gml, depth, item); 45 | } else { 46 | var struct = p.sp.struct; 47 | GmlStructIO.writeFields(struct, gml, depth, vp); 48 | } 49 | gml.addFormat("%-} else buffer_write(_buf, buffer_bool, false);"); 50 | } 51 | override function cppRead(cpp:CppBuf, type:CppType, vp:String):String { 52 | var p = unpack(type); 53 | cpp.addFormat("%|%s %s;", p.type.toCppType_mutable(), vp); 54 | cpp.addFormat("%|if (_in.read()) %{"); 55 | if (p.sp != null) { 56 | CppStructIO.readFields(p.sp.struct, cpp, vp); 57 | } else { 58 | cpp.addFormat("%|%s = %s;", vp, p.type.cppRead(cpp, vp + "_val")); 59 | } 60 | cpp.addFormat("%-} else %s = {};", vp); 61 | return vp; 62 | } 63 | override function cppWrite(cpp:CppBuf, type:CppType, prefix:String, val:String) { 64 | unpack(type).type.cppWrite(cpp, prefix, val); 65 | } 66 | override function getSize(type:CppType):Int { 67 | var p = unpack(type); 68 | return 1 + p.type.getSize(); 69 | } 70 | override function cppDynSize(cpp:CppBuf, type:CppType, prefix:String, val:String, result:String):Int { 71 | var p = unpack(type); 72 | return 1 + p.proc.cppDynSize(cpp, p.type, prefix, val, result); 73 | } 74 | override function gmlReadOut(gml:CppBuf, type:CppType, depth:Int, out:String) { 75 | var p = unpack(type); 76 | if (p.sp != null) { 77 | var vp = "_struct_" + depth; 78 | gml.addFormat("%|%vdp = %s;", vp, out); 79 | switch (CppGen.config.storageMode) { 80 | case SmStruct, SmArray: {}; // OK! 81 | case SmMap: gml.addFormat("%|ds_map_clear(%s);", vp); 82 | case SmList: gml.addFormat("%|ds_list_clear(%s);", vp); 83 | } 84 | GmlStructIO.readFields(p.sp.struct, gml, depth, vp, true); 85 | } else { 86 | var vp = "_box_" + depth; 87 | var vp_val = "_val_" + depth; 88 | gml.addFormat("%|%vdp = %s;", vp, out); 89 | gml.addFormat("%|var %s;", vp_val); 90 | p.type.gmlReadOut(gml, depth + 1, vp); 91 | var isGMK = CppGen.config.isGMK; 92 | if (isGMK) { 93 | gml.addFormat("%|if (ds_list_empty(%s)) %{", vp); 94 | gml.addFormat("%|ds_list_add(%s, %s);", vp, vp_val); 95 | gml.addFormat("%-} else %{"); 96 | gml.addFormat("%|ds_list_replace(%s, 0, %s);", vp, vp_val); 97 | gml.addFormat("%-}"); 98 | } else { 99 | gml.addFormat("%|%s[@0] = %s;", vp, vp_val); 100 | } 101 | } 102 | } 103 | override function isOut():Bool { 104 | return true; 105 | } 106 | override function seekRec(type:CppType, fn:CppType -> Bool):Bool { 107 | return fn(unpack(type).type); 108 | } 109 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcOptional.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import proc.CppTypeProcTuple; 3 | import tools.CppBuf; 4 | 5 | /** 6 | * ... 7 | * @author YellowAfterlife 8 | */ 9 | class CppTypeProcOptional extends CppTypeProc { 10 | public static inline function unpack(type:CppType):CppType { 11 | return type.params[0]; 12 | } 13 | 14 | public static inline var zeroString = "(0)"; 15 | static function getDefValue_1(type:CppType, gmk:Bool){ 16 | var tp = type.proc; 17 | var ds = CppGen.config.preferDS; 18 | if (tp is CppTypeProcOptional) { 19 | return getDefValue_1(unpack(type), gmk); 20 | } 21 | if ((tp is CppTypeProcStruct) || (tp is CppTypeProcVector)) { 22 | return gmk || ds ? "-1" : null; 23 | } 24 | if (tp is CppTypeProcGmlPointer) return gmk ? "-1" : null; 25 | if (tp is CppTypeProcString) return gmk ? zeroString : null; 26 | if (tp is CppTypeProcSimple) return gmk ? '""' : null; 27 | return gmk ? "chr(0)" : null; 28 | } 29 | public static function getDefValue(type:CppType, ?struct:Bool, ?gmk:Bool) { 30 | if (struct == null) struct = CppGen.config.boxMode == BmStruct; 31 | 32 | if (gmk == null) gmk = CppGen.config.isGMK; 33 | if (struct) return "undefined"; 34 | 35 | var v = getDefValue_1(type, gmk); 36 | if (v == null) v = "undefined"; 37 | 38 | return v; 39 | } 40 | override public function gmlWrite(gml:CppBuf, type:CppType, z:Int, val:String):Void { 41 | var v = '_val_$z'; 42 | var f = '_flag_$z'; 43 | var t = unpack(type); 44 | var u = getDefValue(t); 45 | gml.addFormat("%|%vdp = %s;", v, val); 46 | gml.addFormat("%|%vdp = ", f); 47 | if (u == '""') { 48 | gml.addFormat("is_real(%s);", v); 49 | } else if (u == "0") { 50 | gml.addFormat("is_string(%s);", v); 51 | } else { 52 | gml.addFormat("%s != %s;", v, u); 53 | } 54 | gml.addFormat('%|%bw;', 'bool', f); 55 | gml.addFormat("%|if (%s) %{", f); 56 | t.proc.gmlWrite(gml, t, z + 1, v); 57 | gml.addFormat("%-}"); 58 | } 59 | override public function gmlRead(gml:CppBuf, type:CppType, z:Int):String { 60 | var v = '_val_$z'; 61 | gml.addFormat("%|var %s;", v); 62 | gml.addFormat("%|if (buffer_read(_buf, buffer_bool)) %{"); 63 | var t = unpack(type); 64 | var val = t.proc.gmlRead(gml, t, z + 1); 65 | gml.addFormat("%|%s = %s;", v, val); 66 | var u = getDefValue(type); 67 | gml.addFormat("%-} else %s = %s;", v, u); 68 | return v; 69 | } 70 | 71 | override public function cppRead(cpp:CppBuf, type:CppType, vp:String):String { 72 | cpp.addFormat("%|%s %s;", type.toCppType(), vp); 73 | cpp.addFormat("%|if (_in.read()) %{"); 74 | var ot = unpack(type); 75 | var val = ot.proc.cppRead(cpp, ot, vp + '_v'); 76 | cpp.addFormat("%|%s = %s;", vp, val); 77 | cpp.addFormat("%-} else %s = {};", vp); 78 | return vp; 79 | } 80 | override public function cppWrite(cpp:CppBuf, type:CppType, vp:String, val:String):Void { 81 | cpp.addFormat('%|auto& %s = %s;', vp, val); 82 | cpp.addFormat('%|if (%s.has_value()) %{', vp); 83 | cpp.addFormat('%|_out.write(true);'); 84 | var t = unpack(type); 85 | t.proc.cppWrite(cpp, t, vp + '_v', vp + '.value()'); 86 | cpp.addFormat('%-} else _out.write(false);'); 87 | } 88 | 89 | override public function getGmlDocType(type:CppType):String { 90 | var t = unpack(type); 91 | var s = t.proc.getGmlDocTypeEx(t); 92 | return s != null ? s + "?" : null; 93 | } 94 | 95 | override public function getSize(type:CppType):Int { 96 | return unpack(type).getSize() + 1; 97 | } 98 | override function cppDynSize(cpp:CppBuf, type:CppType, vp:String, val:String, out:String):Int { 99 | cpp.addFormat("%|auto& %s = %s;", vp, val); 100 | cpp.addFormat("%|if (%s.has_value()) %{", vp); 101 | var fixed = unpack(type).cppDynSize(cpp, vp + "_v", val + ".value()", out); 102 | if (fixed > 0) cpp.addFormat("%|%s += %d;", out, fixed); 103 | cpp.addFormat("%-}"); 104 | return 1; 105 | } 106 | override function seekRec(type:CppType, fn:CppType -> Bool):Bool { 107 | var t = unpack(type); 108 | return t != null && fn(t); 109 | } 110 | override function usesGmkSpec(type:CppType):Bool { 111 | return true; 112 | } 113 | } 114 | class CppTypeProcTinyOptional extends CppTypeProcOptional { 115 | override public function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 116 | var ts = CppTypeProcOptional.unpack(type).toCppType(); 117 | return '_in.read_tiny_optional<$ts>()'; 118 | } 119 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcSimple.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import proc.CppTypeProc; 3 | import tools.CppBuf; 4 | using StringTools; 5 | 6 | /** 7 | * ... 8 | * @author YellowAfterlife 9 | */ 10 | class CppTypeProcSimple extends CppTypeProc { 11 | public var bufType:String; 12 | public var shortBufType:String; 13 | public var docType:String; 14 | public var size:Int; 15 | public function new(bufType:String, docType:String, size:Int) { 16 | super(); 17 | this.bufType = bufType; 18 | if (bufType.startsWith('buffer_')) { 19 | shortBufType = bufType.substring('buffer_'.length); 20 | } else throw 'Unexpected buffer type "$bufType"'; 21 | this.docType = docType; 22 | this.size = size; 23 | } 24 | override public function gmlRead(gml:CppBuf, type:CppType, depth:Int):String { 25 | return 'buffer_read(_buf, $bufType)'; 26 | } 27 | override public function gmlWrite(gml:CppBuf, type:CppType, depth:Int, val:String):Void { 28 | gml.addFormat('%|%bw;', shortBufType, val); 29 | } 30 | override public function getSize(type:CppType):Int { 31 | return size; 32 | } 33 | override public function getGmlDocType(type:CppType):String { 34 | // TODO: JSDoc types 35 | return docType; 36 | } 37 | } 38 | class CppTypeProcSimpleChar extends CppTypeProcSimple { 39 | override public function getGmlDocType(type:CppType):String { 40 | if (type.ptrCount == 1) return "string"; 41 | return super.getGmlDocType(type); 42 | } 43 | } 44 | class CppTypeProcSimpleIntPtr extends CppTypeProcSimple { 45 | public function new(){ 46 | super("buffer_u64", "int", 8); 47 | } 48 | override public function gmlRead(gml:CppBuf, type:CppType, depth:Int):String { 49 | if (CppGen.config.isGMK) { 50 | return 'buffer_read(_buf, buffer_s32)'; 51 | } else return "ptr(" + super.gmlRead(gml, type, depth) + ")"; 52 | } 53 | override public function gmlWrite(gml:CppBuf, type:CppType, depth:Int, val:String):Void { 54 | if (CppGen.config.isGMK) { 55 | gml.addFormat('%|%bw;', "s32", val); 56 | } else { 57 | super.gmlWrite(gml, type, depth, val); 58 | } 59 | } 60 | override public function usesGmkSpec(type:CppType):Bool { 61 | return true; 62 | } 63 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcString.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import tools.CppBuf; 3 | 4 | /** 5 | * ... 6 | * @author 7 | */ 8 | class CppTypeProcString extends CppTypeProcSimple { 9 | public function new() { 10 | super("buffer_string", "string", 8); 11 | } 12 | override function hasDynSize(type:CppType):Bool { 13 | return true; 14 | } 15 | override function cppDynSize(cpp:CppBuf, type:CppType, prefix:String, val:String, result:String):Int { 16 | cpp.addFormat("%|%s += strlen(%s);", result, val); 17 | return 1; 18 | } 19 | override public function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 20 | return '_in.read_string()'; 21 | } 22 | override public function cppWrite(cpp:CppBuf, type:CppType, prefix:String, val:String):Void { 23 | cpp.addFormat('%|_out.write_string(%s);', val); 24 | } 25 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcStruct.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import haxe.ds.Vector; 3 | import proc.CppTypeProc; 4 | import struct.CppStruct; 5 | import struct.CppStructField; 6 | import struct.*; 7 | import tools.CppBuf; 8 | 9 | /** 10 | * ... 11 | * @author YellowAfterlife 12 | */ 13 | class CppTypeProcStruct extends CppTypeProc { 14 | public var struct:CppStruct; 15 | public function new(struct:CppStruct) { 16 | super(); 17 | this.struct = struct; 18 | } 19 | // 20 | override public function gmlRead(gml:CppBuf, type:CppType, z:Int):String { 21 | var structVar = "_struct_" + z; 22 | gml.addFormat("%|%vdp = ", structVar); 23 | GmlStructIO.createTail(struct, gml); 24 | GmlStructIO.readFields(struct, gml, z, structVar, false); 25 | return structVar; 26 | } 27 | override public function gmlWrite(gml:CppBuf, type:CppType, z:Int, val:String):Void { 28 | var structVar = "_struct_" + z; 29 | gml.addFormat("%|%vdp = %s;", structVar, val); 30 | GmlStructIO.writeFields(struct, gml, z, structVar); 31 | } 32 | // 33 | override function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 34 | cpp.addFormat('%|%s %s;', type.toCppType_mutable(), prefix); 35 | CppStructIO.readFields(struct, cpp, prefix); 36 | return prefix; 37 | } 38 | override function cppWrite(cpp:CppBuf, type:CppType, prefix:String, val:String) { 39 | cpp.addFormat('%|auto& %s = %s;', prefix, val); 40 | CppStructIO.writeFields(struct, cpp, prefix); 41 | } 42 | // 43 | override public function getSize(type:CppType):Int { 44 | var size = 0; 45 | for (fd in struct.fields) size += fd.getSize(); 46 | return size; 47 | } 48 | override function cppDynSize(cpp:CppBuf, type:CppType, prefix:String, val:String, result:String):Int { 49 | var fixed = 0; 50 | var tmp = cpp.fork(); 51 | for (fd in struct.fields) { 52 | // TODO: what if we have a `dynSizeType x[32]` 53 | fixed += fd.type.proc.cppDynSize(tmp, fd.type, 54 | prefix + '_f_' + fd.name, 55 | prefix + "." + fd.name, 56 | result 57 | ) * fd.getQuantity(); 58 | } 59 | if (tmp.hasText) { 60 | cpp.addFormat("%|auto& %s = %s;", prefix, val); 61 | cpp.addBuffer(tmp); 62 | } 63 | return fixed; 64 | } 65 | 66 | override function seekRec(type:CppType, fn:CppType -> Bool):Bool { 67 | for (fd in struct.fields) { 68 | if (fn(fd.type)) return true; 69 | } 70 | return false; 71 | } 72 | override public function usesStructs(type:CppType):Bool { 73 | return true; 74 | } 75 | override public function usesGmkSpec(type:CppType):Bool { 76 | return true; 77 | } 78 | override function isMap(type:CppType):Bool { 79 | return CppGen.config.storageMode == SmMap; 80 | } 81 | override function isList(type:CppType):Bool { 82 | return CppGen.config.storageMode == SmList; 83 | } 84 | } -------------------------------------------------------------------------------- /src/proc/CppTypeProcTuple.hx: -------------------------------------------------------------------------------- 1 | package proc; 2 | import tools.CppBuf; 3 | 4 | /** 5 | * ... 6 | * @author YellowAfterlife 7 | */ 8 | class CppTypeProcTuple extends CppTypeProc { 9 | override public function gmlRead(gml:CppBuf, type:CppType, z:Int):String { 10 | var _tup = '_tup_$z'; 11 | gml.addFormat("var %s = array_create(%d);%|", _tup, type.params.length); 12 | for (i => tupType in type.params) { 13 | var val = tupType.proc.gmlRead(gml, tupType, z + 1); 14 | gml.addFormat("%s[%d] = %s;%|", _tup, i, val); 15 | } 16 | return _tup; 17 | } 18 | override public function gmlWrite(gml:CppBuf, type:CppType, z:Int, val:String):Void { 19 | var _tup = '_tup_$z'; 20 | gml.addFormat("%|var %s = %s;", _tup, val); 21 | for (i => tupType in type.params) { 22 | var val = _tup + "[" + i + "]"; 23 | tupType.proc.gmlWrite(gml, tupType, z + 1, val); 24 | } 25 | } 26 | 27 | static inline function getPrefix(prefix:String, ind:Int) { 28 | return prefix + "_t" + ind; 29 | } 30 | 31 | override public function cppRead(cpp:CppBuf, type:CppType, prefix:String):String { 32 | cpp.addFormat("%|%s %s; %{", type.toCppType(), prefix); 33 | var vb = new CppBuf(); 34 | for (i => tupType in type.params) { 35 | var tupVar = prefix + "_t" + i; 36 | cpp.addFormat("%|%s %s = %s;", 37 | tupType.toCppType(), 38 | tupVar, 39 | tupType.proc.cppRead(cpp, tupType, getPrefix(prefix, i)) 40 | ); 41 | if (i > 0) vb.add(", "); 42 | vb.add(tupVar); 43 | } 44 | cpp.addFormat("%|%s = { %b };", prefix, vb); 45 | cpp.addFormat("%-}"); 46 | return prefix; 47 | } 48 | override public function cppWrite(cpp:CppBuf, type:CppType, prefix:String, val:String):Void { 49 | var v = prefix; 50 | //cpp.addFormat('%|%{'); 51 | cpp.addFormat('%|auto& %s = %s;', v, val); 52 | for (i => t in type.params) { 53 | t.proc.cppWrite(cpp, t, getPrefix(prefix, i), 'std::get<$i>($v)'); 54 | } 55 | //cpp.addFormat('%-}'); 56 | } 57 | 58 | override function getSize(type:CppType):Int { 59 | var n = 0; 60 | for (t in type.params) n += t.getSize(); 61 | return n; 62 | } 63 | override function hasDynSize(type:CppType):Bool { 64 | for (t in type.params) { 65 | if (t.hasDynSize()) return true; 66 | } 67 | return false; 68 | } 69 | override function cppDynSize(cpp:CppBuf, type:CppType, vp:String, val:String, result:String):Int { 70 | var n = 0; 71 | cpp.addFormat("%|auto& %s = %s;", vp, val); 72 | for (i => t in type.params) { 73 | n += t.cppDynSize(cpp, getPrefix(vp, i), 'std::get<$i>($vp)', result); 74 | } 75 | return n; 76 | } 77 | 78 | override function seekRec(type:CppType, fn:(CppType) -> Bool):Bool { 79 | for (t in type.params) if (fn(t)) return true; 80 | return false; 81 | } 82 | 83 | override public function usesStructs(type:CppType):Bool { 84 | for (t in type.params) if (t.proc.usesStructs(t)) return true; 85 | return false; 86 | } 87 | override public function usesGmkSpec(type:CppType):Bool { 88 | for (t in type.params) if (t.proc.usesGmkSpec(t)) return true; 89 | return false; 90 | } 91 | override function isList(type:CppType):Bool { 92 | return CppGen.config.isGMK; 93 | } 94 | } -------------------------------------------------------------------------------- /src/struct/CppStruct.hx: -------------------------------------------------------------------------------- 1 | package struct ; 2 | import proc.CppTypeProcStruct; 3 | import tools.CppReader; 4 | using StringTools; 5 | 6 | /** 7 | * ... 8 | * @author YellowAfterlife 9 | */ 10 | class CppStruct { 11 | public static var list:Array = []; 12 | public static var map:Map = new Map(); 13 | public var name:String; 14 | public var parent:String; 15 | /** "file.cpp:line" */ 16 | public var origin:String; 17 | public var fields:Array = []; 18 | public var proc:CppTypeProcStruct; 19 | /** C++ implementation */ 20 | public var impl:String; 21 | /** 22 | Whether the struct body can/should be copied for forward declaration 23 | (read: it was defined in a source file instead of a header) 24 | **/ 25 | public var shouldForwardDeclare:Bool = true; 26 | public function new(name:String) { 27 | this.name = name; 28 | proc = new CppTypeProcStruct(this); 29 | } 30 | 31 | public static function readStructField(q:tools.CppReader, struct:CppStruct, firstIdent:String) { 32 | var fdType = CppType.read(q, firstIdent); 33 | if (fdType == null) return; 34 | while (q.loop) { 35 | q.skipSpaces(); 36 | var fdName = q.readIdent(); 37 | if (fdName == "") break; 38 | q.skipSpaces(); 39 | if (q.peek() == "(".code) break; // retType funcName() 40 | var fd = new CppStructField(fdType, fdName); 41 | while (q.skipIfEqu("[".code)) { 42 | q.skipSpaces(); 43 | var n = Std.parseInt(q.readIdent()); 44 | q.skipSpaces(); 45 | q.skipIfEqu("]".code); 46 | q.skipSpaces(); 47 | if (n == null) break; 48 | fd.size.push(n); 49 | } 50 | // 51 | struct.fields.push(fd); 52 | q.skipSpaces(); 53 | if (q.skipIfEqu("=".code)) { 54 | q.skipSpaces(); 55 | var depth = 0; 56 | while (q.loop) { 57 | var c = q.read(); 58 | switch (c) { 59 | case '"'.code, "'".code: q.skipCString(c); 60 | case "/".code: { 61 | switch (q.peek()) { 62 | case "/".code: q.skipUntil("\n".code); 63 | case "*".code: q.pos++; q.skipUntilStr("*/"); 64 | } 65 | } 66 | case "{".code, "(".code: depth++; 67 | case "}".code, ")".code: depth--; 68 | case ",".code if (depth == 0): q.back(); break; 69 | case ";".code if (depth == 0): q.back(); break; 70 | } 71 | } 72 | } 73 | // 74 | q.skipSpaces(); 75 | switch (q.peek()) { 76 | case ",".code: q.skip(); 77 | case ";".code: q.skip(); break; 78 | } 79 | } 80 | } 81 | 82 | public static function read(q:tools.CppReader, shouldForwardDeclare) { 83 | var structStart = q.pos - "struct".length; 84 | q.skipSpaces(); 85 | var structName = q.readIdent(); 86 | var struct = new CppStruct(structName); 87 | struct.shouldForwardDeclare = shouldForwardDeclare; 88 | struct.origin = q.name + ":" + q.getRow(structStart); 89 | @:privateAccess CppTypeHelper.map[structName] = struct.proc; 90 | list.push(struct); 91 | map[structName] = struct; 92 | q.skipSpaces(); 93 | if (q.skipIfEqu(":".code)) { 94 | q.skipSpaces(); 95 | struct.parent = q.readIdent(); 96 | } 97 | var depth = 0; 98 | while (q.loop) { 99 | var c = q.read(); 100 | switch (c) { 101 | case '"'.code, "'".code: q.skipCString(c); 102 | case "/".code: { 103 | switch (q.peek()) { 104 | case "/".code: q.skipUntil("\n".code); 105 | case "*".code: q.pos++; q.skipUntilStr("*/"); 106 | } 107 | } 108 | case "{".code, "(".code: depth++; 109 | case "}".code, ")".code: if (--depth <= 0) break; 110 | case _ if (c.isIdent0() && depth == 1): { 111 | var w = q.readIdent(true); 112 | switch (w) { 113 | case "public", "private": {}; 114 | case _ if (w == structName): {}; 115 | default: 116 | readStructField(q, struct, w); 117 | } 118 | } 119 | default: 120 | } 121 | } // can continue 122 | struct.impl = q.substring(structStart, q.pos); 123 | //trace(q.name, structName, structStart, q.len, q.substring(0, structStart) + "<<" + struct.impl + ">>" + q.substring(q.pos, q.len)); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/struct/CppStructField.hx: -------------------------------------------------------------------------------- 1 | package struct ; 2 | import proc.CppTypeProc; 3 | 4 | /** 5 | * ... 6 | * @author YellowAfterlife 7 | */ 8 | class CppStructField { 9 | public var type:CppType; 10 | 11 | public var name:String; 12 | public var size:Array = []; 13 | 14 | public function getSize() { 15 | var n = type.getSize(); 16 | for (m in size) n *= m; 17 | return n; 18 | } 19 | public function getQuantity() { 20 | var n = 1; 21 | for (m in size) n *= m; 22 | return n; 23 | } 24 | public function new(type:CppType, name:String) { 25 | this.type = type; 26 | this.name = name; 27 | } 28 | } -------------------------------------------------------------------------------- /src/struct/CppStructIO.hx: -------------------------------------------------------------------------------- 1 | package struct; 2 | 3 | import proc.CppTypeProc; 4 | import tools.CppBuf; 5 | 6 | class CppStructIO { 7 | public static function readFields(struct:CppStruct, cpp:CppBuf, vp:String) { 8 | for (i => fd in struct.fields) { 9 | for (i => n in fd.size) { 10 | cpp.addFormat("%|for (auto %s = 0u; %0 < %d; %0++) %{", vp + '_i' + i, n); 11 | } 12 | var val = fd.type.proc.cppRead(cpp, fd.type, vp + '_f_' + fd.name); 13 | cpp.addFormat('%|%s.%s', vp, fd.name); 14 | for (i in 0 ... fd.size.length) { 15 | cpp.addFormat('[%s]', vp + '_i' + i); 16 | } 17 | cpp.addFormat(' = %s;', val); 18 | for (_ in 0 ... fd.size.length) { 19 | cpp.addFormat("%-}"); 20 | } 21 | } 22 | } 23 | public static function writeFields(struct:CppStruct, cpp:CppBuf, vp:String) { 24 | for (i => fd in struct.fields) { 25 | for (i => n in fd.size) { 26 | cpp.addFormat("%|for (auto %s = 0u; %0 < %d; %0++) %{", vp + '_i' + i, n); 27 | } 28 | // 29 | var val = vp + "." + fd.name; 30 | for (i in 0 ... fd.size.length) { 31 | val += "[" + vp + '_i' + i + "]"; 32 | } 33 | // 34 | fd.type.proc.cppWrite(cpp, fd.type, vp + '_f_' + fd.name, val); 35 | // 36 | for (_ in 0 ... fd.size.length) { 37 | cpp.addFormat("%-}"); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/struct/GmlStructIO.hx: -------------------------------------------------------------------------------- 1 | package struct; 2 | 3 | import proc.CppTypeProc; 4 | import tools.CppBuf; 5 | 6 | class GmlStructIO { 7 | public static function createTail(struct:CppStruct, gml:CppBuf) { 8 | switch (CppGen.config.storageMode) { 9 | case SmStruct: 10 | gml.addFormat("{}; // %s", struct.name); 11 | case SmArray: 12 | gml.addFormat("array_create(%d); // %s", struct.fields.length, struct.name); 13 | case SmMap: 14 | gml.addFormat("ds_map_create(); // %s", struct.name); 15 | case SmList: 16 | gml.addFormat("ds_list_create(); // %s", struct.name); 17 | } 18 | } 19 | 20 | public static function readFields(struct:CppStruct, gml:CppBuf, z:Int, structVar:String, isOut:Bool) { 21 | var mode = CppGen.config.storageMode; 22 | var useArrays = mode == SmStruct || mode == SmArray; 23 | var acc = isOut ? "@" : ""; 24 | 25 | // this gets called recursively to handle reading fixed-size arrays like `type field[d1][d2]` 26 | function proc(gml:CppBuf, type:CppType, tp:CppTypeProc, z:Int, size:Array, size_ind:Int) { 27 | if (size_ind >= size.length) { 28 | return tp.gmlRead(gml, type, z + 1); 29 | } 30 | if (size_ind == size.length - 1 && type.name == "char") { 31 | // the last char[n] segment becomes a string 32 | var fn = CppGen.config.helperPrefix + "_read_chars"; 33 | return '$fn(_buf, ${size[size_ind]})'; 34 | } 35 | var _arr = '_arr_$z'; 36 | var _ind = '_ind_$z'; 37 | var _len = size[size_ind]; 38 | 39 | // declaration: 40 | gml.addFormat("%|%vdp = ", _arr); 41 | if (useArrays) { 42 | gml.addFormat("array_create(%d);", _len); 43 | } else { 44 | gml.addFormat("ds_list_create();"); 45 | } 46 | 47 | // array itself 48 | gml.addFormat('%|for (%vdb; %0 < %d; %0 += 1) %{', _ind, "0", _len); 49 | var val = proc(gml, type, tp, z + 1, size, size_ind + 1); 50 | if (useArrays) { 51 | gml.addFormat("%|%s[%s%s] = %s;", _arr, acc, _ind, val); 52 | } else { 53 | gml.addFormat("%|ds_list_add(%s, %s", _arr, val); 54 | if (type.proc.isMap(type)) { 55 | gml.addFormat("%|ds_list_mark_as_map(%s, %s);", _arr, _ind); 56 | } else if (type.proc.isMap(type)) { 57 | gml.addFormat("%|ds_list_mark_as_list(%s, %s);", _arr, _ind); 58 | } 59 | } 60 | gml.addFormat("%-}"); 61 | 62 | return _arr; 63 | } // proc 64 | 65 | for (i => fd in struct.fields) { 66 | var tp = fd.type.proc; 67 | var val = proc(gml, fd.type, tp, z + 1, fd.size, 0); 68 | switch (mode) { 69 | case SmStruct: 70 | gml.addFormat("%|%s.%s = %s;", structVar, fd.name, val); 71 | case SmArray: 72 | gml.addFormat("%|%s[%s%d] = %s; // %s", structVar, acc, i, val, fd.name); 73 | case SmMap: 74 | if (tp.isMap(fd.type)) { 75 | gml.addFormat('%|ds_map_add_map(%s, "%s", %s);', structVar, fd.name, val); 76 | } else if (tp.isList(fd.type)) { 77 | gml.addFormat('%|ds_map_add_list(%s, "%s", %s);', structVar, fd.name, val); 78 | } else { 79 | gml.addFormat('%|ds_map_add(%s, "%s", %s);', structVar, fd.name, val); 80 | } 81 | case SmList: 82 | gml.addFormat('%|ds_list_add(%s, %s); // %s', structVar, val, fd.name); 83 | } 84 | } 85 | } 86 | 87 | public static function writeFields(struct:CppStruct, gml:CppBuf, z:Int, structVar:String) { 88 | var mode = CppGen.config.storageMode; 89 | var useArrays = mode == SmStruct || mode == SmArray; 90 | 91 | function proc(gml:CppBuf, type:CppType, tp:CppTypeProc, z:Int, size:Array, size_ind:Int, val:String) { 92 | if (size_ind >= size.length) { 93 | tp.gmlWrite(gml, type, z + 1, val); 94 | return; 95 | } 96 | if (size_ind == size.length - 1 && type.name == "char") { 97 | // same char[n] -> string conversion 98 | var fn = CppGen.config.helperPrefix + "_write_chars"; 99 | gml.addFormat('%|%s(_buf, %s, %d)', fn, val, size[size_ind]); 100 | return; 101 | } 102 | var _arr = '_arr_$z'; 103 | var _ind = '_ind_$z'; 104 | var _len = size[size_ind]; 105 | gml.addFormat("%|%vdp = %s;", _arr, val); 106 | gml.addFormat('%|for (%vdb; %0 < %d; %0 += 1) %{', _ind, 0, _len); 107 | var val = useArrays ? '$_arr[$_ind]' : 'ds_list_find_value($_arr, $_ind)'; 108 | proc(gml, type, tp, z + 1, size, size_ind + 1, val); 109 | gml.addFormat("%-}"); 110 | } // proc 111 | 112 | for (i => fd in struct.fields) { 113 | var note = false; 114 | var val = structVar; 115 | switch (mode) { 116 | case SmStruct: 117 | val += "." + fd.name; 118 | case SmArray: 119 | note = true; 120 | val += '[$i]'; 121 | case SmMap: 122 | val = 'ds_map_find_value($val, "${fd.name}")'; 123 | case SmList: 124 | note = true; 125 | val = 'ds_list_find_value($val, ${i})'; 126 | } 127 | 128 | proc(gml, fd.type, fd.type.proc, z + 1, fd.size, 0, val); 129 | if (note) gml.addFormat(" // %s", fd.name); 130 | } 131 | } 132 | } -------------------------------------------------------------------------------- /src/tools/CharCode.hx: -------------------------------------------------------------------------------- 1 | package tools; 2 | 3 | /** 4 | * ... 5 | * @author YellowAfterlife 6 | */ 7 | abstract CharCode(Int) from Int to Int { 8 | public function isSpace():Bool { 9 | var c = this; 10 | return c == " ".code || c == "\t".code || c == "\r".code || c == "\n".code; 11 | } 12 | public function isLineSpace():Bool { 13 | var c = this; 14 | return c == " ".code || c == "\t".code; 15 | } 16 | public function isIdent0():Bool { 17 | var c = this; 18 | return (c == "_".code 19 | || c >= "a".code && c <= "z".code 20 | || c >= "A".code && c <= "Z".code 21 | ); 22 | } 23 | public function isIdent1():Bool { 24 | var c = this; 25 | return (c == "_".code 26 | || c >= "a".code && c <= "z".code 27 | || c >= "A".code && c <= "Z".code 28 | || c >= "0".code && c <= "9".code 29 | ); 30 | } 31 | public function isDigit():Bool { 32 | var c = this; 33 | return (c >= "0".code && c <= "9".code); 34 | } 35 | } -------------------------------------------------------------------------------- /src/tools/CppReader.hx: -------------------------------------------------------------------------------- 1 | package tools ; 2 | import tools.CharCode; 3 | using StringTools; 4 | 5 | /** 6 | * ... 7 | * @author YellowAfterlife 8 | */ 9 | class CppReader { 10 | public var name:String; 11 | public var str:String; 12 | public var pos:Int = 0; 13 | public var len:Int; 14 | public function new(s:String, name:String) { 15 | this.name = name; 16 | str = s; 17 | len = s.length; 18 | } 19 | 20 | public var loop(get, never):Bool; 21 | private inline function get_loop():Bool { 22 | return pos < len; 23 | } 24 | 25 | public function read():tools.CharCode { 26 | return str.unsafeCodeAt(pos++); 27 | } 28 | 29 | public inline function peek():tools.CharCode { 30 | return str.unsafeCodeAt(pos); 31 | } 32 | public inline function peekAt(ofs:Int):tools.CharCode { 33 | return str.unsafeCodeAt(pos + ofs); 34 | } 35 | 36 | public function peekn(n:Int):String { 37 | return str.substr(pos, n); 38 | } 39 | public function peeknAt(ofs:Int, n:Int):String { 40 | return str.substr(pos + ofs, n); 41 | } 42 | 43 | public function substr(pos:Int, len:Int):String { 44 | return str.substr(pos, len); 45 | } 46 | 47 | public function substring(start:Int, end:Int):String { 48 | return str.substring(start, end); 49 | } 50 | 51 | public inline function skip(n:Int = 1):Void { 52 | pos += n; 53 | } 54 | public inline function back(n:Int = 1):Void { 55 | pos -= n; 56 | } 57 | 58 | public function skipIfEqu(c:tools.CharCode):Bool { 59 | if (peek() == c) { 60 | skip(1); 61 | return true; 62 | } else return false; 63 | } 64 | 65 | public function readIdent(?pastFirst:Bool):String { 66 | var start = pastFirst ? pos - 1 : pos; 67 | while (loop) { 68 | var c = peek(); 69 | if (c.isIdent1()) pos++; else break; 70 | } 71 | return substring(start, pos); 72 | } 73 | 74 | public function readSpIdent():String { 75 | inline this.skipSpaces(); 76 | return inline this.readIdent(); 77 | } 78 | 79 | public function readLspIdent():String { 80 | inline this.skipLineSpaces(); 81 | return inline this.readIdent(); 82 | } 83 | 84 | public function readLine():String { 85 | var start = pos; 86 | while (loop) { 87 | var c = peek(); 88 | if (c == "\n".code) { 89 | return substring(start, pos++); 90 | } else skip(); 91 | } 92 | return substring(start, pos); 93 | } 94 | 95 | public function readLineNonSpace():String { 96 | var start = pos; 97 | while (loop) { 98 | var c = peek(); 99 | if (c == "\n".code) break; 100 | if (!c.isLineSpace()) skip(); else break; 101 | } 102 | return substring(start, pos); 103 | } 104 | 105 | public function skipUntil(c:tools.CharCode) { 106 | while (loop) { 107 | if (read() == c) break; 108 | } 109 | } 110 | 111 | public function skipSpaces() { 112 | while (loop) { 113 | var c = peek(); 114 | if (c.isSpace()) skip(); else break; 115 | } 116 | } 117 | 118 | public function skipLineSpaces() { 119 | while (loop) { 120 | var c = peek(); 121 | if (c.isLineSpace()) skip(); else break; 122 | } 123 | } 124 | 125 | public function skipUntilStr(s:String):Bool { 126 | var n = s.length; 127 | while (loop) { 128 | if (substr(pos, n) == s) { 129 | pos += n; 130 | return true; 131 | } else pos++; 132 | } 133 | return false; 134 | } 135 | 136 | public function skipCString(c1:tools.CharCode) { 137 | while (loop) { 138 | var c = read(); 139 | if (c == c1) break; 140 | if (c == "\\".code) { 141 | pos++; 142 | } 143 | } 144 | } 145 | 146 | public function getRow(pos:Int):Int { 147 | var row = 0; 148 | while (pos > 0) { 149 | row += 1; 150 | pos = str.lastIndexOf("\n", pos - 1); 151 | } 152 | return row; 153 | } 154 | } --------------------------------------------------------------------------------