-
-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3fd6f9d
commit e36b878
Showing
6 changed files
with
303 additions
and
4 deletions.
There are no files selected for viewing
105 changes: 105 additions & 0 deletions
105
indigo-plugin/indigo-plugin/src/indigoplugin/generators/EmbedGLSLShaderPair.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package indigoplugin.generators | ||
|
||
object EmbedGLSLShaderPair { | ||
|
||
def generate( | ||
outDir: os.Path, | ||
moduleName: String, | ||
fullyQualifiedPath: String, | ||
vertex: os.Path, | ||
fragment: os.Path, | ||
runValidator: Boolean | ||
): Seq[os.Path] = { | ||
|
||
val shaderFiles: Seq[os.Path] = | ||
Seq(vertex, fragment) | ||
|
||
// Bail out if the file is missing or not a file. | ||
shaderFiles.foreach { f => | ||
if (!os.exists(f)) throw new Exception("Shader file not found: " + f.toString()) | ||
else if (os.isDir(f)) throw new Exception("Shader path given was a directory, not a file: " + f.toString()) | ||
else () | ||
} | ||
|
||
val wd = outDir / Generators.OutputDirName | ||
|
||
os.makeDir.all(wd) | ||
|
||
if (runValidator) { | ||
val glslValidatorExitCode = os.proc("glslangValidator", "-v").call(os.pwd).exitCode | ||
|
||
if (glslValidatorExitCode == 0) | ||
shaderFiles.foreach { f => | ||
val exitCode = os.proc("glslangValidator", f.toString).call(os.pwd).exitCode | ||
|
||
if (exitCode != 0) throw new Exception("GLSL Validation Error in: " + f.toString) | ||
} | ||
else | ||
throw new Exception("Validation was requested, but the GLSL Validator is not installed.") | ||
} | ||
|
||
val shaderDetails: Seq[ShaderDetails] = | ||
shaderFiles.map(f => extractDetails(f)) | ||
|
||
val contents: String = | ||
shaderDetails | ||
.flatMap { d => | ||
extractShaderCode(d.shaderCode, "vertex", d.newName) ++ | ||
extractShaderCode(d.shaderCode, "fragment", d.newName) ++ | ||
extractShaderCode(d.shaderCode, "prepare", d.newName) ++ | ||
extractShaderCode(d.shaderCode, "light", d.newName) ++ | ||
extractShaderCode(d.shaderCode, "composite", d.newName) | ||
} | ||
.map { snippet => | ||
s""" val ${snippet.variableName}: String = | ||
| ${Generators.TripleQuotes}${snippet.snippet}${Generators.TripleQuotes} | ||
| | ||
""".stripMargin | ||
} | ||
.mkString("\n") | ||
|
||
val file: os.Path = | ||
wd / s"$moduleName.scala" | ||
|
||
val newContents: String = | ||
template(moduleName, fullyQualifiedPath, contents) | ||
|
||
os.write(file, newContents) | ||
|
||
Seq(file) | ||
} | ||
|
||
def sanitiseName(name: String, ext: String): String = { | ||
val noExt = if (ext.nonEmpty && name.endsWith(ext)) name.dropRight(ext.length) else name | ||
noExt.replaceAll("[^A-Za-z0-9]", "-").split("-").map(_.capitalize).mkString | ||
} | ||
|
||
def extractDetails(file: os.Path): ShaderDetails = { | ||
val name = file.last | ||
val ext = file.ext | ||
val sanitised = sanitiseName(file.last, file.ext) | ||
|
||
ShaderDetails(sanitised, name, ext, os.read(file)) | ||
} | ||
|
||
def template(moduleName: String, fullyQualifiedPath: String, contents: String): String = | ||
s"""package $fullyQualifiedPath | ||
| | ||
|object $moduleName { | ||
| | ||
|$contents | ||
| | ||
|} | ||
""".stripMargin | ||
|
||
def extractShaderCode(text: String, tag: String, newName: String): List[ShaderSnippet] = | ||
s"""//<indigo-$tag>\n((.|\n|\r)*)//</indigo-$tag>""".r | ||
.findAllIn(text) | ||
.toList | ||
.map(_.toString) | ||
.map(_.split('\n').drop(1).dropRight(1).mkString("\n")) | ||
.map(program => ShaderSnippet(newName + tag.split("-").map(_.capitalize).mkString, program)) | ||
|
||
case class ShaderDetails(newName: String, originalName: String, ext: String, shaderCode: String) | ||
case class ShaderSnippet(variableName: String, snippet: String) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
indigo-plugin/indigo-plugin/src/indigoplugin/generators/Generators.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package indigoplugin.generators | ||
|
||
object Generators { | ||
|
||
val OutputDirName: String = "indigo-compile-codegen-output" | ||
val TripleQuotes: String = "\"\"\"" | ||
|
||
} |
148 changes: 148 additions & 0 deletions
148
indigo-plugin/indigo-plugin/test/src/indigoplugin/generators/EmbedGLSLShaderPairTests.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package indigoplugin.generators | ||
|
||
class EmbedGLSLShaderPairTests extends munit.FunSuite { | ||
|
||
test("sanitiseName") { | ||
assertEquals(EmbedGLSLShaderPair.sanitiseName("Ha_ erm!What?...12!.vert", "vert"), "HaErmWhat12") | ||
} | ||
|
||
test("template") { | ||
val actual = | ||
EmbedGLSLShaderPair.template("MyModule", "org.example", "// code goes here.") | ||
|
||
val expected = | ||
s"""package org.example | ||
| | ||
|object MyModule { | ||
| | ||
|// code goes here. | ||
| | ||
|} | ||
""".stripMargin | ||
|
||
assertEquals(actual.trim, expected.trim) | ||
} | ||
|
||
test("extractShaderCode - vertex") { | ||
val actual = | ||
EmbedGLSLShaderPair.extractShaderCode(sampleVertexProgram, "vertex", "MyShader") | ||
|
||
val expected = | ||
List( | ||
EmbedGLSLShaderPair.ShaderSnippet( | ||
"MyShaderVertex", | ||
"void vertex(){}" | ||
) | ||
) | ||
|
||
assertEquals(actual, expected) | ||
} | ||
|
||
test("extractShaderCode - fragment") { | ||
val actual = | ||
EmbedGLSLShaderPair.extractShaderCode(sampleFragmentProgram, "fragment", "MyShader") | ||
|
||
val expected = | ||
List( | ||
EmbedGLSLShaderPair.ShaderSnippet( | ||
"MyShaderFragment", | ||
""" | ||
layout (std140) uniform IndigoBitmapData { | ||
highp float FILLTYPE; | ||
}; | ||
void fragment(){ | ||
// 0 = normal; 1 = stretch; 2 = tile | ||
int fillType = int(round(FILLTYPE)); | ||
vec4 textureColor; | ||
switch(fillType) { | ||
case 0: | ||
textureColor = CHANNEL_0; | ||
break; | ||
case 1: | ||
vec2 stretchedUVs = CHANNEL_0_POSITION + UV * CHANNEL_0_SIZE; | ||
textureColor = texture(SRC_CHANNEL, stretchedUVs); | ||
break; | ||
case 2: | ||
vec2 tiledUVs = CHANNEL_0_POSITION + (fract(UV * (SIZE / TEXTURE_SIZE)) * CHANNEL_0_SIZE); | ||
textureColor = texture(SRC_CHANNEL, tiledUVs); | ||
break; | ||
default: | ||
textureColor = CHANNEL_0; | ||
break; | ||
} | ||
COLOR = textureColor; | ||
} | ||
""".trim | ||
) | ||
) | ||
|
||
assertEquals(actual, expected) | ||
} | ||
|
||
val sampleVertexProgram: String = | ||
""" | ||
//<indigo-vertex> | ||
void vertex(){} | ||
//</indigo-vertex> | ||
""" | ||
|
||
val sampleFragmentProgram: String = | ||
""" | ||
#version 300 es | ||
precision mediump float; | ||
uniform sampler2D SRC_CHANNEL; | ||
vec4 CHANNEL_0; | ||
vec4 COLOR; | ||
vec2 UV; | ||
vec2 TEXTURE_SIZE; | ||
vec2 SIZE; | ||
vec2 CHANNEL_0_POSITION; | ||
vec2 CHANNEL_0_SIZE; | ||
//<indigo-fragment> | ||
layout (std140) uniform IndigoBitmapData { | ||
highp float FILLTYPE; | ||
}; | ||
void fragment(){ | ||
// 0 = normal; 1 = stretch; 2 = tile | ||
int fillType = int(round(FILLTYPE)); | ||
vec4 textureColor; | ||
switch(fillType) { | ||
case 0: | ||
textureColor = CHANNEL_0; | ||
break; | ||
case 1: | ||
vec2 stretchedUVs = CHANNEL_0_POSITION + UV * CHANNEL_0_SIZE; | ||
textureColor = texture(SRC_CHANNEL, stretchedUVs); | ||
break; | ||
case 2: | ||
vec2 tiledUVs = CHANNEL_0_POSITION + (fract(UV * (SIZE / TEXTURE_SIZE)) * CHANNEL_0_SIZE); | ||
textureColor = texture(SRC_CHANNEL, tiledUVs); | ||
break; | ||
default: | ||
textureColor = CHANNEL_0; | ||
break; | ||
} | ||
COLOR = textureColor; | ||
} | ||
//</indigo-fragment> | ||
""" | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters