Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
xian committed Nov 3, 2022
1 parent 0e8e0d2 commit 21498d3
Show file tree
Hide file tree
Showing 20 changed files with 473 additions and 136 deletions.
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ org.gradle.console=rich

kotlin.code.style=official

kotlin.build.report.output=file

# TODO: busted, see https://github.com/Kotlin/dukat/issues/207#issuecomment-581559041
#kotlin.js.experimental.generateKotlinExternals=true
71 changes: 33 additions & 38 deletions src/commonMain/kotlin/baaahs/gl/glsl/GlslCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,38 +63,30 @@ class GlslCode(

companion object {
private val logger = Logger<GlslCode>()
}

fun rewriteFunctionBody(originalText: String, symbolSubstitutionFn: (String) -> String): String {
val buf = StringBuilder()
interface StatementRewriter : GlslParser.Tokenizer.State {
fun substitute(text: String): String

var inComment = false
var inDotTraversal = false
GlslParser.Tokenizer().tokenize(originalText).forEach { str ->
when (str) {
"//" -> {
inComment = true; buf.append(str)
}
"." -> {
if (!inComment) inDotTraversal = true; buf.append(str)
}
"\n" -> {
inComment = false; buf.append(str)
}
else -> {
buf.append(
if (inComment || inDotTraversal) str
else symbolSubstitutionFn(str)
)
inDotTraversal = false
}
}
}
return buf.toString()
}
/** Yuck, this is horrible. */
fun drain(): String
}

fun interface Substitutions {
fun substitute(word: String): String
class TokenRewriter(
private val substitutionFn: (String) -> String
) : StatementRewriter {
private val buf: StringBuilder = StringBuilder()

override fun substitute(text: String): String =
substitutionFn.invoke(text)

override fun visit(token: String): GlslParser.Tokenizer.State {
buf.append(substitute(token))
return this
}

override fun drain(): String =
buf.toString().also { buf.clear() }
}

interface GlslStatement {
Expand All @@ -103,13 +95,16 @@ class GlslCode(
val lineNumber: Int?
val comments: List<String>

fun toGlsl(fileNumber: Int?, substitutions: Substitutions): String {
return substituteGlsl(fullText, substitutions, fileNumber)
fun toGlsl(fileNumber: Int?, statementRewriter: StatementRewriter): String {
return substituteGlsl(fullText, statementRewriter, fileNumber)
}

fun substituteGlsl(text: String, substitutions: Substitutions, fileNumber: Int?): String {
fun substituteGlsl(text: String, statementRewriter: StatementRewriter, fileNumber: Int?): String {
return lineNumber?.let { "\n#line $lineNumber${fileNumber?.let { " $it" } ?: ""}\n" } +
rewriteFunctionBody(text) { substitutions.substitute(it) }
run {
GlslParser.Tokenizer().processTokens(text, statementRewriter)
statementRewriter.drain()
}
}
}

Expand Down Expand Up @@ -170,16 +165,16 @@ class GlslCode(
override val hint: Hint? by lazy { Hint.parse(comments.joinToString(" ") { it.trim() }, lineNumber) }
val deferInitialization: Boolean = !isConst && initExpr != null

fun declarationToGlsl(fileNumber: Int?, substitutions: Substitutions): String {
fun declarationToGlsl(fileNumber: Int?, statementRewriter: StatementRewriter): String {
val declaration = if (deferInitialization) {
fullText.substring(0, fullText.indexOf(initExpr!!)) + ";"
} else fullText
return substituteGlsl(declaration, substitutions, fileNumber)
return substituteGlsl(declaration, statementRewriter, fileNumber)
}

fun assignmentToGlsl(fileNumber: Int?, substitutions: Substitutions): String {
fun assignmentToGlsl(fileNumber: Int?, statementRewriter: StatementRewriter): String {
val assignment = " $name$initExpr;"
return substituteGlsl(assignment, substitutions, fileNumber)
return substituteGlsl(assignment, statementRewriter, fileNumber)
}
}

Expand Down Expand Up @@ -263,9 +258,9 @@ class GlslCode(
return params.associate { it.name to (it.findContentType(plugins, this) ?: ContentType.Unknown) }
}

override fun toGlsl(fileNumber: Int?, substitutions: Substitutions): String {
override fun toGlsl(fileNumber: Int?, statementRewriter: StatementRewriter): String {
// Chomp trailing ';' if it's an abstract method.
return super.toGlsl(fileNumber, substitutions)
return super.toGlsl(fileNumber, statementRewriter)
.let { if (isAbstract) it.trimEnd(';') else it }
}

Expand Down
16 changes: 8 additions & 8 deletions src/commonMain/kotlin/baaahs/gl/glsl/GlslParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ class GlslParser {
return tokenizationPattern.findAll(text).map { it.groupValues[0] }
}

fun <S: State<S>> processTokens(
fun processTokens(
text: String,
initialState: S,
initialState: State,
freezeLineNumber: Boolean = false
): S {
): State {
var state = initialState
tokenize(text).forEach { token ->
if (!freezeLineNumber && token == "\n") lineNumber++
Expand All @@ -43,8 +43,8 @@ class GlslParser {
return state
}

interface State<S: State<S>> {
fun visit(token: String): S
interface State {
fun visit(token: String): State
}
}

Expand All @@ -67,7 +67,7 @@ class GlslParser {
initialState: ParseState,
freezeLineNumber: Boolean = false
): ParseState {
return tokenizer.processTokens(text, initialState, freezeLineNumber)
return tokenizer.processTokens(text, initialState, freezeLineNumber) as ParseState
}

fun doUndef(args: List<String>) {
Expand Down Expand Up @@ -123,6 +123,7 @@ class GlslParser {

tokenizer.processTokens(macro.replacement.trim(), parseState, freezeLineNumber = true)
.also { macroDepth-- }
as ParseState
}
else -> ParseState.MacroExpansion(this, parseState, macro)
}
Expand All @@ -137,7 +138,7 @@ class GlslParser {
val replacement: String
)

private sealed class ParseState(val context: Context) : Tokenizer.State<ParseState> {
private sealed class ParseState(val context: Context) : Tokenizer.State {
companion object {
fun initial(context: Context): ParseState =
UnidentifiedStatement(context)
Expand Down Expand Up @@ -177,7 +178,6 @@ class GlslParser {
}

open fun visitText(value: String): ParseState {
println("value = ${value}")
return if (context.outputEnabled || value == "\n") {
context.checkForMacro(value, this)
?: run {
Expand Down
5 changes: 2 additions & 3 deletions src/commonMain/kotlin/baaahs/gl/patch/ShaderComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ class ShaderComponent(
link: ProgramNode
) {
val fn = inputPort.glslArgSite as GlslCode.GlslFunction
buf.append(fn.toGlsl(index) {
buf.append(fn.toGlsl(index, GlslCode.TokenRewriter {
if (it == fn.name) namespace.qualify(it) else it
})
}))
val destComponent = findUpstreamComponent(link)
buf.append(" {\n")
destComponent.appendInvokeAndReturn(buf, inputPort)
Expand Down Expand Up @@ -167,5 +167,4 @@ class ShaderComponent(
}

override fun toString(): String = "ShaderComponent(${prefix}_$id)"

}
17 changes: 15 additions & 2 deletions src/commonMain/kotlin/baaahs/gl/patch/UnresolvedPatches.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,23 @@ import baaahs.show.mutable.MutablePatchSet
import baaahs.util.Logger

class UnresolvedPatches(private val unresolvedPatches: List<UnresolvedPatch>) {
fun find(predicate: (UnresolvedPatch) -> Boolean) =
unresolvedPatches.find(predicate)

fun editShader(title: String, callback: UnresolvedPatch.() -> Unit): UnresolvedPatches =
editShader({ it.mutableShader.title == title }, callback)

fun editShader(predicate: (UnresolvedPatch) -> Boolean, callback: UnresolvedPatch.() -> Unit): UnresolvedPatches {
val match = find(predicate)
?: error("Couldn't find shader.")
match.callback()
return this
}

fun editShader(shader: Shader, callback: UnresolvedPatch.() -> Unit): UnresolvedPatches {
// TODO: src == src is probably the wrong check here:
val match = (unresolvedPatches.find { it.mutableShader.src == shader.src }
?: error("Couldn't find shader \"${shader.title}\""))
val match = find { it.mutableShader.src == shader.src }
?: error("Couldn't find shader \"${shader.title}\"")
match.callback()
return this
}
Expand Down
56 changes: 47 additions & 9 deletions src/commonMain/kotlin/baaahs/gl/shader/OpenShader.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package baaahs.gl.shader

import baaahs.app.ui.patchmod.*
import baaahs.gl.glsl.*
import baaahs.gl.glsl.GlslCode.GlslFunction
import baaahs.gl.glsl.GlslCode.Namespace
Expand Down Expand Up @@ -39,7 +38,10 @@ interface OpenShader : RefCounted {
(inputPorts.map { it.contentType.glslType } + outputPort.contentType.glslType)
.filterIsInstance<GlslType.Struct>()

fun toGlsl(fileNumber: Int?, substitutions: GlslCode.Substitutions): String
fun toGlsl(fileNumber: Int?, substitutions: ShaderSubstitutions) =
toGlsl(fileNumber, shaderDialect.buildStatementRewriter(substitutions))

fun toGlsl(fileNumber: Int?, statementRewriter: GlslCode.StatementRewriter): String

fun invoker(
namespace: Namespace,
Expand Down Expand Up @@ -67,24 +69,24 @@ interface OpenShader : RefCounted {

override val requiresInit = globalVars.any { it.deferInitialization }

override fun toGlsl(fileNumber: Int?, substitutions: GlslCode.Substitutions): String {
override fun toGlsl(fileNumber: Int?, statementRewriter: GlslCode.StatementRewriter): String {
val buf = StringBuilder()
globalVars.forEach { glslVar ->
buf.append(glslVar.declarationToGlsl(fileNumber, substitutions))
buf.append(glslVar.declarationToGlsl(fileNumber, statementRewriter))
buf.append("\n")
}

glslCode.functions.filterNot { it.isAbstract }.forEach { glslFunction ->
buf.append(glslFunction.toGlsl(fileNumber, substitutions))
buf.append(glslFunction.toGlsl(fileNumber, statementRewriter))
buf.append("\n")
}

if (requiresInit) {
buf.append("\n")
buf.append("void ${substitutions.substitute(ShaderSubstitutions.initFnName)}() {")
buf.append("void ${statementRewriter.substitute(ShaderSubstitutions.initFnName)}() {")
globalVars.forEach {
if (it.deferInitialization) {
buf.append(" ${it.assignmentToGlsl(fileNumber, substitutions)}\n")
buf.append(" ${it.assignmentToGlsl(fileNumber, statementRewriter)}\n")
}
}
buf.append("}\n")
Expand All @@ -108,11 +110,47 @@ interface OpenShader : RefCounted {
}
}

open class ShaderStatementRewriter(
private val shaderSubstitutions: ShaderSubstitutions
) : GlslCode.StatementRewriter {
private val buf = StringBuilder()
protected var inComment = false
protected var inDotTraversal = false

override fun visit(token: String): GlslParser.Tokenizer.State {
when (token) {
"//" -> {
inComment = true; buf.append(token)
}
"." -> {
if (!inComment) inDotTraversal = true; buf.append(token)
}
"\n" -> {
inComment = false; buf.append(token)
}
else -> {
buf.append(
if (inComment || inDotTraversal) token
else shaderSubstitutions.substitute(token)
)
inDotTraversal = false
}
}
return this
}

override fun substitute(text: String): String =
shaderSubstitutions.substitute(text)

override fun drain(): String =
buf.toString().also { buf.clear() }
}

class ShaderSubstitutions(
val openShader: OpenShader,
val namespace: Namespace,
portMap: Map<String, GlslExpr>
) : GlslCode.Substitutions {
) {
private val uniformGlobalsMap = portMap.filter { (id, _) ->
val inputPort = openShader.findInputPortOrNull(id)
inputPort?.isGlobal == true ||
Expand All @@ -131,7 +169,7 @@ class ShaderSubstitutions(

private val symbolMap = uniformGlobalsMap + nonUniformGlobalsMap + specialSymbols

override fun substitute(word: String): String =
fun substitute(word: String): String =
symbolMap[word]?.s
?: if (symbolsToNamespace.contains(word)) {
namespace.qualify(word)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package baaahs.gl.shader.dialect

import baaahs.gl.shader.ShaderStatementRewriter
import baaahs.gl.shader.ShaderSubstitutions

abstract class BaseShaderDialect(
override val id: String
) : ShaderDialect
) : ShaderDialect {
override fun buildStatementRewriter(substitutions: ShaderSubstitutions) =
ShaderStatementRewriter(substitutions)
}
Loading

0 comments on commit 21498d3

Please sign in to comment.