ソースを参照

Struct pre-preprocessor directive

Riccardo Balbo 1 年間 前
コミット
e3db2a3f75

+ 48 - 0
jme3-core/src/test/java/com/jme3/shader/GLSLPreprocessorTest.java

@@ -75,4 +75,52 @@ public class GLSLPreprocessorTest {
         String sourceCheck=readAllAsString(testData.openStream());
         assertEquals(sourceCheck, processedSource);                  
     }
+
+    @Test
+    public void testStruct() throws Exception {
+            String source = "// nothing\n#struct MyStruct \n" + "  float x ;//nothing  \n" + "     float y;\n"
+                            + "#endstruct\n//nothing";
+            String processedSource = readAllAsString(
+                            Preprocessor.apply(new ByteArrayInputStream(source.getBytes("UTF-8"))));
+            System.out.println(processedSource);
+            AssetInfo testData = TestUtil.createAssetManager()
+                            .locateAsset(new AssetKey("GLSLPreprocessorTest.testStruct.validOutput"));
+            assertNotNull(testData);
+            String sourceCheck = readAllAsString(testData.openStream());
+            assertEquals(sourceCheck, processedSource);
+    }
+
+    @Test
+    public void testStructExtends() throws Exception {
+            String source = "// nothing\n#struct BaseStruct \n" + "  float x0;\n" + "  float y0;\n"
+                            + "#endstruct\n//nothing\n";
+            source += "//nothing\n#struct MyStruct extends BaseStruct \n" + "  float x;\n" + "  float y;\n"
+                            + "#endstruct\n//nothing\n";
+            String processedSource = readAllAsString(
+                            Preprocessor.apply(new ByteArrayInputStream(source.getBytes("UTF-8"))));
+            System.out.println(processedSource);
+            AssetInfo testData = TestUtil.createAssetManager()
+                            .locateAsset(new AssetKey("GLSLPreprocessorTest.testStructExtends.validOutput"));
+            assertNotNull(testData);
+            String sourceCheck = readAllAsString(testData.openStream());
+            assertEquals(sourceCheck, processedSource);
+    }
+
+    @Test
+    public void testStructExtendsMulti() throws Exception {
+            String source = "#struct BaseStruct \n" + "  float x0;\n" + "  float y0;\n" + "#endstruct\n";
+            source += "#struct BaseStruct2 \n" + "  float x1;\n" + "  float y1;\n"
+                            + "#endstruct\n//nothing\n";
+            source += "#struct MyStruct extends BaseStruct, BaseStruct2\n" + "  float x;\n" + "  float y;\n"
+                            + "#endstruct\n";
+            String processedSource = readAllAsString(
+                            Preprocessor.apply(new ByteArrayInputStream(source.getBytes("UTF-8"))));
+            System.out.println(processedSource);
+            AssetInfo testData = TestUtil.createAssetManager().locateAsset(
+                            new AssetKey("GLSLPreprocessorTest.testStructExtendsMulti.validOutput"));
+            assertNotNull(testData);
+            String sourceCheck = readAllAsString(testData.openStream());
+            assertEquals(sourceCheck, processedSource);
+    }
+
 }

+ 8 - 0
jme3-core/src/test/resources/GLSLPreprocessorTest.testStruct.validOutput

@@ -0,0 +1,8 @@
+// nothing
+#define STRUCT_MyStruct \
+float x ; \
+float y;
+struct MyStruct { 
+STRUCT_MyStruct
+};
+//nothing

+ 17 - 0
jme3-core/src/test/resources/GLSLPreprocessorTest.testStructExtends.validOutput

@@ -0,0 +1,17 @@
+// nothing
+#define STRUCT_BaseStruct \
+float x0; \
+float y0;
+struct BaseStruct { 
+STRUCT_BaseStruct
+};
+//nothing
+//nothing
+#define STRUCT_MyStruct \
+STRUCT_BaseStruct \
+float x; \
+float y;
+struct MyStruct { 
+STRUCT_MyStruct
+};
+//nothing

+ 21 - 0
jme3-core/src/test/resources/GLSLPreprocessorTest.testStructExtendsMulti.validOutput

