Skip to content

Commit 45419b3

Browse files
committed
Vulkan
1 parent f1c6945 commit 45419b3

20 files changed

Lines changed: 1789 additions & 62 deletions

File tree

.github/workflows/build.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,15 @@ jobs:
2727

2828
- name: Install Dependencies (Linux)
2929
if: contains(matrix.os, 'ubuntu')
30-
run: sudo apt-get install -y libgles2-mesa-dev
30+
run: sudo apt-get install -y libgles2-mesa-dev glslang-tools
31+
32+
- name: Install Dependencies (macOS)
33+
if: contains(matrix.os, 'macos')
34+
run: brew install glslang
35+
36+
- name: Install Dependencies (Windows)
37+
if: contains(matrix.os, 'windows')
38+
run: choco install glslang -y
3139

3240
- name: Build Desktop
3341
run: python3 scripts/build.py desktop
@@ -61,6 +69,9 @@ jobs:
6169
with:
6270
ndk-version: r26b
6371

72+
- name: Install Vulkan Shader Compiler
73+
run: sudo apt-get install -y glslang-tools
74+
6475
- name: Build Android
6576
run: python3 scripts/build.py android
6677

.github/workflows/release.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ jobs:
3737

3838
- name: Install Dependencies (Linux)
3939
if: contains(matrix.os, 'ubuntu')
40-
run: sudo apt-get install -y libgles2-mesa-dev
40+
run: sudo apt-get install -y libgles2-mesa-dev glslang-tools
41+
42+
- name: Install Dependencies (macOS)
43+
if: contains(matrix.os, 'macos')
44+
run: brew install glslang
45+
46+
- name: Install Dependencies (Windows)
47+
if: contains(matrix.os, 'windows')
48+
run: choco install glslang -y
4149

4250
- name: Build Desktop
4351
run: python3 scripts/build.py desktop
@@ -70,6 +78,9 @@ jobs:
7078
with:
7179
ndk-version: r26b
7280

81+
- name: Install Vulkan Shader Compiler
82+
run: sudo apt-get install -y glslang-tools
83+
7384
- name: Build Android
7485
run: python3 scripts/build.py android
7586

@@ -108,4 +119,4 @@ jobs:
108119
draft: false
109120
prerelease: false
110121
env:
111-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
122+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

README.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
# Live2D-JavaBinding
22

