diff options
Diffstat (limited to 'src/graveyard')
-rw-r--r-- | src/graveyard/gl_renderer.cpp | 389 | ||||
-rw-r--r-- | src/graveyard/gl_renderer.h | 52 | ||||
-rw-r--r-- | src/graveyard/lin_file.c | 85 | ||||
-rw-r--r-- | src/graveyard/lin_glx_modern.c | 243 | ||||
-rw-r--r-- | src/graveyard/linux_net_stream.c | 192 | ||||
-rw-r--r-- | src/graveyard/win32/Win32WindowService.cpp | 375 | ||||
-rw-r--r-- | src/graveyard/win32/Win32WindowService.h | 33 | ||||
-rw-r--r-- | src/graveyard/win32/win32_florilia.c | 111 | ||||
-rw-r--r-- | src/graveyard/win32/win32_fscord.cpp | 181 | ||||
-rw-r--r-- | src/graveyard/win32/win32_net.c | 79 | ||||
-rw-r--r-- | src/graveyard/win32/win32_network_stream.cpp | 90 | ||||
-rw-r--r-- | src/graveyard/win32/win32_window.c | 389 | ||||
-rw-r--r-- | src/graveyard/win32/win32_window.cpp | 77 | ||||
-rw-r--r-- | src/graveyard/win32_wgl_modern.c | 206 |
14 files changed, 2502 insertions, 0 deletions
diff --git a/src/graveyard/gl_renderer.cpp b/src/graveyard/gl_renderer.cpp new file mode 100644 index 0000000..f6ed6cb --- /dev/null +++ b/src/graveyard/gl_renderer.cpp @@ -0,0 +1,389 @@ +#include "../../platform/platform.h" +#include "../../external/stb_truetype.h" +#include "../../external/khronos/glcorearb.h" + +#include "../renderer.h" +#include "gl_renderer.h" + +#include <stdlib.h> + +// misc +static PFNGLCLEARCOLORPROC glClearColor; +static PFNGLCLEARPROC glClear; +static PFNGLVIEWPORTPROC glViewport; +static PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; +static PFNGLENABLEPROC glEnable; +static PFNGLBLENDFUNCPROC glBlendFunc; +static PFNGLDRAWELEMENTSPROC glDrawElements; +static PFNGLGENERATEMIPMAPPROC glGenerateMipmap; +static PFNGLGETERRORPROC glGetError; +static PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback; +static PFNGLACTIVETEXTUREPROC glActiveTexture; +static PFNGLUNIFORM1IPROC glUniform1i; +static PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; +static PFNGLDRAWARRAYSPROC glDrawArrays; +static PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; +static PFNGLUNIFORM3FPROC glUniform3f; +// framebuffer +static PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; +static PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; +static PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; +static PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; +static PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; +// vertex array +static PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; +static PFNGLBINDVERTEXARRAYPROC glBindVertexArray; +static PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; +static PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; +// buffers +static PFNGLGENBUFFERSPROC glGenBuffers; +static PFNGLBINDBUFFERPROC glBindBuffer; +static PFNGLBUFFERDATAPROC glBufferData; +static PFNGLBUFFERSUBDATAPROC glBufferSubData; +// textures +static PFNGLGENTEXTURESPROC glGenTextures; +static PFNGLDELETETEXTURESPROC glDeleteTextures; +static PFNGLBINDTEXTUREPROC glBindTexture; +static PFNGLTEXIMAGE2DPROC glTexImage2D; +static PFNGLTEXPARAMETERIPROC glTexParameteri; +// shader +static PFNGLCREATESHADERPROC glCreateShader; +static PFNGLSHADERSOURCEPROC glShaderSource; +static PFNGLCOMPILESHADERPROC glCompileShader; +static PFNGLGETSHADERIVPROC glGetShaderiv; +static PFNGLATTACHSHADERPROC glAttachShader; +static PFNGLDELETESHADERPROC glDeleteShader; +static PFNGLCREATEPROGRAMPROC glCreateProgram; +static PFNGLUSEPROGRAMPROC glUseProgram; +static PFNGLLINKPROGRAMPROC glLinkProgram; +static PFNGLVALIDATEPROGRAMPROC glValidateProgram; +static PFNGLGETPROGRAMIVPROC glGetProgramiv; + +void gl_debug_message_callback(GLenum src, GLenum type, GLuint id, + GLenum severity, GLsizei length, + const GLchar *message, const void *user_param) { + printf("====================\n" + "gl error detected\n" + "--------------------\n" + "src = %d\n" + "type = %d\n" + "id = %d\n" + "severity = %d\n" + "length = %d\n" + "message = %s\n" + "====================\n", + src, type, id, severity, length, message); +} + + +Gl_Renderer::Gl_Renderer() { +} + +// Todo: check if function pointers are valid +bool Gl_Renderer::get_functions() { + // only 4.3+ thing + glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)platform_get_gl_proc("glDebugMessageCallback"); + + // misc + glClear = (PFNGLCLEARPROC)platform_get_gl_proc("glClear"); + glClearColor = (PFNGLCLEARCOLORPROC)platform_get_gl_proc("glClearColor"); + glViewport = (PFNGLVIEWPORTPROC)platform_get_gl_proc("glViewport"); + glDrawElements = (PFNGLDRAWELEMENTSPROC)platform_get_gl_proc("glDrawElements"); + glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)platform_get_gl_proc("glGenerateMipmap"); + glGetError = (PFNGLGETERRORPROC)platform_get_gl_proc("glGetError"); + glActiveTexture = (PFNGLACTIVETEXTUREPROC)platform_get_gl_proc("glActiveTexture"); + glUniform1i = (PFNGLUNIFORM1IPROC)platform_get_gl_proc("glUniform1i"); + glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)platform_get_gl_proc("glGetUniformLocation"); + glDrawArrays = (PFNGLDRAWARRAYSPROC)platform_get_gl_proc("glDrawArrays"); + glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)platform_get_gl_proc("glUniformMatrix4fv"); + glUniform3f = (PFNGLUNIFORM3FPROC)platform_get_gl_proc("glUniform3f"); + glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)platform_get_gl_proc("glDeleteFramebuffers"); + glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)platform_get_gl_proc("glGenFramebuffers"); + glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)platform_get_gl_proc("glBindFramebuffer"); + glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)platform_get_gl_proc("glFramebufferTexture2D"); + glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)platform_get_gl_proc("glCheckFramebufferStatus"); + + // vertex array + glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)platform_get_gl_proc("glGenVertexArrays"); + glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)platform_get_gl_proc("glBindVertexArray"); + + // buffers + glGenBuffers = (PFNGLGENBUFFERSPROC)platform_get_gl_proc("glGenBuffers"); + glBindBuffer = (PFNGLBINDBUFFERPROC)platform_get_gl_proc("glBindBuffer"); + glBufferData = (PFNGLBUFFERDATAPROC)platform_get_gl_proc("glBufferData"); + glBufferSubData = (PFNGLBUFFERSUBDATAPROC)platform_get_gl_proc("glBufferSubData"); + glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)platform_get_gl_proc("glEnableVertexAttribArray"); + glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)platform_get_gl_proc("glVertexAttribPointer"); + + // textures + glGenTextures = (PFNGLGENTEXTURESPROC)platform_get_gl_proc("glGenTextures"); + glDeleteTextures = (PFNGLDELETETEXTURESPROC)platform_get_gl_proc("glDeleteTextures"); + glBindTexture = (PFNGLBINDTEXTUREPROC)platform_get_gl_proc("glBindTexture"); + glTexImage2D = (PFNGLTEXIMAGE2DPROC)platform_get_gl_proc("glTexImage2D"); + glTexParameteri = (PFNGLTEXPARAMETERIPROC)platform_get_gl_proc("glTexParameteri"); + + // shader + glCreateShader = (PFNGLCREATESHADERPROC)platform_get_gl_proc("glCreateShader"); + glShaderSource = (PFNGLSHADERSOURCEPROC)platform_get_gl_proc("glShaderSource"); + glCompileShader = (PFNGLCOMPILESHADERPROC)platform_get_gl_proc("glCompileShader"); + glGetShaderiv = (PFNGLGETSHADERIVPROC)platform_get_gl_proc("glGetShaderiv"); + glAttachShader = (PFNGLATTACHSHADERPROC)platform_get_gl_proc("glAttachShader"); + glDeleteShader = (PFNGLDELETESHADERPROC)platform_get_gl_proc("glDeleteShader"); + glCreateProgram = (PFNGLCREATEPROGRAMPROC)platform_get_gl_proc("glCreateProgram"); + glUseProgram = (PFNGLUSEPROGRAMPROC)platform_get_gl_proc("glUseProgram"); + glLinkProgram = (PFNGLLINKPROGRAMPROC)platform_get_gl_proc("glLinkProgram"); + glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)platform_get_gl_proc("glValidateProgram"); + glGetProgramiv = (PFNGLGETPROGRAMIVPROC)platform_get_gl_proc("glGetProgramiv"); + + // misc + glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)platform_get_gl_proc("glGetShaderInfoLog"); + glEnable = (PFNGLENABLEPROC)platform_get_gl_proc("glEnable"); + glBlendFunc = (PFNGLBLENDFUNCPROC)platform_get_gl_proc("glBlendFunc"); + + return true; +} + +bool Gl_Renderer::compile_shader(u32 *id, const char *src, GLenum type) { + u32 shader = glCreateShader(type); + glShaderSource(shader, 1, &src, NULL); + glCompileShader(shader); + + int success; + char info_log[512]; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if(!success) + { + glGetShaderInfoLog(shader, 512, NULL, info_log); + printf("error %s shader compilation failed\n%s\n", type == GL_VERTEX_SHADER ? "vertex" : "fragment", info_log); + + glDeleteShader(shader); + return false; + } + + *id = shader; + return true; +} + +bool Gl_Renderer::create_shader(u32 *shader, const char *vs_src, const char *fs_src) { + u32 vs_id; + u32 fs_id; + if (!compile_shader(&vs_id, vs_src, GL_VERTEX_SHADER) || + !compile_shader(&fs_id, fs_src, GL_FRAGMENT_SHADER)) { + return false; + } + + u32 program_id = glCreateProgram(); + glAttachShader(program_id, vs_id); + glAttachShader(program_id, fs_id); + glLinkProgram(program_id); + + glDeleteShader(vs_id); + glDeleteShader(fs_id); + + int success; + char info_log[512]; + glGetProgramiv(program_id, GL_LINK_STATUS, &success); + if(!success) { + printf("error linking shader program\n%s\n", info_log); + return false; + } + + *shader = program_id; + return true; +} + +// set the OpenGL orthographic projection matrix in vertex shader +void Gl_Renderer::ortho(f32 mat44[4][4], f32 x0, f32 x1, f32 y0, f32 y1, f32 z0, f32 z1) { + mat44[0][0] = 2 / (x1 - x0); + mat44[0][1] = 0; + mat44[0][2] = 0; + mat44[0][3] = 0; + + mat44[1][0] = 0; + mat44[1][1] = 2 / (y1 - y0); + mat44[1][2] = 0; + mat44[1][3] = 0; + + mat44[2][0] = 0; + mat44[2][1] = 0; + mat44[2][2] = 2 / (z1 - z0); + mat44[2][3] = 0; + + mat44[3][0] = -(x1 + x0) / (x1 - x0); + mat44[3][1] = -(y1 + y0) / (y1 - y0); + mat44[3][2] = -(z1 + z0) / (z1 - z0); + mat44[3][3] = 1; +} + +void Gl_Renderer::draw_rect(Rect rect, V3 color) { + Gl_Render_Rect *render_rect = &m_render_rect; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glBindVertexArray(render_rect->vertex_array); + glBindBuffer(GL_ARRAY_BUFFER, render_rect->vertex_buffer); + glUseProgram(render_rect->shader); + + i32 location; + + location = glGetUniformLocation(render_rect->shader, "u_color"); + glUniform3f(location, color.r, color.g, color.b); + + location = glGetUniformLocation(render_rect->shader, "u_projection"); + glUniformMatrix4fv(location, 1, GL_FALSE, &m_projection[0][0]); + + f32 x0 = rect.x0; + f32 y0 = rect.y0; + f32 x1 = rect.x1; + f32 y1 = rect.y1; + + float vertices[] = { + x0, y0, + x1, y0, + x1, y1, + x0, y1, + x0, y0, + x1, y1 + }; + + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +void Gl_Renderer::draw_text(const char *text, f32 x, f32 y) { + y = m_height - y; // transforming to stb_truetype coordinates where the + // origin is top-left instead of bottom-left + + struct Gl_Render_Font *font = &m_render_font; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glUseProgram(font->shader); + glBindVertexArray(font->vertex_array); + glBindBuffer(GL_ARRAY_BUFFER, font->vertex_buffer); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, font->texture); + + GLint loc = glGetUniformLocation(font->shader, "u_projection"); + glUniformMatrix4fv(loc, 1, GL_FALSE, &m_projection_stbtt[0][0]); + + loc = glGetUniformLocation(font->shader, "u_texture"); + glUniform1i(loc, 0); + + while (*text) { + if (*text >= 32 && *text <= 127) { + stbtt_aligned_quad q; + stbtt_GetBakedQuad(font->baked_chars, 512, 512, *text-32, &x, &y, &q, 1); + float vertices[] = { + q.x0, q.y0, q.s0, q.t0, + q.x1, q.y0, q.s1, q.t0, + q.x1, q.y1, q.s1, q.t1, + q.x0, q.y1, q.s0, q.t1, + q.x0, q.y0, q.s0, q.t0, + q.x1, q.y1, q.s1, q.t1, + }; + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); + glDrawArrays(GL_TRIANGLES, 0, 6); + } + text++; + } +} + +// NOTE: ttf_buff must be kept in memory +bool Gl_Renderer::init_text_drawing(u8 *ttf_buff, const char *vs_src, const char *fs_src, f32 font_size) { + struct Gl_Render_Font *font = &m_render_font; + + if (!create_shader(&font->shader, vs_src, fs_src)) + return false; + + // vao + glGenVertexArrays(1, &font->vertex_array); + glBindVertexArray(font->vertex_array); + + // vbo + u32 cnt_vertices = 6; + u32 bytes_per_vertex = 4 * sizeof(f32); + glGenBuffers(1, &font->vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, font->vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, bytes_per_vertex*cnt_vertices, 0, GL_DYNAMIC_DRAW); + + // 2 position, 2 texture + u32 stride = 4 *sizeof(f32); + void *offset_texture = (void*)(2*sizeof(f32)); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, 0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, offset_texture); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + + // font texture + glActiveTexture(GL_TEXTURE0); + u8 tmp_bitmap[512*512]; + stbtt_BakeFontBitmap(ttf_buff, 0, font_size, tmp_bitmap, 512, 512, 32, 96, font->baked_chars); + glGenTextures(1, &font->texture); + glBindTexture(GL_TEXTURE_2D, font->texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 512, 512, 0, GL_RED, GL_UNSIGNED_BYTE, tmp_bitmap); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glBindVertexArray(0); + + return true; +} + +bool Gl_Renderer::init_rect_drawing(const char *vs_src, const char *fs_src) { + struct Gl_Render_Rect *rect = &m_render_rect; + if (!create_shader(&rect->shader, vs_src, fs_src)) + return false; + + // vao + glGenVertexArrays(1, &rect->vertex_array); + glBindVertexArray(rect->vertex_array); + + // vbo + u32 cnt_vertices = 6; + u32 bytes_per_vertex = 2 * sizeof(f32); + glGenBuffers(1, &rect->vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, rect->vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, bytes_per_vertex*cnt_vertices, 0, GL_DYNAMIC_DRAW); + + // 2 position + u32 stride = 2 *sizeof(f32); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, 0); + glEnableVertexAttribArray(0); + + glBindVertexArray(0); + return true; +} + +void Gl_Renderer::draw_background(V3 color) { + glClearColor(color.r, color.g, color.b, 1.0); + glClear(GL_COLOR_BUFFER_BIT); +} + +void Gl_Renderer::viewport(i32 x, i32 y, i32 width, i32 height) { + ortho(m_projection_stbtt, 0, width, height, 0, 0, 1); + ortho(m_projection, 0, width, 0, height, 0, 1); + glViewport(x, y, width, height); + + m_width = width; + m_height = height; +} + +bool Gl_Renderer::init(f32 font_size, u8 *font, const char *font_vs, const char *font_fs, const char *rect_vs, const char *rect_fs) { + if (!get_functions() || + !init_text_drawing(font, font_vs, font_fs, font_size) || + !init_rect_drawing(rect_vs, rect_fs)) { + return false; + } + + glDebugMessageCallback(gl_debug_message_callback, 0); + + return true; +} + diff --git a/src/graveyard/gl_renderer.h b/src/graveyard/gl_renderer.h new file mode 100644 index 0000000..9c70c04 --- /dev/null +++ b/src/graveyard/gl_renderer.h @@ -0,0 +1,52 @@ +struct Gl_Render_Rect { + u32 vertex_array; + u32 vertex_buffer; + u32 shader; +}; + +struct Gl_Render_Font { + u32 vertex_array; + u32 vertex_buffer; + u32 index_buffer; + u32 texture; + u32 shader; + stbtt_bakedchar baked_chars[96]; +}; + +class Gl_Renderer : public Renderer { +private: + Gl_Render_Rect m_render_rect; + Gl_Render_Font m_render_font; + + f32 m_projection_stbtt[4][4]; + f32 m_projection[4][4]; + + i32 m_width; + i32 m_height; + + +public: + Gl_Renderer(); + +public: + bool init(f32 font_size, u8 *ttf_buff, const char *font_vs, const char *font_fs, const char *rect_vs, const char *rect_fs); + + void viewport(i32 x, i32 y, i32 width, i32 height) override; + void draw_background(V3 color) override; + void draw_rect(Rect rect, V3 color) override; + void draw_text(const char *text, f32 x, f32 y) override; + + +private: + bool get_functions(); + bool init_text_drawing(u8 *ttf_buff, const char *vs_src, const char *fs_src, f32 font_size); + bool init_rect_drawing(const char *vs_src, const char *fs_src); + + bool create_shader(u32 *shader, const char *vs_src, const char *fs_src); + bool compile_shader(u32 *id, const char *src, GLenum type); + + + // updates + void ortho(f32 mat44[4][4], f32 x0, f32 y0, f32 x1, f32 y1, f32 z0, f32 z1); +}; + diff --git a/src/graveyard/lin_file.c b/src/graveyard/lin_file.c new file mode 100644 index 0000000..5f0e003 --- /dev/null +++ b/src/graveyard/lin_file.c @@ -0,0 +1,85 @@ +void platform_free_buffer(Platform_Buffer *buff) +{ + free(buff->mem); + buff->size = 0; +} + +bool platform_read_file(Platform_Buffer *buff, const char *pathname) +{ + int fd = open(pathname, O_RDONLY); + if (fd == -1) + { + printf("error reading file %s\n", pathname); + return false; + } + + struct stat statbuff; + if (fstat(fd, &statbuff) == -1) + { + printf("cant fstat file %s\n", pathname); + close(fd); + return false; + } + + void *file_content = malloc(statbuff.st_size); + if (!file_content) + { + printf("error: out of memory\n"); + close(fd); + return false; + } + + ssize_t bytes_read = read(fd, file_content, statbuff.st_size); + if (bytes_read != statbuff.st_size) + { + printf("error: only read %ld/%ld bytes from file %s\n", bytes_read, statbuff.st_size, pathname); + close(fd); + free(file_content); + return false; + } + + buff->size = statbuff.st_size; + buff->mem = file_content; + return true; +} + +bool platform__change_to_runtime_dir() +{ + // prepare home + char *home = getenv("HOME"); + int home_len = strlen(home); + + if (home_len == 0 || home_len >= 4096) { + printf("home dir invalid\n"); + return false; + } + + + // prepare subdir + // Note: it might never end with '/', but let's be sure + bool home_ends_with_slash = home[home_len-1] == '/'; + + const char *subdir = home_ends_with_slash ? ".local/share/florilia" : "/.local/share/florilia"; + int subdir_len = strlen(subdir); + + if (home_len + subdir_len >= 4096) { + printf("home/subdir has invalid length\n"); + return false; + } + + + // set run_tree + char run_tree[4096]; + memcpy(run_tree, home, home_len); + strcpy(run_tree + home_len, subdir); + + + // change to run_tree + int changed = chdir(run_tree); + if (changed == -1) { + perror("chdir"); + return false; + } + + return true; +} diff --git a/src/graveyard/lin_glx_modern.c b/src/graveyard/lin_glx_modern.c new file mode 100644 index 0000000..853e3c7 --- /dev/null +++ b/src/graveyard/lin_glx_modern.c @@ -0,0 +1,243 @@ + +static bool g_glx_context_error_occured = false; + +static int glx_context_error_handler(Display *display, XErrorEvent *event) +{ + printf("glx_context_error_handler received error\n"); + g_glx_context_error_occured = true; + return 0; +} + +// Helper to check for extension string presence. Copied from: +// http://www.opengl.org/resources/features/OGLextensions/ +static bool gl_extension_supported(const char *extList, const char *extension) +{ + const char *start; + const char *where, *terminator; + + // Extension names should not have spaces. + where = strchr(extension, ' '); + if (where || *extension == '\0') + return false; + + for (start=extList;;) + { + where = strstr(start, extension); + if (!where) + break; + + terminator = where + strlen(extension); + + if (where == start || *(where - 1) == ' ') + if (*terminator == ' ' || *terminator == '\0') + return true; + + start = terminator; + } + + return false; +} + +static GLXContext create_current_glx_context(Display *display, Window window, GLXFBConfig fbc) +{ + // get glXCreateContextAttribsARB + const char *glx_extensions = glXQueryExtensionsString(display, DefaultScreen( display)); + + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB"); + + if (!gl_extension_supported(glx_extensions, "GLX_ARB_create_context") || + !glXCreateContextAttribsARB) + { + printf("glXCreateContextAttribsARB() not found\n"); + return 0; + } + + // Install an X error handler so the application won't exit if GL 3.0 + // context allocation fails. + // + // Note this error handler is global. All display connections in all threads + // of a process use the same error handler, so be sure to guard against other + // threads issuing X commands while this code is running. + g_glx_context_error_occured = false; + int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&glx_context_error_handler); + + // create glx context + GLXContext glx_context = 0; + int context_attribs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | GLX_CONTEXT_DEBUG_BIT_ARB, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }; + + glx_context = glXCreateContextAttribsARB(display, fbc, 0, True, context_attribs); + + // check for errors + XSync(display, False); + if (g_glx_context_error_occured || !glx_context) + { + printf("failed to create glx context\n"); + return 0; + } + XSetErrorHandler(oldHandler); + + glXMakeCurrent(display, window, glx_context); + return glx_context; +} + +// Note: special case when debugging +// stepping over glXChooseFBConfig or glXGetFBConfigs cause +// _dl_catch_exception in libc +// stepping more leads to +// ?? () from /usr/lib/libnvidia-glcore.so.510.68.02 +// +// Originally I used glXChooseFBConfig, then tried to fix it with glXGetFBConfigs +// and now I leave it at that for the time being +// +// You can still debug by setting breakpoint later and continuing (c) until +// that breakpoint is hit +static bool get_framebuffer_config(Display *display, GLXFBConfig *config) +{ + int screen = XDefaultScreen(display); + + int fbcs_count; + GLXFBConfig *fbcs = glXGetFBConfigs(display, screen, &fbcs_count); + if (!fbcs) + { + printf("no framebuffer configs received\n"); + return 0; + } + + int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; + for (int i = 0; i < fbcs_count; i++) + { + int fbc_attribs[11]; + glXGetFBConfigAttrib(display, fbcs[i], GLX_X_RENDERABLE, &fbc_attribs[0]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_DRAWABLE_TYPE, &fbc_attribs[1]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_RENDER_TYPE, &fbc_attribs[2]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_X_VISUAL_TYPE, &fbc_attribs[3]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_RED_SIZE, &fbc_attribs[4]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_GREEN_SIZE, &fbc_attribs[5]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_BLUE_SIZE, &fbc_attribs[6]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_ALPHA_SIZE, &fbc_attribs[7]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_DEPTH_SIZE, &fbc_attribs[8]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_STENCIL_SIZE, &fbc_attribs[9]); + glXGetFBConfigAttrib(display, fbcs[i], GLX_DOUBLEBUFFER, &fbc_attribs[10]); + + if (fbc_attribs[0] == True && + fbc_attribs[1] & GLX_WINDOW_BIT && + fbc_attribs[2] & GLX_RGBA_BIT && + fbc_attribs[3] == GLX_TRUE_COLOR && + fbc_attribs[4] == 8 && + fbc_attribs[5] == 8 && + fbc_attribs[6] == 8 && + fbc_attribs[7] == 8 && + fbc_attribs[8] == 24 && + fbc_attribs[9] == 8 && + fbc_attribs[10] == True) + { + XVisualInfo *visual_info = glXGetVisualFromFBConfig(display, fbcs[i]); + if (visual_info) + { + int samp_buf, samples; + glXGetFBConfigAttrib(display, fbcs[i], GLX_SAMPLE_BUFFERS, &samp_buf); + glXGetFBConfigAttrib(display, fbcs[i], GLX_SAMPLES , &samples); + + if (best_fbc < 0 || (samp_buf && samples) > best_num_samp) + { + best_fbc = i; + best_num_samp = samples; + } + if (worst_fbc < 0 || !samp_buf || samples < worst_num_samp) + { + worst_fbc = i; + worst_num_samp = samples; + } + } + XFree(visual_info); + } + } + + if (best_fbc == -1) + { + return false; + } + + *config = fbcs[best_fbc]; + XFree(fbcs); + + return true; +} + +struct Platform_Window* platform_create_window(const char *name, int width, int height) +{ + Display *display = XOpenDisplay(0); + if (!display) + { + printf("XOpenDisplay(0) failed\n"); + return 0; + } + + Window root_window = XDefaultRootWindow(display); + if (!root_window) + { + printf("XDefaultRootWindow(display) failed\n"); + XCloseDisplay(display); + return 0; + } + + // glx version 1.3 required (for framebuffer configs and modern context creation) + int glx_major, glx_minor; + if (!glXQueryVersion(display, &glx_major, &glx_minor) || + (glx_major == 1 && glx_minor < 3) || + (glx_major < 1)) + { + printf("invalid glx version\n"); + return 0; + } + + GLXFBConfig fbc; + if (!get_framebuffer_config(display, &fbc)) + { + printf("no framebuffer config found\n"); + return 0; + } + + // set window attributes + XVisualInfo *visual_info = glXGetVisualFromFBConfig(display, fbc); + Colormap colormap = XCreateColormap(display, root_window, visual_info->visual, AllocNone); + long event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask; + int attribute_mask = CWEventMask | CWColormap; + + XSetWindowAttributes attributes = {}; + attributes.colormap = colormap; + attributes.event_mask = event_mask; + + // create window + Window window = XCreateWindow(display, root_window, 0, 0, width, height, 0, visual_info->depth, InputOutput, visual_info->visual, attribute_mask, &attributes); + XFree(visual_info); + XStoreName(display, window, name); + XMapWindow(display, window); + + GLXContext glx_context = create_current_glx_context(display, window, fbc); + if (!glx_context) + { + return 0; + } + + // create platform window + struct Platform_Window *platform_window = (struct Platform_Window*)malloc(sizeof(struct Platform_Window)); + if (!platform_window) + { + printf("malloc failed\n"); + XCloseDisplay(display); + return 0; + } + + platform_window->display = display; + platform_window->window = window; + + return platform_window; +} diff --git a/src/graveyard/linux_net_stream.c b/src/graveyard/linux_net_stream.c new file mode 100644 index 0000000..f08cdc5 --- /dev/null +++ b/src/graveyard/linux_net_stream.c @@ -0,0 +1,192 @@ +#include <basic/basic.h> +#include <os/os.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + + +typedef struct { + int fd; +} OSNetStream; + + +internal_var u32 s_max_stream_count; +internal_var OSNetStream *s_streams; + +internal_var u32 s_free_id_count; +internal_var u32 *s_free_ids; + + + +internal_fn void +os_net_stream_free(u32 stream_id) +{ + s_free_ids[s_free_id_count] = stream_id; + s_free_id_count += 1; +} + +internal_fn u32 +os_net_stream_alloc() +{ + if (s_free_id_count == 0) { + return OS_NET_STREAM_ID_INVALID; + } + + u32 id = s_free_ids[s_free_id_count-1]; + s_free_id_count -= 1; + + return id; +} + + + +b32 +os_net_stream_send(u32 stream_id, void *buffer, size_t size) +{ + OSNetStream *stream = &s_streams[stream_id]; + + size_t sent = send(stream->fd, buffer, size, 0); + if (sent == -1) { + printf("send failed\n"); + return false; + } else if (sent < size) { + printf("send only sent %ld/%ld bytes\n", sent, size); + return false; + } + return true; +} + +b32 +os_net_stream_recv(u32 stream_id, void *buffer, size_t size) +{ + OSNetStream *stream = &s_streams[stream_id]; + + ssize_t recvd = recv(stream->fd, buffer, size, 0); + if (unlikely(recvd == -1 || recvd != size)) { + return false; + } + + return true; +} + +int +os_net_stream_get_fd(u32 stream_id) +{ + OSNetStream *stream = &s_streams[stream_id]; + return stream->fd; +} + +void +os_net_stream_close(u32 stream_id) +{ + OSNetStream *stream = &s_streams[stream_id]; + close(stream->fd); +} + +u32 +os_net_stream_accept(u32 listener_id) +{ + int fd; + struct sockaddr_in addr; + socklen_t addr_size = sizeof(addr); + + OSNetStream *listener = &s_streams[listener_id]; + fd = accept(listener->fd, (struct sockaddr*)&addr, &addr_size); + if (fd == -1) { + printf("accept failed\n"); + return 0; + } + + u32 stream_id = os_net_stream_alloc(); + OSNetStream *stream = &s_streams[stream_id]; + stream->fd = fd; + return stream_id; +} + +u32 +os_net_stream_listen(u16 port) +{ + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket()"); + return 0; + } + + int enable_reuse = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable_reuse, sizeof(int)) < 0) { + perror("setsockopt(SO_REUSEADDR)"); + close(fd); + return 0; + } + + struct sockaddr_in local_addr; + local_addr.sin_family = AF_INET; + local_addr.sin_port = htons(port); + local_addr.sin_addr.s_addr = INADDR_ANY; + if (bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) { + perror("bind()"); + close(fd); + return 0; + } + + int backlog = 128; + if (listen(fd, backlog) == -1) { + perror("listen()"); + close(fd); + return 0; + } + + u32 listener_id = os_net_stream_alloc(); + OSNetStream *stream = &s_streams[listener_id]; + stream->fd = fd; + + return listener_id; +} + +u32 +os_net_stream_connect(char *address, u16 port) +{ + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + printf("cant open socket\n"); + return 0; + } + + // note: connect binds a local address automatically + struct sockaddr_in target_addr; + memset(&target_addr, 0, sizeof(target_addr)); + target_addr.sin_family = AF_INET; + target_addr.sin_port = htons(1338); + target_addr.sin_addr.s_addr = inet_addr(address); + if (connect(fd, (struct sockaddr*)&target_addr, sizeof(target_addr)) == -1) { + printf("connect failed\n"); + close(fd); + return 0; + } + + u32 stream_id = os_net_stream_alloc(); + OSNetStream *stream = &s_streams[stream_id]; + stream->fd = fd; + + return stream_id; +} + +void +os_net_streams_init(MemArena *arena, size_t max_stream_count) +{ + s_max_stream_count = max_stream_count; + s_streams = mem_arena_push(arena, max_stream_count * sizeof(OSNetStream)); + + s_free_id_count = max_stream_count; + s_free_ids = mem_arena_push(arena, max_stream_count * sizeof(u32)); + for (size_t i = 0; i < max_stream_count; i++) { + s_free_ids[i] = i; + } +} + diff --git a/src/graveyard/win32/Win32WindowService.cpp b/src/graveyard/win32/Win32WindowService.cpp new file mode 100644 index 0000000..80d17c0 --- /dev/null +++ b/src/graveyard/win32/Win32WindowService.cpp @@ -0,0 +1,375 @@ +#include <stdio.h> + +static DWORD g_main_thread_id; +static PIXELFORMATDESCRIPTOR g_pfd; + +internal LRESULT +win32__window_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) +{ + LRESULT result = 0; + switch (message) + { + case WM_CLOSE: + case WM_QUIT: + case WM_CHAR: + case WM_SIZE: + { + PostThreadMessage(g_main_thread_id, message, w_param, l_param); + } + break; + + case WM_KEYDOWN: + { + if (w_param >= VK_LEFT && w_param <= VK_DOWN) + { + PostThreadMessage(g_main_thread_id, message, w_param, l_param); + } + else + { + // let windows turn this into a WM_CHAR + result = DefWindowProcA(window, message, w_param, l_param); + } + } + break; + + default: + { + result = DefWindowProcA(window, message, w_param, l_param); + } + break; + } + + return result; +} + +internal HWND +win32__create_window(const char *name, int width, int height) +{ + const char *classname = "win32_window_class"; + + WNDCLASSEX window_class = {}; + window_class.style = CS_OWNDC; + window_class.cbSize = sizeof(window_class); + window_class.lpfnWndProc = &win32__window_proc; + window_class.hInstance = GetModuleHandle(NULL); + window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); + window_class.hCursor = LoadCursor(NULL, IDC_ARROW); + window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + window_class.lpszClassName = classname; + if (RegisterClassExA(&window_class) == 0) + { + printf("RegisterClassEx() failed\n"); + return 0; + } + + HWND window = CreateWindowExA(0, + classname, + name, + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + width, + height, + 0, + 0, + window_class.hInstance, + 0); + if (!window) + { + printf("CreateWindowEx() failed\n"); + } + + return window; +} + +internal void +win32__destroy_window(HWND window) +{ + DestroyWindow(window); +} + +internal LRESULT +win32__service_window_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) +{ + LRESULT result = 0; + switch (message) + { + case Win32WindowService::CREATE_WINDOW: + { + Win32WindowSettings *settings = (Win32WindowSettings*)w_param; + + HWND handle = win32__create_window(settings->name, settings->width, settings->height); + result = (LRESULT)handle; + } + break; + + case Win32WindowService::DESTROY_WINDOW: + { + win32__destroy_window(window); + } + break; + + default: + { + result = DefWindowProc(window, message, w_param, l_param); + } + break; + } + return result; +} + +HWND +win32__create_service_window() +{ + PIXELFORMATDESCRIPTOR *pfd = &g_pfd; + memset(pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + pfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd->nVersion = 1; + pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; + pfd->iPixelType = PFD_TYPE_RGBA; + pfd->cColorBits = 32; + pfd->cDepthBits = 24; + pfd->cStencilBits = 8; + pfd->iLayerType = PFD_MAIN_PLANE; + + WNDCLASSEX swc = {}; + swc.style = CS_OWNDC; + swc.cbSize = sizeof(swc); + swc.lpfnWndProc = &win32__service_window_proc; + swc.hInstance = GetModuleHandle(NULL); + swc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + swc.hCursor = LoadCursor(NULL, IDC_ARROW); + swc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + swc.lpszClassName = "win32_service_window_class"; + if (RegisterClassEx(&swc) == 0) + { + printf("RegisterClassEx() failed\n"); + return 0; + } + + const char *name = "win32_service_window"; + HWND handle = CreateWindowEx(0, + swc.lpszClassName, + name, + 0, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + 0, + 0, + swc.hInstance, + 0); + if (!handle) + { + printf("CreateWindowEx() for service window failed\n"); + return 0; + } + + HDC dc = GetDC(handle); + if (!dc) + { + printf("GetDC() for service window failed\n"); + DestroyWindow(handle); + return 0; + } + + int pixel_format = ChoosePixelFormat(dc, &g_pfd); + if (pixel_format == 0) + { + printf("ChoosePixelFormat() for service window failed\n"); + DestroyWindow(handle); + return 0; + } + + BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &g_pfd); + if (pixel_format_set == FALSE) + { + printf("SetPixelFormat() for service window failed\n"); + DestroyWindow(handle); + return 0; + } + + return handle; +} + +DWORD WINAPI +win32__window_service_thread(LPVOID data) +{ + Win32WindowService *window_service = (Win32WindowService*)data; + + // create service window and report back to main thread + HWND service_window = win32__create_service_window(); + window_service->m_ServiceWindow = service_window; + if (!service_window) + { + PostThreadMessage(g_main_thread_id, Win32WindowService::SERVICE_WINDOW_NOT_CREATED, 0, 0); + return 0; + } + PostThreadMessage(g_main_thread_id, Win32WindowService::SERVICE_WINDOW_CREATED, 0, 0); + + // get events for all windows, redirect to service window proc, let it report back + for (;;) + { + MSG message; + BOOL recvd = GetMessageA(&message, 0, 0, 0); + if (recvd == -1) + { + printf("GetMessage failed\n"); + return 0; + } + + TranslateMessage(&message); + DispatchMessage(&message); + } +} + +bool +Win32WindowService::Init() +{ + DWORD main_thread_id = GetCurrentThreadId(); + g_main_thread_id = main_thread_id; + + DWORD tid; + HANDLE thread = CreateThread(0, 0, win32__window_service_thread, this, 0, &tid); + if (!thread) + { + printf("CreatThread() when starting window manager failed\n"); + return false; + } + + // wait until service window is ready + for (;;) + { + MSG message; + GetMessageA(&message, 0, 0, 0); + + if (message.message == Win32WindowService::SERVICE_WINDOW_CREATED) + return true; + else if (message.message == Win32WindowService::SERVICE_WINDOW_NOT_CREATED) + return false; + else assert(0); + } +} + +Win32Window * +Win32WindowService::CreateWin32Window(const char *name, int width, int height) +{ + static int counter = 0; + assert(counter++ == 0); + + // let the service (other thread) create the window + Win32WindowSettings settings = {}; + settings.name = name; + settings.width = width; + settings.height = height; + + HWND handle = (HWND)SendMessage(m_ServiceWindow, Win32WindowService::CREATE_WINDOW, (WPARAM)&settings, 0); + if (!handle) return 0; + + + // do remaining initialization + HDC dc = GetDC(handle); + if (!dc) + { + printf("GetDC failed\n"); + return 0; + } + + PIXELFORMATDESCRIPTOR *pfd = &g_pfd; + int pixel_format = ChoosePixelFormat(dc, pfd); + if (pixel_format == 0) + { + printf("ChoosePixelFormat failed\n"); + return false; + } + + BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &g_pfd); + if (pixel_format_set == FALSE) + { + printf("SetPixelFormat() failed\n"); + return false; + } + + Win32Window *window = new Win32Window(handle, dc); + if (!window->RecreateOffscreenBuffer(width, height)) + { + delete window; + window = 0; + } + return window; +} + +void +Win32WindowService::DestroyWin32Window(Win32Window *window) +{ + SendMessage(m_ServiceWindow, Win32WindowService::DESTROY_WINDOW, (WPARAM)window, 0); + delete window; +} + +i32 +Win32WindowService::GetWindowEvents(Win32Window *window, Sys_Event *events, i32 max_event_count) +{ + i32 event_count = 0; + + // This receives messages for all windows, so we can only have 1 window atm. + MSG msg; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) && event_count < max_event_count) + { + Sys_Event *event = events + event_count; + switch (msg.message) + { +#define ADD_KEY_EVENT(keycode) \ + event->type = SYS_EVENT_KEY; \ + event->key.c = (char)keycode; \ + event_count += 1; + case WM_CHAR: + { + char keycode = (char)msg.wParam; + bool is_down = (msg.lParam & (1<<31)) == 0; + if (is_down) + { + ADD_KEY_EVENT(keycode); + } + } + break; + + case WM_KEYDOWN: + { + if (msg.wParam == VK_LEFT) {ADD_KEY_EVENT(SYS_KEY_LEFT)} + else if (msg.wParam == VK_UP) {ADD_KEY_EVENT(SYS_KEY_UP)} + else if (msg.wParam == VK_RIGHT) {ADD_KEY_EVENT(SYS_KEY_RIGHT)} + else if (msg.wParam == VK_DOWN) {ADD_KEY_EVENT(SYS_KEY_DOWN)} + else if (msg.wParam == VK_TAB) {ADD_KEY_EVENT('\t')} + else if (msg.wParam == VK_RETURN){ADD_KEY_EVENT('\r')} + else {} + } + break; +#undef ADD_KEY_EVENT + + case WM_SIZE: + { + i32 width = (i32)LOWORD(msg.lParam); + i32 height = (i32)HIWORD(msg.lParam); + window->RecreateOffscreenBuffer(width, height); + } + break; + + case WM_CLOSE: + case WM_QUIT: + { + return -1; + } + break; + + + default: + { + printf("unhandled window event %d\n", msg.message); + } + } + } + + return event_count; +} + diff --git a/src/graveyard/win32/Win32WindowService.h b/src/graveyard/win32/Win32WindowService.h new file mode 100644 index 0000000..a02ef2b --- /dev/null +++ b/src/graveyard/win32/Win32WindowService.h @@ -0,0 +1,33 @@ +struct Win32WindowSettings +{ + const char *name; + int width; + int height; +}; + +class Win32WindowService +{ +public: + bool Init(); + + Win32Window *CreateWin32Window(const char *name, int width, int height); + void DestroyWin32Window(Win32Window *window); + i32 GetWindowEvents(Win32Window *window, Sys_Event *events, i32 max_event_count); + void ShowOffscreenBuffer(Win32Window *window); + + enum + { + SERVICE_WINDOW_CREATED = (WM_USER + 0), + SERVICE_WINDOW_NOT_CREATED = (WM_USER + 1), + CREATE_WINDOW = (WM_USER + 2), + DESTROY_WINDOW = (WM_USER + 3), + WINDOW_CREATED = (WM_USER + 4), + WINDOW_DESTROYED = (WM_USER + 5) + }; + +private: + void RecreateOffscreenBuffer(Sys_Offscreen_Buffer *buff, i32 width, i32 height); + +public: + HWND m_ServiceWindow; +}; diff --git a/src/graveyard/win32/win32_florilia.c b/src/graveyard/win32/win32_florilia.c new file mode 100644 index 0000000..0c2b807 --- /dev/null +++ b/src/graveyard/win32/win32_florilia.c @@ -0,0 +1,111 @@ +// Note: This is a minimal port to win32, the main target is linux.
+
+#include "../florilia_platform.h"
+#include <windows.h>
+
+
+#include <stdio.h>
+
+typedef struct {
+ BITMAPINFO bitmap_info;
+ i32 width;
+ i32 height;
+ u32 *pixels;
+} Win32_Offscreen_Buffer;
+
+typedef struct {
+ HWND window;
+ HDC dc;
+ Win32_Offscreen_Buffer offscreen_buffer;
+} Win32_Window;
+
+typedef struct {
+ const char *name;
+ int width;
+ int height;
+} Win32_Window_Settings;
+
+#include "win32_window.c"
+#include "win32_net.c"
+
+internal
+PLATFORM_GET_TIME(win32_get_time)
+{
+ florilia_time->seconds = 0;
+ florilia_time->nanoseconds = 0;
+#if 0
+ LARGE_INTEGER frequency;
+ if (QueryPerformanceFrequency(&frequency) == FALSE)
+ {
+ printf("frequency.QuadPart = %lld\n", frequency.QuadPart);
+ }
+
+ LARGE_INTEGER perf_counter;
+ if (QueryPerformanceCounter(&perf_counter) == FALSE)
+ {
+ printf("perf_counter.QuadPart = %lld\n", perf_counter.QuadPart);
+ }
+#endif
+}
+
+
+internal bool
+win32_init_florilia_memory(Florilia_Memory *florilia_memory, u64 permanent_size)
+{
+ void *storage = VirtualAlloc(0, permanent_size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
+ if (!storage)
+ {
+ printf("VirtualAlloc failed\n");
+ return false;
+ }
+
+ florilia_memory->permanent_storage = storage;
+ florilia_memory->permanent_storage_size = permanent_size;
+ florilia_memory->platform.get_time = win32_get_time;
+ florilia_memory->platform.connect = win32_connect;
+ florilia_memory->platform.disconnect = win32_disconnect;
+ florilia_memory->platform.send = win32_send;
+ florilia_memory->platform.recv = win32_recv;
+ return true;
+}
+
+int WINAPI
+WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line, int cmd_show)
+{
+ Win32_Window window = {};
+
+ if (!win32_init_windowing()) return 0;
+ if (!win32_create_window(&window, "Florilia", 1024, 720)) return 0;
+ if (!win32_init_networking()) return 0;
+
+ Florilia_Memory florilia_memory = {};
+ Florilia_Event events[64];
+
+ if (!win32_init_florilia_memory(&florilia_memory, Megabytes(1))) return 0;
+ florilia_init(&florilia_memory);
+
+ for (;;)
+ {
+ u32 event_count = sizeof(events) / sizeof(events[0]);
+ if (!win32_process_window_events(&window, events, &event_count))
+ {
+ break;
+ }
+
+ Florilia_Offscreen_Buffer offscreen_buffer = {};
+
+ offscreen_buffer.red_shift = 16;
+ offscreen_buffer.green_shift = 8;
+ offscreen_buffer.blue_shift = 0;
+ offscreen_buffer.width = window.offscreen_buffer.width;
+ offscreen_buffer.height = window.offscreen_buffer.height;
+ offscreen_buffer.pixels = window.offscreen_buffer.pixels;
+ Florilia_Sound_Buffer sound_buffer = {};
+
+ florilia_update(&florilia_memory, &offscreen_buffer, &sound_buffer, events, event_count);
+
+ win32_show_offscreen_buffer(&window);
+ }
+
+ return 0;
+}
diff --git a/src/graveyard/win32/win32_fscord.cpp b/src/graveyard/win32/win32_fscord.cpp new file mode 100644 index 0000000..b390e29 --- /dev/null +++ b/src/graveyard/win32/win32_fscord.cpp @@ -0,0 +1,181 @@ +#define WIN32_LEAN_AND_MEAN + +// disable annoying warnings +#pragma warning(disable: 4820) // padding in structs +#pragma warning(disable: 5045) // ??? +#define _WINSOCK_DEPRECATED_NO_WARNINGS // inet_addr + +#include <common/fscord_defs.h> +#include <sys/sys.h> + +#include <windows.h> +#include <winsock2.h> +#include <malloc.h> + +#include "Win32Window.h" +#include "Win32WindowService.h" +#include "Win32Tcp.h" + +typedef struct +{ + Sys_Offscreen_Buffer sys_ob; +} Win32_Offscreen_Buffer; + +typedef struct +{ + HWND handle; + HDC dc; + Win32_Offscreen_Buffer offscreen_buffer; +} Win32_Window; + +typedef struct +{ + HWND service_window; + PIXELFORMATDESCRIPTOR pfd; +} Win32Data; + +static Win32Data g_win32_data; +static Win32WindowService g_win32_window_service; + +#include "Win32Window.cpp" +#include "Win32WindowService.cpp" +#include "Win32Tcp.cpp" + +void * +sys_allocate_memory(size_t size) +{ + LPVOID addr = VirtualAlloc(0, size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); + if (!addr) + { + // GetLastError... + printf("VirtualAlloc failed\n"); + } + return addr; +} + +void +sys_free_memory(void *address, size_t size) +{ + BOOL freed = VirtualFree(address, 0, MEM_RELEASE); + if (!freed) + { + printf("VirtualFree failed\n"); + } +} + +Sys_Time +sys_get_time() +{ + // @Incomplete + Sys_Time time = {}; + return time; +} + +Sys_Window * +sys_create_window(const char *name, i32 width, i32 height) +{ + static int counter = 0; + assert(counter++ == 0); + if (!g_win32_window_service.Init()) + { + return 0; + } + + Win32Window *win32_window = g_win32_window_service.CreateWin32Window(name, width, height); + + Sys_Window *sys_window = (Sys_Window*)win32_window; + return sys_window; +} + +void +sys_destroy_window(Sys_Window *window) +{ + Win32Window *win32_window = (Win32Window*)window; + g_win32_window_service.DestroyWin32Window(win32_window); +} + +i32 +sys_get_window_events(Sys_Window *sys_window, Sys_Event *events, i32 max_event_count) +{ + Win32Window *win32_window = (Win32Window*)sys_window; + i32 event_count = g_win32_window_service.GetWindowEvents(win32_window, events, max_event_count); + return event_count; +} + +Sys_Offscreen_Buffer * +sys_get_offscreen_buffer(Sys_Window *sys_window) +{ + Win32Window *window = (Win32Window*)sys_window; + Sys_Offscreen_Buffer *screen = window->GetOffscreenBuffer(); + return screen; +} + +void +sys_show_offscreen_buffer(Sys_Window *sys_window) +{ + Win32Window *window = (Win32Window*)sys_window; + window->ShowOffscreenBuffer(); +} + +Sys_Sound_Device * +sys_open_sound_device() +{ + return 0; +} + +void +sys_close_sound_device(Sys_Sound_Device *device) +{ +} + +Sys_Sound_Buffer * +sys_get_sound_buffer(Sys_Sound_Device *device) +{ + static Sys_Sound_Buffer buff = {}; + return &buff; +} + +void +sys_play_sound_buffer(Sys_Sound_Device *device) +{ +} + +Sys_Tcp * +sys_connect(const char *address, u16 port) +{ + Win32Tcp *tcp = new Win32Tcp(); + if (tcp->Connect(address, port)) { + return (Sys_Tcp*)tcp; + } else { + return 0; + } +} + +void +sys_disconnect(Sys_Tcp *sys_tcp) +{ + Win32Tcp *win32_tcp = (Win32Tcp*)sys_tcp; + delete win32_tcp; +} + +bool +sys_send(Sys_Tcp *sys_tcp, void *buffer, i64 size) +{ + assert(size <= S32_MAX); + + Win32Tcp *win32_tcp = (Win32Tcp*)sys_tcp; + bool sent = win32_tcp->Send(buffer, (i32)size); + return sent; +} + +i64 +sys_recv(Sys_Tcp *sys_tcp, void *buffer, i64 size) +{ + assert(size <= S32_MAX); + + Win32Tcp *win32_tcp = (Win32Tcp*)sys_tcp; + int recvd = win32_tcp->Recv(buffer, (i32)size); + return recvd; +} + + diff --git a/src/graveyard/win32/win32_net.c b/src/graveyard/win32/win32_net.c new file mode 100644 index 0000000..84a9373 --- /dev/null +++ b/src/graveyard/win32/win32_net.c @@ -0,0 +1,79 @@ +DEBUG_PLATFORM_CONNECT(win32_connect)
+{
+ SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sock == INVALID_SOCKET)
+ {
+ int error = WSAGetLastError();
+ printf("socket() failed, error = %d\n", error);
+ return -1;
+ }
+ printf("socket() success\n");
+
+ struct sockaddr_in server_addr;
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(port);
+ server_addr.sin_addr.s_addr = inet_addr(address);
+
+ int connected = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
+ if (connected != 0)
+ {
+ int error = WSAGetLastError();
+ printf("connect() failed, error = %d\n", error);
+ closesocket(sock);
+ return -1;
+ }
+ printf("connect(...) success\n");
+
+ u_long mode = 1;
+ int result = ioctlsocket(sock, FIONBIO, &mode);
+ if (result != NO_ERROR)
+ {
+ int error = WSAGetLastError();
+ printf("ioctlsocket failed, error = %d\n", error);
+ closesocket(sock);
+ return -1;
+ }
+ printf("fcntl() success\n");
+
+ return sock;
+}
+
+DEBUG_PLATFORM_DISCONNECT(win32_disconnect)
+{
+ closesocket(netid);
+}
+
+internal
+DEBUG_PLATFORM_SEND(win32_send)
+{
+ printf("sending...\n");
+ int sent = send(netid, (const char*)buffer, size, 0);
+ printf("sent %d/%u bytes\n", sent, size);
+ return sent;
+}
+
+internal
+DEBUG_PLATFORM_RECV(win32_recv)
+{
+ printf("receving...\n");
+ int recvd = recv(netid, (char*)buffer, size, 0);
+ printf("recvd %d bytes\n", recvd);
+ if (recvd == SOCKET_ERROR)
+ {
+ return -1;
+ }
+ return recvd;
+}
+
+internal b32
+win32_init_networking()
+{
+ static WSADATA wsaData;
+ int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
+ if (iResult != 0) {
+ wprintf(L"WSAStartup failed: %d\n", iResult);
+ return false;
+ }
+ printf("WSAStartup done\n");
+ return true;
+}
diff --git a/src/graveyard/win32/win32_network_stream.cpp b/src/graveyard/win32/win32_network_stream.cpp new file mode 100644 index 0000000..11a180e --- /dev/null +++ b/src/graveyard/win32/win32_network_stream.cpp @@ -0,0 +1,90 @@ +#include <platform/platform.h> +#include <windows.h> +#include <stdlib.h> + +static b32 g_wsa_started; + +struct PlatformNetworkStream { + SOCKET socket; +}; + +PlatformNetworkStream *platform_network_stream_open_connection() { + PlatformNetworkStream *stream = (PlatformNetworkStream*)malloc(sizeof(*stream)); + int err; + + // start wsa + if (!g_wsa_started) { + WSADATA wsa_data; + WORD wsa_version = MAKEWORD(2, 2); + err = WSAStartup(wsa_version, &wsa_data); + if (err) { + printf("WSAStartup error %d\n", err); + return false; + } + g_wsa_started = true; + } + + // open socket + SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == INVALID_SOCKET) { + printf("socket() wsa error: %d\n", WSAGetLastError()); + return false; + } + + // connect + struct sockaddr_in sa = {}; + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = inet_addr(address); + + err = connect(sock, (SOCKADDR*)&sa, sizeof(sa)); + if (err) { + printf("connect() wsa error: %d\n", WSAGetLastError()); + closesocket(sock); + return false; + } + + // make socket non-blocking + u_long io_mode = 1; + err = ioctlsocket(sock, FIONBIO, &io_mode); + if (err) { + printf("ioctlsocket() wsa error: %d\n", WSAGetLastError()); + closesocket(sock); + return false; + } + + m_Socket = sock; + return true; +} + +void platform_network_stream_close(PlatformNetworkStream *stream) { + int err = closesocket(m_Socket); + if (err) { + printf("closesocket() wsa error: %d\n", WSAGetLastError()); + } +} + +bool platform_network_stream_send(PlatformNetworkStream *stream, void *buff, i32 size) { + int sent = send(m_Socket, (const char*)buff, size, 0); + if (sent == SOCKET_ERROR) { + int error_code = WSAGetLastError(); + printf("send() wsa error = %d\n", error_code); + return false; + } + return true; +} + +i64 platform_network_stream_recv(PlatformNetworkStream *stream, void *buff, i64 size) { + int recvd = recv(m_Socket, (char*)buff, size, 0); + if (recvd == SOCKET_ERROR) { + int error_code = WSAGetLastError(); + if (error_code == WSAEWOULDBLOCK) { + return 0; + } else { + printf("recv() wsa error: %d\n", error_code); + return -1; + } + } + return recvd; +} + diff --git a/src/graveyard/win32/win32_window.c b/src/graveyard/win32/win32_window.c new file mode 100644 index 0000000..8a25fed --- /dev/null +++ b/src/graveyard/win32/win32_window.c @@ -0,0 +1,389 @@ +#define WIN32_SERVICE_WINDOW_CREATED (WM_USER + 0)
+#define WIN32_SERVICE_WINDOW_NOT_CREATED (WM_USER + 1)
+#define WIN32_CREATE_WINDOW (WM_USER + 2)
+#define WIN32_DESTROY_WINDOW (WM_USER + 3)
+
+static HWND g_service_window;
+static DWORD g_main_thread_id;
+
+internal void
+init_pfd(PIXELFORMATDESCRIPTOR *pfd)
+{
+ memset(pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
+ pfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
+ pfd->nVersion = 1;
+ pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
+ pfd->iPixelType = PFD_TYPE_RGBA;
+ pfd->cColorBits = 32;
+ pfd->cDepthBits = 24;
+ pfd->cStencilBits = 8;
+ pfd->iLayerType = PFD_MAIN_PLANE;
+}
+
+internal LRESULT
+window_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param)
+{
+ LRESULT result = 0;
+ switch (message)
+ {
+ case WM_CLOSE:
+ {
+ PostThreadMessage(g_main_thread_id, message, (WPARAM)window, l_param);
+ }
+ break;
+
+ case WM_CHAR:
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_QUIT:
+ case WM_SIZE:
+ {
+ PostThreadMessage(g_main_thread_id, message, w_param, l_param);
+ }
+ break;
+
+ default:
+ {
+ result = DefWindowProcA(window, message, w_param, l_param);
+ }
+ break;
+ }
+
+ return result;
+}
+
+internal HWND
+create_window(const char *name, int width, int height)
+{
+ const char *classname = "win32_window_class";
+
+ WNDCLASSEX window_class = {};
+ window_class.style = CS_OWNDC;
+ window_class.cbSize = sizeof(window_class);
+ window_class.lpfnWndProc = &window_proc;
+ window_class.hInstance = GetModuleHandle(NULL);
+ window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
+ window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ window_class.lpszClassName = classname;
+ if (RegisterClassExA(&window_class) == 0)
+ {
+ printf("RegisterClassEx() failed\n");
+ return 0;
+ }
+
+ HWND window = CreateWindowExA(0,
+ classname,
+ name,
+ WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ width,
+ height,
+ 0,
+ 0,
+ window_class.hInstance,
+ 0);
+ if (!window)
+ {
+ printf("CreateWindowEx() failed\n");
+ return 0;
+ }
+ return window;
+}
+
+LRESULT
+win32_service_window_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param)
+{
+ LRESULT result = 0;
+ switch (message)
+ {
+ case WIN32_CREATE_WINDOW:
+ {
+ Win32_Window_Settings *settings = (Win32_Window_Settings*)w_param;
+ return (LRESULT)create_window(settings->name, settings->width, settings->height);
+ }
+ break;
+
+ case WIN32_DESTROY_WINDOW:
+ {
+ DestroyWindow(window);
+ }
+ break;
+
+ default:
+ {
+ result = DefWindowProc(window, message, w_param, l_param);
+ }
+ break;
+ }
+ return result;
+}
+
+internal bool
+create_service_window()
+{
+ WNDCLASSEX service_window_class = {};
+ service_window_class.style = CS_OWNDC;
+ service_window_class.cbSize = sizeof(service_window_class);
+ service_window_class.lpfnWndProc = &win32_service_window_proc;
+ service_window_class.hInstance = GetModuleHandle(NULL);
+ service_window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ service_window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
+ service_window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ service_window_class.lpszClassName = "win32_service_window_class";
+ if (RegisterClassEx(&service_window_class) == 0)
+ {
+ printf("RegisterClassEx() failed\n");
+ return 0;
+ }
+
+ const char *service_window_name = "win32_service_window";
+ HWND service_window = CreateWindowEx(0,
+ service_window_class.lpszClassName,
+ service_window_name,
+ 0,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ 0,
+ 0,
+ service_window_class.hInstance,
+ 0);
+ if (!service_window)
+ {
+ printf("CreateWindowEx() failed\n");
+ return 0;
+ }
+
+ HDC dc = GetDC(service_window);
+ if (!dc)
+ {
+ printf("GetDC() failed\n");
+ return false;
+ }
+
+ PIXELFORMATDESCRIPTOR pfd;
+ init_pfd(&pfd);
+
+ int pixel_format = ChoosePixelFormat(dc, &pfd);
+ if (pixel_format == 0)
+ {
+ printf("ChoosePixelFormat failed\n");
+ return false;
+ }
+
+ BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &pfd);
+ if (pixel_format_set == FALSE)
+ {
+ printf("SetPixelFormat() failed\n");
+ return false;
+ }
+
+ g_service_window = service_window;
+ return true;
+}
+
+DWORD WINAPI win32_service_window_thread(LPVOID lpParameter)
+{
+ if (!create_service_window())
+ {
+ PostThreadMessage(g_main_thread_id, WIN32_SERVICE_WINDOW_NOT_CREATED, 0, 0);
+ return 0;
+ }
+
+ PostThreadMessage(g_main_thread_id, WIN32_SERVICE_WINDOW_CREATED, 0, 0);
+
+ for (;;)
+ {
+ // receive messages for all windows (created by this thread)
+ MSG message;
+ BOOL recvd = GetMessageA(&message, 0, 0, 0);
+ if (recvd == -1)
+ {
+ // handle error
+ printf("GetMessage failed\n");
+ return 0;
+ }
+
+ TranslateMessage(&message);
+ DispatchMessage(&message);
+ }
+}
+
+internal void
+win32_show_offscreen_buffer(Win32_Window *window)
+{
+ Win32_Offscreen_Buffer *buff = &window->offscreen_buffer;
+ StretchDIBits(window->dc,
+ 0, 0, buff->width, buff->height,
+ 0, 0, buff->width, buff->height,
+ buff->pixels,
+ &buff->bitmap_info,
+ DIB_RGB_COLORS,
+ SRCCOPY);
+
+ SwapBuffers(window->dc);
+}
+
+internal b32
+win32_recreate_offscreen_buffer(Win32_Offscreen_Buffer *buff, i32 width, i32 height)
+{
+ i32 bytes_per_pixel = 4;
+ i32 pixels_size = width * height * bytes_per_pixel;
+
+ u32 *pixels = realloc(buff->pixels, pixels_size);
+
+ BITMAPINFO *bitmap_info = &buff->bitmap_info;
+ memset(bitmap_info->bmiColors, 0, sizeof(bitmap_info->bmiColors));
+ bitmap_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmap_info->bmiHeader.biWidth = width;
+ bitmap_info->bmiHeader.biHeight = height;
+ bitmap_info->bmiHeader.biPlanes = 1;
+ bitmap_info->bmiHeader.biBitCount = 32;
+ bitmap_info->bmiHeader.biCompression = BI_RGB;
+ bitmap_info->bmiHeader.biSizeImage = 0;
+ bitmap_info->bmiHeader.biXPelsPerMeter = 0;
+ bitmap_info->bmiHeader.biYPelsPerMeter = 0;
+ bitmap_info->bmiHeader.biClrUsed = 0;
+ bitmap_info->bmiHeader.biClrImportant = 0;
+
+ buff->width = width;
+ buff->height = height;
+ buff->pixels = pixels;
+ return true;
+}
+
+#define ADD_KEY_EVENT(_c) \
+ event->type = FLORILIA_EVENT_KEY; \
+ event->key.c = _c; \
+ *event_count += 1;
+
+internal bool
+win32_process_window_events(Win32_Window *window, Florilia_Event *events, u32 *event_count)
+{
+ u32 event_count_max = *event_count;
+ *event_count = 0;
+
+ MSG message;
+ while (*event_count < event_count_max && PeekMessage(&message, 0, 0, 0, PM_REMOVE))
+ {
+ Florilia_Event *event = events + *event_count;
+
+ switch (message.message)
+ {
+ case WM_SIZE:
+ {
+ UINT width = LOWORD(message.lParam);
+ UINT height = HIWORD(message.lParam);
+ win32_recreate_offscreen_buffer(&window->offscreen_buffer, width, height);
+ }
+ break;
+
+ case WM_CHAR:
+ {
+ if (message.wParam < 0 || message.wParam > 127)
+ break;
+
+ char c = (char)message.wParam;
+ ADD_KEY_EVENT(c);
+ }
+ break;
+
+ case WM_KEYDOWN:
+ {
+ switch (message.wParam)
+ {
+ case VK_LEFT: { ADD_KEY_EVENT(FLORILIA_KEY_LEFT); } break;
+ case VK_RIGHT: { ADD_KEY_EVENT(FLORILIA_KEY_RIGHT); } break;
+ case VK_UP: { ADD_KEY_EVENT(FLORILIA_KEY_UP); } break;
+ case VK_DOWN: { ADD_KEY_EVENT(FLORILIA_KEY_DOWN); } break;
+ case VK_DELETE: { ADD_KEY_EVENT(127 /* in ascii */); } break;
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ case WM_DESTROY:
+ {
+ return false;
+ }
+ break;
+
+ default:
+ {
+ return true;
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+#undef ADD_KEY_EVENT
+
+internal bool
+win32_create_window(Win32_Window *window, const char *name, int width, int height)
+{
+ // SendMessage returns after the request has been processed
+ Win32_Window_Settings settings = {name, width, height};
+ HWND handle = (HWND)SendMessage(g_service_window, WIN32_CREATE_WINDOW, (WPARAM)&settings, 0);
+ if (!handle)
+ return 0;
+
+ // We are back in our thread
+ HDC dc = GetDC(handle);
+ if (!dc)
+ {
+ printf("GetDC failed\n");
+ return 0;
+ }
+
+ PIXELFORMATDESCRIPTOR pfd;
+ init_pfd(&pfd);
+
+ int pixel_format = ChoosePixelFormat(dc, &pfd);
+ if (pixel_format == 0)
+ {
+ printf("ChoosePixelFormat failed\n");
+ return false;
+ }
+
+ BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &pfd);
+ if (pixel_format_set == FALSE)
+ {
+ printf("SetPixelFormat() failed\n");
+ return false;
+ }
+
+ window->window = handle;
+ window->dc = dc;
+ return window;
+}
+
+internal bool
+win32_init_windowing()
+{
+ g_main_thread_id = GetCurrentThreadId();
+
+ DWORD tid;
+ HANDLE thread = CreateThread(0, 0, win32_service_window_thread, 0, 0, &tid);
+ if (!thread)
+ {
+ printf("error: CreateThread(...) failed\n");
+ return false;
+ }
+
+ // wait until service window is ready
+ for (;;)
+ {
+ MSG message;
+ GetMessageA(&message, 0, 0, 0);
+
+ if (message.message == WIN32_SERVICE_WINDOW_CREATED)
+ return true;
+ else
+ return false;
+ }
+}
diff --git a/src/graveyard/win32/win32_window.cpp b/src/graveyard/win32/win32_window.cpp new file mode 100644 index 0000000..6ec0891 --- /dev/null +++ b/src/graveyard/win32/win32_window.cpp @@ -0,0 +1,77 @@ +#include <platform/platform.h> +#include <windows.h> + +struct Win32OffscreenBuffer { + PlatformOffscreenBuffer platform_offscreen_buffer; + BITMAPINFO bitmap_info; +}; + +struct PlatformWindow { + HWND wnd; + HDC dc; + Win32OffscreenBuffer offscreen_buffer; +}; + +Win32Window::Win32Window(HWND handle, HDC dc) +{ + m_Wnd = handle; + m_Dc = dc; + memset((void*)&m_OffscreenBuffer, 0, sizeof(m_OffscreenBuffer)); +} + +bool +Win32Window::RecreateOffscreenBuffer(i32 width, i32 height) +{ + Sys_Offscreen_Buffer *sys_screen = &m_OffscreenBuffer.sys_offscreen_buffer; + + sys_screen->red_shift = 16; + sys_screen->green_shift = 8; + sys_screen->blue_shift = 0; + sys_screen->alpha_shift = 24; + + u32 *new_pixels = (u32*)malloc(sizeof(sys_screen->pixels[0]) * width * height); + if (!new_pixels) + { + return false; + } + free(sys_screen->pixels); + + sys_screen->width = width; + sys_screen->height = height; + sys_screen->pixels = new_pixels; + + + BITMAPINFO *bmi = &m_OffscreenBuffer.bitmap_info; + memset(bmi, 0, sizeof(*bmi)); + bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader); + bmi->bmiHeader.biWidth = width; + bmi->bmiHeader.biHeight = height; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biBitCount = 32; + bmi->bmiHeader.biCompression = BI_RGB; + + return true; +} + +Sys_Offscreen_Buffer * +Win32Window::GetOffscreenBuffer() +{ + Sys_Offscreen_Buffer *screen = &m_OffscreenBuffer.sys_offscreen_buffer; + return screen; +} + +void +Win32Window::ShowOffscreenBuffer() +{ + i32 width = m_OffscreenBuffer.sys_offscreen_buffer.width; + i32 height = m_OffscreenBuffer.sys_offscreen_buffer.height; + u32 *pixels = m_OffscreenBuffer.sys_offscreen_buffer.pixels; + BITMAPINFO *bmi = &m_OffscreenBuffer.bitmap_info; + + StretchDIBits(m_Dc, + 0, 0, width, height, + 0, 0, width, height, + pixels, bmi, DIB_RGB_COLORS, SRCCOPY); + +} + diff --git a/src/graveyard/win32_wgl_modern.c b/src/graveyard/win32_wgl_modern.c new file mode 100644 index 0000000..479dbfe --- /dev/null +++ b/src/graveyard/win32_wgl_modern.c @@ -0,0 +1,206 @@ +internal bool
+create_service_window()
+{
+ WNDCLASSEX service_window_class = {};
+ service_window_class.style = CS_OWNDC;
+ service_window_class.cbSize = sizeof(service_window_class);
+ service_window_class.lpfnWndProc = &win32_service_window_proc;
+ service_window_class.hInstance = GetModuleHandle(NULL);
+ service_window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ service_window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
+ service_window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ service_window_class.lpszClassName = "win32_service_window_class";
+ if (RegisterClassEx(&service_window_class) == 0)
+ {
+ printf("RegisterClassEx() failed\n");
+ return 0;
+ }
+
+ const char *service_window_name = "win32_service_window";
+ HWND service_window = CreateWindowEx(0,
+ service_window_class.lpszClassName,
+ service_window_name,
+ 0,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ 0,
+ 0,
+ service_window_class.hInstance,
+ 0);
+ if (!service_window)
+ {
+ printf("CreateWindowEx() failed\n");
+ return 0;
+ }
+
+ /*
+ * Create fake gl context, so I can create window with modern opengl context.
+ * Doing this with the service window prevents creating another 'fake' window.
+ */
+ HDC dc = GetDC(service_window);
+ if (!dc)
+ {
+ printf("GetDC() failed\n");
+ return false;
+ }
+
+ PIXELFORMATDESCRIPTOR pfd;
+ init_pfd(&pfd);
+
+ int pixel_format = ChoosePixelFormat(dc, &pfd);
+ if (pixel_format == 0)
+ {
+ printf("ChoosePixelFormat failed\n");
+ return false;
+ }
+
+ BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &pfd);
+ if (pixel_format_set == FALSE)
+ {
+ printf("SetPixelFormat() failed\n");
+ return false;
+ }
+
+ HGLRC glrc = wglCreateContext(dc);
+ if (!glrc)
+ {
+ printf("wglCreateContext() failed\n");
+ return false;
+ }
+
+ BOOL made_current = wglMakeCurrent(dc, glrc);
+ if (made_current == FALSE)
+ {
+ printf("wglMakeCurrent() failed\n");
+ return false;
+ }
+
+ // TODO: check if extensions are actually supported
+ // "WGL_ARB_pixel_format"
+ // "WGL_ARB_create_context"
+
+ // TODO: check all return values indicating invalid function from wglGetProcAddress
+ // msdn: 0 https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-wglgetprocaddress
+ // khronos: (void*){0,1,2,3,-1} https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions#Windows_2
+ wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
+ wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
+ if (!wglChoosePixelFormatARB || !wglCreateContextAttribsARB)
+ {
+ printf("wgl functions to create context not received\n");
+ return false;
+ }
+
+ g_service_window = service_window;
+ return true;
+}
+
+Win32_Window* platform_create_window(const char *name, int width, int height)
+{
+ Win32_Window *window = (Win32_Window*)malloc(sizeof(Platform_Window));
+ if (!window)
+ {
+ printf("out of memory to create window\n");
+ return 0;
+ }
+
+ // Note: SendMessage returns when execution is finished, so settings can be on stack
+ Win32_Window_Settings settings = {name, width, height};
+ HWND handle = (HWND)SendMessage(g_service_window, WIN32_CREATE_WINDOW, (WPARAM)&settings, 0);
+ if (!handle)
+ return 0;
+
+ HDC dc = GetDC(handle);
+ if (!dc)
+ {
+ printf("GetDC failed\n");
+ return 0;
+ }
+
+ const int pixel_format_attribs[] =
+ {
+ WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
+ WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
+ WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
+ WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
+ WGL_COLOR_BITS_ARB, 32,
+ WGL_DEPTH_BITS_ARB, 24,
+ WGL_STENCIL_BITS_ARB, 8,
+ 0, // End
+ };
+
+ int pixel_format;
+ UINT cnt_pixel_formats;
+ if (wglChoosePixelFormatARB(dc, pixel_format_attribs, NULL, 1, &pixel_format, &cnt_pixel_formats) == FALSE)
+ {
+ printf("wglChoosePixelFormat return false\n");
+ return 0;
+ }
+
+ PIXELFORMATDESCRIPTOR pfd;
+ init_pfd(&pfd);
+
+ if (SetPixelFormat(dc, pixel_format, &pfd) == FALSE)
+ {
+ printf("SetPixelFormat return false\n");
+ return 0;
+ }
+
+ int context_attribs[] =
+ {
+ WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
+ WGL_CONTEXT_MINOR_VERSION_ARB, 3,
+ WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+ 0
+ };
+
+ HGLRC glrc = wglCreateContextAttribsARB(dc, 0, context_attribs);
+ if (!glrc)
+ {
+ printf("wglCreateContextAttribsARB failed\n");
+ return 0;
+ }
+
+ if (wglMakeCurrent(dc, glrc) == FALSE)
+ {
+ printf("wglMakeCurrent failed\n");
+ return 0;
+ }
+
+ window->window = handle;
+ window->dc = dc;
+ window->glrc = glrc;
+ return window;
+}
+
+bool platform_init_windowing()
+{
+ g_main_thread_id = GetCurrentThreadId();
+ g_opengl_module = LoadLibraryA("opengl32.dll");
+ if (!g_opengl_module)
+ {
+ printf("can't open opengl32.dll\n");
+ return false;
+ }
+
+ DWORD tid;
+ HANDLE thread = CreateThread(0, 0, win32_service_window_thread, 0, 0, &tid);
+ if (!thread)
+ {
+ printf("error: CreateThread(...) failed\n");
+ return false;
+ }
+
+ // wait until service window is ready
+ for (;;)
+ {
+ MSG message;
+ GetMessageA(&message, 0, 0, 0);
+
+ if (message.message == WIN32_SERVICE_WINDOW_CREATED)
+ return true;
+ else
+ return false;
+ }
+}
|