diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 6d783bae..dd794f9d 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -19,9 +19,9 @@ jobs: os: [ ubuntu-latest, windows-latest ] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: | ${{ matrix.java }} @@ -35,15 +35,15 @@ jobs: with: arguments: build --no-daemon -x :samples:test - name: Upload build reports - if: failure() - uses: actions/upload-artifact@v3 + if: ${{ runner.os == 'Linux' && matrix.java == '22-ea' && failure() }} + uses: actions/upload-artifact@v4 with: name: build-reports path: | modules/**/build/reports/ - name: Capture build artifacts if: ${{ runner.os == 'Linux' && matrix.java == '22-ea' }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Artifacts path: | diff --git a/README.md b/README.md index ecb3a747..e254196c 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots" } | stb_image_resize | Resize images larger/smaller with good quality. | | stb_image_write | Image writing to disk: PNG, TGA, BMP | | stb_perlin | Revised Perlin noise (3D input, 1D output). | +| stb_rect_pack | Simple 2D rectangle packer with decent quality. | | stb_truetype | Parse, decode, and rasterize characters from truetype fonts. | | stb_vorbis | Decode ogg vorbis files from file/memory to float/16-bit signed output. | diff --git a/build.gradle.kts b/build.gradle.kts index 524e6eec..2261cef7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ plugins { `java-platform` `maven-publish` signing - id("me.champeau.jmh") version "0.7.1" apply false + id("me.champeau.jmh") version "0.7.2" apply false embeddedKotlin("jvm") apply false } @@ -34,10 +34,6 @@ val overrunMarshalVersion: String by rootProject group = projGroupId version = projVersion -project(":core").ext["subName"] = "" -Artifact.values().forEach { project(it.subprojectName).ext["subName"] = "-${it.subprojectName.substring(1)}" } -project(":samples").ext["subName"] = "-samples" - enum class NativePlatform( val osFamilyName: String, val osArch: String, @@ -82,7 +78,8 @@ enum class Artifact( val projectDescription: String, val subprojectName: String, val mavenName: String, - val nativeBinding: NativeBinding? = null + val nativeBinding: NativeBinding? = null, + val nativeCIVersion: String? = null ) { CORE( "overrungl", "OverrunGL", @@ -112,7 +109,7 @@ enum class Artifact( STB( "overrungl-stb", "OverrunGL - stb bindings", "Single-file public domain libraries for fonts, images, ogg vorbis files and more.", - ":stb", "Stb", NativeBinding.STB + ":stb", "Stb", NativeBinding.STB, nativeCIVersion = "0.1.0-alpha.6" ), //VULKAN("overrungl-vulkan", "OverrunGL - Vulkan bindings", // "A new generation graphics and compute API that provides high-efficiency, cross-platform access to modern GPUs used in a wide variety of devices from PCs and consoles to mobile phones and embedded platforms.", @@ -125,95 +122,104 @@ enum class Artifact( } } -subprojects { - apply(plugin = "org.jetbrains.kotlin.jvm") - apply(plugin = "java-library") - apply(plugin = "idea") - apply(plugin = "me.champeau.jmh") - - group = projGroupId - version = projVersion - val artifactName = "$projArtifactId${ext["subName"]}" - - repositories { - mavenCentral() - // temporary maven repositories - maven { url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots") } - maven { url = uri("https://s01.oss.sonatype.org/content/repositories/releases") } - maven { url = uri("https://maven.aliyun.com/repository/central") } - } +Artifact.values().forEach { project(it.subprojectName).ext["subName"] = "-${it.subprojectName.substring(1)}" } +project(Artifact.CORE.subprojectName).ext["subName"] = "" +project(":samples").ext["subName"] = "-samples" - val annotationProcessor by configurations - val api by configurations - val compileOnly by configurations - val implementation by configurations - dependencies { - compileOnly("org.jetbrains:annotations:24.1.0") - api("io.github.over-run:marshal:$overrunMarshalVersion") - if (project.name != "core") { - implementation(project(":core")) +buildList { + addAll(Artifact.values().map { it.subprojectName }) + add(":samples") +}.forEach { + project(it) { + apply(plugin = "org.jetbrains.kotlin.jvm") + apply(plugin = "java-library") + apply(plugin = "idea") + apply(plugin = "me.champeau.jmh") + + group = projGroupId + version = projVersion + val artifactName = "$projArtifactId${ext["subName"]}" + + repositories { + mavenCentral() + // temporary maven repositories + maven { url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots") } + maven { url = uri("https://s01.oss.sonatype.org/content/repositories/releases") } + maven { url = uri("https://maven.aliyun.com/repository/central") } } - } - tasks.withType { - options.encoding = "UTF-8" - if (jdkEnablePreview.toBoolean()) options.compilerArgs.add("--enable-preview") - options.release.set(targetJavaVersion) - } + val annotationProcessor by configurations + val api by configurations + val compileOnly by configurations + val implementation by configurations + dependencies { + compileOnly("org.jetbrains:annotations:24.1.0") + api("io.github.over-run:marshal:$overrunMarshalVersion") + if (project.name != "core") { + implementation(project(Artifact.CORE.subprojectName)) + } + } - tasks.withType { - kotlinOptions { jvmTarget = kotlinTargetJdkVersion } - } + tasks.withType { + options.encoding = "UTF-8" + if (jdkEnablePreview.toBoolean()) options.compilerArgs.add("--enable-preview") + options.release.set(targetJavaVersion) + } - tasks.withType { - if (jdkEnablePreview.toBoolean()) jvmArgs("--enable-preview") - } + tasks.withType { + kotlinOptions { jvmTarget = kotlinTargetJdkVersion } + } - extensions.configure("java") { - val javaVersion = JavaVersion.toVersion(targetJavaVersion) - if (JavaVersion.current() < javaVersion) { - toolchain.languageVersion.set(JavaLanguageVersion.of(targetJavaVersion)) + tasks.withType { + if (jdkEnablePreview.toBoolean()) jvmArgs("--enable-preview") } - withJavadocJar() - withSourcesJar() - } - tasks.named("jar") { - manifestContentCharset = "utf-8" - metadataCharset = "utf-8" - manifest.attributes( - "Specification-Title" to projName, - "Specification-Vendor" to "Overrun Organization", - "Specification-Version" to projVersion.split('.', limit = 2)[0], - "Implementation-Title" to projName, - "Implementation-Vendor" to "Overrun Organization", - "Implementation-Version" to projVersion - ) - archiveBaseName.set(artifactName) - from("LICENSE") - } + extensions.configure("java") { + val javaVersion = JavaVersion.toVersion(targetJavaVersion) + if (JavaVersion.current() < javaVersion) { + toolchain.languageVersion.set(JavaLanguageVersion.of(targetJavaVersion)) + } + withJavadocJar() + withSourcesJar() + } - tasks.named("sourcesJar") { - dependsOn(tasks["classes"]) - archiveBaseName.set(artifactName) - archiveClassifier.set("sources") - from(sourceSets["main"].allSource, "LICENSE") - } + tasks.named("jar") { + manifestContentCharset = "utf-8" + metadataCharset = "utf-8" + manifest.attributes( + "Specification-Title" to projName, + "Specification-Vendor" to "Overrun Organization", + "Specification-Version" to projVersion.split('.', limit = 2)[0], + "Implementation-Title" to projName, + "Implementation-Vendor" to "Overrun Organization", + "Implementation-Version" to projVersion + ) + archiveBaseName.set(artifactName) + from("LICENSE") + } - tasks.named("javadocJar") { - val javadoc by tasks - dependsOn(javadoc) - archiveBaseName.set(artifactName) - archiveClassifier.set("javadoc") - from(javadoc, "LICENSE") - } + tasks.named("sourcesJar") { + dependsOn(tasks["classes"]) + archiveBaseName.set(artifactName) + archiveClassifier.set("sources") + from(sourceSets["main"].allSource, "LICENSE") + } - artifacts { - archives(tasks["sourcesJar"]) - archives(tasks["javadocJar"]) - } + tasks.named("javadocJar") { + val javadoc by tasks + dependsOn(javadoc) + archiveBaseName.set(artifactName) + archiveClassifier.set("javadoc") + from(javadoc, "LICENSE") + } - the().module.inheritOutputDirs = true + artifacts { + archives(tasks["sourcesJar"]) + archives(tasks["javadocJar"]) + } + + the().module.inheritOutputDirs = true + } } tasks.register("assembleJavadocArgs") { diff --git a/gradle.properties b/gradle.properties index a975d463..ecfbe7ee 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,6 +18,7 @@ jdkEnablePreview=true jdkEarlyAccessDoc=jdk22 kotlinTargetJdkVersion=21 -projModules=core, glfw, nfd, joml, opengl, stb -overrunMarshalVersion=0.1.0-alpha.8-jdk22 +overrunMarshalVersion=0.1.0-alpha.9-jdk22 overrunPlatformVersion=1.0.0 + +cLibraryVersion=0.1.0.0 diff --git a/modules/overrungl.core/src/main/java/overrungl/OverrunGL.java b/modules/overrungl.core/src/main/java/overrungl/OverrunGL.java index 39ecc264..2f8ec868 100644 --- a/modules/overrungl.core/src/main/java/overrungl/OverrunGL.java +++ b/modules/overrungl.core/src/main/java/overrungl/OverrunGL.java @@ -41,7 +41,7 @@ public final class OverrunGL { /** * The version of STB native libraries. */ - public static final String STB_VERSION = "0.1.0.1"; + public static final String STB_VERSION = "0.1.0.2"; private static final Consumer DEFAULT_LOGGER = System.err::println; private static Consumer apiLogger = DEFAULT_LOGGER; diff --git a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFD.java b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFD.java index 06055881..e935fa06 100644 --- a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFD.java +++ b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFD.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023 Overrun Organization + * Copyright (c) 2023-2024 Overrun Organization * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -16,22 +16,23 @@ package overrungl.nfd; -import io.github.overrun.platform.Platform; -import overrungl.Configurations; -import overrungl.FunctionDescriptors; +import overrun.marshal.Downcall; +import overrun.marshal.Marshal; +import overrun.marshal.MemoryStack; +import overrun.marshal.Unmarshal; +import overrun.marshal.gen.Entrypoint; +import overrun.marshal.gen.SizedSeg; +import overrun.marshal.gen.Skip; import overrungl.NativeType; -import overrungl.OverrunGL; -import overrungl.internal.RuntimeHelper; -import overrungl.util.MemoryStack; import overrungl.util.value.Tuple2; -import java.lang.foreign.*; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; -import java.nio.charset.StandardCharsets; -import java.util.function.Supplier; +import java.util.Map; import static java.lang.foreign.ValueLayout.*; -import static overrungl.FunctionDescriptors.*; /** *

Native File Dialog Extended

@@ -58,22 +59,23 @@ * {@snippet lang = java: * import overrungl.util.value.Pair; * void main() { - * NFD.init(); + * var nfd = NFD.INSTANCE; + * nfd.init(); * * try (MemoryStack stack = MemoryStack.stackPush()) { * String[] outPath = new String[1]; * var filterItem = NFDNFilterItem.create(stack, * new Pair<>("Source code", "java"), * new Pair<>("Image file", "png,jpg")); - * var result = NFD.openDialogN(outPath, filterItem, null); + * var result = nfd.openDialogN(outPath, filterItem, null); * switch (result) { - * case ERROR -> System.err.println(STR."Error: \{NFD.getError()}"); + * case ERROR -> System.err.println(STR."Error: \{nfd.getError()}"); * case OKAY -> System.out.println(STR."Success! \{outPath[0]}"); * case CANCEL -> System.out.println("User pressed cancel."); * } * } * - * NFD.quit(); + * nfd.quit(); * }} * *

File Filter Syntax

@@ -121,87 +123,85 @@ * @author squid233 * @since 0.1.0 */ -public final class NFD { - private static final SymbolLookup LOOKUP; - - static { - final Supplier lib = () -> RuntimeHelper.load("nfd", "nfd", OverrunGL.NFD_VERSION); - final var function = Configurations.NFD_SYMBOL_LOOKUP.get(); - LOOKUP = function != null ? function.apply(lib) : lib.get(); - } - - private static final Platform os = Platform.current(); - private static final boolean isOsWin = os instanceof Platform.Windows; - private static final boolean isOsWinOrApple = isOsWin || os instanceof Platform.MacOS; +public interface NFD { /** * The type of the path-set size ({@code long} for Windows and Mac OS X, {@code int} for others). */ - public static final ValueLayout PATH_SET_SIZE; + ValueLayout PATH_SET_SIZE = NFDInternal.isOsWinOrApple ? JAVA_LONG : JAVA_INT; + /** + * The instance of NFD. + */ + NFD INSTANCE = Downcall.load(NFDInternal.LOOKUP, Map.of( + "NFD_PathSet_GetPathN", FunctionDescriptor.of(JAVA_INT, ADDRESS, PATH_SET_SIZE, ADDRESS), + "NFD_PathSet_FreePathN", FunctionDescriptor.ofVoid(ADDRESS), + "NFD_FreePathU8", FunctionDescriptor.ofVoid(ADDRESS), + "NFD_OpenDialogU8", FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, ADDRESS), + "NFD_OpenDialogMultipleU8", FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, ADDRESS), + "NFD_SaveDialogU8", FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS), + "NFD_PickFolderU8", FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS), + "NFD_PathSet_GetPathU8", FunctionDescriptor.of(JAVA_INT, ADDRESS, PATH_SET_SIZE, ADDRESS), + "NFD_PathSet_EnumNextU8", FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS) + )); - static { - PATH_SET_SIZE = isOsWinOrApple ? JAVA_LONG : JAVA_INT; - } + /** + * {@return NFD_PathSet_GetPathN} + */ + MethodHandle NFD_PathSet_GetPathN(); - private static final MethodHandle - NFD_FreePathN = downcall("NFD_FreePathN", PV), - NFD_Init = downcall("NFD_Init", I), - NFD_Quit = downcall("NFD_Quit", V), - NFD_OpenDialogN = downcall("NFD_OpenDialogN", PPIPI), - NFD_OpenDialogMultipleN = downcall("NFD_OpenDialogMultipleN", PPIPI), - NFD_SaveDialogN = downcall("NFD_SaveDialogN", PPIPPI), - NFD_PickFolderN = downcall("NFD_PickFolderN", PPI), - NFD_GetError = downcall("NFD_GetError", p), - NFD_ClearError = downcall("NFD_ClearError", V), - NFD_PathSet_GetCount = downcall("NFD_PathSet_GetCount", PPI), - NFD_PathSet_GetPathN = downcall("NFD_PathSet_GetPathN", FunctionDescriptor.of(JAVA_INT, ADDRESS, PATH_SET_SIZE, ADDRESS)), - NFD_PathSet_FreePathN = downcallSafe("NFD_PathSet_FreePathN", PV), - NFD_PathSet_GetEnum = downcall("NFD_PathSet_GetEnum", PPI), - NFD_PathSet_FreeEnum = downcall("NFD_PathSet_FreeEnum", PV), - NFD_PathSet_EnumNextN = downcall("NFD_PathSet_EnumNextN", PPI), - NFD_PathSet_Free = downcall("NFD_PathSet_Free", PV), - NFD_FreePathU8 = downcallSafe("NFD_FreePathU8", PV), - NFD_OpenDialogU8 = downcallSafe("NFD_OpenDialogU8", PPIPI), - NFD_OpenDialogMultipleU8 = downcallSafe("NFD_OpenDialogMultipleU8", PPIPI), - NFD_SaveDialogU8 = downcallSafe("NFD_SaveDialogU8", PPIPPI), - NFD_PickFolderU8 = downcallSafe("NFD_PickFolderU8", PPI), - NFD_PathSet_GetPathU8 = downcallSafe("NFD_PathSet_GetPathU8", FunctionDescriptor.of(JAVA_INT, ADDRESS, PATH_SET_SIZE, ADDRESS)), - NFD_PathSet_EnumNextU8 = downcallSafe("NFD_PathSet_EnumNextU8", PPI); + /** + * {@return NFD_PathSet_FreePathN} + */ + default MethodHandle NFD_PathSet_FreePathN() { + return null; + } - private NFD() { - //no instance + /** + * {@return NFD_FreePathU8} + */ + default MethodHandle NFD_FreePathU8() { + return null; } - private static MethodHandle downcall(String name, FunctionDescriptors function, Linker.Option... options) { - return RuntimeHelper.downcallThrow(LOOKUP.find(name), function, options); + /** + * {@return NFD_OpenDialogU8} + */ + default MethodHandle NFD_OpenDialogU8() { + return null; } - private static MethodHandle downcall(String name, FunctionDescriptor function) { - return RuntimeHelper.downcallThrow(LOOKUP.find(name), function); + /** + * {@return NFD_OpenDialogMultipleU8} + */ + default MethodHandle NFD_OpenDialogMultipleU8() { + return null; } - private static MethodHandle downcallSafe(String name, FunctionDescriptors function, Linker.Option... options) { - return RuntimeHelper.downcallSafe(LOOKUP.find(name).orElse(MemorySegment.NULL), function, options); + /** + * {@return NFD_SaveDialogU8} + */ + default MethodHandle NFD_SaveDialogU8() { + return null; } - private static MethodHandle downcallSafe(String name, FunctionDescriptor function) { - return RuntimeHelper.downcallSafe(LOOKUP.find(name).orElse(MemorySegment.NULL), function); + /** + * {@return NFD_PickFolderU8} + */ + default MethodHandle NFD_PickFolderU8() { + return null; } - static MemorySegment allocateString(String str) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - if (isOsWin) return stack.allocateFrom(str, StandardCharsets.UTF_16LE); - return stack.allocateFrom(str); - } finally { - stack.setPointer(stackPointer); - } + /** + * {@return NFD_PathSet_GetPathU8} + */ + default MethodHandle NFD_PathSet_GetPathU8() { + return null; } - static String getString(MemorySegment segment, long offset) { - final MemorySegment segment1 = segment.byteSize() == 0 ? segment.reinterpret(Long.MAX_VALUE) : segment; - if (isOsWin) return segment1.getString(offset, StandardCharsets.UTF_16LE); - return segment1.getString(offset); + /** + * {@return NFD_PathSet_EnumNextU8} + */ + default MethodHandle NFD_PathSet_EnumNextU8() { + return null; } /** @@ -211,13 +211,8 @@ static String getString(MemorySegment segment, long offset) { * * @param filePath the file path */ - public static void freePathN(@NativeType("nfdnchar_t*") MemorySegment filePath) { - try { - NFD_FreePathN.invokeExact(filePath); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_FreePathN") + void freePathN(@NativeType("nfdnchar_t*") MemorySegment filePath); /** * initialize NFD - call this for every thread that might use NFD, before calling any other NFD @@ -225,24 +220,14 @@ public static void freePathN(@NativeType("nfdnchar_t*") MemorySegment filePath) * * @return the result */ - public static NFDResult init() { - try { - return NFDResult.of((int) NFD_Init.invokeExact()); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_Init") + NFDResult init(); /** * call this to de-initialize NFD, if {@link #init} returned {@link NFDResult#OKAY} */ - public static void quit() { - try { - NFD_Quit.invokeExact(); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_Quit") + void quit(); /** * single file open dialog @@ -254,13 +239,9 @@ public static void quit() { * @param defaultPath If defaultPath is NULL, the operating system will decide * @return the result */ - public static NFDResult nopenDialogN(@NativeType("nfdnchar_t**") MemorySegment outPath, @NativeType("const nfdnfilteritem_t*") MemorySegment filterList, int filterCount, @NativeType("const nfdnchar_t*") MemorySegment defaultPath) { - try { - return NFDResult.of((int) NFD_OpenDialogN.invokeExact(outPath, filterList, filterCount, defaultPath)); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_OpenDialogN") + NFDResult nopenDialogN(@NativeType("nfdnchar_t**") MemorySegment outPath, NFDNFilterItem filterList, int filterCount, @NativeType("const nfdnchar_t*") MemorySegment defaultPath); + /** * single file open dialog @@ -269,25 +250,22 @@ public static NFDResult nopenDialogN(@NativeType("nfdnchar_t**") MemorySegment o * @param filterList the filter list * @param defaultPath If defaultPath is NULL, the operating system will decide * @return the result - * @see #nopenDialogN(MemorySegment, MemorySegment, int, MemorySegment) nopenDialogN + * @see #nopenDialogN(MemorySegment, NFDNFilterItem, int, MemorySegment) nopenDialogN */ - public static NFDResult openDialogN(String[] outPath, NFDNFilterItem.Buffer filterList, String defaultPath) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.callocPointer(); + @Skip + default NFDResult openDialogN(String[] outPath, NFDNFilterItem filterList, String defaultPath) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = Marshal.marshal(stack, outPath); final NFDResult result = nopenDialogN(seg, - filterList != null ? filterList.address() : MemorySegment.NULL, + filterList, filterList != null ? Math.toIntExact(filterList.elementCount()) : 0, - defaultPath != null ? allocateString(defaultPath) : MemorySegment.NULL); + Marshal.marshal(stack, defaultPath, NFDInternal.nfdCharset)); if (result == NFDResult.OKAY) { - final MemorySegment path = seg.get(ADDRESS, 0); - outPath[0] = getString(path, 0); + final MemorySegment path = seg.get(Unmarshal.STR_LAYOUT, 0L); + outPath[0] = path.getString(0L, NFDInternal.nfdCharset); freePathN(path); } return result; - } finally { - stack.setPointer(stackPointer); } } @@ -301,13 +279,8 @@ public static NFDResult openDialogN(String[] outPath, NFDNFilterItem.Buffer filt * @param defaultPath If defaultPath is NULL, the operating system will decide * @return the result */ - public static NFDResult nopenDialogMultipleN(@NativeType("const nfdpathset_t**") MemorySegment outPaths, @NativeType("const nfdnfilteritem_t*") MemorySegment filterList, int filterCount, @NativeType("const nfdnchar_t*") MemorySegment defaultPath) { - try { - return NFDResult.of((int) NFD_OpenDialogMultipleN.invokeExact(outPaths, filterList, filterCount, defaultPath)); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_OpenDialogMultipleN") + NFDResult nopenDialogMultipleN(@NativeType("const nfdpathset_t**") MemorySegment outPaths, NFDNFilterItem filterList, int filterCount, @NativeType("const nfdnchar_t*") MemorySegment defaultPath); /** * multiple file open dialog @@ -317,13 +290,16 @@ public static NFDResult nopenDialogMultipleN(@NativeType("const nfdpathset_t**") * @param filterList the filter list * @param defaultPath If defaultPath is NULL, the operating system will decide * @return the result - * @see #nopenDialogMultipleN(MemorySegment, MemorySegment, int, MemorySegment) nopenDialogMultipleN + * @see #nopenDialogMultipleN(MemorySegment, NFDNFilterItem, int, MemorySegment) nopenDialogMultipleN */ - public static NFDResult openDialogMultipleN(@NativeType("const nfdpathset_t**") MemorySegment outPaths, NFDNFilterItem.Buffer filterList, String defaultPath) { - return nopenDialogMultipleN(outPaths, - filterList != null ? filterList.address() : MemorySegment.NULL, - filterList != null ? Math.toIntExact(filterList.elementCount()) : 0, - defaultPath != null ? allocateString(defaultPath) : MemorySegment.NULL); + @Skip + default NFDResult openDialogMultipleN(@NativeType("const nfdpathset_t**") MemorySegment outPaths, NFDNFilterItem filterList, String defaultPath) { + try (MemoryStack stack = MemoryStack.stackPush()) { + return nopenDialogMultipleN(outPaths, + filterList, + filterList != null ? Math.toIntExact(filterList.elementCount()) : 0, + Marshal.marshal(stack, defaultPath, NFDInternal.nfdCharset)); + } } /** @@ -337,13 +313,8 @@ public static NFDResult openDialogMultipleN(@NativeType("const nfdpathset_t**") * @param defaultName the default name of the file * @return the result */ - public static NFDResult nsaveDialogN(@NativeType("nfdnchar_t**") MemorySegment outPath, @NativeType("const nfdnfilteritem_t*") MemorySegment filterList, int filterCount, @NativeType("const nfdnchar_t*") MemorySegment defaultPath, @NativeType("const nfdnchar_t*") MemorySegment defaultName) { - try { - return NFDResult.of((int) NFD_SaveDialogN.invokeExact(outPath, filterList, filterCount, defaultPath, defaultName)); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_SaveDialogN") + NFDResult nsaveDialogN(@NativeType("nfdnchar_t**") MemorySegment outPath, NFDNFilterItem filterList, int filterCount, @NativeType("const nfdnchar_t*") MemorySegment defaultPath, @NativeType("const nfdnchar_t*") MemorySegment defaultName); /** * save dialog @@ -353,26 +324,23 @@ public static NFDResult nsaveDialogN(@NativeType("nfdnchar_t**") MemorySegment o * @param defaultPath If defaultPath is NULL, the operating system will decide * @param defaultName the default name of the file * @return the result - * @see #nopenDialogMultipleN(MemorySegment, MemorySegment, int, MemorySegment) nopenDialogMultipleN + * @see #nsaveDialogN(MemorySegment, NFDNFilterItem, int, MemorySegment, MemorySegment) nsaveDialogN */ - public static NFDResult saveDialogN(String[] outPath, NFDNFilterItem.Buffer filterList, String defaultPath, String defaultName) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.callocPointer(); + @Skip + default NFDResult saveDialogN(String[] outPath, NFDNFilterItem filterList, String defaultPath, String defaultName) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = Marshal.marshal(stack, outPath); final NFDResult result = nsaveDialogN(seg, - filterList != null ? filterList.address() : MemorySegment.NULL, + filterList, filterList != null ? Math.toIntExact(filterList.elementCount()) : 0, - defaultPath != null ? allocateString(defaultPath) : MemorySegment.NULL, - defaultName != null ? allocateString(defaultName) : MemorySegment.NULL); + Marshal.marshal(stack, defaultPath, NFDInternal.nfdCharset), + Marshal.marshal(stack, defaultName, NFDInternal.nfdCharset)); if (result == NFDResult.OKAY) { - final MemorySegment path = seg.get(ADDRESS, 0); - outPath[0] = getString(path, 0); + final MemorySegment path = seg.get(Unmarshal.STR_LAYOUT, 0L); + outPath[0] = path.getString(0L, NFDInternal.nfdCharset); freePathN(path); } return result; - } finally { - stack.setPointer(stackPointer); } } @@ -384,13 +352,8 @@ public static NFDResult saveDialogN(String[] outPath, NFDNFilterItem.Buffer filt * @param defaultPath If defaultPath is NULL, the operating system will decide * @return the result */ - public static NFDResult npickFolderN(@NativeType("nfdnchar_t**") MemorySegment outPath, @NativeType("const nfdnchar_t*") MemorySegment defaultPath) { - try { - return NFDResult.of((int) NFD_PickFolderN.invokeExact(outPath, defaultPath)); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_PickFolderN") + NFDResult npickFolderN(@NativeType("nfdnchar_t**") MemorySegment outPath, @NativeType("const nfdnchar_t*") MemorySegment defaultPath); /** * select folder dialog @@ -400,20 +363,17 @@ public static NFDResult npickFolderN(@NativeType("nfdnchar_t**") MemorySegment o * @return the result * @see #npickFolderN(MemorySegment, MemorySegment) npickFolderN */ - public static NFDResult pickFolderN(String[] outPath, String defaultPath) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.callocPointer(); - final NFDResult result = npickFolderN(seg, defaultPath != null ? allocateString(defaultPath) : MemorySegment.NULL); + @Skip + default NFDResult pickFolderN(String[] outPath, String defaultPath) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = Marshal.marshal(stack, outPath); + final NFDResult result = npickFolderN(seg, Marshal.marshal(stack, defaultPath, NFDInternal.nfdCharset)); if (result == NFDResult.OKAY) { - final MemorySegment path = seg.get(ADDRESS, 0); - outPath[0] = getString(path, 0); + final MemorySegment path = seg.get(Unmarshal.STR_LAYOUT, 0); + outPath[0] = path.getString(0, NFDInternal.nfdCharset); freePathN(path); } return result; - } finally { - stack.setPointer(stackPointer); } } @@ -426,13 +386,9 @@ public static NFDResult pickFolderN(String[] outPath, String defaultPath) { * * @return the last error that was set, or NULL if there is no error. */ - public static @NativeType("const char*") MemorySegment ngetError() { - try { - return (MemorySegment) NFD_GetError.invokeExact(); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_GetError") + @NativeType("const char*") + MemorySegment ngetError(); /** * Get last error -- set when {@link NFDResult} returns {@link NFDResult#ERROR} @@ -440,21 +396,15 @@ public static NFDResult pickFolderN(String[] outPath, String defaultPath) { * @return the last error that was set, or NULL if there is no error. * @see #ngetError() ngetError */ - public static String getError() { - final MemorySegment seg = ngetError(); - return RuntimeHelper.isNullptr(seg) ? null : seg.getString(0); - } + @Entrypoint("NFD_GetError") + @SizedSeg(Unmarshal.STR_SIZE) + String getError(); /** * clear the error */ - public static void clearError() { - try { - NFD_ClearError.invokeExact(); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_ClearError") + void clearError(); /** * Gets the number of entries stored in pathSet @@ -466,13 +416,8 @@ public static void clearError() { * @param count the count * @return the result */ - public static NFDResult npathSetGetCount(@NativeType("const nfdpathset_t*") MemorySegment pathSet, @NativeType("nfdpathsetsize_t*") MemorySegment count) { - try { - return NFDResult.of((int) NFD_PathSet_GetCount.invokeExact(pathSet, count)); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_PathSet_GetCount") + NFDResult npathSetGetCount(@NativeType("const nfdpathset_t*") MemorySegment pathSet, @NativeType("nfdpathsetsize_t*") MemorySegment count); /** * Gets the number of entries stored in pathSet @@ -482,11 +427,10 @@ public static NFDResult npathSetGetCount(@NativeType("const nfdpathset_t*") Memo * @return the result * @see #npathSetGetCount(MemorySegment, MemorySegment) npathSetGetCount */ - public static NFDResult pathSetGetCount(@NativeType("const nfdpathset_t*") MemorySegment pathSet, long[] count) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.calloc(PATH_SET_SIZE); + @Skip + default NFDResult pathSetGetCount(@NativeType("const nfdpathset_t*") MemorySegment pathSet, long[] count) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = stack.allocate(PATH_SET_SIZE); final NFDResult result = npathSetGetCount(pathSet, seg); count[0] = switch (PATH_SET_SIZE) { case ValueLayout.OfLong layout -> seg.get(layout, 0); @@ -494,8 +438,6 @@ public static NFDResult pathSetGetCount(@NativeType("const nfdpathset_t*") Memor default -> throw new AssertionError("should not reach here"); }; return result; - } finally { - stack.setPointer(stackPointer); } } @@ -506,19 +448,16 @@ public static NFDResult pathSetGetCount(@NativeType("const nfdpathset_t*") Memor * @return the result and the count * @see #npathSetGetCount(MemorySegment, MemorySegment) npathSetGetCount */ - public static Tuple2.OfObjLong pathSetGetCount(@NativeType("const nfdpathset_t*") MemorySegment pathSet) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.calloc(PATH_SET_SIZE); + @Skip + default Tuple2.OfObjLong pathSetGetCount(@NativeType("const nfdpathset_t*") MemorySegment pathSet) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = stack.allocate(PATH_SET_SIZE); final NFDResult result = npathSetGetCount(pathSet, seg); return new Tuple2.OfObjLong<>(result, switch (PATH_SET_SIZE) { case ValueLayout.OfLong layout -> seg.get(layout, 0); case ValueLayout.OfInt layout -> Integer.toUnsignedLong(seg.get(layout, 0)); default -> throw new AssertionError("should not reach here"); }); - } finally { - stack.setPointer(stackPointer); } } @@ -531,12 +470,13 @@ public static Tuple2.OfObjLong pathSetGetCount(@NativeType("const nfd * via {@link #pathSetFreePathN} if this function returns {@link NFDResult#OKAY} * @return the result */ - public static NFDResult npathSetGetPathN(@NativeType("const nfdpathset_t*") MemorySegment pathSet, long index, @NativeType("nfdnchar_t**") MemorySegment outPath) { + @Skip + default NFDResult npathSetGetPathN(@NativeType("const nfdpathset_t*") MemorySegment pathSet, long index, @NativeType("nfdnchar_t**") MemorySegment outPath) { try { return switch (PATH_SET_SIZE) { - case OfLong _ -> NFDResult.of((int) NFD_PathSet_GetPathN.invokeExact(pathSet, index, outPath)); + case OfLong _ -> NFDResult.of((int) NFD_PathSet_GetPathN().invokeExact(pathSet, index, outPath)); case OfInt _ -> - NFDResult.of((int) NFD_PathSet_GetPathN.invokeExact(pathSet, Math.toIntExact(index), outPath)); + NFDResult.of((int) NFD_PathSet_GetPathN().invokeExact(pathSet, Math.toIntExact(index), outPath)); default -> throw new AssertionError("should not reach here"); }; } catch (Throwable e) { @@ -553,20 +493,17 @@ public static NFDResult npathSetGetPathN(@NativeType("const nfdpathset_t*") Memo * @return the result * @see #npathSetGetPathN(MemorySegment, long, MemorySegment) npathSetGetPathN */ - public static NFDResult pathSetGetPathN(@NativeType("const nfdpathset_t*") MemorySegment pathSet, long index, String[] outPath) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.callocPointer(); + @Skip + default NFDResult pathSetGetPathN(@NativeType("const nfdpathset_t*") MemorySegment pathSet, long index, String[] outPath) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = Marshal.marshal(stack, outPath); final NFDResult result = npathSetGetPathN(pathSet, index, seg); if (result == NFDResult.OKAY) { - final MemorySegment path = seg.get(ADDRESS, 0); - outPath[0] = getString(path, 0); + final MemorySegment path = seg.get(Unmarshal.STR_LAYOUT, 0); + outPath[0] = path.getString(0, NFDInternal.nfdCharset); pathSetFreePathN(path); } return result; - } finally { - stack.setPointer(stackPointer); } } @@ -575,11 +512,12 @@ public static NFDResult pathSetGetPathN(@NativeType("const nfdpathset_t*") Memor * * @param filePath the path */ - public static void pathSetFreePathN(@NativeType("const nfdnchar_t*") MemorySegment filePath) { - if (isOsWinOrApple) { + @Skip + default void pathSetFreePathN(@NativeType("const nfdnchar_t*") MemorySegment filePath) { + if (NFDInternal.isOsWinOrApple) { freePathN(filePath); } else try { - NFD_PathSet_FreePathN.invokeExact(filePath); + NFD_PathSet_FreePathN().invokeExact(filePath); } catch (Throwable e) { throw new AssertionError("should not reach here", e); } @@ -594,26 +532,16 @@ public static void pathSetFreePathN(@NativeType("const nfdnchar_t*") MemorySegme * and it should be freed before freeing the path-set. * @return the result */ - public static NFDResult pathSetGetEnum(@NativeType("const nfdpathset_t*") MemorySegment pathSet, @NativeType("nfdpathsetenum_t*") MemorySegment outEnumerator) { - try { - return NFDResult.of((int) NFD_PathSet_GetEnum.invokeExact(pathSet, outEnumerator)); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_PathSet_GetEnum") + NFDResult pathSetGetEnum(@NativeType("const nfdpathset_t*") MemorySegment pathSet, @NativeType("nfdpathsetenum_t*") MemorySegment outEnumerator); /** * Frees an enumerator of the path set. * * @param enumerator the enumerator */ - public static void pathSetFreeEnum(@NativeType("nfdpathsetenum_t*") MemorySegment enumerator) { - try { - NFD_PathSet_FreeEnum.invokeExact(enumerator); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_PathSet_FreeEnum") + void pathSetFreeEnum(@NativeType("nfdpathsetenum_t*") MemorySegment enumerator); /** * Gets the next item from the path set enumerator. @@ -626,13 +554,8 @@ public static void pathSetFreeEnum(@NativeType("nfdpathsetenum_t*") MemorySegmen * if this function returns {@link NFDResult#OKAY} and {@code *outPath} is not null * @return the result */ - public static NFDResult npathSetEnumNextN(@NativeType("nfdpathsetenum_t*") MemorySegment enumerator, @NativeType("nfdnchar_t**") MemorySegment outPath) { - try { - return NFDResult.of((int) NFD_PathSet_EnumNextN.invokeExact(enumerator, outPath)); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_PathSet_EnumNextN") + NFDResult npathSetEnumNextN(@NativeType("nfdpathsetenum_t*") MemorySegment enumerator, @NativeType("nfdnchar_t**") MemorySegment outPath); /** * Gets the next item from the path set enumerator. @@ -642,22 +565,19 @@ public static NFDResult npathSetEnumNextN(@NativeType("nfdpathsetenum_t*") Memor * @return the result * @see #npathSetEnumNextN(MemorySegment, MemorySegment) npathSetEnumNextN */ - public static NFDResult pathSetEnumNextN(@NativeType("nfdpathsetenum_t*") MemorySegment enumerator, String[] outPath) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.callocPointer(); + @Skip + default NFDResult pathSetEnumNextN(@NativeType("nfdpathsetenum_t*") MemorySegment enumerator, String[] outPath) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = Marshal.marshal(stack, outPath); final NFDResult result = npathSetEnumNextN(enumerator, seg); if (result == NFDResult.OKAY) { - final MemorySegment path = seg.get(ADDRESS, 0); - if (!RuntimeHelper.isNullptr(path)) { - outPath[0] = getString(path, 0); + final MemorySegment path = seg.get(Unmarshal.STR_LAYOUT, 0); + if (!Unmarshal.isNullPointer(path)) { + Unmarshal.copy(path, outPath, NFDInternal.nfdCharset); pathSetFreePathN(path); } } return result; - } finally { - stack.setPointer(stackPointer); } } @@ -666,23 +586,19 @@ public static NFDResult pathSetEnumNextN(@NativeType("nfdpathsetenum_t*") Memory * * @param pathSet the pathSet */ - public static void pathSetFree(@NativeType("const nfdpathset_t*") MemorySegment pathSet) { - try { - NFD_PathSet_Free.invokeExact(pathSet); - } catch (Throwable e) { - throw new AssertionError("should not reach here", e); - } - } + @Entrypoint("NFD_PathSet_Free") + void pathSetFree(@NativeType("const nfdpathset_t*") MemorySegment pathSet); /** * free a file path that was returned * * @param filePath the file path */ - public static void freePathU8(@NativeType("nfdu8char_t*") MemorySegment filePath) { - if (isOsWin) { + @Skip + default void freePathU8(@NativeType("nfdu8char_t*") MemorySegment filePath) { + if (NFDInternal.isOsWin) { try { - NFD_FreePathU8.invokeExact(filePath); + NFD_FreePathU8().invokeExact(filePath); } catch (Throwable e) { throw new AssertionError("should not reach here", e); } @@ -699,14 +615,15 @@ public static void freePathU8(@NativeType("nfdu8char_t*") MemorySegment filePath * @param defaultPath If defaultPath is NULL, the operating system will decide * @return the result */ - public static NFDResult nopenDialogU8(@NativeType("nfdu8char_t**") MemorySegment outPath, @NativeType("const nfdu8filteritem_t*") MemorySegment filterList, int filterCount, @NativeType("const nfdu8char_t*") MemorySegment defaultPath) { - if (isOsWin) { + @Skip + default NFDResult nopenDialogU8(@NativeType("nfdu8char_t**") MemorySegment outPath, NFDU8FilterItem filterList, int filterCount, @NativeType("const nfdu8char_t*") MemorySegment defaultPath) { + if (NFDInternal.isOsWin) { try { - return NFDResult.of((int) NFD_OpenDialogU8.invokeExact(outPath, filterList, filterCount, defaultPath)); + return NFDResult.of((int) NFD_OpenDialogU8().invokeExact(outPath, Marshal.marshal(filterList), filterCount, defaultPath)); } catch (Throwable e) { throw new AssertionError("should not reach here", e); } - } else return nopenDialogN(outPath, filterList, filterCount, defaultPath); + } else return nopenDialogN(outPath, new NFDNFilterItem(filterList.segment()), filterCount, defaultPath); } /** @@ -716,25 +633,22 @@ public static NFDResult nopenDialogU8(@NativeType("nfdu8char_t**") MemorySegment * @param filterList the filter list * @param defaultPath If defaultPath is NULL, the operating system will decide * @return the result - * @see #nopenDialogU8(MemorySegment, MemorySegment, int, MemorySegment) nopenDialogU8 + * @see #nopenDialogU8(MemorySegment, NFDU8FilterItem, int, MemorySegment) nopenDialogU8 */ - public static NFDResult openDialogU8(String[] outPath, NFDU8FilterItem.Buffer filterList, String defaultPath) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.callocPointer(); + @Skip + default NFDResult openDialogU8(String[] outPath, NFDU8FilterItem filterList, String defaultPath) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = Marshal.marshal(stack, outPath); final NFDResult result = nopenDialogU8(seg, - filterList != null ? filterList.address() : MemorySegment.NULL, + filterList, filterList != null ? Math.toIntExact(filterList.elementCount()) : 0, - defaultPath != null ? stack.allocateFrom(defaultPath) : MemorySegment.NULL); + Marshal.marshal(stack, defaultPath)); if (result == NFDResult.OKAY) { - final MemorySegment path = seg.get(ADDRESS, 0); - outPath[0] = RuntimeHelper.getString(path); + final MemorySegment path = seg.get(Unmarshal.STR_LAYOUT, 0); + outPath[0] = path.getString(0L); freePathU8(path); } return result; - } finally { - stack.setPointer(stackPointer); } } @@ -748,14 +662,16 @@ public static NFDResult openDialogU8(String[] outPath, NFDU8FilterItem.Buffer fi * @param defaultPath If defaultPath is NULL, the operating system will decide * @return the result */ - public static NFDResult nopenDialogMultipleU8(@NativeType("const nfdpathset_t**") MemorySegment outPaths, @NativeType("const nfdu8filteritem_t*") MemorySegment filterList, int filterCount, @NativeType("const nfdu8char_t*") MemorySegment defaultPath) { - if (isOsWin) { + @Skip + default NFDResult nopenDialogMultipleU8(@NativeType("const nfdpathset_t**") MemorySegment outPaths, NFDU8FilterItem filterList, int filterCount, @NativeType("const nfdu8char_t*") MemorySegment defaultPath) { + if (NFDInternal.isOsWin) { try { - return NFDResult.of((int) NFD_OpenDialogMultipleU8.invokeExact(outPaths, filterList, filterCount, defaultPath)); + return NFDResult.of((int) NFD_OpenDialogMultipleU8().invokeExact(outPaths, Marshal.marshal(filterList), filterCount, defaultPath)); } catch (Throwable e) { throw new AssertionError("should not reach here", e); } - } else return nopenDialogMultipleN(outPaths, filterList, filterCount, defaultPath); + } else + return nopenDialogMultipleN(outPaths, new NFDNFilterItem(filterList.segment()), filterCount, defaultPath); } /** @@ -766,18 +682,15 @@ public static NFDResult nopenDialogMultipleU8(@NativeType("const nfdpathset_t**" * @param filterList the filter list * @param defaultPath If defaultPath is NULL, the operating system will decide * @return the result - * @see #nopenDialogMultipleU8(MemorySegment, MemorySegment, int, MemorySegment) nopenDialogMultipleU8 + * @see #nopenDialogMultipleU8(MemorySegment, NFDU8FilterItem, int, MemorySegment) nopenDialogMultipleU8 */ - public static NFDResult openDialogMultipleU8(@NativeType("const nfdpathset_t**") MemorySegment outPaths, NFDU8FilterItem.Buffer filterList, String defaultPath) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { + @Skip + default NFDResult openDialogMultipleU8(@NativeType("const nfdpathset_t**") MemorySegment outPaths, NFDU8FilterItem filterList, String defaultPath) { + try (MemoryStack stack = MemoryStack.stackPush()) { return nopenDialogMultipleU8(outPaths, - filterList != null ? filterList.address() : MemorySegment.NULL, + filterList, filterList != null ? Math.toIntExact(filterList.elementCount()) : 0, - defaultPath != null ? stack.allocateFrom(defaultPath) : MemorySegment.NULL); - } finally { - stack.setPointer(stackPointer); + Marshal.marshal(stack, defaultPath)); } } @@ -792,14 +705,16 @@ public static NFDResult openDialogMultipleU8(@NativeType("const nfdpathset_t**") * @param defaultName the default name of the file * @return the result */ - public static NFDResult nsaveDialogU8(@NativeType("nfdu8char_t**") MemorySegment outPath, @NativeType("const nfdu8filteritem_t*") MemorySegment filterList, int filterCount, @NativeType("const nfdu8char_t*") MemorySegment defaultPath, @NativeType("const nfdu8char_t*") MemorySegment defaultName) { - if (isOsWin) { + @Skip + default NFDResult nsaveDialogU8(@NativeType("nfdu8char_t**") MemorySegment outPath, NFDU8FilterItem filterList, int filterCount, @NativeType("const nfdu8char_t*") MemorySegment defaultPath, @NativeType("const nfdu8char_t*") MemorySegment defaultName) { + if (NFDInternal.isOsWin) { try { - return NFDResult.of((int) NFD_SaveDialogU8.invokeExact(outPath, filterList, filterCount, defaultPath, defaultName)); + return NFDResult.of((int) NFD_SaveDialogU8().invokeExact(outPath, Marshal.marshal(filterList), filterCount, defaultPath, defaultName)); } catch (Throwable e) { throw new AssertionError("should not reach here", e); } - } else return nsaveDialogN(outPath, filterList, filterCount, defaultPath, defaultName); + } else + return nsaveDialogN(outPath, new NFDNFilterItem(filterList.segment()), filterCount, defaultPath, defaultName); } /** @@ -810,26 +725,23 @@ public static NFDResult nsaveDialogU8(@NativeType("nfdu8char_t**") MemorySegment * @param defaultPath If defaultPath is NULL, the operating system will decide * @param defaultName the default name of the file * @return the result - * @see #nopenDialogMultipleU8(MemorySegment, MemorySegment, int, MemorySegment) nopenDialogMultipleU8 + * @see #nopenDialogMultipleU8(MemorySegment, NFDU8FilterItem, int, MemorySegment) nopenDialogMultipleU8 */ - public static NFDResult saveDialogU8(String[] outPath, NFDU8FilterItem.Buffer filterList, String defaultPath, String defaultName) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.callocPointer(); + @Skip + default NFDResult saveDialogU8(String[] outPath, NFDU8FilterItem filterList, String defaultPath, String defaultName) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = Marshal.marshal(stack, outPath); final NFDResult result = nsaveDialogU8(seg, - filterList != null ? filterList.address() : MemorySegment.NULL, + filterList, filterList != null ? Math.toIntExact(filterList.elementCount()) : 0, - defaultPath != null ? stack.allocateFrom(defaultPath) : MemorySegment.NULL, - defaultName != null ? stack.allocateFrom(defaultName) : MemorySegment.NULL); + Marshal.marshal(stack, defaultPath), + Marshal.marshal(stack, defaultName)); if (result == NFDResult.OKAY) { - final MemorySegment path = seg.get(ADDRESS, 0); - outPath[0] = RuntimeHelper.getString(path); + final MemorySegment path = seg.get(Unmarshal.STR_LAYOUT, 0); + outPath[0] = path.getString(0L); freePathU8(path); } return result; - } finally { - stack.setPointer(stackPointer); } } @@ -841,10 +753,11 @@ public static NFDResult saveDialogU8(String[] outPath, NFDU8FilterItem.Buffer fi * @param defaultPath If defaultPath is NULL, the operating system will decide * @return the result */ - public static NFDResult npickFolderU8(@NativeType("nfdu8char_t**") MemorySegment outPath, @NativeType("const nfdu8char_t*") MemorySegment defaultPath) { - if (isOsWin) { + @Skip + default NFDResult npickFolderU8(@NativeType("nfdu8char_t**") MemorySegment outPath, @NativeType("const nfdu8char_t*") MemorySegment defaultPath) { + if (NFDInternal.isOsWin) { try { - return NFDResult.of((int) NFD_PickFolderU8.invokeExact(outPath, defaultPath)); + return NFDResult.of((int) NFD_PickFolderU8().invokeExact(outPath, defaultPath)); } catch (Throwable e) { throw new AssertionError("should not reach here", e); } @@ -859,20 +772,17 @@ public static NFDResult npickFolderU8(@NativeType("nfdu8char_t**") MemorySegment * @return the result * @see #npickFolderU8(MemorySegment, MemorySegment) npickFolderU8 */ - public static NFDResult pickFolderU8(String[] outPath, String defaultPath) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.callocPointer(); - final NFDResult result = npickFolderU8(seg, defaultPath != null ? stack.allocateFrom(defaultPath) : MemorySegment.NULL); + @Skip + default NFDResult pickFolderU8(String[] outPath, String defaultPath) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = Marshal.marshal(stack, outPath); + final NFDResult result = npickFolderU8(seg, Marshal.marshal(stack, defaultPath)); if (result == NFDResult.OKAY) { - final MemorySegment path = seg.get(ADDRESS, 0); - outPath[0] = RuntimeHelper.getString(path); + final MemorySegment path = seg.get(Unmarshal.STR_LAYOUT, 0); + outPath[0] = path.getString(0L); freePathU8(path); } return result; - } finally { - stack.setPointer(stackPointer); } } @@ -885,13 +795,14 @@ public static NFDResult pickFolderU8(String[] outPath, String defaultPath) { * via {@link #pathSetFreePathU8} if this function returns {@link NFDResult#OKAY} * @return the result */ - public static NFDResult npathSetGetPathU8(@NativeType("const nfdpathset_t*") MemorySegment pathSet, long index, @NativeType("nfdu8char_t**") MemorySegment outPath) { - if (isOsWin) { + @Skip + default NFDResult npathSetGetPathU8(@NativeType("const nfdpathset_t*") MemorySegment pathSet, long index, @NativeType("nfdu8char_t**") MemorySegment outPath) { + if (NFDInternal.isOsWin) { try { return switch (PATH_SET_SIZE) { - case OfLong _ -> NFDResult.of((int) NFD_PathSet_GetPathU8.invokeExact(pathSet, index, outPath)); + case OfLong _ -> NFDResult.of((int) NFD_PathSet_GetPathU8().invokeExact(pathSet, index, outPath)); case OfInt _ -> - NFDResult.of((int) NFD_PathSet_GetPathU8.invokeExact(pathSet, Math.toIntExact(index), outPath)); + NFDResult.of((int) NFD_PathSet_GetPathU8().invokeExact(pathSet, Math.toIntExact(index), outPath)); default -> throw new AssertionError("should not reach here"); }; } catch (Throwable e) { @@ -909,20 +820,17 @@ public static NFDResult npathSetGetPathU8(@NativeType("const nfdpathset_t*") Mem * @return the result * @see #npathSetGetPathU8(MemorySegment, long, MemorySegment) npathSetGetPathU8 */ - public static NFDResult pathSetGetPathU8(@NativeType("const nfdpathset_t*") MemorySegment pathSet, long index, String[] outPath) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.callocPointer(); + @Skip + default NFDResult pathSetGetPathU8(@NativeType("const nfdpathset_t*") MemorySegment pathSet, long index, String[] outPath) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = Marshal.marshal(stack, outPath); final NFDResult result = npathSetGetPathU8(pathSet, index, seg); if (result == NFDResult.OKAY) { - final MemorySegment path = seg.get(ADDRESS, 0); - outPath[0] = RuntimeHelper.getString(path); + final MemorySegment path = seg.get(Unmarshal.STR_LAYOUT, 0); + outPath[0] = path.getString(0L); pathSetFreePathU8(path); } return result; - } finally { - stack.setPointer(stackPointer); } } @@ -937,10 +845,11 @@ public static NFDResult pathSetGetPathU8(@NativeType("const nfdpathset_t*") Memo * if this function returns {@link NFDResult#OKAY} and {@code *outPath} is not null * @return the result */ - public static NFDResult npathSetEnumNextU8(@NativeType("nfdpathsetenum_t*") MemorySegment enumerator, @NativeType("nfdu8char_t**") MemorySegment outPath) { - if (isOsWin) { + @Skip + default NFDResult npathSetEnumNextU8(@NativeType("nfdpathsetenum_t*") MemorySegment enumerator, @NativeType("nfdu8char_t**") MemorySegment outPath) { + if (NFDInternal.isOsWin) { try { - return NFDResult.of((int) NFD_PathSet_EnumNextU8.invokeExact(enumerator, outPath)); + return NFDResult.of((int) NFD_PathSet_EnumNextU8().invokeExact(enumerator, outPath)); } catch (Throwable e) { throw new AssertionError("should not reach here", e); } @@ -955,22 +864,19 @@ public static NFDResult npathSetEnumNextU8(@NativeType("nfdpathsetenum_t*") Memo * @return the result * @see #npathSetEnumNextU8(MemorySegment, MemorySegment) npathSetEnumNextU8 */ - public static NFDResult pathSetEnumNextU8(@NativeType("nfdpathsetenum_t*") MemorySegment enumerator, String[] outPath) { - final MemoryStack stack = MemoryStack.stackGet(); - final long stackPointer = stack.getPointer(); - try { - final MemorySegment seg = stack.callocPointer(); + @Skip + default NFDResult pathSetEnumNextU8(@NativeType("nfdpathsetenum_t*") MemorySegment enumerator, String[] outPath) { + try (MemoryStack stack = MemoryStack.stackPush()) { + final MemorySegment seg = Marshal.marshal(stack, outPath); final NFDResult result = npathSetEnumNextU8(enumerator, seg); if (result == NFDResult.OKAY) { - final MemorySegment path = seg.get(ADDRESS, 0); - if (!RuntimeHelper.isNullptr(path)) { - outPath[0] = RuntimeHelper.getString(path); + final MemorySegment path = seg.get(Unmarshal.STR_LAYOUT, 0); + if (!Unmarshal.isNullPointer(path)) { + outPath[0] = path.getString(0L); pathSetFreePathU8(path); } } return result; - } finally { - stack.setPointer(stackPointer); } } @@ -979,8 +885,9 @@ public static NFDResult pathSetEnumNextU8(@NativeType("nfdpathsetenum_t*") Memor * * @param filePath the path */ - public static void pathSetFreePathU8(MemorySegment filePath) { - if (isOsWin) freePathU8(filePath); + @Skip + default void pathSetFreePathU8(MemorySegment filePath) { + if (NFDInternal.isOsWin) freePathU8(filePath); else pathSetFreePathN(filePath); } } diff --git a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDEnumerator.java b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDEnumerator.java index 6a92ed55..fa6c8a42 100644 --- a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDEnumerator.java +++ b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDEnumerator.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023 Overrun Organization + * Copyright (c) 2023-2024 Overrun Organization * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -17,7 +17,7 @@ package overrungl.nfd; import org.jetbrains.annotations.NotNull; -import overrungl.Struct; +import overrun.marshal.struct.Struct; import overrungl.util.value.Tuple2; import java.lang.foreign.MemoryLayout; @@ -52,6 +52,7 @@ public String next() { throw new NoSuchElementException(); } }; + private final NFD nfd = NFD.INSTANCE; private final Kind kind; private NFDEnumerator(Kind kind, MemorySegment address) { @@ -100,25 +101,18 @@ public String next() { } String[] s = new String[1]; final NFDResult result = switch (kind) { - case N -> NFD.pathSetEnumNextN(address(), s); - case U8 -> NFD.pathSetEnumNextU8(address(), s); + case N -> nfd.pathSetEnumNextN(segment(), s); + case U8 -> nfd.pathSetEnumNextU8(segment(), s); }; - if (result == NFDResult.ERROR) throw errorIterating(); + if (result == NFDResult.ERROR) throw errorIterating(nfd); nextPath = s[0]; return curr; } } - /** - * {@return the elements size of this struct in bytes} - */ - public static long sizeof() { - return LAYOUT.byteSize(); - } - private static Tuple2 fromPathSet(Kind kind, SegmentAllocator allocator, MemorySegment pathSet) { final MemorySegment seg = allocator.allocate(ADDRESS); - final NFDResult result = NFD.pathSetGetEnum(pathSet, seg); + final NFDResult result = NFD.INSTANCE.pathSetGetEnum(pathSet, seg); return new Tuple2<>(result, result == NFDResult.OKAY ? new NFDEnumerator(kind, seg) : @@ -147,8 +141,8 @@ public static Tuple2 fromPathSetU8(SegmentAllocator al return fromPathSet(Kind.U8, allocator, pathSet); } - private static IllegalStateException errorIterating() { - return new IllegalStateException(STR. "Error iterating: \{ NFD.getError() }" ); + private static IllegalStateException errorIterating(NFD nfd) { + return new IllegalStateException(STR."Error iterating: \{nfd.getError()}"); } @NotNull @@ -157,13 +151,13 @@ public Iterator iterator() { // TODO: 2023/7/6 Value object String[] s = new String[1]; final NFDResult result = switch (kind) { - case N -> NFD.pathSetEnumNextN(address(), s); - case U8 -> NFD.pathSetEnumNextU8(address(), s); + case N -> nfd.pathSetEnumNextN(segment(), s); + case U8 -> nfd.pathSetEnumNextU8(segment(), s); }; final String path = s[0]; if (path == null || result != NFDResult.OKAY) { if (result == NFDResult.ERROR) { - throw errorIterating(); + throw errorIterating(nfd); } return EMPTY_ITERATOR; } @@ -172,6 +166,6 @@ public Iterator iterator() { @Override public void close() { - NFD.pathSetFreeEnum(address()); + nfd.pathSetFreeEnum(segment()); } } diff --git a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDInternal.java b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDInternal.java new file mode 100644 index 00000000..4cbdf2be --- /dev/null +++ b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDInternal.java @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Copyright (c) 2024 Overrun Organization + * + * 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. + */ + +package overrungl.nfd; + +import io.github.overrun.platform.Platform; +import overrungl.Configurations; +import overrungl.OverrunGL; +import overrungl.internal.RuntimeHelper; + +import java.lang.foreign.SymbolLookup; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.function.Supplier; + +/** + * internal + * + * @author squid233 + * @since 0.1.0 + */ +final class NFDInternal { + static final SymbolLookup LOOKUP; + + static { + final Supplier lib = () -> RuntimeHelper.load("nfd", "nfd", OverrunGL.NFD_VERSION); + final var function = Configurations.NFD_SYMBOL_LOOKUP.get(); + LOOKUP = function != null ? function.apply(lib) : lib.get(); + } + + static final Platform os = Platform.current(); + static final boolean isOsWin = os instanceof Platform.Windows; + static final boolean isOsWinOrApple = isOsWin || os instanceof Platform.MacOS; + static final Charset nfdCharset = isOsWin ? StandardCharsets.UTF_16LE : StandardCharsets.UTF_8; +} diff --git a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDNFilterItem.java b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDNFilterItem.java index 9246b1de..e8f5317a 100644 --- a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDNFilterItem.java +++ b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDNFilterItem.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023 Overrun Organization + * Copyright (c) 2023-2024 Overrun Organization * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -16,26 +16,25 @@ package overrungl.nfd; -import overrungl.ArrayPointer; -import overrungl.Struct; +import overrun.marshal.struct.Struct; +import overrun.marshal.struct.StructHandle; +import overrun.marshal.struct.StructHandleView; import overrungl.util.value.Pair; import java.lang.foreign.*; -import java.lang.foreign.MemoryLayout.PathElement; -import java.lang.invoke.VarHandle; /** *

Layout

*

  * struct nfdnfilteritem_t {
- *     const nfdnchar_t* {@link #name() name};
- *     const nfdnchar_t* {@link #spec() spec};
+ *     const nfdnchar_t* {@link #name};
+ *     const nfdnchar_t* {@link #spec};
  * }
* * @author squid233 * @since 0.1.0 */ -public sealed class NFDNFilterItem extends Struct { +public final class NFDNFilterItem extends Struct { /** * The struct layout. */ @@ -43,9 +42,16 @@ public sealed class NFDNFilterItem extends Struct { ValueLayout.ADDRESS.withName("name"), ValueLayout.ADDRESS.withName("spec") ); - private static final VarHandle - pName = LAYOUT.varHandle(PathElement.groupElement("name")), - pSpec = LAYOUT.varHandle(PathElement.groupElement("spec")); + private final StructHandle.Str _name = StructHandle.ofString(this, "name", NFDInternal.nfdCharset); + private final StructHandle.Str _spec = StructHandle.ofString(this, "spec", NFDInternal.nfdCharset); + /** + * name + */ + public final StructHandleView.Str name = _name; + /** + * spec + */ + public final StructHandleView.Str spec = _spec; /** * Create a {@code NFDNFilterItem} instance. @@ -57,20 +63,13 @@ public NFDNFilterItem(MemorySegment address) { } /** - * Creates a struct instance with the given memory layout. + * Creates a struct with the given layout. * - * @param address the address. - * @param layout the memory layout of this struct. + * @param segment the segment + * @param elementCount the element count */ - protected NFDNFilterItem(MemorySegment address, MemoryLayout layout) { - super(address, layout); - } - - /** - * {@return the elements size of this struct in bytes} - */ - public static long sizeof() { - return LAYOUT.byteSize(); + public NFDNFilterItem(MemorySegment segment, long elementCount) { + super(segment, elementCount, LAYOUT); } /** @@ -83,8 +82,8 @@ public static long sizeof() { */ public static NFDNFilterItem create(SegmentAllocator allocator, String name, String spec) { final NFDNFilterItem item = new NFDNFilterItem(allocator.allocate(LAYOUT)); - pName.set(item.segment(), NFD.allocateString(name)); - pSpec.set(item.segment(), NFD.allocateString(spec)); + item._name.set(allocator, name); + item._spec.set(allocator, spec); return item; } @@ -96,121 +95,13 @@ public static NFDNFilterItem create(SegmentAllocator allocator, String name, Str * @return the instance */ @SafeVarargs - public static Buffer create(SegmentAllocator allocator, Pair... items) { - final Buffer buffer = new Buffer(allocator.allocate(LAYOUT, items.length), items.length); + public static NFDNFilterItem create(SegmentAllocator allocator, Pair... items) { + final NFDNFilterItem buffer = new NFDNFilterItem(allocator.allocate(LAYOUT, items.length), items.length); for (int i = 0, len = items.length; i < len; i++) { Pair item = items[i]; - buffer.pName.set(buffer.segment(), (long) i, NFD.allocateString(item.key())); - buffer.pSpec.set(buffer.segment(), (long) i, NFD.allocateString(item.value())); + buffer._name.set(allocator, i, item.key()); + buffer._spec.set(allocator, i, item.value()); } return buffer; } - - /** - * {@return the name of the filter} - */ - public MemorySegment nname() { - return (MemorySegment) pName.get(segment()); - } - - /** - * {@return the name of the filter} - * - * @see #nname() - */ - public String name() { - return NFD.getString(nname(), 0); - } - - /** - * {@return the spec of the filter} - */ - public MemorySegment nspec() { - return (MemorySegment) pSpec.get(segment()); - } - - /** - * {@return the spec of the filter} - * - * @see #nspec() - */ - public String spec() { - return NFD.getString(nspec(), 0); - } - - /** - * @author squid233 - * @since 0.1.0 - */ - public static final class Buffer extends NFDNFilterItem implements ArrayPointer { - private final VarHandle pName, pSpec; - - /** - * Create a {@code NFDNFilterItem.Buffer} instance. - * - * @param address the address. - * @param elementCount the element count - */ - public Buffer(MemorySegment address, long elementCount) { - super(address, MemoryLayout.sequenceLayout(elementCount, LAYOUT)); - pName = layout().varHandle(PathElement.sequenceElement(), PathElement.groupElement("name")); - pSpec = layout().varHandle(PathElement.sequenceElement(), PathElement.groupElement("spec")); - } - - /** - * {@return the name at the given index} - * - * @param index the index - */ - public MemorySegment nnameAt(long index) { - return (MemorySegment) pName.get(segment(), index); - } - - /** - * {@return the name at the given index} - * - * @param index the index - */ - public String nameAt(long index) { - return NFD.getString(nnameAt(index), 0); - } - - /** - * {@return the spec at the given index} - * - * @param index the index - */ - public MemorySegment nspecAt(long index) { - return (MemorySegment) pSpec.get(segment(), index); - } - - /** - * {@return the spec at the given index} - * - * @param index the index - */ - public String specAt(long index) { - return NFD.getString(nspecAt(index), 0); - } - - @Override - public MemorySegment nname() { - return nnameAt(0); - } - - @Override - public String name() { - return nameAt(0); - } - - @Override - public MemorySegment nspec() { - return nspecAt(0); - } - - @Override - public String spec() { - return specAt(0); - } - } } diff --git a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDResult.java b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDResult.java index 27d86b8a..8d3054b3 100644 --- a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDResult.java +++ b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDResult.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023 Overrun Organization + * Copyright (c) 2023-2024 Overrun Organization * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -16,34 +16,53 @@ package overrungl.nfd; +import overrun.marshal.CEnum; + /** + * NFD result + * * @author squid233 * @since 0.1.0 */ -public enum NFDResult { +public enum NFDResult implements CEnum { /** * programmatic error */ - ERROR, + ERROR(0), /** * user pressed okay, or successful return */ - OKAY, + OKAY(1), /** * user pressed cancel */ - CANCEL; + CANCEL(2); + + private final int value; - private static final NFDResult[] VALUES = values(); + NFDResult(int value) { + this.value = value; + } /** * Gets the {@link NFDResult} by the given integer value. * * @param i the value * @return the result - * @throws ArrayIndexOutOfBoundsException if the result is not found + * @throws IllegalArgumentException if the result is not found */ + @Wrapper public static NFDResult of(int i) { - return VALUES[i]; + return switch (i) { + case 0 -> ERROR; + case 1 -> OKAY; + case 2 -> CANCEL; + default -> throw new IllegalArgumentException(STR."Unexpected value: \{i}"); + }; + } + + @Override + public int value() { + return value; } } diff --git a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDU8FilterItem.java b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDU8FilterItem.java index fc624e2f..cb206a89 100644 --- a/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDU8FilterItem.java +++ b/modules/overrungl.nfd/src/main/java/overrungl/nfd/NFDU8FilterItem.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2023 Overrun Organization + * Copyright (c) 2023-2024 Overrun Organization * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -16,26 +16,25 @@ package overrungl.nfd; -import overrungl.ArrayPointer; -import overrungl.Struct; +import overrun.marshal.struct.Struct; +import overrun.marshal.struct.StructHandle; +import overrun.marshal.struct.StructHandleView; import overrungl.util.value.Pair; import java.lang.foreign.*; -import java.lang.foreign.MemoryLayout.PathElement; -import java.lang.invoke.VarHandle; /** *

Layout

*

  * struct nfdu8filteritem_t {
- *     const nfdu8char_t* {@link #name() name};
- *     const nfdu8char_t* {@link #spec() spec};
+ *     const nfdu8char_t* {@link #name};
+ *     const nfdu8char_t* {@link #spec};
  * }
* * @author squid233 * @since 0.1.0 */ -public sealed class NFDU8FilterItem extends Struct { +public final class NFDU8FilterItem extends Struct { /** * The struct layout. */ @@ -43,9 +42,16 @@ public sealed class NFDU8FilterItem extends Struct { ValueLayout.ADDRESS.withName("name"), ValueLayout.ADDRESS.withName("spec") ); - private static final VarHandle - pName = LAYOUT.varHandle(PathElement.groupElement("name")), - pSpec = LAYOUT.varHandle(PathElement.groupElement("spec")); + private final StructHandle.Str _name = StructHandle.ofString(this, "name"); + private final StructHandle.Str _spec = StructHandle.ofString(this, "spec"); + /** + * name + */ + public final StructHandleView.Str name = _name; + /** + * spec + */ + public final StructHandleView.Str spec = _spec; /** * Create a {@code NFDU8FilterItem} instance. @@ -57,20 +63,13 @@ public NFDU8FilterItem(MemorySegment address) { } /** - * Creates a struct instance with the given memory layout. + * Creates a struct with the given layout. * - * @param address the address. - * @param layout the memory layout of this struct. + * @param segment the segment + * @param elementCount the element count */ - protected NFDU8FilterItem(MemorySegment address, MemoryLayout layout) { - super(address, layout); - } - - /** - * {@return the elements size of this struct in bytes} - */ - public static long sizeof() { - return LAYOUT.byteSize(); + public NFDU8FilterItem(MemorySegment segment, long elementCount) { + super(segment, elementCount, LAYOUT); } /** @@ -83,8 +82,8 @@ public static long sizeof() { */ public static NFDU8FilterItem create(SegmentAllocator allocator, String name, String spec) { final NFDU8FilterItem item = new NFDU8FilterItem(allocator.allocate(LAYOUT)); - pName.set(item.segment(), allocator.allocateFrom(name)); - pSpec.set(item.segment(), allocator.allocateFrom(spec)); + item._name.set(allocator, name); + item._spec.set(allocator, spec); return item; } @@ -96,121 +95,13 @@ public static NFDU8FilterItem create(SegmentAllocator allocator, String name, St * @return the instance */ @SafeVarargs - public static Buffer create(SegmentAllocator allocator, Pair... items) { - final Buffer buffer = new Buffer(allocator.allocate(LAYOUT, items.length), items.length); + public static NFDU8FilterItem create(SegmentAllocator allocator, Pair... items) { + final NFDU8FilterItem buffer = new NFDU8FilterItem(allocator.allocate(LAYOUT, items.length), items.length); for (int i = 0, len = items.length; i < len; i++) { Pair item = items[i]; - buffer.pName.set(buffer.segment(), (long) i, allocator.allocateFrom(item.key())); - buffer.pSpec.set(buffer.segment(), (long) i, allocator.allocateFrom(item.value())); + buffer._name.set(allocator, i, item.key()); + buffer._spec.set(allocator, i, item.value()); } return buffer; } - - /** - * {@return the name of the filter} - */ - public MemorySegment nname() { - return (MemorySegment) pName.get(segment()); - } - - /** - * {@return the name of the filter} - * - * @see #nname() - */ - public String name() { - return nname().getString(0); - } - - /** - * {@return the spec of the filter} - */ - public MemorySegment nspec() { - return (MemorySegment) pSpec.get(segment()); - } - - /** - * {@return the spec of the filter} - * - * @see #nspec() - */ - public String spec() { - return nspec().getString(0); - } - - /** - * @author squid233 - * @since 0.1.0 - */ - public static final class Buffer extends NFDU8FilterItem implements ArrayPointer { - private final VarHandle pName, pSpec; - - /** - * Create a {@code NFDU8FilterItem.Buffer} instance. - * - * @param address the address. - * @param elementCount the element count - */ - public Buffer(MemorySegment address, long elementCount) { - super(address, MemoryLayout.sequenceLayout(elementCount, LAYOUT)); - pName = layout().varHandle(PathElement.sequenceElement(), PathElement.groupElement("name")); - pSpec = layout().varHandle(PathElement.sequenceElement(), PathElement.groupElement("spec")); - } - - /** - * {@return the name at the given index} - * - * @param index the index - */ - public MemorySegment nnameAt(long index) { - return (MemorySegment) pName.get(segment(), index); - } - - /** - * {@return the name at the given index} - * - * @param index the index - */ - public String nameAt(long index) { - return nnameAt(index).getString(0); - } - - /** - * {@return the spec at the given index} - * - * @param index the index - */ - public MemorySegment nspecAt(long index) { - return (MemorySegment) pSpec.get(segment(), index); - } - - /** - * {@return the spec at the given index} - * - * @param index the index - */ - public String specAt(long index) { - return nspecAt(index).getString(0); - } - - @Override - public MemorySegment nname() { - return nnameAt(0); - } - - @Override - public String name() { - return nameAt(0); - } - - @Override - public MemorySegment nspec() { - return nspecAt(0); - } - - @Override - public String spec() { - return specAt(0); - } - } } diff --git a/modules/overrungl.stb/src/main/java/overrungl/stb/STBRPContext.java b/modules/overrungl.stb/src/main/java/overrungl/stb/STBRPContext.java new file mode 100644 index 00000000..45f5773b --- /dev/null +++ b/modules/overrungl.stb/src/main/java/overrungl/stb/STBRPContext.java @@ -0,0 +1,82 @@ +/* + * MIT License + * + * Copyright (c) 2024 Overrun Organization + * + * 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. + */ + +package overrungl.stb; + +import overrun.marshal.struct.Struct; + +import java.lang.foreign.*; + +/** + * the details of the following structures don't matter to you, but they must + * be visible so you can handle the memory allocations for them + * @author squid233 + * @since 0.1.0 + */ +public final class STBRPContext extends Struct { + /** + * The layout. + */ + public static final StructLayout LAYOUT= MemoryLayout.structLayout( + ValueLayout.JAVA_INT.withName("width"), + ValueLayout.JAVA_INT.withName("height"), + ValueLayout.JAVA_INT.withName("align"), + ValueLayout.JAVA_INT.withName("init_mode"), + ValueLayout.JAVA_INT.withName("heuristic"), + ValueLayout.JAVA_INT.withName("num_nodes"), + ValueLayout.ADDRESS.withName("active_head").withTargetLayout(MemoryLayout.sequenceLayout(0L, STBRPNode.LAYOUT)), + ValueLayout.ADDRESS.withName("free_head").withTargetLayout(MemoryLayout.sequenceLayout(0L, STBRPNode.LAYOUT)), + MemoryLayout.sequenceLayout(2L, STBRPNode.LAYOUT) + ); + + /** + * Creates a struct with the given layout. + * + * @param segment the segment + * @param elementCount the element count + */ + public STBRPContext(MemorySegment segment, long elementCount) { + super(segment, elementCount, LAYOUT); + } + + /** + * Allocates a struct with the given layout. + * + * @param allocator the allocator + * @param elementCount the element count + */ + public STBRPContext(SegmentAllocator allocator, long elementCount) { + super(allocator, elementCount, LAYOUT); + } + + /** + * Creates a struct with the given layout. + * + * @param segment the segment + */ + public STBRPContext(MemorySegment segment) { + super(segment, LAYOUT); + } + + /** + * Allocates a struct with the given layout. + * + * @param allocator the allocator + */ + public STBRPContext(SegmentAllocator allocator) { + super(allocator, LAYOUT); + } +} diff --git a/modules/overrungl.stb/src/main/java/overrungl/stb/STBRPNode.java b/modules/overrungl.stb/src/main/java/overrungl/stb/STBRPNode.java new file mode 100644 index 00000000..695ccdcf --- /dev/null +++ b/modules/overrungl.stb/src/main/java/overrungl/stb/STBRPNode.java @@ -0,0 +1,77 @@ +/* + * MIT License + * + * Copyright (c) 2024 Overrun Organization + * + * 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. + */ + +package overrungl.stb; + +import overrun.marshal.struct.Struct; + +import java.lang.foreign.*; + +/** + * the details of the following structures don't matter to you, but they must + * be visible so you can handle the memory allocations for them + * + * @author squid233 + * @since 0.1.0 + */ +public final class STBRPNode extends Struct { + /** + * The layout. + */ + public static final StructLayout LAYOUT = MemoryLayout.structLayout( + ValueLayout.JAVA_INT.withName("x"), + ValueLayout.JAVA_INT.withName("y"), + ValueLayout.ADDRESS.withName("next") // self-reference + ); + + /** + * Creates a struct with the given layout. + * + * @param segment the segment + * @param elementCount the element count + */ + public STBRPNode(MemorySegment segment, long elementCount) { + super(segment, elementCount, LAYOUT); + } + + /** + * Allocates a struct with the given layout. + * + * @param allocator the allocator + * @param elementCount the element count + */ + public STBRPNode(SegmentAllocator allocator, long elementCount) { + super(allocator, elementCount, LAYOUT); + } + + /** + * Creates a struct with the given layout. + * + * @param segment the segment + */ + public STBRPNode(MemorySegment segment) { + super(segment, LAYOUT); + } + + /** + * Allocates a struct with the given layout. + * + * @param allocator the allocator + */ + public STBRPNode(SegmentAllocator allocator) { + super(allocator, LAYOUT); + } +} diff --git a/modules/overrungl.stb/src/main/java/overrungl/stb/STBRPRect.java b/modules/overrungl.stb/src/main/java/overrungl/stb/STBRPRect.java new file mode 100644 index 00000000..035edd10 --- /dev/null +++ b/modules/overrungl.stb/src/main/java/overrungl/stb/STBRPRect.java @@ -0,0 +1,98 @@ +/* + * MIT License + * + * Copyright (c) 2024 Overrun Organization + * + * 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. + */ + +package overrungl.stb; + +import overrun.marshal.struct.Struct; +import overrun.marshal.struct.StructHandle; + +import java.lang.foreign.*; + +/** + * 16 bytes, nominally + * + * @author squid233 + * @since 0.1.0 + */ +public final class STBRPRect extends Struct { + /** + * The layout. + */ + public static final StructLayout LAYOUT = MemoryLayout.structLayout( + ValueLayout.JAVA_INT.withName("id"), + ValueLayout.JAVA_INT.withName("w"), + ValueLayout.JAVA_INT.withName("h"), + ValueLayout.JAVA_INT.withName("x"), + ValueLayout.JAVA_INT.withName("y"), + ValueLayout.JAVA_INT.withName("was_packed") + ); + /** + * reserved for your use + */ + public final StructHandle.Int id = StructHandle.ofInt(this, "id"); + /** + * input + */ + public final StructHandle.Int w = StructHandle.ofInt(this, "w"), + h = StructHandle.ofInt(this, "h"); + /** + * output + */ + public final StructHandle.Int x = StructHandle.ofInt(this, "x"), + y = StructHandle.ofInt(this, "y"), + /** + * non-zero if valid packing + */ + wasPacked = StructHandle.ofInt(this, "was_packed"); + + /** + * Creates a struct with the given layout. + * + * @param segment the segment + * @param elementCount the element count + */ + public STBRPRect(MemorySegment segment, long elementCount) { + super(segment, elementCount, LAYOUT); + } + + /** + * Allocates a struct with the given layout. + * + * @param allocator the allocator + * @param elementCount the element count + */ + public STBRPRect(SegmentAllocator allocator, long elementCount) { + super(allocator, elementCount, LAYOUT); + } + + /** + * Creates a struct with the given layout. + * + * @param segment the segment + */ + public STBRPRect(MemorySegment segment) { + super(segment, LAYOUT); + } + + /** + * Allocates a struct with the given layout. + * + * @param allocator the allocator + */ + public STBRPRect(SegmentAllocator allocator) { + super(allocator, LAYOUT); + } +} diff --git a/modules/overrungl.stb/src/main/java/overrungl/stb/STBRectPack.java b/modules/overrungl.stb/src/main/java/overrungl/stb/STBRectPack.java new file mode 100644 index 00000000..854440d1 --- /dev/null +++ b/modules/overrungl.stb/src/main/java/overrungl/stb/STBRectPack.java @@ -0,0 +1,141 @@ +/* + * MIT License + * + * Copyright (c) 2024 Overrun Organization + * + * 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. + */ + +package overrungl.stb; + +import overrun.marshal.Downcall; +import overrun.marshal.gen.Entrypoint; + +/** + * Useful for e.g. packing rectangular textures into an atlas. + * Does not do rotation. + *

+ * his library currently uses the Skyline Bottom-Left algorithm. + * + * @author squid233 + * @since 0.1.0 + */ +public interface STBRectPack { + /** + * The instance of STBRectPack. + */ + STBRectPack INSTANCE = Downcall.load(Handles.lookup); + /** + * Mostly for internal use, but this is the maximum supported coordinate value. + */ + int _MAXVAL = 0x7fffffff; + /** + * heuristic + */ + int HEURISTIC_Skyline_default = 0, + /** + * bottom left + */ + HEURISTIC_Skyline_BL_sortHeight = HEURISTIC_Skyline_default, + /** + * best-fit + */ + HEURISTIC_Skyline_BF_sortHeight = 1; + + /** + * Assign packed locations to rectangles. The rectangles are of type + * 'stbrp_rect' defined below, stored in the array 'rects', and there + * are 'num_rects' many of them. + *

+ * Rectangles which are successfully packed have the 'was_packed' flag + * set to a non-zero value and 'x' and 'y' store the minimum location + * on each axis (i.e. bottom-left in cartesian coordinates, top-left + * if you imagine y increasing downwards). Rectangles which do not fit + * have the 'was_packed' flag set to 0. + *

+ * You should not try to access the 'rects' array from another thread + * while this function is running, as the function temporarily reorders + * the array while it executes. + *

+ * To pack into another rectangle, you need to call stbrp_init_target + * again. To continue packing into the same rectangle, you can call + * this function again. Calling this multiple times with multiple rect + * arrays will probably produce worse packing results than calling it + * a single time with the full rectangle array, but the option is + * available. + * + * @param context context + * @param rects rects + * @param num_rects num of rects + * @return 1 if all of the rectangles were successfully + * packed and 0 otherwise. + */ + @Entrypoint("stbrp_pack_rects") + int packRects(STBRPContext context, STBRPRect rects, int num_rects); + + /** + * Initialize a rectangle packer to: + *

    + *
  • pack a rectangle that is 'width' by 'height' in dimensions
  • + *
  • using temporary storage provided by the array 'nodes', which is 'num_nodes' long
  • + *
+ *

+ * You must call this function every time you start packing into a new target. + *

+ * There is no "shutdown" function. The 'nodes' memory must stay valid for + * the following stbrp_pack_rects() call (or calls), but can be freed after + * the call (or calls) finish. + *

+ * Note: to guarantee best results, either: + *

    + *
  1. make sure 'num_nodes' >= 'width' or
  2. + *
  3. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
  4. + *
+ *

+ * If you don't do either of the above things, widths will be quantized to multiples + * of small integers to guarantee the algorithm doesn't run out of temporary storage. + *

+ * If you do #2, then the non-quantized algorithm will be used, but the algorithm + * may run out of temporary storage and be unable to pack some rectangles. + * + * @param context context + * @param width width + * @param height height + * @param nodes nodes + * @param num_nodes num of nodes + */ + @Entrypoint("stbrp_init_target") + void initTarget(STBRPContext context, int width, int height, STBRPNode nodes, int num_nodes); + + /** + * Optionally call this function after init but before doing any packing to + * change the handling of the out-of-temp-memory scenario, described above. + *

+ * If you call init again, this will be reset to the default (false). + * + * @param context context + * @param allow_out_of_mem allow_out_of_mem + */ + @Entrypoint("stbrp_setup_allow_out_of_mem") + void setupAllowOutOfMem(STBRPContext context, int allow_out_of_mem); + + /** + * Optionally select which packing heuristic the library should use. Different + * heuristics will produce better/worse results for different data sets. + *

+ * If you call init again, this will be reset to the default. + * + * @param context context + * @param heuristic heuristic + */ + @Entrypoint("stbrp_setup_heuristic") + void setupHeuristic(STBRPContext context, int heuristic); +} diff --git a/modules/overrungl.stb/src/main/java/overrungl/stb/STBTrueType.java b/modules/overrungl.stb/src/main/java/overrungl/stb/STBTrueType.java index 5acb8b25..59827cdb 100644 --- a/modules/overrungl.stb/src/main/java/overrungl/stb/STBTrueType.java +++ b/modules/overrungl.stb/src/main/java/overrungl/stb/STBTrueType.java @@ -621,7 +621,7 @@ void getPackedQuad(STBTTPackedChar chardata, int pw, int ph, * @return int */ @Entrypoint("stbtt_PackFontRangesGatherRects") - int packFontRangesGatherRects(@NativeType("stbtt_pack_context *") MemorySegment spc, @NativeType("const stbtt_fontinfo *") MemorySegment info, STBTTPackRange ranges, int num_ranges, @NativeType("stbrp_rect *") MemorySegment rects); + int packFontRangesGatherRects(@NativeType("stbtt_pack_context *") MemorySegment spc, @NativeType("const stbtt_fontinfo *") MemorySegment info, STBTTPackRange ranges, int num_ranges, STBRPRect rects); /** * Calling these functions in sequence is roughly equivalent to calling @@ -639,7 +639,7 @@ void getPackedQuad(STBTTPackedChar chardata, int pw, int ph, * @param num_rects num_rects */ @Entrypoint("stbtt_PackFontRangesPackRects") - void packFontRangesPackRects(@NativeType("stbtt_pack_context *") MemorySegment spc, @NativeType("stbrp_rect *") MemorySegment rects, int num_rects); + void packFontRangesPackRects(@NativeType("stbtt_pack_context *") MemorySegment spc, STBRPRect rects, int num_rects); /** * Calling these functions in sequence is roughly equivalent to calling @@ -660,7 +660,7 @@ void getPackedQuad(STBTTPackedChar chardata, int pw, int ph, * @return int */ @Entrypoint("stbtt_PackFontRangesRenderIntoRects") - int packFontRangesRenderIntoRects(@NativeType("stbtt_pack_context *") MemorySegment spc, @NativeType("const stbtt_fontinfo *") MemorySegment info, STBTTPackRange ranges, int num_ranges, @NativeType("stbrp_rect *") MemorySegment rects); + int packFontRangesRenderIntoRects(@NativeType("stbtt_pack_context *") MemorySegment spc, @NativeType("const stbtt_fontinfo *") MemorySegment info, STBTTPackRange ranges, int num_ranges, STBRPRect rects); ////////////////////////////////////////////////////////////////////////////// // diff --git a/modules/overrungl.stb/src/main/java/overrungl/stb/STBVorbis.java b/modules/overrungl.stb/src/main/java/overrungl/stb/STBVorbis.java index e03e46d2..348b6a42 100644 --- a/modules/overrungl.stb/src/main/java/overrungl/stb/STBVorbis.java +++ b/modules/overrungl.stb/src/main/java/overrungl/stb/STBVorbis.java @@ -16,9 +16,9 @@ package overrungl.stb; -import overrun.marshal.ByValue; import overrun.marshal.Downcall; import overrun.marshal.gen.Entrypoint; +import overrun.marshal.struct.ByValue; import overrungl.NativeType; import java.lang.foreign.MemorySegment; diff --git a/modules/samples/build.gradle.kts b/modules/samples/build.gradle.kts index a746ae2f..251eab64 100644 --- a/modules/samples/build.gradle.kts +++ b/modules/samples/build.gradle.kts @@ -1,7 +1,14 @@ val projModules: String by project dependencies { - projModules.split(',').map { it.trim() }.forEach { + listOf( + "core", + "glfw", + "joml", + "nfd", + "opengl", + "stb" + ).forEach { implementation(project(":$it")) } testImplementation("io.github.over-run:timer:0.3.0") diff --git a/modules/samples/src/test/java/overrungl/demo/nfd/NFDTest.java b/modules/samples/src/test/java/overrungl/demo/nfd/NFDTest.java index 64fb54cc..8be40f99 100644 --- a/modules/samples/src/test/java/overrungl/demo/nfd/NFDTest.java +++ b/modules/samples/src/test/java/overrungl/demo/nfd/NFDTest.java @@ -31,33 +31,35 @@ * @since 0.1.0 */ public final class NFDTest { + private static final NFD nfd = NFD.INSTANCE; + private static void openDialog() { System.out.println("===== openDialog ====="); // initialize NFD // either call NFD::init at the start of your program and NFD::quit at the end of your program, // or before/after every time you want to show a file dialog. - NFD.init(); + nfd.init(); try (MemoryStack stack = MemoryStack.stackPush()) { String[] outPath = new String[1]; // prepare filters for the dialog - final NFDNFilterItem.Buffer filterItem = NFDNFilterItem.create(stack, + final NFDNFilterItem filterItem = NFDNFilterItem.create(stack, new Pair<>("Source code", "java"), new Pair<>("Image file", "png,jpg")); // show the dialog - final NFDResult result = NFD.openDialogN(outPath, filterItem, null); + final NFDResult result = nfd.openDialogN(outPath, filterItem, null); switch (result) { - case ERROR -> System.err.println(STR."Error: \{NFD.getError()}"); + case ERROR -> System.err.println(STR."Error: \{nfd.getError()}"); case OKAY -> System.out.println(STR."Success! \{outPath[0]}"); case CANCEL -> System.out.println("User pressed cancel."); } } // Quit NFD - NFD.quit(); + nfd.quit(); } private static void openDialogMultiple() { @@ -65,40 +67,40 @@ private static void openDialogMultiple() { // initialize NFD // either call NFD::init at the start of your program and NFD::quit at the end of your program, // or before/after every time you want to show a file dialog. - NFD.init(); + nfd.init(); try (MemoryStack stack = MemoryStack.stackPush()) { MemorySegment pOutPaths = stack.callocPointer(); String[] outPath = new String[1]; // prepare filters for the dialog - final NFDNFilterItem.Buffer filterItem = NFDNFilterItem.create(stack, + final NFDNFilterItem filterItem = NFDNFilterItem.create(stack, new Pair<>("Source code", "java"), new Pair<>("Image file", "png,jpg")); // show the dialog - final NFDResult result = NFD.openDialogMultipleN(pOutPaths, filterItem, null); + final NFDResult result = nfd.openDialogMultipleN(pOutPaths, filterItem, null); MemorySegment outPaths = pOutPaths.get(ValueLayout.ADDRESS, 0); switch (result) { - case ERROR -> System.err.println(STR."Error: \{NFD.getError()}"); + case ERROR -> System.err.println(STR."Error: \{nfd.getError()}"); case OKAY -> { System.out.println("Success!"); - for (long i = 0, numPaths = NFD.pathSetGetCount(outPaths).y(); i < numPaths; i++) { - NFD.pathSetGetPathN(outPaths, i, outPath); + for (long i = 0, numPaths = nfd.pathSetGetCount(outPaths).y(); i < numPaths; i++) { + nfd.pathSetGetPathN(outPaths, i, outPath); System.out.println(STR."Path \{i}: \{outPath[0]}"); } // remember to free the path-set memory (since NFDResult::OKAY is returned) - NFD.pathSetFree(outPaths); + nfd.pathSetFree(outPaths); } case CANCEL -> System.out.println("User pressed cancel."); } } // Quit NFD - NFD.quit(); + nfd.quit(); } private static void openDialogMultipleEnum() { @@ -106,22 +108,22 @@ private static void openDialogMultipleEnum() { // initialize NFD // either call NFD::init at the start of your program and NFD::quit at the end of your program, // or before/after every time you want to show a file dialog. - NFD.init(); + nfd.init(); try (MemoryStack stack = MemoryStack.stackPush()) { MemorySegment pOutPaths = stack.callocPointer(); // prepare filters for the dialog - final NFDNFilterItem.Buffer filterItem = NFDNFilterItem.create(stack, + final NFDNFilterItem filterItem = NFDNFilterItem.create(stack, new Pair<>("Source code", "java"), new Pair<>("Image file", "png,jpg")); // show the dialog - final NFDResult result = NFD.openDialogMultipleN(pOutPaths, filterItem, null); + final NFDResult result = nfd.openDialogMultipleN(pOutPaths, filterItem, null); MemorySegment outPaths = pOutPaths.get(ValueLayout.ADDRESS, 0); switch (result) { - case ERROR -> System.err.println(STR."Error: \{NFD.getError()}"); + case ERROR -> System.err.println(STR."Error: \{nfd.getError()}"); case OKAY -> { System.out.println("Success!"); @@ -134,14 +136,14 @@ private static void openDialogMultipleEnum() { } // remember to free the path-set memory (since NFDResult::OKAY is returned) - NFD.pathSetFree(outPaths); + nfd.pathSetFree(outPaths); } case CANCEL -> System.out.println("User pressed cancel."); } } // Quit NFD - NFD.quit(); + nfd.quit(); } private static void pickFolder() { @@ -149,20 +151,20 @@ private static void pickFolder() { // initialize NFD // either call NFD::init at the start of your program and NFD::quit at the end of your program, // or before/after every time you want to show a file dialog. - NFD.init(); + nfd.init(); String[] outPath = new String[1]; // show the dialog - final NFDResult result = NFD.pickFolderN(outPath, null); + final NFDResult result = nfd.pickFolderN(outPath, null); switch (result) { - case ERROR -> System.err.println(STR."Error: \{NFD.getError()}"); + case ERROR -> System.err.println(STR."Error: \{nfd.getError()}"); case OKAY -> System.out.println(STR."Success! \{outPath[0]}"); case CANCEL -> System.out.println("User pressed cancel."); } // Quit NFD - NFD.quit(); + nfd.quit(); } private static void saveDialog() { @@ -170,27 +172,27 @@ private static void saveDialog() { // initialize NFD // either call NFD::init at the start of your program and NFD::quit at the end of your program, // or before/after every time you want to show a file dialog. - NFD.init(); + nfd.init(); try (MemoryStack stack = MemoryStack.stackPush()) { String[] savePath = new String[1]; // prepare filters for the dialog - final NFDNFilterItem.Buffer filterItem = NFDNFilterItem.create(stack, + final NFDNFilterItem filterItem = NFDNFilterItem.create(stack, new Pair<>("Source code", "java"), new Pair<>("Image file", "png,jpg")); // show the dialog - final NFDResult result = NFD.saveDialogN(savePath, filterItem, null, "Untitled.java"); + final NFDResult result = nfd.saveDialogN(savePath, filterItem, null, "Untitled.java"); switch (result) { - case ERROR -> System.err.println(STR."Error: \{NFD.getError()}"); + case ERROR -> System.err.println(STR."Error: \{nfd.getError()}"); case OKAY -> System.out.println(STR."Success! \{savePath[0]}"); case CANCEL -> System.out.println("User pressed cancel."); } } // Quit NFD - NFD.quit(); + nfd.quit(); } public static void main(String[] args) { diff --git a/settings.gradle.kts b/settings.gradle.kts index ac8a1d16..0b35251c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,14 +8,11 @@ pluginManagement { } val projName: String by settings -val projModules: String by settings rootProject.name = projName -projModules.split(',').map { it.trim() }.forEach { - include(it) - project(":$it").projectDir = File("modules/overrungl.$it/") +file("modules").listFiles().forEach { + val s = it.name.substringAfterLast("overrungl.") + include(s) + project(":$s").projectDir = it } - -include("samples") -project(":samples").projectDir = File("modules/samples/")