Skip to content

Commit

Permalink
Project cleanup, makes main file the app implementation only.
Browse files Browse the repository at this point in the history
  • Loading branch information
ikskuh committed Jul 29, 2020
1 parent 6c643c8 commit 23cb99e
Show file tree
Hide file tree
Showing 7 changed files with 585 additions and 575 deletions.
6 changes: 3 additions & 3 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,9 @@ pub fn build(b: *std.build.Builder) !void {
});

make_unsigned_apk.step.dependOn(&aarch64_exe.step);
// make_unsigned_apk.step.dependOn(&arm_exe.step);
// // make_unsigned_apk.step.dependOn(&x86_exe.step);
// make_unsigned_apk.step.dependOn(&x86_64_exe.step);
make_unsigned_apk.step.dependOn(&arm_exe.step);
// make_unsigned_apk.step.dependOn(&x86_exe.step);
make_unsigned_apk.step.dependOn(&x86_64_exe.step);

const unpack_apk = b.addSystemCommand(&[_][]const u8{
"unzip",
Expand Down
2 changes: 1 addition & 1 deletion src/android-bind.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2110,7 +2110,7 @@ pub const ANativeActivity = extern struct {
obbPath: [*:0]const u8,
};
pub const ANativeActivity_createFunc = fn ([*c]ANativeActivity, ?*c_void, usize) callconv(.C) void;
pub const ANativeActivity_onCreate = @compileError("unable to resolve function type ZigClangTypeClass.Typedef"); // /home/felix/projects/android-hass/android-sdk/ndk/21.1.6352462/sysroot/usr/include/android/native_activity.h:255:35

pub extern fn ANativeActivity_finish(activity: [*c]ANativeActivity) void;
pub extern fn ANativeActivity_setWindowFormat(activity: [*c]ANativeActivity, format: i32) void;
pub extern fn ANativeActivity_setWindowFlags(activity: [*c]ANativeActivity, addFlags: u32, removeFlags: u32) void;
Expand Down
204 changes: 204 additions & 0 deletions src/android-support.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
const std = @import("std");

const c = @import("c.zig");

const android = @import("android-bind.zig");
const build_options = @import("build_options");

// Export the flat functions for now
// pub const native = android;
pub usingnamespace android;

const AndroidApp = @import("root").AndroidApp;

pub var sdk_version: c_int = 0;

/// Actual application entry point
export fn ANativeActivity_onCreate(activity: *android.ANativeActivity, savedState: ?[*]u8, savedStateSize: usize) callconv(.C) void {
{
var sdk_ver_str: [92]u8 = undefined;
const len = android.__system_property_get("ro.build.version.sdk", &sdk_ver_str);
if (len <= 0) {
sdk_version = 0;
} else {
const str = sdk_ver_str[0..@intCast(usize, len)];
sdk_version = std.fmt.parseInt(c_int, str, 10) catch 0;
}
}

std.log.debug(.app, "Starting on Android Version {}\n", .{
sdk_version,
});

const app = std.heap.c_allocator.create(AndroidApp) catch {
std.log.emerg(.app_glue, "Could not create new AndroidApp: OutOfMemory!\n", .{});
return;
};

activity.callbacks.* = ANativeActivityGlue(AndroidApp).init();

if (savedState) |state| {
app.* = AndroidApp.initRestore(std.heap.c_allocator, activity, state[0..savedStateSize]) catch |err| {
std.log.emerg(.app_glue, "Failed to restore app state: {}\n", .{err});
std.heap.c_allocator.destroy(app);
return;
};
} else {
app.* = AndroidApp.initFresh(std.heap.c_allocator, activity) catch |err| {
std.log.emerg(.app_glue, "Failed to restore app state: {}\n", .{err});
std.heap.c_allocator.destroy(app);
return;
};
}

app.start() catch |err| {
std.log.emerg(.app_glue, "Failed to start app state: {}\n", .{err});
app.deinit();
std.heap.c_allocator.destroy(app);
return;
};

activity.instance = app;

std.log.debug(.app_glue, "Successfully started the app.\n", .{});
}

// // Required by C code for now…
threadlocal var errno: c_int = 0;
export fn __errno_location() *c_int {
return &errno;
}

// Android Panic implementation
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
std.log.emerg(.panic, "PANIC: {}\n", .{message});

std.os.exit(1);
}

// Android Logging implementation
pub fn log(
comptime message_level: std.log.Level,
comptime scope: @Type(.EnumLiteral),
comptime format: []const u8,
args: anytype,
) void {
var buffer: [8192]u8 = undefined;
const msg = std.fmt.bufPrint(&buffer, format ++ "\x00", args) catch {
// TODO: Handle missing format here…
return;
};

// Make slice 0-terminated with added nul terminator
const msg0 = msg[0..(msg.len - 1) :0];

// Using the function from liblog to write to the actual debug output
_ = android.__android_log_write(switch (message_level) {
// => .ANDROID_LOG_VERBOSE,
.debug => android.ANDROID_LOG_DEBUG,
.info, .notice => android.ANDROID_LOG_INFO,
.warn => android.ANDROID_LOG_WARN,
.err => android.ANDROID_LOG_ERROR,
.crit, .alert, .emerg => android.ANDROID_LOG_FATAL,
}, "ziggy", msg0.ptr);
}

/// Returns a wrapper implementation for the given App type which implements all
/// ANativeActivity callbacks.
fn ANativeActivityGlue(comptime App: type) type {
return struct {
pub fn init() android.ANativeActivityCallbacks {
return android.ANativeActivityCallbacks{
.onStart = onStart,
.onResume = onResume,
.onSaveInstanceState = onSaveInstanceState,
.onPause = onPause,
.onStop = onStop,
.onDestroy = onDestroy,
.onWindowFocusChanged = onWindowFocusChanged,
.onNativeWindowCreated = onNativeWindowCreated,
.onNativeWindowResized = onNativeWindowResized,
.onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded,
.onNativeWindowDestroyed = onNativeWindowDestroyed,
.onInputQueueCreated = onInputQueueCreated,
.onInputQueueDestroyed = onInputQueueDestroyed,
.onContentRectChanged = onContentRectChanged,
.onConfigurationChanged = onConfigurationChanged,
.onLowMemory = onLowMemory,
};
}

fn invoke(activity: *android.ANativeActivity, comptime func: []const u8, args: anytype) void {
if (@hasDecl(App, func)) {
if (activity.instance) |instance| {
@call(.{}, @field(App, func), .{@ptrCast(*App, @alignCast(@alignOf(App), instance))} ++ args);
}
} else {
std.log.debug(.app_glue, "ANativeActivity callback {} not available on {}", .{ func, @typeName(App) });
}
}

// return value must be created with malloc(), so we pass the c_allocator to App.onSaveInstanceState
fn onSaveInstanceState(activity: *android.ANativeActivity, outSize: *usize) callconv(.C) ?[*]u8 {
outSize.* = 0;
if (@hasDecl(App, "onSaveInstanceState")) {
if (activity.instance) |instance| {
const optional_slice = @ptrCast(*App, @alignCast(@alignOf(App), instance)).onSaveInstanceState(std.heap.c_allocator);
if (optional_slice) |slice| {
outSize.* = slice.len;
return slice.ptr;
}
}
} else {
std.log.debug(.app_glue, "ANativeActivity callback onSaveInstanceState not available on {}", .{@typeName(App)});
}
return null;
}

fn onDestroy(activity: *android.ANativeActivity) callconv(.C) void {
invoke(activity, "onDestroy", .{});
}
fn onStart(activity: *android.ANativeActivity) callconv(.C) void {
invoke(activity, "onStart", .{});
}
fn onResume(activity: *android.ANativeActivity) callconv(.C) void {
invoke(activity, "onResume", .{});
}
fn onPause(activity: *android.ANativeActivity) callconv(.C) void {
invoke(activity, "onPause", .{});
}
fn onStop(activity: *android.ANativeActivity) callconv(.C) void {
invoke(activity, "onStop", .{});
}
fn onConfigurationChanged(activity: *android.ANativeActivity) callconv(.C) void {
invoke(activity, "onConfigurationChanged", .{});
}
fn onLowMemory(activity: *android.ANativeActivity) callconv(.C) void {
invoke(activity, "onLowMemory", .{});
}
fn onWindowFocusChanged(activity: *android.ANativeActivity, hasFocus: c_int) callconv(.C) void {
invoke(activity, "onWindowFocusChanged", .{(hasFocus != 0)});
}
fn onNativeWindowCreated(activity: *android.ANativeActivity, window: *android.ANativeWindow) callconv(.C) void {
invoke(activity, "onNativeWindowCreated", .{window});
}
fn onNativeWindowResized(activity: *android.ANativeActivity, window: *android.ANativeWindow) callconv(.C) void {
invoke(activity, "onNativeWindowResized", .{window});
}
fn onNativeWindowRedrawNeeded(activity: *android.ANativeActivity, window: *android.ANativeWindow) callconv(.C) void {
invoke(activity, "onNativeWindowRedrawNeeded", .{window});
}
fn onNativeWindowDestroyed(activity: *android.ANativeActivity, window: *android.ANativeWindow) callconv(.C) void {
invoke(activity, "onNativeWindowDestroyed", .{window});
}
fn onInputQueueCreated(activity: *android.ANativeActivity, input_queue: *android.AInputQueue) callconv(.C) void {
invoke(activity, "onInputQueueCreated", .{input_queue});
}
fn onInputQueueDestroyed(activity: *android.ANativeActivity, input_queue: *android.AInputQueue) callconv(.C) void {
invoke(activity, "onInputQueueDestroyed", .{input_queue});
}
fn onContentRectChanged(activity: *android.ANativeActivity, rect: *const android.ARect) callconv(.C) void {
invoke(activity, "onContentRectChanged", .{rect});
}
};
}
4 changes: 4 additions & 0 deletions src/c.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub usingnamespace @cImport({
@cInclude("EGL/egl.h");
@cInclude("GLES3/gl3.h");
});
127 changes: 127 additions & 0 deletions src/egl.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
const std = @import("std");

const c = @import("c.zig");
const build_options = @import("build_options");

const android = @import("android-support.zig");

pub const EGLContext = struct {
const Self = @This();

display: c.EGLDisplay,
surface: c.EGLSurface,
context: c.EGLContext,

pub fn init(window: *android.ANativeWindow) !Self {
const EGLint = c.EGLint;

var egl_display = c.eglGetDisplay(c.EGL_DEFAULT_DISPLAY);
if (egl_display == c.EGL_NO_DISPLAY) {
std.log.err(.egl, "Error: No display found!\n", .{});
return error.FailedToInitializeEGL;
}

var egl_major: EGLint = undefined;
var egl_minor: EGLint = undefined;
if (c.eglInitialize(egl_display, &egl_major, &egl_minor) == 0) {
std.log.err(.egl, "Error: eglInitialise failed!\n", .{});
return error.FailedToInitializeEGL;
}

std.log.info(.egl,
\\EGL Version: {}
\\EGL Vendor: {}
\\EGL Extensions: {}
\\
, .{
std.mem.span(c.eglQueryString(egl_display, c.EGL_VERSION)),
std.mem.span(c.eglQueryString(egl_display, c.EGL_VENDOR)),
std.mem.span(c.eglQueryString(egl_display, c.EGL_EXTENSIONS)),
});

const config_attribute_list = [_]EGLint{
c.EGL_RED_SIZE,
8,
c.EGL_GREEN_SIZE,
8,
c.EGL_BLUE_SIZE,
8,
c.EGL_ALPHA_SIZE,
8,
c.EGL_BUFFER_SIZE,
32,
c.EGL_STENCIL_SIZE,
0,
c.EGL_DEPTH_SIZE,
16,
// c.EGL_SAMPLES, 1,
c.EGL_RENDERABLE_TYPE,
if (build_options.android_sdk_version >= 28) c.EGL_OPENGL_ES3_BIT else c.EGL_OPENGL_ES2_BIT,
c.EGL_NONE,
};

var config: c.EGLConfig = undefined;
var num_config: c.EGLint = undefined;
if (c.eglChooseConfig(egl_display, &config_attribute_list, &config, 1, &num_config) == c.EGL_FALSE) {
std.log.err(.egl, "Error: eglChooseConfig failed: 0x{X:0>4}\n", .{c.eglGetError()});
return error.FailedToInitializeEGL;
}

std.log.info(.egl, "Config: {}\n", .{num_config});

const context_attribute_list = [_]EGLint{ c.EGL_CONTEXT_CLIENT_VERSION, 2, c.EGL_NONE };

var context = c.eglCreateContext(egl_display, config, c.EGL_NO_CONTEXT, &context_attribute_list);
if (context == c.EGL_NO_CONTEXT) {
std.log.err(.egl, "Error: eglCreateContext failed: 0x{X:0>4}\n", .{c.eglGetError()});
return error.FailedToInitializeEGL;
}
errdefer _ = c.eglDestroyContext(egl_display, context);

std.log.info(.egl, "Context created: {}\n", .{context});

var native_window: c.EGLNativeWindowType = @ptrCast(c.EGLNativeWindowType, window); // this is safe, just a C import problem

const android_width = android.ANativeWindow_getWidth(window);
const android_height = android.ANativeWindow_getHeight(window);

std.log.info(.egl, "Screen Resolution: {}x{}\n", .{ android_width, android_height });

const window_attribute_list = [_]EGLint{c.EGL_NONE};
const egl_surface = c.eglCreateWindowSurface(egl_display, config, native_window, &window_attribute_list);

std.log.info(.egl, "Got Surface: {}\n", .{egl_surface});

if (egl_surface == c.EGL_NO_SURFACE) {
std.log.err(.egl, "Error: eglCreateWindowSurface failed: 0x{X:0>4}\n", .{c.eglGetError()});
return error.FailedToInitializeEGL;
}
errdefer _ = c.eglDestroySurface(egl_display, context);

return Self{
.display = egl_display,
.surface = egl_surface,
.context = context,
};
}

pub fn deinit(self: *Self) void {
_ = c.eglDestroySurface(self.display, self.surface);
_ = c.eglDestroyContext(self.display, self.context);
self.* = undefined;
}

pub fn swapBuffers(self: Self) !void {
if (c.eglSwapBuffers(self.display, self.surface) == c.EGL_FALSE) {
std.log.err(.egl, "Error: eglMakeCurrent failed: 0x{X:0>4}\n", .{c.eglGetError()});
return error.EglFailure;
}
}

pub fn makeCurrent(self: Self) !void {
if (c.eglMakeCurrent(self.display, self.surface, self.surface, self.context) == c.EGL_FALSE) {
std.log.err(.egl, "Error: eglMakeCurrent failed: 0x{X:0>4}\n", .{c.eglGetError()});
return error.EglFailure;
}
}
};
Loading

0 comments on commit 23cb99e

Please sign in to comment.