figure out basic bloom in test scene
This commit is contained in:
parent
094e4a7f09
commit
42ed4666a0
@ -19,6 +19,10 @@ pub fn build(b: *std.Build) !void {
|
||||
.source_file = .{ .path = "libs/zgltf/src/main.zig" },
|
||||
}));
|
||||
|
||||
exe.addAnonymousModule("opengl", .{
|
||||
.source_file = .{ .path = "libs/gl3v3.zig" }
|
||||
});
|
||||
|
||||
// Provide filenames of all files in 'src/ROMs' to program as options
|
||||
{
|
||||
var files = std.ArrayList([]const u8).init(b.allocator);
|
||||
|
5041
libs/gl3v3.zig
Normal file
5041
libs/gl3v3.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -72,7 +72,6 @@ pub fn init(allocator: Allocator) !Self {
|
||||
|
||||
pub fn reset(self: *Self) void {
|
||||
@memset(self.memory, 0);
|
||||
@memset(&self.input, false);
|
||||
@memset(&self.stack, 0);
|
||||
@memset(&self.V, 0);
|
||||
@memset(self.display, false);
|
||||
|
@ -3,6 +3,7 @@ const Gltf = @import("zgltf");
|
||||
const rl = @import("raylib");
|
||||
const std = @import("std");
|
||||
const RaylibChip = @import("raylib-chip.zig");
|
||||
const Light = @import("./light.zig");
|
||||
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -15,6 +16,7 @@ models: std.ArrayList(rl.Model),
|
||||
static_models: std.ArrayList(*rl.Model),
|
||||
buttons: [16]*rl.Model,
|
||||
power_switch: *rl.Model,
|
||||
power_light_position: rl.Vector3,
|
||||
|
||||
bbox: rl.BoundingBox,
|
||||
position: rl.Vector3,
|
||||
@ -281,6 +283,7 @@ pub fn init(allocator: Allocator, powered: *bool, button_state: *[16]bool, scree
|
||||
|
||||
var buttons: [16]*rl.Model = undefined;
|
||||
var power_switch: *rl.Model = undefined;
|
||||
var power_light: ?*rl.Model = null;
|
||||
|
||||
for (scene_nodes.items) |node_index| {
|
||||
const node = gltf.data.nodes.items[node_index];
|
||||
@ -289,22 +292,30 @@ pub fn init(allocator: Allocator, powered: *bool, button_state: *[16]bool, scree
|
||||
models.appendAssumeCapacity(try loadGltfMesh(materials, gltf, node));
|
||||
var model: *rl.Model = &models.items[models.items.len-1];
|
||||
|
||||
if (std.mem.eql(u8, node.name, "Power switch")) {
|
||||
const name = node.name;
|
||||
if (std.mem.eql(u8, name, "Power switch")) {
|
||||
power_switch = model;
|
||||
} else if (std.mem.startsWith(u8, node.name, "Buttons ")) {
|
||||
var space = std.mem.indexOfScalar(u8, node.name, ' ').?;
|
||||
const button_idx = try std.fmt.parseInt(usize, node.name[space+1..], 16);
|
||||
} else if (std.mem.startsWith(u8, name, "Buttons ")) {
|
||||
var space = std.mem.indexOfScalar(u8, name, ' ').?;
|
||||
const button_idx = try std.fmt.parseInt(usize, name[space+1..], 16);
|
||||
buttons[button_idx] = model;
|
||||
} else {
|
||||
try static_models.append(model);
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, node.name, "Screen")) {
|
||||
if (std.mem.eql(u8, name, "Screen")) {
|
||||
const screen_material = &model.materials.?[0];
|
||||
rl.SetMaterialTexture(@ptrCast(screen_material), rl.MATERIAL_MAP_DIFFUSE, screen_texture.texture);
|
||||
} else if (std.mem.eql(u8, name, "Power indicator")) {
|
||||
power_light = model;
|
||||
}
|
||||
}
|
||||
|
||||
var power_light_position = rl.Vector3.zero();
|
||||
if (power_light) |model| {
|
||||
power_light_position = matrixGetTranslation(model.transform);
|
||||
}
|
||||
|
||||
return Self{
|
||||
.allocator = allocator,
|
||||
|
||||
@ -317,6 +328,7 @@ pub fn init(allocator: Allocator, powered: *bool, button_state: *[16]bool, scree
|
||||
.powered = powered,
|
||||
.button_state = button_state,
|
||||
|
||||
.power_light_position = power_light_position,
|
||||
.bbox = rl.GetModelBoundingBox(static_models.items[0].*),
|
||||
.position = rl.Vector3{ .x = 0, .y = 0, .z = 0 },
|
||||
};
|
||||
@ -500,3 +512,12 @@ pub fn draw(self: *Self) void {
|
||||
rl.DrawModel(self.power_switch.*, self.position, 1.0, rl.WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_power_light_position(self: *Self) rl.Vector3 {
|
||||
return self.power_light_position.add(self.position);
|
||||
}
|
||||
|
||||
pub fn get_power_light_color(self: *Self) rl.Color {
|
||||
_ = self;
|
||||
return rl.GREEN;
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
const Self = @This();
|
||||
const rl = @import("raylib");
|
||||
|
||||
camera: rl.Camera3D,
|
||||
|
||||
pub fn init() Self {
|
||||
var camera = rl.Camera3D{
|
||||
.position = rl.Vector3.new(0, 0, -10),
|
||||
.target = rl.Vector3.new(0.0, 0.0, 0.0),
|
||||
.up = rl.Vector3.new(0.0, 1.0, 0.0),
|
||||
.fovy = 45.0,
|
||||
.projection = rl.CameraProjection.CAMERA_PERSPECTIVE,
|
||||
};
|
||||
|
||||
return Self {
|
||||
.camera = camera
|
||||
};
|
||||
}
|
||||
|
88
src/light.zig
Normal file
88
src/light.zig
Normal file
@ -0,0 +1,88 @@
|
||||
const Self = @This();
|
||||
const rl = @import("raylib");
|
||||
const std = @import("std");
|
||||
|
||||
pub const LightType = enum(i32) {
|
||||
DIRECTIONAL = 0,
|
||||
POINT = 1,
|
||||
};
|
||||
|
||||
shader: rl.Shader,
|
||||
|
||||
enabledLoc: i32,
|
||||
typeLoc: i32,
|
||||
positionLoc: i32,
|
||||
targetLoc: i32,
|
||||
colorLoc: i32,
|
||||
intensityLoc: i32,
|
||||
|
||||
fn getLightShaderLocation(shader: rl.Shader, idx: usize, comptime name: []const u8) i32 {
|
||||
var buf: [128]u8 = undefined;
|
||||
var fba = std.heap.FixedBufferAllocator.init(&buf);
|
||||
const prop_name = std.fmt.allocPrintZ(fba.allocator(), "lights[{d}]." ++ name, .{idx}) catch unreachable;
|
||||
return rl.GetShaderLocation(shader, prop_name);
|
||||
}
|
||||
|
||||
pub fn init(shader: rl.Shader, idx: usize) Self {
|
||||
return Self{
|
||||
.shader = shader,
|
||||
|
||||
.enabledLoc = getLightShaderLocation(shader, idx, "enabled"),
|
||||
.typeLoc = getLightShaderLocation(shader, idx, "type"),
|
||||
.positionLoc = getLightShaderLocation(shader, idx, "position"),
|
||||
.targetLoc = getLightShaderLocation(shader, idx, "target"),
|
||||
.colorLoc = getLightShaderLocation(shader, idx, "color"),
|
||||
.intensityLoc = getLightShaderLocation(shader, idx, "intensity"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn set_directional(self: *const Self, color: rl.Color, position: rl.Vector3, intensity: f32, target: rl.Vector3) void {
|
||||
self.set_type(.DIRECTIONAL);
|
||||
self.set_intensity(intensity);
|
||||
self.set_enabled(true);
|
||||
self.set_position(position);
|
||||
self.set_color(color);
|
||||
self.set_target(target);
|
||||
}
|
||||
|
||||
pub fn set_point(self: *const Self, color: rl.Color, position: rl.Vector3, intensity: f32) void {
|
||||
self.set_type(.POINT);
|
||||
self.set_intensity(intensity);
|
||||
self.set_enabled(true);
|
||||
self.set_color(color);
|
||||
self.set_position(position);
|
||||
}
|
||||
|
||||
pub fn set_enabled(self: *const Self, enabled: bool) void {
|
||||
const enabled_i32: i32 = @intFromBool(enabled);
|
||||
rl.SetShaderValue(self.shader, self.enabledLoc, &enabled_i32, .SHADER_UNIFORM_INT);
|
||||
}
|
||||
|
||||
pub fn set_type(self: *const Self, light_type: LightType) void {
|
||||
const light_type_i32: i32 = @intFromEnum(light_type);
|
||||
rl.SetShaderValue(self.shader, self.typeLoc, &light_type_i32, .SHADER_UNIFORM_INT);
|
||||
}
|
||||
|
||||
pub fn set_intensity(self: *const Self, intensity: f32) void {
|
||||
rl.SetShaderValue(self.shader, self.intensityLoc, &intensity, .SHADER_UNIFORM_FLOAT);
|
||||
}
|
||||
|
||||
pub fn set_position(self: *const Self, pos: rl.Vector3) void {
|
||||
const position = [3]f32{ pos.x, pos.y, pos.z };
|
||||
rl.SetShaderValue(self.shader, self.positionLoc, &position, .SHADER_UNIFORM_VEC3);
|
||||
}
|
||||
|
||||
pub fn set_target(self: *const Self, target: rl.Vector3) void {
|
||||
const target_f32 = [3]f32{ target.x, target.y, target.z };
|
||||
rl.SetShaderValue(self.shader, self.targetLoc, &target_f32, .SHADER_UNIFORM_VEC3);
|
||||
}
|
||||
|
||||
pub fn set_color(self: *const Self, color: rl.Color) void {
|
||||
const color_f32 = [4]f32{
|
||||
@as(f32, @floatFromInt(color.r)) / 255.0,
|
||||
@as(f32, @floatFromInt(color.g)) / 255.0,
|
||||
@as(f32, @floatFromInt(color.b)) / 255.0,
|
||||
@as(f32, @floatFromInt(color.a)) / 255.0,
|
||||
};
|
||||
rl.SetShaderValue(self.shader, self.colorLoc, &color_f32, .SHADER_UNIFORM_VEC4);
|
||||
}
|
@ -2,9 +2,10 @@ const Self = @This();
|
||||
const rl = @import("raylib");
|
||||
const std = @import("std");
|
||||
const Gltf = @import("zgltf");
|
||||
const GlobalContext = @import("./global-context.zig");
|
||||
const EmulatorModel = @import("./emulator-model.zig");
|
||||
const ROM = @import("./roms.zig").ROM;
|
||||
const Light = @import("./light.zig");
|
||||
const ShaderCode = @import("./shader-code.zig");
|
||||
|
||||
const ChipContext = @import("chip.zig");
|
||||
const RaylibChip = @import("raylib-chip.zig");
|
||||
@ -13,7 +14,8 @@ const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const StringList = std.ArrayList([]const u8);
|
||||
|
||||
ctx: *GlobalContext,
|
||||
const max_lights: u32 = 3;
|
||||
|
||||
allocator: Allocator,
|
||||
|
||||
emulator: EmulatorModel,
|
||||
@ -23,7 +25,7 @@ camera_target_orientation: ?rl.Vector3 = null,
|
||||
previous_click_time: f64 = 0.0,
|
||||
|
||||
shader: rl.Shader,
|
||||
lights: [2]Light,
|
||||
lights: [max_lights]Light,
|
||||
|
||||
powered: *bool,
|
||||
chip: *ChipContext,
|
||||
@ -47,73 +49,6 @@ pub fn genSinWave(wave: *rl.Wave, frequency: f32) void {
|
||||
}
|
||||
}
|
||||
|
||||
const Light = struct {
|
||||
const LightType = enum(i32) {
|
||||
DIRECTIONAL = 0,
|
||||
POINT = 1,
|
||||
};
|
||||
|
||||
type: LightType,
|
||||
enabled: bool,
|
||||
position: rl.Vector3,
|
||||
target: rl.Vector3,
|
||||
color: rl.Color,
|
||||
attenuation: f32 = 0.0,
|
||||
|
||||
enabledLoc: i32,
|
||||
typeLoc: i32,
|
||||
positionLoc: i32,
|
||||
targetLoc: i32,
|
||||
colorLoc: i32,
|
||||
attenuationLoc: i32 = 0,
|
||||
|
||||
fn getLightShaderLocation(shader: rl.Shader, idx: usize, comptime name: []const u8) i32 {
|
||||
var buf: [128]u8 = undefined;
|
||||
var fba = std.heap.FixedBufferAllocator.init(&buf);
|
||||
const prop_name = std.fmt.allocPrintZ(fba.allocator(), "lights[{d}]." ++ name, .{idx}) catch unreachable;
|
||||
return rl.GetShaderLocation(shader, prop_name);
|
||||
}
|
||||
|
||||
pub fn init(idx: usize, light_type: LightType, postion: rl.Vector3, target: rl.Vector3, color: rl.Color, shader: rl.Shader) Light {
|
||||
var light = Light{
|
||||
.type = light_type,
|
||||
.enabled = true,
|
||||
.position = postion,
|
||||
.target = target,
|
||||
.color = color,
|
||||
.enabledLoc = Light.getLightShaderLocation(shader, idx, "enabled"),
|
||||
.typeLoc = Light.getLightShaderLocation(shader, idx, "type"),
|
||||
.positionLoc = Light.getLightShaderLocation(shader, idx, "position"),
|
||||
.targetLoc = Light.getLightShaderLocation(shader, idx, "target"),
|
||||
.colorLoc = Light.getLightShaderLocation(shader, idx, "color"),
|
||||
};
|
||||
light.update_values(shader);
|
||||
return light;
|
||||
}
|
||||
|
||||
pub fn update_values(self: *Light, shader: rl.Shader) void {
|
||||
const enabled: i32 = @intFromBool(self.enabled);
|
||||
rl.SetShaderValue(shader, self.enabledLoc, &enabled, rl.ShaderUniformDataType.SHADER_UNIFORM_INT);
|
||||
|
||||
const lightType: i32 = @intFromEnum(self.type);
|
||||
rl.SetShaderValue(shader, self.typeLoc, &lightType, rl.ShaderUniformDataType.SHADER_UNIFORM_INT);
|
||||
|
||||
const position = [3]f32{ self.position.x, self.position.y, self.position.z };
|
||||
rl.SetShaderValue(shader, self.positionLoc, &position, rl.ShaderUniformDataType.SHADER_UNIFORM_VEC3);
|
||||
|
||||
const target = [3]f32{ self.target.x, self.target.y, self.target.z };
|
||||
rl.SetShaderValue(shader, self.targetLoc, &target, rl.ShaderUniformDataType.SHADER_UNIFORM_VEC3);
|
||||
|
||||
const color = [4]f32{
|
||||
@as(f32, @floatFromInt(self.color.r)) / 255.0,
|
||||
@as(f32, @floatFromInt(self.color.g)) / 255.0,
|
||||
@as(f32, @floatFromInt(self.color.b)) / 255.0,
|
||||
@as(f32, @floatFromInt(self.color.a)) / 255.0,
|
||||
};
|
||||
rl.SetShaderValue(shader, self.colorLoc, &color, rl.ShaderUniformDataType.SHADER_UNIFORM_VEC4);
|
||||
}
|
||||
};
|
||||
|
||||
fn getCameraProjection(camera: *const rl.Camera3D) rl.Matrix {
|
||||
const screen_width: f32 = @floatFromInt(rl.GetScreenWidth());
|
||||
const screen_height: f32 = @floatFromInt(rl.GetScreenHeight());
|
||||
@ -168,15 +103,28 @@ fn getPrefferedDistanceToBox(camera: *const rl.Camera3D, box: rl.BoundingBox) f3
|
||||
return distance;
|
||||
}
|
||||
|
||||
pub fn init(allocator: Allocator, ctx: *GlobalContext) !Self {
|
||||
const shader = rl.LoadShader("src/shaders/main.vs", "src/shaders/main.fs");
|
||||
pub fn init(allocator: Allocator) !Self {
|
||||
const shader_code = try ShaderCode.init(allocator, max_lights);
|
||||
defer shader_code.deinit();
|
||||
const shader = rl.LoadShaderFromMemory(shader_code.vertex, shader_code.fragment);
|
||||
errdefer rl.UnloadShader(shader);
|
||||
|
||||
if (shader.id == rl.rlGetShaderIdDefault()) {
|
||||
return error.CompileShader;
|
||||
}
|
||||
|
||||
shader.locs.?[@intFromEnum(rl.ShaderLocationIndex.SHADER_LOC_VECTOR_VIEW)] = rl.GetShaderLocation(shader, "viewPos");
|
||||
|
||||
const ambientLoc = rl.GetShaderLocation(shader, "ambient");
|
||||
rl.SetShaderValue(shader, ambientLoc, &[4]f32{ 0.6, 0.6, 1, 1.0 }, .SHADER_UNIFORM_VEC4);
|
||||
|
||||
var light1 = Light.init(0, .DIRECTIONAL, rl.Vector3.new(0.2, 0, -0.2), rl.Vector3.zero(), rl.WHITE, shader);
|
||||
var light2 = Light.init(1, .DIRECTIONAL, rl.Vector3.new(0.2, 0, 0.2), rl.Vector3.zero(), rl.WHITE, shader);
|
||||
var lights: [max_lights]Light = undefined;
|
||||
for (0..max_lights) |i| {
|
||||
lights[i] = Light.init(shader, i);
|
||||
}
|
||||
|
||||
lights[0].set_directional(rl.WHITE, rl.Vector3.new(0.2, 0, -0.2), 1, rl.Vector3.zero());
|
||||
lights[1].set_directional(rl.WHITE, rl.Vector3.new(0.2, 0, 0.2), 1, rl.Vector3.zero());
|
||||
|
||||
var chip = try allocator.create(ChipContext);
|
||||
chip.* = try ChipContext.init(allocator);
|
||||
@ -209,12 +157,13 @@ pub fn init(allocator: Allocator, ctx: *GlobalContext) !Self {
|
||||
errdefer emulator.deinit();
|
||||
emulator.setShader(shader);
|
||||
|
||||
lights[2].set_point(rl.GREEN, emulator.get_power_light_position(), 0.3);
|
||||
|
||||
return Self {
|
||||
.allocator = allocator,
|
||||
.ctx = ctx,
|
||||
.emulator = emulator,
|
||||
.shader = shader,
|
||||
.lights = .{light1, light2},
|
||||
.lights = lights,
|
||||
|
||||
.chip = chip,
|
||||
.raylib_chip = raylib_chip,
|
||||
@ -341,10 +290,7 @@ pub fn update(self: *Self, dt: f32) void {
|
||||
|
||||
const camera = &self.ctx.camera;
|
||||
const cameraPos = [3]f32{ camera.position.x, camera.position.y, camera.position.z };
|
||||
rl.SetShaderValue(self.shader, self.shader.locs.?[@intFromEnum(rl.ShaderLocationIndex.SHADER_LOC_VECTOR_VIEW)], &cameraPos, rl.ShaderUniformDataType.SHADER_UNIFORM_VEC3);
|
||||
for (&self.lights) |*light| {
|
||||
light.update_values(self.shader);
|
||||
}
|
||||
rl.SetShaderValue(self.shader, self.shader.locs.?[@intFromEnum(rl.ShaderLocationIndex.SHADER_LOC_VECTOR_VIEW)], &cameraPos, .SHADER_UNIFORM_VEC3);
|
||||
|
||||
const ray = rl.GetMouseRay(rl.GetMousePosition(), self.ctx.camera);
|
||||
if (self.emulator.isOverPowerSwitch(ray)) {
|
||||
@ -353,11 +299,13 @@ pub fn update(self: *Self, dt: f32) void {
|
||||
}
|
||||
}
|
||||
|
||||
self.raylib_chip.update_input();
|
||||
if (self.powered.*) {
|
||||
self.raylib_chip.update_input();
|
||||
self.raylib_chip.update(dt);
|
||||
}
|
||||
|
||||
self.lights[2].set_enabled(self.powered.*);
|
||||
|
||||
rl.BeginTextureMode(self.screen_texture);
|
||||
{
|
||||
self.raylib_chip.render();
|
||||
@ -414,9 +362,18 @@ pub fn update(self: *Self, dt: f32) void {
|
||||
}
|
||||
|
||||
pub fn draw(self: *Self) void {
|
||||
const emissiveLoc = rl.GetShaderLocation(self.shader, "emissive");
|
||||
const enabled = true;
|
||||
const disabled = false;
|
||||
rl.BeginShaderMode(self.shader);
|
||||
{
|
||||
self.emulator.draw();
|
||||
|
||||
rl.SetShaderValue(self.shader, emissiveLoc, &enabled, .SHADER_UNIFORM_INT);
|
||||
rl.DrawSphere(self.emulator.power_light_position, 0.015, rl.RED);
|
||||
rl.rlDrawRenderBatchActive();
|
||||
rl.SetShaderValue(self.shader, emissiveLoc, &disabled, .SHADER_UNIFORM_INT);
|
||||
}
|
||||
rl.EndShaderMode();
|
||||
|
||||
}
|
||||
|
25
src/main.zig
25
src/main.zig
@ -5,10 +5,11 @@ const print = std.debug.print;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ChipContext = @import("chip.zig");
|
||||
const RaylibChip = @import("raylib-chip.zig");
|
||||
const GlobalContext = @import("./global-context.zig");
|
||||
const MainScene = @import("./main-scene.zig");
|
||||
const listROMs = @import("./roms.zig").listROMs;
|
||||
|
||||
const TestScene = @import("test-scene.zig");
|
||||
|
||||
fn megabytes(amount: usize) usize {
|
||||
return amount * 1024 * 1024;
|
||||
}
|
||||
@ -29,12 +30,11 @@ pub fn main() anyerror!void {
|
||||
|
||||
rl.SetTargetFPS(60);
|
||||
|
||||
var ctx = GlobalContext.init();
|
||||
var main_scene = try MainScene.init(allocator, &ctx);
|
||||
defer main_scene.deinit();
|
||||
var scene = try TestScene.init(allocator);
|
||||
defer scene.deinit();
|
||||
|
||||
const roms = comptime listROMs();
|
||||
main_scene.set_rom(roms[3]);
|
||||
// const roms = comptime listROMs();
|
||||
// scene.set_rom(roms[3]);
|
||||
|
||||
const font_size = 24;
|
||||
const font_ttf_default_numchars = 95; // TTF font generation default charset: 95 glyphs (ASCII 32..126)
|
||||
@ -43,16 +43,7 @@ pub fn main() anyerror!void {
|
||||
|
||||
while (!rl.WindowShouldClose()) {
|
||||
var dt = rl.GetFrameTime();
|
||||
main_scene.update(dt);
|
||||
|
||||
rl.BeginDrawing();
|
||||
{
|
||||
rl.ClearBackground(.{ .r = 33, .g = 33, .b = 33, .a = 255 });
|
||||
|
||||
rl.BeginMode3D(ctx.camera);
|
||||
main_scene.draw();
|
||||
rl.EndMode3D();
|
||||
}
|
||||
rl.EndDrawing();
|
||||
scene.update(dt);
|
||||
scene.draw();
|
||||
}
|
||||
}
|
||||
|
36
src/shader-code.zig
Normal file
36
src/shader-code.zig
Normal file
@ -0,0 +1,36 @@
|
||||
const Self = @This();
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
allocator: Allocator,
|
||||
vertex: [:0]u8,
|
||||
fragment: [:0]u8,
|
||||
|
||||
pub fn init(allocator: Allocator, max_lights_count: u32) !Self {
|
||||
const base_vertex_code = @embedFile("shaders/main_vs.glsl");
|
||||
const base_fragment_code = @embedFile("shaders/main_fs.glsl");
|
||||
|
||||
const vertex = try allocator.dupeZ(u8, base_vertex_code);
|
||||
errdefer allocator.free(vertex);
|
||||
|
||||
const newline = std.mem.indexOfScalar(u8, base_fragment_code, '\n') orelse unreachable;
|
||||
const first_line = base_fragment_code[0..newline];
|
||||
const after_first_line = base_fragment_code[(newline+1)..];
|
||||
const fragment = try std.fmt.allocPrintZ(allocator,
|
||||
\\{s}
|
||||
\\#define MAX_LIGHTS {}
|
||||
\\{s}
|
||||
, .{ first_line, max_lights_count, after_first_line });
|
||||
errdefer allocator.free(fragment);
|
||||
|
||||
return Self {
|
||||
.allocator = allocator,
|
||||
.vertex = vertex,
|
||||
.fragment = fragment
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Self) void {
|
||||
self.allocator.free(self.vertex);
|
||||
self.allocator.free(self.fragment);
|
||||
}
|
39
src/shaders/bloom_fs.glsl
Normal file
39
src/shaders/bloom_fs.glsl
Normal file
@ -0,0 +1,39 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 colDiffuse;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
uniform vec2 renderSize;
|
||||
// const vec2 size = vec2(800, 450); // Framebuffer size
|
||||
const float samples = 7.0; // Pixels per axis; higher = bigger glow, worse performance
|
||||
const float quality = 5.0; // Defines size factor: Lower = smaller glow, better quality
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 sum = vec4(0);
|
||||
vec2 sizeFactor = vec2(1)/renderSize*quality;
|
||||
|
||||
// Texel color fetching from texture sampler
|
||||
vec4 source = texture(texture0, fragTexCoord);
|
||||
|
||||
const int range = (int(samples) - 1)/2; // should be = (samples - 1)/2;
|
||||
|
||||
for (int x = -range; x <= range; x++)
|
||||
{
|
||||
for (int y = -range; y <= range; y++)
|
||||
{
|
||||
sum += texture(texture0, fragTexCoord + vec2(x, y)*sizeFactor);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate final fragment color
|
||||
finalColor = ((sum/(samples*samples)) + source)*colDiffuse;
|
||||
}
|
24
src/shaders/default_vs.glsl
Normal file
24
src/shaders/default_vs.glsl
Normal file
@ -0,0 +1,24 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes
|
||||
in vec3 vertexPosition;
|
||||
in vec2 vertexTexCoord;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 vertexColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform mat4 mvp;
|
||||
|
||||
// Output vertex attributes (to fragment shader)
|
||||
out vec2 fragTexCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Send vertex attributes to fragment shader
|
||||
fragTexCoord = vertexTexCoord;
|
||||
fragColor = vertexColor;
|
||||
|
||||
// Calculate final vertex position
|
||||
gl_Position = mvp*vec4(vertexPosition, 1.0);
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec3 fragPosition;
|
||||
in vec2 fragTexCoord;
|
||||
//in vec4 fragColor;
|
||||
in vec4 fragColor;
|
||||
in vec3 fragNormal;
|
||||
|
||||
// Input uniform values
|
||||
@ -11,13 +11,8 @@ uniform sampler2D texture0;
|
||||
uniform vec4 colDiffuse;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
#define MAX_LIGHTS 2
|
||||
#define LIGHT_DIRECTIONAL 0
|
||||
#define LIGHT_POINT 1
|
||||
layout (location = 0) out vec4 finalColor;
|
||||
layout (location = 1) out vec4 bloomColor;
|
||||
|
||||
struct MaterialProperty {
|
||||
vec3 color;
|
||||
@ -25,12 +20,18 @@ struct MaterialProperty {
|
||||
sampler2D sampler;
|
||||
};
|
||||
|
||||
#define LIGHT_DIRECTIONAL 0
|
||||
#define LIGHT_POINT 1
|
||||
|
||||
struct Light {
|
||||
int enabled;
|
||||
int type;
|
||||
bool enabled;
|
||||
float intensity;
|
||||
vec3 position;
|
||||
vec3 target;
|
||||
vec4 color;
|
||||
|
||||
// Directional light arguments:
|
||||
vec3 target;
|
||||
};
|
||||
|
||||
// Input lighting values
|
||||
@ -38,45 +39,40 @@ uniform Light lights[MAX_LIGHTS];
|
||||
uniform vec4 ambient;
|
||||
uniform vec3 viewPos;
|
||||
|
||||
void main()
|
||||
{
|
||||
void main() {
|
||||
// Texel color fetching from texture sampler
|
||||
vec4 texelColor = texture(texture0, fragTexCoord);
|
||||
vec3 lightDot = vec3(0.0);
|
||||
vec3 normal = normalize(fragNormal);
|
||||
vec3 viewD = normalize(viewPos - fragPosition);
|
||||
vec3 specular = vec3(0.0);
|
||||
|
||||
// NOTE: Implement here your fragment shader code
|
||||
finalColor = fragColor * texelColor;
|
||||
|
||||
{ // Apply lights
|
||||
vec3 lightDot = vec3(0.0);
|
||||
vec3 normal = normalize(fragNormal);
|
||||
vec3 viewD = normalize(viewPos - fragPosition);
|
||||
vec3 specular = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
if (!lights[i].enabled) continue;
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; i++)
|
||||
{
|
||||
if (lights[i].enabled == 1)
|
||||
{
|
||||
vec3 light = vec3(0.0);
|
||||
|
||||
if (lights[i].type == LIGHT_DIRECTIONAL)
|
||||
{
|
||||
if (lights[i].type == LIGHT_DIRECTIONAL) {
|
||||
light = -normalize(lights[i].target - lights[i].position);
|
||||
}
|
||||
|
||||
if (lights[i].type == LIGHT_POINT)
|
||||
{
|
||||
} else if (lights[i].type == LIGHT_POINT) {
|
||||
light = normalize(lights[i].position - fragPosition);
|
||||
}
|
||||
|
||||
float NdotL = max(dot(normal, light), 0.0);
|
||||
lightDot += lights[i].color.rgb*NdotL;
|
||||
lightDot += lights[i].color.rgb * NdotL * lights[i].intensity;
|
||||
|
||||
float specCo = 0.0;
|
||||
if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine
|
||||
specular += specCo;
|
||||
}
|
||||
}
|
||||
|
||||
finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0)));
|
||||
finalColor += texelColor*(ambient/10.0)*colDiffuse;
|
||||
finalColor *= ((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0) + (ambient/10.0)*colDiffuse);
|
||||
}
|
||||
|
||||
// Gamma correction
|
||||
finalColor = pow(finalColor, vec4(1.0/1.9));
|
||||
}
|
||||
|
@ -19,8 +19,7 @@ out vec3 fragNormal;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
void main()
|
||||
{
|
||||
void main() {
|
||||
// Send vertex attributes to fragment shader
|
||||
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
|
||||
fragTexCoord = vertexTexCoord;
|
116
src/test-scene.zig
Normal file
116
src/test-scene.zig
Normal file
@ -0,0 +1,116 @@
|
||||
const Self = @This();
|
||||
|
||||
const rl = @import("raylib");
|
||||
const gl = @import("opengl");
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ShaderCode = @import("./shader-code.zig");
|
||||
const Light = @import("./light.zig");
|
||||
|
||||
const max_lights = 1;
|
||||
|
||||
const SHADER_LOC_VECTOR_VIEW = @intFromEnum(rl.ShaderLocationIndex.SHADER_LOC_VECTOR_VIEW);
|
||||
|
||||
shader: rl.Shader,
|
||||
bloom_shader: rl.Shader,
|
||||
frame_buffer: rl.RenderTexture2D,
|
||||
camera: rl.Camera3D,
|
||||
lights: [max_lights]Light,
|
||||
|
||||
cube: rl.Model,
|
||||
|
||||
pub fn init(allocator: Allocator) !Self {
|
||||
const main_shader_code = try ShaderCode.init(allocator, max_lights);
|
||||
defer main_shader_code.deinit();
|
||||
const shader = rl.LoadShaderFromMemory(main_shader_code.vertex, main_shader_code.fragment);
|
||||
errdefer rl.UnloadShader(shader);
|
||||
|
||||
if (shader.id == rl.rlGetShaderIdDefault()) {
|
||||
return error.CompileShader;
|
||||
}
|
||||
|
||||
const bloom_shader = rl.LoadShaderFromMemory(@embedFile("shaders/default_vs.glsl"), @embedFile("shaders/bloom_fs.glsl"));
|
||||
errdefer rl.UnloadShader(bloom_shader);
|
||||
if (bloom_shader.id == rl.rlGetShaderIdDefault()) {
|
||||
return error.CompileShader;
|
||||
}
|
||||
|
||||
const frame_buffer = rl.LoadRenderTexture(rl.GetScreenWidth(), rl.GetScreenHeight());
|
||||
errdefer rl.UnloadRenderTexture(frame_buffer);
|
||||
|
||||
var lights: [max_lights]Light = undefined;
|
||||
for (0..max_lights) |i| {
|
||||
lights[i] = Light.init(shader, i);
|
||||
}
|
||||
|
||||
Light.init(shader, 0).set_point(rl.RED, rl.Vector3{ .x = 1, .y = 1, .z = 0.5 }, 2.0);
|
||||
|
||||
shader.locs.?[SHADER_LOC_VECTOR_VIEW] = rl.GetShaderLocation(shader, "viewPos");
|
||||
|
||||
const ambientLoc = rl.GetShaderLocation(shader, "ambient");
|
||||
rl.SetShaderValue(shader, ambientLoc, &[4]f32{ 0.6, 0.6, 1, 1.0 }, .SHADER_UNIFORM_VEC4);
|
||||
|
||||
return Self{
|
||||
.shader = shader,
|
||||
.bloom_shader = bloom_shader,
|
||||
.frame_buffer = frame_buffer,
|
||||
.camera = rl.Camera3D{
|
||||
.position = rl.Vector3.new(0, 0, -10),
|
||||
.target = rl.Vector3.new(0.0, 0.0, 0.0),
|
||||
.up = rl.Vector3.new(0.0, 1.0, 0.0),
|
||||
.fovy = 45.0,
|
||||
.projection = rl.CameraProjection.CAMERA_PERSPECTIVE,
|
||||
},
|
||||
.lights = lights,
|
||||
.cube = rl.LoadModelFromMesh(rl.GenMeshCube(1.0, 1.0, 1.0))
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Self) void {
|
||||
rl.UnloadShader(self.shader);
|
||||
rl.UnloadRenderTexture(self.frame_buffer);
|
||||
}
|
||||
|
||||
pub fn update(self: *Self, dt: f32) void {
|
||||
const screen_width = rl.GetScreenWidth();
|
||||
const screen_height = rl.GetScreenHeight();
|
||||
if (self.frame_buffer.texture.width != screen_width or self.frame_buffer.texture.height != screen_height) {
|
||||
rl.UnloadRenderTexture(self.frame_buffer);
|
||||
self.frame_buffer = rl.LoadRenderTexture(screen_width, screen_height);
|
||||
}
|
||||
|
||||
rl.UpdateCamera(&self.camera, .CAMERA_THIRD_PERSON);
|
||||
|
||||
const cameraPos = [3]f32{ self.camera.position.x, self.camera.position.y, self.camera.position.z };
|
||||
rl.SetShaderValue(self.shader, self.shader.locs.?[SHADER_LOC_VECTOR_VIEW], @ptrCast(&cameraPos), .SHADER_UNIFORM_VEC3);
|
||||
_ = dt;
|
||||
}
|
||||
|
||||
pub fn draw(self: *Self) void {
|
||||
rl.BeginTextureMode(self.frame_buffer);
|
||||
{
|
||||
rl.ClearBackground(.{ .r = 33, .g = 33, .b = 33, .a = 255 });
|
||||
|
||||
rl.BeginMode3D(self.camera);
|
||||
rl.BeginShaderMode(self.shader);
|
||||
|
||||
self.cube.materials.?[0].shader = self.shader;
|
||||
rl.DrawModel(self.cube, rl.Vector3Zero(), 1.0, rl.WHITE);
|
||||
|
||||
rl.EndShaderMode();
|
||||
rl.EndMode3D();
|
||||
}
|
||||
rl.EndTextureMode();
|
||||
|
||||
const screen_width = rl.GetScreenWidth();
|
||||
const screen_height = rl.GetScreenHeight();
|
||||
const screen_rect = rl.Rectangle{ .x = 0, .y = 0, .width = @floatFromInt(screen_width), .height = @floatFromInt(screen_height) };
|
||||
|
||||
const loc = rl.GetShaderLocation(self.bloom_shader, "renderSize");
|
||||
rl.SetShaderValue(self.bloom_shader, loc, &[2]f32{ @floatFromInt(screen_width), @floatFromInt(screen_height) }, .SHADER_UNIFORM_VEC2);
|
||||
rl.BeginDrawing();
|
||||
rl.BeginShaderMode(self.bloom_shader);
|
||||
rl.DrawTextureRec(self.frame_buffer.texture, screen_rect, rl.Vector2.zero(), rl.WHITE);
|
||||
rl.EndShaderMode();
|
||||
rl.EndDrawing();
|
||||
}
|
Loading…
Reference in New Issue
Block a user