Mercurial > games > semicongine
changeset 77:4b16d2af316a
add: color functions + gamma correction
author | Sam <sam@basx.dev> |
---|---|
date | Tue, 07 Feb 2023 12:20:04 +0700 |
parents | e5be7a25634e |
children | f67496a189cb |
files | examples/E10_pong.nim src/semicongine/color.nim src/semicongine/engine.nim src/semicongine/math/vector.nim |
diffstat | 4 files changed, 139 insertions(+), 55 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/E10_pong.nim Mon Feb 06 23:36:55 2023 +0700 +++ b/examples/E10_pong.nim Tue Feb 07 12:20:04 2023 +0700 @@ -9,18 +9,20 @@ view: ViewProjectionTransform const - barcolor = Vec3([1'f, 0'f, 0'f]) + barcolor = RGBfromHex("5A3F00").gamma(2.2) barSize = 0.1'f barWidth = 0.01'f - ballcolor = Vec3([0'f, 0'f, 0'f]) + ballcolor = RGBfromHex("B17F08").gamma(2.2) levelRatio = 1 ballSize = 0.01'f + backgroundColor = RGBAfromHex("FAC034").gamma(2.2) + ballSpeed = 60'f var uniforms = Uniforms() pipeline: RenderPipeline[Vertex, Uniforms] level: Thing - ballVelocity = Vec2([1'f, 1'f]).normalized * 30'f + ballVelocity = Vec2([1'f, 1'f]).normalized * ballSpeed proc globalUpdate(engine: var Engine; t, dt: float32) = var height = float32(engine.vulkan.frameSize.y) / float32( @@ -44,9 +46,9 @@ # loose if ball.transform.col(3).x - ballSize/2 <= 0: - ballVelocity = Vec2([1'f, 1'f]).normalized * 30'f - ball.transform[0, 3] = 0.5 - ball.transform[1, 3] = 0.5 + ballVelocity = Vec2([1'f, 1'f]).normalized * ballSpeed + ball.transform[0, 3] = width / 2 + ball.transform[1, 3] = height / 2 # bounce level if ball.transform.col(3).x + ballSize/2 > width: ballVelocity[ @@ -68,7 +70,7 @@ when isMainModule: var myengine = igniteEngine("Pong") - myengine.fps = 60 + myengine.maxFPS = 61 level = newThing("Level") var playerbarmesh = quad[Vertex, Vec2, float32]() playerbarmesh.vertexData.color.data = @[barcolor, barcolor, barcolor, barcolor] @@ -99,7 +101,7 @@ vertexShader, fragmentShader ) - pipeline.clearColor = Vec4([1.0'f, 1.0'f, 1.0'f, 1.0'f]) + pipeline.clearColor = backgroundColor # show something myengine.run(pipeline, globalUpdate) pipeline.trash()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/color.nim Tue Feb 07 12:20:04 2023 +0700 @@ -0,0 +1,42 @@ +import std/parseutils + +import ./math/vector + +func RGBfromHex*(value: string): Vec3 = + assert value != "" + var hex = value + if hex[0] == '#': + hex = hex[1 .. ^0] + assert hex.len == 3 or hex.len == 6 + if hex.len == 3: + hex = hex[0] & hex[0] & hex[1] & hex[1] & hex[2] & hex[2] + var r, g, b: uint8 + assert hex.len == 6 + assert parseHex(hex[0 .. 1], r) == 2 + assert parseHex(hex[2 .. 3], g) == 2 + assert parseHex(hex[4 .. 5], b) == 2 + return Vec3([float32(r), float32(g), float32(b)]) / 255'f + +func RGBAfromHex*(value: string): Vec4 = + assert value != "" + var hex = value + if hex[0] == '#': + hex = hex[1 .. ^0] + # when 3 or 6 -> set alpha to 1.0 + assert hex.len == 3 or hex.len == 6 or hex.len == 4 or hex.len == 8 + if hex.len == 3: + hex = hex & "f" + if hex.len == 4: + hex = hex[0] & hex[0] & hex[1] & hex[1] & hex[2] & hex[2] & hex[3] & hex[3] + if hex.len == 6: + hex = hex & "ff" + assert hex.len == 8 + var r, g, b, a: uint8 + assert parseHex(hex[0 .. 1], r) == 2 + assert parseHex(hex[2 .. 3], g) == 2 + assert parseHex(hex[4 .. 5], b) == 2 + assert parseHex(hex[6 .. 7], a) == 2 + return Vec4([float32(r), float32(g), float32(b), float32(a)]) / 255'f + +func gamma*[T: Vec3|Vec4](color: T, gamma: float32): auto = + return pow(color, gamma)
--- a/src/semicongine/engine.nim Mon Feb 06 23:36:55 2023 +0700 +++ b/src/semicongine/engine.nim Tue Feb 07 12:20:04 2023 +0700 @@ -95,7 +95,7 @@ window*: NativeWindow currentscenedata*: Thing input*: Input - fps*: uint + maxFPS*: uint method update*(thing: Thing, engine: Engine, t, dt: float32) {.base.} = discard @@ -810,8 +810,8 @@ func frametime(engine: Engine): auto = - if engine.fps == 0: 0'f - else: 1'f / float32(engine.fps) + if engine.maxFPS == 0: 0'f + else: 1'f / float32(engine.maxFPS) proc run*(engine: var Engine, pipeline: var RenderPipeline, globalUpdate: proc( engine: var Engine, t, dt: float32)) = @@ -863,11 +863,11 @@ update(thing, engine, now, dt) # submit frame for drawing - if engine.fps == 0 or (now - lastframe >= engine.frametime): # framerate limit + if engine.maxFPS == 0 or (now - lastframe >= engine.frametime): # framerate limit engine.window.drawFrame(engine.vulkan, currentFrame, resized, pipeline) lastframe = now + currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT resized = false - currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT checkVkResult vkDeviceWaitIdle(engine.vulkan.device.device)
--- a/src/semicongine/math/vector.nim Mon Feb 06 23:36:55 2023 +0700 +++ b/src/semicongine/math/vector.nim Tue Feb 07 12:20:04 2023 +0700 @@ -25,7 +25,8 @@ # define some often used constants func ConstOne2[T: SomeNumber](): auto {.compiletime.} = TVec2[T]([T(1), T(1)]) func ConstOne3[T: SomeNumber](): auto {.compiletime.} = TVec3[T]([T(1), T(1), T(1)]) -func ConstOne4[T: SomeNumber](): auto {.compiletime.} = TVec4[T]([T(1), T(1), T(1), T(1)]) +func ConstOne4[T: SomeNumber](): auto {.compiletime.} = TVec4[T]([T(1), T(1), T( + 1), T(1)]) func ConstX[T: SomeNumber](): auto {.compiletime.} = TVec3[T]([T(1), T(0), T(0)]) func ConstY[T: SomeNumber](): auto {.compiletime.} = TVec3[T]([T(0), T(1), T(0)]) func ConstZ[T: SomeNumber](): auto {.compiletime.} = TVec3[T]([T(0), T(0), T(1)]) @@ -39,7 +40,8 @@ macro generateAllConsts() = result = newStmtList() for component in ["X", "Y", "Z", "R", "G", "B", "One2", "One3", "One4"]: - for theType in ["int", "int8", "int16", "int32", "int64", "float", "float32", "float64"]: + for theType in ["int", "int8", "int16", "int32", "int64", "float", + "float32", "float64"]: var typename = theType[0 .. 0] if theType[^2].isDigit: typename = typename & theType[^2] @@ -80,11 +82,16 @@ func `$`*(v: TVec4[SomeNumber]): string = toString[TVec4[SomeNumber]](v) func length*(vec: TVec2[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1]) -func length*(vec: TVec2[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1])) -func length*(vec: TVec3[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]) -func length*(vec: TVec3[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2])) -func length*(vec: TVec4[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3]) -func length*(vec: TVec4[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3])) +func length*(vec: TVec2[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[ + 1] * vec[1])) +func length*(vec: TVec3[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[ + 1] + vec[2] * vec[2]) +func length*(vec: TVec3[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[ + 1] * vec[1] + vec[2] * vec[2])) +func length*(vec: TVec4[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[ + 1] + vec[2] * vec[2] + vec[3] * vec[3]) +func length*(vec: TVec4[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[ + 1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3])) func normalized*[T](vec: TVec2[T]): auto = let l = vec.length @@ -103,62 +110,93 @@ when T is SomeFloat: TVec4[T]([vec[0] / l, vec[1] / l, vec[2] / l, vec[3] / l]) else: - TVec4[float]([float(vec[0]) / l, float(vec[1]) / l, float(vec[2]) / l, float(vec[3]) / l]) + TVec4[float]([float(vec[0]) / l, float(vec[1]) / l, float(vec[2]) / l, + float(vec[3]) / l]) # scalar operations func `+`*(a: TVec2, b: SomeNumber): auto = TVec2([a[0] + b, a[1] + b]) func `+`*(a: TVec3, b: SomeNumber): auto = TVec3([a[0] + b, a[1] + b, a[2] + b]) -func `+`*(a: TVec4, b: SomeNumber): auto = TVec4([a[0] + b, a[1] + b, a[2] + b, a[3] + b]) +func `+`*(a: TVec4, b: SomeNumber): auto = TVec4([a[0] + b, a[1] + b, a[2] + b, + a[3] + b]) func `-`*(a: TVec2, b: SomeNumber): auto = TVec2([a[0] - b, a[1] - b]) func `-`*(a: TVec3, b: SomeNumber): auto = TVec3([a[0] - b, a[1] - b, a[2] - b]) -func `-`*(a: TVec4, b: SomeNumber): auto = TVec4([a[0] - b, a[1] - b, a[2] - b, a[3] - b]) +func `-`*(a: TVec4, b: SomeNumber): auto = TVec4([a[0] - b, a[1] - b, a[2] - b, + a[3] - b]) func `*`*(a: TVec2, b: SomeNumber): auto = TVec2([a[0] * b, a[1] * b]) func `*`*(a: TVec3, b: SomeNumber): auto = TVec3([a[0] * b, a[1] * b, a[2] * b]) -func `*`*(a: TVec4, b: SomeNumber): auto = TVec4([a[0] * b, a[1] * b, a[2] * b, a[3] * b]) -func `/`*[T: SomeInteger](a: TVec2[T], b: SomeInteger): auto = TVec2([a[0] div b, a[1] div b]) +func `*`*(a: TVec4, b: SomeNumber): auto = TVec4([a[0] * b, a[1] * b, a[2] * b, + a[3] * b]) +func `/`*[T: SomeInteger](a: TVec2[T], b: SomeInteger): auto = TVec2([a[ + 0] div b, a[1] div b]) func `/`*[T: SomeFloat](a: TVec2[T], b: SomeFloat): auto = TVec2([a[0] / b, a[1] / b]) -func `/`*[T: SomeInteger](a: TVec3[T], b: SomeInteger): auto = TVec3([a[0] div b, a[1] div b, a[2] div b]) -func `/`*[T: SomeFloat](a: TVec3[T], b: SomeFloat): auto = TVec3([a[0] / b, a[1] / b, a[2] / b]) -func `/`*[T: SomeInteger](a: TVec4[T], b: SomeInteger): auto = TVec4([a[0] div b, a[1] div b, a[2] div b, a[3] div b]) -func `/`*[T: SomeFloat](a: TVec4[T], b: SomeFloat): auto = TVec4([a[0] / b, a[1] / b, a[2] / b, a[3] / b]) +func `/`*[T: SomeInteger](a: TVec3[T], b: SomeInteger): auto = TVec3([a[ + 0] div b, a[1] div b, a[2] div b]) +func `/`*[T: SomeFloat](a: TVec3[T], b: SomeFloat): auto = TVec3([a[0] / b, a[ + 1] / b, a[2] / b]) +func `/`*[T: SomeInteger](a: TVec4[T], b: SomeInteger): auto = TVec4([a[ + 0] div b, a[1] div b, a[2] div b, a[3] div b]) +func `/`*[T: SomeFloat](a: TVec4[T], b: SomeFloat): auto = TVec4([a[0] / b, a[ + 1] / b, a[2] / b, a[3] / b]) func `+`*(a: SomeNumber, b: TVec2): auto = TVec2([a + b[0], a + b[1]]) func `+`*(a: SomeNumber, b: TVec3): auto = TVec3([a + b[0], a + b[1], a + b[2]]) -func `+`*(a: SomeNumber, b: TVec4): auto = TVec4([a + b[0], a + b[1], a + b[2], a + b[3]]) +func `+`*(a: SomeNumber, b: TVec4): auto = TVec4([a + b[0], a + b[1], a + b[2], + a + b[3]]) func `-`*(a: SomeNumber, b: TVec2): auto = TVec2([a - b[0], a - b[1]]) func `-`*(a: SomeNumber, b: TVec3): auto = TVec3([a - b[0], a - b[1], a - b[2]]) -func `-`*(a: SomeNumber, b: TVec4): auto = TVec4([a - b[0], a - b[1], a - b[2], a - b[3]]) +func `-`*(a: SomeNumber, b: TVec4): auto = TVec4([a - b[0], a - b[1], a - b[2], + a - b[3]]) func `*`*(a: SomeNumber, b: TVec2): auto = TVec2([a * b[0], a * b[1]]) func `*`*(a: SomeNumber, b: TVec3): auto = TVec3([a * b[0], a * b[1], a * b[2]]) -func `*`*(a: SomeNumber, b: TVec4): auto = TVec4([a * b[0], a * b[1], a * b[2], a * b[3]]) -func `/`*[T: SomeInteger](a: SomeInteger, b: TVec2[T]): auto = TVec2([a div b[0], a div b[1]]) +func `*`*(a: SomeNumber, b: TVec4): auto = TVec4([a * b[0], a * b[1], a * b[2], + a * b[3]]) +func `/`*[T: SomeInteger](a: SomeInteger, b: TVec2[T]): auto = TVec2([a div b[ + 0], a div b[1]]) func `/`*[T: SomeFloat](a: SomeFloat, b: TVec2[T]): auto = TVec2([a / b[0], a / b[1]]) -func `/`*[T: SomeInteger](a: SomeInteger, b: TVec3[T]): auto = TVec3([a div b[0], a div b[1], a div b[2]]) -func `/`*[T: SomeFloat](a: SomeFloat, b: TVec3[T]): auto = TVec3([a / b[0], a / b[1], a / b[2]]) -func `/`*[T: SomeInteger](a: SomeInteger, b: TVec4[T]): auto = TVec4([a div b[0], a div b[1], a div b[2], a div b[3]]) -func `/`*[T: SomeFloat](a: SomeFloat, b: TVec4[T]): auto = TVec4([a / b[0], a / b[1], a / b[2], a / b[3]]) +func `/`*[T: SomeInteger](a: SomeInteger, b: TVec3[T]): auto = TVec3([a div b[ + 0], a div b[1], a div b[2]]) +func `/`*[T: SomeFloat](a: SomeFloat, b: TVec3[T]): auto = TVec3([a / b[0], a / + b[1], a / b[2]]) +func `/`*[T: SomeInteger](a: SomeInteger, b: TVec4[T]): auto = TVec4([a div b[ + 0], a div b[1], a div b[2], a div b[3]]) +func `/`*[T: SomeFloat](a: SomeFloat, b: TVec4[T]): auto = TVec4([a / b[0], a / + b[1], a / b[2], a / b[3]]) # compontent-wise operations func `+`*(a, b: TVec2): auto = TVec2([a[0] + b[0], a[1] + b[1]]) func `+`*(a, b: TVec3): auto = TVec3([a[0] + b[0], a[1] + b[1], a[2] + b[2]]) -func `+`*(a, b: TVec4): auto = TVec4([a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]]) +func `+`*(a, b: TVec4): auto = TVec4([a[0] + b[0], a[1] + b[1], a[2] + b[2], a[ + 3] + b[3]]) func `-`*(a: TVec2): auto = TVec2([-a[0], -a[1]]) func `-`*(a: TVec3): auto = TVec3([-a[0], -a[1], -a[2]]) func `-`*(a: TVec4): auto = TVec4([-a[0], -a[1], -a[2], -a[3]]) func `-`*(a, b: TVec2): auto = TVec2([a[0] - b[0], a[1] - b[1]]) func `-`*(a, b: TVec3): auto = TVec3([a[0] - b[0], a[1] - b[1], a[2] - b[2]]) -func `-`*(a, b: TVec4): auto = TVec4([a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]]) +func `-`*(a, b: TVec4): auto = TVec4([a[0] - b[0], a[1] - b[1], a[2] - b[2], a[ + 3] - b[3]]) func `*`*(a, b: TVec2): auto = TVec2([a[0] * b[0], a[1] * b[1]]) func `*`*(a, b: TVec3): auto = TVec3([a[0] * b[0], a[1] * b[1], a[2] * b[2]]) -func `*`*(a, b: TVec4): auto = TVec4([a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]]) -func `/`*[T: SomeInteger](a, b: TVec2[T]): auto = TVec2([a[0] div b[0], a[1] div b[1]]) +func `*`*(a, b: TVec4): auto = TVec4([a[0] * b[0], a[1] * b[1], a[2] * b[2], a[ + 3] * b[3]]) +func `/`*[T: SomeInteger](a, b: TVec2[T]): auto = TVec2([a[0] div b[0], a[ + 1] div b[1]]) func `/`*[T: SomeFloat](a, b: TVec2[T]): auto = TVec2([a[0] / b[0], a[1] / b[1]]) -func `/`*[T: SomeInteger](a, b: TVec3[T]): auto = TVec3([a[0] div b[0], a[1] div b[1], a[2] div b[2]]) -func `/`*[T: SomeFloat](a, b: TVec3[T]): auto = TVec3([a[0] / b[0], a[1] / b[1], a[2] / b[2]]) -func `/`*[T: SomeInteger](a, b: TVec4[T]): auto = TVec4([a[0] div b[0], a[1] div b[1], a[2] div b[2], a[3] div b[3]]) -func `/`*[T: SomeFloat](a, b: TVec4[T]): auto = TVec4([a[0] / b[0], a[1] / b[1], a[2] / b[2], a[3] / b[3]]) +func `/`*[T: SomeInteger](a, b: TVec3[T]): auto = TVec3([a[0] div b[0], a[ + 1] div b[1], a[2] div b[2]]) +func `/`*[T: SomeFloat](a, b: TVec3[T]): auto = TVec3([a[0] / b[0], a[1] / b[1], + a[2] / b[2]]) +func `/`*[T: SomeInteger](a, b: TVec4[T]): auto = TVec4([a[0] div b[0], a[ + 1] div b[1], a[2] div b[2], a[3] div b[3]]) +func `/`*[T: SomeFloat](a, b: TVec4[T]): auto = TVec4([a[0] / b[0], a[1] / b[1], + a[2] / b[2], a[3] / b[3]]) # special operations +func pow*(a: TVec2, b: SomeNumber): auto = + TVec2([pow(a[0], b), pow(a[1], b)]) +func pow*(a: TVec3, b: SomeNumber): auto = + TVec3([pow(a[0], b), pow(a[1], b), pow(a[2], b)]) +func pow*(a: TVec4, b: SomeNumber): auto = + TVec4([pow(a[0], b), pow(a[1], b), pow(a[2], b), pow(a[3], b)]) func dot*(a, b: TVec2): auto = a[0] * b[0] + a[1] * b[1] func dot*(a, b: TVec3): auto = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] func dot*(a, b: TVec4): auto = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3] @@ -189,7 +227,8 @@ if accessorvalue.len == 0: raise newException(Exception, "empty attribute") elif accessorvalue.len == 1: - ret = nnkBracketExpr.newTree(ident("value"), newLit(ACCESSOR_INDICES[accessorvalue[0]])) + ret = nnkBracketExpr.newTree(ident("value"), newLit(ACCESSOR_INDICES[ + accessorvalue[0]])) if accessorvalue.len > 1: var attrs = nnkBracket.newTree() for attrname in accessorvalue: @@ -197,9 +236,10 @@ ret = nnkCall.newTree(ident("TVec" & $accessorvalue.len), attrs) newProc( - name=nnkPostfix.newTree(ident("*"), ident(accessor)), - params=[ident("auto"), nnkIdentDefs.newTree(ident("value"), ident("TVec"), newEmptyNode())], - body=newStmtList(ret), + name = nnkPostfix.newTree(ident("*"), ident(accessor)), + params = [ident("auto"), nnkIdentDefs.newTree(ident("value"), ident("TVec"), + newEmptyNode())], + body = newStmtList(ret), procType = nnkFuncDef, ) @@ -221,12 +261,12 @@ # call e.g. Vec2[int]().randomized() to get a random matrix template makeRandomInit(mattype: typedesc) = - proc randomized*[T: SomeInteger](m: mattype[T]): mattype[T] = - for i in 0 ..< result.len: - result[i] = rand(low(typeof(m[0])) .. high(typeof(m[0]))) - proc randomized*[T: SomeFloat](m: mattype[T]): mattype[T] = - for i in 0 ..< result.len: - result[i] = rand(1.0) + proc randomized*[T: SomeInteger](m: mattype[T]): mattype[T] = + for i in 0 ..< result.len: + result[i] = rand(low(typeof(m[0])) .. high(typeof(m[0]))) + proc randomized*[T: SomeFloat](m: mattype[T]): mattype[T] = + for i in 0 ..< result.len: + result[i] = rand(1.0) makeRandomInit(TVec2) makeRandomInit(TVec3)