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;
 +    }
 +}
  | 
