Skip to content

Commit

Permalink
More framework progress
Browse files Browse the repository at this point in the history
  • Loading branch information
tatjam committed Jul 8, 2022
1 parent b07daa3 commit 1113312
Show file tree
Hide file tree
Showing 12 changed files with 295 additions and 65 deletions.
4 changes: 3 additions & 1 deletion res/shader/fullscreen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ void main()

coord = vec2(vTex.x, 1.0 - vTex.y);

FragColor = vec4(coord.x, coord.y, 0.0, 1.0);
vec4 col = texture(tex, coord);

FragColor = vec4(col.xyz, 1.0);
}
17 changes: 17 additions & 0 deletions res/shader/sprite.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#version 330
layout(location = 0) out vec3 color;

in vec2 vTex;

uniform sampler2D tex;

void main()
{
vec2 coord = vTex;

coord = vec2(vTex.x, 1.0 - vTex.y);

vec4 col = texture(tex, coord);

color = col.xyz;
}
13 changes: 13 additions & 0 deletions res/shader/sprite.vs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#version 330
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTex;

out vec2 vTex;

uniform mat4 tform;

void main()
{
vTex = aTex;
gl_Position = tform * vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
Binary file added res/sprite/test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 38 additions & 24 deletions src/engine/base.nim
Original file line number Diff line number Diff line change
@@ -1,49 +1,63 @@
import nimgl/[glfw, opengl]
import graphics/sprite
import graphics/renderer as rnd
import os
include base/renderer
include base/scene_manager

var should_quit* = false
var renderer*: Renderer = nil
var dt*: float32

var update_fnc*: proc(dt: float, w: GLFWWindow) = nil
var update_fnc*: proc() = nil
var render_fnc*: proc() = nil
var quit_fnc*: proc(w: GLFWWindow) = nil
var quit_fnc*: proc() = nil

proc launch_game*() =
assert glfwInit()
assert glfwInit()

glfwWindowHint(GLFWContextVersionMajor, 3)
glfwWindowHint(GLFWContextVersionMinor, 3)
glfwWindowHint(GLFWOpenglForwardCompat, GLFW_TRUE) # Used for Mac
glfwWindowHint(GLFWOpenglProfile, GLFW_OPENGL_CORE_PROFILE)
glfwWindowHint(GLFWResizable, GLFW_FALSE)
glfwWindowHint(GLFWContextVersionMajor, 3)
glfwWindowHint(GLFWContextVersionMinor, 3)
glfwWindowHint(GLFWOpenglForwardCompat, GLFW_TRUE) # Used for Mac
glfwWindowHint(GLFWOpenglProfile, GLFW_OPENGL_CORE_PROFILE)
glfwWindowHint(GLFWResizable, GLFW_FALSE)

let w: GLFWWindow = glfwCreateWindow(800, 600, "Minijam 110")
if w == nil:
quit(-1)

w.makeContextCurrent()
let glfw_window*: GLFWWindow = glfwCreateWindow(800, 600, "Minijam 110")
if glfw_window == nil:
quit(-1)

glfw_window.makeContextCurrent()

# Active V-sync, useful to avoid FPS being in the thousands!
glfwSwapInterval(1)

assert glInit()

assert glInit()
renderer = create_renderer("res/shader/fullscreen", 800, 600)

renderer = create_renderer("res/shader/fullscreen")
proc launch_game*() =
assert scene_stack.len > 0, "Remember to add a scene before starting the game"

var last_time = glfwGetTime()

var dt = 0.0
# Launch the main loop
while not should_quit:
glfwPollEvents()

update_fnc(dt, w)
update_fnc()
scene_manager_update()

glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT)

renderer.render()
renderer.before_render()
if render_fnc != nil: render_fnc()
scene_manager_render(renderer)
renderer.render()

w.swapBuffers()
glfw_window.swapBuffers()
var new_time = glfwGetTime()
dt = new_time - last_time
last_time = new_time

if quit_fnc != nil: quit_fnc(w)
if quit_fnc != nil: quit_fnc()

w.destroyWindow()
glfw_window.destroyWindow()
glfwTerminate()
116 changes: 116 additions & 0 deletions src/engine/base/renderer.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Do not "import" as it will cause issues with the global "renderer"!
# (it's already included by base)

