Skip to content

Commit

Permalink
Almost working shader parser... comments don't quite work properly th…
Browse files Browse the repository at this point in the history
…ough
  • Loading branch information
Tom Brunoli committed Feb 16, 2016
1 parent 5c6e3e4 commit 6ad82a8
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 68 deletions.
5 changes: 5 additions & 0 deletions Quake 3 BSP Renderer/Q3ResourceLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ class Q3ResourceLoader {
return nil
}

func loadShader(path: String) -> String? {
guard let shader = loadResource(path) else { return nil }
return String(data: shader, encoding: NSASCIIStringEncoding)
}

// Finds a resource at path within the data file, and returns the contents
// as NSData if it can be found
private func loadResource(path: String) -> NSData? {
Expand Down
12 changes: 6 additions & 6 deletions Quake 3 BSP Renderer/Q3Shader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,11 @@ struct Q3ShaderStage {
}

struct Q3Shader {
let name: String
let cull: Cull
var name: String = ""
var cull: Cull = .Front
// sky
let blend: Bool
let sort: Int
let vertexDeforms: Array<VertexDeform>
let stages: Array<Q3ShaderStage>
var blend: Bool = false
var sort: Sort = .Opaque
var vertexDeforms: Array<VertexDeform> = []
var stages: Array<Q3ShaderStage> = []
}
177 changes: 123 additions & 54 deletions Quake 3 BSP Renderer/Q3ShaderParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class Q3ShaderParser {
case InvalidTextureCoordinateMod(reason: String)
case InvalidStage(reason: String)
case InvalidShader(reason: String)
case UnknownToken(String)
case EndOfData
}

let scanner: NSScanner
Expand All @@ -31,8 +33,25 @@ class Q3ShaderParser {

}

private func readString() -> String? {
return scanner.scanUpToCharactersFromSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
private func readString() throws -> String {
guard let str = scanner.scanUpToCharactersFromSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) else {
throw Q3ShaderParserError.EndOfData
}

return str
}

private func skipLine() {
scanner.scanUpToCharactersFromSet(NSCharacterSet.newlineCharacterSet())!
}

private func skipBlockComment() {
while true {
let token = try! readString()
if token.hasSuffix("*/") {
return
}
}
}

private func readSourceBlendMode(sourceBlendMode: String) throws -> SourceBlendMode {
Expand All @@ -43,7 +62,7 @@ class Q3ShaderParser {
case "GL_ONE_MINUS_DST_COLOR": return .OneMinusDestColor
case "GL_SRC_ALPHA": return .SourceAlpha
case "GL_ONE_MINUS_SRC_ALPHA": return .OneMinusSourceAlpha
default: throw Q3ShaderParserError.InvalidSourceBlendMode(got: sourceBlendMode)
default: throw Q3ShaderParserError.UnknownToken(sourceBlendMode)
}
}

Expand All @@ -55,42 +74,40 @@ class Q3ShaderParser {
case "GL_ONE_MINUS_SRC_COLOR": return .OneMinusSourceColor
case "GL_SRC_ALPHA": return .SourceAlpha
case "GL_ONE_MINUS_SRC_ALPHA": return .OneMinusSourceAlpha
default: throw Q3ShaderParserError.InvalidDestBlendMode(got: destBlendMode)
default: throw Q3ShaderParserError.UnknownToken(destBlendMode)
}
}

private func readWaveformFunction() throws -> WaveformFunction {
guard let waveformFunction = readString() else {
throw Q3ShaderParserError.InvalidWaveformFunction(got: nil)
}
let waveformFunction = try! readString()

switch waveformFunction {
case "sin": return .Sin
case "triangle": return .Triangle
case "square": return .Square
case "sawtooth": return .Sawtooth
case "inversesawtooth": return .InverseSawtooth
default: throw Q3ShaderParserError.InvalidWaveformFunction(got: waveformFunction)
default: throw Q3ShaderParserError.UnknownToken(waveformFunction)
}
}

