Skip to content

Commit 0ded01f

Browse files
committed
feat(example,JNI):Del log display and add example modify model
1 parent bb4932a commit 0ded01f

140 files changed

Lines changed: 130356 additions & 20 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

example/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@
4747
<dependency><groupId>org.lwjgl</groupId><artifactId>lwjgl-glfw</artifactId><classifier>${lwjgl.natives}</classifier></dependency>
4848
<dependency><groupId>org.lwjgl</groupId><artifactId>lwjgl-opengl</artifactId><classifier>${lwjgl.natives}</classifier></dependency>
4949
<dependency><groupId>org.lwjgl</groupId><artifactId>lwjgl-stb</artifactId><classifier>${lwjgl.natives}</classifier></dependency>
50+
<dependency>
51+
<groupId>com.google.code.gson</groupId>
52+
<artifactId>gson</artifactId>
53+
<version>2.10.1</version>
54+
</dependency>
5055
</dependencies>
5156

5257
<build>

example/src/main/java/dev/eatgrapes/live2d/example/ControlPanel.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,27 @@ public static void show() {
4141
JPanel viewPanel = new JPanel(new GridLayout(0, 1));
4242
viewPanel.setBorder(BorderFactory.createTitledBorder("View"));
4343
addScaleSlider(viewPanel, "Scale", 0.1f, 3.0f, 1.0f);
44+
addModelSelector(viewPanel);
4445
frame.add(viewPanel);
4546

4647
frame.setVisible(true);
4748
});
4849
}
4950

