diff --git a/examples/28-sdl-graphics.sx b/examples/28-sdl-graphics.sx index e803a2a..6459a4d 100644 --- a/examples/28-sdl-graphics.sx +++ b/examples/28-sdl-graphics.sx @@ -131,49 +131,8 @@ main :: () { glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); - // Shaders - vert_src : [:0]u8 = #string glsl -#version 330 core -layout (location = 0) in vec3 aPos; -layout (location = 1) in vec3 aNormal; -uniform mat4 uMVP; -out vec3 vNormal; -out vec3 vPos; - -void main() { - gl_Position = uMVP * vec4(aPos, 1.0); - vNormal = aNormal; - vPos = aPos; -} -glsl; - - frag_src : [:0]u8 = #string GLSL -#version 330 core -in vec3 vNormal; -in vec3 vPos; -out vec4 FragColor; -uniform vec3 uLightDir; -uniform float uWire; -void main() { - if (uWire > 0.5) { - FragColor = vec4(0.05, 0.05, 0.05, 1.0); - return; - } - vec3 n = normalize(vNormal); - vec3 l = normalize(uLightDir); - float diff = max(dot(n, l), 0.15); - float cx = floor(vPos.x * 2.0 + 0.001); - float cy = floor(vPos.y * 2.0 + 0.001); - float cz = floor(vPos.z * 2.0 + 0.001); - float check = mod(cx + cy + cz, 2.0); - vec3 col1 = vec3(0.9, 0.5, 0.2); - vec3 col2 = vec3(0.2, 0.6, 0.9); - vec3 base = mix(col1, col2, check); - FragColor = vec4(base * diff, 1.0); -} -GLSL; - - program := create_program(vert_src, frag_src); + print("create program: {}\n{}\n", VERT_SHADER_SRC, FRAG_SHADER_SRC); + program := create_program(VERT_SHADER_SRC, FRAG_SHADER_SRC); glUseProgram(program); mvp_loc : s32 = glGetUniformLocation(program, "uMVP"); @@ -317,3 +276,44 @@ GLSL; SDL_DestroyWindow(window); SDL_Quit(); } + +VERT_SHADER_SRC : string = #string GLSL +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aNormal; +uniform mat4 uMVP; +out vec3 vNormal; +out vec3 vPos; + +void main() { + gl_Position = uMVP * vec4(aPos, 1.0); + vNormal = aNormal; + vPos = aPos; +} +GLSL; + +FRAG_SHADER_SRC : string = #string GLSL +#version 330 core +in vec3 vNormal; +in vec3 vPos; +out vec4 FragColor; +uniform vec3 uLightDir; +uniform float uWire; +void main() { + if (uWire > 0.5) { + FragColor = vec4(0.05, 0.05, 0.05, 1.0); + return; + } + vec3 n = normalize(vNormal); + vec3 l = normalize(uLightDir); + float diff = max(dot(n, l), 0.15); + float cx = floor(vPos.x * 2.0 + 0.001); + float cy = floor(vPos.y * 2.0 + 0.001); + float cz = floor(vPos.z * 2.0 + 0.001); + float check = mod(cx + cy + cz, 2.0); + vec3 col1 = vec3(0.9, 0.5, 0.2); + vec3 col2 = vec3(0.2, 0.6, 0.9); + vec3 base = mix(col1, col2, check); + FragColor = vec4(base * diff, 1.0); +} +GLSL; \ No newline at end of file diff --git a/src/codegen.zig b/src/codegen.zig index 5222033..5e0efae 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -2349,10 +2349,47 @@ pub const CodeGen = struct { .bool_literal => |lit| { return c.LLVMConstInt(llvm_ty, if (lit.value) 1 else 0, 0); }, + .string_literal => |sl| { + const content = if (sl.is_raw) sl.raw else (unescape.unescapeString(self.allocator, sl.raw) catch return null); + return self.buildConstStrGlobal(content); + }, + .struct_literal => |sl| { + return self.evalConstantStruct(sl, target_ty); + }, else => return null, } } + /// Evaluate a struct literal as a constant (for global initializers). + fn evalConstantStruct(self: *CodeGen, sl: ast.StructLiteral, target_ty: Type) ?c.LLVMValueRef { + const struct_name = sl.struct_name orelse target_ty.struct_type; + const info = self.lookupStructInfo(struct_name) orelse return null; + + if (info.field_names.len > 32) return null; + var field_vals: [32]c.LLVMValueRef = undefined; + const n = info.field_names.len; + + // Initialize with undef for each field + for (0..n) |i| { + field_vals[i] = c.LLVMGetUndef(self.typeToLLVM(info.field_types[i])); + } + + // Fill in provided field values + for (sl.field_inits) |fi| { + const field_name = fi.name orelse continue; // skip positional for now + const idx = blk: { + for (info.field_names, 0..) |fn_name, j| { + if (std.mem.eql(u8, fn_name, field_name)) break :blk j; + } + return null; // unknown field + }; + const val = self.evalConstant(fi.value, info.field_types[idx]) orelse return null; + field_vals[idx] = val; + } + + return c.LLVMConstNamedStruct(info.llvm_type, @ptrCast(&field_vals), @intCast(n)); + } + /// Register a top-level value constant (e.g., `SPECIAL_VALUE :u8: 42;`) as an LLVM global. fn registerTopLevelConstant(self: *CodeGen, cd: ast.ConstDecl) !void { const ta = cd.type_annotation orelse return; // need explicit type for top-level constants @@ -2382,9 +2419,24 @@ pub const CodeGen = struct { const llvm_ty = self.typeToLLVM(sx_ty); const name_z = try self.allocator.dupeZ(u8, vd.name); const global = c.LLVMAddGlobal(self.module, llvm_ty, name_z.ptr); - // Initialize with undef (will be set at runtime, e.g. by load_gl) + + // Try constant-evaluable initializer → register as comptime_global for JIT compatibility + if (vd.value) |val_node| { + if (self.evalConstant(val_node, sx_ty)) |const_val| { + c.LLVMSetInitializer(global, const_val); + c.LLVMSetGlobalConstant(global, 1); + try self.comptime_globals.put(vd.name, .{ + .global = global, + .ty = sx_ty, + .expr = val_node, + .is_resolved = true, + }); + return; + } + } + + // Non-constant globals: mutable, initialized with undef (set at runtime, e.g. by load_gl) c.LLVMSetInitializer(global, self.getUndef(llvm_ty)); - // NOT constant — this is a mutable global c.LLVMSetGlobalConstant(global, 0); try self.global_mutable_vars.put(vd.name, .{ .ptr = global, .ty = sx_ty });