diff --git a/assets/shaders/gradient.comp.spv b/assets/shaders/gradient.comp.spv index 06f8533..a2239d5 100644 Binary files a/assets/shaders/gradient.comp.spv and b/assets/shaders/gradient.comp.spv differ diff --git a/assets/shaders/gui.frag.spv b/assets/shaders/gui.frag.spv index a9ba04a..bcbfac2 100644 Binary files a/assets/shaders/gui.frag.spv and b/assets/shaders/gui.frag.spv differ diff --git a/assets/shaders/gui.vert.spv b/assets/shaders/gui.vert.spv index de658f0..45d2b37 100644 Binary files a/assets/shaders/gui.vert.spv and b/assets/shaders/gui.vert.spv differ diff --git a/assets/shaders/pbr.frag.spv b/assets/shaders/pbr.frag.spv index 6feb4da..049dc69 100644 Binary files a/assets/shaders/pbr.frag.spv and b/assets/shaders/pbr.frag.spv differ diff --git a/assets/shaders/pbr.vert.spv b/assets/shaders/pbr.vert.spv index 5f2ca88..fd390a8 100644 Binary files a/assets/shaders/pbr.vert.spv and b/assets/shaders/pbr.vert.spv differ diff --git a/assets/shaders/triangle.frag.spv b/assets/shaders/triangle.frag.spv index 4af8fe9..7c6c243 100644 Binary files a/assets/shaders/triangle.frag.spv and b/assets/shaders/triangle.frag.spv differ diff --git a/assets/shaders/triangle.vert.spv b/assets/shaders/triangle.vert.spv index c1859a7..bdd93bf 100644 Binary files a/assets/shaders/triangle.vert.spv and b/assets/shaders/triangle.vert.spv differ diff --git a/src/gears/game.d b/src/gears/game.d index f019bd4..4c317a4 100644 --- a/src/gears/game.d +++ b/src/gears/game.d @@ -26,6 +26,7 @@ struct Game Pipeline ui_pipeline; GlobalUniforms globals; + PushConst pc; f32 delta; Timer timer; @@ -35,6 +36,7 @@ struct Game Model model; } + Game InitGame(PlatformWindow* window) { @@ -42,6 +44,11 @@ InitGame(PlatformWindow* window) rd: InitRenderer(window), window: window, timer: CreateTimer(), + globals: { + light_direction: Vec3(-0.57735), + light_color: Vec4(0.8, 0.8, 0.8, 1.0), + ambient_color: Vec4(0.7, 0.7, 0.7, 1.0), + }, }; GfxPipelineInfo triangle_info = { @@ -123,7 +130,7 @@ Update(Game* g, Camera* cam) Extent ext = GetExtent(&g.rd); g.globals.view_matrix = ViewMatrix(cam); - Perspective(&g.globals.projection_matrix, Radians(70.0), cast(f32)(ext.x), cast(f32)(ext.y), 10000.0, 0.1); + Perspective(&g.globals.projection_matrix, Radians(90.0), cast(f32)(ext.x), cast(f32)(ext.y), 0.1, 10000.0); g.globals.projection_matrix[1, 1] *= -1.0; g.globals.view_projection = g.globals.projection_matrix * g.globals.view_matrix; @@ -138,6 +145,7 @@ RotationMatrix(Camera* cam) Quat pitch_rotation, yaw_rotation; QuatFromAxis(&pitch_rotation, cam.pitch, Vec3(1.0, 0.0, 0.0)); QuatFromAxis(&yaw_rotation, cam.yaw, Vec3(0.0, -1.0, 0.0)); + Mat4 pitch_mat = cast(Mat4)(yaw_rotation) * cast(Mat4)(pitch_rotation); return cast(Mat4)(yaw_rotation) * cast(Mat4)(pitch_rotation); } @@ -185,11 +193,28 @@ Cycle(Game* g) Bind(&g.rd, &g.pbr_pipeline); - DrawModel(&g.rd, &g.model); + Quat q; + static f32 angle = 0.0; + angle += 1.0 * g.delta; + QuatFromAxis(&q, angle, Vec3(0.0, 1.0, 0.0)); + g.pc.model_matrix = cast(Mat4)(q); + DrawModel(g, &g.model); FinishFrame(&g.rd); } +pragma(inline): void +DrawModel(Game* g, Model* model) +{ + BindBuffers(&g.rd, &model.index_buffer, &model.vertex_buffer); + foreach(i, part; model.parts) + { + g.pc.mat_id = part.mat; + PushConstants(&g.rd, &g.pc); + DrawIndexed(&g.rd, part.length, 1, part.offset); + } +} + void Destroy(Game* g) { diff --git a/src/gears/main.d b/src/gears/main.d index c786d77..c2edf1e 100644 --- a/src/gears/main.d +++ b/src/gears/main.d @@ -18,21 +18,19 @@ import core.stdc.string : memcpy; void main(string[] argv) { PlatformWindow window = CreateWindow("Video Game", 1920, 1080); - Game g = InitGame(&window); - scope(exit) Destroy(&g); while (true) { HandleEvents(&window); if (window.close) { - Logf("quitting"); break; } - Cycle(&g); } + + Destroy(&g); } diff --git a/src/gears/platform.d b/src/gears/platform.d index a466d5f..2b73b6d 100644 --- a/src/gears/platform.d +++ b/src/gears/platform.d @@ -94,7 +94,8 @@ void CheckErr(PlatformWindow *window, xcb_void_cookie_t *cookie, xcb_generic_err pureFree(err); }; -PlatformWindow CreateWindow(string name, u16 width, u16 height) +PlatformWindow +CreateWindow(string name, u16 width, u16 height) { PlatformWindow window = { w: width, @@ -210,6 +211,9 @@ PlatformWindow CreateWindow(string name, u16 width, u16 height) xcb_xfixes_query_version(window.conn, 4, 0); + LockCursor(&window); + UnlockCursor(&window); + return window; }; @@ -345,6 +349,8 @@ HandleEvents(PlatformWindow* window) case XCB_BUTTON_PRESS: case XCB_BUTTON_RELEASE: { + if (window.input_count == window.inputs.length) continue; + xcb_button_press_event_t* mouse_event = cast(xcb_button_press_event_t*)e; bool pressed = e.response_type == XCB_BUTTON_PRESS; Input input = Input.None; @@ -367,6 +373,7 @@ HandleEvents(PlatformWindow* window) case XCB_MOTION_NOTIFY: { if (ignore_mouse_events) continue; + if (window.input_count == window.inputs.length) continue; xcb_motion_notify_event_t* move_event = cast(xcb_motion_notify_event_t*)e; diff --git a/src/gears/renderer.d b/src/gears/renderer.d index 59e3230..246ed4e 100644 --- a/src/gears/renderer.d +++ b/src/gears/renderer.d @@ -4,7 +4,7 @@ import assets; import util; import alloc; import vulkan; -import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRender, SetUniform, PrepComputeDrawImage, Dispatch, FinishFrame, BeginFrame, WaitIdle; +import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRender, SetUniform, PrepComputeDrawImage, Dispatch, FinishFrame, BeginFrame, WaitIdle, PushConstants, BindBuffers; import assets; import std.math.traits : isNaN; import util : Logf; @@ -56,6 +56,9 @@ struct GlobalUniforms Mat4 view_matrix = Mat4Identity(); Mat4 projection_matrix = Mat4Identity(); Mat4 view_projection = Mat4Identity(); + Vec4 light_color; + Vec4 ambient_color; + align(16): Vec3 light_direction; Vec2 res; } @@ -64,12 +67,6 @@ struct ShaderUniforms f32 placeholder; } -struct PushConst -{ - Mat4 model_matrix; - u32 mat_id; -} - enum PipelineType : int { Graphics, @@ -114,8 +111,12 @@ struct Renderer UIVertex[] ui_vertex_buf; u32[] ui_index_buf; u32 ui_count; +} - PushConst push_const; +struct PushConst +{ + Mat4 model_matrix; + u32 mat_id; } struct Extent @@ -179,22 +180,6 @@ InitRenderer(PlatformWindow* window) return rd; } -pragma(inline): void -DrawModel(Renderer* rd, Model* model) -{ - BindBuffers(&rd.vk, &model.index_buffer, &model.vertex_buffer); - - rd.push_const.model_matrix = Mat4Identity(); - Translate(&rd.push_const.model_matrix, Vec3(0.0, 0.0, 0.0)); - - foreach(i, part; model.parts) - { - rd.push_const.mat_id = part.mat; - PushConstants(&rd.vk, &rd.push_const); - DrawIndexed(rd, part.length, 1, part.offset); - } -} - pragma(inline): Extent GetExtent(Renderer* rd) { @@ -289,6 +274,18 @@ DrawRect(Renderer* rd, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col) rd.ui_count += 1; } +pragma(inline): void +BindBuffers(Renderer* rd, Buffer* index_buffer, Buffer* vertex_buffer) +{ + BindBuffers(&rd.vk, index_buffer, vertex_buffer); +} + +pragma(inline): void +PushConstants(Renderer* rd, PushConst* pc) +{ + PushConstants(&rd.vk, pc); +} + pragma(inline): Pipeline BuildGfxPipeline(Renderer* rd, GfxPipelineInfo* info) { @@ -473,6 +470,38 @@ LoadModel(Renderer* rd, string name) indices[i2] = i2; } + for(u64 i = 0; i < indices.length; i += 3) + { + u32 i0 = indices[i+0]; + u32 i1 = indices[i+1]; + u32 i2 = indices[i+2]; + + Vec3 edge1 = vertices[i1].pos - vertices[i0].pos; + Vec3 edge2 = vertices[i2].pos - vertices[i0].pos; + + Vec2 delta_uv1 = vertices[i1].uv - vertices[i0].uv; + Vec2 delta_uv2 = vertices[i2].uv - vertices[i0].uv; + + f32 dividend = delta_uv1.x * delta_uv2.y - delta_uv2.x * delta_uv1.y; + f32 fc = 1.0 / dividend; + + Vec3 tangent = Vec3( + fc * (delta_uv2.y * edge1.x - delta_uv1.y * edge2.x), + fc * (delta_uv2.y * edge1.y - delta_uv1.y * edge2.y), + fc * (delta_uv2.y * edge1.z - delta_uv1.y * edge2.z) + ); + + Normalize(&tangent); + + f32 handedness = ((delta_uv1.y * delta_uv2.x - delta_uv2.y * delta_uv1.x) < 0.0) ? -1.0 : 1.0; + + Vec3 t = tangent * handedness; + + vertices[i0].tangent = Vec4(t, handedness); + vertices[i1].tangent = Vec4(t, handedness); + vertices[i2].tangent = Vec4(t, handedness); + } + assert(vertices.length > 0 && indices.length > 0, "Error loading model"); CreateBuffer(&rd.vk, &model.vertex_buffer, BT.Vertex, vertices.length * Vertex.sizeof, false); diff --git a/src/shaders/pbr.frag.glsl b/src/shaders/pbr.frag.glsl index 776ab70..75542f5 100644 --- a/src/shaders/pbr.frag.glsl +++ b/src/shaders/pbr.frag.glsl @@ -5,12 +5,30 @@ #include "structures.layout" -layout (location = 0) in vec4 in_col; -layout (location = 1) in vec2 in_uv; +layout (location = 0) in struct FragDataIn { + vec3 normal; + vec2 uv; +} FragData; layout (location = 0) out vec4 FragColor; +vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, vec3 dir, vec3 normal) +{ + float diffuse_factor = max(dot(normal, -dir), 0.0); + + vec4 ambient = vec4(vec3(G.ambient_color * diff_col), diff_samp.a); + vec4 diffuse = vec4(vec3(light_col * diffuse_factor), diff_samp.a); + + diffuse *= diff_samp; + ambient *= diff_samp; + + return (ambient + diffuse); +} + void main() { - FragColor = in_col; + vec4 col = Materials[nonuniformEXT(PC.mat_id)].diffuse; + vec4 tex_col = texture(sampler2D(Textures[nonuniformEXT(Materials[nonuniformEXT(PC.mat_id)].albedo_texture)], SamplerNearest), FragData.uv); + + FragColor = CalculateDirectionalLight(col, tex_col, G.light_color, G.light_direction, FragData.normal); } diff --git a/src/shaders/pbr.vert.glsl b/src/shaders/pbr.vert.glsl index 1e37a61..b5551b4 100644 --- a/src/shaders/pbr.vert.glsl +++ b/src/shaders/pbr.vert.glsl @@ -11,8 +11,10 @@ layout (location = 2) in vec3 in_pos; layout (location = 3) in vec3 in_normal; layout (location = 4) in vec2 in_uv; -layout (location = 0) out vec4 out_col; -layout (location = 1) out vec2 out_uv; +layout (location = 0) out struct FragDataOut { + vec3 normal; + vec2 uv; +} FragData; mat4 y_matrix = mat4( 1.0, 0.0, 0.0, 0.0, @@ -25,14 +27,6 @@ void main() { gl_Position = G.projection_matrix * G.view_matrix * PC.model_matrix * vec4(in_pos, 1.0); - vec4 col = Materials[nonuniformEXT(PC.mat_id)].diffuse; - - if (Materials[nonuniformEXT(PC.mat_id)].albedo_has_texture) - { - vec4 tex_col = texture(sampler2D(Textures[nonuniformEXT(Materials[nonuniformEXT(PC.mat_id)].albedo_texture)], SamplerNearest), in_uv); - col = col * tex_col; - } - - out_col = col; - out_uv = in_uv; + FragData.uv = in_uv; + FragData.normal = mat3(PC.model_matrix) * in_normal; } diff --git a/src/shaders/structures.layout b/src/shaders/structures.layout index 92d2ccc..01a73e9 100644 --- a/src/shaders/structures.layout +++ b/src/shaders/structures.layout @@ -6,6 +6,9 @@ layout (set = 0, binding = 0) uniform GlobalUniforms { mat4 view_matrix; mat4 projection_matrix; mat4 view_projection; + vec4 light_color; + vec4 ambient_color; + vec3 light_direction; vec2 res; } G; diff --git a/src/shared/math.d b/src/shared/math.d index 2879caa..d8f09e5 100644 --- a/src/shared/math.d +++ b/src/shared/math.d @@ -702,7 +702,7 @@ struct Quat U opCast(U)() if (is(U: Mat4)) { - f32 norm = Normalize(&vec); + f32 norm = Norm(&vec); f32 s = norm > 0.0 ? 2.0 / norm : 0.0; f32 _x = x; @@ -818,22 +818,36 @@ Dot(Vec4* l, Vec4* r) } pragma(inline): f32 -Normalize(Vec3* v) +Norm(Vec3* v) { return sqrtf(Dot(v, v)); } pragma(inline): f32 -Normalize(Vec4* v) +Norm(Vec4* v) { // TODO: SIMD this return sqrtf(Dot(v, v)); } +pragma(inline): void +Normalize(T)(T* vec) if (is(T: Vec2) || is(T: Vec3) || is(T: Vec4)) +{ + f32 length = Norm(vec); + mixin(GenerateLoop!("vec.v[@] /= length;", vec._N)()); +} + +pragma(inline): Vector +Normalize(T)(T vec) if (is(T: Vec2) || is(T: Vec3) || is(T: Vec4)) +{ + Normalize(&vec); + return vec; +} + pragma(inline): void NormalizeTo(Vec3* v, Vec3* dst) { - f32 norm = Normalize(v); + f32 norm = Norm(v); if (norm < f32.epsilon) {