zacharycarter / zengine

2D | 3D Game development library
156 stars 13 forks source link
2d 3d game-development game-engine nim

zengine

2D | 3D Game development library

NOTE - Please run examples from root directory for now

Progress -

3D Skeletal Animation Lit Model Model Loading FPS Camera 2D & 3D Primitive Rendering

Dependencies: Assimp

import zengine, sdl2, opengl

type
  LightKind = enum
    Point, Directional, Spot

  Light = ref object
    id: int
    enabled: bool
    kind: LightKind
    position: Vector3
    target: Vector3
    radius: float
    diffuse: ZColor
    intensity: float
    coneAngle: float

const 
  WIDTH = 960
  HEIGHT = 540
  MAX_LIGHTS = 8

var lights: array[MAX_LIGHTS, Light]
var lightsCount = 0
var lightsLocs: array[MAX_LIGHTS, array[8, int]]

proc createLight(kind: LightKind, position: Vector3, diffuse: ZColor): Light =
  result = nil

  if lightsCount < MAX_LIGHTS:
    result = Light(
      id: lightsCount,
      kind: kind,
      enabled: true,
      position: position,
      target: vectorZero(),
      intensity: 1.0,
      diffuse: diffuse
    )

    lights[lightsCount] = result

    inc(lightsCount)
  else:
    result = lights[lightsCount]

proc setShaderLightsValues(shader: Shader) =
  var tempInt: array[8, GLint]
  var tempFloat: array[8, GLfloat]

  for i in 0..<MAX_LIGHTS:
    if i < lightsCount:
      tempInt[0] = lights[i].enabled.GLint
      setShaderValuei(shader, lightsLocs[i][0].GLint, tempInt, 1)

      tempInt[0] = lights[i].kind.GLint
      setShaderValuei(shader, lightsLocs[i][1].GLint, tempInt, 1)

      tempFloat[0] = lights[i].diffuse.r.float/255.0
      tempFloat[1] = lights[i].diffuse.g.float/255.0
      tempFloat[2] = lights[i].diffuse.b.float/255.0
      tempFloat[3] = lights[i].diffuse.a.float/255.0
      setShaderValue(shader, lightsLocs[i][5].GLint, tempFloat, 4)

      tempFloat[0] = lights[i].intensity
      setShaderValue(shader, lightsLocs[i][6].GLint, tempFloat, 1)

      case lights[i].kind:
        of LightKind.Point:
          tempFloat[0] = lights[i].position.x
          tempFloat[1] = lights[i].position.y
          tempFloat[2] = lights[i].position.z
          setShaderValue(shader, lightsLocs[i][2].GLint, tempFloat, 3)

          tempFloat[0] = lights[i].radius
          setShaderValue(shader, lightsLocs[i][4].GLint, tempFloat, 1)
        of LightKind.Directional:
          var direction = vectorSubtract(lights[i].target, lights[i].position)
          vectorNormalize(direction)

          tempFloat[0] = direction.x
          tempFloat[1] = direction.y
          tempFloat[2] = direction.z
          setShaderValue(shader, lightsLocs[i][3].GLint, tempFloat, 3)
        of LightKind.Spot:
          tempFloat[0] = lights[i].position.x
          tempFloat[1] = lights[i].position.y
          tempFloat[2] = lights[i].position.z
          setShaderValue(shader, lightsLocs[i][2].GLint, tempFloat, 3)

          var direction = vectorSubtract(lights[i].target, lights[i].position)
          vectorNormalize(direction)

          tempFloat[0] = direction.x
          tempFloat[1] = direction.y
          tempFloat[2] = direction.z
          setShaderValue(shader, lightsLocs[i][3].GLint, tempFloat, 3)

          tempFloat[0] = lights[i].coneAngle
          setShaderValue(shader, lightsLocs[i][7].GLint, tempFloat, 1)
    else:
      tempInt[0] = 0
      setShaderValuei(shader, lightsLocs[i][0].GLint, tempInt, 1)

