Porting to WASM
This commit is contained in:
2
build.sh
2
build.sh
@@ -48,7 +48,7 @@ if [ ! -f "lbaselib.o" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f "metaprogram.exe" ]; then
|
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 \
|
-nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g \
|
||||||
-Wno-writable-strings \
|
-Wno-writable-strings \
|
||||||
-I../src
|
-I../src
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ Color.TitleBarSelection = GruvboxLight3
|
|||||||
Color.ResizerBackground = GruvboxLight0Hard
|
Color.ResizerBackground = GruvboxLight0Hard
|
||||||
Color.ResizerOutline = GruvboxLight3
|
Color.ResizerOutline = GruvboxLight3
|
||||||
Style = {}
|
Style = {}
|
||||||
Style.WaitForEvents = 1
|
Style.WaitForEvents = 0
|
||||||
Style.DrawLineNumbers = 1
|
Style.DrawLineNumbers = 1
|
||||||
Style.DrawScrollbar = 1
|
Style.DrawScrollbar = 1
|
||||||
Style.IndentSize = 4
|
Style.IndentSize = 4
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#define OS_POSIX 1
|
#define OS_POSIX 1
|
||||||
#define OS_LINUX 1
|
#define OS_LINUX 1
|
||||||
|
#elif defined(__EMSCRIPTEN__)
|
||||||
|
#define OS_WASM 1
|
||||||
#else
|
#else
|
||||||
#error Unsupported platform
|
#error Unsupported platform
|
||||||
#endif
|
#endif
|
||||||
@@ -31,6 +33,10 @@
|
|||||||
#error Unsupported compiler
|
#error Unsupported compiler
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef OS_WASM
|
||||||
|
#define OS_WASM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef OS_MAC
|
#ifndef OS_MAC
|
||||||
#define OS_MAC 0
|
#define OS_MAC 0
|
||||||
#endif
|
#endif
|
||||||
@@ -60,14 +66,18 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
#define DebugBreak() __debugbreak()
|
#define BREAK() __debugbreak()
|
||||||
#elif OS_LINUX
|
#elif OS_LINUX
|
||||||
#define DebugBreak() raise(SIGTRAP)
|
#define BREAK() raise(SIGTRAP)
|
||||||
|
#elif OS_WASM
|
||||||
|
#include <emscripten.h>
|
||||||
|
extern "C" void JS_Breakpoint(void);
|
||||||
|
#define BREAK() JS_Breakpoint()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define Assert(x) \
|
#define Assert(x) \
|
||||||
if (!(x)) { \
|
if (!(x)) { \
|
||||||
DebugBreak(); \
|
BREAK(); \
|
||||||
}
|
}
|
||||||
#define InvalidCodepath() Assert(!"invalid codepath")
|
#define InvalidCodepath() Assert(!"invalid codepath")
|
||||||
#define ElseInvalidCodepath() else {InvalidCodepath()}
|
#define ElseInvalidCodepath() else {InvalidCodepath()}
|
||||||
@@ -1035,8 +1045,8 @@ bool VCommit(void *p, size_t size);
|
|||||||
bool VRelease(void *p, size_t size);
|
bool VRelease(void *p, size_t size);
|
||||||
bool VDecommit(void *p, size_t size);
|
bool VDecommit(void *p, size_t size);
|
||||||
|
|
||||||
void InitArena(Arena *arena, size_t reserve = GiB(4));
|
void InitArena(Arena *arena, size_t reserve = MiB(256));
|
||||||
Arena *AllocArena(size_t reserve = GiB(4));
|
Arena *AllocArena(size_t reserve = MiB(256));
|
||||||
Arena *AllocArena(Allocator allocator, size_t size);
|
Arena *AllocArena(Allocator allocator, size_t size);
|
||||||
void *PushSize(Arena *arena, size_t size);
|
void *PushSize(Arena *arena, size_t size);
|
||||||
void Release(Arena *arena);
|
void Release(Arena *arena);
|
||||||
@@ -1707,11 +1717,22 @@ void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread_local Arena *ScratchArenaPool[4];
|
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) {
|
for (int i = 0; i < Lengthof(ScratchArenaPool); i += 1) {
|
||||||
ScratchArenaPool[i] = AllocArena();
|
ScratchArenaPool[i] = AllocArena();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TempArena GetScratchEx(Arena **conflicts, int conflict_count) {
|
TempArena GetScratchEx(Arena **conflicts, int conflict_count) {
|
||||||
Arena *unoccupied = 0;
|
Arena *unoccupied = 0;
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include <spawn.h>
|
#include <spawn.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
|
||||||
|
|
||||||
void (*Error)(const char *, ...);
|
void (*Error)(const char *, ...);
|
||||||
|
|
||||||
void *VReserve(size_t size) {
|
void *VReserve(size_t size) {
|
||||||
@@ -112,7 +111,7 @@ String GetAbsolutePath(Allocator al, String path) {
|
|||||||
char *buffer = AllocArray(al, char, PATH_MAX);
|
char *buffer = AllocArray(al, char, PATH_MAX);
|
||||||
realpath(null_term.data, buffer);
|
realpath(null_term.data, buffer);
|
||||||
String result = buffer;
|
String result = buffer;
|
||||||
return buffer;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileExists(String path) {
|
bool FileExists(String path) {
|
||||||
|
|||||||
@@ -14,11 +14,7 @@ void PushWork(WorkQueue *wq, void *data, WorkQueueCallback *callback) {
|
|||||||
entry->data = data;
|
entry->data = data;
|
||||||
entry->callback = callback;
|
entry->callback = callback;
|
||||||
|
|
||||||
wq->completion_goal += 1;dex_to_read + 1) % Lengthof(wq->entries);
|
wq->completion_goal += 1;
|
||||||
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 +
|
|
||||||
_WriteBarrier();
|
_WriteBarrier();
|
||||||
wq->index_to_write = new_index;
|
wq->index_to_write = new_index;
|
||||||
ReleaseSemaphore(wq->semaphore, 1, 0);
|
ReleaseSemaphore(wq->semaphore, 1, 0);
|
||||||
@@ -27,7 +23,11 @@ void PushWork(WorkQueue *wq, void *data, WorkQueueCallback *callback) {
|
|||||||
bool TryDoingWork(WorkQueue *wq) {
|
bool TryDoingWork(WorkQueue *wq) {
|
||||||
bool should_sleep = false;
|
bool should_sleep = false;
|
||||||
int64_t original_index_to_read = wq->index_to_read;
|
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);
|
entry->callback(entry->data);
|
||||||
AtomicIncrement(&wq->completion_index);
|
AtomicIncrement(&wq->completion_index);
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/external/minicoro.h
vendored
7
src/external/minicoro.h
vendored
@@ -349,10 +349,6 @@ MCO_API const char *mco_result_description(mco_result res); /* Get the descripti
|
|||||||
|
|
||||||
#ifdef MINICORO_IMPL
|
#ifdef MINICORO_IMPL
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Minimum stack size when creating a coroutine. */
|
/* Minimum stack size when creating a coroutine. */
|
||||||
@@ -1973,9 +1969,6 @@ const char *mco_result_description(mco_result res) {
|
|||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MINICORO_IMPL */
|
#endif /* MINICORO_IMPL */
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#define BASIC_IMPL
|
#define BASIC_IMPL
|
||||||
#include "basic/basic.h"
|
#include "basic/basic.h"
|
||||||
#include "basic/filesystem.h"
|
#include "basic/filesystem.h"
|
||||||
#include "basic/unix.cpp"
|
|
||||||
int main() {
|
int main() {
|
||||||
InitScratch();
|
InitScratch();
|
||||||
|
|
||||||
@@ -14,5 +14,5 @@ int main() {
|
|||||||
Add(&array, String{"\n)==\";\n"});
|
Add(&array, String{"\n)==\";\n"});
|
||||||
String result = Merge(scratch, array, "");
|
String result = Merge(scratch, array, "");
|
||||||
WriteFile("../src/text_editor/generated_config.cpp", result);
|
WriteFile("../src/text_editor/generated_config.cpp", result);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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 {
|
struct Vertex2D {
|
||||||
Vec2 pos;
|
Vec2 pos;
|
||||||
Vec2 tex;
|
Vec2 tex;
|
||||||
@@ -23,6 +16,12 @@ struct VertexList2D {
|
|||||||
VertexNode2D *last;
|
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;
|
VertexList2D Vertices;
|
||||||
int64_t TotalVertexCount;
|
int64_t TotalVertexCount;
|
||||||
|
|
||||||
@@ -35,6 +34,155 @@ Font MainFont;
|
|||||||
Int FontLineSpacing;
|
Int FontLineSpacing;
|
||||||
Int FontCharSpacing;
|
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) {
|
void BeginFrameRender(float wx, float wy) {
|
||||||
Clear(&RenderArena);
|
Clear(&RenderArena);
|
||||||
TotalVertexCount = 0;
|
TotalVertexCount = 0;
|
||||||
@@ -43,6 +191,7 @@ void BeginFrameRender(float wx, float wy) {
|
|||||||
CurrentScissor = Rect0Size(wx, wy);
|
CurrentScissor = Rect0Size(wx, wy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- EndFrameRender for ES3 ----------
|
||||||
void EndFrameRender(float wx, float wy, Color color) {
|
void EndFrameRender(float wx, float wy, Color color) {
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glEnable(GL_SCISSOR_TEST);
|
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);
|
glClearColor(color.r, color.g, color.b, color.a);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
// Default draw using the font texture
|
// Use program and set uniforms
|
||||||
glBindProgramPipeline(Shader2D.pipeline);
|
glUseProgram(Shader2D.program);
|
||||||
float xinverse = 1.f / (wx / 2.f);
|
float xinverse = 1.f / (wx / 2.f);
|
||||||
float yinverse = 1.f / (wy / 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) {
|
for (VertexNode2D *it = Vertices.first; it; it = it->next) {
|
||||||
Rect2 rect = it->scissor;
|
Rect2 rect = it->scissor;
|
||||||
GLint x = (GLint)rect.min.x;
|
GLint x = (GLint)rect.min.x;
|
||||||
GLint y = (GLint)rect.min.y;
|
GLint y = (GLint)rect.min.y;
|
||||||
GLsizei w = (GLsizei)(rect.max.x - x);
|
GLsizei w = (GLsizei)(rect.max.x - x);
|
||||||
GLsizei h = (GLsizei)(rect.max.y - y);
|
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);
|
glScissor(x, (GLint)wy - (GLint)rect.max.y, w, h);
|
||||||
glNamedBufferSubData(VBO, 0, it->count * sizeof(Vertex2D), it->vertices);
|
|
||||||
glBindVertexArray(VAO);
|
// upload vertex data into VBO at offset 0
|
||||||
GLint s_texture = 0; // texture unit that sampler2D will use in GLSL code
|
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||||
glBindTextureUnit(s_texture, MainFont.texture_id);
|
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);
|
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 *AllocVertexNode2D(Allocator allocator, VertexList2D *list) {
|
||||||
VertexNode2D *node = AllocType(allocator, VertexNode2D);
|
VertexNode2D *node = AllocType(allocator, VertexNode2D);
|
||||||
@@ -352,9 +417,11 @@ void DrawCircle(Vec2 pos, float radius, Color color) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------- ReloadFont - replace DSA texture calls ----------
|
||||||
void ReloadFont() {
|
void ReloadFont() {
|
||||||
Int size = StyleFontSize;
|
Int size = StyleFontSize;
|
||||||
size = ClampBottom((Int)2, size);
|
size = ClampBottom((Int)2, size);
|
||||||
if (MainFont.texture_id) {
|
if (MainFont.texture_id) {
|
||||||
glDeleteTextures(1, &MainFont.texture_id);
|
glDeleteTextures(1, &MainFont.texture_id);
|
||||||
Dealloc(&MainFont.glyphs);
|
Dealloc(&MainFont.glyphs);
|
||||||
@@ -362,20 +429,25 @@ void ReloadFont() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
Atlas atlas = CreateAtlas(scratch, {2048, 2048});
|
Atlas atlas = CreateAtlas(scratch, {2048, 2048});
|
||||||
MainFont = CreateFont(&atlas, (uint32_t)size, StyleFont);
|
MainFont = CreateFont(&atlas, (uint32_t)size, StyleFont);
|
||||||
{
|
|
||||||
GLint filter = GL_NEAREST;
|
// create and fill texture with ES3-compatible API
|
||||||
if (StyleFontFilter == 1) filter = GL_LINEAR;
|
GLint filter = GL_NEAREST;
|
||||||
glCreateTextures(GL_TEXTURE_2D, 1, &atlas.texture_id);
|
if (StyleFontFilter == 1) filter = GL_LINEAR;
|
||||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MIN_FILTER, filter);
|
|
||||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MAG_FILTER, filter);
|
GLuint tex = 0;
|
||||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glGenTextures(1, &tex);
|
||||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glBindTexture(GL_TEXTURE_2D, tex);
|
||||||
glTextureStorage2D(atlas.texture_id, 1, GL_R8, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||||
glTextureSubImage2D(atlas.texture_id, 0, 0, 0, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y, GL_RED, GL_UNSIGNED_BYTE, atlas.bitmap);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||||||
}
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
MainFont.texture_id = atlas.texture_id;
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
FontCharSpacing = GetCharSpacing(&MainFont);
|
// allocate storage and upload
|
||||||
FontLineSpacing = GetLineSpacing(&MainFont);
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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<S8_String> *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<S8_String> sources;
|
|
||||||
Array<S8_String> objects;
|
|
||||||
Array<S8_String> include_paths;
|
|
||||||
Array<S8_String> defines;
|
|
||||||
Array<S8_String> 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<S8_String> 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<S8_String> 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<Library> libs = {};
|
|
||||||
// if (Profile == PROFILE_DEBUG) libs.add(PrepareSDLDynamic());
|
|
||||||
// else
|
|
||||||
libs.add(PrepareSDL());
|
|
||||||
libs.add(PrepareLua());
|
|
||||||
libs.add(PrepareGlad());
|
|
||||||
|
|
||||||
Array<S8_String> 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<Var> 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<Var> 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<Var> 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<S8_String> 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;
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@ void AddText(String string) {
|
|||||||
event.kind = EVENT_TEXT_INPUT;
|
event.kind = EVENT_TEXT_INPUT;
|
||||||
event.xwindow = 1280;
|
event.xwindow = 1280;
|
||||||
event.ywindow = 720;
|
event.ywindow = 720;
|
||||||
event.text = Copy(Perm, string).data;
|
event.text = Copy(SysAllocator, string).data;
|
||||||
Add(&EventPlayback, event);
|
Add(&EventPlayback, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ void Wait(mco_coro *co) {
|
|||||||
|
|
||||||
void PlayTestOpen(mco_coro *co) {
|
void PlayTestOpen(mco_coro *co) {
|
||||||
// Open file, move a little, then open again and verify the caret didn't move
|
// 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);
|
AddCtrlPress(SDLK_P);
|
||||||
Add(&EventPlayback, {EVENT_KEY_PRESS, SDLK_UP, 1280, 720});
|
Add(&EventPlayback, {EVENT_KEY_PRESS, SDLK_UP, 1280, 720});
|
||||||
@@ -69,7 +69,7 @@ void PlayTestOpen(mco_coro *co) {
|
|||||||
buffer_len = main.buffer->len;
|
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);
|
AddCtrlPress(SDLK_Q);
|
||||||
Wait(co);
|
Wait(co);
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ void PlayTestOpen(mco_coro *co) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Test(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);
|
PlayTestOpen(co);
|
||||||
|
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ void InitTests() {
|
|||||||
StyleWaitForEvents = false;
|
StyleWaitForEvents = false;
|
||||||
{
|
{
|
||||||
String file = __FILE__;
|
String file = __FILE__;
|
||||||
file = NormalizePath(Perm, file);
|
file = NormalizePath(SysAllocator, file);
|
||||||
file = ChopLastSlash(file);
|
file = ChopLastSlash(file);
|
||||||
TestDir = file;
|
TestDir = file;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,43 @@
|
|||||||
void MakeSureToUseSystemAllocator_SaveInClipboard(String16 string, Array<String16> caret_strings = {}) {
|
#if OS_WASM
|
||||||
Allocator sys_allocator = GetSystemAllocator();
|
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) {
|
EM_ASYNC_JS(const char *, GetClipboardText, (), {
|
||||||
For(SavedClipboardCarets) Dealloc(sys_allocator, &it.data);
|
const text = await navigator.clipboard.readText();
|
||||||
Dealloc(sys_allocator, &SavedClipboardCarets.data);
|
return stringToNewUTF8(text);
|
||||||
SavedClipboardCarets.len = {};
|
})
|
||||||
}
|
#define FreeClipboardText free
|
||||||
|
#else
|
||||||
|
#define FreeClipboardText SDL_free
|
||||||
|
#define GetClipboardText SDL_GetClipboardText
|
||||||
|
#define _SetClipboardText SDL_SetClipboardText
|
||||||
|
#endif
|
||||||
|
|
||||||
if (SavedClipboardString.data) {
|
void SetClipboardText(String16 string16) {
|
||||||
Dealloc(sys_allocator, &SavedClipboardString.data);
|
String string = ToString(SysAllocator, string16);
|
||||||
SavedClipboardString = {};
|
defer { Dealloc(SysAllocator, &string.data); };
|
||||||
}
|
_SetClipboardText(string.data);
|
||||||
|
}
|
||||||
|
|
||||||
SavedClipboardString = string;
|
void FreeClipboardGlobals() {
|
||||||
SavedClipboardCarets = caret_strings;
|
For(SavedClipboardCarets) Dealloc(SysAllocator, &it.data);
|
||||||
|
SavedClipboardCarets.len = 0;
|
||||||
Scratch scratch;
|
Dealloc(SysAllocator, &SavedClipboardString.data);
|
||||||
String string_to_save = ToString(scratch, SavedClipboardString).data;
|
|
||||||
SDL_SetClipboardText(string_to_save.data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveStringInClipboard(String16 string) {
|
void SaveStringInClipboard(String16 string) {
|
||||||
string = Copy(GetSystemAllocator(), string);
|
FreeClipboardGlobals();
|
||||||
MakeSureToUseSystemAllocator_SaveInClipboard(string);
|
SavedClipboardString = Copy(SysAllocator, string);
|
||||||
|
SetClipboardText(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Command_Copy(View *view) {
|
void Command_Copy(View *view) {
|
||||||
Allocator sys_allocator = GetSystemAllocator();
|
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
|
|
||||||
// First, if there is no selection - select the entire line
|
// First, if there is no selection - select the entire line
|
||||||
@@ -38,25 +49,27 @@ void Command_Copy(View *view) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Array<String16> caret_strings = {sys_allocator};
|
FreeClipboardGlobals();
|
||||||
|
|
||||||
For(view->carets) {
|
For(view->carets) {
|
||||||
String16 string = GetString(buffer, it.range);
|
String16 string = GetString(buffer, it.range);
|
||||||
String16 copy = Copy(sys_allocator, string);
|
String16 copy = Copy(SysAllocator, string);
|
||||||
Add(&SavedClipboardCarets, copy);
|
Add(&SavedClipboardCarets, copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo: maybe only add new line if there is no new line at the end, experiment with it
|
// @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");
|
SavedClipboardString = Merge(SysAllocator, SavedClipboardCarets, u"\n");
|
||||||
MakeSureToUseSystemAllocator_SaveInClipboard(final_string, caret_strings);
|
SetClipboardText(SavedClipboardString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Command_Paste(View *view) {
|
void Command_Paste(View *view) {
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
const char *text = SDL_GetClipboardText();
|
const char *text = GetClipboardText();
|
||||||
defer { SDL_free((void *)text); };
|
defer { FreeClipboardText((void *)text); };
|
||||||
|
|
||||||
String16 string = ToUnixString16(scratch, text);
|
String16 string = ToUnixString16(SysAllocator, text);
|
||||||
|
defer { Dealloc(SysAllocator, &string.data); };
|
||||||
|
|
||||||
// Regular paste
|
// Regular paste
|
||||||
if (string != SavedClipboardString || SavedClipboardCarets.len != view->carets.len) {
|
if (string != SavedClipboardString || SavedClipboardCarets.len != view->carets.len) {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ Color.TitleBarSelection = GruvboxLight3
|
|||||||
Color.ResizerBackground = GruvboxLight0Hard
|
Color.ResizerBackground = GruvboxLight0Hard
|
||||||
Color.ResizerOutline = GruvboxLight3
|
Color.ResizerOutline = GruvboxLight3
|
||||||
Style = {}
|
Style = {}
|
||||||
Style.WaitForEvents = 1
|
Style.WaitForEvents = 0
|
||||||
Style.DrawLineNumbers = 1
|
Style.DrawLineNumbers = 1
|
||||||
Style.DrawScrollbar = 1
|
Style.DrawScrollbar = 1
|
||||||
Style.IndentSize = 4
|
Style.IndentSize = 4
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ struct InternTable {
|
|||||||
};
|
};
|
||||||
|
|
||||||
String Intern(InternTable *table, String string) {
|
String Intern(InternTable *table, String string) {
|
||||||
|
Allocator sys_allocator = GetSystemAllocator();
|
||||||
if (table->arena == NULL) {
|
if (table->arena == NULL) {
|
||||||
table->arena = AllocArena();
|
table->arena = AllocArena(sys_allocator, MiB(8));
|
||||||
table->strings.allocator = *table->arena;
|
table->strings.allocator = *table->arena;
|
||||||
}
|
}
|
||||||
String *value = table->strings.get(string);
|
String *value = table->strings.get(string);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ extern luaL_Reg LuaFunctions[];
|
|||||||
|
|
||||||
// clipboard
|
// clipboard
|
||||||
String16 SavedClipboardString;
|
String16 SavedClipboardString;
|
||||||
Array<String16> SavedClipboardCarets;
|
Array<String16> SavedClipboardCarets = {SysAllocator};
|
||||||
|
|
||||||
|
|
||||||
String GetUniqueBufferName(String working_dir, String prepend_name, String extension = ".log") {
|
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 *CreateWindow(bool create_command_buffer = true) {
|
||||||
Window *w = AllocType(Perm, Window);
|
Window *w = AllocType(SysAllocator, Window);
|
||||||
w->visible = true;
|
w->visible = true;
|
||||||
w->draw_scrollbar = StyleDrawScrollbar;
|
w->draw_scrollbar = StyleDrawScrollbar;
|
||||||
w->draw_line_numbers = StyleDrawLineNumbers;
|
w->draw_line_numbers = StyleDrawLineNumbers;
|
||||||
|
|||||||
@@ -161,6 +161,25 @@ Event TranslateSDLEvent(SDL_Event *input_event) {
|
|||||||
return 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) {
|
void SetMouseCursor(SDL_SystemCursor id) {
|
||||||
static SDL_Cursor *SDL_MouseCursor;
|
static SDL_Cursor *SDL_MouseCursor;
|
||||||
static SDL_SystemCursor last_id;
|
static SDL_SystemCursor last_id;
|
||||||
@@ -174,6 +193,7 @@ void SetMouseCursor(SDL_SystemCursor id) {
|
|||||||
last_id = id;
|
last_id = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void SetMouseCursor(Event event) {
|
void SetMouseCursor(Event event) {
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
@@ -309,6 +329,59 @@ void Windows_SetupVCVarsall(mco_coro *co) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainLoop() {
|
||||||
|
FrameID += 1;
|
||||||
|
|
||||||
|
Scratch scratch;
|
||||||
|
Array<Event> 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<Window *> 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
|
#if _WIN32
|
||||||
int WinMain(void *hInstance, void *hPrevInstance, const char *lpCmdLine, int nShowCmd)
|
int WinMain(void *hInstance, void *hPrevInstance, const char *lpCmdLine, int nShowCmd)
|
||||||
#else
|
#else
|
||||||
@@ -322,7 +395,6 @@ int main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
BeginProfiler();
|
BeginProfiler();
|
||||||
InitScratch();
|
InitScratch();
|
||||||
InitArena(&Perm);
|
|
||||||
|
|
||||||
#if !OS_WINDOWS
|
#if !OS_WINDOWS
|
||||||
for (int i = 0; environ[i]; i += 1) {
|
for (int i = 0; environ[i]; i += 1) {
|
||||||
@@ -330,7 +402,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
WorkDir = GetWorkingDir(Perm);
|
WorkDir = GetWorkingDir(SysAllocator);
|
||||||
{
|
{
|
||||||
String sdl_config_path = SDL_GetPrefPath("krzosa", "text_editor");
|
String sdl_config_path = SDL_GetPrefPath("krzosa", "text_editor");
|
||||||
if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '\\') {
|
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] == '/') {
|
if (sdl_config_path.len && sdl_config_path.data[sdl_config_path.len - 1] == '/') {
|
||||||
sdl_config_path = Chop(sdl_config_path, 1); // chop '/'
|
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);
|
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_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
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_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
|
||||||
|
#endif
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
@@ -410,6 +488,7 @@ int main(int argc, char **argv)
|
|||||||
InitWindows();
|
InitWindows();
|
||||||
InitOS(ReportWarningf);
|
InitOS(ReportWarningf);
|
||||||
|
|
||||||
|
|
||||||
bool testing = false;
|
bool testing = false;
|
||||||
for (int i = 1; i < argc; i += 1) {
|
for (int i = 1; i < argc; i += 1) {
|
||||||
String it = argv[i];
|
String it = argv[i];
|
||||||
@@ -428,61 +507,16 @@ int main(int argc, char **argv)
|
|||||||
ReportConsolef("WorkDir = %.*s", FmtString(WorkDir));
|
ReportConsolef("WorkDir = %.*s", FmtString(WorkDir));
|
||||||
InitLuaConfig();
|
InitLuaConfig();
|
||||||
if (testing) InitTests();
|
if (testing) InitTests();
|
||||||
#if _WIN32
|
#if OS_WINDOWS
|
||||||
AddCo(Windows_SetupVCVarsall);
|
AddCo(Windows_SetupVCVarsall);
|
||||||
#endif
|
#endif
|
||||||
|
#if OS_WASM
|
||||||
Serializer ser = {EventBuffer};
|
emscripten_set_main_loop(MainLoop, 0, 1);
|
||||||
|
#else
|
||||||
while (AppIsRunning) {
|
while (AppIsRunning) {
|
||||||
FrameID += 1;
|
MainLoop();
|
||||||
|
|
||||||
Scratch scratch;
|
|
||||||
Array<Event> 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<Window *> 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);
|
|
||||||
}
|
}
|
||||||
end_of_editor_loop:;
|
#endif
|
||||||
|
|
||||||
SDL_DestroyWindow(SDLWindow);
|
SDL_DestroyWindow(SDLWindow);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
|||||||
@@ -101,8 +101,8 @@ struct BSet {
|
|||||||
// Dont use it
|
// Dont use it
|
||||||
Int FrameID;
|
Int FrameID;
|
||||||
|
|
||||||
|
Allocator SysAllocator = {SystemAllocator_Alloc};
|
||||||
String ConfigDir;
|
String ConfigDir;
|
||||||
Arena Perm;
|
|
||||||
float DPIScale = 1.0f;
|
float DPIScale = 1.0f;
|
||||||
|
|
||||||
Rect2I GetVisibleCells(Window *window);
|
Rect2I GetVisibleCells(Window *window);
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ void ReplaceTitleBarData(Window *window) {
|
|||||||
Range replace_range = {0, title.buffer->len};
|
Range replace_range = {0, title.buffer->len};
|
||||||
bool found_separator = Seek(buffer_string, u" |", &replace_range.max);
|
bool found_separator = Seek(buffer_string, u" |", &replace_range.max);
|
||||||
|
|
||||||
|
// Parse the title and line
|
||||||
if (window->id == ActiveWindow) {
|
if (window->id == ActiveWindow) {
|
||||||
if (title.buffer->change_id == title.window->title_bar_last_buffer_change_id) {
|
if (title.buffer->change_id == title.window->title_bar_last_buffer_change_id) {
|
||||||
return;
|
return;
|
||||||
@@ -112,9 +113,16 @@ void ReplaceTitleBarData(Window *window) {
|
|||||||
AdjustCarets(edits, &caret_copy);
|
AdjustCarets(edits, &caret_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// replace data up to separator with filename and stuff
|
// replace data up to separator with filename and stuff
|
||||||
const char *reopen = main.buffer->changed_on_disk ? " Reopen()" : "";
|
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);
|
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 = ToString16(scratch, s);
|
||||||
String16 string_to_replace = GetString(title.buffer, replace_range);
|
String16 string_to_replace = GetString(title.buffer, replace_range);
|
||||||
if (string_to_replace != string) {
|
if (string_to_replace != string) {
|
||||||
|
|||||||
@@ -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 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?
|
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
|
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
|
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 Search whole words, case sensitive etc.
|
||||||
FEATURE Select all searched occurences
|
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
|
PLATFORM Fix windows build
|
||||||
|
|
||||||
ISSUE What to do / how should Reopen work after we delete the file on disk in some other program?
|
ISSUE What to do / how should Reopen work after we delete the file on disk in some other program?
|
||||||
|
DESIGN Changing window properties by changing the window name?
|
||||||
- Changing window properties by changing the window name?
|
FEATURE commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top
|
||||||
- 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!)
|
||||||
- Add metadata to Lua bindings so that we would get a better listing (function args?, what else?)
|
DESIGN Check. Convert more commands to taking buffer instead of view
|
||||||
- Kill buffer command (it should be marked for deletion and deleted at the end of frame!)
|
DESIGN Check. Rewrite more commands to use already implemented commands?
|
||||||
- Delete directory/file on disk command
|
FEATURE Lua namespaces for different kinds of commands (by ids, using main_set, using active_set)?
|
||||||
- Check. Convert more commands to taking buffer instead of view
|
FEATURE Some decl/function indexing in fuzzy format
|
||||||
- Check. Rewrite more commands to use already implemented commands?
|
ISSUE? Fix jump scroll, the query ends up the last line on screen, kind of wacky
|
||||||
- Lua namespaces for different kinds of commands (by ids, using main_set, using active_set)?
|
FEATURE dump text editor state to file, restore state
|
||||||
- Some decl/function indexing in fuzzy format
|
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
|
||||||
- Fix jump scroll, the query ends up the last line on screen, kind of wacky
|
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
|
||||||
|
|
||||||
- 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
|
|
||||||
- Search and replace
|
- Search and replace
|
||||||
- A lister which is going to show project without the full path and sorted by recency
|
|
||||||
- word complete
|
- 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?)
|
- 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
|
- 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
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ Int GetTitleBarSize(Window *window) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WindowSplit *CreateSplitForWindow(WindowSplit *parent, Window *window) {
|
WindowSplit *CreateSplitForWindow(WindowSplit *parent, Window *window) {
|
||||||
WindowSplit *split = AllocType(Perm, WindowSplit);
|
WindowSplit *split = AllocType(SysAllocator, WindowSplit);
|
||||||
split->kind = WindowSplitKind_Window;
|
split->kind = WindowSplitKind_Window;
|
||||||
split->window = window;
|
split->window = window;
|
||||||
split->parent = parent;
|
split->parent = parent;
|
||||||
@@ -79,7 +79,7 @@ void SplitWindowEx(WindowSplit **node, WindowSplit *split, Window *target, Windo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowSplit *hori = AllocType(Perm, WindowSplit);
|
WindowSplit *hori = AllocType(SysAllocator, WindowSplit);
|
||||||
hori->parent = node[0]->parent;
|
hori->parent = node[0]->parent;
|
||||||
hori->kind = kind;
|
hori->kind = kind;
|
||||||
hori->value = 0.5;
|
hori->value = 0.5;
|
||||||
@@ -156,8 +156,6 @@ https://www.lua.org/manual/5.4/
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InitWindows() {
|
void InitWindows() {
|
||||||
Allocator sys_allocator = Perm;
|
|
||||||
|
|
||||||
WindowSplit *split = &WindowSplits;
|
WindowSplit *split = &WindowSplits;
|
||||||
split->kind = WindowSplitKind_Horizontal;
|
split->kind = WindowSplitKind_Horizontal;
|
||||||
split->value = (double)0.9;
|
split->value = (double)0.9;
|
||||||
@@ -192,7 +190,7 @@ void InitWindows() {
|
|||||||
window->visible = false;
|
window->visible = false;
|
||||||
window->z = 2;
|
window->z = 2;
|
||||||
|
|
||||||
Buffer *buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "debug"));
|
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "debug"));
|
||||||
DebugBufferID = buffer->id;
|
DebugBufferID = buffer->id;
|
||||||
buffer->no_history = true;
|
buffer->no_history = true;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user