@@ 0,0 1,95 @@
+import opengl
+import glm
+import sequtils
+import draw_util
+
+type DebugCtx = tuple
+ mesh: seq[Vec3f]
+ buffer: GLuint
+ buffer_vao: GLuint
+ prog: GLuint
+
+proc init_debug*(): DebugCtx =
+ var c: DebugCtx
+ c.mesh = @[]
+ c.prog = make_program((GL_VERTEX_SHADER, """
+#version 450 core
+ layout(location = 0) in vec3 vpos;
+ uniform mat4 MVP;
+ void main() {
+ gl_Position = MVP * vec4(vpos, 1.0);
+ }
+ """),
+ (GL_FRAGMENT_SHADER, """
+#version 450 core
+
+ out vec3 color;
+ uniform sampler2D diffuse;
+
+ void main() {
+ color = vec3(1, 1, 0);
+ }
+ """))
+
+ # setup debug draw buffer
+ gl_create_vertex_arrays(1, c.buffer_vao.addr)
+ gl_create_buffers(1, c.buffer.addr)
+ gl_enable_vertex_array_attrib(c.buffer_vao, 0)
+ gl_vertex_array_vertex_buffer(c.buffer_vao, 0, c.buffer, 0, Vec3f.sizeof.GLsizei)
+ gl_vertex_array_attrib_format(c.buffer_vao, 0, 3, cGL_FLOAT, false, 0) # pos
+ gl_named_buffer_data(c.buffer, Vec3f.sizeof * 1024, nil, GL_DYNAMIC_DRAW)
+
+ return c
+
+proc clear*(c: var DebugCtx) =
+ c.mesh.set_len(0)
+
+proc draw*(c: DebugCtx, mvp: var Mat4f) =
+ gl_use_program(c.prog)
+ let p = gl_map_named_buffer(c.buffer, GL_WRITE_ONLY)
+ copy_mem(p, c.mesh[0].unsafeAddr, Vec3f.sizeof * len(c.mesh))
+ discard gl_unmap_named_buffer(c.buffer)
+
+ gl_bind_vertex_array(c.buffer_vao)
+ gl_bind_buffer(GL_ARRAY_BUFFER, c.buffer)
+ gl_uniform_matrix4fv(gl_get_uniform_location(c.prog, "MVP"), 1, false, mvp.caddr)
+ gl_point_size(5)
+ gl_draw_arrays(GL_LINES, 0, (len(c.mesh)).GLsizei)
+ gl_draw_arrays(GL_POINTS, 0, (len(c.mesh)).GLsizei)
+
+proc edge*(c: var DebugCtx, vs: varargs[Vec3f]) =
+ for (a, b) in zip(vs, vs[1..^1]):
+ c.mesh.add(a)
+ c.mesh.add(b)
+
+proc sphere*(c: var DebugCtx, pos: Vec3f, radius: float32, np: uint = 8, nm: uint = 16) =
+ for j in 0..< np:
+ let pp = PI * (j).float / np.float
+ let p = PI * (j + 1).float / np.float
+ let
+ spp = sin(pp)
+ cpp = cos(pp)
+ let
+ sp = sin(p)
+ cp = cos(p)
+ for i in 1.. nm:
+ let pm = 2.0 * PI * (i - 1).float / nm.float
+ let m = 2.0 * PI * i.float / nm.float
+ # ring
+ c.edge(
+ pos + radius * vec3f(sp * cos(pm), cp, sp * sin(pm)),
+ pos + radius * vec3f(sp * cos(m), cp, sp * sin(m)))
+ # connecting edge
+ c.edge(
+ pos + radius * vec3f(spp * cos(m), cpp, spp * sin(m)),
+ pos + radius * vec3f(sp * cos(m), cp, sp * sin(m)))
+
+proc AABB*(c: var DebugCtx, a, b: Vec3f) =
+ c.edge(a, vec3f(a.x, b.y, a.z), vec3f(b.x, b.y, a.z), vec3f(b.x, a.y, a.z), a)
+ c.edge(vec3f(a.x, a.y, b.z), vec3f(a.x, b.y, b.z), vec3f(b.x, b.y, b.z), vec3f(b.x, a.y, b.z), vec3f(a.x, a.y, b.z))
+
+ c.edge(vec3f(a.x, a.y, a.z), vec3f(a.x, a.y, b.z))
+ c.edge(vec3f(b.x, a.y, a.z), vec3f(b.x, a.y, b.z))
+ c.edge(vec3f(b.x, b.y, a.z), vec3f(b.x, b.y, b.z))
+ c.edge(vec3f(a.x, b.y, a.z), vec3f(a.x, b.y, b.z))
+
@@ 8,11 8,12 @@ import strutils
import sugar
import sets
import macros
-import stb_image/read as stbi
import math
import complex
import options
import bitops
+import draw_util
+import debug_draw
const max_entities = 1024;
@@ 50,9 51,9 @@ when isMainModule:
## math
type
- Plane = tuple[pos: Vec3f, normal: Vec3f]
- Ellipse = tuple[pos: Vec3f, radius: Vec3f]
- Triangle = array[3, Vec3f]
+ Plane* = tuple[pos: Vec3f, normal: Vec3f]
+ Ellipse* = tuple[pos: Vec3f, radius: Vec3f]
+ Triangle* = array[3, Vec3f]
proc is_facing(p: Plane, dir: Vec3f): bool =
return p.normal.dot(dir) <= 0
@@ 99,25 100,6 @@ proc in_triangle(p: Vec3f, t: Triangle): bool =
let z = x + y - ac_bb
return bitand(bitand(z.uint32, bitnot(bitor(x.uint32, y.uint32))), 0x80000000.uint32) != 0
-
-
-
-proc make_program(shaders: varargs[(GLenum, string)]): uint32 =
- let program = gl_create_program()
- var shader_ids: seq[uint32] = @[]
- for (ty, source) in shaders:
- let shader = gl_create_shader(ty)
- let a = alloc_c_string_array([source])
- defer: dealloc_c_string_array(a)
- gl_shader_source(shader, 1, a, nil)
- gl_compile_shader(shader)
- gl_attach_shader(program, shader) # now attach to the main program
- shader_ids.add(shader)
- gl_link_program(program)
- for s in shader_ids:
- gl_delete_shader(s)
- return program
-
proc parse_obj(path: string): (seq[float32], seq[uint16]) =
var
vertices = newSeq[Vec3f]()
@@ 185,104 167,7 @@ proc parse_obj(path: string): (seq[float32], seq[uint16]) =
r.add(d)
return (r, element_indices)
-proc make_mesh(vertex_data: seq[float32], face_indices: seq[uint16]): uint =
- var vao_id: GLuint
- gl_gen_vertex_arrays(1, vao_id.addr)
- assert vao_id != 0
- gl_bind_vertex_array(vao_id)
- var vbo_id: GLuint
- gl_gen_buffers(1, vbo_id.addr)
-
- gl_bind_buffer(GL_ARRAY_BUFFER, vbo_id)
- gl_buffer_data(GL_ARRAY_BUFFER, vertex_data.len * float32.sizeof, vertex_data[0].unsafeAddr, GL_STATIC_DRAW)
-
- gl_vertex_attrib_pointer(0, 3, cGL_FLOAT, false, 8 * float32.sizeof, cast[ptr int](0)) # pos
- gl_enable_vertex_attrib_array(0)
- gl_vertex_attrib_pointer(1, 3, cGL_FLOAT, false, 8 * float32.sizeof, cast[ptr int](3 * float32.sizeof)) # normal
- gl_enable_vertex_attrib_array(1)
- gl_vertex_attrib_pointer(2, 2, cGL_FLOAT, false, 8 * float32.sizeof, cast[ptr int](6 * float32.sizeof)) # uv
- gl_enable_vertex_attrib_array(2)
-
- var ebo_id: GLuint
- gl_gen_buffers(1, ebo_id.addr)
-
- gl_bind_buffer(GL_ELEMENT_ARRAY_BUFFER, ebo_id)
- gl_buffer_data(GL_ELEMENT_ARRAY_BUFFER, face_indices.len * uint16.sizeof, face_indices[0].unsafeAddr, GL_STATIC_DRAW)
-
- gl_bind_vertex_array(0)
- return vao_id
-
-proc load_mesh(path: string): uint16 =
- let (vert_data, face_indices) = parse_obj(path)
- let vao = make_mesh(vert_data, face_indices)
- meshes.add((filepath: path, vao: vao.uint32, nfaces: face_indices.len.uint16, nverts: (face_indices.len * 3).uint16).Mesh)
- return (meshes.len - 1).uint16
-
-proc load_texture(file: string): uint64 =
- # TODO: check if the file existed first
- #let q = textures.where((file: file, id: _,
- var tex_id: GLuint
- var w, h, nchannels: int
- let data = stbi.load(file, w, h, nchannels, stbi.Default)
-
- gl_create_textures(GL_TEXTURE_2D, 1, tex_id.addr)
- gl_texture_parameteri(tex_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
- gl_texture_parameteri(tex_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
- gl_texture_parameteri(tex_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
- gl_texture_parameteri(tex_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
-
- let num_mipmaps = (log2(float(max(w, h) + 1))).GLsizei;
- gl_texture_storage_2d(tex_id, num_mipmaps, GL_RGB8, w.GLsizei, h.GLsizei);
- gl_texture_subimage_2d(tex_id, 0, 0, 0, w.GLsizei, h.GLsizei, GL_RGBA, GL_UNSIGNED_BYTE, data[0].unsafeAddr)
- gl_generate_texture_mipmap(tex_id)
-
- let handle = gl_get_texture_handle_arb(tex_id)
- gl_make_texture_handle_resident_arb(handle)
- textures.insert((filepath: file, handle: handle, width: w.uint16, height: h.uint16).Texture)
- return handle
-
-var debug_mesh = newSeq[Vec3f]()
-
-proc debug_edge(vs: varargs[Vec3f]) =
- for (a, b) in zip(vs, vs[1..^1]):
- debug_mesh.add(a)
- debug_mesh.add(b)
-
-
-proc debug_sphere(pos: Vec3f, radius: float32, np: uint = 8, nm: uint = 16) =
- for j in 0..< np:
- let pp = PI * (j).float / np.float
- let p = PI * (j + 1).float / np.float
- let
- spp = sin(pp)
- cpp = cos(pp)
- let
- sp = sin(p)
- cp = cos(p)
- for i in 1.. nm:
- let pm = 2.0 * PI * (i - 1).float / nm.float
- let m = 2.0 * PI * i.float / nm.float
- # ring
- debug_edge(
- pos + radius * vec3f(sp * cos(pm), cp, sp * sin(pm)),
- pos + radius * vec3f(sp * cos(m), cp, sp * sin(m)))
- # connecting edge
- debug_edge(
- pos + radius * vec3f(spp * cos(m), cpp, spp * sin(m)),
- pos + radius * vec3f(sp * cos(m), cp, sp * sin(m)))
-
-proc debug_sphere(e: Ellipse) = debug_sphere(e.pos, e.radius.x)
-
-proc debug_AABB(a, b: Vec3f) =
- debug_edge(a, vec3f(a.x, b.y, a.z), vec3f(b.x, b.y, a.z), vec3f(b.x, a.y, a.z), a)
- debug_edge(vec3f(a.x, a.y, b.z), vec3f(a.x, b.y, b.z), vec3f(b.x, b.y, b.z), vec3f(b.x, a.y, b.z), vec3f(a.x, a.y, b.z))
-
- debug_edge(vec3f(a.x, a.y, a.z), vec3f(a.x, a.y, b.z))
- debug_edge(vec3f(b.x, a.y, a.z), vec3f(b.x, a.y, b.z))
- debug_edge(vec3f(b.x, b.y, a.z), vec3f(b.x, b.y, b.z))
- debug_edge(vec3f(a.x, b.y, a.z), vec3f(a.x, b.y, b.z))
-
-proc check_collision(e: Ellipse, vel: Vec3f, tri: Triangle): Option[Vec3f] =
+proc check_collision*(e: Ellipse, vel: Vec3f, tri: Triangle): Option[Vec3f] =
let tp = triangle_plane(tri)
if not tp.is_facing(-vel):
return
@@ 363,242 248,215 @@ proc check_collision(e: Ellipse, vel: Vec3f, tri: Triangle): Option[Vec3f] =
if found_col:
return some(col_point)
-var cam_pos = vec3f(0, 1, 2)
-var cam_look = vec3f(0, 0, 1)
-let cam_up = vec3f(0, 1, 0)
-var cam_yaw: float = radians(0.0)
-var cam_pitch: float = radians(90.0)
-
-let width = 800
-let height = 600
-
-var last_x = (width/2).float64
-var last_y = (height/2).float64
-
-proc cursor_pos_callback(w: Window, pos: tuple[x, y: float64]) =
- let dx = last_x - pos.x
- let dy = last_y - pos.y
- last_x = pos.x
- last_y = pos.y
- cam_pitch += (dy * 0.1)
- cam_yaw -= (dx * 0.1)
- cam_look.x = cos(radians(cam_pitch)) * cos(radians(cam_yaw))
- cam_look.y = sin(radians(cam_pitch))
- cam_look.z = cos(radians(cam_pitch)) * sin(radians(cam_yaw))
- cam_look = cam_look.normalize()
+proc load_mesh(path: string): uint16 =
+ let (vert_data, face_indices) = parse_obj(path)
+ let vao = make_mesh(vert_data, face_indices)
+ meshes.add((filepath: path, vao: vao.uint32, nfaces: face_indices.len.uint16, nverts: (face_indices.len * 3).uint16).Mesh)
+ return (meshes.len - 1).uint16
-###
+if is_main_module:
+ var cam_pos = vec3f(0, 1, 2)
+ var cam_look = vec3f(0, 0, 1)
+ let cam_up = vec3f(0, 1, 0)
+ var cam_yaw: float = radians(0.0)
+ var cam_pitch: float = radians(90.0)
-glfw.initialize()
+ let width = 800
+ let height = 600
-load_extensions()
+ var last_x = (width/2).float64
+ var last_y = (height/2).float64
-var c = DefaultOpenglWindowConfig
-c.title = "game"
-var w = new_window(c)
-w.cursor_position_cb = cursor_pos_callback
-w.cursor_mode = cm_disabled
+ proc cursor_pos_callback(w: Window, pos: tuple[x, y: float64]) =
+ let dx = last_x - pos.x
+ let dy = last_y - pos.y
+ last_x = pos.x
+ last_y = pos.y
+ cam_pitch += (dy * 0.1)
+ cam_yaw -= (dx * 0.1)
+ cam_look.x = cos(radians(cam_pitch)) * cos(radians(cam_yaw))
+ cam_look.y = sin(radians(cam_pitch))
+ cam_look.z = cos(radians(cam_pitch)) * sin(radians(cam_yaw))
+ cam_look = cam_look.normalize()
-glfw.make_context_current(w)
+ ###
-var debug_buffer: GLuint
-var debug_buffer_vao: GLuint
-let debug_prog = make_program((GL_VERTEX_SHADER, """
-#version 450 core
-layout(location = 0) in vec3 vpos;
-uniform mat4 MVP;
-void main() {
- gl_Position = MVP * vec4(vpos, 1.0);
-}
-"""),
-(GL_FRAGMENT_SHADER, """
-#version 450 core
+ glfw.initialize()
-out vec3 color;
-uniform sampler2D diffuse;
+ load_extensions()
-void main() {
- color = vec3(1, 1, 0);
-}
-"""))
+ var c = DefaultOpenglWindowConfig
+ c.title = "game"
+ var w = new_window(c)
+ w.cursor_position_cb = cursor_pos_callback
+ w.cursor_mode = cm_disabled
-block: # setup debug draw buffer
- gl_create_vertex_arrays(1, debug_buffer_vao.addr)
- gl_create_buffers(1, debug_buffer.addr)
- gl_enable_vertex_array_attrib(debug_buffer_vao, 0)
- gl_vertex_array_vertex_buffer(debug_buffer_vao, 0, debug_buffer, 0, Vec3f.sizeof.GLsizei)
- gl_vertex_array_attrib_format(debug_buffer_vao, 0, 3, cGL_FLOAT, false, 0) # pos
- gl_named_buffer_data(debug_buffer, Vec3f.sizeof * 1024, nil, GL_DYNAMIC_DRAW)
+ glfw.make_context_current(w)
+ var debug = init_debug()
-###
+ ###
-let prog = make_program((GL_VERTEX_SHADER, """
+ let prog = make_program((GL_VERTEX_SHADER, """
#version 450 core
#extension GL_ARB_bindless_texture : require
-layout(location = 0) in vec3 vpos;
-layout(location = 1) in vec3 norm;
-layout(location = 2) in vec2 iuv;
-uniform mat4 M;
-uniform mat4 MVP;
-
-uniform mat4 lightSpaceMatrix;
-
-out vec3 normal;
-out vec3 worldPos;
-out vec4 fragPosLightSpace;
-out vec2 uv;
-void main() {
- gl_Position = MVP * vec4(vpos, 1.0);
- uv = iuv;
- worldPos = (M * vec4(vpos, 1.0)).xyz;
- fragPosLightSpace = lightSpaceMatrix * vec4(worldPos, 1.0);
- normal = norm;
-}
-"""),
-(GL_FRAGMENT_SHADER, """
+ layout(location = 0) in vec3 vpos;
+ layout(location = 1) in vec3 norm;
+ layout(location = 2) in vec2 iuv;
+ uniform mat4 M;
+ uniform mat4 MVP;
+
+ uniform mat4 lightSpaceMatrix;
+
+ out vec3 normal;
+ out vec3 worldPos;
+ out vec4 fragPosLightSpace;
+ out vec2 uv;
+ void main() {
+ gl_Position = MVP * vec4(vpos, 1.0);
+ uv = iuv;
+ worldPos = (M * vec4(vpos, 1.0)).xyz;
+ fragPosLightSpace = lightSpaceMatrix * vec4(worldPos, 1.0);
+ normal = norm;
+ }
+ """),
+ (GL_FRAGMENT_SHADER, """
#version 450 core
#extension GL_ARB_bindless_texture : require
-in vec3 normal;
-in vec3 worldPos;
-in vec4 fragPosLightSpace;
-in vec2 uv;
-out vec3 color;
-layout(bindless_sampler, location=1) uniform sampler2D diffuse;
-
-void main() {
- vec3 lightPos = vec3(4, 4, 4);
- vec3 n = normalize(normal);
- vec3 lightDir = normalize(lightPos - worldPos);
- float diff = max(dot(n, lightDir), 0.0);
- color = diff * texture(diffuse, uv).xyz;
-}
-"""
-))
-
-let wireframe_prog = make_program((GL_VERTEX_SHADER, """
+ in vec3 normal;
+ in vec3 worldPos;
+ in vec4 fragPosLightSpace;
+ in vec2 uv;
+ out vec3 color;
+ layout(bindless_sampler, location=1) uniform sampler2D diffuse;
+
+ void main() {
+ vec3 lightPos = vec3(4, 4, 4);
+ vec3 n = normalize(normal);
+ vec3 lightDir = normalize(lightPos - worldPos);
+ float diff = max(dot(n, lightDir), 0.0);
+ color = diff * texture(diffuse, uv).xyz;
+ }
+ """
+ ))
+
+ let wireframe_prog = make_program((GL_VERTEX_SHADER, """
#version 450 core
-layout(location = 0) in vec3 vpos;
-layout(location = 1) in vec3 norm;
-layout(location = 2) in vec2 iuv;
-uniform mat4 MVP;
-
-void main() {
- gl_Position = MVP * vec4(vpos, 1.0);
-}
-"""),
-(GL_GEOMETRY_SHADER, """
+ layout(location = 0) in vec3 vpos;
+ layout(location = 1) in vec3 norm;
+ layout(location = 2) in vec2 iuv;
+ uniform mat4 MVP;
+
+ void main() {
+ gl_Position = MVP * vec4(vpos, 1.0);
+ }
+ """),
+ (GL_GEOMETRY_SHADER, """
#version 450
-layout (triangles) in;
-layout (line_strip /*for lines, use "points" for points*/, max_vertices=3) out;
+ layout (triangles) in;
+ layout (line_strip, max_vertices=3) out;
-void main(void)
-{
- int i;
- for (i = 0; i < gl_in.length(); i++)
+ void main(void)
{
- gl_Position = gl_in[i].gl_Position; //Pass through
- EmitVertex();
+ int i;
+ for (i = 0; i < gl_in.length(); i++)
+ {
+ gl_Position = gl_in[i].gl_Position; //Pass through
+ EmitVertex();
+ }
+ EndPrimitive();
}
- EndPrimitive();
-}
-"""
-),
-(GL_FRAGMENT_SHADER, """
+ """
+ ),
+ (GL_FRAGMENT_SHADER, """
#version 450 core
-out vec3 color;
-uniform sampler2D diffuse;
-
-void main() {
- color = vec3(0, 1, 1);
-}
-"""
-))
-
-let player_mesh = load_mesh("ninja.obj")
-drawables.add((mesh_id: player_mesh, pos: vec3f(0, 0, 0)).Drawable)
-let ninja_tex = load_texture("ninja_mask.png")
-let test_tex = load_texture("test.png")
-texture_bindings.insert((player_mesh, ninja_tex, "diffuse").TextureBinding)
-
-let terrain_id = load_mesh("terrain.obj")
-drawables.add((mesh_id: terrain_id, pos: vec3f(0, 0, 0)).Drawable)
-texture_bindings.insert((terrain_id, test_tex, "diffuse").TextureBinding)
-
-gl_clear_color(0, 0, 0, 1)
-gl_clear_depth(1)
-gl_enable(GL_DEPTH_TEST)
-gl_depth_func(GL_LEQUAL)
-
-var ell = (pos: vec3f(0, 0, 0), radius: vec3f(1, 1, 1)).Ellipse
-
-let proj: Mat4[float32] = perspective[float32](Pi / 4, width.float32 / height.float32, 0.1, 100)
-
-let use_progs = [prog, wireframe_prog]
-var use_prog_i = 0
-var use_prog = use_progs[use_prog_i]
-
-proc keyboard_callback(w: Window, key: Key, scancode: int32, action: KeyAction, modKeys: set[ModifierKey]) =
- if key == Key.keyV and action == KeyAction.kaDown:
- use_prog_i = (use_prog_i + 1) mod len(use_progs)
- use_prog = use_progs[use_prog_i]
-w.key_cb = keyboard_callback
-
-while true:
- let move_speed = if w.is_key_down(Key.keyLeftShift): 0.2 else: 0.05
- if w.is_key_down(Key.keyW): cam_pos += move_speed.float32 * cam_look
- if w.is_key_down(Key.keyS): cam_pos -= move_speed.float32 * cam_look
- if w.is_key_down(Key.keyA): cam_pos -= move_speed.float32 * cam_look.cross(cam_up).normalize
- if w.is_key_down(Key.keyD): cam_pos += move_speed.float32 * cam_look.cross(cam_up).normalize
- ####
- if w.is_key_down(Key.keyI): ell.pos.y += 0.1
- if w.is_key_down(Key.keyK): ell.pos.y -= 0.1
- if w.is_key_down(Key.keyJ): ell.pos.x += 0.1
- if w.is_key_down(Key.keyL): ell.pos.x -= 0.1
-
- let view: Mat4[float32] = look_at(cam_pos, cam_pos + cam_look, cam_up)
- gl_clear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) # Clear color and depth buffers
- gl_use_program(use_prog)
- debug_mesh = @[]
- for id, d in drawables:
- let mesh = meshes[d.mesh_id]
-
- for i, b in texture_bindings.where((drawable_id: id.uint16, texture_id: _, texture_name: _)):
- gl_uniform_handle_ui64ARB(gl_get_uniform_location(use_prog, b.texture_name), b.texture_handle)
-
- var m = translate(mat4f(), d.pos) # model matrix
- var mvp: Mat4[float32] = proj * view * m
-
- gl_uniform_matrix4fv(gl_get_uniform_location(use_prog, "MVP"), 1, false, mvp.caddr)
- gl_uniform_matrix4fv(gl_get_uniform_location(use_prog, "M"), 1, false, m.caddr)
-
- gl_bind_vertex_array(mesh.vao)
- gl_draw_elements(GL_TRIANGLES, mesh.nfaces.GLsizei, cGL_UNSIGNED_SHORT, cast[ptr int](0))
-
- #debug_edge(vec3f(0, 0, 0), vec3f(0.1,0.1,0.1))
- #debug_edge(vec3f(0.1,0.1,0.1), vec3f(-0.3,0.1,0.1))
- debug_AABB(vec3f(0, 0, 2), vec3f(1, 1, 3))
- debug_sphere(ell)
-
- block: # draw debug
- gl_use_program(debug_prog)
- let p = gl_map_named_buffer(debug_buffer, GL_WRITE_ONLY)
- copy_mem(p, debug_mesh[0].unsafeAddr, Vec3f.sizeof * len(debug_mesh))
- discard gl_unmap_named_buffer(debug_buffer)
-
- gl_bind_vertex_array(debug_buffer_vao)
- gl_bind_buffer(GL_ARRAY_BUFFER, debug_buffer)
- var mvp: Mat4[float32] = proj * view
- gl_uniform_matrix4fv(gl_get_uniform_location(debug_prog, "MVP"), 1, false, mvp.caddr)
- gl_point_size(5)
- gl_draw_arrays(GL_LINES, 0, (len(debug_mesh)).GLsizei)
- gl_draw_arrays(GL_POINTS, 0, (len(debug_mesh)).GLsizei)
-
- w.swap_buffers
- poll_events()
- if w.should_close == true or w.is_key_down(keyEscape):
- break
-
-w.destroy()
-glfw.terminate()
+ out vec3 color;
+ uniform sampler2D diffuse;
+
+ void main() {
+ color = vec3(0, 1, 1);
+ }
+ """
+ ))
+
+ let player_mesh = load_mesh("ninja.obj")
+ drawables.add((mesh_id: player_mesh, pos: vec3f(0, 0, 0)).Drawable)
+
+ let ninja_tex = load_texture("ninja_mask.png").Texture
+ textures.insert(ninja_tex)
+ let test_tex = load_texture("test.png").Texture
+ textures.insert(test_tex)
+ texture_bindings.insert((player_mesh, ninja_tex.handle, "diffuse").TextureBinding)
+
+ let terrain_id = load_mesh("terrain.obj")
+ drawables.add((mesh_id: terrain_id, pos: vec3f(0, 0, 0)).Drawable)
+ texture_bindings.insert((terrain_id, test_tex.handle, "diffuse").TextureBinding)
+
+ gl_clear_color(0, 0, 0, 1)
+ gl_clear_depth(1)
+ gl_enable(GL_DEPTH_TEST)
+ gl_depth_func(GL_LEQUAL)
+
+ var ell = (pos: vec3f(0, 0, 0), radius: vec3f(1, 1, 1)).Ellipse
+
+ let proj: Mat4[float32] = perspective[float32](Pi / 4, width.float32 / height.float32, 0.1, 100)
+
+ let use_progs = [prog, wireframe_prog]
+ var use_prog_i = 0
+ var use_prog = use_progs[use_prog_i]
+
+ proc keyboard_callback(w: Window, key: Key, scancode: int32, action: KeyAction, modKeys: set[ModifierKey]) =
+ if key == Key.keyV and action == KeyAction.kaDown:
+ use_prog_i = (use_prog_i + 1) mod len(use_progs)
+ use_prog = use_progs[use_prog_i]
+ w.key_cb = keyboard_callback
+
+ while true:
+ let move_speed = if w.is_key_down(Key.keyLeftShift): 0.2 else: 0.05
+ if w.is_key_down(Key.keyW): cam_pos += move_speed.float32 * cam_look
+ if w.is_key_down(Key.keyS): cam_pos -= move_speed.float32 * cam_look
+ if w.is_key_down(Key.keyA): cam_pos -= move_speed.float32 * cam_look.cross(cam_up).normalize
+ if w.is_key_down(Key.keyD): cam_pos += move_speed.float32 * cam_look.cross(cam_up).normalize
+ ####
+ if w.is_key_down(Key.keyI): ell.pos.y += 0.1
+ if w.is_key_down(Key.keyK): ell.pos.y -= 0.1
+ if w.is_key_down(Key.keyJ): ell.pos.x += 0.1
+ if w.is_key_down(Key.keyL): ell.pos.x -= 0.1
+
+ let view: Mat4[float32] = look_at(cam_pos, cam_pos + cam_look, cam_up)
+ gl_clear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) # Clear color and depth buffers
+ gl_use_program(use_prog)
+
+ debug.clear()
+
+ for id, d in drawables:
+ let mesh = meshes[d.mesh_id]
+
+ for i, b in texture_bindings.where((drawable_id: id.uint16, texture_id: _, texture_name: _)):
+ gl_uniform_handle_ui64ARB(gl_get_uniform_location(use_prog, b.texture_name), b.texture_handle)
+
+ var m = translate(mat4f(), d.pos) # model matrix
+ var mvp: Mat4[float32] = proj * view * m
+
+ gl_uniform_matrix4fv(gl_get_uniform_location(use_prog, "MVP"), 1, false, mvp.caddr)
+ gl_uniform_matrix4fv(gl_get_uniform_location(use_prog, "M"), 1, false, m.caddr)
+
+ gl_bind_vertex_array(mesh.vao)
+ gl_draw_elements(GL_TRIANGLES, mesh.nfaces.GLsizei, cGL_UNSIGNED_SHORT, cast[ptr int](0))
+
+ #debug_edge(vec3f(0, 0, 0), vec3f(0.1,0.1,0.1))
+ #debug_edge(vec3f(0.1,0.1,0.1), vec3f(-0.3,0.1,0.1))
+ debug.AABB(vec3f(0, 0, 2), vec3f(1, 1, 3))
+ debug.sphere(ell.pos, ell.radius.x)
+
+ var debug_mvp = proj * view
+ debug.draw(debug_mvp)
+
+ w.swap_buffers
+ poll_events()
+ if w.should_close == true or w.is_key_down(keyEscape):
+ break
+
+ w.destroy()
+ glfw.terminate()
@@ 0,0 1,69 @@
+import opengl
+import stb_image/read as stbi
+import math
+
+proc make_program*(shaders: varargs[(GLenum, string)]): uint32 =
+ let program = gl_create_program()
+ var shader_ids: seq[uint32] = @[]
+ for (ty, source) in shaders:
+ let shader = gl_create_shader(ty)
+ let a = alloc_c_string_array([source])
+ defer: dealloc_c_string_array(a)
+ gl_shader_source(shader, 1, a, nil)
+ gl_compile_shader(shader)
+ gl_attach_shader(program, shader) # now attach to the main program
+ shader_ids.add(shader)
+ gl_link_program(program)
+ for s in shader_ids:
+ gl_delete_shader(s)
+ return program
+
+proc make_mesh*(vertex_data: seq[float32], face_indices: seq[uint16]): uint =
+ var vao_id: GLuint
+ gl_gen_vertex_arrays(1, vao_id.addr)
+ assert vao_id != 0
+ gl_bind_vertex_array(vao_id)
+ var vbo_id: GLuint
+ gl_gen_buffers(1, vbo_id.addr)
+
+ gl_bind_buffer(GL_ARRAY_BUFFER, vbo_id)
+ gl_buffer_data(GL_ARRAY_BUFFER, vertex_data.len * float32.sizeof, vertex_data[0].unsafeAddr, GL_STATIC_DRAW)
+
+ gl_vertex_attrib_pointer(0, 3, cGL_FLOAT, false, 8 * float32.sizeof, cast[ptr int](0)) # pos
+ gl_enable_vertex_attrib_array(0)
+ gl_vertex_attrib_pointer(1, 3, cGL_FLOAT, false, 8 * float32.sizeof, cast[ptr int](3 * float32.sizeof)) # normal
+ gl_enable_vertex_attrib_array(1)
+ gl_vertex_attrib_pointer(2, 2, cGL_FLOAT, false, 8 * float32.sizeof, cast[ptr int](6 * float32.sizeof)) # uv
+ gl_enable_vertex_attrib_array(2)
+
+ var ebo_id: GLuint
+ gl_gen_buffers(1, ebo_id.addr)
+
+ gl_bind_buffer(GL_ELEMENT_ARRAY_BUFFER, ebo_id)
+ gl_buffer_data(GL_ELEMENT_ARRAY_BUFFER, face_indices.len * uint16.sizeof, face_indices[0].unsafeAddr, GL_STATIC_DRAW)
+
+ gl_bind_vertex_array(0)
+ return vao_id
+
+proc load_texture*(file: string): tuple[filepath: string, handle: GLuint64, width: uint16, height: uint16] =
+ # TODO: check if the file existed first
+ #let q = textures.where((file: file, id: _,
+ var tex_id: GLuint
+ var w, h, nchannels: int
+ let data = stbi.load(file, w, h, nchannels, stbi.Default)
+
+ gl_create_textures(GL_TEXTURE_2D, 1, tex_id.addr)
+ gl_texture_parameteri(tex_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
+ gl_texture_parameteri(tex_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
+ gl_texture_parameteri(tex_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
+ gl_texture_parameteri(tex_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
+
+ let num_mipmaps = (log2(float(max(w, h) + 1))).GLsizei;
+ gl_texture_storage_2d(tex_id, num_mipmaps, GL_RGB8, w.GLsizei, h.GLsizei);
+ gl_texture_subimage_2d(tex_id, 0, 0, 0, w.GLsizei, h.GLsizei, GL_RGBA, GL_UNSIGNED_BYTE, data[0].unsafeAddr)
+ gl_generate_texture_mipmap(tex_id)
+
+ let handle = gl_get_texture_handle_arb(tex_id)
+ gl_make_texture_handle_resident_arb(handle)
+ return (filepath: file, handle: handle, width: w.uint16, height: h.uint16)
+