51+
private static void addModelSelector(JPanel panel) {
52+
JPanel p = new JPanel(new BorderLayout());
53+
JLabel l = new JLabel("Model");
54+
p.add(l, BorderLayout.WEST);
55+
String[] models = {"Hiyori", "Haru", "Mao", "Mark", "Natori", "Rice", "Wanko"};
56+
JComboBox<String> box = new JComboBox<>(models);
57+
box.addActionListener(e -> {
58+
String m = (String) box.getSelectedItem();
59+
sendRequest("/model?name=" + m);
60+
});
61+
p.add(box, BorderLayout.CENTER);
62+
panel.add(p);
63+
}
64+
5065
private static void addScaleSlider(JPanel panel, String label, float min, float max, float initial) {
5166
JPanel p = new JPanel(new BorderLayout());
5267
JLabel l = new JLabel(label);

example/src/main/java/dev/eatgrapes/live2d/example/Main.java

Lines changed: 119 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package dev.eatgrapes.live2d.example;
22

3+
import com.google.gson.Gson;
4+
import com.google.gson.JsonArray;
5+
import com.google.gson.JsonElement;
6+
import com.google.gson.JsonObject;
37
import com.sun.net.httpserver.HttpServer;
48
import dev.eatgrapes.live2d.CubismFramework;
59
import dev.eatgrapes.live2d.CubismUserModel;
@@ -8,14 +12,18 @@
812
import org.lwjgl.system.MemoryStack;
913

1014
import java.io.InputStream;
15+
import java.io.InputStreamReader;
16+
import java.io.Reader;
1117
import java.net.InetSocketAddress;
1218
import java.nio.ByteBuffer;
13-
import java.nio.DoubleBuffer;
1419
import java.nio.IntBuffer;
20+
import java.nio.charset.StandardCharsets;
1521
import java.nio.file.Files;
1622
import java.nio.file.Path;
1723
import java.nio.file.StandardCopyOption;
24+
import java.util.ArrayList;
1825
import java.util.HashMap;
26+
import java.util.List;
1927
import java.util.Map;
2028
import java.util.concurrent.ConcurrentLinkedQueue;
2129

@@ -26,7 +34,8 @@
2634
public class Main {
2735
private long window;
2836
private CubismUserModel model;
29-
private final Map<String, byte[]> motions = new HashMap<>();
37+
private final Map<String, List<byte[]>> motionGroups = new HashMap<>();
38+
private final List<Integer> loadedTextures = new ArrayList<>();
3039
private final float[] mvp = new float[]{1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
3140
private final ConcurrentLinkedQueue<Runnable> taskQueue = new ConcurrentLinkedQueue<>();
3241
private float modelScale = 1.0f;
@@ -46,8 +55,20 @@ private void startServer() throws Exception {
4655
String query = t.getRequestURI().getQuery();
4756
String id = query.split("=")[1];
4857
taskQueue.add(() -> {
49-
if (motions.containsKey(id)) {
50-
model.startMotion(motions.get(id), 3, false, null);
58+
String key = id.toLowerCase();
59+
if (key.equals("tap_body")) key = "tapbody";
60+
61+
List<byte[]> group = null;
62+
for (String k : motionGroups.keySet()) {
63+
if (k.equalsIgnoreCase(key)) {
64+
group = motionGroups.get(k);
65+
break;
66+
}
67+
}
68+
69+
if (group != null && !group.isEmpty()) {
70+
int idx = (int) (Math.random() * group.size());
71+
model.startMotion(group.get(idx), 3, false, null);
5172
}
5273
});
5374
t.sendResponseHeaders(200, 0);
@@ -84,6 +105,19 @@ private void startServer() throws Exception {
84105
t.sendResponseHeaders(200, 0);
85106
t.close();
86107
});
108+
server.createContext("/model", t -> {
109+
String query = t.getRequestURI().getQuery();
110+
String name = query.split("=")[1];
111+
taskQueue.add(() -> {
112+
try {
113+
loadModel(name);
114+
} catch (Exception e) {
115+
e.printStackTrace();
116+
}
117+
});
118+
t.sendResponseHeaders(200, 0);
119+
t.close();
120+
});
87121
server.setExecutor(null);
88122
server.start();
89123
System.out.println("Control server started on port 8080");
@@ -108,20 +142,77 @@ private void init() {
108142
if (model != null) model.setDragging(nx, ny);
109143
}
110144
});
145+
146+
CubismFramework.startUp();
147+
CubismFramework.initialize();
111148
}
112149

113150
private void setup() throws Exception {
114-
CubismFramework.startUp();
115-
CubismFramework.initialize();
151+
loadModel("Hiyori");
152+
}
153+
154+
private void loadModel(String name) throws Exception {
155+
if (model != null) {
156+
model.close();
157+
model = null;
158+
}
159+
for (int tex : loadedTextures) {
160+
glDeleteTextures(tex);
161+
}
162+
loadedTextures.clear();
163+
motionGroups.clear();
164+
165+
String baseDir = "/model/" + name + "/";
166+
String model3Path = baseDir + name + ".model3.json";
167+
168+
Gson gson = new Gson();
169+
JsonObject settings;
170+
try (InputStream is = getClass().getResourceAsStream(model3Path)) {
171+
if (is == null) throw new RuntimeException("Model config not found: " + model3Path);
172+
try (Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
173+
settings = gson.fromJson(reader, JsonObject.class);
174+
}
175+
}
176+
116177
model = new CubismUserModel();
117-
model.loadModel(load("/model/Hiyori/Hiyori.moc3"));
118-
model.loadPose(load("/model/Hiyori/Hiyori.pose3.json"));
119-
model.loadPhysics(load("/model/Hiyori/Hiyori.physics3.json"));
178+
179+
JsonObject refs = settings.getAsJsonObject("FileReferences");
180+
181+
String mocFile = refs.get("Moc").getAsString();
182+
model.loadModel(load(baseDir + mocFile));
183+
184+
if (refs.has("Pose")) {
185+
model.loadPose(load(baseDir + refs.get("Pose").getAsString()));
186+
}
187+
188+
if (refs.has("Physics")) {
189+
model.loadPhysics(load(baseDir + refs.get("Physics").getAsString()));
190+
}
191+
120192
model.createRenderer();
121-
model.registerTexture(0, loadTex("/model/Hiyori/Hiyori.2048/texture_00.png"));
122-
model.registerTexture(1, loadTex("/model/Hiyori/Hiyori.2048/texture_01.png"));
123-
motions.put("idle", load("/model/Hiyori/motions/Hiyori_m01.motion3.json"));
124-
motions.put("tap_body", load("/model/Hiyori/motions/Hiyori_m04.motion3.json"));
193+
194+
JsonArray textures = refs.getAsJsonArray("Textures");
195+
for (int i = 0; i < textures.size(); i++) {
196+
String texFile = textures.get(i).getAsString();
197+
model.registerTexture(i, loadTex(baseDir + texFile));
198+
}
199+
200+
if (refs.has("Motions")) {
201+
JsonObject motionsObj = refs.getAsJsonObject("Motions");
202+
for (String groupName : motionsObj.keySet()) {
203+
JsonArray groupArr = motionsObj.getAsJsonArray(groupName);
204+
List<byte[]> loadedGroup = new ArrayList<>();
205+
for (JsonElement elem : groupArr) {
206+
JsonObject m = elem.getAsJsonObject();
207+
String mFile = m.get("File").getAsString();
208+
try {
209+
loadedGroup.add(load(baseDir + mFile));
210+
} catch (Exception e) {
211+
}
212+
}
213+
motionGroups.put(groupName, loadedGroup);
214+
}
215+
}
125216
}
126217

127218
private void loop() {
@@ -138,31 +229,40 @@ private void loop() {
138229
for (int i = 0; i < 16; i++) mvp[i] = 0;
139230
mvp[0] = modelScale / aspect; mvp[5] = modelScale; mvp[10] = 1.0f; mvp[15] = 1.0f;
140231
}
141-
model.update(0.016f);
142-
model.draw(mvp);
232+
if (model != null) {
233+
model.update(0.016f);
234+
model.draw(mvp);
235+
}
143236
glfwSwapBuffers(window);
144237
glfwPollEvents();
145238
}
146239
}
147240

