changeset 831:902735626b66

add: missing material module, some functions for noise
author Sam <sam@basx.dev>
date Wed, 22 Nov 2023 23:23:40 +0700
parents e314407ea9db
children 388c4b35a6e3
files src/semicongine/material.nim src/semicongine/noise.nim tests/test_noise.nim
diffstat 3 files changed, 164 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/semicongine/material.nim	Wed Nov 22 23:23:40 2023 +0700
@@ -0,0 +1,113 @@
+import std/tables
+import std/strformat
+import std/strutils
+import std/hashes
+
+
+import ./core
+
+type
+  MaterialType* = object
+    name*: string
+    meshAttributes*: Table[string, DataType]
+    attributes*: Table[string, DataType]
+  MaterialData* = object
+    theType*: MaterialType
+    name*: string
+    attributes*: Table[string, DataList]
+
+proc hash*(materialType: MaterialType): Hash =
+  return hash(materialType.name)
+
+proc hash*(materialData: MaterialData): Hash =
+  return hash(materialData.name)
+
+proc `==`*(a, b: MaterialType): bool =
+  return a.name == b.name
+
+proc `==`*(a, b: MaterialData): bool =
+  return a.name == b.name
+
+let EMPTY_MATERIAL* = MaterialType(
+  name: "empty material",
+  meshAttributes: {"position": Vec3F32}.toTable,
+)
+let COLORED_MATERIAL* = MaterialType(
+  name: "single color material",
+  meshAttributes: {"position": Vec3F32}.toTable,
+  attributes: {"color": Vec4F32}.toTable,
+)
+let VERTEX_COLORED_MATERIAL* = MaterialType(
+  name: "vertex color material",
+  meshAttributes: {
+    "position": Vec3F32,
+    "color": Vec4F32,
+  }.toTable,
+)
+let SINGLE_COLOR_MATERIAL* = MaterialType(
+  name: "single color material",
+  meshAttributes: {
+    "position": Vec3F32,
+  }.toTable,
+  attributes: {"color": Vec4F32}.toTable
+)
+let SINGLE_TEXTURE_MATERIAL* = MaterialType(
+  name: "single texture material",
+  meshAttributes: {
+    "position": Vec3F32,
+    "uv": Vec2F32,
+  }.toTable,
+  attributes: {"baseTexture": TextureType}.toTable
+)
+let COLORED_SINGLE_TEXTURE_MATERIAL* = MaterialType(
+  name: "colored single texture material",
+  meshAttributes: {
+    "position": Vec3F32,
+    "uv": Vec2F32,
+  }.toTable,
+  attributes: {"baseTexture": TextureType, "color": Vec4F32}.toTable
+)
+
+proc `$`*(materialType: MaterialType): string =
+  var attributes: seq[string]
+  for key, value in materialType.attributes.pairs:
+    attributes.add &"{key}: {value}"
+  return &"""MaterialType '{materialType.name}' | Attributes: {attributes.join(", ")}"""
+
+proc `$`*(material: MaterialData): string =
+  var attributes: seq[string]
+  for key, value in material.attributes.pairs:
+    attributes.add &"{key}: {value}"
+  return &"""Material '{material.name}' | Attributes: {attributes.join(", ")}"""
+
+proc initMaterialData*(
+  materialType: MaterialType,
+  name: string,
+  attributes: Table[string, DataList],
+): MaterialData =
+  var theName = name
+  if theName == "":
+    theName = &"material instance of '{materialType}'"
+  for matName, theType in materialType.attributes.pairs:
+    assert attributes.contains(matName), &"missing material attribute '{matName}' for {materialType}"
+    assert attributes[matName].theType == theType
+  MaterialData(
+    theType: materialType,
+    name: theName,
+    attributes: attributes,
+  )
+
+proc initMaterialData*(
+  materialType: MaterialType,
+  name: string = "",
+  attributes: seq[(string, DataList)] = @[],
+): MaterialData =
+  var theName = name
+  if theName == "":
+    theName = &"material instance of '{materialType}'"
+  initMaterialData(materialType=materialType, name=theName, attributes=attributes.toTable)
+
+let DEFAULT_MATERIAL* = MaterialData(
+  name: "default material"
+)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/semicongine/noise.nim	Wed Nov 22 23:23:40 2023 +0700
@@ -0,0 +1,34 @@
+import hashes
+import math
+
+import ./core/vector
+
+
+proc randomGradient(pos: Vec2f, seed: int32 = 0): Vec2f =
+  let randomAngle: float32 = TAU * (float32(int(hash((pos.x, pos.y, seed)))) / float32(high(int)))
+  return newVec2f(cos(randomAngle), sin(randomAngle))
+
+proc interpolate(a: float32, b: float32, weight: float32): float32 =
+  # with Smootherstep
+  (b - a) * ((weight * (weight * 6.0 - 15.0) + 10.0) * weight * weight * weight) + a;
+
+proc perlin*(pos: Vec2f, seed: int32 = 0): float32 =
+  let
+    # grid coordinates around target point
+    topleft = newVec2f(trunc(pos.x), trunc(pos.y))
+    topright = topleft + newVec2f(1, 0)
+    bottomleft = topleft + newVec2f(0, 1)
+    bottomright = topleft + newVec2f(1, 1)
+    # products for weights
+    topleft_dot = topleft.randomGradient(seed).dot((pos - topleft))
+    topright_dot = topright.randomGradient(seed).dot((pos - topright))
+    bottomleft_dot = bottomleft.randomGradient(seed).dot((pos - bottomleft))
+    bottomright_dot = bottomright.randomGradient(seed).dot((pos - bottomright))
+    xinterpol = pos.x - topleft.x
+    yinterpol = pos.y - topleft.y
+
+  return interpolate(
+    interpolate(topleft_dot, bottomleft_dot, yinterpol),
+    interpolate(topright_dot, bottomright_dot, yinterpol),
+    xinterpol
+  )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_noise.nim	Wed Nov 22 23:23:40 2023 +0700
@@ -0,0 +1,17 @@
+import semicongine
+
+const w = 500
+const h = 500
+
+var o = "P2\n" & $ w & " " & $ h & "\n255\n"
+
+for y in 0 ..< h:
+  for x in 0 ..< w:
+    let v = (
+      perlin(newVec2f(float(x) * 0.01, float(y) * 0.01)) * 0.7 +
+      perlin(newVec2f(float(x) * 0.05, float(y) * 0.05)) * 0.25 +
+      perlin(newVec2f(float(x) * 0.2, float(y) * 0.2)) * 0.05
+    )
+    o = o & $(int((v * 0.5 + 0.5) * 255)) & " "
+  o = o & "\n"
+echo o