proc getShaderLightsLocation(shader: Shader) =
  var locName = "lights[x]."
  var locNameUpdated = newStringOfCap(64)

  for i in 0..<MAX_LIGHTS:
    locName[7] = ('0'.int + i).char

    locNameUpdated = locName
    locNameUpdated &= "enabled"
    lightsLocs[i][0] = getShaderLocation(shader, locNameUpdated)

    locNameUpdated[0] = ' '
    locNameUpdated = locName
    locNameUpdated &= "type"
    lightsLocs[i][1] = getShaderLocation(shader, locNameUpdated)

    locNameUpdated[0] = ' '
    locNameUpdated = locName
    locNameUpdated &= "position"
    lightsLocs[i][2] = getShaderLocation(shader, locNameUpdated)

    locNameUpdated[0] = ' '
    locNameUpdated = locName
    locNameUpdated &= "direction"
    lightsLocs[i][3] = getShaderLocation(shader, locNameUpdated)

    locNameUpdated[0] = ' '
    locNameUpdated = locName
    locNameUpdated &= "radius"
    lightsLocs[i][4] = getShaderLocation(shader, locNameUpdated)

    locNameUpdated[0] = ' '
    locNameUpdated = locName
    locNameUpdated &= "diffuse"
    lightsLocs[i][5] = getShaderLocation(shader, locNameUpdated)

    locNameUpdated[0] = ' '
    locNameUpdated = locName
    locNameUpdated &= "intensity"
    lightsLocs[i][6] = getShaderLocation(shader, locNameUpdated)

    locNameUpdated[0] = ' '
    locNameUpdated = locName
    locNameUpdated &= "coneAngle"
    lightsLocs[i][7] = getShaderLocation(shader, locNameUpdated)

zengine.init(WIDTH, HEIGHT, "zengine example: 00_Initialization")

var 
  evt = sdl2.defaultEvent
  running = true
  camera = Camera(
    position: Vector3(x: 4, y: 2, z: 4),
    target: Vector3(x: 0, y: 1.8, z: 0),
    up: Vector3(x: 0, y: 1, z: 0),
    fovY: 60
  )
  mouseWheelMovement = 0
  mouseXRel = 0
  mouseYRel = 0

camera.setMode(CameraMode.Free)
#camera.setMode(CameraMode.FirstPerson)

let shader = loadShader("examples/data/shaders/glsl330/forward.vs", "examples/data/shaders/glsl330/forward.fs")

var model = loadModel("examples/data/models/mannequin/walking.dae", shader)

getShaderLightsLocation(shader)

var spotLight = createLight(LightKind.Spot, Vector3(x:0.0, y:5.0, z:0.0), ZColor(r:255, g:255, b:255, a:255))
spotLight.target = Vector3(x: 0.0, y: 0.0, z: 0.0)
spotLight.intensity = 2.0
spotlight.diffuse = ZColor(r: 0, g: 0, b: 255, a: 255)
spotLight.coneAngle = 60.0

var dirLight = createLight(LightKind.Directional, Vector3(x:0.0, y: -3.0, z: -3.0), ZColor(r:0, g:0, b:255, a:255))
dirLight.target = Vector3(x: 1.0, y: -2.0, z: -2.0)
dirLight.intensity = 2.0
dirLight.diffuse = ZColor(r: 100, g:255, b:100, a:255)

var pointLight = createLight(LightKind.Point, Vector3(x:0.0, y: 4.0, z: 5.0), ZColor(r:255, g:255, b:255, a:255))
pointLight.intensity = 2.0
pointLight.diffuse = ZColor(r: 100, g:100, b:255, a:255)
pointLight.radius = 3.0

setShaderLightsValues(shader)

while running:
  mouseWheelMovement = 0
  mouseXRel = 0
  mouseYRel = 0
  while sdl2.pollEvent(evt):
    case evt.kind
    of QuitEvent:
      running = false
    of MouseMotion:
      var mouseMoveEvent = cast[MouseMotionEventPtr](addr evt)
      mouseXRel = mouseMoveEvent.xrel
      mouseYRel = mouseMoveEvent.yrel
    of MouseWheel:
      var mouseWheelEvent = cast[MouseWheelEventPtr](addr evt)
      mouseWheelMovement = mouseWheelEvent.y
    else:
      discard

  pollInput()

  camera.update(mouseWheelMovement, mouseXRel, mouseYRel)

  beginDrawing()
  clearBackground(ZENGRAY)

  begin3dMode(camera)
  drawPlane(Vector3(x: 0.0, y: 0.0, z: 0.0), Vector2(x: 32.0, y: 32.0), GREEN)
  drawCube(Vector3(x: -16.0, y: 2.5, z: 0.0), 1.0, 5.0, 32.0, BLUE)
  drawCube(Vector3(x: 16.0, y: 2.5, z: 0.0), 1.0, 5.0, 32.0, RED)
  drawCube(Vector3(x: 0.0, y: 2.5, z: 16.0), 32.0, 5.0, 1.0, WHITE)
  drawModel(model, WHITE)
  end3dMode()

  drawText("Hello zengine!", 5, 5, 30, ZColor(r: 255, g: 255, b: 255, a: 255))

  endDrawing()

zengine.shutdown()