diff options
| author | Amir Rajan <[email protected]> | 2020-11-13 01:29:16 -0600 |
|---|---|---|
| committer | Amir Rajan <[email protected]> | 2020-11-13 01:29:16 -0600 |
| commit | 128fa1d90cea6289605a49daf56a0cbb72e2dd28 (patch) | |
| tree | 5cfdb499d275e2b43075e4d6a076365fc58ff0f7 /samples/12_c_extensions | |
| parent | 05cbef7fb8224332795e5685be499d81d20e7d93 (diff) | |
| download | dragonruby-game-toolkit-contrib-128fa1d90cea6289605a49daf56a0cbb72e2dd28.tar.gz dragonruby-game-toolkit-contrib-128fa1d90cea6289605a49daf56a0cbb72e2dd28.zip | |
synced from DRGTK 1.27
Diffstat (limited to 'samples/12_c_extensions')
8 files changed, 193 insertions, 0 deletions
diff --git a/samples/12_c_extensions/03_native_pixel_arrays/README.md b/samples/12_c_extensions/03_native_pixel_arrays/README.md new file mode 100644 index 0000000..f7cd12b --- /dev/null +++ b/samples/12_c_extensions/03_native_pixel_arrays/README.md @@ -0,0 +1,13 @@ +Please see samples/12_c_extensions/01_basics for the overview of C extensions. + +This sample reproduces the same program from +samples/07_advanced_rendering/06_pixel_arrays, but moves the creation of the +pixel array to C code. + +This particular use-case doesn't need heavier processing power, so you are +only risking problems and portability loss by moving into native code, but +for more computationally demanding jobs, this can be quite helpful: not only +can C crunch numbers and access memory faster, but you can also hand your +pixel array to the renderer without having to convert it to a Ruby array +first (which the engine would then just convert it right back again anyhow). + diff --git a/samples/12_c_extensions/03_native_pixel_arrays/app/ext.c b/samples/12_c_extensions/03_native_pixel_arrays/app/ext.c new file mode 100644 index 0000000..49d0e40 --- /dev/null +++ b/samples/12_c_extensions/03_native_pixel_arrays/app/ext.c @@ -0,0 +1,54 @@ +#ifndef NULL +#define NULL 0 +#endif +typedef unsigned int Uint32; + +extern void *(*drb_symbol_lookup)(const char *sym); +typedef void (*drb_upload_pixel_array_fn)(const char *name, const int w, const int h, const Uint32 *pixels); + +void update_scanner_texture(void) +{ + #define dimension 10 + + static drb_upload_pixel_array_fn drb_upload_pixel_array = NULL; + static int pos = 0; + static int posinc = 1; + + if (!drb_upload_pixel_array) { + drb_upload_pixel_array = drb_symbol_lookup("drb_upload_pixel_array"); + if (!drb_upload_pixel_array) { + return; // oh well. + } + } + + + // Set up our "scanner" pixel array and fill it with black pixels. + + // You could make this faster by making this array static (which will + // initialize it all to zero at startup), and then blanking the previous + // line and drawing the next, and not touching the rest. + Uint32 pixels[dimension * dimension]; + for (int i = 0; i < (dimension * dimension); i++) { + pixels[i] = 0xFF000000; // full alpha, full black + } + + // Draw a green line that bounces up and down the sprite. + Uint32 *line = pixels + (pos * dimension); + for (int i = 0; i < dimension; i++) { + line[i] = 0xFF00FF00; // full alpha, full green + } + + // Adjust position for next frame. + pos += posinc; + if ((posinc > 0) && (pos >= dimension)) { + posinc = -1; + pos = dimension - 1; + } else if ((posinc < 0) && (pos < 0)) { + posinc = 1; + pos = 1; + } + + // Send it to the renderer to create/update a sprite. + drb_upload_pixel_array("scanner", dimension, dimension, pixels); +} + diff --git a/samples/12_c_extensions/03_native_pixel_arrays/app/main.rb b/samples/12_c_extensions/03_native_pixel_arrays/app/main.rb new file mode 100644 index 0000000..1dbc716 --- /dev/null +++ b/samples/12_c_extensions/03_native_pixel_arrays/app/main.rb @@ -0,0 +1,22 @@ +$gtk.ffi_misc.gtk_dlopen("ext") +include FFI::CExt + +def tick args + args.state.rotation ||= 0 + + update_scanner_texture # this calls into a C extension! + + # New/changed pixel arrays get uploaded to the GPU before we render + # anything. At that point, they can be scaled, rotated, and otherwise + # used like any other sprite. + w = 100 + h = 100 + x = (1280 - w) / 2 + y = (720 - h) / 2 + args.outputs.background_color = [64, 0, 128] + args.outputs.primitives << [x, y, w, h, :scanner, args.state.rotation].sprite + args.state.rotation += 1 + + args.outputs.primitives << args.gtk.current_framerate_primitives +end + diff --git a/samples/12_c_extensions/03_native_pixel_arrays/license-for-sample.txt b/samples/12_c_extensions/03_native_pixel_arrays/license-for-sample.txt new file mode 100644 index 0000000..100dcec --- /dev/null +++ b/samples/12_c_extensions/03_native_pixel_arrays/license-for-sample.txt @@ -0,0 +1,9 @@ +Copyright 2019 DragonRuby LLC + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/samples/12_c_extensions/03_native_pixel_arrays/metadata/game_metadata.txt b/samples/12_c_extensions/03_native_pixel_arrays/metadata/game_metadata.txt new file mode 100644 index 0000000..a8772d0 --- /dev/null +++ b/samples/12_c_extensions/03_native_pixel_arrays/metadata/game_metadata.txt @@ -0,0 +1,5 @@ +devid=dragonruby +devtitle=DragonRuby LLC +gameid=cbasics +gametitle=C Basics +version=1.0 diff --git a/samples/12_c_extensions/03_native_pixel_arrays/native/ext-bindings.c b/samples/12_c_extensions/03_native_pixel_arrays/native/ext-bindings.c new file mode 100644 index 0000000..c0a923c --- /dev/null +++ b/samples/12_c_extensions/03_native_pixel_arrays/native/ext-bindings.c @@ -0,0 +1,66 @@ +#include <mruby.h> +#include <string.h> +#include <assert.h> +#include <mruby/string.h> +#include <mruby/data.h> +#include <dragonruby.h> +#include "app/ext.c" + +// MRuby `typedef`s mrb_int in the mruby/value.h +// Then `#define`s mrb_int in mruby.h +// We need to undo the macro and avoid it's usage +// FIXME: I'm surely doing something wrong +#ifdef mrb_int +#undef mrb_int +#endif + +void *(*drb_symbol_lookup)(const char *sym) = NULL; + +static void (*drb_free_foreign_object_f)(mrb_state *, void *); +static struct RClass *(*mrb_module_get_f)(mrb_state *, const char *); +static mrb_int (*mrb_get_args_f)(mrb_state *, mrb_args_format, ...); +static struct RClass *(*mrb_module_get_under_f)(mrb_state *, struct RClass *, const char *); +static struct RClass *(*mrb_class_get_under_f)(mrb_state *, struct RClass *, const char *); +static struct RClass *(*mrb_define_module_under_f)(mrb_state *, struct RClass *, const char *); +static void (*mrb_define_module_function_f)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec); +static struct RClass *(*mrb_define_class_under_f)(mrb_state *, struct RClass *, const char *, struct RClass *); +static void (*mrb_define_method_f)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec); +static void (*mrb_define_class_method_f)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec); +static struct RData *(*mrb_data_object_alloc_f)(mrb_state *, struct RClass *, void *, const mrb_data_type *); +static mrb_value (*mrb_str_new_cstr_f)(mrb_state *, const char *); +static void (*mrb_raise_f)(mrb_state *, struct RClass *, const char *); +static struct RClass *(*mrb_exc_get_f)(mrb_state *, const char *); +static void drb_free_foreign_object_indirect(mrb_state *state, void *pointer) { + drb_free_foreign_object_f(state, pointer); +} +static mrb_value drb_ffi_update_scanner_texture_Binding(mrb_state *state, mrb_value value) { + update_scanner_texture(); + return mrb_nil_value(); +} +static int drb_ffi_init_indirect_functions(void *(*lookup)(const char *)); +DRB_FFI_EXPORT +void drb_register_c_extensions(void *(*lookup)(const char *), mrb_state *state, struct RClass *FFI) { + if (drb_ffi_init_indirect_functions(lookup)) + return; + struct RClass *module = mrb_define_module_under_f(state, FFI, "CExt"); + struct RClass *object_class = state->object_class; + mrb_define_module_function_f(state, module, "update_scanner_texture", drb_ffi_update_scanner_texture_Binding, MRB_ARGS_REQ(0)); +} +static int drb_ffi_init_indirect_functions(void *(*lookup)(const char *fnname)) { + drb_symbol_lookup = lookup; + if (!(mrb_exc_get_f = (struct RClass *(*)(mrb_state *, const char *)) lookup("mrb_exc_get"))) return -1; + if (!(mrb_raise_f = (void (*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_raise"))) return -1; + if (!(mrb_class_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_class_get_under"))) return -1; + if (!(mrb_module_get_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_module_get_under"))) return -1; + if (!(drb_free_foreign_object_f = (void (*)(mrb_state *, void *)) lookup("drb_free_foreign_object"))) return -1; + if (!(mrb_module_get_f = (struct RClass *(*)(mrb_state *, const char *)) lookup("mrb_module_get"))) return -1; + if (!(mrb_define_module_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *)) lookup("mrb_define_module_under"))) return -1; + if (!(mrb_data_object_alloc_f = (struct RData *(*)(mrb_state *, struct RClass *, void *, const mrb_data_type *)) lookup("mrb_data_object_alloc"))) return -1; + if (!(mrb_define_module_function_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_module_function"))) return -1; + if (!(mrb_get_args_f = (mrb_int (*)(mrb_state *, mrb_args_format, ...)) lookup("mrb_get_args"))) return -1; + if (!(mrb_define_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_method"))) return -1; + if (!(mrb_define_class_method_f = (void (*)(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec)) lookup("mrb_define_class_method"))) return -1; + if (!(mrb_str_new_cstr_f = (mrb_value (*)(mrb_state *, const char *)) lookup("mrb_str_new_cstr"))) return -1; + if (!(mrb_define_class_under_f = (struct RClass *(*)(mrb_state *, struct RClass *, const char *, struct RClass *)) lookup("mrb_define_class_under"))) return -1; + return 0; +} diff --git a/samples/12_c_extensions/03_native_pixel_arrays/pre.bat b/samples/12_c_extensions/03_native_pixel_arrays/pre.bat new file mode 100644 index 0000000..16befa3 --- /dev/null +++ b/samples/12_c_extensions/03_native_pixel_arrays/pre.bat @@ -0,0 +1,5 @@ +set DRB_ROOT=..\..\..\ +md native +md native\windows-amd64 +%DRB_ROOT%\dragonruby-bind.exe --output=native\ext-bind.c app\ext.c +clang -shared .\native\ext-bind.c --sysroot=C:\mingw-w64\mingw64 --target=x86_64-w64-mingw32 -fuse-ld=lld -isystem %DRB_ROOT%\include -I. -o native\windows-amd64\ext.dll diff --git a/samples/12_c_extensions/03_native_pixel_arrays/pre.sh b/samples/12_c_extensions/03_native_pixel_arrays/pre.sh new file mode 100755 index 0000000..07965a5 --- /dev/null +++ b/samples/12_c_extensions/03_native_pixel_arrays/pre.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +OSTYPE=`uname -s` +if [ "x$OSTYPE" = "xDarwin" ]; then + PLATFORM=macos + DLLEXT=dylib +else + PLATFORM=linux-amd64 + DLLEXT=so +fi + +DRB_ROOT=../../.. +mkdir -p native/$PLATFORM + +$DRB_ROOT/dragonruby-bind --output=native/ext-bindings.c app/ext.c +clang \ + -isystem $DRB_ROOT/include -I. \ + -fPIC -shared native/ext-bindings.c -o native/$PLATFORM/ext.$DLLEXT + |