private func readWaveform() throws -> Waveform {
let waveformFunction = try readWaveformFunction()

guard let base = scanner.scanFloat() else {
throw Q3ShaderParserError.InvalidWaveform(reason: "base")
throw Q3ShaderParserError.EndOfData
}

guard let amplitude = scanner.scanFloat() else {
throw Q3ShaderParserError.InvalidWaveform(reason: "amplitude")
throw Q3ShaderParserError.EndOfData
}

guard let phase = scanner.scanFloat() else {
throw Q3ShaderParserError.InvalidWaveform(reason: "phase")
throw Q3ShaderParserError.EndOfData
}

guard let frequency = scanner.scanFloat() else {
throw Q3ShaderParserError.InvalidWaveform(reason: "frequency")
throw Q3ShaderParserError.EndOfData
}

return Waveform(
Expand All @@ -103,9 +120,7 @@ class Q3ShaderParser {
}

private func readSort() throws -> Sort {
guard let sort = readString() else {
throw Q3ShaderParserError.InvalidSort(got: nil)
}
let sort = try! readString()

switch sort {
case "portal": return .Portal
Expand All @@ -127,19 +142,19 @@ class Q3ShaderParser {

private func readTurbulance() throws -> TurbulanceDescription {
guard let base = scanner.scanFloat() else {
throw Q3ShaderParserError.InvalidTurbulance(reason: "base")
throw Q3ShaderParserError.EndOfData
}

guard let amplitude = scanner.scanFloat() else {
throw Q3ShaderParserError.InvalidTurbulance(reason: "amplitude")
throw Q3ShaderParserError.EndOfData
}

guard let phase = scanner.scanFloat() else {
throw Q3ShaderParserError.InvalidTurbulance(reason: "phase")
throw Q3ShaderParserError.EndOfData
}

guard let frequency = scanner.scanFloat() else {
throw Q3ShaderParserError.InvalidTurbulance(reason: "frequency")
throw Q3ShaderParserError.EndOfData
}

return TurbulanceDescription(
Expand All @@ -151,9 +166,7 @@ class Q3ShaderParser {
}

private func readTextureCoordinateMod() throws -> TextureCoordinateMod {
guard let type = readString() else {
throw Q3ShaderParserError.InvalidTextureCoordinateMod(reason: "No Type")
}
let type = try! readString()

switch type {
case "turb":
Expand Down Expand Up @@ -226,9 +239,7 @@ class Q3ShaderParser {
func readStage() throws -> Q3ShaderStage {
var stage = Q3ShaderStage()

guard var token = readString() else {
throw Q3ShaderParserError.InvalidStage(reason: "")
}
var token = try! readString()

while true {
print("got token: \(token)")
Expand All @@ -237,13 +248,16 @@ class Q3ShaderParser {
if token.hasPrefix("//") {
scanner.scanUpToCharactersFromSet(NSCharacterSet.newlineCharacterSet())
continue
} else if token.hasPrefix("/*") {
skipBlockComment()
continue
}

switch token.lowercaseString {
case "map": stage.map = readString()
case "map": stage.map = try! readString()

case "clampmap":
let clampmap = readString()
let clampmap = try! readString()
print("clampmap: \(clampmap)")

case "animmap":
Expand All @@ -257,7 +271,7 @@ class Q3ShaderParser {

// Read each animation map
while true {
let map = readString()!
let map = try! readString()

if !map.hasSuffix(".tga") {
token = map
Expand All @@ -272,9 +286,7 @@ class Q3ShaderParser {
continue

case "alphafunc":
guard let alphaFunc = readString() else {
throw Q3ShaderParserError.InvalidStage(reason: "alphafunc")
}
let alphaFunc = try! readString()

switch alphaFunc {
case "GT0": stage.alphaFunction = .GT0
Expand All @@ -284,9 +296,7 @@ class Q3ShaderParser {
}

case "depthfunc":
guard let depthFunc = readString() else {
throw Q3ShaderParserError.InvalidStage(reason: "depthFunc")
}
let depthFunc = try! readString()

switch depthFunc {
case "lequal": stage.depthFunction = .LessThanOrEqual
Expand All @@ -295,9 +305,7 @@ class Q3ShaderParser {
}

case "blendfunc":
guard let blendfunc = readString() else {
throw Q3ShaderParserError.InvalidStage(reason: "blendfunc")
}
let blendfunc = try! readString()

switch blendfunc {
case "add":
Expand All @@ -312,17 +320,13 @@ class Q3ShaderParser {
default:
stage.blendSource = try readSourceBlendMode(blendfunc)

guard let destBlend = readString() else {
throw Q3ShaderParserError.InvalidStage(reason: "dest blend mode")
}
let destBlend = try! readString()

stage.blendDest = try readDestBlendMode(destBlend)
}

case "rgbgen":
guard let gen = readString() else {
throw Q3ShaderParserError.InvalidStage(reason: "rgbgen")
}
let gen = try! readString()

switch gen {
case "identity": stage.rgbGenerator = .Identity
Expand All @@ -335,9 +339,7 @@ class Q3ShaderParser {
}

case "alphagen":
guard let gen = readString() else {
throw Q3ShaderParserError.InvalidStage(reason: "alphagen")
}
let gen = try! readString()

switch gen {

Expand All @@ -346,9 +348,7 @@ class Q3ShaderParser {
}

case "tcgen", "texgen":
guard let gen = readString() else {
throw Q3ShaderParserError.InvalidStage(reason: "texgen")
}
let gen = try! readString()

switch gen {
case "texture", "base": stage.textureCoordinateGenerator = .Base
Expand Down Expand Up @@ -398,15 +398,84 @@ class Q3ShaderParser {
throw Q3ShaderParserError.InvalidStage(reason: "Unknown token \(token)")
}

if scanner.atEnd {
throw Q3ShaderParserError.InvalidStage(reason: "End of data")
token = try! readString()
}
}

private func readShader(name: String) throws -> Q3Shader {
var shader = Q3Shader()
shader.name = name

while true {
let token = try! readString()
print("got token: \(token)")

// Skip commented lines, radiant editor, q3map
if token.hasPrefix("//") ||
token.lowercaseString.hasPrefix("qer") ||
token.lowercaseString.hasPrefix("q3map_") {
skipLine()
continue
} else if token.hasPrefix("/*") {
skipBlockComment()
continue
}

token = readString()!
switch token.lowercaseString {
case "{": shader.stages.append(try! readStage())

case "tesssize", "surfaceparm", "light": skipLine()

case "skyparms": skipLine()

case "cull": skipLine()

case "deformvertexes": skipLine()

case "fogparms": skipLine()

case "nopicmip": skipLine()

case "nomipmap": skipLine()

case "polygonoffset": skipLine()

case "portal": skipLine()

case "sort": shader.sort = try! readSort()

case "}": return shader

default: throw Q3ShaderParserError.InvalidShader(reason: "Unknown token: \(token)")
}
}
}

private func readShader() throws -> Q3Shader {
throw Q3ShaderParserError.InvalidStage(reason: "Not implemented")
func readShaders() throws -> Array<Q3Shader> {
var shaders: Array<Q3Shader> = []

while true {
let name = try! readString()

// Skip commented lines
if name.hasPrefix("//") {
scanner.scanUpToCharactersFromSet(NSCharacterSet.newlineCharacterSet())
continue
}

let brace = try! readString()

if brace != "{" {
throw Q3ShaderParserError.InvalidShader(reason: "No opening brace")
}

shaders.append(try readShader(name))

if scanner.atEnd {
break
}
}

return shaders
}
}
Loading

0 comments on commit 6ad82a8

Please sign in to comment.