Working on rendering

This commit is contained in:
Krzosa Karol
2024-06-22 08:35:11 +02:00
parent a329bc2424
commit 94555d2a60
11 changed files with 258 additions and 150 deletions

View File

@@ -53,6 +53,22 @@ Library BuildZLib() {
return l; return l;
} }
void AddCommonFlags(Array<S8_String> *cmd, bool debug = true) {
cmd->add("/MP /Zi /FC /nologo");
cmd->add("/WX /W3 /wd4200 /diagnostics:column");
cmd->add("/Oi");
cmd->add("-D_CRT_SECURE_NO_WARNINGS");
if (debug) {
cmd->add("-DDEBUG_BUILD=1");
cmd->add("-DRELEASE_BUILD=0");
// cmd->add("-D_DEBUG /MDd");
} else {
cmd->add("-DDEBUG_BUILD=0");
cmd->add("-DRELEASE_BUILD=1");
cmd->add("/O2 /MT /DNDEBUG /GL");
}
}
int main() { int main() {
MA_InitScratch(); MA_InitScratch();
SRC_InitCache(Perm, "pdf_browser.cache"); SRC_InitCache(Perm, "pdf_browser.cache");
@@ -64,25 +80,12 @@ int main() {
cmd.add("cl.exe"); cmd.add("cl.exe");
cmd.add("-Fe:transcript_browser.exe"); cmd.add("-Fe:transcript_browser.exe");
cmd.add("-Fd:transcript_browser.pdb"); cmd.add("-Fd:transcript_browser.pdb");
cmd.add("/MP /Zi /FC /nologo");
cmd.add("/WX /W3 /wd4200 /diagnostics:column");
cmd.add("/Oi");
cmd.add("-std:c++20"); // semaphore cmd.add("-std:c++20"); // semaphore
AddCommonFlags(&cmd);
cmd.add("-D_CRT_SECURE_NO_WARNINGS");
if (1) {
cmd.add("-DDEBUG_BUILD=1");
cmd.add("-DRELEASE_BUILD=0");
// cmd.add("-D_DEBUG /MDd");
} else {
cmd.add("-DDEBUG_BUILD=0");
cmd.add("-DRELEASE_BUILD=1");
cmd.add("/O2 /MT /DNDEBUG /GL");
}
cmd.add("-I ../src/external/raylib/include"); cmd.add("-I ../src/external/raylib/include");
cmd.add("../src/transcript_browser/main.cpp"); cmd.add("../src/transcript_browser/main.cpp");
cmd.add("../src/transcript_browser/win32.cpp"); cmd.add("../src/basic/win32.cpp");
cmd.add("/link"); cmd.add("/link");
cmd.add("../src/external/raylib/lib/raylib.lib"); cmd.add("../src/external/raylib/lib/raylib.lib");
@@ -99,25 +102,12 @@ int main() {
cmd.add("cl.exe"); cmd.add("cl.exe");
cmd.add("-Fe:text_editor.exe"); cmd.add("-Fe:text_editor.exe");
cmd.add("-Fd:text_editor.pdb"); cmd.add("-Fd:text_editor.pdb");
cmd.add("/MP /Zi /FC /nologo");
cmd.add("/WX /W3 /wd4200 /diagnostics:column");
cmd.add("/Oi");
cmd.add("-std:c++20"); // semaphore cmd.add("-std:c++20"); // semaphore
AddCommonFlags(&cmd);
cmd.add("-D_CRT_SECURE_NO_WARNINGS");
if (1) {
cmd.add("-DDEBUG_BUILD=1");
cmd.add("-DRELEASE_BUILD=0");
// cmd.add("-D_DEBUG /MDd");
} else {
cmd.add("-DDEBUG_BUILD=0");
cmd.add("-DRELEASE_BUILD=1");
cmd.add("/O2 /MT /DNDEBUG /GL");
}
cmd.add("-I ../src/external/raylib/include"); cmd.add("-I ../src/external/raylib/include");
cmd.add("../src/text_editor/main.cpp"); cmd.add("../src/text_editor/main.cpp");
cmd.add("../src/transcript_browser/win32.cpp"); cmd.add("../src/basic/win32.cpp");
cmd.add("/link"); cmd.add("/link");
cmd.add("../src/external/raylib/lib/raylib.lib"); cmd.add("../src/external/raylib/lib/raylib.lib");

View File

@@ -90,9 +90,8 @@ T ClampBottom(T bottom, T b) {
template <class T> template <class T>
T Clamp(T value, T min, T max) { T Clamp(T value, T min, T max) {
Assert(max >= min);
if (value > max) return max;
if (value < min) return min; if (value < min) return min;
if (value > max) return max;
return value; return value;
} }
@@ -1394,6 +1393,31 @@ String SkipToLastPeriod(String s) {
return result; return result;
} }
String Merge(Allocator allocator, Array<String> list, String separator = " ") {
int64_t char_count = 0;
For(list) char_count += it.len;
if (char_count == 0) return {};
int64_t node_count = list.len;
int64_t base_size = (char_count + 1);
int64_t sep_size = (node_count - 1) * separator.len;
int64_t size = base_size + sep_size;
char *buff = (char *)AllocSize(allocator, sizeof(char) * (size + 1));
String string = {buff, 0};
For(list) {
Assert(string.len + it.len <= size);
memcpy(string.data + string.len, it.data, it.len);
string.len += it.len;
if (!list.is_last(it)) {
memcpy(string.data + string.len, separator.data, separator.len);
string.len += separator.len;
}
}
Assert(string.len == size - 1);
string.data[size] = 0;
return string;
}
#include <stdio.h> #include <stdio.h>
String FormatV(Allocator allocator, const char *data, va_list args1) { String FormatV(Allocator allocator, const char *data, va_list args1) {
va_list args2; va_list args2;

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#include "../pdf_browser/basic.h" #include "../basic/basic.h"
struct FileIter { struct FileIter {
bool is_valid; bool is_valid;

View File

@@ -1,12 +0,0 @@
#define BASIC_IMPL
#include "basic.h"
#include <string.h>
#include "read_pdf.cpp"
int main(int argc, char *argv[]) {
InitScratch();
Scratch scratch;
return (0);
}

View File

@@ -1,24 +0,0 @@
String Merge(Allocator allocator, Array<String> list, String separator = " ") {
int64_t char_count = 0;
For(list) char_count += it.len;
if (char_count == 0) return {};
int64_t node_count = list.len;
int64_t base_size = (char_count + 1);
int64_t sep_size = (node_count - 1) * separator.len;
int64_t size = base_size + sep_size;
char *buff = (char *)AllocSize(allocator, sizeof(char) * (size + 1));
String string = {buff, 0};
For(list) {
Assert(string.len + it.len <= size);
memcpy(string.data + string.len, it.data, it.len);
string.len += it.len;
if (!list.is_last(it)) {
memcpy(string.data + string.len, separator.data, separator.len);
string.len += separator.len;
}
}
Assert(string.len == size - 1);
string.data[size] = 0;
return string;
}

View File

@@ -1,27 +0,0 @@
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
void *VReserve(size_t size) {
void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
return result;
}
bool VCommit(void *p, size_t size) {
void *result = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE);
return result ? true : false;
}
bool VRelease(void *p) {
BOOL result = VirtualFree(p, 0, MEM_RELEASE);
return result ? true : false;
}
bool VDecommit(void *p, size_t size) {
BOOL result = VirtualFree(p, size, MEM_DECOMMIT);
return result ? true : false;
}

View File

@@ -9,7 +9,8 @@ much better then the rest.
First of all you can represent the cursor at the end of the buffer First of all you can represent the cursor at the end of the buffer
by doing: <buffer_len, buffer_len>. This action in itself doesn't by doing: <buffer_len, buffer_len>. This action in itself doesn't
select anything, the formation doesn't force you to index the select anything, the formation doesn't force you to index the
buffer and so on, it's reduced to a pure position. buffer and so on, it's reduced to a pure position. In the end
you can nicely represent cursors in select mode and non-select mode.
This property of being able to represent pure positions makes This property of being able to represent pure positions makes
it possible to clamp the values to the same range <0, buffer_len>, it possible to clamp the values to the same range <0, buffer_len>,
@@ -23,11 +24,21 @@ struct Range {
// <0,4> = 0,1,2,3 // <0,4> = 0,1,2,3
}; };
struct Line {
int64_t number;
Range range;
};
struct Edit { struct Edit {
Range range; Range range;
String string; String string;
}; };
// :buffer_initialized
// @todo: it's very tempting to ensure that buffer is initialized
// then we know:
// - we always have at least one thing in lines array.
// - I think it would be probably easy enough to enforce
struct Buffer { struct Buffer {
Allocator allocator; Allocator allocator;
char *data[2]; char *data[2];
@@ -47,54 +58,62 @@ Range GetRange(const Buffer &buffer) {
return result; return result;
} }
int64_t Clamp(Buffer *buffer, int64_t pos) { int64_t Clamp(const Buffer &buffer, int64_t pos) {
int64_t result = Clamp(pos, (int64_t)0, buffer->len); int64_t result = Clamp(pos, (int64_t)0, buffer.len);
return result; return result;
} }
Range Clamp(Buffer *buffer, Range range) { Range Clamp(const Buffer &buffer, Range range) {
Range result = {}; Range result = {};
result.min = Clamp(buffer, range.min); result.min = Clamp(buffer, range.min);
result.max = Clamp(buffer, range.max); result.max = Clamp(buffer, range.max);
return result; return result;
} }
Range GetEnd(const Buffer &buffer) {
Range range = {buffer.len, buffer.len};
return range;
}
void AddEdit(Array<Edit> *edits, Range range, String string) { void AddEdit(Array<Edit> *edits, Range range, String string) {
edits->add({range, string}); edits->add({range, string});
} }
bool InBounds(Buffer *buffer, int64_t pos) { bool InBounds(const Buffer &buffer, int64_t pos) {
bool result = pos >= 0 && pos < buffer->len; bool result = pos >= 0 && pos < buffer.len;
return result; return result;
} }
char GetChar(Buffer *buffer, int64_t pos) { char GetChar(const Buffer &buffer, int64_t pos) {
if (!InBounds(buffer, pos)) return 0; if (!InBounds(buffer, pos)) return 0;
return buffer->data[buffer->bi][pos]; return buffer.data[buffer.bi][pos];
} }
char *GetCharP(Buffer *buffer, int64_t pos) { char *GetCharP(const Buffer &buffer, int64_t pos) {
if (!InBounds(buffer, pos)) return 0; if (!InBounds(buffer, pos)) return 0;
return buffer->data[buffer->bi] + pos; return buffer.data[buffer.bi] + pos;
} }
String GetString(Buffer *buffer, Range range) { String GetString(const Buffer &buffer, Range range = {0, INT64_MAX}) {
range = Clamp(buffer, range); range = Clamp(buffer, range);
String result = {GetCharP(buffer, range.min), GetRangeSize(range)}; String result = {GetCharP(buffer, range.min), GetRangeSize(range)};
return result; return result;
} }
void ApplyEdits(Buffer *buffer, Array<Edit> edits) { void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
Assert(edits.len);
int64_t size_to_delete = 0; int64_t size_to_delete = 0;
int64_t size_to_insert = 0; int64_t size_to_insert = 0;
For(edits) { For(edits) {
it.range.min = Clamp(buffer, it.range.min); Assert(it.range.min >= 0);
it.range.max = Clamp(buffer, it.range.max); Assert(it.range.max >= it.range.min);
Assert(it.range.max <= buffer->len);
size_to_delete += GetRangeSize(it.range); size_to_delete += GetRangeSize(it.range);
size_to_insert += it.string.len; size_to_insert += it.string.len;
} }
#if DEBUG_BUILD #if DEBUG_BUILD
// Make sure edit ranges don't overlap
ForItem(it1, edits) { ForItem(it1, edits) {
ForItem(it2, edits) { ForItem(it2, edits) {
if (&it1 == &it2) continue; if (&it1 == &it2) continue;
@@ -176,6 +195,9 @@ void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
buffer->len = new_buffer_len; buffer->len = new_buffer_len;
// Update lines // Update lines
// Make sure we always have one line, even if the buffer is empty,
// this way we can nicely clamp things without worrying of getting
// a negative when doing (len - 1).
{ {
String delimiter = "\n"; String delimiter = "\n";
String string = {buffer->data[dsti], buffer->len}; String string = {buffer->data[dsti], buffer->len};
@@ -193,9 +215,46 @@ void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
} }
} }
int64_t AdjustUTF8Pos(Buffer *buffer, int64_t pos, int64_t direction = 1) { void InitBuffer(Buffer *buffer) {
Scratch scratch;
Array<Edit> edits = {};
AddEdit(&edits, {}, "");
ApplyEdits(buffer, edits);
}
String CopyNullTerminated(Allocator allocator, Buffer &buffer, Range range) {
String buffer_string = GetString(buffer, range);
String result = Copy(allocator, buffer_string);
return result;
}
Line GetLine(Buffer &buffer, int64_t line) {
// :buffer_initialized
// @todo: do I enfore initialized state of the buffer +
// lines array maybe should always have something
Assert(buffer.lines.len);
line = Clamp(line, (int64_t)0, buffer.lines.len - 1);
Range range = buffer.lines[line];
Line result = {line, range};
return result;
}
Line FindLine(Buffer &buffer, int64_t pos) {
For(buffer.lines) {
// The program is doing '<= it.max' so as to include the new line.
// Otherwise this function wouldn't be able to find certain positions.
if (pos >= it.min && pos <= it.max) {
Line result = {buffer.lines.get_index(it), it};
return result;
}
}
return {};
}
int64_t AdjustUTF8Pos(const Buffer &buffer, int64_t pos, int64_t direction = 1) {
int64_t result = pos; int64_t result = pos;
for (; result >= 0 && result < buffer->len;) { for (; result >= 0 && result < buffer.len;) {
char c = GetChar(buffer, pos); char c = GetChar(buffer, pos);
if (IsUTF8ContinuationByte(c)) { if (IsUTF8ContinuationByte(c)) {
result += direction; result += direction;
@@ -206,13 +265,13 @@ int64_t AdjustUTF8Pos(Buffer *buffer, int64_t pos, int64_t direction = 1) {
return result; return result;
} }
uint32_t GetUTF32(Buffer *buffer, int64_t pos, int64_t *codepoint_size) { uint32_t GetUTF32(Buffer &buffer, int64_t pos, int64_t *codepoint_size) {
if (!InBounds(buffer, pos)) { if (!InBounds(buffer, pos)) {
return 0; return 0;
} }
char *p = GetCharP(buffer, pos); char *p = GetCharP(buffer, pos);
int64_t max = buffer->len - pos; int64_t max = buffer.len - pos;
UTF32Result utf32 = UTF8ToUTF32(p, (int)max); UTF32Result utf32 = UTF8ToUTF32(p, (int)max);
Assert(utf32.error == 0); Assert(utf32.error == 0);
@@ -245,8 +304,8 @@ bool IsValid(const BufferIter &iter) {
} }
if (result) { if (result) {
Assert(!IsUTF8ContinuationByte(GetChar(iter.buffer, iter.pos))); Assert(!IsUTF8ContinuationByte(GetChar(*iter.buffer, iter.pos)));
Assert(InBounds(iter.buffer, iter.pos)); Assert(InBounds(*iter.buffer, iter.pos));
} }
return result; return result;
} }
@@ -258,19 +317,19 @@ void Advance(BufferIter *iter) {
if (iter->direction == ITERATE_FORWARD) { if (iter->direction == ITERATE_FORWARD) {
iter->pos += iter->utf8_codepoint_size; iter->pos += iter->utf8_codepoint_size;
} else { } else {
iter->pos = AdjustUTF8Pos(iter->buffer, iter->pos - 1, ITERATE_BACKWARD); iter->pos = AdjustUTF8Pos(*iter->buffer, iter->pos - 1, ITERATE_BACKWARD);
} }
if (!IsValid(*iter)) return; if (!IsValid(*iter)) return;
iter->item = GetUTF32(iter->buffer, iter->pos, &iter->utf8_codepoint_size); iter->item = GetUTF32(*iter->buffer, iter->pos, &iter->utf8_codepoint_size);
} }
BufferIter Iterate(Buffer *buffer, Range range, int64_t direction = ITERATE_FORWARD) { BufferIter Iterate(Buffer *buffer, Range range, int64_t direction = ITERATE_FORWARD) {
Assert(direction == ITERATE_FORWARD || direction == ITERATE_BACKWARD); Assert(direction == ITERATE_FORWARD || direction == ITERATE_BACKWARD);
Assert(!IsUTF8ContinuationByte(GetChar(buffer, range.min))); Assert(!IsUTF8ContinuationByte(GetChar(*buffer, range.min)));
Assert(range.max >= range.min); Assert(range.max >= range.min);
range.min = Clamp(buffer, range.min); range.min = Clamp(*buffer, range.min);
range.max = Clamp(buffer, range.max); range.max = Clamp(*buffer, range.max);
BufferIter result = {buffer, range.min, range.max, direction}; BufferIter result = {buffer, range.min, range.max, direction};
if (direction == ITERATE_BACKWARD) { if (direction == ITERATE_BACKWARD) {
@@ -292,12 +351,20 @@ void RunBufferTests() {
String string = {buffer.data[buffer.bi], buffer.len}; String string = {buffer.data[buffer.bi], buffer.len};
Assert(string == "Things and other things"); Assert(string == "Things and other things");
Assert(buffer.lines.len == 1); Assert(buffer.lines.len == 1);
Assert(GetString(&buffer, buffer.lines[0]) == "Things and other things"); Assert(GetString(buffer, buffer.lines[0]) == "Things and other things");
edits.clear(); edits.clear();
AddEdit(&edits, {1000, 1000}, " memes"); AddEdit(&edits, GetEnd(buffer), " memes");
ApplyEdits(&buffer, edits); ApplyEdits(&buffer, edits);
Assert(GetString(&buffer, buffer.lines[0]) == "Things and other things memes"); Assert(GetString(buffer, buffer.lines[0]) == "Things and other things memes");
}
{
Buffer buffer = {scratch};
Array<Edit> edits = {scratch};
edits.add({});
ApplyEdits(&buffer, edits);
Assert("" == GetString(buffer));
Assert(buffer.lines.len == 1);
} }
{ {
Buffer buffer = {scratch}; Buffer buffer = {scratch};
@@ -317,7 +384,7 @@ void RunBufferTests() {
String string = {buffer.data[buffer.bi], buffer.len}; String string = {buffer.data[buffer.bi], buffer.len};
Assert(string == "Memes dna BigOther things"); Assert(string == "Memes dna BigOther things");
Assert(buffer.lines.len == 1); Assert(buffer.lines.len == 1);
Assert(GetString(&buffer, buffer.lines[0]) == "Memes dna BigOther things"); Assert(GetString(buffer, buffer.lines[0]) == "Memes dna BigOther things");
} }
{ {
Buffer buffer = {scratch}; Buffer buffer = {scratch};
@@ -329,9 +396,9 @@ void RunBufferTests() {
}); });
ApplyEdits(&buffer, edits); ApplyEdits(&buffer, edits);
Assert(buffer.lines.len == 3); Assert(buffer.lines.len == 3);
Assert(GetString(&buffer, buffer.lines[1]) == "Things and other things"); Assert(GetString(buffer, buffer.lines[1]) == "Things and other things");
Assert(GetString(&buffer, buffer.lines[0]) == "Things and other things"); Assert(GetString(buffer, buffer.lines[0]) == "Things and other things");
Assert(GetString(&buffer, buffer.lines[2]) == ""); Assert(GetString(buffer, buffer.lines[2]) == "");
{ {
Array<char> s = {scratch}; Array<char> s = {scratch};
@@ -361,7 +428,7 @@ void RunBufferTests() {
s.add((char)iter.item); s.add((char)iter.item);
} }
String str = {s.data, s.len}; String str = {s.data, s.len};
String b = {GetCharP(&buffer, 0), buffer.len}; String b = {GetCharP(buffer, 0), buffer.len};
Assert(str == b); Assert(str == b);
} }
{ {
@@ -372,7 +439,7 @@ void RunBufferTests() {
s.add((char)iter.item); s.add((char)iter.item);
} }
String str = {s.data, s.len}; String str = {s.data, s.len};
String b = {GetCharP(&buffer, 0), buffer.len}; String b = {GetCharP(buffer, 0), buffer.len};
Assert(str.len == b.len); Assert(str.len == b.len);
} }
} }
@@ -391,11 +458,28 @@ void RunBufferTests() {
for (int i = 0; i < iters; i += 1) { for (int i = 0; i < iters; i += 1) {
ApplyEdits(&buffer, edits); ApplyEdits(&buffer, edits);
for (int64_t j = 0; j < i; j += 1) { for (int64_t j = 0; j < i; j += 1) {
String string = GetString(&buffer, {edits[0].string.len * j, edits[0].string.len * (j + 1)}); String string = GetString(buffer, {edits[0].string.len * j, edits[0].string.len * (j + 1)});
Assert(string == edits[0].string); Assert(string == edits[0].string);
} }
} }
Assert(edits[0].string.len * iters == buffer.len); Assert(edits[0].string.len * iters == buffer.len);
Assert(buffer.lines.len == iters * 2 + 1); Assert(buffer.lines.len == iters * 2 + 1);
Line l0 = FindLine(buffer, 4);
Assert(l0.number == 0);
Assert(l0.range.min == 0);
Assert(l0.range.max < 30);
Line l1 = FindLine(buffer, 30);
Assert(l1.number == 1);
Assert(l1.range.min > 20);
Assert(l1.range.max < 50);
Assert(l1.range.max == GetLine(buffer, 1).range.max);
// Make sure there are no gaps
for (int64_t i = 100; i < 600; i += 1) {
Line l2 = FindLine(buffer, i);
Assert(l2.number > 0);
}
} }
} }

View File

@@ -1,16 +1,23 @@
#define BASIC_IMPL #define BASIC_IMPL
#include "../pdf_browser/basic.h" #include "../basic/basic.h"
#include "raylib.h" #include "raylib.h"
#include "raymath.h" #include "raymath.h"
#include "buffer.cpp" #include "buffer.cpp"
Arena FrameArena;
using Vec2 = Vector2; using Vec2 = Vector2;
struct Rect2 { struct Rect2 {
Vec2 min; Vec2 min;
Vec2 max; Vec2 max;
}; };
Vec2 GetSize(Rect2 r) {
Vec2 result = {r.max.x - r.min.x, r.max.y - r.min.y};
return result;
}
Rectangle ToRectangle(Rect2 r) { Rectangle ToRectangle(Rect2 r) {
Rectangle result = {r.min.x, r.min.y, r.max.x - r.min.x, r.max.y - r.min.y}; Rectangle result = {r.min.x, r.min.y, r.max.x - r.min.x, r.max.y - r.min.y};
return result; return result;
@@ -19,12 +26,21 @@ Rectangle ToRectangle(Rect2 r) {
// Render units - positions ready to draw, y // Render units - positions ready to draw, y
// World units - positions offset by screen movement // World units - positions offset by screen movement
// Window units - positions inside the window (starts in left top of window) // Window units - positions inside the window (starts in left top of window)
// World window units // WindowWorld units - positions offset by a position inside the buffer
struct Window { struct Window {
Rect2 rect_in_world_units; Rect2 rect_in_world_units;
Vec2 window_world_to_window_units;
Array<Range> cursors;
Buffer buffer;
}; };
Vec2 WindowWorldToWindowUnits(Vec2 value, const Window &window) {
Vec2 result = Vector2Subtract(value, window.window_world_to_window_units);
return result;
}
Vec2 WorldToRenderUnits(Vec2 value, Vec2 camera_offset_world_to_render_units) { Vec2 WorldToRenderUnits(Vec2 value, Vec2 camera_offset_world_to_render_units) {
Vec2 result = Vector2Subtract(value, camera_offset_world_to_render_units); Vec2 result = Vector2Subtract(value, camera_offset_world_to_render_units);
return result; return result;
@@ -47,15 +63,22 @@ int main() {
InitScratch(); InitScratch();
RunBufferTests(); RunBufferTests();
return 0;
InitWindow(800, 600, "Hello"); InitWindow(800, 600, "Hello");
SetTargetFPS(60); SetTargetFPS(60);
InitArena(&FrameArena);
float font_size = 14; float font_size = 14;
float font_spacing = 1; float font_spacing = 1;
Font font = LoadFontEx("C:/Windows/Fonts/consola.ttf", (int)font_size, NULL, 250); Font font = LoadFontEx("C:/Windows/Fonts/consola.ttf", (int)font_size, NULL, 250);
Array<char> buffer = {}; Buffer buffer = {};
InitBuffer(&buffer);
for (int i = 0; i < 100; i += 1) {
Array<Edit> edits = {FrameArena};
AddEdit(&edits, GetEnd(buffer), Format(FrameArena, "line number: %d\n", i));
ApplyEdits(&buffer, edits);
}
Array<Window> windows = {}; Array<Window> windows = {};
windows.add({GetScreenRectRenderUnits()}); windows.add({GetScreenRectRenderUnits()});
@@ -64,38 +87,80 @@ int main() {
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsKeyDown(KEY_SPACE)) { if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsKeyDown(KEY_SPACE)) {
camera_offset_world_to_render_units = Vector2Subtract(camera_offset_world_to_render_units, GetMouseDelta()); camera_offset_world_to_render_units = Vector2Subtract(camera_offset_world_to_render_units, GetMouseDelta());
} }
{
Window *focused_window = &windows[0];
float mouse_wheel = GetMouseWheelMove() * 48;
focused_window->window_world_to_window_units.y -= mouse_wheel;
}
for (int c = GetCharPressed(); c; c = GetCharPressed()) { for (int c = GetCharPressed(); c; c = GetCharPressed()) {
Assert(c >= ' ' && c <= '~'); String string = "?";
buffer.add((char)c); UTF8Result utf8 = UTF32ToUTF8((uint32_t)c);
if (utf8.error == 0) {
string = {(char *)utf8.out_str, (int64_t)utf8.len};
}
Array<Edit> edits = {FrameArena};
AddEdit(&edits, {}, string);
ApplyEdits(&buffer, edits);
} }
BeginDrawing(); BeginDrawing();
ClearBackground(RAYWHITE); ClearBackground(RAYWHITE);
For(windows) { For(windows) {
Rect2 rect_in_render_units = { Rect2 window_rect_in_render_units = {
WorldToRenderUnits(it.rect_in_world_units.min, camera_offset_world_to_render_units), WorldToRenderUnits(it.rect_in_world_units.min, camera_offset_world_to_render_units),
WorldToRenderUnits(it.rect_in_world_units.max, camera_offset_world_to_render_units), WorldToRenderUnits(it.rect_in_world_units.max, camera_offset_world_to_render_units),
}; };
Rectangle rectangle_in_render_units = ToRectangle(rect_in_render_units); Rectangle rectangle_in_render_units = ToRectangle(window_rect_in_render_units);
DrawRectangleRec(rectangle_in_render_units, WHITE); DrawRectangleRec(rectangle_in_render_units, WHITE);
// @todo: add window bar?
// {
// Vec2 text_position_in_window_units = {};
// Vec2 text_position_in_world_units = WindowToWorldUnits(text_position_in_window_units, it);
// Vec2 text_position_in_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units);
// DrawTextEx(font, "window 1", text_position_in_render_units, font_size, font_spacing, BLACK);
// }
//
// Line rendering
//
{ {
Vec2 text_position_in_window_units = {}; Rect2 screen_rect_in_render_units = GetScreenRectRenderUnits();
Rect2 window_rect_in_render_units_clamped_to_screen = window_rect_in_render_units;
window_rect_in_render_units_clamped_to_screen.min.x = Clamp(window_rect_in_render_units_clamped_to_screen.min.x, screen_rect_in_render_units.min.x, screen_rect_in_render_units.max.x);
window_rect_in_render_units_clamped_to_screen.max.x = Clamp(window_rect_in_render_units_clamped_to_screen.max.x, screen_rect_in_render_units.min.x, screen_rect_in_render_units.max.x);
window_rect_in_render_units_clamped_to_screen.min.y = Clamp(window_rect_in_render_units_clamped_to_screen.min.y, screen_rect_in_render_units.min.y, screen_rect_in_render_units.max.y);
window_rect_in_render_units_clamped_to_screen.max.y = Clamp(window_rect_in_render_units_clamped_to_screen.max.y, screen_rect_in_render_units.min.y, screen_rect_in_render_units.max.y);
Vec2 s = GetSize(window_rect_in_render_units_clamped_to_screen);
// buffer_pixel_size := GetRectSize(text_window_rect);
// _miny := w.scroll.y / Monosize.y;
// _maxy := (w.scroll.y + buffer_pixel_size.y) / Monosize.y;
// _minx := w.scroll.x / Monosize.x;
// _maxx := (w.scroll.x + buffer_pixel_size.x) / Monosize.x;
// miny := :int(floorf(_miny));
// minx := :int(floorf(_minx));
// maxy := :int(ceilf(_maxy));
// maxx := :int(ceilf(_maxx));
float y = 0;
ForItem(line_range, buffer.lines) {
Vec2 text_position_in_world_window_units = {0, y};
y += font_size;
Vec2 text_position_in_window_units = WindowWorldToWindowUnits(text_position_in_world_window_units, it);
Vec2 text_position_in_world_units = WindowToWorldUnits(text_position_in_window_units, it); Vec2 text_position_in_world_units = WindowToWorldUnits(text_position_in_window_units, it);
Vec2 text_position_in_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units); Vec2 text_position_in_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units);
DrawTextEx(font, "window 1", text_position_in_render_units, font_size, font_spacing, BLACK);
String string = CopyNullTerminated(FrameArena, buffer, line_range);
DrawTextEx(font, string.data, text_position_in_render_units, font_size, font_spacing, BLACK);
} }
{
Vec2 text_position_in_window_units = {0, font_size};
Vec2 text_position_in_world_units = WindowToWorldUnits(text_position_in_window_units, it);
Vec2 text_position_in_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units);
buffer.add('\0');
DrawTextEx(font, buffer.data, text_position_in_render_units, font_size, font_spacing, BLACK);
buffer.pop();
} }
} }

View File

@@ -10,6 +10,14 @@
Arena Perm; Arena Perm;
/* New threading model idea
I could just spin up a bunch of threads and then
don't kill them. Just use them for searching! Each
one would have it's own xarena and so on.
*/
struct TimeString { struct TimeString {
uint16_t hour; uint16_t hour;
uint16_t minute; uint16_t minute;