1 module creator.io.inpexport;
2 import creator.atlas;
3 import creator.ext;
4 import inochi2d;
5 
6 private {
7     vec2 mapUVCoord(vec2 value, vec2 min, vec2 max) {
8         vec2 range = max - min;
9         vec2 tmp = (value - min);
10         vec2 off = vec2(tmp.x / range.x, tmp.y / range.y);
11 
12         vec2 clamped = vec2(
13             clamp(off.x, 0, 1),
14             clamp(off.y, 0, 1),
15         );
16         return clamped;
17     }
18 }
19 
20 void incExportINP(Puppet origin, Atlas[] atlasses, string file) {
21     Puppet editable = inLoadINPPuppet(inWriteINPPuppetMemory(origin));
22     
23     // Apply all atlasses
24     foreach(Part part; editable.getAllParts()) {
25         foreach(Atlas atlas; atlasses) {
26             
27             // Look for our part in the atlas
28             if (part.uuid in atlas.mappings) {
29 
30                 // This will remap the UV coordinates of the part
31                 // To 0..1 range if need be.
32                 vec2[] uvs = part.getMesh().uvs.dup;
33                 vec4 uvArea = vec4(1, 1, 0, 0);
34                 foreach(vec2 uv; uvs) {
35                     if (uv.x < uvArea.x) uvArea.x = uv.x;
36                     if (uv.y < uvArea.y) uvArea.y = uv.y;
37                     if (uv.x > uvArea.z) uvArea.z = uv.x;
38                     if (uv.y > uvArea.w) uvArea.w = uv.y;
39                 }
40                 vec2 minUV = uvArea.xy;
41                 vec2 maxUV = uvArea.zw;
42                 foreach(ref uv; uvs) uv = uv.mapUVCoord(minUV, maxUV);
43 
44                 // Now we need to scale those UV coordinates to fit within the mapping
45                 float atlasSize = cast(float)atlas.textures[0].width;
46                 rect mapping = atlas.mappings[part.uuid];
47                 foreach(ref uv; uvs) {
48                     uv.x = (mapping.x+(uv.x*mapping.width))/atlasSize;
49                     uv.y = (mapping.y+(uv.y*mapping.height))/atlasSize;
50                 }
51 
52                 // Apply our UVs
53                 part.getMesh().uvs = uvs;
54 
55                 // Finally apply our atlas textures to the part
56                 foreach(i; 0..TextureUsage.COUNT) {
57                     part.textures[i] = atlas.textures[i];
58                 }
59 
60                 break;
61             }
62         }
63     }
64 
65     // Flatten all parameter groups
66     Parameter[] params;
67     foreach(i, ref param; editable.parameters) {
68         import std.array : insertInPlace;
69         if (auto group = cast(ExParameterGroup)param) params ~= group.children;
70         else params ~= param;
71     }
72     editable.parameters = params;
73 
74     // Remove cameras
75     foreach(ref camera; editable.findNodesType!ExCamera(editable.root)) {
76         camera.parent = null;
77     }
78 
79     editable.populateTextureSlots();
80     inWriteINPPuppet(editable, file);
81 }