@@ -0,0 +1,21 @@
+#define STRUCT_BaseStruct \
+float x0; \
+float y0;
+struct BaseStruct { 
+STRUCT_BaseStruct
+};
+#define STRUCT_BaseStruct2 \
+float x1; \
+float y1;
+struct BaseStruct2 { 
+STRUCT_BaseStruct2
+};
+//nothing
+#define STRUCT_MyStruct \
+STRUCT_BaseStruct \
+STRUCT_BaseStruct2 \
+float x; \
+float y;
+struct MyStruct { 
+STRUCT_MyStruct
+};

+ 93 - 0
jme3-core/src/tools/java/jme3tools/shader/Preprocessor.java

@@ -58,6 +58,7 @@ public class Preprocessor {
         String code = bos.toString("UTF-8");
 
         code = Preprocessor.forMacro(code);
+        code = Preprocessor.structMacro(code);
 
         return new ByteArrayInputStream(code.getBytes("UTF-8"));
     }
@@ -118,4 +119,96 @@ public class Preprocessor {
         return code;
     }
 
+    /**
+     * <code>
+     * #struct MyStruct extends BaseStruct, BaseStruct2
+     *  int i; 
+     *  int b; 
+     * #endstruct
+     * </code>
+     */
+    // match #struct MyStruct extends BaseStruct, BaseStruct2
+    // extends is optional
+    // private static final Pattern FOR_REGEX = Pattern
+    // .compile("([^=]+)=\\s*([0-9]+)\\s*\\.\\.\\s*([0-9]+)\\s*\\((.+)\\)");
+
+    private static final Pattern STRUCT_REGEX = Pattern
+            .compile("(\\w+)(?:\\s+extends\\s+(\\w+(?:,\\s*\\w+)*))?");
+
+    public static String structMacro(String code) {
+        StringBuilder expandedCode = new StringBuilder();
+        StringBuilder currentStruct = null;
+        String structDec = null;
+        int skip = 0;
+        String[] codeLines = code.split("\n");
+        boolean captured = false;
+        for (String line : codeLines) {
+            if (!captured) {
+                String trimmedLine = line.trim();
+                if (trimmedLine.startsWith("#struct")) {
+                    if (skip == 0) {
+                        structDec = trimmedLine;
+                        currentStruct = new StringBuilder();
+                        skip++;
+                        continue;
+                    }
+                    skip++;
+                } else if (trimmedLine.startsWith("#endstruct")) {
+                    skip--;
+                    if (skip == 0) {
+                        structDec = structDec.substring("#struct ".length()).trim();
+
+                        Matcher matcher = STRUCT_REGEX.matcher(structDec);
+                        if (matcher.matches()) {
+                            String structName = matcher.group(1);
+                            if (structName == null) structName = "";
+
+                            String extendsStructs = matcher.group(2);
+                            String extendedStructs[];
+                            if (extendsStructs != null) {
+                                extendedStructs = extendsStructs.split(",\\s*");
+                            } else {
+                                extendedStructs = new String[0];
+                            }
+                            String structBody = currentStruct.toString();
+                            if (structBody == null) structBody = "";
+                            else {
+                                // remove tail spaces
+                                structBody = structBody.replaceAll("\\s+$", "");
+                            }
+
+                            currentStruct = null;
+                            expandedCode.append("#define STRUCT_").append(structName).append(" \\\n");
+                            for (String extendedStruct : extendedStructs) {
+                                expandedCode.append("STRUCT_").append(extendedStruct).append(" \\\n");
+                            }
+                            String structBodyLines[] = structBody.split("\n");
+                            for (int i = 0; i < structBodyLines.length; i++) {
+                                String structBodyLine = structBodyLines[i];
+                                structBodyLine = structBodyLine.trim();
+                                if (structBodyLine == "") continue;
+                                // remove comments if any
+                                int commentIndex = structBodyLine.indexOf("//");
+                                if (commentIndex >= 0)
+                                    structBodyLine = structBodyLine.substring(0, commentIndex);
+                                expandedCode.append(structBodyLine);
+                                if (i < structBodyLines.length - 1) expandedCode.append(" \\");
+                                expandedCode.append("\n");
+                            }
+                            expandedCode.append("struct ").append(structName).append(" { \nSTRUCT_")
+                                    .append(structName).append("\n};\n");
+                            captured = true;
+                            continue;
+                        }
+                    }
+                }
+            }
+            if (currentStruct != null) currentStruct.append(line).append("\n");
+            else expandedCode.append(line).append("\n");
+        }
+        code = expandedCode.toString();
+        if (captured) code = structMacro(code);
+        return code;
+    }
+
 }