Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ fn linkLibraries(b: *std.Build, exe: *std.Build.Step.Compile, useLocalDeps: bool
exe.root_module.addObjectFile(subPath.path(b, libName(b, "SPIRV-Tools", t)));
exe.root_module.addObjectFile(subPath.path(b, libName(b, "SPIRV-Tools-opt", t)));

const translate_c = b.addTranslateC(.{
.root_source_file = b.path("src/c.h"),
.target = target,
.optimize = optimize,
});
translate_c.addIncludePath(headersDeps.path("include"));

exe.root_module.addImport("c", translate_c.createModule());

if (t.os.tag == .macos) {
const moltenVkLibInstall = b.addInstallFile(subPath.path(b, "libMoltenVK.dylib"), "bin/Cubyz.app/Contents/Frameworks/libMoltenVK.dylib");
const moltenVkJsonInstall = b.addInstallFile(subPath.path(b, "MoltenVK_icd.json"), "bin/Cubyz.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json");
Expand Down
27 changes: 27 additions & 0 deletions src/c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// used for text rendering
Comment thread
AfmanS marked this conversation as resolved.
Outdated
#include <freetype/ftadvanc.h>
#include <freetype/ftbbox.h>
#include <freetype/ftbitmap.h>
#include <freetype/ftcolor.h>
#include <freetype/ftlcdfil.h>
#include <freetype/ftsizes.h>
#include <freetype/ftstroke.h>
#include <freetype/fttrigon.h>
#include <freetype/ftsynth.h>
#include <hb.h>
#include <hb-ft.h>

// used for rendering graphics and windows
Comment thread
AfmanS marked this conversation as resolved.
Outdated
#include <glad/gl.h>
// NOTE(blackedout): glad is currently not used on macOS, so use Vulkan header from the Vulkan-Headers repository instead
#ifdef __MACH__
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_beta.h>
#else
#include <glad/vulkan.h>
#endif
#include <GLFW/glfw3.h>

// used for exporting and reading images to/from files
Comment thread
AfmanS marked this conversation as resolved.
Outdated
#include <stb/stb_image.h>
#include <stb/stb_image_write.h>
100 changes: 34 additions & 66 deletions src/graphics.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,7 @@
const std = @import("std");
const builtin = @import("builtin");

pub const hbft = @cImport({
@cDefine("_BITS_STDIO2_H", ""); // TODO: Zig fails to include this header file
Comment thread
IntegratedQuantum marked this conversation as resolved.
@cInclude("freetype/ftadvanc.h");
@cInclude("freetype/ftbbox.h");
@cInclude("freetype/ftbitmap.h");
@cInclude("freetype/ftcolor.h");
@cInclude("freetype/ftlcdfil.h");
@cInclude("freetype/ftsizes.h");
@cInclude("freetype/ftstroke.h");
@cInclude("freetype/fttrigon.h");
@cInclude("freetype/ftsynth.h");
@cInclude("hb.h");
@cInclude("hb-ft.h");
});
pub const c = @import("c");
Comment thread
AfmanS marked this conversation as resolved.
Outdated

const vec = @import("vec.zig");
const Mat4f = vec.Mat4f;
Expand All @@ -36,25 +23,6 @@ pub const ComputePipeline = pipelines.ComputePipeline;
pub const Pipeline = pipelines.Pipeline;
pub const vulkan = @import("graphics/vulkan.zig");

pub const c = @cImport({
@cInclude("glad/gl.h");

// NOTE(blackedout): glad is currently not used on macOS, so use Vulkan header from the Vulkan-Headers repository instead
Comment thread
IntegratedQuantum marked this conversation as resolved.
if (builtin.target.os.tag == .macos) {
@cInclude("vulkan/vulkan.h");
@cInclude("vulkan/vulkan_beta.h");
} else {
@cInclude("glad/vulkan.h");
}
@cInclude("GLFW/glfw3.h");
});

pub const stb_image = @cImport({
@cDefine("_BITS_STDIO2_H", ""); // TODO: Zig fails to include this header file
@cInclude("stb/stb_image.h");
@cInclude("stb/stb_image_write.h");
});

pub const draw = struct { // MARK: draw
var color: u32 = 0;
var clip: ?Vec4i = null;
Expand Down Expand Up @@ -596,7 +564,7 @@ pub const TextBuffer = struct { // MARK: TextBuffer

alignment: Alignment,
width: f32,
buffer: ?*hbft.hb_buffer_t,
buffer: ?*c.hb_buffer_t,
glyphs: []GlyphData,
lines: main.List(Line),
lineBreaks: main.List(LineBreak),
Expand Down Expand Up @@ -797,19 +765,19 @@ pub const TextBuffer = struct { // MARK: TextBuffer
}

// Let harfbuzz do its thing:
const buffer = hbft.hb_buffer_create() orelse @panic("Out of Memory while creating harfbuzz buffer");
defer hbft.hb_buffer_destroy(buffer);
hbft.hb_buffer_add_utf32(buffer, parser.parsedText.items.ptr, @intCast(parser.parsedText.items.len), 0, @intCast(parser.parsedText.items.len));
hbft.hb_buffer_set_direction(buffer, hbft.HB_DIRECTION_LTR);
hbft.hb_buffer_set_script(buffer, hbft.HB_SCRIPT_COMMON);
hbft.hb_buffer_set_language(buffer, hbft.hb_language_get_default());
hbft.hb_shape(TextRendering.harfbuzzFont, buffer, null, 0);
var glyphInfos: []hbft.hb_glyph_info_t = undefined;
var glyphPositions: []hbft.hb_glyph_position_t = undefined;
const buffer = c.hb_buffer_create() orelse @panic("Out of Memory while creating harfbuzz buffer");
defer c.hb_buffer_destroy(buffer);
c.hb_buffer_add_utf32(buffer, parser.parsedText.items.ptr, @intCast(parser.parsedText.items.len), 0, @intCast(parser.parsedText.items.len));
c.hb_buffer_set_direction(buffer, c.HB_DIRECTION_LTR);
c.hb_buffer_set_script(buffer, c.HB_SCRIPT_COMMON);
c.hb_buffer_set_language(buffer, c.hb_language_get_default());
c.hb_shape(TextRendering.harfbuzzFont, buffer, null, 0);
var glyphInfos: []c.hb_glyph_info_t = undefined;
var glyphPositions: []c.hb_glyph_position_t = undefined;
{
var len: c_uint = 0;
glyphInfos.ptr = hbft.hb_buffer_get_glyph_infos(buffer, &len).?;
glyphPositions.ptr = hbft.hb_buffer_get_glyph_positions(buffer, &len).?;
glyphInfos.ptr = c.hb_buffer_get_glyph_infos(buffer, &len).?;
glyphPositions.ptr = c.hb_buffer_get_glyph_positions(buffer, &len).?;
glyphInfos.len = len;
glyphPositions.len = len;
}
Expand Down Expand Up @@ -1131,10 +1099,10 @@ const TextRendering = struct { // MARK: TextRendering
alpha: c_int,
} = undefined;

var freetypeLib: hbft.FT_Library = undefined;
var freetypeFace: hbft.FT_Face = undefined;
var harfbuzzFace: ?*hbft.hb_face_t = undefined;
var harfbuzzFont: ?*hbft.hb_font_t = undefined;
var freetypeLib: c.FT_Library = undefined;
var freetypeFace: c.FT_Face = undefined;
var harfbuzzFace: ?*c.hb_face_t = undefined;
var harfbuzzFont: ?*c.hb_font_t = undefined;
var glyphMapping: main.List(u31) = undefined;
var glyphData: main.List(Glyph) = undefined;
var glyphTexture: [2]c_uint = undefined;
Expand All @@ -1143,9 +1111,9 @@ const TextRendering = struct { // MARK: TextRendering
var textureOffset: i32 = 0;
var fontUnitsPerPixel: f32 = undefined;

fn ftError(errorCode: hbft.FT_Error) !void {
fn ftError(errorCode: c.FT_Error) !void {
if (errorCode == 0) return;
const errorString = hbft.FT_Error_String(errorCode);
const errorString = c.FT_Error_String(errorCode);
std.log.err("Got freetype error {s}", .{errorString});
return error.freetype;
}
Expand All @@ -1166,11 +1134,11 @@ const TextRendering = struct { // MARK: TextRendering
errdefer pipeline.deinit();
c.glUniform1f(uniforms.alpha, 1.0);
c.glUniform2f(uniforms.fontSize, @floatFromInt(textureWidth), @floatFromInt(textureHeight));
try ftError(hbft.FT_Init_FreeType(&freetypeLib));
try ftError(hbft.FT_New_Face(freetypeLib, "assets/cubyz/fonts/unscii-16-full.ttf", 0, &freetypeFace));
try ftError(hbft.FT_Set_Pixel_Sizes(freetypeFace, 0, textureHeight));
harfbuzzFace = hbft.hb_ft_face_create_referenced(freetypeFace);
harfbuzzFont = hbft.hb_font_create(harfbuzzFace);
try ftError(c.FT_Init_FreeType(&freetypeLib));
try ftError(c.FT_New_Face(freetypeLib, "assets/cubyz/fonts/unscii-16-full.ttf", 0, &freetypeFace));
try ftError(c.FT_Set_Pixel_Sizes(freetypeFace, 0, textureHeight));
harfbuzzFace = c.hb_ft_face_create_referenced(freetypeFace);
harfbuzzFont = c.hb_font_create(harfbuzzFace);
fontUnitsPerPixel = @as(f32, @floatFromInt(freetypeFace.*.units_per_EM))/@as(f32, @floatFromInt(textureHeight));

glyphMapping = .init(main.globalAllocator);
Expand All @@ -1192,11 +1160,11 @@ const TextRendering = struct { // MARK: TextRendering

fn deinit() void {
pipeline.deinit();
ftError(hbft.FT_Done_FreeType(freetypeLib)) catch {};
ftError(c.FT_Done_FreeType(freetypeLib)) catch {};
glyphMapping.deinit();
glyphData.deinit();
c.glDeleteTextures(2, &glyphTexture);
hbft.hb_font_destroy(harfbuzzFont);
c.hb_font_destroy(harfbuzzFont);
}

fn resizeTexture(newWidth: i32) void {
Expand All @@ -1212,7 +1180,7 @@ const TextRendering = struct { // MARK: TextRendering
c.glUniform2f(uniforms.fontSize, @floatFromInt(textureWidth), @floatFromInt(textureHeight));
}

fn uploadData(bitmap: hbft.FT_Bitmap) void {
fn uploadData(bitmap: c.FT_Bitmap) void {
const width: i32 = @bitCast(bitmap.width);
const height: i32 = @bitCast(bitmap.rows);
const buffer = bitmap.buffer orelse return;
Expand All @@ -1229,7 +1197,7 @@ const TextRendering = struct { // MARK: TextRendering
glyphMapping.appendNTimes(0, index - glyphMapping.items.len + 1);
}
if (glyphMapping.items[index] == 0) { // glyph was not initialized yet.
try ftError(hbft.FT_Load_Glyph(freetypeFace, index, hbft.FT_LOAD_RENDER));
try ftError(c.FT_Load_Glyph(freetypeFace, index, c.FT_LOAD_RENDER));
const glyph = freetypeFace.*.glyph;
const bitmap = glyph.*.bitmap;
const width = bitmap.width;
Expand Down Expand Up @@ -2122,32 +2090,32 @@ pub const Image = struct { // MARK: Image
var channel: c_int = undefined;
const nullTerminatedPath = main.stackAllocator.dupeZ(u8, path); // TODO: Find a more zig-friendly image loading library.
errdefer main.stackAllocator.free(nullTerminatedPath);
stb_image.stbi_set_flip_vertically_on_load(1);
const data = stb_image.stbi_load(nullTerminatedPath.ptr, @ptrCast(&result.width), @ptrCast(&result.height), &channel, 4) orelse {
c.stbi_set_flip_vertically_on_load(1);
const data = c.stbi_load(nullTerminatedPath.ptr, @ptrCast(&result.width), @ptrCast(&result.height), &channel, 4) orelse {
return error.FileNotFound;
};
main.stackAllocator.free(nullTerminatedPath);
result.imageData = allocator.dupe(Color, @as([*]Color, @ptrCast(data))[0 .. result.width*result.height]);
stb_image.stbi_image_free(data);
c.stbi_image_free(data);
return result;
}
pub fn readUnflippedFromFile(allocator: NeverFailingAllocator, path: []const u8) !Image {
var result: Image = undefined;
var channel: c_int = undefined;
const nullTerminatedPath = main.stackAllocator.dupeZ(u8, path); // TODO: Find a more zig-friendly image loading library.
errdefer main.stackAllocator.free(nullTerminatedPath);
const data = stb_image.stbi_load(nullTerminatedPath.ptr, @ptrCast(&result.width), @ptrCast(&result.height), &channel, 4) orelse {
const data = c.stbi_load(nullTerminatedPath.ptr, @ptrCast(&result.width), @ptrCast(&result.height), &channel, 4) orelse {
return error.FileNotFound;
};
main.stackAllocator.free(nullTerminatedPath);
result.imageData = allocator.dupe(Color, @as([*]Color, @ptrCast(data))[0 .. result.width*result.height]);
stb_image.stbi_image_free(data);
c.stbi_image_free(data);
return result;
}
pub fn exportToFile(self: Image, path: []const u8) !void {
const nullTerminated = main.stackAllocator.dupeZ(u8, path);
defer main.stackAllocator.free(nullTerminated);
_ = stb_image.stbi_write_png(nullTerminated.ptr, self.width, self.height, 4, self.imageData.ptr, self.width*4); // TODO: Handle the return type.
_ = c.stbi_write_png(nullTerminated.ptr, self.width, self.height, 4, self.imageData.ptr, self.width*4); // TODO: Handle the return type.
}
pub fn getRGB(self: Image, x: usize, y: usize) Color {
std.debug.assert(x < self.width);
Expand Down
Loading