├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── bootstrap.c ├── dub.sdl ├── dub.selections.json ├── inochi2d.h └── source ├── binding ├── binding.d ├── camera.d ├── deform.d ├── drawable.d ├── err.d ├── meshdata.d ├── nodes.d ├── package.d ├── param.d ├── part.d ├── puppet.d ├── render.d └── texture.d └── utils.d /.gitignore: -------------------------------------------------------------------------------- 1 | .dub 2 | docs.json 3 | __dummy.html 4 | docs/ 5 | /inochi2d-c 6 | inochi2d-c.so 7 | inochi2d-c.dylib 8 | inochi2d-c.dll 9 | inochi2d-c.a 10 | inochi2d-c.lib 11 | inochi2d-c-test-* 12 | *.exe 13 | *.o 14 | *.obj 15 | *.lst 16 | out/ 17 | bootstrap 18 | *.inx 19 | *.inp -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020, Inochi2D Project 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | out/libinochi2d-c.so: 2 | dub build --compiler=ldc --config=yesgl 3 | 4 | bootstrap: bootstrap.c inochi2d.h out/libinochi2d-c.so 5 | gcc $< $(shell pkg-config --libs glfw3 gl) -Lout/ -Wl,-rpath=out -linochi2d-c -o bootstrap 6 | 7 | clean: 8 | rm -rf out 9 | rm -f bootstrap -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inochi2D SDK for C ABIs 2 | This repository contains the neccesary code to use the reference Inochi2D implementation outside of DLang, as well as with non-Inochi2D renderers. 3 | 4 | 5 | ## Initializing and Closing Inochi2D 6 | You will need to pass a function with the signature `double timingFunc()` to Inochi2D on initialization. 7 | * timingFunc should return the current time of the application rendering the game in `sec.ms` format. 8 | * timingFunc is used for physics as well animation calculations 9 | 10 | ```c 11 | double timingFunc() { 12 | return glfwGetTime(); 13 | } 14 | ``` 15 | 16 | To initialize Inochi2D itself you will need to call `inInit` passing your timing function in. 17 | Remember to run inCleanup when you're done using Inochi2D to unload the DLang runtime! 18 | 19 | ```c 20 | inInit(&timingFunc); 21 | // Game and Inochi2D goodness happens here 22 | inCleanup(); 23 | ``` 24 | 25 | ## Loading a puppet 26 | Use `inLoadPuppet` to load a puppet, you will need to pass an UTF-8 encoded null-terminated string to this function. 27 | Use `inDestroyPuppet` to destroy a puppet when it no longer is needed. 28 | 29 | ```c 30 | InPuppet* puppet = inLoadPuppet("myPuppet.inp"); 31 | // Do stuff 32 | 33 | inDestroyPuppet(puppet); 34 | ``` 35 | 36 | ## Getting arrays from Inochi2D 37 | 38 | Such functions take arguments including two: `Type** arr_ptr, size_t* len_ptr`: 39 | 40 | 0) If arr_ptr == null, length is written into `*len_ptr`. End. 41 | 1) If *arr_ptr == null, an array allocated by D is written into `*arr_ptr`. 42 | 2) Otherwise, fill the buffer passed by 'arr_ptr' with length. 43 | 44 | User can use these in following way. 45 | 46 | 0) D manages the memory: Call function with `*arr_ptr==NULL`. 47 | 1) C manages the memory: 48 | 49 | 1) call function with `arr_ptr==NULL`. function returns length of the buffer. 50 | 2) call function with array pre-allocated (`*buff != NULL`) given the length. function fills values to provided array. 51 | 52 | Example: 53 | 54 | ```c 55 | struct { 56 | size_t len; 57 | InParameter **cont; 58 | } parameters; 59 | // let D allocate memory 60 | parameters.cont = NULL; 61 | inPuppetGetParameters(myPuppet, ¶meters.cont, ¶meters.len); 62 | for (size_t i = 0; i < parameters.len; i++) { 63 | char *name = inParameterGetName(parameters.cont[i]); 64 | bool isVec2 = inParameterIsVec2(parameters.cont[i]); 65 | printf("Parameter #%zu: %s is%s vec2.\n", i, name, isVec2 ? "" : " not"); 66 | } 67 | ``` 68 | 69 | ## Using Inochi2D with your own renderer 70 | Inochi2D requires the following GPU accellerated features to be present: 71 | * Framebuffer support (Inochi2D needs 2) 72 | * sRGB->Linear RGB conversion support 73 | * Premultiplied Alpha support 74 | * Vertex buffers 75 | * Stencil buffers 76 | * Pixel shaders 77 | * ROP support or method to emulate porter-duff blending in shader 78 | * At least 4096x4096 texture resolution support 79 | 80 | Optionally the following features may be present 81 | * SPIR-v shader support (For per-part shaders) 82 | 83 | -------------------------------------------------------------------------------- /bootstrap.c: -------------------------------------------------------------------------------- 1 | #define INOCHI2D_GLYES 2 | #include "inochi2d.h" 3 | 4 | #include 5 | #include 6 | 7 | #define WINDOW_WIDTH 480 8 | #define WINDOW_HEIGHT 800 9 | 10 | double timingFunc() { 11 | return glfwGetTime(); 12 | } 13 | 14 | void error_callback(int error, const char* description) { 15 | fprintf(stderr, "Error: %s\n", description); 16 | } 17 | 18 | int main() { 19 | glfwSetErrorCallback(error_callback); 20 | if (!glfwInit()) 21 | return -1; 22 | 23 | // Inochi2D is officially targeted to OpenGL 3.1 and above 24 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 25 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); 26 | GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Inochi2D - C Binding", NULL, NULL); 27 | 28 | glfwMakeContextCurrent(window); 29 | glfwSwapInterval(1); 30 | 31 | // A timing function that returns the current applications runtime in seconds and milliseconds is needed 32 | inInit(&timingFunc); 33 | 34 | // viewport size, which is the size of the scene 35 | uint sceneWidth; 36 | uint sceneHeight; 37 | 38 | // It is highly recommended to change the viewport with 39 | // inSetViewport to match the viewport you want, otherwise it'll be 640x480 40 | inViewportSet(WINDOW_WIDTH, WINDOW_HEIGHT); 41 | inViewportGet(&sceneWidth, &sceneHeight); 42 | 43 | // Also many vtuber textures are pretty big so let's zoom out a bit. 44 | InCamera* camera = inCameraGetCurrent(); 45 | inCameraSetZoom(camera, 0.2); 46 | inCameraSetPosition(camera, 0, 1000); 47 | 48 | // You can get example models at https://github.com/Inochi2D/example-models 49 | InPuppet* myPuppet = inPuppetLoad("Aka.inx"); 50 | 51 | struct { 52 | size_t len; 53 | InParameter **cont; 54 | } parameters; 55 | // let D allocate memory (see README) 56 | parameters.cont = NULL; 57 | inPuppetGetParameters(myPuppet, ¶meters.cont, ¶meters.len); 58 | for (size_t i = 0; i < parameters.len; i++) { 59 | char *name = inParameterGetName(parameters.cont[i]); 60 | bool isVec2 = inParameterIsVec2(parameters.cont[i]); 61 | printf("Parameter #%zu: %s is%s vec2.\n", i, name, isVec2 ? "" : " not"); 62 | } 63 | // set "Head:: Roll" to -1.0 64 | inParameterSetValue(parameters.cont[1], -1, 0); 65 | 66 | while(!glfwWindowShouldClose(window)) { 67 | // NOTE: Inochi2D does not itself clear the main framebuffer 68 | // you have to do that your self. 69 | glClear(GL_COLOR_BUFFER_BIT); 70 | 71 | // Run inUpdate first 72 | // This updates various submodules and time managment for animation 73 | inUpdate(); 74 | 75 | // Imagine there's a lot of rendering code here 76 | // Maybe even some game logic or something 77 | 78 | // Begins drawing in to the Inochi2D scene 79 | // NOTE: You *need* to do this otherwise rendering may break 80 | inSceneBegin(); 81 | 82 | // Draw and update myPuppet. 83 | // Convention for using Inochi2D in D is to put everything 84 | // in a scene block one indent in. 85 | inPuppetUpdate(myPuppet); 86 | inPuppetDraw(myPuppet); 87 | 88 | // Ends drawing in to the Inochi2D scene. 89 | inSceneEnd(); 90 | 91 | // Draw the scene, background is transparent 92 | inSceneDraw(0, 0, sceneWidth, sceneHeight); 93 | 94 | // Do the buffer swapping and event polling last 95 | glfwSwapBuffers(window); 96 | glfwPollEvents(); 97 | } 98 | 99 | inCleanup(); 100 | glfwTerminate(); 101 | return 0; 102 | } -------------------------------------------------------------------------------- /dub.sdl: -------------------------------------------------------------------------------- 1 | name "inochi2d-c" 2 | description "Inochi2D C compatibility layer" 3 | authors "Inochi2D Project" 4 | copyright "Copyright © 2022, Inochi2D Project" 5 | license "BSD 2-clause" 6 | dependency "inochi2d" version="~>0.9.0" 7 | targetType "dynamicLibrary" 8 | targetPath "out/" 9 | 10 | toolchainRequirements dmd="no" gdc="no" ldc=">=1.11.0" 11 | 12 | dflags "-mscrtlib=msvcrt" platform="windows-ldc" // Use the dynamic CRT on Windows. 13 | dflags "-flto=full" platform="ldc" 14 | dflags "-fvisibility=hidden" platform="ldc" 15 | dflags "-link-defaultlib-shared=false" platform="ldc" 16 | dflags "-d-version=GL_ARB" platform="ldc" 17 | 18 | copyFiles "*/inochi2d-c.lib" platform="windows-ldc" // On Windows, copy the lib file to allow usage of link.exe 19 | 20 | configuration "nogl" { 21 | subConfiguration "inochi2d" "renderless" 22 | versions "nogl" 23 | } 24 | 25 | configuration "yesgl" { 26 | subConfiguration "inochi2d" "full" 27 | versions "yesgl" 28 | } -------------------------------------------------------------------------------- /dub.selections.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileVersion": 1, 3 | "versions": { 4 | "bindbc-loader": "1.0.3", 5 | "bindbc-opengl": "1.0.5", 6 | "fghj": "1.0.1", 7 | "imagefmt": "2.1.2", 8 | "inmath": "1.0.5", 9 | "inochi2d": "0.7.2", 10 | "mir-algorithm": "3.20.1", 11 | "mir-core": "1.5.5", 12 | "silly": "1.1.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /inochi2d.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2022, Inochi2D Project 3 | Distributed under the 2-Clause BSD License, see LICENSE file. 4 | 5 | Authors: Luna Nielsen 6 | */ 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef H_INOCHI2D 12 | #define H_INOCHI2D 13 | 14 | // Handle calling convention on Windows. 15 | // This will ensure MSVC does not try to use stdcall 16 | // when the D library uses cdecl. 17 | #ifdef _WIN32 18 | #ifdef _MSC_VER 19 | #define EXPORT_I2D __cdecl 20 | #else 21 | #define EXPORT_I2D 22 | #endif 23 | #else 24 | #define EXPORT_I2D 25 | #endif 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | typedef uint32_t uint; 31 | 32 | struct InError { 33 | size_t len; 34 | const char* msg; 35 | }; 36 | typedef struct InError InError; 37 | EXPORT_I2D InError* inErrorGet(); 38 | 39 | typedef struct InPuppet InPuppet; 40 | typedef struct InCamera InCamera; 41 | typedef struct InRenderable InRenderable; 42 | 43 | // Inochi2D runtime functionality 44 | EXPORT_I2D void inInit(double (*timingFunc)()); 45 | EXPORT_I2D void inCleanup(); 46 | EXPORT_I2D void inUpdate(); 47 | EXPORT_I2D void inBlockProtected(void (*func)()); 48 | EXPORT_I2D void inViewportSet(uint width, uint height); 49 | EXPORT_I2D void inViewportGet(uint* width, uint* height); 50 | #ifdef INOCHI2D_GLYES 51 | EXPORT_I2D void inSceneBegin(); 52 | EXPORT_I2D void inSceneEnd(); 53 | EXPORT_I2D void inSceneDraw(float x, float y, float width, float height); 54 | #endif 55 | 56 | // Inochi2D Cameras 57 | EXPORT_I2D InCamera* inCameraGetCurrent(); 58 | EXPORT_I2D void inCameraDestroy(InCamera* camera); 59 | EXPORT_I2D void inCameraGetPosition(InCamera* camera, float* x, float* y); 60 | EXPORT_I2D void inCameraSetPosition(InCamera* camera, float x, float y); 61 | EXPORT_I2D void inCameraGetZoom(InCamera* camera, float* zoom); 62 | EXPORT_I2D void inCameraSetZoom(InCamera* camera, float zoom); 63 | EXPORT_I2D void inCameraGetCenterOffset(InCamera* camera, float* x, float* y); 64 | EXPORT_I2D void inCameraGetRealSize(InCamera* camera, float* x, float* y); 65 | EXPORT_I2D void inCameraGetMatrix(InCamera* camera, float* mat4); // NOTE: mat4 array needs to be 16 elements long. 66 | 67 | // Inochi2D Puppets 68 | EXPORT_I2D InPuppet* inPuppetLoad(const char *path); 69 | EXPORT_I2D InPuppet* inPuppetLoadEx(const char *path, size_t length); 70 | EXPORT_I2D InPuppet* inPuppetLoadFromMemory(uint8_t* data, size_t length); 71 | EXPORT_I2D void inPuppetDestroy(InPuppet* puppet); 72 | EXPORT_I2D void inPuppetGetName(InPuppet* puppet, const char *text, size_t *len); 73 | EXPORT_I2D void inPuppetUpdate(InPuppet* puppet); 74 | #ifdef INOCHI2D_GLYES 75 | EXPORT_I2D void inPuppetDraw(InPuppet* puppet); 76 | #endif 77 | 78 | // Inochi2D Puppet Parameters 79 | typedef struct InParameter InParameter; 80 | EXPORT_I2D void inPuppetGetParameters(InPuppet* puppet, InParameter*** array_ptr, size_t* length); 81 | EXPORT_I2D char* inParameterGetName(InParameter* param); 82 | EXPORT_I2D void inParameterGetValue(InParameter* param, float* x, float* y); 83 | EXPORT_I2D void inParameterSetValue(InParameter* param, float x, float y); 84 | EXPORT_I2D uint inParameterGetUUID(InParameter* param); 85 | EXPORT_I2D bool inParameterIsVec2(InParameter* param); 86 | EXPORT_I2D void inParameterGetMin(InParameter* param, float* xmin, float* ymin); 87 | EXPORT_I2D void inParameterGetMax(InParameter* param, float* xmax, float* ymax); 88 | EXPORT_I2D void inParameterGetAxes(InParameter* param, float*** axes, size_t* xLength, size_t* yLength); 89 | EXPORT_I2D void inParameterFindClosestKeypoint(InParameter* param, float x, float y, uint* index_x, uint* index_y); 90 | EXPORT_I2D void inParameterFindClosestKeypointAtCurrent(InParameter* param, uint* index_x, uint* index_y); 91 | EXPORT_I2D void inParameterDestroy(InParameter* param); 92 | EXPORT_I2D void inParameterReset(InParameter* param); 93 | 94 | // Inochi2D Puppet Parameter Bindings 95 | typedef struct InNode InNode; 96 | typedef struct InParameterBinding InParameterBinding; 97 | EXPORT_I2D InParameterBinding* inParameterGetBinding(InParameter* param, InNode* node, char* bindingName); 98 | EXPORT_I2D InParameterBinding* inParameterCreateBinding(InParameter* param, InNode* node, char* bindingName); 99 | EXPORT_I2D InParameterBinding* inParameterGetOrAddBinding(InParameter* param, InNode* node, char* bindingName); 100 | EXPORT_I2D void inParameterAddBinding(InParameter* param, InParameterBinding* binding); 101 | EXPORT_I2D void inParameterRemoveBinding(InParameter* param, InParameterBinding* binding); 102 | 103 | #ifdef __cplusplus 104 | } 105 | #endif 106 | 107 | 108 | #endif -------------------------------------------------------------------------------- /source/binding/binding.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding.binding; 10 | import binding; 11 | import binding.err; 12 | import binding.param; 13 | import binding.nodes: InNode; 14 | import std.stdio; 15 | import std.string; 16 | import inochi2d; 17 | import core.stdc.stdlib; 18 | import core.stdc.string; 19 | import utils; 20 | 21 | // Everything here should be C ABI compatible 22 | extern(C) export: 23 | 24 | struct InParameterBinding { 25 | ParameterBinding binding; 26 | }; 27 | 28 | InParameterBinding* to_binding(ref ParameterBinding b) { 29 | auto result = alloc!(ParameterBinding, InParameterBinding)(b); 30 | return result; 31 | } 32 | 33 | void inParameterGetBindings(InParameter* param, InParameterBinding*** arr, size_t* length) { 34 | array2carray!(ParameterBinding, InParameterBinding*, to_binding)(param.param.bindings, arr, length); 35 | } 36 | 37 | /** 38 | Apply a binding to the model at the given parameter value 39 | */ 40 | void inParameterBindingApply(InParameterBinding* binding, uint leftKeyPointX, uint leftKeyPointY, float offsetX, float offsetY) { 41 | auto leftKeyPoint = vec2u(leftKeyPointX, leftKeyPointY); 42 | auto offset = vec2(offsetX, offsetY); 43 | binding.binding.apply(leftKeyPoint, offset); 44 | } 45 | 46 | /** 47 | Clear all keypoint data 48 | */ 49 | void inParameterBindingClear(InParameterBinding* binding) { 50 | binding.binding.clear(); 51 | } 52 | 53 | /** 54 | Sets value at specified keypoint to the current value 55 | */ 56 | void inParameterBindingSetCurrent(InParameterBinding* binding, uint x, uint y) { 57 | auto key = vec2u(x, y); 58 | binding.binding.setCurrent(key); 59 | } 60 | 61 | /** 62 | Unsets value at specified keypoint 63 | */ 64 | void inParameterBindingUnset(InParameterBinding* binding, uint x, uint y) { 65 | auto key = vec2u(x, y); 66 | binding.binding.unset(key); 67 | } 68 | 69 | /** 70 | Resets value at specified keypoint to default 71 | */ 72 | void inParameterBindingReset(InParameterBinding* binding, uint x, uint y) { 73 | auto key = vec2u(x, y); 74 | binding.binding.reset(key); 75 | } 76 | 77 | /** 78 | Returns whether the specified keypoint is set 79 | */ 80 | bool inParameterBindingIsSet(InParameterBinding* binding, uint x, uint y) { 81 | auto key = vec2u(x, y); 82 | return binding.binding.isSet(key); 83 | } 84 | 85 | /** 86 | Scales the value, optionally with axis awareness 87 | */ 88 | void inParameterBindingScaleValueAt(InParameterBinding* binding, uint x, uint y, int axis, float scale) { 89 | auto key = vec2u(x, y); 90 | binding.binding.scaleValueAt(key, axis, scale); 91 | } 92 | 93 | /** 94 | Extrapolates the value across an axis 95 | */ 96 | void inParameterBindingExtrapolateValueAt(InParameterBinding* binding, uint x, uint y, int axis) { 97 | auto key = vec2u(x, y); 98 | binding.binding.extrapolateValueAt(key, axis); 99 | } 100 | 101 | /** 102 | Copies the value to a point on another compatible binding 103 | */ 104 | void inParameterBindingCopyKeypointToBinding(InParameterBinding* binding, uint srcX, uint srcY, InParameterBinding* other, uint destX, uint destY) { 105 | auto src = vec2u(srcX, srcY); 106 | auto dest = vec2u(destX, destY); 107 | binding.binding.copyKeypointToBinding(src, other.binding, dest); 108 | } 109 | 110 | /** 111 | Swaps the value to a point on another compatible binding 112 | */ 113 | void inParameterBindingSwapKeypointWithBinding(InParameterBinding* binding, uint srcX, uint srcY, InParameterBinding* other, uint destX, uint destY) { 114 | auto src = vec2u(srcX, srcY); 115 | auto dest = vec2u(destX, destY); 116 | binding.binding.swapKeypointWithBinding(src, other.binding, dest); 117 | } 118 | 119 | /** 120 | Flip the keypoints on an axis 121 | */ 122 | void inParameterBindingReverseAxis(InParameterBinding* binding, uint axis) { 123 | binding.binding.reverseAxis(axis); 124 | } 125 | 126 | /** 127 | Update keypoint interpolation 128 | */ 129 | void inParameterBindingReInterpolate(InParameterBinding* binding) { 130 | binding.binding.reInterpolate(); 131 | } 132 | 133 | /** 134 | Move keypoints to a new axis point 135 | */ 136 | void inParameterBindingMoveKeypoints(InParameterBinding* binding, uint axis, uint oldindex, uint index) { 137 | binding.binding.moveKeypoints(axis, oldindex, index); 138 | } 139 | 140 | /** 141 | Add keypoints along a new axis point 142 | */ 143 | void inParameterBindingInsertKeypoints(InParameterBinding* binding, uint axis, uint index) { 144 | binding.binding.insertKeypoints(axis, index); 145 | } 146 | 147 | /** 148 | Remove keypoints along an axis point 149 | */ 150 | void inParameterBindingDeleteKeypoints(InParameterBinding* binding, uint axis, uint index) { 151 | binding.binding.deleteKeypoints(axis, index); 152 | } 153 | 154 | /** 155 | Gets name of binding 156 | */ 157 | char* inParameterBindingGetName(InParameterBinding* binding) { 158 | return str2cstr(binding.binding.getName()); 159 | } 160 | 161 | /** 162 | Gets the node of the binding 163 | */ 164 | InNode* inParameterBindingGetNode(InParameterBinding* binding) { 165 | return alloc!(Node, InNode)(binding.binding.getNode()); 166 | } 167 | 168 | /** 169 | Gets the uuid of the node of the binding 170 | */ 171 | uint inParameterBindingGetNodeUUID(InParameterBinding* binding) { 172 | return binding.binding.getNodeUUID(); 173 | } 174 | 175 | /** 176 | Checks whether a binding is compatible with another node 177 | */ 178 | bool inParameterBindingIsCompatibleWithNode(InParameterBinding* binding, InNode* other) { 179 | return binding.binding.isCompatibleWithNode(other.node); 180 | } 181 | 182 | /** 183 | Gets the interpolation mode 184 | */ 185 | uint inParameterBindingGetInterpolateMode(InParameterBinding* binding) { 186 | return cast(uint)binding.binding.interpolateMode(); 187 | } 188 | 189 | /** 190 | Sets the interpolation mode 191 | */ 192 | void inParameterBindingSetInterpolateMode(InParameterBinding* binding, uint mode) { 193 | binding.binding.interpolateMode(cast(InterpolateMode)mode); 194 | } 195 | 196 | void inParameterBindingDestroy(InParameterBinding* binding) { 197 | free_obj(binding); 198 | } -------------------------------------------------------------------------------- /source/binding/camera.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding.camera; 10 | import binding; 11 | import utils; 12 | 13 | // Everything here should be C ABI compatible 14 | extern(C) export: 15 | 16 | struct InCamera { 17 | Inochi2D.Camera camera; 18 | } 19 | 20 | private { 21 | InCamera* to_camera(ref Camera c) { 22 | return alloc!(Camera, InCamera)(c); 23 | } 24 | 25 | } 26 | 27 | /** 28 | Gets the current camera 29 | */ 30 | InCamera* inCameraGetCurrent() { 31 | Camera camera = Inochi2D.inGetCamera(); 32 | return to_camera(camera); 33 | } 34 | 35 | /** 36 | Sets the position of a camera 37 | */ 38 | void inCameraSetPosition(InCamera* camera, float x, float y) { 39 | camera.camera.position = vec2(x, y); 40 | } 41 | 42 | /** 43 | Sets the position of a camera 44 | */ 45 | void inCameraGetPosition(InCamera* camera, float* x, float* y) { 46 | *x = camera.camera.position.x; 47 | *y = camera.camera.position.y; 48 | } 49 | 50 | 51 | /** 52 | Sets the zoom of a camera 53 | */ 54 | void inCameraSetZoom(InCamera* camera, float zoom) { 55 | camera.camera.scale = vec2(zoom, zoom); 56 | } 57 | 58 | /** 59 | Gets the zoom of a camera 60 | */ 61 | void inCameraGetZoom(InCamera* camera, float* zoom) { 62 | *zoom = camera.camera.scale.x; 63 | } 64 | 65 | /** 66 | Gets the center offset of the camera 67 | */ 68 | void inCameraGetCenterOffset(InCamera* camera, float* x, float* y) { 69 | auto v = camera.camera.getCenterOffset; 70 | *x = v.x; 71 | *y = v.y; 72 | } 73 | 74 | /** 75 | Gets the "real size" from the camera 76 | */ 77 | void inCameraGetRealSize(InCamera* camera, float* x, float* y) { 78 | auto v = camera.camera.getRealSize; 79 | *x = v.x; 80 | *y = v.y; 81 | } 82 | 83 | /** 84 | Copies the values of the internal camera matrix out to mat4 85 | */ 86 | void inCameraGetMatrix(InCamera* camera, const(float)* mat4) { 87 | import core.stdc.string : memcpy; 88 | memcpy(cast(void*)mat4, camera.camera.matrix.ptr, float.sizeof*16); 89 | } 90 | 91 | /** 92 | Destroys a camera 93 | */ 94 | void inCameraDestroy(InCamera* camera) { 95 | free_obj(camera); 96 | } 97 | 98 | void inCameraGetScreenToGlobalMatrix(InCamera* camera, const(float)* mat) { 99 | auto center = camera.camera.getCenterOffset(); 100 | auto matrix = mat4.translation(- (center.x + camera.camera.position.x), (center.y + camera.camera.position.y), 0) * mat4.scaling(1 / camera.camera.scale.x, -1 / camera.camera.scale.y, 0); 101 | import core.stdc.string : memcpy; 102 | memcpy(cast(void*)mat, matrix.ptr, float.sizeof*16); 103 | } -------------------------------------------------------------------------------- /source/binding/deform.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding.deform; 10 | 11 | import inochi2d; 12 | import binding.binding; 13 | import utils; 14 | import core.stdc.stdlib; 15 | import core.stdc.string; 16 | 17 | extern(C) export: 18 | 19 | enum BindingType { 20 | Value, Deformation, End 21 | } 22 | 23 | bool inParameterBindingGetFloat(InParameterBinding* binding, uint x, uint y, float* value) { 24 | auto floatBinding = cast(ValueParameterBinding)binding.binding; 25 | if (floatBinding is null) 26 | return false; 27 | *value = floatBinding.values[x][y]; 28 | return true; 29 | } 30 | 31 | bool inParameterBindingSetFloat(InParameterBinding* binding, uint x, uint y, float value) { 32 | auto floatBinding = cast(ValueParameterBinding)binding.binding; 33 | if (floatBinding is null) 34 | return false; 35 | 36 | floatBinding.values[x][y] = value; 37 | floatBinding.isSet_[x][y] = true; 38 | return true; 39 | } 40 | 41 | void inParameterBindingClearValue(InParameterBinding* binding, uint x, uint y) { 42 | binding.binding.getIsSet()[x][y] = false; 43 | } 44 | 45 | bool inParameterBindingGetDeformation(InParameterBinding* binding, uint x, uint y, float** values, size_t* length) { 46 | auto deformBinding = cast(DeformationParameterBinding)binding.binding; 47 | if (deformBinding is null) 48 | return false; 49 | 50 | vec2array2farray(deformBinding.values[x][y].vertexOffsets, values, length); 51 | return true; 52 | } 53 | 54 | bool inParameterBindingSetDeformation(InParameterBinding* binding, uint x, uint y, float* values, size_t length) { 55 | auto deformBinding = cast(DeformationParameterBinding)binding.binding; 56 | if (deformBinding is null) 57 | return false; 58 | 59 | deformBinding.values[x][y].vertexOffsets.length = length / 2; 60 | memcpy(deformBinding.values[x][y].vertexOffsets.ptr, values, length * float.sizeof); 61 | deformBinding.isSet_[x][y] = true; 62 | return true; 63 | } 64 | 65 | BindingType inParameterBindingGetType(InParameterBinding* binding) { 66 | if (cast(ValueParameterBinding)binding.binding) { 67 | return BindingType.Value; 68 | } else if (cast(DeformationParameterBinding)binding.binding) { 69 | return BindingType.Deformation; 70 | } else { 71 | return BindingType.End; 72 | } 73 | } 74 | 75 | BindingType inParameterBindingGetValue(InParameterBinding* binding, uint x, uint y, float** values, size_t* length) { 76 | BindingType result = inParameterBindingGetType(binding); 77 | switch (result) { 78 | case BindingType.Value: 79 | if (length) 80 | *length = 1; 81 | if (values) { 82 | *values = cast(float*)malloc(float.sizeof); 83 | inParameterBindingGetFloat(binding, x, y, *values); 84 | } 85 | break; 86 | case BindingType.Deformation: 87 | inParameterBindingGetDeformation(binding, x, y, values, length); 88 | break; 89 | default: 90 | break; 91 | } 92 | return result; 93 | } 94 | 95 | BindingType inParameterBindingSetValue(InParameterBinding* binding, uint x, uint y, float* values, size_t length) { 96 | BindingType result = inParameterBindingGetType(binding); 97 | switch (result) { 98 | case BindingType.Value: 99 | inParameterBindingSetFloat(binding, x, y, *values); 100 | break; 101 | case BindingType.Deformation: 102 | inParameterBindingSetDeformation(binding, x, y, values, length); 103 | break; 104 | default: 105 | break; 106 | } 107 | return result; 108 | } -------------------------------------------------------------------------------- /source/binding/drawable.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding.drawable; 10 | 11 | import binding; 12 | import binding.err; 13 | import binding.puppet; 14 | import binding.nodes: InNode; 15 | import inochi2d; 16 | import core.stdc.string; 17 | import utils; 18 | 19 | // Everything here should be C ABI compatible 20 | extern(C) export: 21 | 22 | void inSetUpdateBounds(bool state) { 23 | inochi2d.inSetUpdateBounds(state); 24 | } 25 | 26 | bool inDrawableGetVertices(InNode* node, float** vertices, size_t* length) { 27 | Drawable drawable = cast(Drawable)node.node; 28 | if (drawable is null) 29 | return false; 30 | 31 | vec2array2farray(drawable.vertices, vertices, length); 32 | return true; 33 | } 34 | 35 | bool inDrawableSetVertices(InNode* node, float* vertices, size_t length) { 36 | Drawable drawable = cast(Drawable)node.node; 37 | if (drawable is null) 38 | return false; 39 | 40 | drawable.vertices.length = length / 2; 41 | memcpy(drawable.vertices.ptr, vertices, length * float.sizeof); 42 | return true; 43 | } 44 | 45 | bool inDrawableGetDeformation(InNode* node, float** deformation, size_t* length) { 46 | Drawable drawable = cast(Drawable)node.node; 47 | if (drawable is null) 48 | return false; 49 | 50 | vec2array2farray(drawable.deformation, deformation, length); 51 | return true; 52 | } 53 | 54 | bool inDrawableRefresh(InNode* node) { 55 | Drawable drawable = cast(Drawable)node.node; 56 | if (drawable is null) 57 | return false; 58 | 59 | drawable.refresh(); 60 | return true; 61 | } 62 | 63 | bool inDrawableRefreshDeform(InNode* node) { 64 | Drawable drawable = cast(Drawable)node.node; 65 | if (drawable is null) 66 | return false; 67 | 68 | drawable.refreshDeform(); 69 | return true; 70 | } 71 | 72 | bool inDrawableReset(InNode* node) { 73 | Drawable drawable = cast(Drawable)node.node; 74 | if (drawable is null) 75 | return false; 76 | 77 | drawable.reset(); 78 | return true; 79 | } 80 | 81 | bool inDrawableDrawBounds(InNode* node) { 82 | Drawable drawable = cast(Drawable)node.node; 83 | if (drawable is null) 84 | return false; 85 | 86 | drawable.drawBounds(); 87 | return true; 88 | } 89 | 90 | bool inDrawableDrawMeshLines(InNode* node) { 91 | Drawable drawable = cast(Drawable)node.node; 92 | if (drawable is null) 93 | return false; 94 | 95 | drawable.drawMeshLines(); 96 | return true; 97 | } 98 | 99 | bool inDrawableDrawMeshPoints(InNode* node) { 100 | Drawable drawable = cast(Drawable)node.node; 101 | if (drawable is null) 102 | return false; 103 | 104 | drawable.drawMeshPoints(); 105 | return true; 106 | } 107 | 108 | bool inDrawableGetDynamicMatrix(InNode* node, float* mat4) { 109 | import core.stdc.string : memcpy; 110 | Drawable drawable = cast(Drawable)node.node; 111 | MeshGroup group = cast(MeshGroup)node.node; 112 | if (drawable is null || group !is null) { 113 | auto matrix = node.node.transform.matrix; 114 | memcpy(cast(void*)mat4, matrix.ptr, float.sizeof*16); 115 | return true; 116 | } 117 | 118 | auto matrix = drawable.getDynamicMatrix(); 119 | memcpy(cast(void*)mat4, matrix.ptr, float.sizeof*16); 120 | return true; 121 | } 122 | -------------------------------------------------------------------------------- /source/binding/err.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding.err; 10 | 11 | package(binding) { 12 | InError* currError_; 13 | 14 | void setError(Exception ex) { 15 | currError_ = new InError(ex.msg); 16 | } 17 | } 18 | 19 | /** 20 | An Inochi2D error 21 | */ 22 | struct InError { 23 | string msg; 24 | } 25 | 26 | extern(C) export: 27 | 28 | InError* inErrorGet() { 29 | return currError_; 30 | } -------------------------------------------------------------------------------- /source/binding/meshdata.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding.meshdata; 10 | import binding.nodes: InNode; 11 | import inochi2d; 12 | import utils; 13 | import core.stdc.string; 14 | import binding.nodes; 15 | 16 | extern(C) export: 17 | 18 | bool inDrawableGetMeshData(InNode* node, float** vertices, size_t* vertLen, 19 | float** uvs, size_t* uvLen, ushort** indices, size_t* indLen, 20 | float*** gridAxes, size_t* axesLenX, size_t* axesLenY, 21 | float* originX, float* originY) { 22 | auto drawable = cast(Drawable)node.node; 23 | if (drawable is null) 24 | return false; 25 | 26 | MeshData data = drawable.getMesh(); 27 | vec2array2farray(data.vertices, vertices, vertLen); 28 | vec2array2farray(data.uvs, uvs, uvLen); 29 | array2carray!(ushort, ushort)(data.indices, indices, indLen); 30 | 31 | if (gridAxes) { 32 | size_t*[2] length = [axesLenY, axesLenX]; 33 | size_t dummy; 34 | size_t index = 0; 35 | 36 | array2carray!(float[], float*, (float[] points) { 37 | float* result = null; 38 | array2carray!(float, float)(points, &result, length[index++]); 39 | return result; 40 | })(data.gridAxes, gridAxes, &dummy); 41 | } 42 | 43 | if (originX) *originX = data.origin.x; 44 | if (originY) *originY = data.origin.y; 45 | 46 | return true; 47 | } 48 | 49 | 50 | bool inDrawableSetMeshData(InNode* node, float* vertices, uint vertLen, 51 | float* uvs, uint uvLen, ushort* indices, uint indLen, 52 | float** gridAxes, uint axesLenX, uint axesLenY, 53 | float* originX, float* originY) { 54 | auto drawable = cast(Drawable)node.node; 55 | if (drawable is null) 56 | return false; 57 | 58 | MeshData data = drawable.getMesh(); 59 | if (vertices) { 60 | data.vertices.length = vertLen / 2; 61 | memcpy(data.vertices.ptr, vertices, vertLen * float.sizeof); 62 | } 63 | 64 | if (uvs) { 65 | data.uvs.length = uvLen / 2; 66 | memcpy(data.uvs.ptr, uvs, uvLen * float.sizeof); 67 | } 68 | 69 | if (indices) { 70 | data.indices.length = indLen; 71 | memcpy(data.indices.ptr, indices, indLen * ushort.sizeof); 72 | } 73 | 74 | if (gridAxes) { 75 | data.gridAxes.length = 2; 76 | data.gridAxes[0].length = axesLenY; 77 | memcpy(data.gridAxes[0].ptr, gridAxes[0], axesLenY * float.sizeof); 78 | data.gridAxes[1].length = axesLenX; 79 | memcpy(data.gridAxes[1].ptr, gridAxes[1], axesLenX * float.sizeof); 80 | } 81 | 82 | if (originX) { 83 | data.origin.x = *originX; 84 | } 85 | 86 | if (originY) { 87 | data.origin.y = *originY; 88 | } 89 | 90 | if (auto mgroup = cast(MeshGroup)node.node) { 91 | mgroup.clearCache(); 92 | } 93 | 94 | drawable.rebuffer(data); 95 | return true; 96 | } -------------------------------------------------------------------------------- /source/binding/nodes.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding.nodes; 10 | 11 | import binding; 12 | import binding.err; 13 | import binding.puppet; 14 | import inochi2d; 15 | import utils; 16 | import fghj; 17 | 18 | import std.array : appender, Appender; 19 | import std.range.primitives : put; 20 | 21 | 22 | // Everything here should be C ABI compatible 23 | extern(C) export: 24 | 25 | struct InNode { 26 | Node node; 27 | } 28 | private { 29 | InNode* to_node(ref Node b) { 30 | return alloc!(Node, InNode)(b); 31 | } 32 | 33 | } 34 | 35 | InNode* inPuppetGetRootNode(InPuppet* puppet) { 36 | return to_node(puppet.puppet.root); 37 | } 38 | 39 | void inNodeGetChildren(InNode* node, InNode*** array_ptr, size_t* length) { 40 | array2carray!(Node, InNode*, to_node)(node.node.children, array_ptr, length); 41 | } 42 | 43 | char* inNodeGetName(InNode* node) { 44 | return str2cstr(node.node.name); 45 | } 46 | 47 | uint inNodeGetUUID(InNode* node) { 48 | return node.node.uuid; 49 | } 50 | 51 | InNode* inNodeGetParent(InNode* node) { 52 | return to_node(node.node.parent); 53 | } 54 | 55 | float inNodeGetZSort(InNode* node) { 56 | return node.node.zSort; 57 | } 58 | 59 | bool inNodeGetLockToRoot(InNode* node) { 60 | return node.node.lockToRoot; 61 | } 62 | 63 | char* inNodeGetPath(InNode* node) { 64 | return str2cstr(node.node.getNodePath); 65 | } 66 | 67 | bool inNodeGetEnabled(InNode* node) { 68 | return node.node.enabled; 69 | } 70 | 71 | char* inNodeGetTypeId(InNode* node) { 72 | return str2cstr(node.node.typeId); 73 | } 74 | 75 | bool inNodeHasParam(InNode* node, char* name) { 76 | auto dName = cstr2str(name); 77 | return node.node.hasParam(dName); 78 | } 79 | 80 | float inNodeGetValue(InNode* node, char* name) { 81 | return node.node.getValue(cstr2str(name)); 82 | } 83 | 84 | void inNodeSetValue(InNode* node, char* name, float value) { 85 | node.node.setValue(cstr2str(name), value); 86 | } 87 | 88 | void inNodeGetTranslation(InNode* node, float*x, float* y, float *z) { 89 | auto tran = node.node.localTransform.translation; 90 | *x = tran.x; 91 | *y = tran.y; 92 | *z = tran.z; 93 | } 94 | 95 | void inNodeGetRotation(InNode* node, float*x, float* y, float* z) { 96 | auto rot = node.node.localTransform.rotation; 97 | *x = rot.x; 98 | *y = rot.y; 99 | *z = rot.z; 100 | } 101 | 102 | void inNodeGetScale(InNode* node, float*x, float* y, float* z) { 103 | auto scale = node.node.localTransform.scale; 104 | *x = scale.x; 105 | *y = scale.y; 106 | } 107 | 108 | void inNodeSetTranslation(InNode* node, float x, float y, float z) { 109 | node.node.localTransform.translation = vec3(x, y, z); 110 | } 111 | 112 | void inNodeSetRotation(InNode* node, float x, float y, float z) { 113 | node.node.localTransform.rotation = vec3(x, y, z); 114 | } 115 | 116 | void inNodeSetScale(InNode* node, float x, float y) { 117 | node.node.localTransform.scale = vec2(x, y); 118 | } 119 | 120 | version (yesgl) { 121 | 122 | /** 123 | Draw node 124 | */ 125 | void inNodeDraw(InNode* node) { 126 | node.node.draw(); 127 | } 128 | 129 | void inNodeDrawOne(InNode* node) { 130 | node.node.drawOne(); 131 | } 132 | } 133 | 134 | void inNodeUpdate(InNode* node) { 135 | node.node.update(); 136 | } 137 | 138 | void inNodeBeginUpdate(InNode* node) { 139 | node.node.beginUpdate(); 140 | } 141 | 142 | void inNodeTransformChanged(InNode* node) { 143 | node.node.transformChanged(); 144 | } 145 | 146 | void inNodeGetCombinedBounds(InNode* node, float* x, float* y, float* z, float* w) { 147 | vec4 result = node.node.getCombinedBounds(); 148 | *x = result.x; 149 | *y = result.y; 150 | *z = result.z; 151 | *w = result.w; 152 | } 153 | 154 | void inNodeGetCombinedBoundsWithUpdate(InNode* node, float* x, float* y, float* z, float* w) { 155 | vec4 result = node.node.getCombinedBounds!true(); 156 | *x = result.x; 157 | *y = result.y; 158 | *z = result.z; 159 | *w = result.w; 160 | } 161 | 162 | void inNodeLoadJson(InNode* node, char* text) { 163 | auto jsonText = cstr2str(text); 164 | Fghj data = parseJson(jsonText); 165 | node.node.deserializeFromFghj(data); 166 | } 167 | 168 | char* inNodeDumpJson(InNode* node, bool recursive) { 169 | auto app = appender!(char[]); 170 | auto serializer = inCreateSerializer(app); 171 | // serializer.serializeValue(node.node); 172 | uint state = serializer.objectBegin(); 173 | node.node.serializePartial(serializer, recursive); 174 | serializer.objectEnd(state); 175 | serializer.flush(); 176 | return str2cstr(cast(string)app.data); 177 | } 178 | 179 | void inNodeAddChild(InNode* node, InNode* child) { 180 | node.node.addChild(child.node); 181 | } 182 | 183 | void inNodeInsertInto(InNode* node, InNode* other, size_t offset) { 184 | node.node.insertInto(other.node, offset); 185 | } 186 | 187 | void inNodeRemoveChild(InNode* node, InNode* child) { 188 | if (child.node.parent == node.node) { 189 | child.node.parent = null; 190 | } 191 | } 192 | 193 | void inNodeGetTransformMatrix(InNode* node, float* mat4) { 194 | import core.stdc.string : memcpy; 195 | auto matrix = node.node.transform.matrix; 196 | memcpy(cast(void*)mat4, matrix.ptr, float.sizeof*16); 197 | } 198 | 199 | void inNodeGetLocalTransformMatrix(InNode* node, float* mat4) { 200 | import core.stdc.string : memcpy; 201 | auto matrix = node.node.localTransform.matrix; 202 | memcpy(cast(void*)mat4, matrix.ptr, float.sizeof*16); 203 | } 204 | 205 | void inNodeDestroy(InNode* node) { 206 | free_obj(node); 207 | } -------------------------------------------------------------------------------- /source/binding/package.d: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2022, Inochi2D Project 3 | Distributed under the 2-Clause BSD License, see LICENSE file. 4 | 5 | Authors: Luna Nielsen, seagetch 6 | */ 7 | module binding; 8 | public import std.string : fromStringz; 9 | public import Inochi2D = inochi2d; 10 | public import inochi2d.integration; 11 | public import inochi2d.math; 12 | public import core.runtime; 13 | public import core.memory; 14 | 15 | import core.sys.windows.windows; 16 | import core.sys.windows.dll; 17 | import bindbc.opengl; 18 | import core.stdc.stdlib; 19 | import std.datetime.systime; 20 | import utils; 21 | 22 | import std.stdio; 23 | 24 | // This needs to be here for Windows to link properly 25 | version(Windows) { 26 | mixin SimpleDllMain; 27 | } else { 28 | version = NotWindows; 29 | } 30 | 31 | alias i2DTimingFuncSignature = double function(); 32 | 33 | double currTime() { 34 | auto t = Clock.currTime; 35 | double result = (t.toUnixTime() + t.fracSecs.total!"msecs" * 0.001); 36 | return result; 37 | } 38 | 39 | // Everything here should be C ABI compatible 40 | extern(C) export: 41 | 42 | /** 43 | Initializes Inochi2D 44 | */ 45 | void inInit(i2DTimingFuncSignature func) { 46 | 47 | try { 48 | version(NotWindows) Runtime.initialize(); 49 | version(yesgl) { 50 | loadOpenGL(); 51 | } 52 | if (func is null) { 53 | Inochi2D.inInit(&currTime); 54 | } 55 | else 56 | Inochi2D.inInit(func); 57 | } catch (Exception ex) { 58 | import std.stdio; 59 | writeln(ex); 60 | } 61 | } 62 | 63 | /** 64 | Updates the Inochi2D timing systems 65 | */ 66 | void inUpdate() { 67 | Inochi2D.inUpdate(); 68 | } 69 | 70 | /** 71 | Uninitializes Inochi2D and cleans up everything 72 | */ 73 | void inCleanup() { 74 | version(yesgl) { 75 | unloadOpenGL(); 76 | } 77 | version(NotWindows) Runtime.terminate(); 78 | } 79 | 80 | /** 81 | Sets viewport 82 | */ 83 | void inViewportSet(int width, int height) { 84 | Inochi2D.inSetViewport(width, height); 85 | } 86 | 87 | /** 88 | Gets viewport size 89 | */ 90 | void inViewportGet(int* width, int* height) { 91 | int w, h; 92 | Inochi2D.inGetViewport(w, h); 93 | 94 | *width = w; 95 | *height = h; 96 | } 97 | 98 | version (yesgl) { 99 | /** 100 | Begins a scene render 101 | */ 102 | void inSceneBegin() { 103 | Inochi2D.inBeginScene(); 104 | } 105 | 106 | /** 107 | Ends a scene render 108 | */ 109 | void inSceneEnd() { 110 | Inochi2D.inEndScene(); 111 | } 112 | 113 | /** 114 | Draws Inochi2D scene 115 | */ 116 | void inSceneDraw(float x, float y, float width, float height) { 117 | Inochi2D.inDrawScene(vec4(x, y, width, height)); 118 | } 119 | } 120 | 121 | /** 122 | Runs function in a protected block that catches D exceptions. 123 | */ 124 | void inBlockProtected(void function() func) { 125 | try { 126 | func(); 127 | } catch(Exception ex) { 128 | import std.stdio : writeln; 129 | writeln(ex); 130 | } 131 | } 132 | 133 | void inFreeMem(void* mem) { 134 | free(mem); 135 | } 136 | 137 | void inFreeArray(void** mem, size_t length) { 138 | for (size_t i = 0; i < length; i ++) { 139 | free(mem[i]); 140 | } 141 | free(mem); 142 | } -------------------------------------------------------------------------------- /source/binding/param.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding.param; 10 | 11 | import binding; 12 | import binding.err; 13 | import binding.nodes: InNode; 14 | import binding.puppet; 15 | import binding.binding; 16 | import inochi2d; 17 | import utils; 18 | 19 | // Everything here should be C ABI compatible 20 | extern(C) export: 21 | 22 | struct InParameter { 23 | Inochi2D.Parameter param; 24 | } 25 | private { 26 | InParameter* to_param(ref Parameter b) { 27 | return alloc!(Parameter, InParameter)(b); 28 | } 29 | } 30 | 31 | void inPuppetGetParameters(InPuppet* puppet, InParameter*** array_ptr, size_t* length) { 32 | array2carray!(Parameter, InParameter*, to_param)(puppet.puppet.parameters, array_ptr, length); 33 | } 34 | 35 | char* inParameterGetName(InParameter* param) { 36 | return str2cstr(param.param.name); 37 | } 38 | 39 | void inParameterGetValue(InParameter* param, float* x, float* y) { 40 | *x = param.param.value.x; 41 | *y = param.param.value.y; 42 | } 43 | 44 | void inParameterSetValue(InParameter* param, float x, float y) { 45 | param.param.value.x = x; 46 | param.param.value.y = y; 47 | } 48 | 49 | uint inParameterGetUUID(InParameter* param) { 50 | return param.param.uuid; 51 | } 52 | 53 | bool inParameterIsVec2(InParameter* param) { 54 | return param.param.isVec2; 55 | } 56 | 57 | void inParameterGetMin(InParameter* param, float* xmin, float* ymin) { 58 | *xmin = param.param.min.x; 59 | *ymin = param.param.min.y; 60 | } 61 | 62 | void inParameterGetMax(InParameter* param, float* xmax, float* ymax) { 63 | *xmax = param.param.max.x; 64 | *ymax = param.param.max.y; 65 | } 66 | 67 | void inParameterGetAxes(InParameter* param, float*** axes, size_t* xLength, size_t* yLength) { 68 | size_t*[2] length = [xLength, yLength]; 69 | size_t dummy; 70 | size_t index = 0; 71 | array2carray!(float[], float*, (float[] points) { 72 | float* result = null; 73 | array2carray!(float, float)(points, &result, length[index++]); 74 | return result; 75 | })(param.param.axisPoints, axes, &dummy); 76 | } 77 | 78 | void inParameterFindClosestKeypoint(InParameter* param, float x, float y, uint* index_x, uint* index_y) { 79 | vec2u result = param.param.findClosestKeypoint(vec2(x, y)); 80 | *index_x = result.x; 81 | *index_y = result.y; 82 | } 83 | 84 | void inParameterFindClosestKeypointAtCurrent(InParameter* param, uint* index_x, uint* index_y) { 85 | vec2u result = param.param.findClosestKeypoint(); 86 | *index_x = result.x; 87 | *index_y = result.y; 88 | } 89 | 90 | void inParameterDestroy(InParameter* param) { 91 | free_obj(param); 92 | } 93 | 94 | InParameterBinding* inParameterGetBinding(InParameter* param, InNode* node, char* bindingName) { 95 | string name = cstr2str(bindingName); 96 | auto binding = param.param.getBinding(node.node, name); 97 | return to_binding(binding); 98 | } 99 | 100 | InParameterBinding* inParameterCreateBinding(InParameter* param, InNode* node, char* bindingName) { 101 | string name = cstr2str(bindingName); 102 | auto binding = param.param.createBinding(node.node, name); 103 | return to_binding(binding); 104 | } 105 | 106 | InParameterBinding* inParameterGetOrAddBinding(InParameter* param, InNode* node, char* bindingName) { 107 | string name = cstr2str(bindingName); 108 | auto binding = param.param.getOrAddBinding(node.node, name); 109 | return to_binding(binding); 110 | } 111 | 112 | void inParameterAddBinding(InParameter* param, InParameterBinding* binding) { 113 | param.param.addBinding(binding.binding); 114 | } 115 | 116 | void inParameterRemoveBinding(InParameter* param, InParameterBinding* binding) { 117 | param.param.removeBinding(binding.binding); 118 | } 119 | 120 | void inParameterReset(InParameter* param) { 121 | param.param.value = param.param.defaults; 122 | } -------------------------------------------------------------------------------- /source/binding/part.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding.part; 10 | 11 | import binding; 12 | import binding.err; 13 | import binding.texture; 14 | import binding.nodes: InNode; 15 | import inochi2d; 16 | import core.stdc.string; 17 | import utils; 18 | 19 | // Everything here should be C ABI compatible 20 | extern(C) export: 21 | 22 | bool inPartGetTextures(InNode* node, InTexture*** array_ptr, size_t* length) { 23 | auto part = cast(Part)node.node; 24 | if (part is null) 25 | return false; 26 | 27 | array2carray!(Texture, InTexture*, to_texture)(part.textures, array_ptr, length); 28 | return true; 29 | } -------------------------------------------------------------------------------- /source/binding/puppet.d: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2022, Inochi2D Project 3 | Distributed under the 2-Clause BSD License, see LICENSE file. 4 | 5 | Authors: Luna Nielsen, seagetch 6 | */ 7 | module binding.puppet; 8 | import binding; 9 | import binding.err; 10 | import std.stdio; 11 | import inochi2d; 12 | import utils; 13 | 14 | // Everything here should be C ABI compatible 15 | extern(C) export: 16 | 17 | struct InPuppet { 18 | Inochi2D.Puppet puppet; 19 | version(nogl) TextureBlob[] blob; 20 | } 21 | private { 22 | InPuppet* to_puppet(ref Puppet c) { 23 | return alloc!(Puppet, InPuppet)(c); 24 | } 25 | 26 | } 27 | 28 | /** 29 | Loads a puppet from path 30 | */ 31 | InPuppet* inPuppetLoad(const(char)* path) { 32 | try { 33 | auto puppet = Inochi2D.inLoadPuppet(cast(string)path.fromStringz); 34 | auto result = to_puppet(puppet); 35 | version(nogl) { 36 | result.blob = inCurrentPuppetTextureSlots.dup; 37 | inCurrentPuppetTextureSlots.length = 0; 38 | } 39 | return result; 40 | } catch(Exception ex) { 41 | writeln(ex); 42 | setError(ex); 43 | return null; 44 | } 45 | } 46 | 47 | 48 | /** 49 | Loads a puppet from path (length denominated string) 50 | */ 51 | InPuppet* inPuppetLoadEx(const(char)* path, size_t length) { 52 | try { 53 | auto puppet = Inochi2D.inLoadPuppet(cast(string)path[0..length]); 54 | auto result = to_puppet(puppet); 55 | version(nogl) { 56 | result.blob = inCurrentPuppetTextureSlots.dup; 57 | inCurrentPuppetTextureSlots.length = 0; 58 | } 59 | return result; 60 | } catch(Exception ex) { 61 | setError(ex); 62 | return null; 63 | } 64 | } 65 | 66 | /** 67 | Loads a puppet from memory 68 | */ 69 | InPuppet* inPuppetLoadFromMemory(ubyte* data, size_t length) { 70 | try { 71 | auto puppet = Inochi2D.inLoadINPPuppet(data[0..length]); 72 | auto result = to_puppet(puppet); 73 | version(nogl) { 74 | result.blob = inCurrentPuppetTextureSlots.dup; 75 | inCurrentPuppetTextureSlots.length = 0; 76 | } 77 | return result; 78 | } catch(Exception ex) { 79 | setError(ex); 80 | return null; 81 | } 82 | } 83 | 84 | /** 85 | Destroys a puppet and unloads its 86 | */ 87 | void inPuppetDestroy(InPuppet* puppet) { 88 | free_obj(puppet); 89 | } 90 | 91 | /** 92 | Gets the name of a puppet (as written in metadata) 93 | */ 94 | void inPuppetGetName(InPuppet* puppet, const(char)** ptr, size_t* len) { 95 | import core.stdc.string : memcpy; 96 | import core.stdc.stdlib : malloc; 97 | 98 | // Nothing to do 99 | if (puppet.puppet.meta.name.length == 0) return; 100 | 101 | const(char)* str = cast(const(char)*)malloc(puppet.puppet.meta.name.length); 102 | memcpy(cast(void*)str, cast(void*)puppet.puppet.meta.name.ptr, puppet.puppet.meta.name.length); 103 | *ptr = str; 104 | *len = puppet.puppet.meta.name.length; 105 | } 106 | 107 | bool inPuppetGetEnableDrivers(InPuppet* puppet) { 108 | return puppet.puppet.enableDrivers; 109 | } 110 | 111 | void inPuppetSetEnableDrivers(InPuppet* puppet, bool value) { 112 | puppet.puppet.enableDrivers = value; 113 | puppet.puppet.resetDrivers(); 114 | } 115 | 116 | /** 117 | Update puppet 118 | */ 119 | void inPuppetUpdate(InPuppet* puppet) { 120 | puppet.puppet.update(); 121 | } 122 | 123 | version (yesgl) { 124 | 125 | /** 126 | Draw puppet 127 | */ 128 | void inPuppetDraw(InPuppet* puppet) { 129 | puppet.puppet.draw(); 130 | } 131 | } 132 | 133 | void inNodeResetDrivers(InPuppet* puppet) { 134 | puppet.puppet.resetDrivers(); 135 | } 136 | -------------------------------------------------------------------------------- /source/binding/render.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding; 10 | -------------------------------------------------------------------------------- /source/binding/texture.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module binding.texture; 10 | 11 | import binding; 12 | import binding.err; 13 | import binding.puppet; 14 | import inochi2d; 15 | import utils; 16 | 17 | import core.stdc.string; 18 | 19 | // Everything here should be C ABI compatible 20 | extern(C) export: 21 | struct InTexture { 22 | Texture texture; 23 | } 24 | 25 | struct InShallowTexture { 26 | ShallowTexture texture; 27 | } 28 | 29 | InTexture* to_texture(ref Texture c) { 30 | return alloc!(Texture, InTexture)(c); 31 | } 32 | 33 | InShallowTexture* to_stexture(ref ShallowTexture c) { 34 | return alloc!(ShallowTexture, InShallowTexture)(c); 35 | } 36 | 37 | InTexture* inPuppetGetTexture(InPuppet* puppet, uint id) { 38 | Texture texture = puppet.puppet.textureSlots[id]; 39 | return to_texture(texture); 40 | } 41 | 42 | int inTextureGetWidth(InTexture* texture) { 43 | return texture.texture.width(); 44 | } 45 | 46 | int inTextureGetHeight(InTexture* texture) { 47 | return texture.texture.height(); 48 | } 49 | 50 | uint inTextureGetColorMode(InTexture* texture) { 51 | return texture.texture.colorMode(); 52 | } 53 | 54 | int inTextureGetChannels(InTexture* texture) { 55 | return texture.texture.channels(); 56 | } 57 | 58 | void inTextureGetCenter(InTexture* texture, int* x, int* y) { 59 | auto center = texture.texture.center(); 60 | *x = center.x; 61 | *y = center.y; 62 | } 63 | 64 | void inTextureGetSize(InTexture* texture, int* x, int* y) { 65 | auto center = texture.texture.size(); 66 | *x = center.x; 67 | *y = center.y; 68 | } 69 | 70 | void inTextureBind(InTexture* texture, uint unit) { 71 | texture.texture.bind(unit); 72 | } 73 | 74 | uint inTextureGetTextureId(InTexture* texture) { 75 | return texture.texture.getTextureId(); 76 | } 77 | 78 | void inTextureDispose(InTexture* texture) { 79 | texture.texture.dispose(); 80 | } 81 | 82 | void inTextureSetData(InTexture* texture, ubyte* buffer, size_t length) { 83 | ubyte[] data; 84 | data.length = length; 85 | memcpy(data.ptr, buffer, length * ubyte.sizeof); 86 | texture.texture.setData(data); 87 | } 88 | 89 | void inTextureGetTextureData(InTexture* texture, bool unmultiply, ubyte** buffer, size_t* length) { 90 | auto data = texture.texture.getTextureData(unmultiply); 91 | array2carray!(ubyte, ubyte)(data, buffer, length); 92 | } 93 | 94 | void inTextureDestroy(InTexture* texture) { 95 | free_obj(texture); 96 | } -------------------------------------------------------------------------------- /source/utils.d: -------------------------------------------------------------------------------- 1 | /* 2 | Inochi2D C ABI 3 | 4 | Copyright © 2023, Inochi2D Project 5 | Distributed under the 2-Clause BSD License, see LICENSE file. 6 | 7 | Authors: Luna Nielsen, seagetch 8 | */ 9 | module utils; 10 | import inochi2d; 11 | 12 | import binding; 13 | import binding.err; 14 | 15 | import core.stdc.stdlib; 16 | import core.stdc.string; 17 | 18 | char* str2cstr(string str) { 19 | char* result = cast(char*)malloc(str.length * char.sizeof + 1); 20 | memcpy(result, str.ptr, str.length * char.sizeof); 21 | result[str.length] = 0; 22 | return result; 23 | } 24 | 25 | string cstr2str(char* cstr) { 26 | char[] result; 27 | result.length = strlen(cstr); 28 | memcpy(result.ptr, cstr, result.length); 29 | return cast(string)result; 30 | } 31 | 32 | T2 id(T1, T2)(ref T1 src) { 33 | return cast(T2)src; 34 | } 35 | 36 | void array2carray(T1, T2, alias Convert = id!(T1, T2))(T1[] in_arr, T2** arr, size_t* length) { 37 | if (length !is null) 38 | *length = in_arr.length; 39 | if (arr !is null) { 40 | T2* result; 41 | import std.stdio; 42 | if (*arr is null) { 43 | result = cast(T2*)malloc(in_arr.length * T2.sizeof); 44 | *arr = result; 45 | } else { 46 | result = *arr; 47 | } 48 | foreach (i, a; in_arr) { 49 | result[i] = Convert(a); 50 | } 51 | } 52 | } 53 | 54 | void vec2array2farray(vec2[] in_arr, float** arr, size_t* length) { 55 | array2carray!(vec2, vec2)(in_arr, cast(vec2**)arr, length); 56 | if (length !is null) 57 | *length *= 2; 58 | } 59 | 60 | T2* alloc(T1, T2)(T1 obj) { 61 | auto result = new T2(obj); 62 | GC.addRoot(result); 63 | return result; 64 | 65 | // T2* result = cast(T2*)malloc(T2.sizeof); 66 | // *result = T2(obj); 67 | // return result; 68 | } 69 | 70 | void free_obj(T2)(T2* obj) { 71 | GC.removeRoot(obj); 72 | destroy!false(obj); 73 | 74 | // free(obj); 75 | } --------------------------------------------------------------------------------