From: Brendan Hansen Date: Sat, 15 Dec 2018 05:42:55 +0000 (-0600) Subject: board rendering working X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=c2996da666d92cf2c822b17f80f997425299cf88;p=light.git board rendering working --- diff --git a/christmas_proj b/christmas_proj index b8d76b0..8bf1cf3 100755 Binary files a/christmas_proj and b/christmas_proj differ diff --git a/data/progs/test.lgt b/data/progs/test.lgt index e8f784f..93a5427 100644 --- a/data/progs/test.lgt +++ b/data/progs/test.lgt @@ -5,4 +5,11 @@ WHILE $MEM_2 < 100000 DO $MEM_3 = $MEM_1 + $MEM_2 $MEM_1 = $MEM_2 $MEM_2 = $MEM_3 -END \ No newline at end of file + !PRINT($MEM_3, 3 + $MEM_7) +END + +IF !IN_BOUNDS($POS_X + 1, $POS_Y) THEN + !SAY($MEM_8) +END + +!REDRAW() \ No newline at end of file diff --git a/data/shaders/board.frag b/data/shaders/board.frag new file mode 100644 index 0000000..6295c19 --- /dev/null +++ b/data/shaders/board.frag @@ -0,0 +1,11 @@ +#version 300 es + +precision mediump float; + +in vec4 v_col; + +out vec4 fragColor; + +void main() { + fragColor = v_col; +} \ No newline at end of file diff --git a/data/shaders/board.vert b/data/shaders/board.vert new file mode 100644 index 0000000..8f09879 --- /dev/null +++ b/data/shaders/board.vert @@ -0,0 +1,16 @@ +#version 300 es + +layout(location = 0) in vec2 a_pos; +layout(location = 1) in vec4 a_col; + +uniform mat3 u_proj; +uniform int board_width; +uniform int board_height; + +out vec4 v_col; + +void main() { + vec2 offset = vec2(gl_InstanceID % board_width, gl_InstanceID / board_width); + gl_Position = vec4(u_proj * vec3(a_pos + offset, 1), 1); + v_col = a_col; +} \ No newline at end of file diff --git a/src/board/board.nim b/src/board/board.nim new file mode 100644 index 0000000..35101fd --- /dev/null +++ b/src/board/board.nim @@ -0,0 +1,168 @@ +import opengl +import ../gfx/glutils + +type + LightBoard = ref object + width: int + height: int + data: ref array[1024 * 1024, GLuint] + colors: ref array[1024 * 1024 * 4, GLfloat] + + vertexArrayObject: GLuint + vertexBufferObject: GLuint + indexBufferObject: GLuint + colorBufferObject: GLuint + +proc CreateBoard*(width, height: int): LightBoard = + var data = new(array[1024 * 1024, GLuint]) + var colors = new(array[1024 * 1024 * 4, GLfloat]) + for i in 0 ..< (width * height): + data[i] = 0x0.GLuint + colors[i * 4 + 0] = 0.GLfloat + colors[i * 4 + 1] = 0.GLfloat + colors[i * 4 + 2] = 0.GLfloat + colors[i * 4 + 3] = 1.GLfloat + LightBoard( + width: width, + height: height, + data: data, + colors: colors + ) + +func GetCol*(board: LightBoard, x, y: int): GLuint = + if x < 0 or y < 0 or x >= board.width or y >= board.height: + 0.GLuint + else: + board.data[][x + y * board.width] + +proc SetCol*(board: LightBoard, x, y: int, val: GLuint) = + if x < 0 or y < 0 or x >= board.width or y >= board.height: + return + + board.data[][x + y * board.width] = val + let + r = ((val shr 16) and 0xff).GLfloat / 255.GLfloat + g = ((val shr 8) and 0xff).GLfloat / 255.GLfloat + b = ((val shr 0) and 0xff).GLfloat / 255.GLfloat + board.colors[][x * 4 + y * board.width * 4 + 0] = r + board.colors[][x * 4 + y * board.width * 4 + 1] = g + board.colors[][x * 4 + y * board.width * 4 + 2] = b + +func GetA*(board: LightBoard, x, y: int): GLuint = + if x < 0 or y < 0 or x >= board.width or y >= board.height: + 0.GLuint + else: + (board.data[][x + y * board.width] shr 24) and 0xff + +func GetR*(board: LightBoard, x, y: int): GLuint = + if x < 0 or y < 0 or x >= board.width or y >= board.height: + 0.GLuint + else: + (board.data[][x + y * board.width] shr 16) and 0xff + +func GetG*(board: LightBoard, x, y: int): GLuint = + if x < 0 or y < 0 or x >= board.width or y >= board.height: + 0.GLuint + else: + (board.data[][x + y * board.width] shr 8) and 0xff + +func GetB*(board: LightBoard, x, y: int): GLuint = + if x < 0 or y < 0 or x >= board.width or y >= board.height: + 0.GLuint + else: + (board.data[][x + y * board.width] shr 0) and 0xff + +proc SetA*(board: LightBoard, x, y: int, val: GLuint) = + if x < 0 or y < 0 or x >= board.width or y >= board.height: + return + + let mval = val mod 256 + board.data[][x + y * board.width] = board.data[][x + y * board.width] and 0x00ffffff.GLuint + board.data[][x + y * board.width] = board.data[][x + y * board.width] or (mval shl 24) + +proc SetR*(board: LightBoard, x, y: int, val: GLuint) = + if x < 0 or y < 0 or x >= board.width or y >= board.height: + return + + let mval = val mod 256 + board.data[][x + y * board.width] = board.data[][x + y * board.width] and 0xff00ffff.GLuint + board.data[][x + y * board.width] = board.data[][x + y * board.width] or (mval shl 16) + board.colors[][x * 4 + y * board.width * 4 + 0] = mval.GLfloat / 256.GLfloat + +proc SetG*(board: LightBoard, x, y: int, val: GLuint) = + if x < 0 or y < 0 or x >= board.width or y >= board.height: + return + + let mval = val mod 256 + board.data[][x + y * board.width] = board.data[][x + y * board.width] and 0xffff00ff.GLuint + board.data[][x + y * board.width] = board.data[][x + y * board.width] or (mval shl 8) + board.colors[][x * 4 + y * board.width * 4 + 1] = mval.GLfloat / 256.GLfloat + +proc SetB*(board: LightBoard, x, y: int, val: GLuint) = + if x < 0 or y < 0 or x >= board.width or y >= board.height: + return + + let mval = val mod 256 + board.data[][x + y * board.width] = board.data[][x + y * board.width] and 0xffffff00.GLuint + board.data[][x + y * board.width] = board.data[][x + y * board.width] or (mval shl 0) + board.colors[][x * 4 + y * board.width * 4 + 2] = mval.GLfloat / 256.GLfloat + +proc InitRendering*(board: LightBoard) = + glGenVertexArrays(1, board.vertexArrayObject.addr) + glBindVertexArray(board.vertexArrayObject) + + var vertex_data: array[8, GLfloat] = [ + 0'f32, 0'f32, + 0'f32, 1'f32, + 1'f32, 1'f32, + 1'f32, 0'f32, + ] + glGenBuffers(1, board.vertexBufferObject.addr) + glBindBuffer(GL_ARRAY_BUFFER, board.vertexBufferObject) + glBufferData(GL_ARRAY_BUFFER, vertex_data.sizeof, vertex_data.addr, GL_STATIC_DRAW) + glEnableVertexAttribArray(0) + glVertexAttribPointer(0, 2, cGL_FLOAT, GL_FALSE, 8.GLsizei, nil) + + glGenBuffers(1, board.colorBufferObject.addr) + glBindBuffer(GL_ARRAY_BUFFER, board.colorBufferObject) + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4 * board.width * board.height, board.colors.addr, GL_DYNAMIC_DRAW) + glEnableVertexAttribArray(1) + glVertexAttribDivisor(1, 1) + glVertexAttribPointer(1, 4, cGL_FLOAT, GL_FALSE, 16.GLsizei, nil) + + var index_data: array[6, GLubyte] = [ + 0.GLubyte, 1.GLubyte, 2.GLubyte, 0.GLubyte, 2.GLubyte, 3.GLubyte + ] + glGenBuffers(1, board.indexBufferObject.addr) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, board.indexBufferObject) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * 6, index_data.addr, GL_STATIC_DRAW) + + glBindVertexArray(0) + + let vertex_shader = glutils.CreateShader(glutils.stVertex, "./data/shaders/board.vert") + let fragment_shader = glutils.CreateShader(glutils.stFragment, "./data/shaders/board.frag") + let program = glutils.LinkProgram(vertex_shader, fragment_shader) + glUseProgram(program) + + let u_board_width = glGetUniformLocation(program, "board_width") + let u_board_height = glGetUniformLocation(program, "board_height") + let u_proj = glGetUniformLocation(program, "u_proj") + glUniform1i(u_board_width, board.width.GLint) + glUniform1i(u_board_height, board.height.GLint) + + var proj_mat: array[9, GLfloat] = [ + (2.GLfloat / board.width.GLfloat).GLfloat, 0.GLfloat, 0.GLfloat, + 0.GLfloat, (-2.GLfloat / board.height.GLfloat).GLfloat, 0.GLfloat, + -1.GLfloat, 1.GLfloat, 1.GLfloat + ] + glUniformMatrix3fv(u_proj, 1.GLsizei, GL_FALSE, proj_mat[0].addr) + +proc RebufferColors*(board: LightBoard) = + glBindBuffer(GL_ARRAY_BUFFER, board.colorBufferObject) + glBufferSubData(GL_ARRAY_BUFFER, 0.GLintptr, sizeof(GLfloat) * 4 * board.width * board.height, board.colors[].addr) + glBindBuffer(GL_ARRAY_BUFFER, 0) + +proc Render*(board: LightBoard) = + glBindVertexArray(board.vertexArrayObject) + glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nil, (board.width * board.height).GLsizei) + glBindVertexArray(0) \ No newline at end of file diff --git a/src/christmas_proj.nim b/src/christmas_proj.nim index 2267a2b..49b211e 100644 --- a/src/christmas_proj.nim +++ b/src/christmas_proj.nim @@ -1,6 +1,7 @@ import os import sequtils import opengl +import random import glfw3 as glfw import gfx/window as gfx_window import gfx/glutils as glutils @@ -10,18 +11,16 @@ import lang/lexer as lexer import lang/parser as parser import lang/tokens +import board/board + proc key_down(window: glfw.Window, key, scancode, action, modifier: cint) {.cdecl.} = if key == glfw.KEY_ESCAPE and action == glfw.PRESS: glfw.SetWindowShouldClose(window, glfw.TRUE) proc main2() = let window = gfxWindow.NewWindow(800, 600, "ASDF") - window.SetKeyCallback(key_down) - var version = cast[cstring](glGetString(GL_VERSION)) - echo $version - let vertex_shader = glutils.CreateShader(glutils.stVertex, "./data/shaders/basic.vert") let fragment_shader = glutils.CreateShader(glutils.stFragment, "./data/shaders/basic.frag") let program = glutils.LinkProgram(vertex_shader, fragment_shader) @@ -69,28 +68,32 @@ proc main2() = glBindVertexArray(0) + +proc main() = + let window = gfxWindow.NewWindow(1200, 700, "ASDF") + window.SetKeyCallback(key_down) + + let source_code = readFile("data/progs/test.lgt") + let tokens = toSeq(lexer.GenerateTokens(source_code)) + for exp in parser.ParseTokens(tokens): + echo exp + + let board = CreateBoard(256, 256) + board.InitRendering() + while not window.ShouldClose(): glClearColor(0, 0, 0, 1) glClear(GL_COLOR_BUFFER_BIT) - glBindVertexArray(vao) - glDrawElementsInstanced(GL_TRIANGLES, 3.GLsizei, GL_UNSIGNED_INT, nil, 2) - glBindVertexArray(0) + board.SetCol(random.rand(256), random.rand(256), random.rand(0xffffff).GLuint) + + board.RebufferColors() + board.Render() + os.sleep(1) window.Refresh() window.CloseWindow() -proc main() = - let source_code = readFile("data/progs/test.lgt") - let tokens = toSeq(lexer.GenerateTokens(source_code)) - for token in tokens: - echo token - - echo "\n\n\n" - - for exp in parser.ParseTokens(tokens): - echo exp - when isMainModule: main() diff --git a/src/lang/ast.nim b/src/lang/ast.nim index 1836b56..e0fee97 100644 --- a/src/lang/ast.nim +++ b/src/lang/ast.nim @@ -3,16 +3,17 @@ import ./tokens type LightExprType* = enum - leNull = 0, - leVar = 1, - leNumLit = 2, - leOp = 3, - leAssign = 4, - leLabel = 5, - leGoto = 6, - leIf = 7, - leWhile = 8, - leBreak = 9 + leNull = 0, + leVar = 1, + leNumLit = 2, + leOp = 3, + leAssign = 4, + leLabel = 5, + leGoto = 6, + leIf = 7, + leWhile = 8, + leBreak = 9, + leFuncCall = 10, LightExpr* = ref object case kind*: LightExprType @@ -32,6 +33,9 @@ type of leIf, leWhile: condition*: LightExpr body*: seq[LightExpr] + of leFuncCall: + func_name*: string + params*: seq[LightExpr] else: discard @@ -46,4 +50,5 @@ proc `$`*(exp: LightExpr): string = of leIf: "If[" & $exp.condition & " -> " & $exp.body & "]" of leWhile: "While[" & $exp.condition & " -> " & $exp.body & "]" of leBreak: "Break" + of leFuncCall: "FuncCall[" & exp.func_name & ", " & $exp.params & "]" else: "" \ No newline at end of file diff --git a/src/lang/lexer.nim b/src/lang/lexer.nim index 197acb7..a5acc32 100644 --- a/src/lang/lexer.nim +++ b/src/lang/lexer.nim @@ -6,34 +6,46 @@ import ./types import ./tokens iterator Generate_tokens*(source: string): LightToken = - for token, is_sep in strutils.tokenize(source, {' ', '\n', ';', '\t', '='}): + for token, is_sep in strutils.tokenize(source, {' ', '\n', ';', '\t', '=', ',', '(', ')'}): if is_sep: - if token.contains({'\n', ';'}): - yield LightToken(kind: ltExprDelim) if token.contains({'='}): yield LightToken(kind: ltEq) + if token.contains({','}): + yield LightToken(kind: ltParamDelim) + if token.contains({'('}): + yield LightToken(kind: ltParamStart) + if token.contains({')'}): + yield LightToken(kind: ltParamEnd) + if token.contains({'\n', ';'}): + yield LightToken(kind: ltExprDelim) continue if token.startsWith('$'): - let varString = token[1 .. ^1] + let varString = token[1 .. ^1].toLowerAscii var varName: LightVariable if varString == "": raise newException(IOError, "Expected variable name") else: - if varString == "MEM_1": varName = var1 - elif varString == "MEM_2": varName = var2 - elif varString == "MEM_3": varName = var3 - elif varString == "MEM_4": varName = var4 - elif varString == "MEM_5": varName = var5 - elif varString == "MEM_6": varName = var6 - elif varString == "MEM_7": varName = var7 - elif varString == "MEM_8": varName = var8 + if varString == "mem_1": varName = var1 + elif varString == "mem_2": varName = var2 + elif varString == "mem_3": varName = var3 + elif varString == "mem_4": varName = var4 + elif varString == "mem_5": varName = var5 + elif varString == "mem_6": varName = var6 + elif varString == "mem_7": varName = var7 + elif varString == "mem_8": varName = var8 + elif varString == "pos_x": varName = var9 + elif varString == "pos_y": varName = var10 else: raise newException(IOError, "Invalid variable name.") yield LightToken(kind: ltVar, var_name: varName) + elif token.startsWith('!'): + let funcName = token[1..^1].toLowerAscii + yield LightToken(kind: ltFunc, func_name: funcName) + elif token == "=": yield LightToken(kind: ltEq) diff --git a/src/lang/parser.nim b/src/lang/parser.nim index 6de13b5..b040077 100644 --- a/src/lang/parser.nim +++ b/src/lang/parser.nim @@ -6,33 +6,33 @@ import ./ast import ../utils/iter type - LightParser* = object + LightParser = object tokens: Iter[LightToken] -func CreateParser*(tokens: Iter[LightToken]): LightParser = +func CreateParser(tokens: Iter[LightToken]): LightParser = LightParser(tokens: tokens) -func CreateParser*(tokens: seq[LightToken]): LightParser = +func CreateParser(tokens: seq[LightToken]): LightParser = CreateParser(CreateIter[LightToken](tokens, LightToken(kind: ltNull))) -func NextExpr*(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType]): LightExpr +func NextExpr(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType]): LightExpr -func Parse_block(tokens: Iter[LightToken]): seq[LightExpr] = +func Parse_block(tokens: Iter[LightToken], sep, endd: LightTokenType): seq[LightExpr] = result = @[] var last = tokens.Current - if last.kind == ltBlockEnd: + if last.kind == endd: tokens.Step() return var parser = CreateParser(tokens) - while last.kind != ltBlockEnd: - let p = parser.NextExpr(LightExpr(kind: leNull), {ltExprDelim, ltBlockEnd}) + while last.kind != endd: + let p = parser.NextExpr(LightExpr(kind: leNull), {sep, endd}) if p.kind != leNull: result.add(p) last = parser.tokens.Current parser.tokens.Step() -func NextExpr*(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType]): LightExpr = +func NextExpr(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType]): LightExpr = let curr = parser.tokens.Current if curr.kind in stop_at: @@ -62,13 +62,14 @@ func NextExpr*(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType if prev.kind != leVar: raise newException(ValueError, "Expected variable on the left of assignment operator") - let next = parser.NextExpr(LightExpr(kind: leNull), stop_at) + else: + let next = parser.NextExpr(LightExpr(kind: leNull), stop_at) - return LightExpr( - kind: leAssign, - variable: prev.var_name, - expression: next - ) + return LightExpr( + kind: leAssign, + variable: prev.var_name, + expression: next + ) elif curr.kind == ltLabel: return LightExpr( @@ -80,16 +81,17 @@ func NextExpr*(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType let next = parser.tokens.Current if next.kind != ltLabel: raise newException(ValueError, "Expected label after goto") - - return LightExpr( - kind: leGoto, - label: next.label_name - ) + + else: + return LightExpr( + kind: leGoto, + label: next.label_name + ) elif curr.kind == ltIf: let condition = parser.NextExpr(LightExpr(kind: leNull), {ltBlockStart}) parser.tokens.Step() - let body = Parse_block(parser.tokens) + let body = Parse_block(parser.tokens, ltExprDelim, ltBlockEnd) return LightExpr( kind: leIf, @@ -100,7 +102,7 @@ func NextExpr*(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType elif curr.kind == ltWhile: let condition = parser.NextExpr(LightExpr(kind: leNull), {ltBlockStart}) parser.tokens.Step() - let body = Parse_block(parser.tokens) + let body = Parse_block(parser.tokens, ltExprDelim, ltBlockEnd) return LightExpr( kind: leWhile, @@ -112,6 +114,19 @@ func NextExpr*(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType return LightExpr( kind: leBreak ) + + elif curr.kind == ltFunc: + if parser.tokens.Current.kind != ltParamStart: + raise newException(ValueError, "Expected parameter list after function call") + + parser.tokens.Step() + let params = Parse_block(parser.tokens, ltParamDelim, ltParamEnd) + + return LightExpr( + kind: leFuncCall, + func_name: curr.func_name, + params: params + ) iterator Parse_tokens*(tokens: seq[LightToken]): LightExpr = var parser = CreateParser(tokens) diff --git a/src/lang/tokens.nim b/src/lang/tokens.nim index 7fd56ea..9a9cdcb 100644 --- a/src/lang/tokens.nim +++ b/src/lang/tokens.nim @@ -6,8 +6,12 @@ type ltVar, ltNum, ltExprDelim, ltLabel, ltGoto, - ltIf, ltWhile, ltBlockStart, ltBlockEnd, + ltIf, ltWhile, + ltBlockStart, ltBlockEnd, ltBreak, + ltFunc, + ltParamStart, ltParamEnd, + ltParamDelim, ltOp, ltEq LightToken* = ref object @@ -18,6 +22,8 @@ type value*: LightInt of ltLabel: label_name*: string + of ltFunc: + func_name*: string of ltOp: operation*: LightOperation else: @@ -33,6 +39,8 @@ func `$`*(variable: LightVariable): string = of var6: "MEM_6" of var7: "MEM_7" of var8: "MEM_8" + of var9: "POS_X" + of var10: "POS_Y" proc `$`*(token: LightToken): string = return @@ -49,4 +57,9 @@ proc `$`*(token: LightToken): string = of ltBreak: "BreakToken" of ltBlockStart: "BlockStartToken" of ltBlockEnd: "BlockEndToken" - of ltOp: "OpeartionToken[" & $token.operation & "]" \ No newline at end of file + of ltFunc: "FunctionToken[" & token.func_name & "]" + of ltParamStart: "ParamStartToken" + of ltParamEnd: "ParamEndToken" + of ltParamDelim: "ParamDelimToken" + of ltOp: "OpeartionToken[" & $token.operation & "]" + else: "UndefinedToken" \ No newline at end of file diff --git a/src/lang/types.nim b/src/lang/types.nim index 2ba8c9a..847ff5d 100644 --- a/src/lang/types.nim +++ b/src/lang/types.nim @@ -1,7 +1,8 @@ type LightVariable* = enum var1 = 0, var2 = 1, var3 = 2, var4 = 3, - var5 = 4, var6 = 5, var7 = 6, var8 = 7 + var5 = 4, var6 = 5, var7 = 6, var8 = 7, + var9 = 8, var10 = 9 LightOperation* = enum loAdd, loSub, loMul, loDiv, loMod,