diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..cc0d143 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sh text eof=lf diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml new file mode 100644 index 0000000..f213893 --- /dev/null +++ b/.gitea/workflows/build.yaml @@ -0,0 +1,25 @@ +name: Build +run-name: Building docker container. +on: + workflow_dispatch: + push: + branches: stable + +jobs: + build: + runs-on: ubuntu-latest + container: + image: git.mixedup.dev/quik/docker-cross-compiler + env: + QUIK_API_KEY: "${{secrets.QUIK_API_KEY}}" + volumes: + - ${{ gitea.workspace }}:/home/quik/src + steps: + - name: Check repository out. + uses: actions/checkout@v3 + with: + submodules: recursive + - name: Run Build Script + run: "./build_native.sh" + - name: Publish Package + run: "./publish.sh" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c27cc2c --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +**/bin +**/obj +**/out +**/runtimes +**/.vs* +**/.atom diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a4c74ed --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.0) + +project(quik_stbi LANGUAGES C VERSION 1.0) + +add_compile_options(-static-libgcc) + +add_library(stbi SHARED "quik_stbi.c") +install( + TARGETS stbi + RUNTIME DESTINATION . + LIBRARY DESTINATION .) diff --git a/NativeTypeNameAttribute.cs b/NativeTypeNameAttribute.cs new file mode 100644 index 0000000..becb962 --- /dev/null +++ b/NativeTypeNameAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Quik.Stb.Image +{ + [AttributeUsage(System.AttributeTargets.All, Inherited = false, AllowMultiple = true)] + internal sealed class NativeTypeNameAttribute : System.Attribute + { + public NativeTypeNameAttribute(string typename) + { + } + } +} diff --git a/Quik.Common b/Quik.Common index 11bb72a..d9c98b5 160000 --- a/Quik.Common +++ b/Quik.Common @@ -1 +1 @@ -Subproject commit 11bb72a464215693d5a3a6896b25e568cc6e3313 +Subproject commit d9c98b5cdc37b2ba1855c8fa9ce0fac8266b0f89 diff --git a/Quik.StbImage.csproj b/Quik.StbImage.csproj new file mode 100644 index 0000000..c8f983f --- /dev/null +++ b/Quik.StbImage.csproj @@ -0,0 +1,61 @@ + + + + net6.0 + disable + 7.3 + True + linux-arm;linux-arm64;linux-x64;win-x86;win-x64 + + + + + True + Quik.StbImage + 1.0.0 + STBI Authors, H. Utku Maden + + A C# wrapper for the ubiquitous Stb Image library. + + + + + + + runtimes/linux-arm/native/ + true + PreserveNewest + + + runtimes/linux-arm64/native/ + true + PreserveNewest/ + + + runtimes/linux-x64/native/ + true + PreserveNewest + + + runtimes/linux-x86/native/ + true + PreserveNewest + + + runtimes/win-x64/native/ + true + PreserveNewest + + + runtimes/win-x86/native/ + true + PreserveNewest + + + + diff --git a/Quik.StbImage.sln b/Quik.StbImage.sln new file mode 100644 index 0000000..6b44dac --- /dev/null +++ b/Quik.StbImage.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Quik.StbImage", "Quik.StbImage.csproj", "{C808B4BC-C3AF-4682-8EDA-EAAC780800C3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C808B4BC-C3AF-4682-8EDA-EAAC780800C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C808B4BC-C3AF-4682-8EDA-EAAC780800C3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C808B4BC-C3AF-4682-8EDA-EAAC780800C3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C808B4BC-C3AF-4682-8EDA-EAAC780800C3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B04E5FBA-41E6-4B0B-BC31-F996BE353F5A} + EndGlobalSection +EndGlobal diff --git a/StbImage.cs b/StbImage.cs new file mode 100644 index 0000000..e2af68f --- /dev/null +++ b/StbImage.cs @@ -0,0 +1,144 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace Quik.Stb +{ + /// + /// A class that encompasses all features of stb_image.h in a safe way. + /// + public unsafe class StbImage : IDisposable + { + private bool isDisposed = false; + + /// + /// Pointer to the image. + /// + public IntPtr ImagePointer { get; } + + /// + /// Width of the image. + /// + public int Width { get; } + + /// + /// Height of the image. + /// + /// + public int Height { get; } + + /// + /// Internal image format. + /// + public StbiImageFormat Format { get; } + public bool IsFloat { get; } + + private StbImage(IntPtr image, int x, int y, StbiImageFormat format, bool isFloat) + { + ImagePointer = image; + Width = x; + Height = y; + Format = format; + IsFloat = isFloat; + } + + ~StbImage() + { + Dispose(false); + } + + public void Dispose() => Dispose(true); + + private void Dispose(bool disposing) + { + if (isDisposed) return; + + if (disposing) + { + GC.SuppressFinalize(this); + } + + Stbi.image_free(ImagePointer.ToPointer()); + isDisposed = true; + } + + /// + /// Set to flip the y-axis of loaded images on load. + /// + public static bool FlipVerticallyOnLoad { set => Stbi.set_flip_vertically_on_load(1); } + + /// + /// Set to unpremultiply images on load. + /// + /// + /// According to the stb_image documentation, only iPhone PNG images + /// can come with premultiplied alpha. + /// + public static bool UnpremultiplyOnLoad { set => Stbi.set_unpremultiply_on_load(1); } + + /// + /// Try loading an image, without raising exceptions. + /// + /// The resulting image. + /// Source stream. + /// The desired image format. + /// True on success. + public static bool TryLoad(out StbImage image, Stream stream, StbiImageFormat format = StbiImageFormat.Default, bool isFloat = false) + { + int x, y, iFormat; + StbiStreamWrapper wrapper = new StbiStreamWrapper(stream, true); + wrapper.CreateCallbacks(out stbi_io_callbacks cb); + + stream.Position = 0; + IntPtr imagePtr; + if (isFloat) + { + imagePtr = (IntPtr)Stbi.loadf_from_callbacks(&cb, null, &x, &y, &iFormat, (int)format); + } + else + { + imagePtr = (IntPtr)Stbi.load_from_callbacks(&cb, null, &x, &y, &iFormat, (int)format); + } + + if (imagePtr != IntPtr.Zero) + { + image = new StbImage(imagePtr, x, y, (StbiImageFormat)iFormat, isFloat); + return true; + } + else + { + image = null; + return false; + } + } + + /// + /// Load an image. + /// + /// The stream to load from. + /// The desired image format. + /// The image object. + public static StbImage Load(Stream stream, StbiImageFormat format = StbiImageFormat.Default, bool isFloat = false) + { + if (TryLoad(out StbImage image, stream, format, isFloat)) + { + return image; + } + + string reason = Marshal.PtrToStringUTF8((IntPtr)Stbi.failure_reason()); + throw new Exception($"Failed to load image: {reason}"); + } + + public bool IsLoadable(Stream stream) + { + int x, y, iFormat; + StbiStreamWrapper wrapper = new StbiStreamWrapper(stream, true); + wrapper.CreateCallbacks(out stbi_io_callbacks cb); + + stream.Position = 0; + int result = Stbi.info_from_callbacks(&cb, null, &x, &y, &iFormat); + + return result != 0; + } + } +} \ No newline at end of file diff --git a/Stbi.Manual.cs b/Stbi.Manual.cs new file mode 100644 index 0000000..30e8254 --- /dev/null +++ b/Stbi.Manual.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Reflection; + +namespace Quik.Stb +{ + public unsafe static partial class Stbi + { + private delegate void FailedAssertProc(byte *expression, byte *file, int line, byte *function); + + private static readonly string[] LibraryNames = new string[] + { + //FIXME: This is wrong on so many levels, but, i need to do this + // in order to get a change of this running. + "runtimes/win-x64/native/libstbi.dll", + "runtimes/win-x86/native/libstbi.dll", + "runtimes/linux-arm/native/libstbi.so", + "runtimes/linux-arm64/native/libstbi.so", + "runtimes/linux-x64/native/libstbi.so", + "runtimes/native/libstbi.dylib", + "libstbi.dll", + "libstbi.so", + "libstbi.dylib", + }; + + static Stbi() + { + NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), Resolver); + + // quik_stbi_failed_assert_store(Marshal.GetFunctionPointerForDelegate(FailedAssert)); + } + + private static IntPtr Resolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) + { + if (libraryName != "stbi") + return IntPtr.Zero; + + foreach (string name in LibraryNames) + { + if (NativeLibrary.TryLoad(name, assembly, searchPath, out IntPtr handle)) + { + return handle; + } + } + + return NativeLibrary.Load(libraryName); + } + + private static void FailedAssert(byte *expression, byte *file, int line, byte *function) + { + string expr = expression == null ? string.Empty : Marshal.PtrToStringUTF8((IntPtr)expression); + string f = file == null ? string.Empty : Marshal.PtrToStringUTF8((IntPtr)file); + string func = function == null ? string.Empty : Marshal.PtrToStringUTF8((IntPtr)function); + + Exception ex = new Exception("Assert failed in native stbi code."); + ex.Data.Add("Expression", expr); + ex.Data.Add("File", f); + ex.Data.Add("Line", line); + ex.Data.Add("Function", func); + throw ex; + } + } +} \ No newline at end of file diff --git a/Stbi.cs b/Stbi.cs new file mode 100644 index 0000000..0a9510c --- /dev/null +++ b/Stbi.cs @@ -0,0 +1,174 @@ +using System; +using System.Runtime.InteropServices; +using Quik.Stb.Image; + +namespace Quik.Stb +{ + [NativeTypeName("unsigned int")] + public enum StbiEnum : uint + { + STBI_default = 0, + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4, + } + + public partial struct stbi_io_callbacks + { + [NativeTypeName("int (*)(void *, char *, int)")] + public IntPtr read; + + [NativeTypeName("void (*)(void *, int)")] + public IntPtr skip; + + [NativeTypeName("int (*)(void *)")] + public IntPtr eof; + } + + public static unsafe partial class Stbi + { + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_memory", ExactSpelling = true)] + [return: NativeTypeName("stbi_uc *")] + public static extern byte* load_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_callbacks", ExactSpelling = true)] + [return: NativeTypeName("stbi_uc *")] + public static extern byte* load_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load", ExactSpelling = true)] + [return: NativeTypeName("stbi_uc *")] + public static extern byte* load([NativeTypeName("const char *")] sbyte* filename, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_file", ExactSpelling = true)] + [return: NativeTypeName("stbi_uc *")] + public static extern byte* load_from_file([NativeTypeName("FILE *")] void* f, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_gif_from_memory", ExactSpelling = true)] + [return: NativeTypeName("stbi_uc *")] + public static extern byte* load_gif_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len, int** delays, int* x, int* y, int* z, int* comp, int req_comp); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_16_from_memory", ExactSpelling = true)] + [return: NativeTypeName("stbi_us *")] + public static extern ushort* load_16_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_16_from_callbacks", ExactSpelling = true)] + [return: NativeTypeName("stbi_us *")] + public static extern ushort* load_16_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_16", ExactSpelling = true)] + [return: NativeTypeName("stbi_us *")] + public static extern ushort* load_16([NativeTypeName("const char *")] sbyte* filename, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_file_16", ExactSpelling = true)] + [return: NativeTypeName("stbi_us *")] + public static extern ushort* load_from_file_16([NativeTypeName("FILE *")] void* f, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_loadf_from_memory", ExactSpelling = true)] + public static extern float* loadf_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_loadf_from_callbacks", ExactSpelling = true)] + public static extern float* loadf_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_loadf", ExactSpelling = true)] + public static extern float* loadf([NativeTypeName("const char *")] sbyte* filename, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_loadf_from_file", ExactSpelling = true)] + public static extern float* loadf_from_file([NativeTypeName("FILE *")] void* f, int* x, int* y, int* channels_in_file, int desired_channels); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_hdr_to_ldr_gamma", ExactSpelling = true)] + public static extern void hdr_to_ldr_gamma(float gamma); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_hdr_to_ldr_scale", ExactSpelling = true)] + public static extern void hdr_to_ldr_scale(float scale); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_ldr_to_hdr_gamma", ExactSpelling = true)] + public static extern void ldr_to_hdr_gamma(float gamma); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_ldr_to_hdr_scale", ExactSpelling = true)] + public static extern void ldr_to_hdr_scale(float scale); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_hdr_from_callbacks", ExactSpelling = true)] + public static extern int is_hdr_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_hdr_from_memory", ExactSpelling = true)] + public static extern int is_hdr_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_hdr", ExactSpelling = true)] + public static extern int is_hdr([NativeTypeName("const char *")] sbyte* filename); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_hdr_from_file", ExactSpelling = true)] + public static extern int is_hdr_from_file([NativeTypeName("FILE *")] void* f); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_failure_reason", ExactSpelling = true)] + [return: NativeTypeName("const char *")] + public static extern sbyte* failure_reason(); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_image_free", ExactSpelling = true)] + public static extern void image_free(void* retval_from_stbi_load); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_info_from_memory", ExactSpelling = true)] + public static extern int info_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len, int* x, int* y, int* comp); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_info_from_callbacks", ExactSpelling = true)] + public static extern int info_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user, int* x, int* y, int* comp); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_16_bit_from_memory", ExactSpelling = true)] + public static extern int is_16_bit_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_16_bit_from_callbacks", ExactSpelling = true)] + public static extern int is_16_bit_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_info", ExactSpelling = true)] + public static extern int info([NativeTypeName("const char *")] sbyte* filename, int* x, int* y, int* comp); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_info_from_file", ExactSpelling = true)] + public static extern int info_from_file([NativeTypeName("FILE *")] void* f, int* x, int* y, int* comp); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_16_bit", ExactSpelling = true)] + public static extern int is_16_bit([NativeTypeName("const char *")] sbyte* filename); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_16_bit_from_file", ExactSpelling = true)] + public static extern int is_16_bit_from_file([NativeTypeName("FILE *")] void* f); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_set_unpremultiply_on_load", ExactSpelling = true)] + public static extern void set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_convert_iphone_png_to_rgb", ExactSpelling = true)] + public static extern void convert_iphone_png_to_rgb(int flag_true_if_should_convert); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_set_flip_vertically_on_load", ExactSpelling = true)] + public static extern void set_flip_vertically_on_load(int flag_true_if_should_flip); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_set_unpremultiply_on_load_thread", ExactSpelling = true)] + public static extern void set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_convert_iphone_png_to_rgb_thread", ExactSpelling = true)] + public static extern void convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_set_flip_vertically_on_load_thread", ExactSpelling = true)] + public static extern void set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_malloc_guesssize", ExactSpelling = true)] + [return: NativeTypeName("char *")] + public static extern sbyte* zlib_decode_malloc_guesssize([NativeTypeName("const char *")] sbyte* buffer, int len, int initial_size, int* outlen); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_malloc_guesssize_headerflag", ExactSpelling = true)] + [return: NativeTypeName("char *")] + public static extern sbyte* zlib_decode_malloc_guesssize_headerflag([NativeTypeName("const char *")] sbyte* buffer, int len, int initial_size, int* outlen, int parse_header); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_malloc", ExactSpelling = true)] + [return: NativeTypeName("char *")] + public static extern sbyte* zlib_decode_malloc([NativeTypeName("const char *")] sbyte* buffer, int len, int* outlen); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_buffer", ExactSpelling = true)] + public static extern int zlib_decode_buffer([NativeTypeName("char *")] sbyte* obuffer, int olen, [NativeTypeName("const char *")] sbyte* ibuffer, int ilen); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_noheader_malloc", ExactSpelling = true)] + [return: NativeTypeName("char *")] + public static extern sbyte* zlib_decode_noheader_malloc([NativeTypeName("const char *")] sbyte* buffer, int len, int* outlen); + + [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_noheader_buffer", ExactSpelling = true)] + public static extern int zlib_decode_noheader_buffer([NativeTypeName("char *")] sbyte* obuffer, int olen, [NativeTypeName("const char *")] sbyte* ibuffer, int ilen); + } +} diff --git a/StbiImageFormat.cs b/StbiImageFormat.cs new file mode 100644 index 0000000..a4c0c61 --- /dev/null +++ b/StbiImageFormat.cs @@ -0,0 +1,11 @@ +namespace Quik.Stb +{ + public enum StbiImageFormat + { + Default = (int)StbiEnum.STBI_default, + Grey = (int)StbiEnum.STBI_grey, + GreyAlpha = (int)StbiEnum.STBI_grey_alpha, + Rgb = (int)StbiEnum.STBI_rgb, + Rgba = (int)StbiEnum.STBI_rgb_alpha + } +} \ No newline at end of file diff --git a/StbiStreamWrapper.cs b/StbiStreamWrapper.cs new file mode 100644 index 0000000..4038c48 --- /dev/null +++ b/StbiStreamWrapper.cs @@ -0,0 +1,60 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace Quik.Stb +{ + public unsafe class StbiStreamWrapper : IDisposable + { + private Stream _stream; + private bool _keepOpen; + private bool _isDisposed; + + private delegate int ReadProc(void *userdata, byte* buffer, int count); + private delegate void SkipProc(void *userdata, int count); + private delegate int Eof(void *userdata); + + public StbiStreamWrapper(Stream stream, bool keepOpen = false) + { + if (stream == null) throw new ArgumentNullException(nameof(stream)); + + _stream = stream; + _keepOpen = keepOpen; + } + + public void CreateCallbacks(out stbi_io_callbacks cb) + { + cb = default; + cb.read = Marshal.GetFunctionPointerForDelegate(ReadCb); + cb.skip = Marshal.GetFunctionPointerForDelegate(SkipCb); + cb.eof = Marshal.GetFunctionPointerForDelegate(EofCb); + } + + private int ReadCb(void *userdata, byte* buffer, int count) + { + Span bytes = new Span(buffer, count); + return _stream.Read(bytes); + } + + private void SkipCb(void *userdata, int count) + { + _stream.Seek(count, SeekOrigin.Current); + } + + private int EofCb(void *userdata) + { + if (!_stream.CanRead || _stream.Position == _stream.Length) + return 1; + return 0; + } + + public void Dispose() + { + if (_isDisposed) return; + + if (!_keepOpen) _stream.Dispose(); + + _isDisposed = true; + } + } +} \ No newline at end of file diff --git a/build_ci_cd.sh b/build_ci_cd.sh new file mode 100644 index 0000000..d76789c --- /dev/null +++ b/build_ci_cd.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +cd $(dirname "$0") +if [ -z "$QUIK_API_KEY" ] +then + echo "Please define QUIK_API_KEY" + exit 1 +fi + +pwd +docker-compose run build && docker-compose run publish diff --git a/build_native.sh b/build_native.sh new file mode 100755 index 0000000..eb77add --- /dev/null +++ b/build_native.sh @@ -0,0 +1,4 @@ +#!/bin/bash +cd $(dirname "$0") +./Quik.Common/sh/quik_build_native.sh . +dotnet build diff --git a/clangsharp.rsp b/clangsharp.rsp new file mode 100644 index 0000000..d0ebfed --- /dev/null +++ b/clangsharp.rsp @@ -0,0 +1,30 @@ +-x + c +-l + stbi +--config + compatible-codegen + single-file + exclude-fnptr-codegen + generate-aggressive-inlining + generate-setslastsystemerror-attribute + unix-types +--include-directory + ../lib +--include-directory + ../Quik.StbImage +--include-directory + /usr/lib/llvm-14/lib/clang/14.0.6/include +--file + ../Quik.StbImage.redist/quik_stbi.h + ../lib/stb/stb_image.h +--methodClassName + Stbi +--namespace + Quik.Stb +--output + Stbi.cs +--prefixStrip + stbi_ +--with-type + FILE=void diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..c73e8d6 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,16 @@ +version: "2" + +services: + build: + image: git.mixedup.dev/quik/docker-cross-compiler + command: "/home/quik/src/build_native.sh" + volumes: + - .:/home/quik/src + publish: + image: git.mixedup.dev/quik/docker-cross-compiler + command: "/home/quik/src/publish.sh" + environment: + QUIK_API_KEY: ${QUIK_API_KEY} + volumes: + - .:/home/quik/src + \ No newline at end of file diff --git a/publish.sh b/publish.sh new file mode 100755 index 0000000..01762a4 --- /dev/null +++ b/publish.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +cd $(dirname "$0") +if [ -z "$QUIK_API_KEY" ] +then + echo "Please define QUIK_API_KEY" + exit 1 +fi + +dotnet nuget add source \ + -n QUIK -u themixedupstuff -p "$QUIK_API_KEY" \ + --store-password-in-clear-text \ + https://git.mixedup.dev/api/packages/QUIK/nuget/index.json +dotnet nuget push -s QUIK bin/*/*.nupkg diff --git a/quik_stbi.c b/quik_stbi.c new file mode 100644 index 0000000..312c61b --- /dev/null +++ b/quik_stbi.c @@ -0,0 +1,4 @@ +#include "quik_stbi.h" + +#define STB_IMAGE_IMPLEMENTATION 1 +#include "stb/stb_image.h" diff --git a/quik_stbi.h b/quik_stbi.h new file mode 100644 index 0000000..cd2b84b --- /dev/null +++ b/quik_stbi.h @@ -0,0 +1,10 @@ +#ifndef _QUIK_STBI_H_ +#define _QUIK_STBI_H_ + +#include "Quik.Common/include/quik_common.h" + +#define STBIDEF QEXTERN + +#include "stb/stb_image.h" + +#endif