From 90897bd8d672aab74fa1abb0fb41420e05606f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20H=C3=BCbner?= Date: Sat, 23 Jun 2018 02:02:07 +0200 Subject: [PATCH] basic emu workin, now we can work on it yes --- imgui.ini | 10 +++ programs/sqrt.ch8 | Bin 0 -> 386 bytes source/app.d | 222 ++++++++++++++++++++++++++++++++++++++++++---- source/imgui.d | 119 ++++++++++++++++++++----- source/window.d | 50 ++++++----- 5 files changed, 340 insertions(+), 61 deletions(-) create mode 100644 imgui.ini create mode 100644 programs/sqrt.ch8 diff --git a/imgui.ini b/imgui.ini new file mode 100644 index 0000000..b828e05 --- /dev/null +++ b/imgui.ini @@ -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 + diff --git a/programs/sqrt.ch8 b/programs/sqrt.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..56485517d0afb9cfe9d5ab74d3348026dcb2d0aa GIT binary patch literal 386 zcmY+8KTE?<6vfZ0X++S{Ce0?XS|WCECUSQkzA`E3$(!pGZNeofuqCKzq>aaVGDGK{Y9of^-l< z_`*_drRd$#lGK%#oQkj&DRT4^N<|QsXiTa%aA7?2!&Mh$nmyw?gbe%a$ywNWfUM63 zh_%o;hFKGBWHMaXpWSOjh%A?x7cpWzsRk@+M;_@;Qb{Z3sqpTvOy?sI9GPl!VP1*` grHA>+Jjh$`-cX+{=bR?8qd|+E@7K1<8|(+bFV!QG%>V!Z literal 0 HcmV?d00001 diff --git a/source/app.d b/source/app.d index e2134c8..61657f0 100644 --- a/source/app.d +++ b/source/app.d @@ -6,6 +6,168 @@ import glad.gl.all; import window; 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)(){ import std.string : format; @@ -79,11 +241,11 @@ struct Chip8 { bool run_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); - ram[offset .. offset + data.length] = data[]; + ram[offset .. offset + data.length] = cast(ubyte[])data[]; } // load @@ -430,9 +592,9 @@ struct Chip8 { } // step - void handle_event(ref SDL_Event ev) { + void handleEvent(ref SDL_Event ev) { - } // handle_event + } // handleEvent void tick() { @@ -456,30 +618,28 @@ struct Chip8 { } // Emulator -void load_libs() { - - import glad.gl.loader; +void loadLibs() { DerelictSDL2.load(); DerelictImgui.load(); - auto status = gladLoadGL(); } -void init_libs() { +void initLibs() { SDL_Init(SDL_INIT_VIDEO); + SDL_GL_LoadLibrary(null); } -void setup_imgui() { +void setupImgui() { } void main() { - load_libs(); - init_libs(); + loadLibs(); + initLibs(); Emulator emu; emu.create(); @@ -491,22 +651,34 @@ struct Emulator { bool running; + // debug + Chip8Status status; + Window window; - Chip8 chip8; + Imgui imgui; + Chip8 emu; void create() { // 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; while (SDL_PollEvent(&event)) { - chip8.handle_event(event); + imgui.handleEvent(event); + emu.handleEvent(event); switch (event.type) with (SDL_EventType) { case SDL_QUIT: { @@ -520,14 +692,14 @@ struct Emulator { } - } // handle_events + } // handleEvents void run() { running = true; while (running) { - handle_events(); + handleEvents(); tick(); draw(); } @@ -536,10 +708,24 @@ struct Emulator { void tick() { + emu.tick(); + } void draw() { + window.renderClear(0x428bca); + imgui.newFrame(window); + + status.draw(); + + imgui.endFrame(); + window.renderPresent(); + + } + + void quit() { + running = false; } } \ No newline at end of file diff --git a/source/imgui.d b/source/imgui.d index 54c2bf5..ba5f589 100644 --- a/source/imgui.d +++ b/source/imgui.d @@ -29,6 +29,10 @@ struct Imgui { int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 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() { auto io = igGetIO(); @@ -52,23 +56,45 @@ struct Imgui { io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y; io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z; - io.RenderDrawListsFn = bindDelegate(&render_draw_lists); - io.SetClipboardTextFn = bindDelegate(&set_clipboard_text); - io.GetClipboardTextFn = bindDelegate(&get_clipboard_text); + io.RenderDrawListsFn = bindDelegate(&renderDrawLists); + io.SetClipboardTextFn = bindDelegate(&setClipboardText); + 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 GLint last_texture, last_array_buffer, last_vertex_array; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); - glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); - glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); + if (last_texture != 0) glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + if (last_array_buffer != 0) glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); + if (last_vertex_array != 0) glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); const GLchar *vertex_shader = q{ #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_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, ImDrawVert.sizeof, cast(void*)ImDrawVert.col.offsetof); - create_font_texture(); + createFontTexture(); // restore modified GL state glBindTexture(GL_TEXTURE_2D, last_texture); @@ -137,7 +163,7 @@ struct Imgui { } 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) auto io = igGetIO(); @@ -183,6 +209,7 @@ struct Imgui { [ 0.0f, 0.0f, -1.0f, 0.0f ], [-1.0f, 1.0f, 0.0f, 1.0f ], ]; + glUseProgram(g_ShaderHandle); glUniform1i(g_AttribLocationTex, 0); glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); @@ -236,38 +263,88 @@ struct Imgui { } extern(C) nothrow - const(char)* get_clipboard_text(void* user_data) { + const(char)* getClipboardText(void* user_data) { return SDL_GetClipboardText(); } extern(C) nothrow - void set_clipboard_text(void* user_data, const (char)* text) { + void setClipboardText(void* user_data, const (char)* 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) { case SDL_TEXTINPUT: + ImGuiIO_AddInputCharacter(cast(ushort)ev.text.text[0]); + 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; - 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; + case SDL_MOUSEWHEEL: - break; + scroll_wheel += ev.wheel.y; - case SDL_KEYDOWN: break; - case SDL_KEYUP: - break; - + default: break; diff --git a/source/window.d b/source/window.d index 237eb88..adeb6d6 100644 --- a/source/window.d +++ b/source/window.d @@ -28,7 +28,7 @@ struct Window { SDL_Window* window; 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(h > 0, "window height must be > 0"); @@ -50,46 +50,52 @@ struct Window { 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 window = new_win; context = new_con; 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]); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } + } // renderClear - void render_present() { + void renderPresent() { 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() { - int 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]; - } - - } + void framebuffer_size(ref int w, ref int h) { + SDL_GL_GetDrawableSize(window, &w, &h); + } } // Window \ No newline at end of file