summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/licensing.c110
-rw-r--r--src/licensing.h40
-rw-r--r--src/linux/platform.c12
-rw-r--r--src/platform.h447
-rw-r--r--src/windows/platform.c2680
5 files changed, 1690 insertions, 1599 deletions
diff --git a/src/licensing.c b/src/licensing.c
index 834313f..f619970 100644
--- a/src/licensing.c
+++ b/src/licensing.c
@@ -1,36 +1,74 @@
-/*
-* BSD 2-Clause “Simplified” License
-* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
-* All rights reserved.
-*/
-
-#include "external/cJSON.h"
-
-static void* validate_license_thread(void *arg)
-{
- char params[50];
- sprintf(params, "can_run?ti=%s", license_key);
-
- char response[MAX_INPUT_LENGTH];
- if (platform_send_http_request("api.aldrik.org", params, response))
- {
- cJSON *result = cJSON_Parse(response);
- if (!result) return false;
- cJSON *canRun = cJSON_GetObjectItem(result, "canRun");
- license_is_valid = canRun->valueint;
- }
-
- return 0;
-}
-
-void validate_license()
-{
- license_is_valid = true;
-
-#ifdef MODE_DEVELOPER
- return;
-#endif
-
- thread license_thread = thread_start(validate_license_thread, NULL);
- thread_detach(&license_thread);
-}
+/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#include "external/cJSON.h"
+
+static void* validate_license_thread(void *arg)
+{
+ char *mac_address = arg;
+
+ char params[80];
+ sprintf(params, "can_run?ti=%s&addr=%s", license_key, mac_address);
+
+ char response[MAX_INPUT_LENGTH];
+ while (main_window->is_open)
+ {
+ // send activity ping
+ if (platform_send_http_request("api.aldrik.org", params, response))
+ {
+ cJSON *result = cJSON_Parse(response);
+ if (!result) return false;
+ cJSON *response = cJSON_GetObjectItem(result, "response");
+
+ if (response)
+ global_license_status = response->valueint;
+ }
+
+ thread_sleep(5*1000*1000); // 5s
+ }
+
+ mem_free(mac_address);
+ return 0;
+}
+
+void validate_license()
+{
+ char *mac_address_buffer = mem_alloc(30);
+ platform_get_mac_address(mac_address_buffer, 30);
+
+#ifdef MODE_DEVELOPER
+ return;
+#endif
+
+ thread license_thread = thread_start(validate_license_thread, mac_address_buffer);
+ thread_detach(&license_thread);
+}
+
+bool license_check_status()
+{
+ if (global_license_status == LICENSE_STATUS_VALID)
+ {
+ return true;
+ }
+ else if (global_license_status == LICENSE_STATUS_INVALID)
+ {
+ char message[200];
+ sprintf(message, localize("invalid_license"), license_key);
+ platform_show_message(main_window, message, localize("license_error"));
+ main_window->is_open = false;
+ return false;
+ }
+ else if (global_license_status == LICENSE_STATUS_TOO_MANY_USERS)
+ {
+ char message[200];
+ sprintf(message, localize("too_many_users_using_license"), license_key);
+ platform_show_message(main_window, message, localize("license_error"));
+ main_window->is_open = false;
+ return false;
+ }
+
+ return true;
+} \ No newline at end of file
diff --git a/src/licensing.h b/src/licensing.h
index 5255ffd..471dcd9 100644
--- a/src/licensing.h
+++ b/src/licensing.h
@@ -1,17 +1,25 @@
-/*
-* BSD 2-Clause “Simplified” License
-* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
-* All rights reserved.
-*/
-
-#ifndef INCLUDE_LICENSING
-#define INCLUDE_LICENSING
-
-// NOTE DO NOT TOUCH THIS!
-char license_key[18] = { "[LICENSELOCATION]" };
-// NOTE DO NOT TOUCH THIS!
-
-bool license_is_valid = true;
-void validate_license();
-
+/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_LICENSING
+#define INCLUDE_LICENSING
+
+typedef enum t_license_status
+{
+ LICENSE_STATUS_VALID = 1,
+ LICENSE_STATUS_INVALID = 2,
+ LICENSE_STATUS_TOO_MANY_USERS = 3,
+} license_status;
+
+// NOTE DO NOT TOUCH THIS!
+char license_key[18] = { "[LICENSELOCATION]" };
+// NOTE DO NOT TOUCH THIS!
+
+license_status global_license_status = LICENSE_STATUS_VALID;
+void validate_license();
+bool license_check_status();
+
#endif \ No newline at end of file
diff --git a/src/linux/platform.c b/src/linux/platform.c
index 8e8f01d..4915138 100644
--- a/src/linux/platform.c
+++ b/src/linux/platform.c
@@ -615,9 +615,9 @@ inline void platform_init(int argc, char **argv)
char buf[MAX_INPUT_LENGTH];
get_directory_from_path(buf, binary_path);
string_copyn(binary_path, buf, MAX_INPUT_LENGTH);
-
+
curl = curl_easy_init();
-
+
assets_create();
}
@@ -1613,7 +1613,7 @@ uint write_cb(char *in, uint size, uint nmemb, char *buffer)
bool platform_send_http_request(char *url, char *params, char *response_buffer)
{
string_copyn(response_buffer, "", MAX_INPUT_LENGTH);
-
+
char fullurl[200];
sprintf(fullurl, "https://%s/%s", url, params);
curl_easy_setopt(curl, CURLOPT_URL,fullurl);
@@ -1625,6 +1625,12 @@ bool platform_send_http_request(char *url, char *params, char *response_buffer)
curl_easy_setopt(curl, CURLOPT_WRITEDATA, response_buffer);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) return false;
+
+ return true;
+}
+bool platform_get_mac_address(char *buffer, s32 buf_size)
+{
+ string_copyn(buffer, "", buf_size);
return true;
} \ No newline at end of file
diff --git a/src/platform.h b/src/platform.h
index 5575dcf..35ec81b 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -1,224 +1,225 @@
-/*
-* BSD 2-Clause “Simplified” License
-* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
-* All rights reserved.
-*/
-
-#ifndef INCLUDE_PLATFORM
-#define INCLUDE_PLATFORM
-
-typedef struct t_platform_window platform_window;
-
-////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////
-
-typedef struct t_found_file
-{
- char *matched_filter;
- char *path;
-} found_file;
-
-typedef struct t_file_match
-{
- found_file file;
- s16 file_error;
- s32 file_size;
-
- u32 line_nr;
- s32 word_match_offset;
- s32 word_match_length;
- s32 word_match_offset_x; // highlight render offset
- s32 word_match_width; // highlight render width
- char *line_info; // will be null when no match is found
-} file_match;
-
-typedef struct t_search_result
-{
- array work_queue;
- array files;
- array matches;
- u64 find_duration_us;
- array errors;
- bool show_error_message; // error occured
- bool found_file_matches; // found/finding file matches
- s32 files_searched;
- s32 files_matched;
- s32 search_result_source_dir_len;
- bool match_found; // found text match
- mutex mutex;
- bool walking_file_system;
- bool cancel_search;
- bool done_finding_matches;
- s32 search_id;
- u64 start_time;
- bool done_finding_files;
- memory_bucket mem_bucket;
- bool is_command_line_search;
- bool threads_closed;
-
- char *export_path;
- char *file_filter;
- char *directory_to_search;
- char *text_to_find;
- s32 max_thread_count;
- s32 max_file_size;
- bool is_recursive;
-} search_result;
-
-typedef struct t_find_text_args
-{
- file_match file;
- search_result *search_result_buffer;
-} find_text_args;
-
-////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////
-
-typedef struct t_file_content
-{
- s64 content_length;
- void *content;
- s16 file_error;
-} file_content;
-
-typedef enum t_time_type
-{
- TIME_FULL, // realtime
- TIME_THREAD, // run time for calling thread
- TIME_PROCESS, // run time for calling process
-} time_type;
-
-typedef enum t_time_precision
-{
- TIME_NS, // nanoseconds
- TIME_US, // microseconds
- TIME_MILI_S, // miliseconds
- TIME_S, // seconds
-} time_precision;
-
-typedef struct t_cpu_info
-{
- s32 model;
- char model_name[255];
- float32 frequency;
- u32 cache_size;
- u32 cache_alignment;
-} cpu_info;
-
-typedef enum t_file_dialog_type
-{
- OPEN_FILE,
- OPEN_DIRECTORY,
- SAVE_FILE,
-} file_dialog_type;
-
-typedef enum t_file_open_error
-{
- FILE_ERROR_TOO_MANY_OPEN_FILES_PROCESS = 1,
- FILE_ERROR_TOO_MANY_OPEN_FILES_SYSTEM = 2,
- FILE_ERROR_NO_ACCESS = 3,
- FILE_ERROR_NOT_FOUND = 4,
- FILE_ERROR_CONNECTION_ABORTED = 5,
- FILE_ERROR_CONNECTION_REFUSED = 6,
- FILE_ERROR_NETWORK_DOWN = 7,
- FILE_ERROR_REMOTE_IO_ERROR = 8,
- FILE_ERROR_STALE = 9, // NFS server file is removed/renamed
- FILE_ERROR_GENERIC = 10,
-} file_open_error;
-
-struct open_dialog_args
-{
- char *buffer;
- char *file_filter;
- char *start_path;
- char *default_save_file_extension;
- file_dialog_type type;
-};
-
-typedef struct t_list_file_args
-{
- array *list;
- char *start_dir;
- char *pattern;
- bool recursive;
- bool include_directories;
- bool *state;
- bool *is_cancelled;
- memory_bucket *bucket;
-} list_file_args;
-
-typedef enum t_cursor_type
-{
- CURSOR_DEFAULT,
- CURSOR_POINTER,
-} cursor_type;
-
-typedef struct t_vec2
-{
- s32 x;
- s32 y;
-} vec2;
-
-platform_window *main_window = 0;
-platform_window *settings_window = 0;
-
-bool platform_window_is_valid(platform_window *window);
-platform_window platform_open_window(char *name, u16 width, u16 height, u16 max_w, u16 max_h, u16 min_w, u16 min_h);
-void platform_get_focus(platform_window *window);
-bool platform_set_clipboard(platform_window *window, char *buffer);
-bool platform_get_clipboard(platform_window *window, char *buffer);
-void platform_window_set_size(platform_window *window, u16 width, u16 height);
-void platform_window_set_position(platform_window *window, u16 x, u16 y);
-void platform_destroy_window(platform_window *window);
-void platform_handle_events(platform_window *window, mouse_input *mouse, keyboard_input *keyboard);
-void platform_window_swap_buffers(platform_window *window);
-void platform_set_cursor(platform_window *window, cursor_type type);
-void platform_window_set_title(platform_window *window, char *name);
-file_content platform_read_file_content(char *path, const char *mode);
-bool platform_write_file_content(char *path, const char *mode, char *buffer, s32 len);
-void platform_destroy_file_content(file_content *content);
-bool get_active_directory(char *buffer);
-bool set_active_directory(char *path);
-void platform_show_message(platform_window *window, char *message, char *title);
-array get_filters(char *filter);
-void platform_list_files_block(array *list, char *start_dir, array filters, bool recursive, memory_bucket *bucket, bool include_directories, bool *is_cancelled);
-void platform_list_files(array *list, char *start_dir, char *filter, bool recursive, memory_bucket *bucket, bool *is_cancelled, bool *state);
-void platform_open_file_dialog(file_dialog_type type, char *buffer, char *file_filter, char *start_path);
-bool is_platform_in_darkmode();
-void *platform_open_file_dialog_block(void *arg);
-char *platform_get_full_path(char *file);
-void platform_open_url(char *command);
-bool platform_send_http_request(char *url, char *params, char *response_buffer);
-void platform_run_command(char *command);
-void platform_window_make_current(platform_window *window);
-void platform_init(int argc, char **argv);
-void platform_destroy();
-void platform_set_icon(platform_window *window, image *img);
-void platform_autocomplete_path(char *buffer, bool want_dir);
-bool platform_directory_exists(char *path);
-void platform_create_directory(char *path);
-bool platform_file_exists(char *path);
-void platform_show_alert(char *title, char *message);
-char *get_config_save_location(char *buffer);
-char *get_file_extension(char *path);
-void get_name_from_path(char *buffer, char *path);
-void get_directory_from_path(char *buffer, char *path);
-vec2 platform_get_window_size(platform_window *window);
-s32 filter_matches(array *filters, char *string, char **matched_filter);
-void platform_delete_file(char *path);
-
-u64 platform_get_time(time_type time_type, time_precision precision);
-s32 platform_get_memory_size();
-s32 platform_get_cpu_count();
-
-u64 string_to_u64(char *str);
-u32 string_to_u32(char *str);
-u16 string_to_u16(char *str);
-u8 string_to_u8(char *str);
-
-s64 string_to_s64(char *str);
-s32 string_to_s32(char *str);
-s16 string_to_s16(char *str);
-s8 string_to_s8(char *str);
-
+/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_PLATFORM
+#define INCLUDE_PLATFORM
+
+typedef struct t_platform_window platform_window;
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+
+typedef struct t_found_file
+{
+ char *matched_filter;
+ char *path;
+} found_file;
+
+typedef struct t_file_match
+{
+ found_file file;
+ s16 file_error;
+ s32 file_size;
+
+ u32 line_nr;
+ s32 word_match_offset;
+ s32 word_match_length;
+ s32 word_match_offset_x; // highlight render offset
+ s32 word_match_width; // highlight render width
+ char *line_info; // will be null when no match is found
+} file_match;
+
+typedef struct t_search_result
+{
+ array work_queue;
+ array files;
+ array matches;
+ u64 find_duration_us;
+ array errors;
+ bool show_error_message; // error occured
+ bool found_file_matches; // found/finding file matches
+ s32 files_searched;
+ s32 files_matched;
+ s32 search_result_source_dir_len;
+ bool match_found; // found text match
+ mutex mutex;
+ bool walking_file_system;
+ bool cancel_search;
+ bool done_finding_matches;
+ s32 search_id;
+ u64 start_time;
+ bool done_finding_files;
+ memory_bucket mem_bucket;
+ bool is_command_line_search;
+ bool threads_closed;
+
+ char *export_path;
+ char *file_filter;
+ char *directory_to_search;
+ char *text_to_find;
+ s32 max_thread_count;
+ s32 max_file_size;
+ bool is_recursive;
+} search_result;
+
+typedef struct t_find_text_args
+{
+ file_match file;
+ search_result *search_result_buffer;
+} find_text_args;
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+
+typedef struct t_file_content
+{
+ s64 content_length;
+ void *content;
+ s16 file_error;
+} file_content;
+
+typedef enum t_time_type
+{
+ TIME_FULL, // realtime
+ TIME_THREAD, // run time for calling thread
+ TIME_PROCESS, // run time for calling process
+} time_type;
+
+typedef enum t_time_precision
+{
+ TIME_NS, // nanoseconds
+ TIME_US, // microseconds
+ TIME_MILI_S, // miliseconds
+ TIME_S, // seconds
+} time_precision;
+
+typedef struct t_cpu_info
+{
+ s32 model;
+ char model_name[255];
+ float32 frequency;
+ u32 cache_size;
+ u32 cache_alignment;
+} cpu_info;
+
+typedef enum t_file_dialog_type
+{
+ OPEN_FILE,
+ OPEN_DIRECTORY,
+ SAVE_FILE,
+} file_dialog_type;
+
+typedef enum t_file_open_error
+{
+ FILE_ERROR_TOO_MANY_OPEN_FILES_PROCESS = 1,
+ FILE_ERROR_TOO_MANY_OPEN_FILES_SYSTEM = 2,
+ FILE_ERROR_NO_ACCESS = 3,
+ FILE_ERROR_NOT_FOUND = 4,
+ FILE_ERROR_CONNECTION_ABORTED = 5,
+ FILE_ERROR_CONNECTION_REFUSED = 6,
+ FILE_ERROR_NETWORK_DOWN = 7,
+ FILE_ERROR_REMOTE_IO_ERROR = 8,
+ FILE_ERROR_STALE = 9, // NFS server file is removed/renamed
+ FILE_ERROR_GENERIC = 10,
+} file_open_error;
+
+struct open_dialog_args
+{
+ char *buffer;
+ char *file_filter;
+ char *start_path;
+ char *default_save_file_extension;
+ file_dialog_type type;
+};
+
+typedef struct t_list_file_args
+{
+ array *list;
+ char *start_dir;
+ char *pattern;
+ bool recursive;
+ bool include_directories;
+ bool *state;
+ bool *is_cancelled;
+ memory_bucket *bucket;
+} list_file_args;
+
+typedef enum t_cursor_type
+{
+ CURSOR_DEFAULT,
+ CURSOR_POINTER,
+} cursor_type;
+
+typedef struct t_vec2
+{
+ s32 x;
+ s32 y;
+} vec2;
+
+platform_window *main_window = 0;
+platform_window *settings_window = 0;
+
+bool platform_window_is_valid(platform_window *window);
+platform_window platform_open_window(char *name, u16 width, u16 height, u16 max_w, u16 max_h, u16 min_w, u16 min_h);
+void platform_get_focus(platform_window *window);
+bool platform_set_clipboard(platform_window *window, char *buffer);
+bool platform_get_clipboard(platform_window *window, char *buffer);
+void platform_window_set_size(platform_window *window, u16 width, u16 height);
+void platform_window_set_position(platform_window *window, u16 x, u16 y);
+void platform_destroy_window(platform_window *window);
+void platform_handle_events(platform_window *window, mouse_input *mouse, keyboard_input *keyboard);
+void platform_window_swap_buffers(platform_window *window);
+void platform_set_cursor(platform_window *window, cursor_type type);
+void platform_window_set_title(platform_window *window, char *name);
+file_content platform_read_file_content(char *path, const char *mode);
+bool platform_write_file_content(char *path, const char *mode, char *buffer, s32 len);
+void platform_destroy_file_content(file_content *content);
+bool get_active_directory(char *buffer);
+bool set_active_directory(char *path);
+void platform_show_message(platform_window *window, char *message, char *title);
+array get_filters(char *filter);
+void platform_list_files_block(array *list, char *start_dir, array filters, bool recursive, memory_bucket *bucket, bool include_directories, bool *is_cancelled);
+void platform_list_files(array *list, char *start_dir, char *filter, bool recursive, memory_bucket *bucket, bool *is_cancelled, bool *state);
+void platform_open_file_dialog(file_dialog_type type, char *buffer, char *file_filter, char *start_path);
+bool platform_get_mac_address(char *buffer, s32 buf_size);
+bool is_platform_in_darkmode();
+void *platform_open_file_dialog_block(void *arg);
+char *platform_get_full_path(char *file);
+void platform_open_url(char *command);
+bool platform_send_http_request(char *url, char *params, char *response_buffer);
+void platform_run_command(char *command);
+void platform_window_make_current(platform_window *window);
+void platform_init(int argc, char **argv);
+void platform_destroy();
+void platform_set_icon(platform_window *window, image *img);
+void platform_autocomplete_path(char *buffer, bool want_dir);
+bool platform_directory_exists(char *path);
+void platform_create_directory(char *path);
+bool platform_file_exists(char *path);
+void platform_show_alert(char *title, char *message);
+char *get_config_save_location(char *buffer);
+char *get_file_extension(char *path);
+void get_name_from_path(char *buffer, char *path);
+void get_directory_from_path(char *buffer, char *path);
+vec2 platform_get_window_size(platform_window *window);
+s32 filter_matches(array *filters, char *string, char **matched_filter);
+void platform_delete_file(char *path);
+
+u64 platform_get_time(time_type time_type, time_precision precision);
+s32 platform_get_memory_size();
+s32 platform_get_cpu_count();
+
+u64 string_to_u64(char *str);
+u32 string_to_u32(char *str);
+u16 string_to_u16(char *str);
+u8 string_to_u8(char *str);
+
+s64 string_to_s64(char *str);
+s32 string_to_s32(char *str);
+s16 string_to_s16(char *str);
+s8 string_to_s8(char *str);
+
#endif \ No newline at end of file
diff --git a/src/windows/platform.c b/src/windows/platform.c
index 2172fd5..246e50d 100644
--- a/src/windows/platform.c
+++ b/src/windows/platform.c
@@ -1,1322 +1,1360 @@
-/*
-* BSD 2-Clause “Simplified” License
-* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
-* All rights reserved.
-*/
-
-#include <wininet.h>
-#include <locale.h>
-#include <windows.h>
-#include <GL/gl.h>
-#include <stdbool.h>
-#include <sysinfoapi.h>
-#include <wingdi.h>
-#include <errno.h>
-#include <shlwapi.h>
-#include <objbase.h>
-#include <shellapi.h>
-#include <gdiplus.h>
-#include <shlobj.h>
-#include "../external/LooplessSizeMove.c"
-
-struct t_platform_window
-{
- HWND window_handle;
- HDC hdc;
- HGLRC gl_context;
- WNDCLASS window_class;
-
- s32 min_width;
- s32 min_height;
- s32 max_width;
- s32 max_height;
-
- // shared window properties
- s32 width;
- s32 height;
- bool is_open;
- bool has_focus;
- cursor_type curr_cursor_type;
- cursor_type next_cursor_type;
-};
-
-extern BOOL GetPhysicallyInstalledSystemMemory(PULONGLONG TotalMemoryInKilobytes);
-
-LARGE_INTEGER perf_frequency;
-static HINSTANCE instance;
-platform_window *current_window_to_handle;
-keyboard_input *current_keyboard_to_handle;
-mouse_input *current_mouse_to_handle;
-
-int cmd_show;
-
-bool platform_get_clipboard(platform_window *window, char *buffer)
-{
- if (!OpenClipboard(NULL))
- return false;
-
- if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
- {
- CloseClipboard();
- return false;
- }
-
- wchar_t* clip_str = GetClipboardData(CF_UNICODETEXT);
- if (!clip_str)
- {
- CloseClipboard();
- return false;
- }
-
- WideCharToMultiByte(CP_UTF8, 0, clip_str, -1, buffer, MAX_INPUT_LENGTH ,0,0);
-
- CloseClipboard();
- return true;
-}
-
-bool platform_set_clipboard(platform_window *window, char *buffer)
-{
- HANDLE clipboard_data;
-
- int char_num = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, 0, 0);
- wchar_t *convstr = mem_alloc(char_num*2);
- int result = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, convstr, char_num);
-
- size_t len = result;
- size_t size = (len+1) * sizeof(wchar_t);
- LPSTR dst;
-
- if (!OpenClipboard(NULL))
- return false;
-
- clipboard_data = GlobalAlloc(GMEM_MOVEABLE, size);
- if (clipboard_data)
- {
- dst = GlobalLock(clipboard_data);
- memmove(dst, convstr, size);
- dst[len*2] = 0;
- GlobalUnlock(clipboard_data);
-
- SetClipboardData(CF_UNICODETEXT, clipboard_data);
- }
- else
- {
- CloseClipboard();
- return false;
- }
-
- CloseClipboard();
- return true;
-}
-
-inline void platform_show_alert(char *title, char *message)
-{
- // not implemented
-}
-
-inline void platform_destroy()
-{
- assets_destroy();
-
-#if defined(MODE_DEVELOPER)
- memory_print_leaks();
-#endif
-}
-
-bool is_platform_in_darkmode()
-{
- char *key = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\\";
-
- HKEY result;
- LSTATUS o = RegOpenKeyExA(HKEY_CURRENT_USER, key, 0, KEY_READ, &result);
-
- if (o == 0)
- {
- BYTE data;
- DWORD len = 4;
- RegQueryValueExA(result, "AppsUseLightTheme", NULL, NULL, &data, &len);
-
- if (data == 1) return true;
- }
-
- return false;
-}
-
-inline void platform_set_cursor(platform_window *window, cursor_type type)
-{
- if (window->next_cursor_type != type)
- {
- window->next_cursor_type = type;
- }
-}
-
-bool platform_directory_exists(char *path)
-{
- return PathFileExistsA(path) == TRUE;
-}
-
-static void create_key_tables()
-{
- keycode_map[0x30] = KEY_0;
- keycode_map[0x31] = KEY_1;
- keycode_map[0x32] = KEY_2;
- keycode_map[0x33] = KEY_3;
- keycode_map[0x34] = KEY_4;
- keycode_map[0x35] = KEY_5;
- keycode_map[0x36] = KEY_6;
- keycode_map[0x37] = KEY_7;
- keycode_map[0x38] = KEY_8;
- keycode_map[0x39] = KEY_9;
- keycode_map[0x41] = KEY_A;
- keycode_map[0x42] = KEY_B;
- keycode_map[0x43] = KEY_C;
- keycode_map[0x44] = KEY_D;
- keycode_map[0x45] = KEY_E;
- keycode_map[0x46] = KEY_F;
- keycode_map[0x47] = KEY_G;
- keycode_map[0x48] = KEY_H;
- keycode_map[0x49] = KEY_I;
- keycode_map[0x4A] = KEY_J;
- keycode_map[0x4B] = KEY_K;
- keycode_map[0x4C] = KEY_L;
- keycode_map[0x4D] = KEY_M;
- keycode_map[0x4E] = KEY_N;
- keycode_map[0x4F] = KEY_O;
- keycode_map[0x50] = KEY_P;
- keycode_map[0x51] = KEY_Q;
- keycode_map[0x52] = KEY_R;
- keycode_map[0x53] = KEY_S;
- keycode_map[0x54] = KEY_T;
- keycode_map[0x55] = KEY_U;
- keycode_map[0x56] = KEY_V;
- keycode_map[0x57] = KEY_W;
- keycode_map[0x58] = KEY_X;
- keycode_map[0x59] = KEY_Y;
- keycode_map[0x5A] = KEY_Z;
-
- keycode_map[VK_OEM_7] = KEY_APOSTROPHE;
- keycode_map[VK_OEM_102] = KEY_BACKSLASH;
- keycode_map[VK_OEM_COMMA] = KEY_COMMA;
- keycode_map[VK_OEM_3] = KEY_GRAVE_ACCENT;
- keycode_map[VK_OEM_4] = KEY_LEFT_BRACKET;
- keycode_map[VK_OEM_MINUS] = KEY_MINUS;
- keycode_map[VK_OEM_PERIOD] = KEY_PERIOD;
-
- keycode_map[VK_BACK] = KEY_BACKSPACE;
- keycode_map[VK_DELETE] = KEY_DELETE;
- keycode_map[VK_END] = KEY_END;
- keycode_map[VK_RETURN] = KEY_ENTER;
- keycode_map[VK_ESCAPE] = KEY_ESCAPE;
- keycode_map[VK_HOME] = KEY_HOME;
- keycode_map[VK_INSERT] = KEY_INSERT;
- keycode_map[VK_MENU] = KEY_MENU;
- keycode_map[VK_NEXT] = KEY_PAGE_DOWN;
- keycode_map[VK_PRIOR] = KEY_PAGE_UP;
- keycode_map[VK_PAUSE] = KEY_PAUSE;
- keycode_map[VK_TAB] = KEY_TAB;
- keycode_map[VK_CAPITAL] = KEY_CAPS_LOCK;
- keycode_map[VK_NUMLOCK] = KEY_NUM_LOCK;
- keycode_map[VK_SCROLL] = KEY_SCROLL_LOCK;
- keycode_map[0x70] = KEY_F1;
- keycode_map[0x71] = KEY_F2;
- keycode_map[0x72] = KEY_F3;
- keycode_map[0x73] = KEY_F4;
- keycode_map[0x74] = KEY_F5;
- keycode_map[0x75] = KEY_F6;
- keycode_map[0x76] = KEY_F7;
- keycode_map[0x77] = KEY_F8;
- keycode_map[0x78] = KEY_F9;
- keycode_map[0x79] = KEY_F10;
- keycode_map[0x7A] = KEY_F11;
- keycode_map[0x7B] = KEY_F12;
- keycode_map[0x7C] = KEY_F13;
- keycode_map[0x7D] = KEY_F14;
- keycode_map[0x7E] = KEY_F15;
- keycode_map[0x7F] = KEY_F16;
- keycode_map[0x80] = KEY_F17;
- keycode_map[0x81] = KEY_F18;
- keycode_map[0x82] = KEY_F19;
- keycode_map[0x83] = KEY_F20;
- keycode_map[0x84] = KEY_F21;
- keycode_map[0x85] = KEY_F22;
- keycode_map[0x86] = KEY_F23;
- keycode_map[0x87] = KEY_F24;
- keycode_map[0x88] = KEY_LEFT_ALT;
- keycode_map[VK_CONTROL] = KEY_LEFT_CONTROL;
- keycode_map[VK_LCONTROL] = KEY_LEFT_CONTROL;
- keycode_map[VK_LSHIFT] = KEY_LEFT_SHIFT;
- keycode_map[VK_LWIN] = KEY_LEFT_SUPER;
- keycode_map[VK_SNAPSHOT] = KEY_PRINT_SCREEN;
- keycode_map[VK_RMENU] = KEY_RIGHT_ALT;
- keycode_map[VK_RCONTROL] = KEY_RIGHT_CONTROL;
- keycode_map[VK_RSHIFT] = KEY_RIGHT_SHIFT;
- keycode_map[VK_RWIN] = KEY_RIGHT_SUPER;
- keycode_map[VK_DOWN] = KEY_DOWN;
- keycode_map[VK_LEFT] = KEY_LEFT;
- keycode_map[VK_RIGHT] = KEY_RIGHT;
- keycode_map[VK_UP] = KEY_UP;
-
- keycode_map[VK_NUMPAD0] = KEY_KP_0;
- keycode_map[VK_NUMPAD1] = KEY_KP_1;
- keycode_map[VK_NUMPAD2] = KEY_KP_2;
- keycode_map[VK_NUMPAD3] = KEY_KP_3;
- keycode_map[VK_NUMPAD4] = KEY_KP_4;
- keycode_map[VK_NUMPAD5] = KEY_KP_5;
- keycode_map[VK_NUMPAD6] = KEY_KP_6;
- keycode_map[VK_NUMPAD7] = KEY_KP_7;
- keycode_map[VK_NUMPAD8] = KEY_KP_8;
- keycode_map[VK_NUMPAD9] = KEY_KP_9;
- keycode_map[VK_ADD] = KEY_KP_ADD;
- keycode_map[VK_DECIMAL] = KEY_KP_DECIMAL;
- keycode_map[VK_DIVIDE] = KEY_KP_DIVIDE;
- keycode_map[VK_MULTIPLY] = KEY_KP_MULTIPLY;
- keycode_map[VK_SUBTRACT] = KEY_KP_SUBTRACT;
-}
-
-bool platform_file_exists(char *path)
-{
- DWORD dwAttrib = GetFileAttributes(path);
-
- return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
- !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
-}
-
-void platform_create_config_directory()
-{
- char tmp[PATH_MAX];
- if(SUCCEEDED(SHGetFolderPathA(0, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, tmp)))
- {
- string_appendn(tmp, CONFIG_DIRECTORY, PATH_MAX);
- }
-
-
- if (!platform_directory_exists(tmp))
- {
- CreateDirectoryA(tmp, NULL);
- }
-}
-
-char* get_config_save_location(char *buffer)
-{
- if(SUCCEEDED(SHGetFolderPathA(0, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, buffer)))
- {
- string_appendn(buffer, CONFIG_DIRECTORY"\\config.txt", MAX_INPUT_LENGTH);
- return buffer;
- }
-
- return 0;
-}
-
-void platform_show_message(platform_window *window, char *message, char *title)
-{
- HWND handle = window ? window->window_handle : NULL;
- MessageBox(handle, message, title, MB_ICONINFORMATION | MB_OK);
-}
-
-LRESULT CALLBACK main_window_callback(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
-{
- LRESULT result = 0;
-
- if (message == WM_SIZE)
- {
- u32 width = lparam&0xFFFF;
- u32 height = lparam>>16;
-
- current_window_to_handle->width = width;
- current_window_to_handle->height = height;
- }
- else if (message == WM_CHAR)
- {
- if (current_keyboard_to_handle->take_input)
- {
- char buf[5];
- memset(buf, 0, 5);
- char *ch = 0;
-
- wchar_t codep = wparam;
-
- WideCharToMultiByte(CP_UTF8, 0, &codep, 1, buf, 5 ,0,0);
-
- if (utf8len(buf) == 1)
- {
- char val = buf[0];
-
- if (current_keyboard_to_handle->input_mode == INPUT_NUMERIC)
- {
- if (!(val >= 48 && val <= 57))
- {
- ch = 0;
- }
- else
- {
- snprintf(buf, 2, "%c", val);
- ch = buf;
- }
- }
- else if (val >= 32 && val <= 126)
- {
- snprintf(buf, 5, "%c", val);
- ch = buf;
- }
- }
-
- if (ch != 0)
- keyboard_handle_input_string(current_window_to_handle, current_keyboard_to_handle, ch);
- }
- }
- else if (message == WM_MOUSELEAVE)
- {
- //current_mouse_to_handle->x = MOUSE_OFFSCREEN;
- //current_mouse_to_handle->y = MOUSE_OFFSCREEN;
- }
- else if (message == WM_KILLFOCUS)
- {
- current_mouse_to_handle->x = MOUSE_OFFSCREEN;
- current_mouse_to_handle->y = MOUSE_OFFSCREEN;
-
- current_window_to_handle->has_focus = false;
- memset(current_keyboard_to_handle->keys, 0, MAX_KEYCODE);
- }
- else if (message == WM_SETFOCUS)
- {
- current_window_to_handle->has_focus = true;
- }
- else if (message == WM_KEYDOWN)
- {
- s32 key = wparam;
-
- current_keyboard_to_handle->keys[keycode_map[key]] = true;
- current_keyboard_to_handle->input_keys[keycode_map[key]] = true;
-
- if (current_keyboard_to_handle->take_input)
- keyboard_handle_input_string(current_window_to_handle,
- current_keyboard_to_handle, 0);
- }
- else if (message == WM_KEYUP)
- {
- s32 key = wparam;
- current_keyboard_to_handle->keys[keycode_map[key]] = false;
- current_keyboard_to_handle->input_keys[keycode_map[key]] = false;
- }
- else if (message == WM_LBUTTONDOWN ||
- message == WM_RBUTTONDOWN ||
- message == WM_MBUTTONDOWN ||
- message == WM_MOUSEWHEEL)
- {
- bool is_left_down = wparam & MK_LBUTTON;
- bool is_right_down = wparam & MK_RBUTTON;
- bool is_middle_down = wparam & MK_MBUTTON;
-
- u64 ev_time = platform_get_time(TIME_FULL, TIME_MILI_S);
- static u64 last_ev_time = 0;
-
- if (message == WM_MOUSEWHEEL)
- {
- s16 scroll_val = wparam>>16;
-
- if (scroll_val < 0)
- current_mouse_to_handle->scroll_state = SCROLL_DOWN;
- else
- current_mouse_to_handle->scroll_state = SCROLL_UP;
- }
-
- if (is_left_down)
- {
- if (ev_time - last_ev_time < 200)
- {
- current_mouse_to_handle->left_state |= MOUSE_DOUBLE_CLICK;
- }
-
- current_mouse_to_handle->left_state |= MOUSE_DOWN;
- current_mouse_to_handle->left_state |= MOUSE_CLICK;
-
- current_mouse_to_handle->total_move_x = 0;
- current_mouse_to_handle->total_move_y = 0;
- last_ev_time = ev_time;
- }
- if (is_right_down)
- {
- current_mouse_to_handle->right_state |= MOUSE_DOWN;
- current_mouse_to_handle->right_state |= MOUSE_CLICK;
- }
- }
- else if (message == WM_LBUTTONUP ||
- message == WM_RBUTTONUP ||
- message == WM_MBUTTONUP)
- {
- bool is_left_up = message == WM_LBUTTONUP;
- bool is_right_up = message == WM_RBUTTONUP;
- bool is_middle_up = message == WM_MBUTTONUP;
-
- if (is_left_up)
- {
- current_mouse_to_handle->left_state = MOUSE_RELEASE;
- }
- if (is_right_up)
- {
- current_mouse_to_handle->right_state = MOUSE_RELEASE;
- }
- }
- else if (message == WM_MOUSEMOVE)
- {
- current_window_to_handle->curr_cursor_type = -999;
-
-#if 0
- s32 x = lparam&0xFFFF;
- s32 y = lparam>>16;
-
- current_mouse_to_handle->x = x;
- current_mouse_to_handle->y = y;
-#endif
-
- TRACKMOUSEEVENT track;
- track.cbSize = sizeof(track);
- track.dwFlags = TME_LEAVE;
- track.hwndTrack = current_window_to_handle->window_handle;
- TrackMouseEvent(&track);
- }
- else if (message == WM_GETMINMAXINFO)
- {
- MINMAXINFO *info = (MINMAXINFO*)lparam;
-
- info->ptMinTrackSize.x = current_window_to_handle->min_width;
- info->ptMinTrackSize.y = current_window_to_handle->min_height;
-
- if (current_window_to_handle->max_width)
- info->ptMaxTrackSize.x = current_window_to_handle->max_width;
- if (current_window_to_handle->max_height)
- info->ptMaxTrackSize.y = current_window_to_handle->max_height;
- }
- else if (message == WM_DESTROY)
- {
- current_window_to_handle->is_open = false;
- }
- else if (message == WM_CLOSE)
- {
- current_window_to_handle->is_open = false;
- }
- else
- {
- result = LSMProc(window, message, wparam, lparam);
- }
-
- return result;
-}
-
-void platform_window_set_title(platform_window *window, char *name)
-{
- SetWindowText(window->window_handle, name);
-}
-
-vec2 platform_get_window_size(platform_window *window)
-{
- RECT rec;
- GetWindowRect(window->window_handle, &rec);
- vec2 res;
- res.x = rec.right - rec.left;
- res.y = rec.bottom - rec.top;
- return res;
-}
-
-void platform_get_focus(platform_window *window)
-{
- SetFocus(window->window_handle);
-}
-
-platform_window platform_open_window(char *name, u16 width, u16 height, u16 max_w, u16 max_h, u16 min_w, u16 min_h)
-{
-#if !defined(MODE_GDBDEBUG) && !defined(MODE_DEVELOPER)
- ShowWindow(GetConsoleWindow(), SW_HIDE);
-#endif
-
- platform_window window;
- window.has_focus = true;
- window.window_handle = 0;
- window.hdc = 0;
- window.width = width;
- window.height = height;
- window.min_width = min_w;
- window.min_height = min_h;
- window.max_width = max_w;
- window.max_height = max_h;
- window.curr_cursor_type = -1;
- window.next_cursor_type = CURSOR_DEFAULT;
-
- current_window_to_handle = &window;
-
- memset(&window.window_class, 0, sizeof(WNDCLASS));
- window.window_class.style = CS_OWNDC;
- window.window_class.lpfnWndProc = main_window_callback;
- window.window_class.hInstance = instance;
- window.window_class.lpszClassName = name;
- window.window_class.hIcon = LoadIcon(NULL, IDI_WINLOGO);
- //window.window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
-
- if (RegisterClass(&window.window_class))
- {
- int style = WS_VISIBLE|WS_SYSMENU|WS_CAPTION|WS_MINIMIZEBOX;
-
- if (min_w != max_w && min_h != max_h)
- style |= WS_SIZEBOX;
- else
- style |= WS_THICKFRAME;
-
- window.window_handle = CreateWindowEx(0,
- window.window_class.lpszClassName,
- name,
- style,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- width,
- height,
- 0,
- 0,
- instance,
- 0);
-
- if (window.window_handle)
- {
- window.hdc = GetDC(window.window_handle);
-
- PIXELFORMATDESCRIPTOR format;
- memset(&format, 0, sizeof(PIXELFORMATDESCRIPTOR));
- format.nSize = sizeof(PIXELFORMATDESCRIPTOR);
- format.nVersion = 1;
- format.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
- format.cColorBits = 24;
- format.cAlphaBits = 8;
- format.iLayerType = PFD_MAIN_PLANE; // PFD_TYPE_RGBA
- s32 suggested_format_index = ChoosePixelFormat(window.hdc, &format);
-
- PIXELFORMATDESCRIPTOR actual_format;
- DescribePixelFormat(window.hdc, suggested_format_index, sizeof(actual_format), &actual_format);
- SetPixelFormat(window.hdc, suggested_format_index, &actual_format);
-
- window.gl_context = wglCreateContext(window.hdc);
-
- static HGLRC share_list = 0;
- if (share_list == 0)
- {
- share_list = window.gl_context;
- }
- else
- {
- wglShareLists(share_list, window.gl_context);
- }
-
- wglMakeCurrent(window.hdc, window.gl_context);
-
- ShowWindow(window.window_handle, cmd_show);
-
- // blending
- glEnable(GL_DEPTH_TEST);
- //glDepthMask(true);
- //glClearDepth(50);
- glDepthFunc(GL_LEQUAL);
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- // setup multisampling
-#if 0
- glEnable(GL_ALPHA_TEST);
- glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
- glEnable(GL_SAMPLE_ALPHA_TO_ONE);
- glEnable(GL_MULTISAMPLE);
- glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
-#endif
-
- // https://stackoverflow.com/questions/5627229/sub-pixel-drawing-with-opengl
- //glHint(GL_POINT_SMOOTH, GL_NICEST);
- //glHint(GL_LINE_SMOOTH, GL_NICEST);
- //glHint(GL_POLYGON_SMOOTH, GL_NICEST);
-
- //glEnable(GL_SMOOTH);
- //glEnable(GL_POINT_SMOOTH);
- //glEnable(GL_LINE_SMOOTH);
- //glEnable(GL_POLYGON_SMOOTH);
- //////////////////
-
- window.is_open = true;
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0, width, height, 0, -1, 1);
-
- //GLint m_viewport[4];
- //glGetIntegerv( GL_VIEWPORT, m_viewport );
- //printf("%d %d %d %d\n", m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]);
-
- glMatrixMode(GL_MODELVIEW);
-
- TRACKMOUSEEVENT track;
- track.cbSize = sizeof(track);
- track.dwFlags = TME_LEAVE;
- track.hwndTrack = window.window_handle;
- TrackMouseEvent(&track);
- }
- else
- {
- platform_show_message(0, "An error occured within Windows, please restart the program.", "Error");
- abort();
- }
- }
- else
- {
- platform_show_message(0, "An error occured within Windows, please restart the program.", "Error");
- abort();
- }
-
- platform_get_focus(&window);
-
- return window;
-}
-
-void platform_window_set_size(platform_window *window, u16 width, u16 height)
-{
- s32 style = GetWindowLong(window->window_handle, GWL_STYLE);
- BOOL menu = FALSE;
-
- RECT rec;
- rec.left = 0;
- rec.top = 0;
- rec.right = width;
- rec.bottom = height;
- AdjustWindowRectEx(&rec, style, menu, 0);
- SetWindowPos(window->window_handle,NULL,rec.left,rec.top,rec.right,rec.bottom,SWP_NOMOVE|SWP_NOZORDER);
-}
-
-void platform_window_set_position(platform_window *window, u16 x, u16 y)
-{
- RECT rec;
- GetWindowRect(window->window_handle, &rec);
- MoveWindow(window->window_handle, x, y, rec.right-rec.left, rec.bottom-rec.top, FALSE);
-}
-
-bool platform_window_is_valid(platform_window *window)
-{
- return window->hdc && window->window_handle;
-}
-
-void platform_destroy_window(platform_window *window)
-{
- wglMakeCurrent(NULL, NULL);
- wglDeleteContext(window->gl_context);
-
- ReleaseDC(window->window_handle, window->hdc);
- CloseWindow(window->window_handle);
- DestroyWindow(window->window_handle);
- UnregisterClassA(window->window_class.lpszClassName, instance);
- window->hdc = 0;
- window->window_handle = 0;
-}
-
-void platform_handle_events(platform_window *window, mouse_input *mouse, keyboard_input *keyboard)
-{
- current_window_to_handle = window;
- current_keyboard_to_handle = keyboard;
- current_mouse_to_handle = mouse;
-
- mouse->left_state &= ~MOUSE_CLICK;
- mouse->right_state &= ~MOUSE_CLICK;
- mouse->left_state &= ~MOUSE_DOUBLE_CLICK;
- mouse->right_state &= ~MOUSE_DOUBLE_CLICK;
- mouse->left_state &= ~MOUSE_RELEASE;
- mouse->right_state &= ~MOUSE_RELEASE;
- memset(keyboard->input_keys, 0, MAX_KEYCODE);
- mouse->move_x = 0;
- mouse->move_y = 0;
- mouse->scroll_state = 0;
- keyboard->text_changed = false;
-
- // mouse position (including outside of window)
- current_window_to_handle->has_focus = GetFocus() == current_window_to_handle->window_handle;
-
- if (current_window_to_handle->has_focus)
- {
- if((GetKeyState(VK_LBUTTON) & 0x100) == 0)
- {
- current_mouse_to_handle->left_state = MOUSE_RELEASE;
- }
-
- RECT rec;
- GetWindowRect(window->window_handle, &rec);
- POINT p;
- GetCursorPos(&p);
- mouse->x = p.x - rec.left - GetSystemMetrics(SM_CYSIZEFRAME);
- mouse->y = p.y - rec.top - GetSystemMetrics(SM_CYSIZE) - GetSystemMetrics(SM_CYFRAME);
- //printf("%d %d\n",GetSystemMetrics(SM_CYSIZE), GetSystemMetrics(SM_CYFRAME));
- }
-
- MSG message;
- while(PeekMessageA(&message, window->window_handle, 0, 0, TRUE))
- {
- TranslateMessage(&message);
- SizingCheck(&message);
- DispatchMessage(&message);
- }
-
- glViewport(0, 0, window->width, window->height);
-}
-
-void platform_window_swap_buffers(platform_window *window)
-{
- // set cursor if changed
- if (window->curr_cursor_type != window->next_cursor_type)
- {
- char *cursor_shape = 0;
- switch(window->next_cursor_type)
- {
- case CURSOR_DEFAULT: cursor_shape = IDC_ARROW; break;
- case CURSOR_POINTER: cursor_shape = IDC_HAND; break;
- }
-
- HCURSOR cursor = LoadCursorA(NULL, cursor_shape);
-
- window->curr_cursor_type = window->next_cursor_type;
- SetCursor(cursor);
- }
-
- SwapBuffers(window->hdc);
-}
-
-file_content platform_read_file_content(char *path, const char *mode)
-{
- file_content result;
- result.content = 0;
- result.content_length = 0;
- result.file_error = 0;
-
- FILE *file = fopen(path, mode);
- if (!file)
- {
- if (errno == EMFILE)
- result.file_error = FILE_ERROR_TOO_MANY_OPEN_FILES_PROCESS;
- else if (errno == ENFILE)
- result.file_error = FILE_ERROR_TOO_MANY_OPEN_FILES_SYSTEM;
- else if (errno == EACCES)
- result.file_error = FILE_ERROR_NO_ACCESS;
- else if (errno == EPERM)
- result.file_error = FILE_ERROR_NO_ACCESS;
- else if (errno == ENOENT)
- result.file_error = FILE_ERROR_NOT_FOUND;
- else if (errno == ECONNABORTED)
- result.file_error = FILE_ERROR_CONNECTION_ABORTED;
- else if (errno == ECONNREFUSED)
- result.file_error = FILE_ERROR_CONNECTION_REFUSED;
- else if (errno == ENETDOWN)
- result.file_error = FILE_ERROR_NETWORK_DOWN;
- else
- {
- result.file_error = FILE_ERROR_GENERIC;
- printf("ERROR: %d\n", errno);
- }
-
- goto done_failure;
- }
-
- fseek(file, 0 , SEEK_END);
- int length = ftell(file);
- fseek(file, 0, SEEK_SET);
-
- s32 length_to_alloc = length+1;
-
- result.content = mem_alloc(length_to_alloc);
- if (!result.content) goto done;
-
- memset(result.content, 0, length);
- s32 read_result = fread(result.content, 1, length, file);
- if (read_result == 0 && length != 0)
- {
- mem_free(result.content);
- result.content = 0;
- return result;
- }
-
- result.content_length = read_result;
-
- ((char*)result.content)[length] = 0;
-
- done:
- fclose(file);
- done_failure:
- return result;
-}
-
-void platform_delete_file(char *path)
-{
- remove(path);
-}
-
-bool platform_write_file_content(char *path, const char *mode, char *buffer, s32 len)
-{
- bool result = false;
-
- FILE *file = fopen(path, mode);
-
- if (!file)
- {
- goto done_failure;
- }
- else
- {
- fwrite(buffer, 1, len, file);
- //fprintf(file, buffer);
- }
-
- //done:
- fclose(file);
- done_failure:
- return result;
-}
-
-void platform_destroy_file_content(file_content *content)
-{
- assert(content);
- mem_free(content->content);
-}
-
-bool get_active_directory(char *buffer)
-{
- return GetCurrentDirectory(MAX_INPUT_LENGTH, buffer);
-}
-
-bool set_active_directory(char *path)
-{
- return SetCurrentDirectory(path);
-}
-
-void platform_list_files_block(array *list, char *start_dir, array filters, bool recursive, memory_bucket *bucket, bool include_directories, bool *is_cancelled)
-{
- assert(list);
- s32 len = 0;
- char *matched_filter = 0;
-
- char *subdirname_buf;
- if (bucket)
- subdirname_buf = memory_bucket_reserve(bucket, MAX_INPUT_LENGTH);
- else
- subdirname_buf = mem_alloc(MAX_INPUT_LENGTH);
-
- char *start_dir_fix;
- if (bucket)
- start_dir_fix = memory_bucket_reserve(bucket, MAX_INPUT_LENGTH);
- else
- start_dir_fix = mem_alloc(MAX_INPUT_LENGTH);
- snprintf(start_dir_fix, MAX_INPUT_LENGTH, "%s*", start_dir);
-
- char *start_dir_clean;
- if (bucket)
- start_dir_clean = memory_bucket_reserve(bucket, MAX_INPUT_LENGTH);
- else
- start_dir_clean = mem_alloc(MAX_INPUT_LENGTH);
- string_copyn(start_dir_clean, start_dir, MAX_INPUT_LENGTH);
-
- WIN32_FIND_DATAA file_info;
- HWND handle = FindFirstFileA(start_dir_fix, &file_info);
-
- if (!bucket)
- mem_free(start_dir_fix);
-
- if (handle == INVALID_HANDLE_VALUE)
- {
- return;
- }
-
- do
- {
- if (*is_cancelled) break;
- char *name = file_info.cFileName;
-
- // symbolic link is not allowed..
- if ((file_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
- continue;
-
-
- if ((file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
- {
- if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
- continue;
-
- if (include_directories)
- {
- if ((len = filter_matches(&filters, name,
- &matched_filter)) && len != -1)
- {
- // is file
- char *buf;
- if (bucket)
- buf = memory_bucket_reserve(bucket, MAX_INPUT_LENGTH);
- else
- buf = mem_alloc(MAX_INPUT_LENGTH);
- snprintf(buf, MAX_INPUT_LENGTH, "%s%s",start_dir, name);
-
- found_file f;
- f.path = buf;
-
- if (bucket)
- f.matched_filter= memory_bucket_reserve(bucket, len+1);
- else
- f.matched_filter= mem_alloc(len+1);
-
- string_copyn(f.matched_filter, matched_filter, len+1);
-
- mutex_lock(&list->mutex);
- array_push_size(list, &f, sizeof(found_file));
- mutex_unlock(&list->mutex);
- }
- }
-
- if (recursive)
- {
- string_copyn(subdirname_buf, start_dir_clean, MAX_INPUT_LENGTH);
- string_appendn(subdirname_buf, name, MAX_INPUT_LENGTH);
- string_appendn(subdirname_buf, "\\", MAX_INPUT_LENGTH);
-
- // is directory
- platform_list_files_block(list, subdirname_buf, filters, recursive, bucket, include_directories, is_cancelled);
- }
- }
- else if ((file_info.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ||
- (file_info.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ||
- (file_info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ||
- (file_info.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
- (file_info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ||
- (file_info.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE))
- {
- if ((len = filter_matches(&filters, name,
- &matched_filter)) && len != -1)
- {
- // is file
- char *buf;
- if (bucket)
- buf = memory_bucket_reserve(bucket, MAX_INPUT_LENGTH);
- else
- buf = mem_alloc(MAX_INPUT_LENGTH);
-
- snprintf(buf, MAX_INPUT_LENGTH, "%s%s",start_dir, name);
-
- found_file f;
- f.path = buf;
-
- if (bucket)
- f.matched_filter = memory_bucket_reserve(bucket, len+1);
- else
- f.matched_filter = mem_alloc(len+1);
-
- string_copyn(f.matched_filter, matched_filter, len+1);
-
- mutex_lock(&list->mutex);
- array_push_size(list, &f, sizeof(found_file));
- mutex_unlock(&list->mutex);
- }
- }
- }
- while (FindNextFile(handle, &file_info) != 0);
-
- if (!bucket)
- mem_free(start_dir_clean);
-
- FindClose(handle);
-}
-
-static void* platform_open_file_dialog_implementation(void *data)
-{
- struct open_dialog_args *args = data;
-
- OPENFILENAME info;
- info.lStructSize = sizeof(OPENFILENAME);
- info.hwndOwner = NULL;
- info.hInstance = NULL;
-
- char filter[MAX_INPUT_LENGTH];
- memset(filter, 0, MAX_INPUT_LENGTH);
-
- if (args->file_filter)
- {
- string_copyn(filter, args->file_filter, MAX_INPUT_LENGTH);
- filter[strlen(filter)] = 0;
- filter[strlen(filter)+1] = 0;
- info.lpstrFilter = filter;
- }
- else
- {
- info.lpstrFilter = NULL;
- }
-
- char szFile[MAX_INPUT_LENGTH];
- memset(szFile, 0, MAX_INPUT_LENGTH);
-
- info.lpstrCustomFilter = NULL;
- info.nMaxCustFilter = MAX_INPUT_LENGTH;
- info.nFilterIndex = 0;
- info.lpstrFile = (char*)szFile;
- info.nMaxFile = MAX_INPUT_LENGTH;
-
- info.lpstrDefExt = args->default_save_file_extension;
-
- info.lpstrFileTitle = NULL;
- info.lpstrInitialDir = args->start_path;
- info.lpstrTitle = NULL;
-
- if (args->type == SAVE_FILE)
- {
- info.Flags = OFN_EXTENSIONDIFFERENT | OFN_OVERWRITEPROMPT;
- GetSaveFileNameA(&info);
- string_copyn(args->buffer, info.lpstrFile, MAX_INPUT_LENGTH);
- }
- else if (args->type == OPEN_DIRECTORY)
- {
- BROWSEINFOA inf;
- PIDLIST_ABSOLUTE result = SHBrowseForFolderA(&inf);
- if (!result) return 0;
-
- SHGetPathFromIDListA(result, args->buffer);
- }
- else if (args->type == OPEN_FILE)
- {
- info.Flags = OFN_FILEMUSTEXIST;
- GetOpenFileNameA(&info);
- string_copyn(args->buffer, info.lpstrFile, MAX_INPUT_LENGTH);
- }
-
- return 0;
-}
-
-void *platform_open_file_dialog_block(void *arg)
-{
- platform_open_file_dialog_implementation(arg);
- mem_free(arg);
- return 0;
-}
-
-char *platform_get_full_path(char *file)
-{
- char *buf = mem_alloc(MAX_INPUT_LENGTH);
- if (!GetFullPathNameA(file, MAX_INPUT_LENGTH, buf, NULL))
- {
- buf[0] = 0;
- }
-
- return buf;
-}
-
-void platform_open_url(char *command)
-{
- platform_run_command(command);
-}
-
-void platform_run_command(char *command)
-{
- // might be start instead of open
- ShellExecuteA(NULL, "open", command, NULL, NULL, SW_SHOWDEFAULT);
-}
-
-void platform_window_make_current(platform_window *window)
-{
- wglMakeCurrent(window->hdc, window->gl_context);
-}
-
-void platform_init(int argc, char **argv)
-{
- setlocale(LC_ALL, "en_US.UTF-8");
-
- QueryPerformanceFrequency(&perf_frequency);
- CoInitialize(NULL);
- create_key_tables();
-
- instance = GetModuleHandle(NULL);
- cmd_show = argc;
-
- // get fullpath of the directory the exe is residing in
- binary_path = platform_get_full_path(argv[0]);
-
- platform_create_config_directory();
-
- char buf[MAX_INPUT_LENGTH];
- get_directory_from_path(buf, binary_path);
- string_copyn(binary_path, buf, MAX_INPUT_LENGTH);
-
- assets_create();
-}
-
-void platform_set_icon(platform_window *window, image *img)
-{
- BYTE *bmp;
- s32 data_len = img->width * img->height * 4;
- s32 total_len = data_len + 40 * 4;
-
- bmp = mem_alloc(total_len);
-
- struct {
- int32_t header_size, width, geight;
- int16_t color_plane, bits_per_pixel;
- int32_t compression_mode, img_length, obsolete[4];
- } bmp_header = {40, img->width, img->height * 2, 1, 32, BI_RGB, data_len, {0,0,0,0} };
-
- memcpy(bmp, &bmp_header, 40);
-
- s32 index = 0;
- for (s32 y = img->height-1; y >= 0; y--)
- {
- for (s32 x = 0; x < img->width; x++)
- {
- s32 img_pixel = *(((s32*)img->data+(x+(y*img->width))));
-
- // 0xAABBGGRR
- s32 a = (img_pixel>>24) & 0x000000FF;
- s32 b = (img_pixel>>16) & 0x000000FF;
- s32 g = (img_pixel>> 8) & 0x000000FF;
- s32 r = (img_pixel>> 0) & 0x000000FF;
-
- //s32 c = (r << 24) | (g << 16) | (b << 8) | (a << 0);
- s32 c = (a << 24) | (r << 16) | (g << 8) | (b << 0);
- memcpy(bmp+40+(index*4), &c, 4);
-
- ++index;
- }
- }
-
- HICON icon = CreateIconFromResourceEx(bmp, total_len, TRUE, 0x00030000, img->width, img->height, LR_DEFAULTCOLOR);
-
- SendMessage(window->window_handle, WM_SETICON, ICON_SMALL, (LPARAM)icon);
- SendMessage(window->window_handle, WM_SETICON, ICON_BIG, (LPARAM)icon);
-
- mem_free(bmp);
-
- if (!icon)
- printf("Failed to load icon, error code: %ld.\n", GetLastError());
-}
-
-u64 platform_get_time(time_type time_type, time_precision precision)
-{
- LARGE_INTEGER counter;
- QueryPerformanceCounter(&counter);
-
- double sec = counter.QuadPart / (double)(perf_frequency.QuadPart);
-
- //printf("%I64d %I64d %f\n", counter.QuadPart, perf_frequency.QuadPart, sec);
-
- double val = sec;
-
- if (precision == TIME_NS)
- {
- return val*1000000000;
- }
- if (precision == TIME_US)
- {
- return val*1000000;
- }
- if (precision == TIME_MILI_S)
- {
- return val*1000;
- }
- if (precision == TIME_S)
- {
- return val;
- }
- return val;
-}
-
-s32 platform_get_memory_size()
-{
- u64 result;
- GetPhysicallyInstalledSystemMemory(&result);
- return result;
-}
-
-s32 platform_get_cpu_count()
-{
- SYSTEM_INFO info;
- GetSystemInfo(&info);
-
- return info.dwNumberOfProcessors;
-}
-
-u64 string_to_u64(char *str)
-{
- return (u64)strtoull(str, 0, 10);
-}
-
-u32 string_to_u32(char *str)
-{
- return (u32)strtoul(str, 0, 10);
-}
-
-u16 string_to_u16(char *str)
-{
- return (u16)strtoul(str, 0, 10);
-}
-
-u8 string_to_u8(char *str)
-{
- return (u8)strtoul(str, 0, 10);
-}
-
-s64 string_to_s64(char *str)
-{
- return (s64)strtoull(str, 0, 10);
-}
-
-s32 string_to_s32(char *str)
-{
- return (s32)strtoul(str, 0, 10);
-}
-
-s16 string_to_s16(char *str)
-{
- return (s16)strtoul(str, 0, 10);
-}
-
-s8 string_to_s8(char *str)
-{
- return (s8)strtoul(str, 0, 10);
-}
-
-bool platform_send_http_request(char *url, char *params, char *response_buffer)
-{
- // https://www.unix.com/programming/187337-c-http-get-request-using-sockets.html
-
- bool response = true;
- HINTERNET hIntSession = 0;
- HINTERNET hHttpSession = 0;
- HINTERNET hHttpRequest = 0;
-
- hIntSession = InternetOpen("Text-Search", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
- if (!hIntSession) goto failure;
-
- hHttpSession = InternetConnect(hIntSession, url, 80, 0, 0, INTERNET_SERVICE_HTTP, 0, 0);
- if (!hHttpSession) goto failure;
-
- hHttpRequest = HttpOpenRequest(
- hHttpSession,
- "GET",
- params,
- 0, 0, 0, INTERNET_FLAG_RELOAD, 0);
-
-
- char* szHeaders = "Content-Type: application/json";
- char szReq[1024] = "";
- if(!HttpSendRequest(hHttpRequest, szHeaders, strlen(szHeaders), szReq, strlen(szReq))) {
- goto failure;
- }
-
- DWORD dwRead=0;
- while(InternetReadFile(hHttpRequest, response_buffer, MAX_INPUT_LENGTH-1, &dwRead) && dwRead) {
- response_buffer[dwRead] = 0;
- dwRead=0;
- }
-
- goto done;
-
- failure:
- printf("failure");
- response = false;
-
- done:
- InternetCloseHandle(hHttpRequest);
- InternetCloseHandle(hHttpSession);
- InternetCloseHandle(hIntSession);
-
- return response;
+/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#include <wininet.h>
+#include <locale.h>
+#include <windows.h>
+#include <GL/gl.h>
+#include <stdbool.h>
+#include <sysinfoapi.h>
+#include <wingdi.h>
+#include <errno.h>
+#include <shlwapi.h>
+#include <objbase.h>
+#include <shellapi.h>
+#include <gdiplus.h>
+#include <shlobj.h>
+#include <iphlpapi.h>
+#include "../external/LooplessSizeMove.c"
+
+struct t_platform_window
+{
+ HWND window_handle;
+ HDC hdc;
+ HGLRC gl_context;
+ WNDCLASS window_class;
+
+ s32 min_width;
+ s32 min_height;
+ s32 max_width;
+ s32 max_height;
+
+ // shared window properties
+ s32 width;
+ s32 height;
+ bool is_open;
+ bool has_focus;
+ cursor_type curr_cursor_type;
+ cursor_type next_cursor_type;
+};
+
+extern BOOL GetPhysicallyInstalledSystemMemory(PULONGLONG TotalMemoryInKilobytes);
+
+LARGE_INTEGER perf_frequency;
+static HINSTANCE instance;
+platform_window *current_window_to_handle;
+keyboard_input *current_keyboard_to_handle;
+mouse_input *current_mouse_to_handle;
+
+int cmd_show;
+
+bool platform_get_clipboard(platform_window *window, char *buffer)
+{
+ if (!OpenClipboard(NULL))
+ return false;
+
+ if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
+ {
+ CloseClipboard();
+ return false;
+ }
+
+ wchar_t* clip_str = GetClipboardData(CF_UNICODETEXT);
+ if (!clip_str)
+ {
+ CloseClipboard();
+ return false;
+ }
+
+ WideCharToMultiByte(CP_UTF8, 0, clip_str, -1, buffer, MAX_INPUT_LENGTH ,0,0);
+
+ CloseClipboard();
+ return true;
+}
+
+bool platform_set_clipboard(platform_window *window, char *buffer)
+{
+ HANDLE clipboard_data;
+
+ int char_num = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, 0, 0);
+ wchar_t *convstr = mem_alloc(char_num*2);
+ int result = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, convstr, char_num);
+
+ size_t len = result;
+ size_t size = (len+1) * sizeof(wchar_t);
+ LPSTR dst;
+
+ if (!OpenClipboard(NULL))
+ return false;
+
+ clipboard_data = GlobalAlloc(GMEM_MOVEABLE, size);
+ if (clipboard_data)
+ {
+ dst = GlobalLock(clipboard_data);
+ memmove(dst, convstr, size);
+ dst[len*2] = 0;
+ GlobalUnlock(clipboard_data);
+
+ SetClipboardData(CF_UNICODETEXT, clipboard_data);
+ }
+ else
+ {
+ CloseClipboard();
+ return false;
+ }
+
+ CloseClipboard();
+ return true;
+}
+
+inline void platform_show_alert(char *title, char *message)
+{
+ // not implemented
+}
+
+inline void platform_destroy()
+{
+ assets_destroy();
+
+#if defined(MODE_DEVELOPER)
+ memory_print_leaks();
+#endif
+}
+
+bool is_platform_in_darkmode()
+{
+ char *key = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\\";
+
+ HKEY result;
+ LSTATUS o = RegOpenKeyExA(HKEY_CURRENT_USER, key, 0, KEY_READ, &result);
+
+ if (o == 0)
+ {
+ BYTE data;
+ DWORD len = 4;
+ RegQueryValueExA(result, "AppsUseLightTheme", NULL, NULL, &data, &len);
+
+ if (data == 1) return true;
+ }
+
+ return false;
+}
+
+inline void platform_set_cursor(platform_window *window, cursor_type type)
+{
+ if (window->next_cursor_type != type)
+ {
+ window->next_cursor_type = type;
+ }
+}
+
+bool platform_directory_exists(char *path)
+{
+ return PathFileExistsA(path) == TRUE;
+}
+
+static void create_key_tables()
+{
+ keycode_map[0x30] = KEY_0;
+ keycode_map[0x31] = KEY_1;
+ keycode_map[0x32] = KEY_2;
+ keycode_map[0x33] = KEY_3;
+ keycode_map[0x34] = KEY_4;
+ keycode_map[0x35] = KEY_5;
+ keycode_map[0x36] = KEY_6;
+ keycode_map[0x37] = KEY_7;
+ keycode_map[0x38] = KEY_8;
+ keycode_map[0x39] = KEY_9;
+ keycode_map[0x41] = KEY_A;
+ keycode_map[0x42] = KEY_B;
+ keycode_map[0x43] = KEY_C;
+ keycode_map[0x44] = KEY_D;
+ keycode_map[0x45] = KEY_E;
+ keycode_map[0x46] = KEY_F;
+ keycode_map[0x47] = KEY_G;
+ keycode_map[0x48] = KEY_H;
+ keycode_map[0x49] = KEY_I;
+ keycode_map[0x4A] = KEY_J;
+ keycode_map[0x4B] = KEY_K;
+ keycode_map[0x4C] = KEY_L;
+ keycode_map[0x4D] = KEY_M;
+ keycode_map[0x4E] = KEY_N;
+ keycode_map[0x4F] = KEY_O;
+ keycode_map[0x50] = KEY_P;
+ keycode_map[0x51] = KEY_Q;
+ keycode_map[0x52] = KEY_R;
+ keycode_map[0x53] = KEY_S;
+ keycode_map[0x54] = KEY_T;
+ keycode_map[0x55] = KEY_U;
+ keycode_map[0x56] = KEY_V;
+ keycode_map[0x57] = KEY_W;
+ keycode_map[0x58] = KEY_X;
+ keycode_map[0x59] = KEY_Y;
+ keycode_map[0x5A] = KEY_Z;
+
+ keycode_map[VK_OEM_7] = KEY_APOSTROPHE;
+ keycode_map[VK_OEM_102] = KEY_BACKSLASH;
+ keycode_map[VK_OEM_COMMA] = KEY_COMMA;
+ keycode_map[VK_OEM_3] = KEY_GRAVE_ACCENT;
+ keycode_map[VK_OEM_4] = KEY_LEFT_BRACKET;
+ keycode_map[VK_OEM_MINUS] = KEY_MINUS;
+ keycode_map[VK_OEM_PERIOD] = KEY_PERIOD;
+
+ keycode_map[VK_BACK] = KEY_BACKSPACE;
+ keycode_map[VK_DELETE] = KEY_DELETE;
+ keycode_map[VK_END] = KEY_END;
+ keycode_map[VK_RETURN] = KEY_ENTER;
+ keycode_map[VK_ESCAPE] = KEY_ESCAPE;
+ keycode_map[VK_HOME] = KEY_HOME;
+ keycode_map[VK_INSERT] = KEY_INSERT;
+ keycode_map[VK_MENU] = KEY_MENU;
+ keycode_map[VK_NEXT] = KEY_PAGE_DOWN;
+ keycode_map[VK_PRIOR] = KEY_PAGE_UP;
+ keycode_map[VK_PAUSE] = KEY_PAUSE;
+ keycode_map[VK_TAB] = KEY_TAB;
+ keycode_map[VK_CAPITAL] = KEY_CAPS_LOCK;
+ keycode_map[VK_NUMLOCK] = KEY_NUM_LOCK;
+ keycode_map[VK_SCROLL] = KEY_SCROLL_LOCK;
+ keycode_map[0x70] = KEY_F1;
+ keycode_map[0x71] = KEY_F2;
+ keycode_map[0x72] = KEY_F3;
+ keycode_map[0x73] = KEY_F4;
+ keycode_map[0x74] = KEY_F5;
+ keycode_map[0x75] = KEY_F6;
+ keycode_map[0x76] = KEY_F7;
+ keycode_map[0x77] = KEY_F8;
+ keycode_map[0x78] = KEY_F9;
+ keycode_map[0x79] = KEY_F10;
+ keycode_map[0x7A] = KEY_F11;
+ keycode_map[0x7B] = KEY_F12;
+ keycode_map[0x7C] = KEY_F13;
+ keycode_map[0x7D] = KEY_F14;
+ keycode_map[0x7E] = KEY_F15;
+ keycode_map[0x7F] = KEY_F16;
+ keycode_map[0x80] = KEY_F17;
+ keycode_map[0x81] = KEY_F18;
+ keycode_map[0x82] = KEY_F19;
+ keycode_map[0x83] = KEY_F20;
+ keycode_map[0x84] = KEY_F21;
+ keycode_map[0x85] = KEY_F22;
+ keycode_map[0x86] = KEY_F23;
+ keycode_map[0x87] = KEY_F24;
+ keycode_map[0x88] = KEY_LEFT_ALT;
+ keycode_map[VK_CONTROL] = KEY_LEFT_CONTROL;
+ keycode_map[VK_LCONTROL] = KEY_LEFT_CONTROL;
+ keycode_map[VK_LSHIFT] = KEY_LEFT_SHIFT;
+ keycode_map[VK_LWIN] = KEY_LEFT_SUPER;
+ keycode_map[VK_SNAPSHOT] = KEY_PRINT_SCREEN;
+ keycode_map[VK_RMENU] = KEY_RIGHT_ALT;
+ keycode_map[VK_RCONTROL] = KEY_RIGHT_CONTROL;
+ keycode_map[VK_RSHIFT] = KEY_RIGHT_SHIFT;
+ keycode_map[VK_RWIN] = KEY_RIGHT_SUPER;
+ keycode_map[VK_DOWN] = KEY_DOWN;
+ keycode_map[VK_LEFT] = KEY_LEFT;
+ keycode_map[VK_RIGHT] = KEY_RIGHT;
+ keycode_map[VK_UP] = KEY_UP;
+
+ keycode_map[VK_NUMPAD0] = KEY_KP_0;
+ keycode_map[VK_NUMPAD1] = KEY_KP_1;
+ keycode_map[VK_NUMPAD2] = KEY_KP_2;
+ keycode_map[VK_NUMPAD3] = KEY_KP_3;
+ keycode_map[VK_NUMPAD4] = KEY_KP_4;
+ keycode_map[VK_NUMPAD5] = KEY_KP_5;
+ keycode_map[VK_NUMPAD6] = KEY_KP_6;
+ keycode_map[VK_NUMPAD7] = KEY_KP_7;
+ keycode_map[VK_NUMPAD8] = KEY_KP_8;
+ keycode_map[VK_NUMPAD9] = KEY_KP_9;
+ keycode_map[VK_ADD] = KEY_KP_ADD;
+ keycode_map[VK_DECIMAL] = KEY_KP_DECIMAL;
+ keycode_map[VK_DIVIDE] = KEY_KP_DIVIDE;
+ keycode_map[VK_MULTIPLY] = KEY_KP_MULTIPLY;
+ keycode_map[VK_SUBTRACT] = KEY_KP_SUBTRACT;
+}
+
+bool platform_file_exists(char *path)
+{
+ DWORD dwAttrib = GetFileAttributes(path);
+
+ return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
+ !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
+}
+
+void platform_create_config_directory()
+{
+ char tmp[PATH_MAX];
+ if(SUCCEEDED(SHGetFolderPathA(0, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, tmp)))
+ {
+ string_appendn(tmp, CONFIG_DIRECTORY, PATH_MAX);
+ }
+
+
+ if (!platform_directory_exists(tmp))
+ {
+ CreateDirectoryA(tmp, NULL);
+ }
+}
+
+char* get_config_save_location(char *buffer)
+{
+ if(SUCCEEDED(SHGetFolderPathA(0, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, buffer)))
+ {
+ string_appendn(buffer, CONFIG_DIRECTORY"\\config.txt", MAX_INPUT_LENGTH);
+ return buffer;
+ }
+
+ return 0;
+}
+
+void platform_show_message(platform_window *window, char *message, char *title)
+{
+ HWND handle = window ? window->window_handle : NULL;
+ MessageBox(handle, message, title, MB_ICONINFORMATION | MB_OK);
+}
+
+LRESULT CALLBACK main_window_callback(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
+{
+ LRESULT result = 0;
+
+ if (message == WM_SIZE)
+ {
+ u32 width = lparam&0xFFFF;
+ u32 height = lparam>>16;
+
+ current_window_to_handle->width = width;
+ current_window_to_handle->height = height;
+ }
+ else if (message == WM_CHAR)
+ {
+ if (current_keyboard_to_handle->take_input)
+ {
+ char buf[5];
+ memset(buf, 0, 5);
+ char *ch = 0;
+
+ wchar_t codep = wparam;
+
+ WideCharToMultiByte(CP_UTF8, 0, &codep, 1, buf, 5 ,0,0);
+
+ if (utf8len(buf) == 1)
+ {
+ char val = buf[0];
+
+ if (current_keyboard_to_handle->input_mode == INPUT_NUMERIC)
+ {
+ if (!(val >= 48 && val <= 57))
+ {
+ ch = 0;
+ }
+ else
+ {
+ snprintf(buf, 2, "%c", val);
+ ch = buf;
+ }
+ }
+ else if (val >= 32 && val <= 126)
+ {
+ snprintf(buf, 5, "%c", val);
+ ch = buf;
+ }
+ }
+
+ if (ch != 0)
+ keyboard_handle_input_string(current_window_to_handle, current_keyboard_to_handle, ch);
+ }
+ }
+ else if (message == WM_MOUSELEAVE)
+ {
+ //current_mouse_to_handle->x = MOUSE_OFFSCREEN;
+ //current_mouse_to_handle->y = MOUSE_OFFSCREEN;
+ }
+ else if (message == WM_KILLFOCUS)
+ {
+ current_mouse_to_handle->x = MOUSE_OFFSCREEN;
+ current_mouse_to_handle->y = MOUSE_OFFSCREEN;
+
+ current_window_to_handle->has_focus = false;
+ memset(current_keyboard_to_handle->keys, 0, MAX_KEYCODE);
+ }
+ else if (message == WM_SETFOCUS)
+ {
+ current_window_to_handle->has_focus = true;
+ }
+ else if (message == WM_KEYDOWN)
+ {
+ s32 key = wparam;
+
+ current_keyboard_to_handle->keys[keycode_map[key]] = true;
+ current_keyboard_to_handle->input_keys[keycode_map[key]] = true;
+
+ if (current_keyboard_to_handle->take_input)
+ keyboard_handle_input_string(current_window_to_handle,
+ current_keyboard_to_handle, 0);
+ }
+ else if (message == WM_KEYUP)
+ {
+ s32 key = wparam;
+ current_keyboard_to_handle->keys[keycode_map[key]] = false;
+ current_keyboard_to_handle->input_keys[keycode_map[key]] = false;
+ }
+ else if (message == WM_LBUTTONDOWN ||
+ message == WM_RBUTTONDOWN ||
+ message == WM_MBUTTONDOWN ||
+ message == WM_MOUSEWHEEL)
+ {
+ bool is_left_down = wparam & MK_LBUTTON;
+ bool is_right_down = wparam & MK_RBUTTON;
+ bool is_middle_down = wparam & MK_MBUTTON;
+
+ u64 ev_time = platform_get_time(TIME_FULL, TIME_MILI_S);
+ static u64 last_ev_time = 0;
+
+ if (message == WM_MOUSEWHEEL)
+ {
+ s16 scroll_val = wparam>>16;
+
+ if (scroll_val < 0)
+ current_mouse_to_handle->scroll_state = SCROLL_DOWN;
+ else
+ current_mouse_to_handle->scroll_state = SCROLL_UP;
+ }
+
+ if (is_left_down)
+ {
+ if (ev_time - last_ev_time < 200)
+ {
+ current_mouse_to_handle->left_state |= MOUSE_DOUBLE_CLICK;
+ }
+
+ current_mouse_to_handle->left_state |= MOUSE_DOWN;
+ current_mouse_to_handle->left_state |= MOUSE_CLICK;
+
+ current_mouse_to_handle->total_move_x = 0;
+ current_mouse_to_handle->total_move_y = 0;
+ last_ev_time = ev_time;
+ }
+ if (is_right_down)
+ {
+ current_mouse_to_handle->right_state |= MOUSE_DOWN;
+ current_mouse_to_handle->right_state |= MOUSE_CLICK;
+ }
+ }
+ else if (message == WM_LBUTTONUP ||
+ message == WM_RBUTTONUP ||
+ message == WM_MBUTTONUP)
+ {
+ bool is_left_up = message == WM_LBUTTONUP;
+ bool is_right_up = message == WM_RBUTTONUP;
+ bool is_middle_up = message == WM_MBUTTONUP;
+
+ if (is_left_up)
+ {
+ current_mouse_to_handle->left_state = MOUSE_RELEASE;
+ }
+ if (is_right_up)
+ {
+ current_mouse_to_handle->right_state = MOUSE_RELEASE;
+ }
+ }
+ else if (message == WM_MOUSEMOVE)
+ {
+ current_window_to_handle->curr_cursor_type = -999;
+
+#if 0
+ s32 x = lparam&0xFFFF;
+ s32 y = lparam>>16;
+
+ current_mouse_to_handle->x = x;
+ current_mouse_to_handle->y = y;
+#endif
+
+ TRACKMOUSEEVENT track;
+ track.cbSize = sizeof(track);
+ track.dwFlags = TME_LEAVE;
+ track.hwndTrack = current_window_to_handle->window_handle;
+ TrackMouseEvent(&track);
+ }
+ else if (message == WM_GETMINMAXINFO)
+ {
+ MINMAXINFO *info = (MINMAXINFO*)lparam;
+
+ info->ptMinTrackSize.x = current_window_to_handle->min_width;
+ info->ptMinTrackSize.y = current_window_to_handle->min_height;
+
+ if (current_window_to_handle->max_width)
+ info->ptMaxTrackSize.x = current_window_to_handle->max_width;
+ if (current_window_to_handle->max_height)
+ info->ptMaxTrackSize.y = current_window_to_handle->max_height;
+ }
+ else if (message == WM_DESTROY)
+ {
+ current_window_to_handle->is_open = false;
+ }
+ else if (message == WM_CLOSE)
+ {
+ current_window_to_handle->is_open = false;
+ }
+ else
+ {
+ result = LSMProc(window, message, wparam, lparam);
+ }
+
+ return result;
+}
+
+void platform_window_set_title(platform_window *window, char *name)
+{
+ SetWindowText(window->window_handle, name);
+}
+
+vec2 platform_get_window_size(platform_window *window)
+{
+ RECT rec;
+ GetWindowRect(window->window_handle, &rec);
+ vec2 res;
+ res.x = rec.right - rec.left;
+ res.y = rec.bottom - rec.top;
+ return res;
+}
+
+void platform_get_focus(platform_window *window)
+{
+ SetFocus(window->window_handle);
+}
+
+platform_window platform_open_window(char *name, u16 width, u16 height, u16 max_w, u16 max_h, u16 min_w, u16 min_h)
+{
+#if !defined(MODE_GDBDEBUG) && !defined(MODE_DEVELOPER)
+ ShowWindow(GetConsoleWindow(), SW_HIDE);
+#endif
+
+ platform_window window;
+ window.has_focus = true;
+ window.window_handle = 0;
+ window.hdc = 0;
+ window.width = width;
+ window.height = height;
+ window.min_width = min_w;
+ window.min_height = min_h;
+ window.max_width = max_w;
+ window.max_height = max_h;
+ window.curr_cursor_type = -1;
+ window.next_cursor_type = CURSOR_DEFAULT;
+
+ current_window_to_handle = &window;
+
+ memset(&window.window_class, 0, sizeof(WNDCLASS));
+ window.window_class.style = CS_OWNDC;
+ window.window_class.lpfnWndProc = main_window_callback;
+ window.window_class.hInstance = instance;
+ window.window_class.lpszClassName = name;
+ window.window_class.hIcon = LoadIcon(NULL, IDI_WINLOGO);
+ //window.window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
+
+ if (RegisterClass(&window.window_class))
+ {
+ int style = WS_VISIBLE|WS_SYSMENU|WS_CAPTION|WS_MINIMIZEBOX;
+
+ if (min_w != max_w && min_h != max_h)
+ style |= WS_SIZEBOX;
+ else
+ style |= WS_THICKFRAME;
+
+ window.window_handle = CreateWindowEx(0,
+ window.window_class.lpszClassName,
+ name,
+ style,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ width,
+ height,
+ 0,
+ 0,
+ instance,
+ 0);
+
+ if (window.window_handle)
+ {
+ window.hdc = GetDC(window.window_handle);
+
+ PIXELFORMATDESCRIPTOR format;
+ memset(&format, 0, sizeof(PIXELFORMATDESCRIPTOR));
+ format.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+ format.nVersion = 1;
+ format.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
+ format.cColorBits = 24;
+ format.cAlphaBits = 8;
+ format.iLayerType = PFD_MAIN_PLANE; // PFD_TYPE_RGBA
+ s32 suggested_format_index = ChoosePixelFormat(window.hdc, &format);
+
+ PIXELFORMATDESCRIPTOR actual_format;
+ DescribePixelFormat(window.hdc, suggested_format_index, sizeof(actual_format), &actual_format);
+ SetPixelFormat(window.hdc, suggested_format_index, &actual_format);
+
+ window.gl_context = wglCreateContext(window.hdc);
+
+ static HGLRC share_list = 0;
+ if (share_list == 0)
+ {
+ share_list = window.gl_context;
+ }
+ else
+ {
+ wglShareLists(share_list, window.gl_context);
+ }
+
+ wglMakeCurrent(window.hdc, window.gl_context);
+
+ ShowWindow(window.window_handle, cmd_show);
+
+ // blending
+ glEnable(GL_DEPTH_TEST);
+ //glDepthMask(true);
+ //glClearDepth(50);
+ glDepthFunc(GL_LEQUAL);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // setup multisampling
+#if 0
+ glEnable(GL_ALPHA_TEST);
+ glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+ glEnable(GL_SAMPLE_ALPHA_TO_ONE);
+ glEnable(GL_MULTISAMPLE);
+ glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
+#endif
+
+ // https://stackoverflow.com/questions/5627229/sub-pixel-drawing-with-opengl
+ //glHint(GL_POINT_SMOOTH, GL_NICEST);
+ //glHint(GL_LINE_SMOOTH, GL_NICEST);
+ //glHint(GL_POLYGON_SMOOTH, GL_NICEST);
+
+ //glEnable(GL_SMOOTH);
+ //glEnable(GL_POINT_SMOOTH);
+ //glEnable(GL_LINE_SMOOTH);
+ //glEnable(GL_POLYGON_SMOOTH);
+ //////////////////
+
+ window.is_open = true;
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, width, height, 0, -1, 1);
+
+ //GLint m_viewport[4];
+ //glGetIntegerv( GL_VIEWPORT, m_viewport );
+ //printf("%d %d %d %d\n", m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ TRACKMOUSEEVENT track;
+ track.cbSize = sizeof(track);
+ track.dwFlags = TME_LEAVE;
+ track.hwndTrack = window.window_handle;
+ TrackMouseEvent(&track);
+ }
+ else
+ {
+ platform_show_message(0, "An error occured within Windows, please restart the program.", "Error");
+ abort();
+ }
+ }
+ else
+ {
+ platform_show_message(0, "An error occured within Windows, please restart the program.", "Error");
+ abort();
+ }
+
+ platform_get_focus(&window);
+
+ return window;
+}
+
+void platform_window_set_size(platform_window *window, u16 width, u16 height)
+{
+ s32 style = GetWindowLong(window->window_handle, GWL_STYLE);
+ BOOL menu = FALSE;
+
+ RECT rec;
+ rec.left = 0;
+ rec.top = 0;
+ rec.right = width;
+ rec.bottom = height;
+ AdjustWindowRectEx(&rec, style, menu, 0);
+ SetWindowPos(window->window_handle,NULL,rec.left,rec.top,rec.right,rec.bottom,SWP_NOMOVE|SWP_NOZORDER);
+}
+
+void platform_window_set_position(platform_window *window, u16 x, u16 y)
+{
+ RECT rec;
+ GetWindowRect(window->window_handle, &rec);
+ MoveWindow(window->window_handle, x, y, rec.right-rec.left, rec.bottom-rec.top, FALSE);
+}
+
+bool platform_window_is_valid(platform_window *window)
+{
+ return window->hdc && window->window_handle;
+}
+
+void platform_destroy_window(platform_window *window)
+{
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(window->gl_context);
+
+ ReleaseDC(window->window_handle, window->hdc);
+ CloseWindow(window->window_handle);
+ DestroyWindow(window->window_handle);
+ UnregisterClassA(window->window_class.lpszClassName, instance);
+ window->hdc = 0;
+ window->window_handle = 0;
+}
+
+void platform_handle_events(platform_window *window, mouse_input *mouse, keyboard_input *keyboard)
+{
+ current_window_to_handle = window;
+ current_keyboard_to_handle = keyboard;
+ current_mouse_to_handle = mouse;
+
+ mouse->left_state &= ~MOUSE_CLICK;
+ mouse->right_state &= ~MOUSE_CLICK;
+ mouse->left_state &= ~MOUSE_DOUBLE_CLICK;
+ mouse->right_state &= ~MOUSE_DOUBLE_CLICK;
+ mouse->left_state &= ~MOUSE_RELEASE;
+ mouse->right_state &= ~MOUSE_RELEASE;
+ memset(keyboard->input_keys, 0, MAX_KEYCODE);
+ mouse->move_x = 0;
+ mouse->move_y = 0;
+ mouse->scroll_state = 0;
+ keyboard->text_changed = false;
+
+ // mouse position (including outside of window)
+ current_window_to_handle->has_focus = GetFocus() == current_window_to_handle->window_handle;
+
+ if (current_window_to_handle->has_focus)
+ {
+ if((GetKeyState(VK_LBUTTON) & 0x100) == 0)
+ {
+ current_mouse_to_handle->left_state = MOUSE_RELEASE;
+ }
+
+ RECT rec;
+ GetWindowRect(window->window_handle, &rec);
+ POINT p;
+ GetCursorPos(&p);
+ mouse->x = p.x - rec.left - GetSystemMetrics(SM_CYSIZEFRAME);
+ mouse->y = p.y - rec.top - GetSystemMetrics(SM_CYSIZE) - GetSystemMetrics(SM_CYFRAME);
+ //printf("%d %d\n",GetSystemMetrics(SM_CYSIZE), GetSystemMetrics(SM_CYFRAME));
+ }
+
+ MSG message;
+ while(PeekMessageA(&message, window->window_handle, 0, 0, TRUE))
+ {
+ TranslateMessage(&message);
+ SizingCheck(&message);
+ DispatchMessage(&message);
+ }
+
+ glViewport(0, 0, window->width, window->height);
+}
+
+void platform_window_swap_buffers(platform_window *window)
+{
+ // set cursor if changed
+ if (window->curr_cursor_type != window->next_cursor_type)
+ {
+ char *cursor_shape = 0;
+ switch(window->next_cursor_type)
+ {
+ case CURSOR_DEFAULT: cursor_shape = IDC_ARROW; break;
+ case CURSOR_POINTER: cursor_shape = IDC_HAND; break;
+ }
+
+ HCURSOR cursor = LoadCursorA(NULL, cursor_shape);
+
+ window->curr_cursor_type = window->next_cursor_type;
+ SetCursor(cursor);
+ }
+
+ SwapBuffers(window->hdc);
+}
+
+file_content platform_read_file_content(char *path, const char *mode)
+{
+ file_content result;
+ result.content = 0;
+ result.content_length = 0;
+ result.file_error = 0;
+
+ FILE *file = fopen(path, mode);
+ if (!file)
+ {
+ if (errno == EMFILE)
+ result.file_error = FILE_ERROR_TOO_MANY_OPEN_FILES_PROCESS;
+ else if (errno == ENFILE)
+ result.file_error = FILE_ERROR_TOO_MANY_OPEN_FILES_SYSTEM;
+ else if (errno == EACCES)
+ result.file_error = FILE_ERROR_NO_ACCESS;
+ else if (errno == EPERM)
+ result.file_error = FILE_ERROR_NO_ACCESS;
+ else if (errno == ENOENT)
+ result.file_error = FILE_ERROR_NOT_FOUND;
+ else if (errno == ECONNABORTED)
+ result.file_error = FILE_ERROR_CONNECTION_ABORTED;
+ else if (errno == ECONNREFUSED)
+ result.file_error = FILE_ERROR_CONNECTION_REFUSED;
+ else if (errno == ENETDOWN)
+ result.file_error = FILE_ERROR_NETWORK_DOWN;
+ else
+ {
+ result.file_error = FILE_ERROR_GENERIC;
+ printf("ERROR: %d\n", errno);
+ }
+
+ goto done_failure;
+ }
+
+ fseek(file, 0 , SEEK_END);
+ int length = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ s32 length_to_alloc = length+1;
+
+ result.content = mem_alloc(length_to_alloc);
+ if (!result.content) goto done;
+
+ memset(result.content, 0, length);
+ s32 read_result = fread(result.content, 1, length, file);
+ if (read_result == 0 && length != 0)
+ {
+ mem_free(result.content);
+ result.content = 0;
+ return result;
+ }
+
+ result.content_length = read_result;
+
+ ((char*)result.content)[length] = 0;
+
+ done:
+ fclose(file);
+ done_failure:
+ return result;
+}
+
+void platform_delete_file(char *path)
+{
+ remove(path);
+}
+
+bool platform_write_file_content(char *path, const char *mode, char *buffer, s32 len)
+{
+ bool result = false;
+
+ FILE *file = fopen(path, mode);
+
+ if (!file)
+ {
+ goto done_failure;
+ }
+ else
+ {
+ fwrite(buffer, 1, len, file);
+ //fprintf(file, buffer);
+ }
+
+ //done:
+ fclose(file);
+ done_failure:
+ return result;
+}
+
+void platform_destroy_file_content(file_content *content)
+{
+ assert(content);
+ mem_free(content->content);
+}
+
+bool get_active_directory(char *buffer)
+{
+ return GetCurrentDirectory(MAX_INPUT_LENGTH, buffer);
+}
+
+bool set_active_directory(char *path)
+{
+ return SetCurrentDirectory(path);
+}
+
+void platform_list_files_block(array *list, char *start_dir, array filters, bool recursive, memory_bucket *bucket, bool include_directories, bool *is_cancelled)
+{
+ assert(list);
+ s32 len = 0;
+ char *matched_filter = 0;
+
+ char *subdirname_buf;
+ if (bucket)
+ subdirname_buf = memory_bucket_reserve(bucket, MAX_INPUT_LENGTH);
+ else
+ subdirname_buf = mem_alloc(MAX_INPUT_LENGTH);
+
+ char *start_dir_fix;
+ if (bucket)
+ start_dir_fix = memory_bucket_reserve(bucket, MAX_INPUT_LENGTH);
+ else
+ start_dir_fix = mem_alloc(MAX_INPUT_LENGTH);
+ snprintf(start_dir_fix, MAX_INPUT_LENGTH, "%s*", start_dir);
+
+ char *start_dir_clean;
+ if (bucket)
+ start_dir_clean = memory_bucket_reserve(bucket, MAX_INPUT_LENGTH);
+ else
+ start_dir_clean = mem_alloc(MAX_INPUT_LENGTH);
+ string_copyn(start_dir_clean, start_dir, MAX_INPUT_LENGTH);
+
+ WIN32_FIND_DATAA file_info;
+ HWND handle = FindFirstFileA(start_dir_fix, &file_info);
+
+ if (!bucket)
+ mem_free(start_dir_fix);
+
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ return;
+ }
+
+ do
+ {
+ if (*is_cancelled) break;
+ char *name = file_info.cFileName;
+
+ // symbolic link is not allowed..
+ if ((file_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
+ continue;
+
+
+ if ((file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
+ continue;
+
+ if (include_directories)
+ {
+ if ((len = filter_matches(&filters, name,
+ &matched_filter)) && len != -1)
+ {
+ // is file
+ char *buf;
+ if (bucket)
+ buf = memory_bucket_reserve(bucket, MAX_INPUT_LENGTH);
+ else
+ buf = mem_alloc(MAX_INPUT_LENGTH);
+ snprintf(buf, MAX_INPUT_LENGTH, "%s%s",start_dir, name);
+
+ found_file f;
+ f.path = buf;
+
+ if (bucket)
+ f.matched_filter= memory_bucket_reserve(bucket, len+1);
+ else
+ f.matched_filter= mem_alloc(len+1);
+
+ string_copyn(f.matched_filter, matched_filter, len+1);
+
+ mutex_lock(&list->mutex);
+ array_push_size(list, &f, sizeof(found_file));
+ mutex_unlock(&list->mutex);
+ }
+ }
+
+ if (recursive)
+ {
+ string_copyn(subdirname_buf, start_dir_clean, MAX_INPUT_LENGTH);
+ string_appendn(subdirname_buf, name, MAX_INPUT_LENGTH);
+ string_appendn(subdirname_buf, "\\", MAX_INPUT_LENGTH);
+
+ // is directory
+ platform_list_files_block(list, subdirname_buf, filters, recursive, bucket, include_directories, is_cancelled);
+ }
+ }
+ else if ((file_info.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ||
+ (file_info.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ||
+ (file_info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ||
+ (file_info.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
+ (file_info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ||
+ (file_info.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE))
+ {
+ if ((len = filter_matches(&filters, name,
+ &matched_filter)) && len != -1)
+ {
+ // is file
+ char *buf;
+ if (bucket)
+ buf = memory_bucket_reserve(bucket, MAX_INPUT_LENGTH);
+ else
+ buf = mem_alloc(MAX_INPUT_LENGTH);
+
+ snprintf(buf, MAX_INPUT_LENGTH, "%s%s",start_dir, name);
+
+ found_file f;
+ f.path = buf;
+
+ if (bucket)
+ f.matched_filter = memory_bucket_reserve(bucket, len+1);
+ else
+ f.matched_filter = mem_alloc(len+1);
+
+ string_copyn(f.matched_filter, matched_filter, len+1);
+
+ mutex_lock(&list->mutex);
+ array_push_size(list, &f, sizeof(found_file));
+ mutex_unlock(&list->mutex);
+ }
+ }
+ }
+ while (FindNextFile(handle, &file_info) != 0);
+
+ if (!bucket)
+ mem_free(start_dir_clean);
+
+ FindClose(handle);
+}
+
+static void* platform_open_file_dialog_implementation(void *data)
+{
+ struct open_dialog_args *args = data;
+
+ OPENFILENAME info;
+ info.lStructSize = sizeof(OPENFILENAME);
+ info.hwndOwner = NULL;
+ info.hInstance = NULL;
+
+ char filter[MAX_INPUT_LENGTH];
+ memset(filter, 0, MAX_INPUT_LENGTH);
+
+ if (args->file_filter)
+ {
+ string_copyn(filter, args->file_filter, MAX_INPUT_LENGTH);
+ filter[strlen(filter)] = 0;
+ filter[strlen(filter)+1] = 0;
+ info.lpstrFilter = filter;
+ }
+ else
+ {
+ info.lpstrFilter = NULL;
+ }
+
+ char szFile[MAX_INPUT_LENGTH];
+ memset(szFile, 0, MAX_INPUT_LENGTH);
+
+ info.lpstrCustomFilter = NULL;
+ info.nMaxCustFilter = MAX_INPUT_LENGTH;
+ info.nFilterIndex = 0;
+ info.lpstrFile = (char*)szFile;
+ info.nMaxFile = MAX_INPUT_LENGTH;
+
+ info.lpstrDefExt = args->default_save_file_extension;
+
+ info.lpstrFileTitle = NULL;
+ info.lpstrInitialDir = args->start_path;
+ info.lpstrTitle = NULL;
+
+ if (args->type == SAVE_FILE)
+ {
+ info.Flags = OFN_EXTENSIONDIFFERENT | OFN_OVERWRITEPROMPT;
+ GetSaveFileNameA(&info);
+ string_copyn(args->buffer, info.lpstrFile, MAX_INPUT_LENGTH);
+ }
+ else if (args->type == OPEN_DIRECTORY)
+ {
+ BROWSEINFOA inf;
+ PIDLIST_ABSOLUTE result = SHBrowseForFolderA(&inf);
+ if (!result) return 0;
+
+ SHGetPathFromIDListA(result, args->buffer);
+ }
+ else if (args->type == OPEN_FILE)
+ {
+ info.Flags = OFN_FILEMUSTEXIST;
+ GetOpenFileNameA(&info);
+ string_copyn(args->buffer, info.lpstrFile, MAX_INPUT_LENGTH);
+ }
+
+ return 0;
+}
+
+void *platform_open_file_dialog_block(void *arg)
+{
+ platform_open_file_dialog_implementation(arg);
+ mem_free(arg);
+ return 0;
+}
+
+char *platform_get_full_path(char *file)
+{
+ char *buf = mem_alloc(MAX_INPUT_LENGTH);
+ if (!GetFullPathNameA(file, MAX_INPUT_LENGTH, buf, NULL))
+ {
+ buf[0] = 0;
+ }
+
+ return buf;
+}
+
+void platform_open_url(char *command)
+{
+ platform_run_command(command);
+}
+
+void platform_run_command(char *command)
+{
+ // might be start instead of open
+ ShellExecuteA(NULL, "open", command, NULL, NULL, SW_SHOWDEFAULT);
+}
+
+void platform_window_make_current(platform_window *window)
+{
+ wglMakeCurrent(window->hdc, window->gl_context);
+}
+
+void platform_init(int argc, char **argv)
+{
+ setlocale(LC_ALL, "en_US.UTF-8");
+
+ QueryPerformanceFrequency(&perf_frequency);
+ CoInitialize(NULL);
+ create_key_tables();
+
+ instance = GetModuleHandle(NULL);
+ cmd_show = argc;
+
+ // get fullpath of the directory the exe is residing in
+ binary_path = platform_get_full_path(argv[0]);
+
+ platform_create_config_directory();
+
+ char buf[MAX_INPUT_LENGTH];
+ get_directory_from_path(buf, binary_path);
+ string_copyn(binary_path, buf, MAX_INPUT_LENGTH);
+
+ assets_create();
+}
+
+void platform_set_icon(platform_window *window, image *img)
+{
+ BYTE *bmp;
+ s32 data_len = img->width * img->height * 4;
+ s32 total_len = data_len + 40 * 4;
+
+ bmp = mem_alloc(total_len);
+
+ struct {
+ int32_t header_size, width, geight;
+ int16_t color_plane, bits_per_pixel;
+ int32_t compression_mode, img_length, obsolete[4];
+ } bmp_header = {40, img->width, img->height * 2, 1, 32, BI_RGB, data_len, {0,0,0,0} };
+
+ memcpy(bmp, &bmp_header, 40);
+
+ s32 index = 0;
+ for (s32 y = img->height-1; y >= 0; y--)
+ {
+ for (s32 x = 0; x < img->width; x++)
+ {
+ s32 img_pixel = *(((s32*)img->data+(x+(y*img->width))));
+
+ // 0xAABBGGRR
+ s32 a = (img_pixel>>24) & 0x000000FF;
+ s32 b = (img_pixel>>16) & 0x000000FF;
+ s32 g = (img_pixel>> 8) & 0x000000FF;
+ s32 r = (img_pixel>> 0) & 0x000000FF;
+
+ //s32 c = (r << 24) | (g << 16) | (b << 8) | (a << 0);
+ s32 c = (a << 24) | (r << 16) | (g << 8) | (b << 0);
+ memcpy(bmp+40+(index*4), &c, 4);
+
+ ++index;
+ }
+ }
+
+ HICON icon = CreateIconFromResourceEx(bmp, total_len, TRUE, 0x00030000, img->width, img->height, LR_DEFAULTCOLOR);
+
+ SendMessage(window->window_handle, WM_SETICON, ICON_SMALL, (LPARAM)icon);
+ SendMessage(window->window_handle, WM_SETICON, ICON_BIG, (LPARAM)icon);
+
+ mem_free(bmp);
+
+ if (!icon)
+ printf("Failed to load icon, error code: %ld.\n", GetLastError());
+}
+
+u64 platform_get_time(time_type time_type, time_precision precision)
+{
+ LARGE_INTEGER counter;
+ QueryPerformanceCounter(&counter);
+
+ double sec = counter.QuadPart / (double)(perf_frequency.QuadPart);
+
+ //printf("%I64d %I64d %f\n", counter.QuadPart, perf_frequency.QuadPart, sec);
+
+ double val = sec;
+
+ if (precision == TIME_NS)
+ {
+ return val*1000000000;
+ }
+ if (precision == TIME_US)
+ {
+ return val*1000000;
+ }
+ if (precision == TIME_MILI_S)
+ {
+ return val*1000;
+ }
+ if (precision == TIME_S)
+ {
+ return val;
+ }
+ return val;
+}
+
+s32 platform_get_memory_size()
+{
+ u64 result;
+ GetPhysicallyInstalledSystemMemory(&result);
+ return result;
+}
+
+s32 platform_get_cpu_count()
+{
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+
+ return info.dwNumberOfProcessors;
+}
+
+u64 string_to_u64(char *str)
+{
+ return (u64)strtoull(str, 0, 10);
+}
+
+u32 string_to_u32(char *str)
+{
+ return (u32)strtoul(str, 0, 10);
+}
+
+u16 string_to_u16(char *str)
+{
+ return (u16)strtoul(str, 0, 10);
+}
+
+u8 string_to_u8(char *str)
+{
+ return (u8)strtoul(str, 0, 10);
+}
+
+s64 string_to_s64(char *str)
+{
+ return (s64)strtoull(str, 0, 10);
+}
+
+s32 string_to_s32(char *str)
+{
+ return (s32)strtoul(str, 0, 10);
+}
+
+s16 string_to_s16(char *str)
+{
+ return (s16)strtoul(str, 0, 10);
+}
+
+s8 string_to_s8(char *str)
+{
+ return (s8)strtoul(str, 0, 10);
+}
+
+bool platform_send_http_request(char *url, char *params, char *response_buffer)
+{
+ // https://www.unix.com/programming/187337-c-http-get-request-using-sockets.html
+
+ bool response = true;
+ HINTERNET hIntSession = 0;
+ HINTERNET hHttpSession = 0;
+ HINTERNET hHttpRequest = 0;
+
+ hIntSession = InternetOpen("Text-Search", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
+ if (!hIntSession) goto failure;
+
+ hHttpSession = InternetConnect(hIntSession, url, 80, 0, 0, INTERNET_SERVICE_HTTP, 0, 0);
+ if (!hHttpSession) goto failure;
+
+ hHttpRequest = HttpOpenRequest(
+ hHttpSession,
+ "GET",
+ params,
+ 0, 0, 0, INTERNET_FLAG_RELOAD, 0);
+
+
+ char* szHeaders = "Content-Type: application/json";
+ char szReq[1024] = "";
+ if(!HttpSendRequest(hHttpRequest, szHeaders, strlen(szHeaders), szReq, strlen(szReq))) {
+ goto failure;
+ }
+
+ DWORD dwRead=0;
+ while(InternetReadFile(hHttpRequest, response_buffer, MAX_INPUT_LENGTH-1, &dwRead) && dwRead) {
+ response_buffer[dwRead] = 0;
+ dwRead=0;
+ }
+
+ goto done;
+
+ failure:
+ printf("failure");
+ response = false;
+
+ done:
+ InternetCloseHandle(hHttpRequest);
+ InternetCloseHandle(hHttpSession);
+ InternetCloseHandle(hIntSession);
+
+ return response;
+}
+
+bool platform_get_mac_address(char *buffer, s32 buf_size)
+{
+ PIP_ADAPTER_INFO pAdapterInfo;
+ PIP_ADAPTER_INFO pAdapter = NULL;
+ DWORD dwRetVal = 0;
+ UINT i;
+
+ ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
+ pAdapterInfo = mem_alloc(sizeof(IP_ADAPTER_INFO));
+
+ if (!pAdapterInfo) return false;
+
+ if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
+ mem_free(pAdapterInfo);
+ pAdapterInfo = mem_alloc(ulOutBufLen);
+ if (!pAdapterInfo) return false;
+ }
+
+ if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
+ pAdapter = pAdapterInfo;
+
+ if (pAdapter) {
+ for (i = 0; i < pAdapter->AddressLength; i++) {
+ if (i == (pAdapter->AddressLength - 1))
+ buffer += sprintf(buffer, "%.2X", (int)pAdapter->Address[i]);
+ else
+ buffer += sprintf(buffer, "%.2X-", (int)pAdapter->Address[i]);
+ }
+
+ if (pAdapterInfo) mem_free(pAdapterInfo);
+ return true;
+ }
+ }
+
+ return false;
} \ No newline at end of file