# Implements generic, layered drawing for drawables, binding
# only the most basic uniforms in the shaders:
# tform: camera + object transformation
# It renders to a framebuffer to allow fullscreen effects
# Layering is achieved by the use of the depth buffer!
# Drawables must implement:
# -> .position (returns Vec2f, position of the drawable), (optional if using draw_at)
# -> .shader (returns a shader to be used for the draw)
# -> .do_draw (calls the appropiate OpenGL for actually drawing the object, including additional shader stuff)
# -> .layer (returns int, the layer of the object)
# Keep layers below LAYER_CAP, as its used for scene overlaying

import ../graphics/camera
import ../graphics/shader
import ../graphics/gl_rectangle
import glm
import nimgl/opengl

const LAYER_CAP = 100000

type Renderer* = ref object
camera*: Camera
fullscreen_shader*: Shader
fbuffer, rnd_texture, depth_buffer: GLuint
# All drawable calls while layer_bias is enabled get increased by LAYER_CAP
layer_bias*: bool
width*, height*: int

proc resize(renderer: var Renderer, width: int, height: int) =
glViewport(0, 0, width.GLsizei, height.GLsizei)

renderer.width = width
renderer.height = height

# Remove the old buffers if present
if renderer.fbuffer != 0:
glDeleteFramebuffers(1, addr renderer.fbuffer)
glDeleteTextures(1, addr renderer.rnd_texture)
glDeleteRenderbuffers(1, addr renderer.depth_buffer)

glGenFramebuffers(1, addr renderer.fbuffer)
glBindFramebuffer(GL_FRAMEBUFFER, renderer.fbuffer)

glGenTextures(1, addr renderer.rnd_texture)
glBindTexture(GL_TEXTURE_2D, renderer.rnd_texture)

glTexImage2D(GL_TEXTURE_2D, 0'i32, GL_RGB.GLint, width.GLsizei, height.GLsizei, 0.GLint, GL_RGB, GL_UNSIGNED_BYTE, nil)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST.GLint)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST.GLint)

glGenRenderbuffers(1, addr renderer.depth_buffer)
glBindRenderbuffer(GL_RENDERBUFFER, renderer.depth_buffer)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width.GLsizei, height.GLsizei)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderer.depth_buffer)

glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderer.rnd_texture, 0)
var dbuffers = [GL_COLOR_ATTACHMENT_0]
glDrawBuffers(1, addr dbuffers[0])



proc create_renderer*(shader_path: string, width: int, height: int): Renderer =
let shader = load_shader(shader_path)
let camera = create_camera()
var rnd = Renderer(camera: camera, fullscreen_shader: shader)
rnd.resize(width, height)
return rnd

# Render stuff to the framebuffer after this call
proc before_render*(renderer: Renderer) =
glBindFramebuffer(GL_FRAMEBUFFER, renderer.fbuffer)

# Stop rendering stuff to the framebuffer after this call
proc render*(renderer: Renderer) =

# Draw the fullscreen rectangle, binding texture 0
glBindFramebuffer(GL_FRAMEBUFFER, 0);
renderer.fullscreen_shader.use()
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, renderer.rnd_texture)
renderer.fullscreen_shader.set_int("tex", 0)

var tform = translate(mat4f(), -1.0, -1.0, 0.0).scale(2.0, 2.0, 2.0)
renderer.fullscreen_shader.set_mat4("tform", tform)
draw_rectangle()

proc draw*[T](renderer: Renderer, drawable: T) =
drawable.shader.use()

let pos = drawable.position
var layer = drawable.layer
assert layer < LAYER_CAP
if renderer.layer_bias:
layer += LAYER_CAP
var tform = renderer.camera.get_transform_matrix()
tform = tform.translate(pos.x, pos.y, layer.toFloat())

drawable.shader.set_mat4("tform", tform)
drawable.do_draw()

proc draw_at*[T](renderer: Renderer, drawable: T, pos: Vec2f) =
drawable.shader.use()