3-
A native Java binding for the [Live2D Cubism SDK](https://www.live2d.com/en/sdk/about/), enabling seamless integration of Live2D models in Java applications (Suitable for OpenGL).
3+
A native Java binding for the [Live2D Cubism SDK](https://www.live2d.com/en/sdk/about/), enabling seamless integration of Live2D models in Java applications.
44

55
For detailed documentation, please visit our [Wiki](https://github.com/Eatgrapes/Live2D-JavaBinding/wiki).
66

77
## Features
88

99
- **Decoupled Distribution**: Java logic and native binaries are separated for flexibility. Native JARs are fully self-contained.
10-
- **Cross-Platform Support**: Compatible with Windows (x64), Linux (x64, arm64), and macOS (x64, arm64).
11-
- **OpenGL Based**: Designed for OpenGL-accelerated applications (e.g., LWJGL, JOGL).
10+
- **Cross-Platform Support**: OpenGL path works on existing supported desktop targets.
11+
- **Dual Backend**: Runtime switching via `CubismFramework.makeGL()` / `CubismFramework.makeVulkan(...)`.
12+
- **Vulkan Scope**: Vulkan backend is supported on **linux-x64** and **windows-x64** only.
1213
- **Simple and Intuitive API**: Easy-to-use interfaces for model loading, rendering, and interaction.
1314
- **JNI Integration**: Leverages Java Native Interface (JNI) for high-performance native code execution.
1415

@@ -19,7 +20,7 @@ For detailed documentation, please visit our [Wiki](https://github.com/Eatgrapes
1920
- [x] **Motion System**: Playback with priority control and callbacks.
2021
- [x] **Parameter Control**: Manually set or get model parameter values.
2122
- [x] **Interaction**: Dragging support and hit detection.
22-
- [x] **Rendering**: OpenGL-based rendering and texture management.
23+
- [x] **Rendering**: OpenGL and Vulkan rendering paths.
2324

2425
## About JNI Integration
2526

@@ -40,6 +41,7 @@ import dev.eatgrapes.live2d.CubismUserModel;
4041

4142
// 1. Initialize the Framework
4243
CubismFramework.startUp();
44+
CubismFramework.makeGL(); // or CubismFramework.makeVulkan(...)
4345
CubismFramework.initialize();
4446

4547
// 2. Load Model & Components
@@ -50,7 +52,8 @@ model.loadPhysics(physicsBytes); // Load physics data
5052

5153
// 3. Setup Renderer
5254
model.createRenderer();
53-
model.registerTexture(0, openGLTextureId); // Bind textures
55+
model.registerTexture(0, openGLTextureId); // OpenGL texture
56+
// Vulkan: model.registerTextureVulkan(index, width, height, rgbaPixels);
5457

5558
// 4. Handle Interactions & Motions
5659
model.setDragging(nx, ny); // Enable eye tracking or dragging
@@ -63,12 +66,17 @@ model.update(deltaTime); // Update model state
6366
model.draw(mvpMatrix); // Render the model
6467
```
6568

69+
For Vulkan, update render target each frame before `draw`:
70+
```java
71+
model.setVulkanRenderTarget(vkImage, vkImageView, vkFormat, width, height);
72+
```
73+
6674
## Project Structure
6775

6876
- **`binding/`**: Contains the Java API definitions and module configurations.
6977
- **`native/`**: Houses the JNI C++ implementation, along with CMake build scripts for native compilation.
7078
- **`scripts/`**: Python scripts for automating builds across all supported platforms.
71-
- **`example/`**: A complete Maven-based demo project using LWJGL 3 for OpenGL integration.
79+
- **`example/`**: LWJGL 3 demos for OpenGL (`Main`) and Vulkan (`VulkanMain`).
7280

7381
## Building the Project
7482

@@ -77,6 +85,7 @@ model.draw(mvpMatrix); // Render the model
7785
- CMake 3.10+
7886
- A C++14-compatible compiler (e.g., GCC, Clang, or MSVC)
7987
- JDK 9 or higher
88+
- Vulkan shader compiler (`glslangValidator` or `glslc`) when building shader resources
8089

8190
### Build Command
8291
Run the following in the project root:
@@ -89,6 +98,8 @@ This will generate artifacts in the `out/` directory:
8998
- `live2d-shared.jar`: The core Java API.
9099
- `live2d-native-[platform].jar`: Platform-specific native libraries (e.g., `live2d-native-windows-x64.jar`).
91100

101+
OpenGL and Vulkan are bundled into the same shared/native dependencies. No extra Vulkan-only JAR is required.
102+
92103
## Contributing
93104

94105
We welcome Pull Requests (PRs)! Whether it's implementing additional SDK features, enhancing platform support, or fixing bugs, your help is appreciated. Please follow these steps:

binding/src/main/java/dev/eatgrapes/live2d/CubismFramework.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,62 @@ public static void startUp(LogCallback callback, LogLevel level) {
6161

6262
private static native void startUpNative(boolean hasCallback, int logLevel);
6363

64+
/**
65+
* Selects OpenGL as the renderer backend for newly created renderers.
66+
* Call this before {@link dev.eatgrapes.live2d.CubismUserModel#createRenderer()}.
67+
*/
68+
public static native void makeGL();
69+
70+
/**
71+
* Selects Vulkan as the renderer backend for newly created renderers and sets
72+
* required Vulkan shared context values.
73+
* <p>
74+
* Supported targets: Linux x64 and Windows x64.
75+
* Call this before {@link dev.eatgrapes.live2d.CubismUserModel#createRenderer()}.
76+
*
77+
* @param device VkDevice handle
78+
* @param physicalDevice VkPhysicalDevice handle
79+
* @param commandPool VkCommandPool handle
80+
* @param queue VkQueue handle
81+
* @param swapchainImageCount swapchain image count
82+
* @param width render target width
83+
* @param height render target height
84+
* @param imageView VkImageView handle of current render target
85+
* @param imageFormat VkFormat value of render target
86+
* @param depthFormat VkFormat value for depth image
87+
*/
88+
public static void makeVulkan(
89+
long device,
90+
long physicalDevice,
91+
long commandPool,
92+
long queue,
93+
int swapchainImageCount,
94+
int width,
95+
int height,
96+
long imageView,
97+
int imageFormat,
98+
int depthFormat
99+
) {
100+
LibraryLoader.prepareVulkanShadersToDisk();
101+
makeVulkanNative(
102+
device, physicalDevice, commandPool, queue,
103+
swapchainImageCount, width, height, imageView, imageFormat, depthFormat
104+
);
105+
}
106+
107+
private static native void makeVulkanNative(
108+
long device,
109+
long physicalDevice,
110+
long commandPool,
111+
long queue,
112+
int swapchainImageCount,
113+
int width,
114+
int height,
115+
long imageView,
116+
int imageFormat,
117+
int depthFormat
118+
);
119+
64120
/**
65121
* Initializes the framework resources.
66122
* Must be called after {@link #startUp()} and before using any other framework features.

binding/src/main/java/dev/eatgrapes/live2d/CubismUserModel.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,32 @@ public CubismUserModel() {
7373
public void registerTexture(int index, int textureId) { registerTextureNative(_ptr, index, textureId); }
7474
private static native void registerTextureNative(long ptr, int index, int textureId);
7575

76+
/**
77+
* Registers a texture for Vulkan renderer.
78+
* @param index The texture index (as defined in the model data).
79+
* @param width Texture width.
80+
* @param height Texture height.
81+
* @param rgbaPixels Texture pixels in RGBA8 format.
82+
*/
83+
public void registerTextureVulkan(int index, int width, int height, byte[] rgbaPixels) {
84+
registerTextureVulkanNative(_ptr, index, width, height, rgbaPixels);
85+
}
86+
private static native void registerTextureVulkanNative(long ptr, int index, int width, int height, byte[] rgbaPixels);
87+
88+
/**
89+
* Updates Vulkan render target for the current frame.
90+
*
91+
* @param image VkImage handle
92+
* @param imageView VkImageView handle
93+
* @param imageFormat VkFormat value
94+
* @param width Render target width
95+
* @param height Render target height
96+
*/
97+
public void setVulkanRenderTarget(long image, long imageView, int imageFormat, int width, int height) {
98+
setVulkanRenderTargetNative(_ptr, image, imageView, imageFormat, width, height);
99+
}
100+
private static native void setVulkanRenderTargetNative(long ptr, long image, long imageView, int imageFormat, int width, int height);
101+
76102
/**
77103
* Sets the dragging coordinates for interaction (e.g., look-at behavior).
78104
* @param x The x-coordinate in model space.

binding/src/main/java/dev/eatgrapes/live2d/LibraryLoader.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@
1313
*/
1414
public class LibraryLoader {
1515
private static boolean loaded = false;
16+
private static final String[] VULKAN_SHADER_FILES = {
17+
"VertShaderSrcSetupMask.spv",
18+
"FragShaderSrcSetupMask.spv",
19+
"VertShaderSrc.spv",
20+
"FragShaderSrc.spv",
21+
"VertShaderSrcMasked.spv",
22+
"FragShaderSrcMask.spv",
23+
"FragShaderSrcMaskInverted.spv",
24+
"FragShaderSrcPremultipliedAlpha.spv",
25+
"FragShaderSrcMaskPremultipliedAlpha.spv",
26+
"FragShaderSrcMaskInvertedPremultipliedAlpha.spv"
27+
};
1628

1729
/**
1830
* Loads the native library.
@@ -76,12 +88,42 @@ public static synchronized void load() {
7688
* @return The byte content of the shader file, or null if not found.
7789
*/
7890
public static byte[] loadResource(String name) {
79-
String internalPath = "/live2d/shaders/" + name.substring(name.lastIndexOf("/") + 1);
91+
if (name == null || name.isEmpty()) return null;
92+
String normalized = name.replace('\\', '/');
93+
String fileName = normalized.substring(normalized.lastIndexOf('/') + 1);
94+
String shaderGroup = fileName.endsWith(".spv") ? "vulkan" : "opengl";
95+
String internalPath = "/live2d/shaders/" + shaderGroup + "/" + fileName;
8096
try (InputStream is = LibraryLoader.class.getResourceAsStream(internalPath)) {
8197
if (is == null) return null;
8298
return is.readAllBytes();
8399
} catch (IOException e) {
84100
return null;
85101
}
86102
}
87-
}
103+
104+
/**
105+
* Ensures Vulkan SPIR-V shaders exist in the runtime working directory under {@code FrameworkShaders/}.
106+
* This keeps compatibility with Cubism Vulkan shader loading paths.
107+
*/
108+
public static synchronized void prepareVulkanShadersToDisk() {
109+
Path shaderDir = Paths.get("FrameworkShaders");
110+
try {
111+
Files.createDirectories(shaderDir);
112+
for (String fileName : VULKAN_SHADER_FILES) {
113+
Path target = shaderDir.resolve(fileName);
114+
if (Files.exists(target) && Files.size(target) > 0) {
115+
continue;
116+
}
117+
String internalPath = "/live2d/shaders/vulkan/" + fileName;
118+
try (InputStream is = LibraryLoader.class.getResourceAsStream(internalPath)) {
119+
if (is == null) {
120+
throw new RuntimeException("Vulkan shader not found in resources: " + internalPath);
121+
}
122+
Files.copy(is, target, StandardCopyOption.REPLACE_EXISTING);
123+
}
124+
}
125+
} catch (IOException e) {
126+
throw new RuntimeException("Failed to prepare Vulkan shaders on disk", e);
127+
}
128+
}
129+
}

0 commit comments

Comments
 (0)