From 56cdb9557de57ec86a770524e749da814dccc36d Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Mon, 24 Nov 2025 22:59:11 +0100 Subject: [PATCH] Porting to WASM --- build.sh | 2 +- data/init.lua | 2 +- src/basic/basic.h | 33 ++- src/basic/unix.cpp | 3 +- src/basic/win32_thread.cpp | 12 +- src/external/minicoro.h | 7 - src/metaprogram/metaprogram.cpp | 4 +- src/render/opengl.cpp | 356 ++++++++++++++---------- src/test/basic_env/basic_env.cpp | 367 ------------------------- src/test/tests.cpp | 10 +- src/text_editor/commands_clipboard.cpp | 67 +++-- src/text_editor/generated_config.cpp | 2 +- src/text_editor/intern_table.cpp | 3 +- src/text_editor/management.cpp | 4 +- src/text_editor/text_editor.cpp | 142 ++++++---- src/text_editor/text_editor.h | 2 +- src/text_editor/title_bar.cpp | 8 + src/text_editor/todo.txt | 36 +-- src/text_editor/window.cpp | 8 +- 19 files changed, 414 insertions(+), 654 deletions(-) delete mode 100644 src/test/basic_env/basic_env.cpp diff --git a/build.sh b/build.sh index d6d0d8b..43b1653 100644 --- a/build.sh +++ b/build.sh @@ -48,7 +48,7 @@ if [ ! -f "lbaselib.o" ]; then fi if [ ! -f "metaprogram.exe" ]; then - clang ../src/metaprogram/metaprogram.cpp -o metaprogram.exe \ + clang ../src/metaprogram/metaprogram.cpp ../src/basic/unix.cpp -o metaprogram.exe \ -nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g \ -Wno-writable-strings \ -I../src diff --git a/data/init.lua b/data/init.lua index 47892d6..ae1bb07 100644 --- a/data/init.lua +++ b/data/init.lua @@ -59,7 +59,7 @@ Color.TitleBarSelection = GruvboxLight3 Color.ResizerBackground = GruvboxLight0Hard Color.ResizerOutline = GruvboxLight3 Style = {} -Style.WaitForEvents = 1 +Style.WaitForEvents = 0 Style.DrawLineNumbers = 1 Style.DrawScrollbar = 1 Style.IndentSize = 4 diff --git a/src/basic/basic.h b/src/basic/basic.h index d84a452..e67f86d 100644 --- a/src/basic/basic.h +++ b/src/basic/basic.h @@ -17,6 +17,8 @@ #elif defined(__linux__) #define OS_POSIX 1 #define OS_LINUX 1 +#elif defined(__EMSCRIPTEN__) + #define OS_WASM 1 #else #error Unsupported platform #endif @@ -31,6 +33,10 @@ #error Unsupported compiler #endif +#ifndef OS_WASM + #define OS_WASM 0 +#endif + #ifndef OS_MAC #define OS_MAC 0 #endif @@ -60,14 +66,18 @@ #endif #if OS_WINDOWS -#define DebugBreak() __debugbreak() +#define BREAK() __debugbreak() #elif OS_LINUX -#define DebugBreak() raise(SIGTRAP) +#define BREAK() raise(SIGTRAP) +#elif OS_WASM +#include +extern "C" void JS_Breakpoint(void); +#define BREAK() JS_Breakpoint() #endif #define Assert(x) \ if (!(x)) { \ - DebugBreak(); \ + BREAK(); \ } #define InvalidCodepath() Assert(!"invalid codepath") #define ElseInvalidCodepath() else {InvalidCodepath()} @@ -1035,8 +1045,8 @@ bool VCommit(void *p, size_t size); bool VRelease(void *p, size_t size); bool VDecommit(void *p, size_t size); -void InitArena(Arena *arena, size_t reserve = GiB(4)); -Arena *AllocArena(size_t reserve = GiB(4)); +void InitArena(Arena *arena, size_t reserve = MiB(256)); +Arena *AllocArena(size_t reserve = MiB(256)); Arena *AllocArena(Allocator allocator, size_t size); void *PushSize(Arena *arena, size_t size); void Release(Arena *arena); @@ -1707,11 +1717,22 @@ void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size) { } thread_local Arena *ScratchArenaPool[4]; -void InitScratch() { + +#if OS_WASM +void InitScratch() { + Allocator sys_allocator = GetSystemAllocator(); + ScratchArenaPool[0] = AllocArena(sys_allocator, MiB(8)); + ScratchArenaPool[1] = AllocArena(sys_allocator, MiB(2)); + ScratchArenaPool[3] = AllocArena(sys_allocator, MiB(1)); + ScratchArenaPool[3] = AllocArena(sys_allocator, KiB(512)); +} +#else +void InitScratch() { for (int i = 0; i < Lengthof(ScratchArenaPool); i += 1) { ScratchArenaPool[i] = AllocArena(); } } +#endif TempArena GetScratchEx(Arena **conflicts, int conflict_count) { Arena *unoccupied = 0; diff --git a/src/basic/unix.cpp b/src/basic/unix.cpp index 80c1312..6bb00b5 100644 --- a/src/basic/unix.cpp +++ b/src/basic/unix.cpp @@ -15,7 +15,6 @@ #include #include - void (*Error)(const char *, ...); void *VReserve(size_t size) { @@ -112,7 +111,7 @@ String GetAbsolutePath(Allocator al, String path) { char *buffer = AllocArray(al, char, PATH_MAX); realpath(null_term.data, buffer); String result = buffer; - return buffer; + return result; } bool FileExists(String path) { diff --git a/src/basic/win32_thread.cpp b/src/basic/win32_thread.cpp index 370d709..d51bc4a 100644 --- a/src/basic/win32_thread.cpp +++ b/src/basic/win32_thread.cpp @@ -14,11 +14,7 @@ void PushWork(WorkQueue *wq, void *data, WorkQueueCallback *callback) { entry->data = data; entry->callback = callback; - wq->completion_goal += 1;dex_to_read + 1) % Lengthof(wq->entries); - if (original_index_to_read != wq->index_to_write) { - int64_t index = AtomicCompareAndSwap(&wq->index_to_read, new_index_to_read, original_index_to_read); - if (index == original_index_to_read) { - WorkQueueEntry *entry = wq->entries + + wq->completion_goal += 1; _WriteBarrier(); wq->index_to_write = new_index; ReleaseSemaphore(wq->semaphore, 1, 0); @@ -27,7 +23,11 @@ void PushWork(WorkQueue *wq, void *data, WorkQueueCallback *callback) { bool TryDoingWork(WorkQueue *wq) { bool should_sleep = false; int64_t original_index_to_read = wq->index_to_read; - int64_t new_index_to_read = (original_inindex; + int64_t new_index_to_read = (original_index_to_read + 1) % Lengthof(wq->entries); + if (original_index_to_read != wq->index_to_write) { + int64_t index = AtomicCompareAndSwap(&wq->index_to_read, new_index_to_read, original_index_to_read); + if (index == original_index_to_read) { + WorkQueueEntry *entry = wq->entries + index; entry->callback(entry->data); AtomicIncrement(&wq->completion_index); } diff --git a/src/external/minicoro.h b/src/external/minicoro.h index a354bee..0be8954 100644 --- a/src/external/minicoro.h +++ b/src/external/minicoro.h @@ -349,10 +349,6 @@ MCO_API const char *mco_result_description(mco_result res); /* Get the descripti #ifdef MINICORO_IMPL - #ifdef __cplusplus -extern "C" { - #endif - /* ---------------------------------------------------------------------------------------------- */ /* Minimum stack size when creating a coroutine. */ @@ -1973,9 +1969,6 @@ const char *mco_result_description(mco_result res) { return "Unknown error"; } - #ifdef __cplusplus -} - #endif #endif /* MINICORO_IMPL */ diff --git a/src/metaprogram/metaprogram.cpp b/src/metaprogram/metaprogram.cpp index 86d2236..7854362 100644 --- a/src/metaprogram/metaprogram.cpp +++ b/src/metaprogram/metaprogram.cpp @@ -1,7 +1,7 @@ #define BASIC_IMPL #include "basic/basic.h" #include "basic/filesystem.h" -#include "basic/unix.cpp" + int main() { InitScratch(); @@ -14,5 +14,5 @@ int main() { Add(&array, String{"\n)==\";\n"}); String result = Merge(scratch, array, ""); WriteFile("../src/text_editor/generated_config.cpp", result); - + } \ No newline at end of file diff --git a/src/render/opengl.cpp b/src/render/opengl.cpp index 8994d72..7023b82 100644 --- a/src/render/opengl.cpp +++ b/src/render/opengl.cpp @@ -1,10 +1,3 @@ -struct Shader { - uint32_t pipeline; - uint32_t fshader; - uint32_t vshader; -}; -Shader CreateShader(char *glsl_vshader, char *glsl_fshader); - struct Vertex2D { Vec2 pos; Vec2 tex; @@ -23,6 +16,12 @@ struct VertexList2D { VertexNode2D *last; }; +struct Shader { + GLuint program; // linked program (vertex+fragment) + GLint uni_invHalf; // uniform location for inv half-screen size + GLint uni_texture; // sampler location +}; + VertexList2D Vertices; int64_t TotalVertexCount; @@ -35,6 +34,155 @@ Font MainFont; Int FontLineSpacing; Int FontCharSpacing; +// ---------- shaders (ES3 / WebGL2) ---------- +static const char *glsl_vshader_es3 = R"==(#version 300 es + precision highp float; + + uniform vec2 U_InvHalfScreenSize; // same meaning as before + + layout(location = 0) in vec2 aPos; + layout(location = 1) in vec2 aTex; + layout(location = 2) in vec4 aColor; // normalized unsigned byte will map to 0..1 if we use normalized=true + + out vec2 vUV; + out vec4 vColor; + + void main() { + vec2 pos = aPos * U_InvHalfScreenSize; + pos.y = 2.0 - pos.y; // invert Y the same way you had + pos -= vec2(1.0, 1.0); + gl_Position = vec4(pos, 0.0, 1.0); + vUV = aTex; + vColor = aColor; // already 0..1 + } +)=="; + +static const char *glsl_fshader_es3 = R"==(#version 300 es + precision mediump float; + + in vec2 vUV; + in vec4 vColor; + + uniform sampler2D S_Texture; + out vec4 OutColor; + + void main() { + float a = texture(S_Texture, vUV).r; + vec4 c = vColor; + c.a *= a; + OutColor = c; + } +)=="; + +void ReportWarningf(const char *fmt, ...); +void GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *user) { + ReportWarningf("OpenGL message: %s", message); + if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenGL error", message, NULL); + } +} + +// ---------- helper: compile/link ---------- +static GLuint CompileShaderSrc(GLenum kind, const char *src) { + GLuint s = glCreateShader(kind); + glShaderSource(s, 1, &src, NULL); + glCompileShader(s); + GLint ok = 0; + glGetShaderiv(s, GL_COMPILE_STATUS, &ok); + if (!ok) { + char buf[1024]; + glGetShaderInfoLog(s, sizeof(buf), NULL, buf); + SDL_Log("%s", buf); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, + (kind == GL_VERTEX_SHADER ? "Vertex shader compile error" : "Fragment shader compile error"), + buf, NULL); + } + return s; +} + +Shader CreateShaderES3(const char *vsrc, const char *fsrc) { + Shader out = {}; + GLuint vs = CompileShaderSrc(GL_VERTEX_SHADER, vsrc); + GLuint fs = CompileShaderSrc(GL_FRAGMENT_SHADER, fsrc); + + GLuint prog = glCreateProgram(); + glAttachShader(prog, vs); + glAttachShader(prog, fs); + + // Bind attribute locations to match layout locations (optional because we use layout(location=...)) + // glBindAttribLocation(prog, 0, "aPos"); + // glBindAttribLocation(prog, 1, "aTex"); + // glBindAttribLocation(prog, 2, "aColor"); + + glLinkProgram(prog); + GLint linked = 0; + glGetProgramiv(prog, GL_LINK_STATUS, &linked); + if (!linked) { + char buf[1024]; + glGetProgramInfoLog(prog, sizeof(buf), NULL, buf); + SDL_Log("%s", buf); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Program link error", buf, NULL); + } + + // We can detach/delete shaders after linking + glDetachShader(prog, vs); + glDetachShader(prog, fs); + glDeleteShader(vs); + glDeleteShader(fs); + + out.program = prog; + out.uni_invHalf = glGetUniformLocation(prog, "U_InvHalfScreenSize"); + out.uni_texture = glGetUniformLocation(prog, "S_Texture"); + + return out; +} + +// ---------- InitRender for ES3 ---------- +void InitRender() { +#if OS_WASM + RenderArena = *AllocArena(GetSystemAllocator(), MiB(64)); +#else + InitArena(&RenderArena); +#endif + +#if !OS_WASM + glDebugMessageCallback(&GLDebugCallback, NULL); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); +#endif + + // Create VBO (non-DSA path) + glGenBuffers(1, &VBO); + // reserve buffer big enough for one VertexNode2D->vertices array (same as original intent) + GLsizeiptr vbo_size = (GLsizeiptr) (Lengthof(((VertexNode2D*)0)->vertices) * sizeof(Vertex2D)); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, vbo_size, NULL, GL_DYNAMIC_DRAW); // NULL initial, dynamic usage + + // Create and setup VAO + glGenVertexArrays(1, &VAO); + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + // attribute 0 : pos (vec2, floats) + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (const void*)offsetof(Vertex2D, pos)); + // attribute 1 : tex (vec2) + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (const void*)offsetof(Vertex2D, tex)); + // attribute 2 : color (vec4) -- stored as 4 unsigned bytes; we want normalized floats 0..1 + glEnableVertexAttribArray(2); + // Using normalized GL_TRUE to map 0..255 -> 0..1 directly in shader + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex2D), (const void*)offsetof(Vertex2D, color)); + + // Unbind VAO and VBO + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // Create shader program (ES3) + Shader2D = CreateShaderES3(glsl_vshader_es3, glsl_fshader_es3); + + // other initializations like fonts will be done elsewhere (ReloadFont) +} + void BeginFrameRender(float wx, float wy) { Clear(&RenderArena); TotalVertexCount = 0; @@ -43,6 +191,7 @@ void BeginFrameRender(float wx, float wy) { CurrentScissor = Rect0Size(wx, wy); } +// ---------- EndFrameRender for ES3 ---------- void EndFrameRender(float wx, float wy, Color color) { glEnable(GL_BLEND); glEnable(GL_SCISSOR_TEST); @@ -55,131 +204,47 @@ void EndFrameRender(float wx, float wy, Color color) { glClearColor(color.r, color.g, color.b, color.a); glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - // Default draw using the font texture - glBindProgramPipeline(Shader2D.pipeline); + // Use program and set uniforms + glUseProgram(Shader2D.program); float xinverse = 1.f / (wx / 2.f); float yinverse = 1.f / (wy / 2.f); - glProgramUniform2f(Shader2D.vshader, 0, xinverse, yinverse); + // set uniform (U_InvHalfScreenSize) + if (Shader2D.uni_invHalf >= 0) { + glUniform2f(Shader2D.uni_invHalf, xinverse, yinverse); + } + // set sampler to texture unit 0 + if (Shader2D.uni_texture >= 0) { + glUniform1i(Shader2D.uni_texture, 0); + } + + glBindVertexArray(VAO); for (VertexNode2D *it = Vertices.first; it; it = it->next) { - Rect2 rect = it->scissor; - GLint x = (GLint)rect.min.x; - GLint y = (GLint)rect.min.y; - GLsizei w = (GLsizei)(rect.max.x - x); - GLsizei h = (GLsizei)(rect.max.y - y); + Rect2 rect = it->scissor; + GLint x = (GLint)rect.min.x; + GLint y = (GLint)rect.min.y; + GLsizei w = (GLsizei)(rect.max.x - x); + GLsizei h = (GLsizei)(rect.max.y - y); + // convert scissor Y to OpenGL bottom-left origin like before glScissor(x, (GLint)wy - (GLint)rect.max.y, w, h); - glNamedBufferSubData(VBO, 0, it->count * sizeof(Vertex2D), it->vertices); - glBindVertexArray(VAO); - GLint s_texture = 0; // texture unit that sampler2D will use in GLSL code - glBindTextureUnit(s_texture, MainFont.texture_id); + + // upload vertex data into VBO at offset 0 + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferSubData(GL_ARRAY_BUFFER, 0, it->count * sizeof(Vertex2D), it->vertices); + + // bind texture unit 0 and the font texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, MainFont.texture_id); + + // draw glDrawArrays(GL_TRIANGLES, 0, it->count); + + // unbind VBO (optional) + glBindBuffer(GL_ARRAY_BUFFER, 0); } + glBindVertexArray(0); + glUseProgram(0); } -void ReportWarningf(const char *fmt, ...); -void GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *user) { - ReportWarningf("OpenGL message: %s", message); - if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) { - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenGL error", message, NULL); - } -} - -void InitRender() { - InitArena(&RenderArena); - - glDebugMessageCallback(&GLDebugCallback, NULL); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - - glCreateBuffers(1, &VBO); - glNamedBufferStorage(VBO, Lengthof(VertexNode2D::vertices) * sizeof(Vertex2D), 0, GL_DYNAMIC_STORAGE_BIT); - - glCreateVertexArrays(1, &VAO); - - GLint vbuf_index = 0; - glVertexArrayVertexBuffer(VAO, vbuf_index, VBO, 0, sizeof(struct Vertex2D)); - - GLint a_pos = 0; - glVertexArrayAttribFormat(VAO, a_pos, 2, GL_FLOAT, GL_FALSE, offsetof(struct Vertex2D, pos)); - glVertexArrayAttribBinding(VAO, a_pos, vbuf_index); - glEnableVertexArrayAttrib(VAO, a_pos); - - GLint a_tex = 1; - glVertexArrayAttribFormat(VAO, a_tex, 2, GL_FLOAT, GL_FALSE, offsetof(struct Vertex2D, tex)); - glVertexArrayAttribBinding(VAO, a_tex, vbuf_index); - glEnableVertexArrayAttrib(VAO, a_tex); - - GLint a_color = 2; - glVertexArrayAttribFormat(VAO, a_color, 4, GL_UNSIGNED_BYTE, GL_FALSE, offsetof(struct Vertex2D, color)); - glVertexArrayAttribBinding(VAO, a_color, vbuf_index); - glEnableVertexArrayAttrib(VAO, a_color); - - char *glsl_vshader = R"==( - #version 450 core - - layout(location=0) uniform vec2 U_InvHalfScreenSize; - layout(location=0) in vec2 VPos; - layout(location=1) in vec2 VTex; - layout(location=2) in vec4 VColor; - - out gl_PerVertex { vec4 gl_Position; }; // required because of ARB_separate_shader_objects - out vec2 FUV; - out vec4 FColor; - - void main() { - vec2 pos = VPos * U_InvHalfScreenSize; - pos.y = 2 - pos.y; // invert y axis - pos -= vec2(1, 1); // convert to 0,1 range - - gl_Position = vec4(pos, 0, 1); - FUV = VTex; - - FColor = VColor / 255.0; - } - )=="; - - char *glsl_fshader = R"==( - #version 450 core - - in vec2 FUV; - in vec4 FColor; - - layout (binding=0) uniform sampler2D S_Texture; - layout (location=0) out vec4 OutColor; - - void main() { - vec4 c = FColor; - c.a *= texture(S_Texture, FUV).r; - OutColor = c; - } - )=="; - - Shader2D = CreateShader(glsl_vshader, glsl_fshader); -} - -Shader CreateShader(char *glsl_vshader, char *glsl_fshader) { - Shader result = {}; - result.vshader = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vshader); - result.fshader = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fshader); - - GLint linked; - glGetProgramiv(result.vshader, GL_LINK_STATUS, &linked); - if (!linked) { - char message[1024]; - glGetProgramInfoLog(result.vshader, sizeof(message), NULL, message); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Failed to create vertex shader!", message, NULL); - } - - glGetProgramiv(result.fshader, GL_LINK_STATUS, &linked); - if (!linked) { - char message[1024]; - glGetProgramInfoLog(result.fshader, sizeof(message), NULL, message); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Failed to create fragment shader!", message, NULL); - } - - glGenProgramPipelines(1, &result.pipeline); - glUseProgramStages(result.pipeline, GL_VERTEX_SHADER_BIT, result.vshader); - glUseProgramStages(result.pipeline, GL_FRAGMENT_SHADER_BIT, result.fshader); - return result; -} VertexNode2D *AllocVertexNode2D(Allocator allocator, VertexList2D *list) { VertexNode2D *node = AllocType(allocator, VertexNode2D); @@ -352,9 +417,11 @@ void DrawCircle(Vec2 pos, float radius, Color color) { } } + +// ---------- ReloadFont - replace DSA texture calls ---------- void ReloadFont() { Int size = StyleFontSize; - size = ClampBottom((Int)2, size); + size = ClampBottom((Int)2, size); if (MainFont.texture_id) { glDeleteTextures(1, &MainFont.texture_id); Dealloc(&MainFont.glyphs); @@ -362,20 +429,25 @@ void ReloadFont() { } Scratch scratch; - Atlas atlas = CreateAtlas(scratch, {2048, 2048}); - MainFont = CreateFont(&atlas, (uint32_t)size, StyleFont); - { - GLint filter = GL_NEAREST; - if (StyleFontFilter == 1) filter = GL_LINEAR; - glCreateTextures(GL_TEXTURE_2D, 1, &atlas.texture_id); - glTextureParameteri(atlas.texture_id, GL_TEXTURE_MIN_FILTER, filter); - glTextureParameteri(atlas.texture_id, GL_TEXTURE_MAG_FILTER, filter); - glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTextureStorage2D(atlas.texture_id, 1, GL_R8, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y); - glTextureSubImage2D(atlas.texture_id, 0, 0, 0, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y, GL_RED, GL_UNSIGNED_BYTE, atlas.bitmap); - } - MainFont.texture_id = atlas.texture_id; - FontCharSpacing = GetCharSpacing(&MainFont); - FontLineSpacing = GetLineSpacing(&MainFont); -} \ No newline at end of file + Atlas atlas = CreateAtlas(scratch, {2048, 2048}); + MainFont = CreateFont(&atlas, (uint32_t)size, StyleFont); + + // create and fill texture with ES3-compatible API + GLint filter = GL_NEAREST; + if (StyleFontFilter == 1) filter = GL_LINEAR; + + GLuint tex = 0; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // allocate storage and upload + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y, 0, GL_RED, GL_UNSIGNED_BYTE, atlas.bitmap); + glBindTexture(GL_TEXTURE_2D, 0); + + MainFont.texture_id = tex; + FontCharSpacing = GetCharSpacing(&MainFont); + FontLineSpacing = GetLineSpacing(&MainFont); +} diff --git a/src/test/basic_env/basic_env.cpp b/src/test/basic_env/basic_env.cpp deleted file mode 100644 index ee518a7..0000000 --- a/src/test/basic_env/basic_env.cpp +++ /dev/null @@ -1,367 +0,0 @@ -#include "src/build_tool/library.cpp" - -enum { - PROFILE_DEBUG, - PROFILE_RELEASE, -}; -int Profile = PROFILE_DEBUG; -S8_String Compiler = "cl.exe"; - -void AddCommonFlags(Array *cmd) { - if (Compiler == "cl.exe") { - cmd->add("/MP"); - } - cmd->add("/Zi /FC /nologo"); - cmd->add("/WX /W3 /wd4200 /diagnostics:column"); - if (Compiler == "clang-cl.exe") { - cmd->add("-fdiagnostics-absolute-paths"); - cmd->add("-Wno-missing-braces"); - cmd->add("-Wno-writable-strings"); - cmd->add("-Wno-unused-function"); - } - cmd->add("/Oi"); - cmd->add("-D_CRT_SECURE_NO_WARNINGS"); - if (Profile == PROFILE_DEBUG) { - cmd->add("-DDEBUG_BUILD=1"); - cmd->add("-DRELEASE_BUILD=0"); - // cmd->add("-fsanitize=address"); - // cmd->add("-DUSE_ADDRESS_SANITIZER"); - // cmd->add("/MDd"); - } else { - cmd->add("-DDEBUG_BUILD=0"); - cmd->add("-DRELEASE_BUILD=1"); - cmd->add("/O2 /MT /DNDEBUG /GL"); - } -} - -struct Library { - Array sources; - Array objects; - Array include_paths; - Array defines; - Array link; -}; - -Library PrepareSDL() { - Library l = {}; - l.include_paths.add("../src/external/SDL/include"); - l.objects.add("../src/external/SDL/VisualC/static_x64/Release/SDL3.lib"); - l.link.add("/SUBSYSTEM:WINDOWS"); - l.link.add("opengl32.lib"); - l.link.add("imm32.lib"); - l.link.add("gdi32.lib"); - l.link.add("winmm.lib"); - l.link.add("shell32.lib"); - l.link.add("user32.lib"); - l.link.add("advapi32.lib"); - l.link.add("Setupapi.lib"); - l.link.add("ole32.lib"); - l.link.add("oleaut32.lib"); - l.link.add("Version.lib"); - return l; -} - -Library PrepareSDLDynamic() { - Library l = {}; - l.include_paths.add("../src/external/SDL/include"); - l.objects.add("../src/external/SDL/VisualC/x64/Release/SDL3.lib"); - l.link.add("/SUBSYSTEM:WINDOWS"); - OS_CopyFile("../src/external/SDL/VisualC/x64/Release/SDL3.dll", "./SDL3.dll", false); - return l; -} - -Library PrepareRaylib() { - Library l = {}; - l.include_paths.add("../src/external/raylib/include"); - if (0) { - l.objects.add("../src/external/raylib/lib/raylib.lib"); - } else { - l.objects.add("../src/external/raylib/lib/raylibdll.lib"); - OS_CopyFile("../src/external/raylib/lib/raylib.dll", "./raylib.dll", false); - } - return l; -} - -Library PrepareLua() { - Library l = {}; - l.include_paths.add("../src/external/lua/src"); - - MA_Scratch scratch; - for (OS_FileIter it = OS_IterateFiles(scratch, "../src/external/lua/src"); OS_IsValid(it); OS_Advance(&it)) { - if (it.filename == "luac.c") continue; - if (it.filename == "lua.c") continue; - if (S8_EndsWith(it.filename, ".c", true)) { - l.sources.add(it.absolute_path); - S8_String file = S8_ChopLastPeriod(it.filename); - l.objects.add(Fmt("%.*s.obj", S8_Expand(file))); - } - } - - if (!OS_FileExists(l.objects[0])) { - Array cmd = {}; - cmd.add(Compiler); - cmd.add("-c"); - AddCommonFlags(&cmd); - For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it))); - cmd += l.sources; - Run(cmd); - } - return l; -} - -Library PrepareGlad() { - Library l = {}; - l.sources.add("../src/external/glad/glad.c"); - l.include_paths.add("../src/external/glad/"); - l.objects.add("glad.obj"); - if (!OS_FileExists(l.objects[0])) { - Array cmd = {}; - cmd.add(Compiler); - cmd.add("-c"); - AddCommonFlags(&cmd); - For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it))); - cmd += l.sources; - Run(cmd); - } - return l; -} - -int CompileTextEditor() { - int result = 0; - - Array libs = {}; - // if (Profile == PROFILE_DEBUG) libs.add(PrepareSDLDynamic()); - // else - libs.add(PrepareSDL()); - libs.add(PrepareLua()); - libs.add(PrepareGlad()); - - Array cmd = {}; - cmd.add(Compiler); - cmd.add("-Fe:te.exe"); - cmd.add("-Fd:te.pdb"); - cmd.add("-I ../src"); - AddCommonFlags(&cmd); - For2(lib, libs) For(lib.defines) cmd.add(it); - - cmd.add("../src/text_editor/text_editor.cpp"); - cmd.add("../src/basic/win32.cpp"); - - For2(lib, libs) For(lib.include_paths) cmd.add(Fmt("-I %.*s", S8_Expand(it))); - - cmd.add("/link"); - cmd.add("/incremental:no"); - // cmd.add("/SUBSYSTEM:WINDOWS"); - // cmd.add("opengl32.lib gdi32.lib winmm.lib shell32.lib user32.lib msvcrt.lib /NODEFAULTLIB:LIBCMT"); - For2(lib, libs) For(lib.link) cmd.add(it); - For(libs) For2(o, it.objects) cmd.add(o); - cmd.add("icon.res"); - - OS_DeleteFile("te.pdb"); - // For(cmd) IO_Printf("%.*s\n", S8_Expand(it)); - if (!OS_FileExists("icon.res")) { - OS_CopyFile("../data/icon.ico", "icon.ico", true); - OS_CopyFile("../data/icon.rc", "icon.rc", true); - Run("rc icon.rc"); - } - result += Run(cmd); - if (result == 0) { - OS_MakeDir("../package"); - OS_CopyFile("../build/te.exe", "../package/te.exe", true); - OS_CopyFile("../build/te.pdb", "../package/te.pdb", true); - } - - return result; -} - -char *C(const char *value) { - if (value[0] == '0' && value[1] == 'x') { - S8_String f = Fmt("{0x%.*s, 0x%.*s, 0x%.*s, 0x%.*s}", 2, value + 2, 2, value + 4, 2, value + 6, 2, value + 8); - return f.str; - } else { - return (char *)value; - } -} - -void GenerateConfig() { - struct Var { - const char *name; - const char *value; - }; - - Array gruvbox = {}; - gruvbox.add({"GruvboxDark0Hard", "0x1d2021ff"}); - gruvbox.add({"GruvboxDark0", "0x282828ff"}); - gruvbox.add({"GruvboxDark0Soft", "0x32302fff"}); - gruvbox.add({"GruvboxDark1", "0x3c3836ff"}); - gruvbox.add({"GruvboxDark2", "0x504945ff"}); - gruvbox.add({"GruvboxDark3", "0x665c54ff"}); - gruvbox.add({"GruvboxDark4", "0x7c6f64ff"}); - gruvbox.add({"GruvboxGray245", "0x928374ff"}); - gruvbox.add({"GruvboxGray244", "0x928374ff"}); - gruvbox.add({"GruvboxLight0Hard", "0xf9f5d7ff"}); - gruvbox.add({"GruvboxLight0", "0xfbf1c7ff"}); - gruvbox.add({"GruvboxLight0Soft", "0xf2e5bcff"}); - gruvbox.add({"GruvboxLight1", "0xebdbb2ff"}); - gruvbox.add({"GruvboxLight2", "0xd5c4a1ff"}); - gruvbox.add({"GruvboxLight3", "0xbdae93ff"}); - gruvbox.add({"GruvboxLight4", "0xa89984ff"}); - gruvbox.add({"GruvboxBrightRed", "0xfb4934ff"}); - gruvbox.add({"GruvboxBrightGreen", "0xb8bb26ff"}); - gruvbox.add({"GruvboxBrightYellow", "0xfabd2fff"}); - gruvbox.add({"GruvboxBrightBlue", "0x83a598ff"}); - gruvbox.add({"GruvboxBrightPurple", "0xd3869bff"}); - gruvbox.add({"GruvboxBrightAqua", "0x8ec07cff"}); - gruvbox.add({"GruvboxBrightOrange", "0xfe8019ff"}); - gruvbox.add({"GruvboxNeutralRed", "0xcc241dff"}); - gruvbox.add({"GruvboxNeutralGreen", "0x98971aff"}); - gruvbox.add({"GruvboxNeutralYellow", "0xd79921ff"}); - gruvbox.add({"GruvboxNeutralBlue", "0x458588ff"}); - gruvbox.add({"GruvboxNeutralPurple", "0xb16286ff"}); - gruvbox.add({"GruvboxNeutralAqua", "0x689d6aff"}); - gruvbox.add({"GruvboxNeutralOrange", "0xd65d0eff"}); - gruvbox.add({"GruvboxFadedRed", "0x9d0006ff"}); - gruvbox.add({"GruvboxFadedGreen", "0x79740eff"}); - gruvbox.add({"GruvboxFadedYellow", "0xb57614ff"}); - gruvbox.add({"GruvboxFadedBlue", "0x076678ff"}); - gruvbox.add({"GruvboxFadedPurple", "0x8f3f71ff"}); - gruvbox.add({"GruvboxFadedAqua", "0x427b58ff"}); - gruvbox.add({"GruvboxFadedOrange", "0xaf3a03ff"}); - - Array colors = {}; - colors.add({"Text", "GruvboxDark0Hard"}); - colors.add({"LoadTextHighlight", "0x0000000F"}); - colors.add({"Background", "GruvboxLight0Hard"}); - colors.add({"InactiveWindow", "0x0000000F"}); - colors.add({"TextLineNumbers", "GruvboxDark4"}); - colors.add({"LineHighlight", "GruvboxLight0Soft"}); - colors.add({"MainCaret", "GruvboxDark0Hard"}); - colors.add({"SubCaret", "GruvboxGray245"}); - colors.add({"Selection", "GruvboxLight1"}); - colors.add({"WhitespaceDuringSelection", "GruvboxLight4"}); - colors.add({"MouseUnderline", "GruvboxDark0Hard"}); - colors.add({"CaretUnderline", "GruvboxGray245"}); - - colors.add({"FuzzySearchLineHighlight", "GruvboxDark0"}); - - colors.add({"ScrollbarBackground", "GruvboxLight2"}); - colors.add({"ScrollbarScroller", "GruvboxLight1"}); - colors.add({"ScrollbarScrollerSelected", "GruvboxLight0Hard"}); - - colors.add({"TitleBarText", "GruvboxDark2"}); - colors.add({"TitleBarBackground", "GruvboxLight1"}); - colors.add({"TitleBarActiveBackground", "0xfefefefe"}); - colors.add({"TitleBarSelection", "GruvboxLight3"}); - - colors.add({"ResizerBackground", "GruvboxLight0Hard"}); - colors.add({"ResizerOutline", "GruvboxLight3"}); - - Array style = {}; - style.add({"WaitForEvents", "1"}); - style.add({"DrawLineNumbers", "1"}); - style.add({"DrawScrollbar", "1"}); - style.add({"IndentSize", "4"}); - style.add({"FontSize", "15"}); - style.add({"FontFilter", "0"}); // nearest = 0, linear = 1 - seems like nearest always better? - style.add({"Font", "C:/Windows/Fonts/consola.ttf"}); - style.add({"VCVarsall", "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"}); - - { - MA_Scratch scratch; - Array sb = {MA_GetAllocator(scratch)}; - { - For(gruvbox) sb.add(Fmt("Color %s = %s;", it.name, C(it.value))); - For(colors) sb.add(Fmt("Color Color%s = %s;", it.name, C(it.value))); - For(style) { - if (CHAR_IsDigit(it.value[0])) { - sb.add(Fmt("Int Style%s = %s;", it.name, it.value)); - } else { - sb.add(Fmt("String Style%s = \"%s\";", it.name, it.value)); - } - } - } - S8_String string = Merge(scratch, sb, "\n"); - OS_WriteFile("../src/text_editor/generated_variables.cpp", string); - sb = {}; - - sb.add("String BaseLuaConfig = R\"==("); - { - For(gruvbox) sb.add(Fmt("local %s = %s", it.name, it.value)); - - sb.add("Color = {}"); - For(colors) sb.add(Fmt("Color.%s = %s", it.name, it.value)); - - sb.add("Style = {}"); - For(style) { - if (CHAR_IsDigit(it.value[0])) sb.add(Fmt("Style.%s = %s", it.name, it.value)); - else sb.add(Fmt("Style.%s = \"%s\"", it.name, it.value)); - } - - S8_String init_file = OS_ReadFile(scratch, "../data/init.lua"); - sb.add(init_file); - } - sb.add(")==\";"); - - sb.add("void ReloadStyle() {"); - { - For(colors) sb.add(Fmt(" Color%s = GetColor(\"%s\", Color%s);", it.name, it.name, it.name)); - For(style) { - if (CHAR_IsDigit(it.value[0])) sb.add(Fmt(" Style%s = GetStyleInt(\"%s\", Style%s);", it.name, it.name, it.name)); - else sb.add(Fmt(" Style%s = GetStyleString(\"%s\", Style%s);", it.name, it.name, it.name)); - } - } - sb.add("}"); - - string = Merge(scratch, sb, "\n"); - OS_WriteFile("../src/text_editor/generated.cpp", string); - } -} - -void GenerateLuaApi() { - MA_Scratch scratch; - S8_String file = OS_ReadFile(scratch, "../src/text_editor/lua_api.cpp"); - S8_String file2 = OS_ReadFile(scratch, "../src/text_editor/commands.cpp"); - S8_List list = S8_Split(scratch, file, "\n"); - S8_List list2 = S8_Split(scratch, file2, "\n"); - list = S8_ConcatLists(scratch, list, list2); - - S8_List funcs = {}; - for (S8_Node *it = list.first; it; it = it->next) { - S8_String s = S8_Trim(it->string); - if (S8_StartsWith(s, "int Lua_")) { - s = S8_Skip(s, 4); - S8_Seek(s, "(", 0, &s.len); - S8_Add(scratch, &funcs, s); - } - } - - S8_List sb = {}; - S8_AddF(scratch, &sb, "luaL_Reg LuaFunctions[] = {\n"); - for (S8_Node *it = funcs.first; it; it = it->next) { - S8_String lua_name = S8_Skip(it->string, 4); - S8_AddF(scratch, &sb, " {\"%.*s\", %.*s},\n", S8_Expand(lua_name), S8_Expand(it->string)); - } - S8_AddF(scratch, &sb, " {NULL, NULL},\n"); - S8_AddF(scratch, &sb, "};\n"); - - S8_String output = S8_Merge(scratch, sb); - OS_WriteFile("../src/text_editor/lua_api_generated.cpp", output); -} - -int main() { - MA_InitScratch(); - SRC_InitCache(Perm, "te.cache"); - - GenerateLuaApi(); - GenerateConfig(); - int result = CompileTextEditor(); - // int result = CompileNewPlatform(); - - if (result != 0) { - OS_DeleteFile("te.cache"); - return result; - } - - SRC_SaveCache(); - return 0; -} \ No newline at end of file diff --git a/src/test/tests.cpp b/src/test/tests.cpp index f015281..7359d7f 100644 --- a/src/test/tests.cpp +++ b/src/test/tests.cpp @@ -14,7 +14,7 @@ void AddText(String string) { event.kind = EVENT_TEXT_INPUT; event.xwindow = 1280; event.ywindow = 720; - event.text = Copy(Perm, string).data; + event.text = Copy(SysAllocator, string).data; Add(&EventPlayback, event); } @@ -26,7 +26,7 @@ void Wait(mco_coro *co) { void PlayTestOpen(mco_coro *co) { // Open file, move a little, then open again and verify the caret didn't move - String basic_env_cpp = Format(Perm, "%.*s/basic_env/basic_env.cpp", FmtString(TestDir)); + String basic_env_cpp = Format(SysAllocator, "%.*s/basic_env/basic_env.cpp", FmtString(TestDir)); AddCtrlPress(SDLK_P); Add(&EventPlayback, {EVENT_KEY_PRESS, SDLK_UP, 1280, 720}); @@ -69,7 +69,7 @@ void PlayTestOpen(mco_coro *co) { buffer_len = main.buffer->len; } - AddText(Format(Perm, "%.*s:20", FmtString(basic_env_cpp))); + AddText(Format(SysAllocator, "%.*s:20", FmtString(basic_env_cpp))); AddCtrlPress(SDLK_Q); Wait(co); @@ -98,7 +98,7 @@ void PlayTestOpen(mco_coro *co) { } void Test(mco_coro *co) { - WorkDir = Format(Perm, "%.*s/basic_env", FmtString(TestDir)); + WorkDir = Format(SysAllocator, "%.*s/basic_env", FmtString(TestDir)); PlayTestOpen(co); @@ -110,7 +110,7 @@ void InitTests() { StyleWaitForEvents = false; { String file = __FILE__; - file = NormalizePath(Perm, file); + file = NormalizePath(SysAllocator, file); file = ChopLastSlash(file); TestDir = file; } diff --git a/src/text_editor/commands_clipboard.cpp b/src/text_editor/commands_clipboard.cpp index 1403344..5c2c4d0 100644 --- a/src/text_editor/commands_clipboard.cpp +++ b/src/text_editor/commands_clipboard.cpp @@ -1,32 +1,43 @@ -void MakeSureToUseSystemAllocator_SaveInClipboard(String16 string, Array caret_strings = {}) { - Allocator sys_allocator = GetSystemAllocator(); +#if OS_WASM +EM_ASYNC_JS(void, _SetClipboardText, (const char* c_str), { + const type = "text/plain"; + const clipboardItemData = { + [type]: UTF8ToString(c_str), + }; + const clipboardItem = new ClipboardItem(clipboardItemData); + await navigator.clipboard.write([clipboardItem]); +}) - if (SavedClipboardCarets.data) { - For(SavedClipboardCarets) Dealloc(sys_allocator, &it.data); - Dealloc(sys_allocator, &SavedClipboardCarets.data); - SavedClipboardCarets.len = {}; - } +EM_ASYNC_JS(const char *, GetClipboardText, (), { + const text = await navigator.clipboard.readText(); + return stringToNewUTF8(text); +}) +#define FreeClipboardText free +#else +#define FreeClipboardText SDL_free +#define GetClipboardText SDL_GetClipboardText +#define _SetClipboardText SDL_SetClipboardText +#endif - if (SavedClipboardString.data) { - Dealloc(sys_allocator, &SavedClipboardString.data); - SavedClipboardString = {}; - } +void SetClipboardText(String16 string16) { + String string = ToString(SysAllocator, string16); + defer { Dealloc(SysAllocator, &string.data); }; + _SetClipboardText(string.data); +} - SavedClipboardString = string; - SavedClipboardCarets = caret_strings; - - Scratch scratch; - String string_to_save = ToString(scratch, SavedClipboardString).data; - SDL_SetClipboardText(string_to_save.data); +void FreeClipboardGlobals() { + For(SavedClipboardCarets) Dealloc(SysAllocator, &it.data); + SavedClipboardCarets.len = 0; + Dealloc(SysAllocator, &SavedClipboardString.data); } void SaveStringInClipboard(String16 string) { - string = Copy(GetSystemAllocator(), string); - MakeSureToUseSystemAllocator_SaveInClipboard(string); + FreeClipboardGlobals(); + SavedClipboardString = Copy(SysAllocator, string); + SetClipboardText(string); } void Command_Copy(View *view) { - Allocator sys_allocator = GetSystemAllocator(); Buffer *buffer = GetBuffer(view->active_buffer); // First, if there is no selection - select the entire line @@ -38,25 +49,27 @@ void Command_Copy(View *view) { } } - Array caret_strings = {sys_allocator}; + FreeClipboardGlobals(); + For(view->carets) { String16 string = GetString(buffer, it.range); - String16 copy = Copy(sys_allocator, string); + String16 copy = Copy(SysAllocator, string); Add(&SavedClipboardCarets, copy); } // @todo: maybe only add new line if there is no new line at the end, experiment with it - String16 final_string = Merge(sys_allocator, SavedClipboardCarets, u"\n"); - MakeSureToUseSystemAllocator_SaveInClipboard(final_string, caret_strings); + SavedClipboardString = Merge(SysAllocator, SavedClipboardCarets, u"\n"); + SetClipboardText(SavedClipboardString); } void Command_Paste(View *view) { Scratch scratch; Buffer *buffer = GetBuffer(view->active_buffer); - const char *text = SDL_GetClipboardText(); - defer { SDL_free((void *)text); }; + const char *text = GetClipboardText(); + defer { FreeClipboardText((void *)text); }; - String16 string = ToUnixString16(scratch, text); + String16 string = ToUnixString16(SysAllocator, text); + defer { Dealloc(SysAllocator, &string.data); }; // Regular paste if (string != SavedClipboardString || SavedClipboardCarets.len != view->carets.len) { diff --git a/src/text_editor/generated_config.cpp b/src/text_editor/generated_config.cpp index 5b4f922..48e70f0 100644 --- a/src/text_editor/generated_config.cpp +++ b/src/text_editor/generated_config.cpp @@ -60,7 +60,7 @@ Color.TitleBarSelection = GruvboxLight3 Color.ResizerBackground = GruvboxLight0Hard Color.ResizerOutline = GruvboxLight3 Style = {} -Style.WaitForEvents = 1 +Style.WaitForEvents = 0 Style.DrawLineNumbers = 1 Style.DrawScrollbar = 1 Style.IndentSize = 4 diff --git a/src/text_editor/intern_table.cpp b/src/text_editor/intern_table.cpp index 5d65adf..7b3391c 100644 --- a/src/text_editor/intern_table.cpp +++ b/src/text_editor/intern_table.cpp @@ -4,8 +4,9 @@ struct InternTable { }; String Intern(InternTable *table, String string) { + Allocator sys_allocator = GetSystemAllocator(); if (table->arena == NULL) { - table->arena = AllocArena(); + table->arena = AllocArena(sys_allocator, MiB(8)); table->strings.allocator = *table->arena; } String *value = table->strings.get(string); diff --git a/src/text_editor/management.cpp b/src/text_editor/management.cpp index 35e2e18..6df5aab 100644 --- a/src/text_editor/management.cpp +++ b/src/text_editor/management.cpp @@ -51,7 +51,7 @@ extern luaL_Reg LuaFunctions[]; // clipboard String16 SavedClipboardString; -Array SavedClipboardCarets; +Array SavedClipboardCarets = {SysAllocator}; String GetUniqueBufferName(String working_dir, String prepend_name, String extension = ".log") { @@ -181,7 +181,7 @@ Buffer *CreateTempBuffer(Allocator allocator, Int size = 4096) { } Window *CreateWindow(bool create_command_buffer = true) { - Window *w = AllocType(Perm, Window); + Window *w = AllocType(SysAllocator, Window); w->visible = true; w->draw_scrollbar = StyleDrawScrollbar; w->draw_line_numbers = StyleDrawLineNumbers; diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index fa83398..f85995a 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -161,6 +161,25 @@ Event TranslateSDLEvent(SDL_Event *input_event) { return event; } +#if OS_WASM +EM_JS(void, JS_SetMouseCursor, (const char *cursor_str), { + document.getElementById("canvas").style.cursor = UTF8ToString(cursor_str); +}) + +void SetMouseCursor(SDL_SystemCursor id) { + if (id == SDL_SYSTEM_CURSOR_EW_RESIZE) { + JS_SetMouseCursor("ew-resize"); + } else if (id == SDL_SYSTEM_CURSOR_NS_RESIZE) { + JS_SetMouseCursor("ns-resize"); + } else if (id == SDL_SYSTEM_CURSOR_DEFAULT) { + JS_SetMouseCursor("default"); + } else if (id == SDL_SYSTEM_CURSOR_TEXT) { + JS_SetMouseCursor("text"); + } else { + InvalidCodepath(); + } +} +#else void SetMouseCursor(SDL_SystemCursor id) { static SDL_Cursor *SDL_MouseCursor; static SDL_SystemCursor last_id; @@ -174,6 +193,7 @@ void SetMouseCursor(SDL_SystemCursor id) { last_id = id; } } +#endif void SetMouseCursor(Event event) { Scratch scratch; @@ -309,6 +329,59 @@ void Windows_SetupVCVarsall(mco_coro *co) { } } +void MainLoop() { + FrameID += 1; + + Scratch scratch; + Array frame_events = GetEventsForFrame(scratch); + For(frame_events) { + // Serialize(&ser, &it); + if (it.kind == EVENT_QUIT) { + AppIsRunning = false; + return; + } + + if (it.xwindow == 0 || it.ywindow == 0) { + int xwindow, ywindow; + SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow); + it.xwindow = xwindow; + it.ywindow = ywindow; + } + + Update(it); + } + + WaitForEvents = StyleWaitForEvents; + if (IsDocumentSelectionValid() || IsScrollbarSelectionValid() || ActiveProcesses.len) { + WaitForEvents = false; + } + + // This shouldn't matter to the state of the program, only appearance for + // the user + { + Window *window = GetActiveWindow(); + View *view = GetView(window->active_view); + Buffer *buffer = GetBuffer(view->active_buffer); + const char *dirty = buffer->dirty ? " !" : ""; + String string = Format(scratch, "%.*s%s", FmtString(buffer->name), dirty); + SDL_SetWindowTitle(SDLWindow, string.data); + } + + Event *event = GetLast(frame_events); + SetMouseCursor(*event); + LayoutWindows(event->xwindow, event->ywindow); // This is here to render changes in title bar size without a frame of delay + BeginFrameRender(event->xwindow, event->ywindow); + DrawSplits(&WindowSplits); + + Array order = GetWindowZOrder(scratch); + For(IterateInReverse(&order)) { + if (!it->visible) continue; + DrawWindow(it, *GetLast(frame_events)); + } + EndFrameRender(event->xwindow, event->ywindow, ColorBackground); + SDL_GL_SwapWindow(SDLWindow); +} + #if _WIN32 int WinMain(void *hInstance, void *hPrevInstance, const char *lpCmdLine, int nShowCmd) #else @@ -322,7 +395,6 @@ int main(int argc, char **argv) #endif BeginProfiler(); InitScratch(); - InitArena(&Perm); #if !OS_WINDOWS for (int i = 0; environ[i]; i += 1) { @@ -330,7 +402,7 @@ int main(int argc, char **argv) } #endif - WorkDir = GetWorkingDir(Perm); + WorkDir = GetWorkingDir(SysAllocator); { String sdl_config_path = SDL_GetPrefPath("krzosa", "text_editor"); if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '\\') { @@ -339,7 +411,7 @@ int main(int argc, char **argv) if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '/') { sdl_config_path = Chop(sdl_config_path, 1); // chop '/' } - ConfigDir = NormalizePath(Perm, sdl_config_path); + ConfigDir = NormalizePath(SysAllocator, sdl_config_path); SDL_free(sdl_config_path.data); } @@ -352,9 +424,15 @@ int main(int argc, char **argv) SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); +#if OS_WASM + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); +#else SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); +#endif SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); @@ -410,6 +488,7 @@ int main(int argc, char **argv) InitWindows(); InitOS(ReportWarningf); + bool testing = false; for (int i = 1; i < argc; i += 1) { String it = argv[i]; @@ -428,61 +507,16 @@ int main(int argc, char **argv) ReportConsolef("WorkDir = %.*s", FmtString(WorkDir)); InitLuaConfig(); if (testing) InitTests(); -#if _WIN32 +#if OS_WINDOWS AddCo(Windows_SetupVCVarsall); #endif - - Serializer ser = {EventBuffer}; +#if OS_WASM + emscripten_set_main_loop(MainLoop, 0, 1); +#else while (AppIsRunning) { - FrameID += 1; - - Scratch scratch; - Array frame_events = GetEventsForFrame(scratch); - For(frame_events) { - Serialize(&ser, &it); - if (it.kind == EVENT_QUIT) goto end_of_editor_loop; - - if (it.xwindow == 0 || it.ywindow == 0) { - int xwindow, ywindow; - SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow); - it.xwindow = xwindow; - it.ywindow = ywindow; - } - - Update(it); - } - - WaitForEvents = StyleWaitForEvents; - if (IsDocumentSelectionValid() || IsScrollbarSelectionValid() || ActiveProcesses.len) { - WaitForEvents = false; - } - - // This shouldn't matter to the state of the program, only appearance for - // the user - { - Window *window = GetActiveWindow(); - View *view = GetView(window->active_view); - Buffer *buffer = GetBuffer(view->active_buffer); - const char *dirty = buffer->dirty ? " !" : ""; - String string = Format(scratch, "%.*s%s", FmtString(buffer->name), dirty); - SDL_SetWindowTitle(SDLWindow, string.data); - } - - Event *event = GetLast(frame_events); - SetMouseCursor(*event); - LayoutWindows(event->xwindow, event->ywindow); // This is here to render changes in title bar size without a frame of delay - BeginFrameRender(event->xwindow, event->ywindow); - DrawSplits(&WindowSplits); - - Array order = GetWindowZOrder(scratch); - For(IterateInReverse(&order)) { - if (!it->visible) continue; - DrawWindow(it, *GetLast(frame_events)); - } - EndFrameRender(event->xwindow, event->ywindow, ColorBackground); - SDL_GL_SwapWindow(SDLWindow); + MainLoop(); } -end_of_editor_loop:; +#endif SDL_DestroyWindow(SDLWindow); SDL_Quit(); diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index 76f9b67..8acd828 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -101,8 +101,8 @@ struct BSet { // Dont use it Int FrameID; +Allocator SysAllocator = {SystemAllocator_Alloc}; String ConfigDir; -Arena Perm; float DPIScale = 1.0f; Rect2I GetVisibleCells(Window *window); diff --git a/src/text_editor/title_bar.cpp b/src/text_editor/title_bar.cpp index d218518..0ab91cd 100644 --- a/src/text_editor/title_bar.cpp +++ b/src/text_editor/title_bar.cpp @@ -53,6 +53,7 @@ void ReplaceTitleBarData(Window *window) { Range replace_range = {0, title.buffer->len}; bool found_separator = Seek(buffer_string, u" |", &replace_range.max); + // Parse the title and line if (window->id == ActiveWindow) { if (title.buffer->change_id == title.window->title_bar_last_buffer_change_id) { return; @@ -112,9 +113,16 @@ void ReplaceTitleBarData(Window *window) { AdjustCarets(edits, &caret_copy); } + // replace data up to separator with filename and stuff const char *reopen = main.buffer->changed_on_disk ? " Reopen()" : ""; String s = Format(scratch, "%.*s:%lld:%lld%s", FmtString(main.buffer->name), (long long)xy.line + 1ll, (long long)xy.col + 1ll, reopen); + For (ActiveProcesses) { + if (it.view_id == main.view->id.id) { + s = Format(scratch, "%.*s %lld", FmtString(s), (long long)it.id); + } + } + String16 string = ToString16(scratch, s); String16 string_to_replace = GetString(title.buffer, replace_range); if (string_to_replace != string) { diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index 6b44a19..942b7dc 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -1,4 +1,3 @@ -FEATURE SaveAll dirty files which are saved on disk already but dirty DESIGN try to make console less special, make stuff reusable etc. DESIGN Config file versions, when loading should be checked, at the top of the file, what to do when old version? ISSUE Ctrl+Alt+Down (DuplicateLine) doesn't work on ubuntu @@ -9,32 +8,21 @@ FEATURE KillConsole, or maybe some window targetting but how?? ISSUE I hit a case where GC tried deleting a buffer which was not attached to the buffer list, it had zeroed next, prev. It happened after iterating through directories using the ctrl + period FEATURE Search whole words, case sensitive etc. FEATURE Select all searched occurences -DESIGN Indicate maybe on the console border that a process is running in the console! also maybe exit code when exits PLATFORM Fix windows build - ISSUE What to do / how should Reopen work after we delete the file on disk in some other program? - -- Changing window properties by changing the window name? -- commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top -- Add metadata to Lua bindings so that we would get a better listing (function args?, what else?) -- Kill buffer command (it should be marked for deletion and deleted at the end of frame!) -- Delete directory/file on disk command -- Check. Convert more commands to taking buffer instead of view -- Check. Rewrite more commands to use already implemented commands? -- Lua namespaces for different kinds of commands (by ids, using main_set, using active_set)? -- Some decl/function indexing in fuzzy format - -- Fix jump scroll, the query ends up the last line on screen, kind of wacky - -- LoadWord, EncloseWord configurable? -- dump text editor state to file, restore state -- proper lister - -- ask user if he really wants to quit even though he has an unsaved buffer - popup window | we could just show ForceClose() in the titlebar -- Find matches using grep, change things in that buffer then apply those changes to all items -- group history entries so the you can rollback through multiple ones at once and not waste time on skipping whitespace trimming or deleting every character +DESIGN Changing window properties by changing the window name? +FEATURE commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top +FEATURE Kill buffer command (it should be marked for deletion and deleted at the end of frame!) +DESIGN Check. Convert more commands to taking buffer instead of view +DESIGN Check. Rewrite more commands to use already implemented commands? +FEATURE Lua namespaces for different kinds of commands (by ids, using main_set, using active_set)? +FEATURE Some decl/function indexing in fuzzy format +ISSUE? Fix jump scroll, the query ends up the last line on screen, kind of wacky +FEATURE dump text editor state to file, restore state +DESIGN ask user if he really wants to quit even though he has an unsaved buffer - popup window | we could just show ForceClose() in the titlebar +FEATURE Find matches using grep, change things in that buffer then apply those changes to all items +FEATURE group history entries so the you can rollback through multiple ones at once and not waste time on skipping whitespace trimming or deleting every character - Search and replace -- A lister which is going to show project without the full path and sorted by recency - word complete - Search all buffers in 10X style, incrementally searched results popping up on every key press (maybe we need coroutine library in C so this is easier?) - escapeing multiple cursor after ctrl + d should put the cursor where it was (probably will need to swap secondary and primary cursor for new cursor diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index bcfbbfa..fc49ab4 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -61,7 +61,7 @@ Int GetTitleBarSize(Window *window) { } WindowSplit *CreateSplitForWindow(WindowSplit *parent, Window *window) { - WindowSplit *split = AllocType(Perm, WindowSplit); + WindowSplit *split = AllocType(SysAllocator, WindowSplit); split->kind = WindowSplitKind_Window; split->window = window; split->parent = parent; @@ -79,7 +79,7 @@ void SplitWindowEx(WindowSplit **node, WindowSplit *split, Window *target, Windo return; } - WindowSplit *hori = AllocType(Perm, WindowSplit); + WindowSplit *hori = AllocType(SysAllocator, WindowSplit); hori->parent = node[0]->parent; hori->kind = kind; hori->value = 0.5; @@ -156,8 +156,6 @@ https://www.lua.org/manual/5.4/ } void InitWindows() { - Allocator sys_allocator = Perm; - WindowSplit *split = &WindowSplits; split->kind = WindowSplitKind_Horizontal; split->value = (double)0.9; @@ -192,7 +190,7 @@ void InitWindows() { window->visible = false; window->z = 2; - Buffer *buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "debug")); + Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "debug")); DebugBufferID = buffer->id; buffer->no_history = true;