Working on rendering
This commit is contained in:
@@ -53,6 +53,22 @@ Library BuildZLib() {
|
||||
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() {
|
||||
MA_InitScratch();
|
||||
SRC_InitCache(Perm, "pdf_browser.cache");
|
||||
@@ -64,25 +80,12 @@ int main() {
|
||||
cmd.add("cl.exe");
|
||||
cmd.add("-Fe:transcript_browser.exe");
|
||||
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("-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");
|
||||
}
|
||||
AddCommonFlags(&cmd);
|
||||
|
||||
cmd.add("-I ../src/external/raylib/include");
|
||||
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("../src/external/raylib/lib/raylib.lib");
|
||||
@@ -99,25 +102,12 @@ int main() {
|
||||
cmd.add("cl.exe");
|
||||
cmd.add("-Fe:text_editor.exe");
|
||||
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("-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");
|
||||
}
|
||||
AddCommonFlags(&cmd);
|
||||
|
||||
cmd.add("-I ../src/external/raylib/include");
|
||||
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("../src/external/raylib/lib/raylib.lib");
|
||||
|
||||
@@ -90,9 +90,8 @@ T ClampBottom(T bottom, T b) {
|
||||
|
||||
template <class T>
|
||||
T Clamp(T value, T min, T max) {
|
||||
Assert(max >= min);
|
||||
if (value > max) return max;
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -1394,6 +1393,31 @@ String SkipToLastPeriod(String s) {
|
||||
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>
|
||||
String FormatV(Allocator allocator, const char *data, va_list args1) {
|
||||
va_list args2;
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "../pdf_browser/basic.h"
|
||||
#include "../basic/basic.h"
|
||||
|
||||
struct FileIter {
|
||||
bool is_valid;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -9,7 +9,8 @@ much better then the rest.
|
||||
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
|
||||
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
|
||||
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
|
||||
};
|
||||
|
||||
struct Line {
|
||||
int64_t number;
|
||||
Range range;
|
||||
};
|
||||
|
||||
struct Edit {
|
||||
Range range;
|
||||
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 {
|
||||
Allocator allocator;
|
||||
char *data[2];
|
||||
@@ -47,54 +58,62 @@ Range GetRange(const Buffer &buffer) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t Clamp(Buffer *buffer, int64_t pos) {
|
||||
int64_t result = Clamp(pos, (int64_t)0, buffer->len);
|
||||
int64_t Clamp(const Buffer &buffer, int64_t pos) {
|
||||
int64_t result = Clamp(pos, (int64_t)0, buffer.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
Range Clamp(Buffer *buffer, Range range) {
|
||||
Range Clamp(const Buffer &buffer, Range range) {
|
||||
Range result = {};
|
||||
result.min = Clamp(buffer, range.min);
|
||||
result.max = Clamp(buffer, range.max);
|
||||
return result;
|
||||
}
|
||||
|
||||
Range GetEnd(const Buffer &buffer) {
|
||||
Range range = {buffer.len, buffer.len};
|
||||
return range;
|
||||
}
|
||||
|
||||
void AddEdit(Array<Edit> *edits, Range range, String string) {
|
||||
edits->add({range, string});
|
||||
}
|
||||
|
||||
bool InBounds(Buffer *buffer, int64_t pos) {
|
||||
bool result = pos >= 0 && pos < buffer->len;
|
||||
bool InBounds(const Buffer &buffer, int64_t pos) {
|
||||
bool result = pos >= 0 && pos < buffer.len;
|
||||
return result;
|
||||
}
|
||||
|
||||
char GetChar(Buffer *buffer, int64_t pos) {
|
||||
char GetChar(const Buffer &buffer, int64_t pos) {
|
||||
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;
|
||||
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);
|
||||
String result = {GetCharP(buffer, range.min), GetRangeSize(range)};
|
||||
return result;
|
||||
}
|
||||
|
||||
void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
|
||||
Assert(edits.len);
|
||||
int64_t size_to_delete = 0;
|
||||
int64_t size_to_insert = 0;
|
||||
For(edits) {
|
||||
it.range.min = Clamp(buffer, it.range.min);
|
||||
it.range.max = Clamp(buffer, it.range.max);
|
||||
Assert(it.range.min >= 0);
|
||||
Assert(it.range.max >= it.range.min);
|
||||
Assert(it.range.max <= buffer->len);
|
||||
size_to_delete += GetRangeSize(it.range);
|
||||
size_to_insert += it.string.len;
|
||||
}
|
||||
|
||||
#if DEBUG_BUILD
|
||||
// Make sure edit ranges don't overlap
|
||||
ForItem(it1, edits) {
|
||||
ForItem(it2, edits) {
|
||||
if (&it1 == &it2) continue;
|
||||
@@ -176,6 +195,9 @@ void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
|
||||
buffer->len = new_buffer_len;
|
||||
|
||||
// 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 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;
|
||||
for (; result >= 0 && result < buffer->len;) {
|
||||
for (; result >= 0 && result < buffer.len;) {
|
||||
char c = GetChar(buffer, pos);
|
||||
if (IsUTF8ContinuationByte(c)) {
|
||||
result += direction;
|
||||
@@ -206,13 +265,13 @@ int64_t AdjustUTF8Pos(Buffer *buffer, int64_t pos, int64_t direction = 1) {
|
||||
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)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *p = GetCharP(buffer, pos);
|
||||
int64_t max = buffer->len - pos;
|
||||
int64_t max = buffer.len - pos;
|
||||
UTF32Result utf32 = UTF8ToUTF32(p, (int)max);
|
||||
Assert(utf32.error == 0);
|
||||
|
||||
@@ -245,8 +304,8 @@ bool IsValid(const BufferIter &iter) {
|
||||
}
|
||||
|
||||
if (result) {
|
||||
Assert(!IsUTF8ContinuationByte(GetChar(iter.buffer, iter.pos)));
|
||||
Assert(InBounds(iter.buffer, iter.pos));
|
||||
Assert(!IsUTF8ContinuationByte(GetChar(*iter.buffer, iter.pos)));
|
||||
Assert(InBounds(*iter.buffer, iter.pos));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -258,19 +317,19 @@ void Advance(BufferIter *iter) {
|
||||
if (iter->direction == ITERATE_FORWARD) {
|
||||
iter->pos += iter->utf8_codepoint_size;
|
||||
} 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;
|
||||
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) {
|
||||
Assert(direction == ITERATE_FORWARD || direction == ITERATE_BACKWARD);
|
||||
Assert(!IsUTF8ContinuationByte(GetChar(buffer, range.min)));
|
||||
Assert(!IsUTF8ContinuationByte(GetChar(*buffer, range.min)));
|
||||
Assert(range.max >= range.min);
|
||||
range.min = Clamp(buffer, range.min);
|
||||
range.max = Clamp(buffer, range.max);
|
||||
range.min = Clamp(*buffer, range.min);
|
||||
range.max = Clamp(*buffer, range.max);
|
||||
|
||||
BufferIter result = {buffer, range.min, range.max, direction};
|
||||
if (direction == ITERATE_BACKWARD) {
|
||||
@@ -292,12 +351,20 @@ void RunBufferTests() {
|
||||
String string = {buffer.data[buffer.bi], buffer.len};
|
||||
Assert(string == "Things and other things");
|
||||
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();
|
||||
AddEdit(&edits, {1000, 1000}, " memes");
|
||||
AddEdit(&edits, GetEnd(buffer), " memes");
|
||||
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};
|
||||
@@ -317,7 +384,7 @@ void RunBufferTests() {
|
||||
String string = {buffer.data[buffer.bi], buffer.len};
|
||||
Assert(string == "Memes dna BigOther things");
|
||||
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};
|
||||
@@ -329,9 +396,9 @@ void RunBufferTests() {
|
||||
});
|
||||
ApplyEdits(&buffer, edits);
|
||||
Assert(buffer.lines.len == 3);
|
||||
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[2]) == "");
|
||||
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[2]) == "");
|
||||
|
||||
{
|
||||
Array<char> s = {scratch};
|
||||
@@ -361,7 +428,7 @@ void RunBufferTests() {
|
||||
s.add((char)iter.item);
|
||||
}
|
||||
String str = {s.data, s.len};
|
||||
String b = {GetCharP(&buffer, 0), buffer.len};
|
||||
String b = {GetCharP(buffer, 0), buffer.len};
|
||||
Assert(str == b);
|
||||
}
|
||||
{
|
||||
@@ -372,7 +439,7 @@ void RunBufferTests() {
|
||||
s.add((char)iter.item);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -391,11 +458,28 @@ void RunBufferTests() {
|
||||
for (int i = 0; i < iters; i += 1) {
|
||||
ApplyEdits(&buffer, edits);
|
||||
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(edits[0].string.len * iters == buffer.len);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,23 @@
|
||||
#define BASIC_IMPL
|
||||
#include "../pdf_browser/basic.h"
|
||||
#include "../basic/basic.h"
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
|
||||
#include "buffer.cpp"
|
||||
|
||||
Arena FrameArena;
|
||||
|
||||
using Vec2 = Vector2;
|
||||
struct Rect2 {
|
||||
Vec2 min;
|
||||
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 result = {r.min.x, r.min.y, r.max.x - r.min.x, r.max.y - r.min.y};
|
||||
return result;
|
||||
@@ -19,12 +26,21 @@ Rectangle ToRectangle(Rect2 r) {
|
||||
// Render units - positions ready to draw, y
|
||||
// World units - positions offset by screen movement
|
||||
// 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 {
|
||||
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 result = Vector2Subtract(value, camera_offset_world_to_render_units);
|
||||
return result;
|
||||
@@ -47,15 +63,22 @@ int main() {
|
||||
InitScratch();
|
||||
RunBufferTests();
|
||||
|
||||
return 0;
|
||||
InitWindow(800, 600, "Hello");
|
||||
SetTargetFPS(60);
|
||||
|
||||
InitArena(&FrameArena);
|
||||
float font_size = 14;
|
||||
float font_spacing = 1;
|
||||
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 = {};
|
||||
windows.add({GetScreenRectRenderUnits()});
|
||||
|
||||
@@ -64,38 +87,80 @@ int main() {
|
||||
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsKeyDown(KEY_SPACE)) {
|
||||
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()) {
|
||||
Assert(c >= ' ' && c <= '~');
|
||||
buffer.add((char)c);
|
||||
String string = "?";
|
||||
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();
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
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.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);
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
// @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 = {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);
|
||||
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);
|
||||
|
||||
buffer.add('\0');
|
||||
DrawTextEx(font, buffer.data, text_position_in_render_units, font_size, font_spacing, BLACK);
|
||||
buffer.pop();
|
||||
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_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units);
|
||||
|
||||
String string = CopyNullTerminated(FrameArena, buffer, line_range);
|
||||
DrawTextEx(font, string.data, text_position_in_render_units, font_size, font_spacing, BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,14 @@
|
||||
|
||||
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 {
|
||||
uint16_t hour;
|
||||
uint16_t minute;
|
||||
|
||||
Reference in New Issue
Block a user