Compare commits
2 Commits
a636ae5932
...
90897bd8d6
Author | SHA1 | Date |
---|---|---|
Robin Hübner | 90897bd8d6 | |
Robin Hübner | 57efb162d6 |
Binary file not shown.
3
dub.json
3
dub.json
|
@ -4,7 +4,8 @@
|
|||
"profan"
|
||||
],
|
||||
"dependencies": {
|
||||
"derelict-sdl2": "~>3.1.0-alpha.4"
|
||||
"derelict-sdl2": "~>3.1.0-alpha.4",
|
||||
"derelict-imgui": "~>0.10.0"
|
||||
},
|
||||
"description": "A minimal D application.",
|
||||
"copyright": "Copyright © 2018, profan",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"fileVersion": 1,
|
||||
"versions": {
|
||||
"derelict-gl3": "2.0.0-beta.6",
|
||||
"derelict-imgui": "0.10.0",
|
||||
"derelict-sdl2": "3.1.0-alpha.4",
|
||||
"derelict-util": "3.0.0-beta.2"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
Binary file not shown.
288
source/app.d
288
source/app.d
|
@ -1,7 +1,173 @@
|
|||
import std.stdio;
|
||||
import derelict.sdl2.sdl;
|
||||
import derelict.imgui.imgui;
|
||||
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;
|
||||
|
@ -75,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
|
||||
|
||||
|
@ -426,6 +592,10 @@ struct Chip8 {
|
|||
|
||||
} // step
|
||||
|
||||
void handleEvent(ref SDL_Event ev) {
|
||||
|
||||
} // handleEvent
|
||||
|
||||
void tick() {
|
||||
|
||||
if (run_flag) {
|
||||
|
@ -448,67 +618,28 @@ struct Chip8 {
|
|||
|
||||
} // Emulator
|
||||
|
||||
struct Window {
|
||||
|
||||
import core.stdc.stdio;
|
||||
import core.stdc.stdlib;
|
||||
|
||||
SDL_Window* window;
|
||||
SDL_GLContext context;
|
||||
|
||||
void create_window(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");
|
||||
|
||||
// minimum OpenGL 3.3
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
|
||||
SDL_Window* new_win = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_OPENGL);
|
||||
if (new_win == null) {
|
||||
printf("SDL2 - Window could not be created: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_GLContext new_con = SDL_GL_CreateContext(new_win);
|
||||
if (new_con == null) {
|
||||
printf("SDL2 - failed creating OpenGL 3.3 context: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
// assign em yes
|
||||
window = new_win;
|
||||
context = new_con;
|
||||
|
||||
atexit(SDL_Quit);
|
||||
|
||||
} // create_window
|
||||
|
||||
} // Window
|
||||
|
||||
void load_libs() {
|
||||
|
||||
import glad.gl.loader;
|
||||
void loadLibs() {
|
||||
|
||||
DerelictSDL2.load();
|
||||
auto status = gladLoadGL();
|
||||
DerelictImgui.load();
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -520,42 +651,36 @@ 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)) {
|
||||
|
||||
imgui.handleEvent(event);
|
||||
emu.handleEvent(event);
|
||||
|
||||
switch (event.type) with (SDL_EventType) {
|
||||
case SDL_TEXTINPUT: {
|
||||
break;
|
||||
}
|
||||
case SDL_TEXTEDITING: {
|
||||
break;
|
||||
}
|
||||
case SDL_MOUSEBUTTONDOWN: {
|
||||
break;
|
||||
}
|
||||
case SDL_MOUSEBUTTONUP: {
|
||||
break;
|
||||
}
|
||||
case SDL_MOUSEWHEEL: {
|
||||
break;
|
||||
}
|
||||
case SDL_KEYDOWN: {
|
||||
break;
|
||||
}
|
||||
case SDL_KEYUP: {
|
||||
break;
|
||||
}
|
||||
case SDL_QUIT: {
|
||||
running = false;
|
||||
break;
|
||||
|
@ -564,16 +689,17 @@ struct Emulator {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // handle_events
|
||||
} // handleEvents
|
||||
|
||||
void run() {
|
||||
|
||||
running = true;
|
||||
|
||||
while (running) {
|
||||
handle_events();
|
||||
handleEvents();
|
||||
tick();
|
||||
draw();
|
||||
}
|
||||
|
@ -582,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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,355 @@
|
|||
module imgui;
|
||||
|
||||
import glad.gl.all;
|
||||
import derelict.sdl2.sdl;
|
||||
import derelict.imgui.imgui;
|
||||
|
||||
import window;
|
||||
|
||||
import std.traits : isDelegate, ReturnType, ParameterTypeTuple;
|
||||
auto bindDelegate(T, string file = __FILE__, size_t line = __LINE__)(T t) if(isDelegate!T) {
|
||||
|
||||
static T dg;
|
||||
dg = t;
|
||||
|
||||
extern(C) static ReturnType!T func(ParameterTypeTuple!T args) {
|
||||
return dg(args);
|
||||
}
|
||||
|
||||
return &func;
|
||||
|
||||
} // bindDelegate (thanks Destructionator)
|
||||
|
||||
struct Imgui {
|
||||
|
||||
// OpenGL data, cleanup soon
|
||||
GLuint g_FontTexture = 0;
|
||||
int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
|
||||
int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;
|
||||
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();
|
||||
io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
|
||||
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
|
||||
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
|
||||
io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN;
|
||||
io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A;
|
||||
io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C;
|
||||
io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V;
|
||||
io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X;
|
||||
io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
|
||||
|
||||
io.RenderDrawListsFn = bindDelegate(&renderDrawLists);
|
||||
io.SetClipboardTextFn = bindDelegate(&setClipboardText);
|
||||
io.GetClipboardTextFn = bindDelegate(&getClipboardText);
|
||||
|
||||
}
|
||||
|
||||
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 createDeviceObjects() {
|
||||
|
||||
// backup GL state
|
||||
GLint last_texture, last_array_buffer, 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
|
||||
uniform mat4 ProjMtx;
|
||||
in vec2 Position;
|
||||
in vec2 UV;
|
||||
in vec4 Color;
|
||||
out vec2 Frag_UV;
|
||||
out vec4 Frag_Color;
|
||||
void main() {
|
||||
Frag_UV = UV;
|
||||
Frag_Color = Color;
|
||||
gl_Position = ProjMtx * vec4(Position.xy,0,1);
|
||||
}
|
||||
};
|
||||
|
||||
const GLchar* fragment_shader = q{
|
||||
#version 330
|
||||
uniform sampler2D Texture;
|
||||
in vec2 Frag_UV;
|
||||
in vec4 Frag_Color;
|
||||
out vec4 Out_Color;
|
||||
void main() {
|
||||
Out_Color = Frag_Color * texture( Texture, Frag_UV.st);
|
||||
}
|
||||
};
|
||||
|
||||
g_ShaderHandle = glCreateProgram();
|
||||
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
|
||||
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(g_VertHandle, 1, &vertex_shader, null);
|
||||
glShaderSource(g_FragHandle, 1, &fragment_shader, null);
|
||||
glCompileShader(g_VertHandle);
|
||||
glCompileShader(g_FragHandle);
|
||||
glAttachShader(g_ShaderHandle, g_VertHandle);
|
||||
glAttachShader(g_ShaderHandle, g_FragHandle);
|
||||
glLinkProgram(g_ShaderHandle);
|
||||
|
||||
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
|
||||
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
|
||||
g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position");
|
||||
g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV");
|
||||
g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color");
|
||||
|
||||
glGenBuffers(1, &g_VboHandle);
|
||||
glGenBuffers(1, &g_ElementsHandle);
|
||||
|
||||
glGenVertexArrays(1, &g_VaoHandle);
|
||||
glBindVertexArray(g_VaoHandle);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
||||
glEnableVertexAttribArray(g_AttribLocationPosition);
|
||||
glEnableVertexAttribArray(g_AttribLocationUV);
|
||||
glEnableVertexAttribArray(g_AttribLocationColor);
|
||||
|
||||
glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, ImDrawVert.sizeof, cast(void*)ImDrawVert.pos.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);
|
||||
|
||||
createFontTexture();
|
||||
|
||||
// restore modified GL state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
glBindVertexArray(last_vertex_array);
|
||||
|
||||
}
|
||||
|
||||
extern(C) nothrow
|
||||
void renderDrawLists(ImDrawData* draw_data) {
|
||||
|
||||
// avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
auto io = igGetIO();
|
||||
int fb_width = cast(int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
|
||||
int fb_height = cast(int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
|
||||
if (fb_width == 0 || fb_height == 0) { return; }
|
||||
draw_data.ScaleClipRects(io.DisplayFramebufferScale);
|
||||
|
||||
// backup GL state
|
||||
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, cast(GLint*)&last_active_texture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
|
||||
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
|
||||
GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
GLint[4] last_viewport; glGetIntegerv(GL_VIEWPORT, last_viewport.ptr);
|
||||
GLint[4] last_scissor_box; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box.ptr);
|
||||
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, cast(GLint*)&last_blend_src_rgb);
|
||||
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, cast(GLint*)&last_blend_dst_rgb);
|
||||
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, cast(GLint*)&last_blend_src_alpha);
|
||||
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, cast(GLint*)&last_blend_dst_alpha);
|
||||
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, cast(GLint*)&last_blend_equation_rgb);
|
||||
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, cast(GLint*)&last_blend_equation_alpha);
|
||||
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
// Setup viewport, orthographic projection matrix
|
||||
glViewport(0, 0, cast(GLsizei)fb_width, cast(GLsizei)fb_height);
|
||||
const float[4][4] ortho_projection = [
|
||||
[ 2.0f/io.DisplaySize.x, 0.0f, 0.0f, 0.0f ],
|
||||
[ 0.0f, 2.0f/-io.DisplaySize.y, 0.0f, 0.0f ],
|
||||
[ 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]);
|
||||
glBindVertexArray(g_VaoHandle);
|
||||
|
||||
foreach (int n; 0 .. draw_data.CmdListsCount) {
|
||||
ImDrawList* cmd_list = draw_data.CmdLists[n];
|
||||
ImDrawIdx* idx_buffer_offset;
|
||||
|
||||
auto countVertices = ImDrawList_GetVertexBufferSize(cmd_list);
|
||||
auto countIndices = ImDrawList_GetIndexBufferSize(cmd_list);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
||||
glBufferData(GL_ARRAY_BUFFER, countVertices * ImDrawVert.sizeof, cast(GLvoid*)ImDrawList_GetVertexPtr(cmd_list,0), GL_STREAM_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, countIndices * ImDrawIdx.sizeof, cast(GLvoid*)ImDrawList_GetIndexPtr(cmd_list,0), GL_STREAM_DRAW);
|
||||
|
||||
auto cmdCnt = ImDrawList_GetCmdSize(cmd_list);
|
||||
|
||||
foreach(int cmd_i; 0 .. cmdCnt) {
|
||||
auto pcmd = ImDrawList_GetCmdPtr(cmd_list, cmd_i);
|
||||
|
||||
if (pcmd.UserCallback) {
|
||||
pcmd.UserCallback(cmd_list, pcmd);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, cast(GLuint)pcmd.TextureId);
|
||||
glScissor(cast(int)pcmd.ClipRect.x, cast(int)(fb_height - pcmd.ClipRect.w), cast(int)(pcmd.ClipRect.z - pcmd.ClipRect.x), cast(int)(pcmd.ClipRect.w - pcmd.ClipRect.y));
|
||||
glDrawElements(GL_TRIANGLES, cast(GLsizei)pcmd.ElemCount, ImDrawIdx.sizeof == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
|
||||
}
|
||||
idx_buffer_offset += pcmd.ElemCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore modified GL state
|
||||
glUseProgram(last_program);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
glActiveTexture(last_active_texture);
|
||||
glBindVertexArray(last_vertex_array);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
|
||||
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||
glViewport(last_viewport[0], last_viewport[1], cast(GLsizei)last_viewport[2], cast(GLsizei)last_viewport[3]);
|
||||
glScissor(last_scissor_box[0], last_scissor_box[1], cast(GLsizei)last_scissor_box[2], cast(GLsizei)last_scissor_box[3]);
|
||||
|
||||
}
|
||||
|
||||
extern(C) nothrow
|
||||
const(char)* getClipboardText(void* user_data) {
|
||||
return SDL_GetClipboardText();
|
||||
}
|
||||
|
||||
extern(C) nothrow
|
||||
void setClipboardText(void* user_data, const (char)* text) {
|
||||
SDL_SetClipboardText(text);
|
||||
}
|
||||
|
||||
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 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_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_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP:
|
||||
auto btn = ev.button.button;
|
||||
|
||||
if (btn < 4) {
|
||||
mouse_buttons_pressed[btn - 1] = (ev.type == SDL_MOUSEBUTTONDOWN);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
scroll_wheel += ev.wheel.y;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
module window;
|
||||
|
||||
import derelict.sdl2.sdl;
|
||||
import glad.gl.all;
|
||||
|
||||
/**
|
||||
* Converts an integer representing a colour, for example 0x428bca into a 4 element
|
||||
* int array for passing to OpenGL.
|
||||
*/
|
||||
GLfloat[4] to(T : GLfloat[4])(int color, ubyte alpha = 255) nothrow @nogc pure {
|
||||
|
||||
GLfloat[4] gl_color = [ //mask out r, g, b components from int
|
||||
cast(float)cast(ubyte)(color>>16)/255,
|
||||
cast(float)cast(ubyte)(color>>8)/255,
|
||||
cast(float)cast(ubyte)(color)/255,
|
||||
cast(float)cast(ubyte)(alpha)/255
|
||||
];
|
||||
|
||||
return gl_color;
|
||||
|
||||
} // to!GLfloat[4]
|
||||
|
||||
struct Window {
|
||||
|
||||
import core.stdc.stdio;
|
||||
import core.stdc.stdlib;
|
||||
|
||||
SDL_Window* window;
|
||||
SDL_GLContext context;
|
||||
|
||||
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");
|
||||
|
||||
// minimum OpenGL 3.3
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32);
|
||||
|
||||
SDL_Window* new_win = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_OPENGL);
|
||||
if (new_win == null) {
|
||||
printf("SDL2 - Window could not be created: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_GLContext new_con = SDL_GL_CreateContext(new_win);
|
||||
if (new_con == null) {
|
||||
printf("SDL2 - failed creating OpenGL 3.3 context: %s\n", SDL_GetError());
|
||||
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);
|
||||
|
||||
} // createWindow
|
||||
|
||||
void handleEvent(ref SDL_Event ev) {
|
||||
|
||||
} // handleEvent
|
||||
|
||||
void renderClear(int colour) {
|
||||
|
||||
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 renderPresent() {
|
||||
|
||||
SDL_GL_SwapWindow(window);
|
||||
|
||||
} // renderPresent
|
||||
|
||||
void mouse_pos(ref int x, ref int y) {
|
||||
SDL_GetMouseState(&x, &y);
|
||||
}
|
||||
|
||||
void window_size(ref int w, ref int h) {
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
}
|
||||
|
||||
void framebuffer_size(ref int w, ref int h) {
|
||||
SDL_GL_GetDrawableSize(window, &w, &h);
|
||||
}
|
||||
|
||||
} // Window
|
Loading…
Reference in New Issue