basic emu workin, now we can work on it yes

This commit is contained in:
Robin Hübner 2018-06-23 02:02:07 +02:00
parent 57efb162d6
commit 90897bd8d6
5 changed files with 340 additions and 61 deletions

10
imgui.ini Normal file
View File

@ -0,0 +1,10 @@
[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0
[Window][Emulator Status]
Pos=156,47
Size=370,370
Collapsed=0

BIN
programs/sqrt.ch8 Normal file

Binary file not shown.

View File

@ -6,6 +6,168 @@ import glad.gl.all;
import window; import window;
import imgui; import imgui;
struct Chip8Status {
//emu ptr
Emulator* run_;
Chip8* emu_;
// mem editor
// MemoryEditor mem_editor_;
// state
bool status_menu_ = true;
int stack_cur_ = -1;
void initialize(Emulator* run, Chip8* emu) {
this.run_ = run;
this.emu_ = emu;
} // initialize
alias Callback = float delegate(int idx, const char** out_text);
static extern(C) bool doCallback(void* ptr, int idx, const (char**) out_text) {
auto callback = *(cast(Callback*) ptr);
callback(idx, out_text);
return true;
} // doCallback;
void getStackFrame(int idx, const (char**) out_text) {
static char[32] frame_text;
import core.stdc.stdio : sprintf;
sprintf(frame_text.ptr, "0x%04X", emu_.stack[idx]);
auto p = frame_text.ptr;
auto op = cast(char**)out_text;
*op = p;
} // getStackFrame
void loadShortcut() {
import std.file : read;
auto buf = read("programs/sqrt.ch8");
emu_.load(0x200, buf); // do ze load yes, will copy all the data in
} // loadShortcut
void saveShortcut() {
} // saveShortcut
void debugShortcut() {
status_menu_ = !status_menu_;
} // debugShortcut
void redrawShortcut() {
emu_.draw_flag = true;
} // redrawShortcut
void toggleRunShortcut() {
emu_.run_flag = !emu_.run_flag;
} // toggleRunShortcut
void stepShortcut() {
emu_.step();
} // stepShortcut
void quitShortcut() {
run_.quit();
} // quitShortcut
void draw() {
if (!status_menu_) return;
if (igBeginMainMenuBar()) {
if (igBeginMenu("Menu")) {
if (igMenuItem("Load", "CTRL+L")) {
loadShortcut();
}
if (igMenuItem("Save", "CTRL+S")) {
saveShortcut();
}
if (igMenuItem("Debug", "CTRL+D")) {
debugShortcut();
}
if (igMenuItem("Quit", "CTRL+Q")) {
quitShortcut();
}
igEndMenu();
}
igEndMainMenuBar();
}
{
import std.range : chunks;
igBegin("Emulator Status");
igBeginChild("General");
igText("OpCode: 0x%04X", emu_.cpu.opcode);
igText("PC:");
igSameLine();
igDragInt("##pc", cast(int*)&emu_.cpu.pc, 0.5f, 0, emu_.ram.length);
igText("Registers (v0 - vF)");
igColumns(4, null, false);
auto n = 0;
foreach (ref chunk; emu_.cpu.v[].chunks(4)) {
igText("v%0X 0x%02X ", n, chunk[0]);
igText("v%0X 0x%02X ", n+1, chunk[1]);
igText("v%0X 0x%02X ", n+2, chunk[2]);
igText("v%0X 0x%02X ", n+3, chunk[3]);
igNextColumn();
n += 4;
}
igColumns(1, null, false);
igText("Index Register: 0x%04X", emu_.cpu.i);
igText("Delay Timer: 0x%04X", emu_.cpu.delay_timer);
igText("Sound Timer: 0x%04X", emu_.cpu.sound_timer);
if(igButton("Step")) {
emu_.step();
}
igSameLine();
if (igButton((emu_.run_flag) ? "Stop" : "Run")) {
emu_.run_flag = !emu_.run_flag;
}
igText("Stack");
auto d = &getStackFrame;
igPushItemWidth(-1);
igListBox2("", &stack_cur_, &doCallback, cast(void*)&d, emu_.stack.length, 16);
igPopItemWidth();
igEndChild();
igEnd();
}
// mem_editor_.draw("Emulator Memory", emu_.ram[]);
} // draw
} // Chip8Status
string doCapture(string sym, uint start, uint end)(){ string doCapture(string sym, uint start, uint end)(){
import std.string : format; import std.string : format;
@ -79,11 +241,11 @@ struct Chip8 {
bool run_flag; bool run_flag;
bool draw_flag; bool draw_flag;
void load(size_t offset, in ubyte[] data) { void load(size_t offset, in void[] data) {
assert(offset + data.length < ram.length); assert(offset + data.length < ram.length);
ram[offset .. offset + data.length] = data[]; ram[offset .. offset + data.length] = cast(ubyte[])data[];
} // load } // load
@ -430,9 +592,9 @@ struct Chip8 {
} // step } // step
void handle_event(ref SDL_Event ev) { void handleEvent(ref SDL_Event ev) {
} // handle_event } // handleEvent
void tick() { void tick() {
@ -456,30 +618,28 @@ struct Chip8 {
} // Emulator } // Emulator
void load_libs() { void loadLibs() {
import glad.gl.loader;
DerelictSDL2.load(); DerelictSDL2.load();
DerelictImgui.load(); DerelictImgui.load();
auto status = gladLoadGL();
} }
void init_libs() { void initLibs() {
SDL_Init(SDL_INIT_VIDEO); SDL_Init(SDL_INIT_VIDEO);
SDL_GL_LoadLibrary(null);
} }
void setup_imgui() { void setupImgui() {
} }
void main() { void main() {
load_libs(); loadLibs();
init_libs(); initLibs();
Emulator emu; Emulator emu;
emu.create(); emu.create();
@ -491,22 +651,34 @@ struct Emulator {
bool running; bool running;
// debug
Chip8Status status;
Window window; Window window;
Chip8 chip8; Imgui imgui;
Chip8 emu;
void create() { void create() {
// create window // create window
window.create_window(640, 480); window.createWindow(640, 480);
// setup imgui
imgui.initialize();
imgui.createDeviceObjects();
// setup debug ui
status.initialize(&this, &emu);
} }
void handle_events() { void handleEvents() {
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
chip8.handle_event(event); imgui.handleEvent(event);
emu.handleEvent(event);
switch (event.type) with (SDL_EventType) { switch (event.type) with (SDL_EventType) {
case SDL_QUIT: { case SDL_QUIT: {
@ -520,14 +692,14 @@ struct Emulator {
} }
} // handle_events } // handleEvents
void run() { void run() {
running = true; running = true;
while (running) { while (running) {
handle_events(); handleEvents();
tick(); tick();
draw(); draw();
} }
@ -536,10 +708,24 @@ struct Emulator {
void tick() { void tick() {
emu.tick();
} }
void draw() { void draw() {
window.renderClear(0x428bca);
imgui.newFrame(window);
status.draw();
imgui.endFrame();
window.renderPresent();
}
void quit() {
running = false;
} }
} }

View File

@ -29,6 +29,10 @@ struct Imgui {
int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0; int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0;
uint g_VboHandle = 0, g_VaoHandle = 0, g_ElementsHandle = 0; uint g_VboHandle = 0, g_VaoHandle = 0, g_ElementsHandle = 0;
// imgui input related state
bool[3] mouse_buttons_pressed;
float scroll_wheel = 0.0f;
void initialize() { void initialize() {
auto io = igGetIO(); auto io = igGetIO();
@ -52,23 +56,45 @@ struct Imgui {
io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y; io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z; io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
io.RenderDrawListsFn = bindDelegate(&render_draw_lists); io.RenderDrawListsFn = bindDelegate(&renderDrawLists);
io.SetClipboardTextFn = bindDelegate(&set_clipboard_text); io.SetClipboardTextFn = bindDelegate(&setClipboardText);
io.GetClipboardTextFn = bindDelegate(&get_clipboard_text); io.GetClipboardTextFn = bindDelegate(&getClipboardText);
} }
void create_font_texture() { void createFontTexture() {
// build texture atlas
auto io = igGetIO();
ubyte* pixels;
int width, height;
ImFontAtlas_GetTexDataAsRGBA32(io.Fonts, &pixels, &width, &height, null);
// upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// store our identifier
ImFontAtlas_SetTexID(io.Fonts, cast(void*)g_FontTexture);
// restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
} }
void create_device_objects() { void createDeviceObjects() {
// backup GL state // backup GL state
GLint last_texture, last_array_buffer, last_vertex_array; GLint last_texture, last_array_buffer, last_vertex_array;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); if (last_texture != 0) glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); if (last_array_buffer != 0) glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); if (last_vertex_array != 0) glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
const GLchar *vertex_shader = q{ const GLchar *vertex_shader = q{
#version 330 #version 330
@ -127,7 +153,7 @@ struct Imgui {
glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, ImDrawVert.sizeof, cast(void*)ImDrawVert.uv.offsetof); glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, ImDrawVert.sizeof, cast(void*)ImDrawVert.uv.offsetof);
glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, ImDrawVert.sizeof, cast(void*)ImDrawVert.col.offsetof); glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, ImDrawVert.sizeof, cast(void*)ImDrawVert.col.offsetof);
create_font_texture(); createFontTexture();
// restore modified GL state // restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture); glBindTexture(GL_TEXTURE_2D, last_texture);
@ -137,7 +163,7 @@ struct Imgui {
} }
extern(C) nothrow extern(C) nothrow
void render_draw_lists(ImDrawData* draw_data) { void renderDrawLists(ImDrawData* draw_data) {
// avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) // avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
auto io = igGetIO(); auto io = igGetIO();
@ -183,6 +209,7 @@ struct Imgui {
[ 0.0f, 0.0f, -1.0f, 0.0f ], [ 0.0f, 0.0f, -1.0f, 0.0f ],
[-1.0f, 1.0f, 0.0f, 1.0f ], [-1.0f, 1.0f, 0.0f, 1.0f ],
]; ];
glUseProgram(g_ShaderHandle); glUseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0); glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
@ -236,38 +263,88 @@ struct Imgui {
} }
extern(C) nothrow extern(C) nothrow
const(char)* get_clipboard_text(void* user_data) { const(char)* getClipboardText(void* user_data) {
return SDL_GetClipboardText(); return SDL_GetClipboardText();
} }
extern(C) nothrow extern(C) nothrow
void set_clipboard_text(void* user_data, const (char)* text) { void setClipboardText(void* user_data, const (char)* text) {
SDL_SetClipboardText(text); SDL_SetClipboardText(text);
} }
void new_frame(ref Window win) { void newFrame(ref Window win) {
auto io = igGetIO();
int win_w, win_h;
win.window_size(win_w, win_h);
int fbo_w, fbo_h;
win.framebuffer_size(fbo_w, fbo_h);
io.DisplaySize = ImVec2(win_w, win_h);
io.DisplayFramebufferScale = ImVec2(cast(float)fbo_w / win_w, cast(float)fbo_h / win_h);
int m_x, m_y;
win.mouse_pos(m_x, m_y);
io.MousePos = ImVec2(cast(float)m_x, cast(float)m_y);
io.MouseDown[0] = mouse_buttons_pressed[0] || (SDL_GetMouseState(null, null) & SDL_BUTTON_LEFT) != 0;
mouse_buttons_pressed[0] = false;
io.MouseDown[1] = mouse_buttons_pressed[0] || (SDL_GetMouseState(null, null) & SDL_BUTTON_MIDDLE) != 0;
mouse_buttons_pressed[1] = false;
io.MouseDown[2] = mouse_buttons_pressed[2] || (SDL_GetMouseState(null, null) & SDL_BUTTON_RIGHT) != 0;
mouse_buttons_pressed[2] = false;
io.MouseWheel = scroll_wheel;
scroll_wheel = 0.0f;
igNewFrame();
} }
void handle_event(ref SDL_Event ev) { void endFrame() {
igRender();
}
void handleEvent(ref SDL_Event ev) {
auto io = igGetIO();
switch (ev.type) with (SDL_EventType) { switch (ev.type) with (SDL_EventType) {
case SDL_TEXTINPUT: case SDL_TEXTINPUT:
ImGuiIO_AddInputCharacter(cast(ushort)ev.text.text[0]);
break; break;
case SDL_MOUSEBUTTONDOWN: case SDL_KEYDOWN, SDL_KEYUP:
auto mods = ev.key.keysym.mod;
io.KeyCtrl = (mods & KMOD_CTRL) != 0;
io.KeyShift = (mods & KMOD_SHIFT) != 0;
io.KeyAlt = (mods & KMOD_ALT) != 0;
break; break;
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP:
auto btn = ev.button.button;
if (btn < 4) {
mouse_buttons_pressed[btn - 1] = (ev.type == SDL_MOUSEBUTTONDOWN);
}
break; break;
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
break; scroll_wheel += ev.wheel.y;
case SDL_KEYDOWN:
break; break;
case SDL_KEYUP:
break;
default: default:
break; break;

View File

@ -28,7 +28,7 @@ struct Window {
SDL_Window* window; SDL_Window* window;
SDL_GLContext context; SDL_GLContext context;
void create_window(int w, int h, const char* title = "Chipd8 Emu") { void createWindow(int w, int h, const char* title = "Chipd8 Emu") {
assert(w > 0, "window width must be > 0"); assert(w > 0, "window width must be > 0");
assert(h > 0, "window height must be > 0"); assert(h > 0, "window height must be > 0");
@ -50,46 +50,52 @@ struct Window {
return; return;
} }
import glad.gl.loader;
import std.functional;
// Check OpenGL properties
printf("OpenGL loaded\n");
gladLoadGL((const (char)* a) => SDL_GL_GetProcAddress(a));
printf("Vendor: %s\n", glGetString(GL_VENDOR));
printf("Renderer: %s\n", glGetString(GL_RENDERER));
printf("Version: %s\n", glGetString(GL_VERSION));
// assign em yes // assign em yes
window = new_win; window = new_win;
context = new_con; context = new_con;
atexit(SDL_Quit); atexit(SDL_Quit);
} // create_window } // createWindow
void handle_event(ref SDL_Event ev) { void handleEvent(ref SDL_Event ev) {
} } // handleEvent
void render_clear(int colour) { void renderClear(int colour) {
auto col = to!GLColor(color, 255); auto col = to!(float[4])(colour, 255);
glClearColor(col[0], col[1], col[2], col[3]); glClearColor(col[0], col[1], col[2], col[3]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} } // renderClear
void render_present() { void renderPresent() {
SDL_GL_SwapWindow(window); SDL_GL_SwapWindow(window);
} // renderPresent
void mouse_pos(ref int x, ref int y) {
SDL_GetMouseState(&x, &y);
} }
@property nothrow @nogc { void window_size(ref int w, ref int h) {
SDL_GetWindowSize(window, &w, &h);
}
int[2] window_size() { void framebuffer_size(ref int w, ref int h) {
int w, h; SDL_GL_GetDrawableSize(window, &w, &h);
SDL_GetWindowSize(window, &w, &h); }
return [w, h];
}
int[2] framebuffer_size() {
int w, h;
SDL_GL_GetDrawableSize(window, &w, &h);
return [w, h];
}
}
} // Window } // Window