var layer = drawable.layer
assert layer < LAYER_CAP
if renderer.layer_bias:
layer += LAYER_CAP
var tform = renderer.camera.get_transform_matrix()
tform = tform.translate(pos.x, pos.y, layer.toFloat())

drawable.shader.set_mat4("tform", tform)
drawable.do_draw()
49 changes: 49 additions & 0 deletions src/engine/base/scene_manager.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# As renderer, do not manually import, as this is an integral part of the engine

# Implements a basic scene manager based on OOP.
# Scenes may implement the following functions:
# -> init(): called on load of the scene
# -> update(): called every frame the scene is active
# -> render(): called every frame the scene is active / overlaid with rendering
# -> unload(): called on unloading of the scene
# Scenes may be overlaid, in such a way that the bottom scene renders but does not update
# (Useful for menus. Only one scene may be overlaid on top of another)
# Bottom scenes are always below top scenes via the adding of a big number to the layer of upper scene
# Scene travel works in a stack fashion

type Scene* = ref object of RootObj

method init(this: Scene) {.base.} = return
method update(this: Scene) {.base.} = return
method render(this: Scene) {.base.} = return
method unload(this: Scene) {.base.} = return

var scene_stack = newSeq[Scene]()
var overlaid = false

# Loads a new scene, optionally as an overlay
proc load_scene*(scene: Scene, overlay: bool = false) =
scene_stack.add(scene)
if overlay:
assert scene_stack.len >= 2
assert overlaid == false
overlaid = true

# Goes to previous scene
proc leave_scene*() =
scene_stack.setLen(scene_stack.len - 1)
if overlaid:
overlaid = false

proc is_overlaid(): bool = return overlaid

proc scene_manager_update*() =
scene_stack[^1].update()

proc scene_manager_render*(renderer: Renderer) =

scene_stack[^1].render()
if overlaid:
renderer.layer_bias = true
scene_stack[^2].render()
renderer.layer_bias = false
6 changes: 3 additions & 3 deletions src/engine/graphics/camera.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
import glm

type Camera* = ref object
center: Vec2f
center*: Vec2f
# Scale is pixels / unit, rotation in radians
scale, rotation: float
scale*, rotation*: float

proc create_camera*(): Camera =
return Camera(center: vec2f(0, 0), scale: 1.0, rotation: 0.0)

# Obtains a transform matrix such that the world is rendered
proc get_transform_matrix*(cam: Camera): Mat4f =
result = result.translate(vec3f(cam.center, 0.0))
return mat4f().translate(vec3f(-cam.center, 0.0))
.rotate(cam.rotation, 0, 0, 1)
.scale(cam.scale, cam.scale, cam.scale)
23 changes: 0 additions & 23 deletions src/engine/graphics/renderer.nim

This file was deleted.

17 changes: 16 additions & 1 deletion src/engine/graphics/shader.nim
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,19 @@ proc use*(shader: Shader) =
glUseProgram(shader.gl)

proc set_mat4*(shader: Shader, name: cstring, mat: var Mat4f) =
glUniformMatrix4fv(glGetUniformLocation(shader.gl, name), 1.GLsizei, false, mat.caddr)
glUniformMatrix4fv(glGetUniformLocation(shader.gl, name), 1.GLsizei, false, mat.caddr)

proc set_int*(shader: Shader, name: cstring, val: int32) =
glUniform1i(glGetUniformLocation(shader.gl, name), val)

proc set_vec3*(shader: Shader, name: cstring, val: Vec3f) =
glUniform3f(glGetUniformLocation(shader.gl, name), val.x, val.y, val.z)

proc set_vec3*(shader: Shader, name: cstring, x: float32, y: float32, z: float32) =
glUniform3f(glGetUniformLocation(shader.gl, name), x, y, z)

proc set_vec4*(shader: Shader, name: cstring, val: Vec4f) =
glUniform4f(glGetUniformLocation(shader.gl, name), val.x, val.y, val.z, val.w)

proc set_vec4*(shader: Shader, name: cstring, x: float32, y: float32, z: float32, w: float32) =
glUniform4f(glGetUniformLocation(shader.gl, name), x, y, z, w)
Loading

0 comments on commit 1113312

Please sign in to comment.