107 lines
3.6 KiB
Zig
107 lines
3.6 KiB
Zig
const std = @import("std");
|
|
const cpu = @import("cpu.zig");
|
|
const Display = @import("display.zig").Display;
|
|
const c = @cImport({
|
|
@cInclude("SDL2/SDL.h");
|
|
});
|
|
const assert = @import("std").debug.assert;
|
|
|
|
// See https://github.com/zig-lang/zig/issues/565
|
|
// SDL_video.h:#define SDL_WINDOWPOS_UNDEFINED SDL_WINDOWPOS_UNDEFINED_DISPLAY(0)
|
|
// SDL_video.h:#define SDL_WINDOWPOS_UNDEFINED_DISPLAY(X) (SDL_WINDOWPOS_UNDEFINED_MASK|(X))
|
|
// SDL_video.h:#define SDL_WINDOWPOS_UNDEFINED_MASK 0x1FFF0000u
|
|
const SDL_WINDOWPOS_UNDEFINED = @bitCast(c_int, c.SDL_WINDOWPOS_UNDEFINED_MASK);
|
|
|
|
extern fn SDL_PollEvent(event: *c.SDL_Event) c_int;
|
|
|
|
// SDL_RWclose is fundamentally unrepresentable in Zig, because `ctx` is
|
|
// evaluated twice. One could make the case that this is a bug in SDL,
|
|
// especially since the docs list a real function prototype that would not
|
|
// have this double-evaluation of the parameter.
|
|
// If SDL would instead of a macro use a static inline function,
|
|
// it would resolve the SDL bug as well as make the function visible to Zig
|
|
// and to debuggers.
|
|
// SDL_rwops.h:#define SDL_RWclose(ctx) (ctx)->close(ctx)
|
|
inline fn SDL_RWclose(ctx: [*]c.SDL_RWops) c_int {
|
|
return ctx[0].close.?(ctx);
|
|
}
|
|
|
|
pub fn main() !void {
|
|
// Initialize SDL2
|
|
if (c.SDL_Init(c.SDL_INIT_VIDEO) != 0) {
|
|
c.SDL_Log("Unable to initialize SDL: %s", c.SDL_GetError());
|
|
return error.SDLInitializationFailed;
|
|
}
|
|
defer c.SDL_Quit();
|
|
|
|
// Create Screen (Maybe introduce scaling somehow?)
|
|
const screen = c.SDL_CreateWindow("Zig8", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 320, c.SDL_WINDOW_OPENGL) orelse
|
|
{
|
|
c.SDL_Log("Unable to create window: %s", c.SDL_GetError());
|
|
return error.SDLInitializationFailed;
|
|
};
|
|
defer c.SDL_DestroyWindow(screen);
|
|
|
|
// Create Renderer
|
|
const renderer = c.SDL_CreateRenderer(screen, -1, c.SDL_RENDERER_ACCELERATED) orelse {
|
|
c.SDL_Log("Unable to create renderer: %s", c.SDL_GetError());
|
|
return error.SDLInitializationFailed;
|
|
};
|
|
defer c.SDL_DestroyRenderer(renderer);
|
|
|
|
// Create RGBA Texture
|
|
const texture = c.SDL_CreateTexture(renderer, c.SDL_PIXELFORMAT_RGBA8888, c.SDL_TEXTUREACCESS_STREAMING, 64, 32) orelse {
|
|
c.SDL_Log("Unable to create texture: %s", c.SDL_GetError());
|
|
return error.SDLInitializationFailed;
|
|
};
|
|
defer c.SDL_DestroyTexture(texture);
|
|
|
|
// Initialize CHIP-8 Emulator
|
|
var chip8 = cpu.Cpu {
|
|
.i = 0x00,
|
|
.pc = 0x0200,
|
|
.sp = 0x00,
|
|
.v = [_]u8{0x0} ** 16,
|
|
.stack = [_]u16{0x0} ** 16,
|
|
.memory = [_]u8{0x0} ** 4096,
|
|
.disp = Display.new(),
|
|
};
|
|
|
|
var path = "./bin/IBM Logo.ch8";
|
|
|
|
// Load Game ROM into CHIP-8 Emulator
|
|
try cpu.load_rom_path(&chip8, path);
|
|
|
|
|
|
// Create Pixel Buffer (Temporary)
|
|
const buf_size = 64 * 32 * @sizeOf(u32);
|
|
var pixels: [buf_size]u8 = [_]u8{255} ** buf_size;
|
|
|
|
// Render
|
|
var quit = false;
|
|
while (!quit) {
|
|
|
|
var buf_ptr: [*c]?*c_void = &@ptrCast(?*c_void, &pixels[0]);
|
|
|
|
_ = c.SDL_LockTexture(texture, null, buf_ptr, 64 * @sizeOf(u32));
|
|
c.SDL_UnlockTexture(texture);
|
|
|
|
var event: c.SDL_Event = undefined;
|
|
while (SDL_PollEvent(&event) != 0) {
|
|
switch (event.@"type") {
|
|
c.SDL_QUIT => {
|
|
quit = true;
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
|
|
_ = c.SDL_RenderClear(renderer);
|
|
_ = c.SDL_RenderCopy(renderer, texture, null, null);
|
|
c.SDL_RenderPresent(renderer);
|
|
|
|
cpu.cycle(&chip8);
|
|
|
|
c.SDL_Delay(17);
|
|
}
|
|
} |