148241
private void cleanup() {
149-
model.close();
242+
if (model != null) model.close();
150243
CubismFramework.dispose();
151244
glfwTerminate();
152245
}
153246

154247
private byte[] load(String p) throws Exception {
155-
try (InputStream is = getClass().getResourceAsStream(p)) { return is.readAllBytes(); }
248+
try (InputStream is = getClass().getResourceAsStream(p)) {
249+
if (is == null) throw new RuntimeException("Resource not found: " + p);
250+
return is.readAllBytes();
251+
}
156252
}
157253

158254
private int loadTex(String p) throws Exception {
159255
Path tmp = Files.createTempFile("l2d", ".png");
160-
try (InputStream is = getClass().getResourceAsStream(p)) { Files.copy(is, tmp, StandardCopyOption.REPLACE_EXISTING); }
256+
try (InputStream is = getClass().getResourceAsStream(p)) {
257+
if (is == null) throw new RuntimeException("Texture not found: " + p);
258+
Files.copy(is, tmp, StandardCopyOption.REPLACE_EXISTING);
259+
}
161260
int w, h, tex;
162261
ByteBuffer img;
163262
try (MemoryStack s = MemoryStack.stackPush()) {
164263
IntBuffer wb = s.mallocInt(1), hb = s.mallocInt(1), cb = s.mallocInt(1);
165264
img = STBImage.stbi_load(tmp.toString(), wb, hb, cb, 4);
265+
if (img == null) throw new RuntimeException("Failed to load texture image: " + p);
166266
w = wb.get(); h = hb.get();
167267
}
168268
tex = glGenTextures();
@@ -174,6 +274,7 @@ private int loadTex(String p) throws Exception {
174274
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
175275
STBImage.stbi_image_free(img);
176276
Files.delete(tmp);
277+
loadedTextures.add(tex);
177278
return tex;
178279
}
179280

1.46 MB
Loading
1.13 MB
Loading

0 commit comments

Comments
 (0)