yterm

commit 9ba204cc3741c2c54c2e2511c47be3a0ab68338a

Author: mesyeti <mesyeti@mesyeti.uk>

screen/buffer renderer - but the CPU is being melted

 source/app.c | 40 +++++++++++++++++++++++
 source/app.h | 17 ++++++++++
 source/backends/glLegacy.c | 6 +++
 source/bitmapFont.c | 47 +++++++++++++++++++++++++++
 source/bitmapFont.h | 17 ++++++++++
 source/buffer.c | 41 ++++++++++++++++++++++++
 source/buffer.h | 38 ++++++++++++++++++++++
 source/char.h | 8 ++++
 source/log.c | 39 ----------------------
 source/log.h | 2 -
 source/main.c | 9 +++++
 source/screen.c | 68 ++++++++++++++++++++++++++++++++++++++++
 source/screen.h | 18 ++++++++++
 source/text.c | 55 ++++++++++++++++++++++++++++++++
 source/text.h | 25 ++++++++++++++
 source/theme.c | 25 ++++++++++++++
 source/theme.h | 17 ++++++++++
 source/video.c | 13 -------
 source/video.h | 4 +


diff --git a/assets/default_7x16.png b/assets/default_7x16.png
new file mode 100644
index 0000000000000000000000000000000000000000..cb58391177867254feb9752b35577869e38b6cb0
Binary files /dev/null and b/assets/default_7x16.png differ




diff --git a/source/app.c b/source/app.c
new file mode 100644
index 0000000000000000000000000000000000000000..eb3fe559b5ed833ad311535130f65520577af76f
--- /dev/null
+++ b/source/app.c
@@ -0,0 +1,40 @@
+#include "app.h"
+#include "event.h"
+#include "screen.h"
+#include "backend.h"
+
+App app;
+
+void App_Init(void) {
+	app.running = true;
+
+	Event_Init();
+	Window_Init();
+	Video_Init("yterm");
+	Screen_Init();
+}
+
+void App_Update(void) {
+	Event e;
+
+	while (Event_Poll(&e)) {
+		switch (e.type) {
+			case EVENT_QUIT: app.running = false; break;
+			default:         continue;
+		}
+	}
+
+	Backend_Begin();
+	Backend_Clear(0, 0, 0);
+
+	Screen_Render();
+
+	Backend_FinishRender();
+}
+
+void App_Free(void) {
+	Screen_Free();
+	Video_Free();
+	Window_Quit();
+	Event_Free();
+}




diff --git a/source/app.h b/source/app.h
new file mode 100644
index 0000000000000000000000000000000000000000..7470181ff74045295309cd2f6a01a57d15948304
--- /dev/null
+++ b/source/app.h
@@ -0,0 +1,17 @@
+#ifndef YT_APP_H
+#define YT_APP_H
+
+#include "video.h"
+#include "common.h"
+
+typedef struct {
+	bool running;
+} App;
+
+extern App app;
+
+void App_Init(void);
+void App_Update(void);
+void App_Free(void);
+
+#endif




diff --git a/source/backends/glLegacy.c b/source/backends/glLegacy.c
index 61db6d5ba459a25d6cd6117a407368d0cf585e62..a64b18c47af50ed6319adbdf572b5dc545dd5963 100644
--- a/source/backends/glLegacy.c
+++ b/source/backends/glLegacy.c
@@ -87,6 +87,12 @@
 	state.ctx = SDL_GL_CreateContext(video.windows[0].window);
 	assert(SDL_GL_MakeCurrent(video.windows[0].window, state.ctx) == 0);
 
+	if (SDL_GL_SetSwapInterval(-1) == -1) {
+		if (SDL_GL_SetSwapInterval(1) == -1) {
+			Log("Failed to turn on vsync");
+		}
+	}
+
 	Log("Backend info: GL Legacy");
 
 	Log("==================");




diff --git a/source/bitmapFont.c b/source/bitmapFont.c
new file mode 100644
index 0000000000000000000000000000000000000000..c222e275de8aadebb696cf9ca79fea5104866713
--- /dev/null
+++ b/source/bitmapFont.c
@@ -0,0 +1,47 @@
+#include "util.h"
+#include "texture.h"
+#include "bitmapFont.h"
+
+BMFont BMFont_Load(const char* path, bool* success) {
+	BMFont ret = {0};
+	*success = true;
+
+	ret.texture = Texture_LoadFile(path);
+
+	if (!ret.texture) {
+		Log("Failed to load file '%s'", path);
+		*success = false;
+		return ret;
+	}
+
+	Vec2 fontSize  = Backend_GetTextureSize(ret.texture);
+	ret.charWidth  = fontSize.x / 16;
+	ret.charHeight = fontSize.y / 16;
+
+	printf("Font is %dx%d\n", fontSize.x, fontSize.y);
+	return ret;
+}
+
+void BMFont_Free(BMFont* font) {
+	Backend_FreeTexture(font->texture);
+}
+
+void BMFont_RenderChar(BMFont* font, char ch, int x, int y, ColourRGB colour) {
+	Rect dest;
+	dest.x = x;
+	dest.y = y;
+	dest.w = font->charWidth;
+	dest.h = font->charHeight;
+
+	Rect src;
+	src.x = ((int) (ch % 16)) * font->charWidth;
+	src.y = ((int) (ch / 16)) * font->charHeight;
+	src.w = font->charWidth;
+	src.h = font->charHeight;
+
+	TextureRenderOpt opt;
+	opt.doTint = true;
+	opt.tint   = (Colour) {colour.r, colour.g, colour.b, 255};
+
+	Backend_DrawTexture(font->texture, &opt, &src, &dest);
+}




diff --git a/source/bitmapFont.h b/source/bitmapFont.h
new file mode 100644
index 0000000000000000000000000000000000000000..c0b408155d3fdc775cf08a7e2031123a7342c696
--- /dev/null
+++ b/source/bitmapFont.h
@@ -0,0 +1,17 @@
+#ifndef YT_BITMAP_FONT_H
+#define YT_BITMAP_FONT_H
+
+#include "video.h"
+#include "backend.h"
+
+typedef struct {
+	Texture* texture;
+	int      charWidth;
+	int      charHeight;
+} BMFont;
+
+BMFont BMFont_Load(const char* path, bool* success);
+void   BMFont_Free(BMFont* font);
+void   BMFont_RenderChar(BMFont* font, char ch, int x, int y, ColourRGB colour);
+
+#endif




diff --git a/source/buffer.c b/source/buffer.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fc8b68cc668162f9601bf50683997a6bad6d475
--- /dev/null
+++ b/source/buffer.c
@@ -0,0 +1,41 @@
+#include "mem.h"
+#include "buffer.h"
+
+static BufCell FromChar(char ch) {
+	BufCell ret;
+	ret.ch     = ch;
+	ret.fgMode = BUF_16COL;
+	ret.bgMode = BUF_16COL;
+	ret.fg.idx = 0x7;
+	ret.bg.idx = 0x4;
+	return ret;
+}
+
+Buffer Buffer_New(int width, int height) {
+	Buffer ret;
+	ret.buf = SafeMalloc(width * height * sizeof(BufCell));
+
+	for (int i = 0; i < width * height; ++ i) {
+		ret.buf[i] = FromChar('a');
+	}
+
+	ret.width  = width;
+	ret.height = height;
+	return ret;
+}
+
+void Buffer_Free(Buffer* buf) {
+	free(buf->buf);
+}
+
+void Buffer_WriteChar(Buffer* buf, UChar ch, int x, int y) {
+	if ((x < 0) || (y < 0) || (x >= buf->width) || (y >= buf->height)) return;
+
+	buf->buf[(y * buf->width) + x] = FromChar(ch);
+}
+
+BufCell* Buffer_Get(Buffer* buf, int x, int y) {
+	if ((x < 0) || (y < 0) || (x >= buf->width) || (y >= buf->height)) return NULL;
+
+	return &buf->buf[(y * buf->width) + x];
+}




diff --git a/source/buffer.h b/source/buffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ef2d01260d3b857d75017dbfd9e00d19bb1b2e7
--- /dev/null
+++ b/source/buffer.h
@@ -0,0 +1,38 @@
+#ifndef YT_BUFFER_H
+#define YT_BUFFER_H
+
+#include "char.h"
+#include "video.h"
+
+enum {
+	BUF_DEFAULT = 0,
+	BUF_16COL,
+	BUF_256COL,
+	BUF_TC
+};
+
+typedef union {
+	uint8_t   idx;
+	ColourRGB rgb;
+} BufCol;
+
+typedef struct {
+	UChar   ch;
+	uint8_t fgMode;
+	uint8_t bgMode;
+	BufCol  fg;
+	BufCol  bg;
+} BufCell;
+
+typedef struct {
+	BufCell* buf;
+	int      width;
+	int      height;
+} Buffer;
+
+Buffer   Buffer_New(int width, int height);
+void     Buffer_Free(Buffer* buf);
+void     Buffer_WriteChar(Buffer* buf, UChar ch, int x, int y);
+BufCell* Buffer_Get(Buffer* buf, int x, int y);
+
+#endif




diff --git a/source/char.h b/source/char.h
new file mode 100644
index 0000000000000000000000000000000000000000..e05f357243625e1b17f9bb3a6e02e87928d440f5
--- /dev/null
+++ b/source/char.h
@@ -0,0 +1,8 @@
+#ifndef YT_CHAR_H
+#define YT_CHAR_H
+
+#include "common.h"
+
+typedef uint32_t UChar;
+
+#endif




diff --git a/source/log.c b/source/log.c
index 1370d53de631952710cbdb1081e8c56a9bac5d87..ba802280f85ded24f17ff62daacebb2a1051a8a0 100644
--- a/source/log.c
+++ b/source/log.c
@@ -6,23 +6,6 @@ #include "log.h"
 #include "mem.h"
 #include "window.h"
 
-static FILE* logFile = NULL;
-
-void Log_Init(void) {
-// 	logFile = fopen(AE_LOCATION "log.txt", "w");
-// 
-// 	if (!logFile) {
-// 		Warn("Cannot open log file: " AE_LOCATION "log.txt");
-// 	}
-}
-
-void Log_End(void) {
-	// if (!logFile) {
-	// 	fflush(logFile);
-	// 	fclose(logFile);
-	// }
-}
-
 // most of this is taken from vsprintf(3)
 #define FMT(RET, FORMAT) do { \
 	int     n    = 0; \
@@ -60,14 +43,6 @@ 	time(&rawTime);
 	tm = localtime(&rawTime);
 	
 	printf("[%.2d:%.2d:%.2d] %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, ret);
-	if (logFile) {
-		fprintf(
-			logFile, "[%.2d:%.2d:%.2d] %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec,
-			ret
-		);
-		fflush(logFile);
-	}
-
 	free(ret);
 }
 
@@ -83,13 +58,6 @@ 	time(&rawTime);
 	tm = localtime(&rawTime);
 	
 	printf("[%.2d:%.2d:%.2d] %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, ret);
-	if (logFile) {
-		fprintf(
-			logFile, "[%.2d:%.2d:%.2d] %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec,
-			ret
-		);
-		fflush(logFile);
-	}
 
 	Window_MessageBox(WINDOW_MSG_ERROR, "Fatal error", ret);
 	free(ret);
@@ -108,13 +76,6 @@ 	time(&rawTime);
 	tm = localtime(&rawTime);
 	
 	printf("[%.2d:%.2d:%.2d] %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, ret);
-	if (logFile) {
-		fprintf(
-			logFile, "[%.2d:%.2d:%.2d] %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec,
-			ret
-		);
-		fflush(logFile);
-	}
 
 	Window_MessageBox(WINDOW_MSG_WARNING, "Warning", ret);
 	free(ret);




diff --git a/source/log.h b/source/log.h
index 61d7a2c15d8e3524b6a9edfe980798324053b6c2..6bf132568aa6a39a6ff597152d755b9c620b6be1 100644
--- a/source/log.h
+++ b/source/log.h
@@ -1,8 +1,6 @@
 #ifndef YT_LOG_H
 #define YT_LOG_H
 
-void Log_Init(void);
-void Log_End(void);
 void Log(const char* format, ...);
 void Error(const char* format, ...);
 void Warn(const char* format, ...);




diff --git a/source/main.c b/source/main.c
index 061ed7eefd8af6f58434de4e2c9fec463f6bf076..aa9f267a558405d678b52d18aae41f062bdb5c06 100644
--- a/source/main.c
+++ b/source/main.c
@@ -1,3 +1,12 @@
+#include "app.h"
+
 int main(void) {
+	App_Init();
+
+	while (app.running) {
+		App_Update();
+	}
+
+	App_Free();
 	return 0;
 }




diff --git a/source/screen.c b/source/screen.c
new file mode 100644
index 0000000000000000000000000000000000000000..74f2d1947ad82614ccc73e3d3cc8a54c112bc99c
--- /dev/null
+++ b/source/screen.c
@@ -0,0 +1,68 @@
+#include <assert.h>
+#include "log.h"
+#include "theme.h"
+#include "screen.h"
+#include "bitmapFont.h"
+
+Screen screen;
+
+void Screen_Init(void) {
+	Theme_Init();
+
+	// load font
+	bool   success;
+	BMFont font = BMFont_Load("assets/default_7x16.png", &success);
+
+	if (!success) {
+		Error("Failed to load font");
+		return;
+	}
+
+	screen.font = Font_FromBMFont(font);
+
+	int cw;
+	int ch;
+	Font_CharSize(&screen.font, &cw, &ch);
+
+	screen.buffer = Buffer_New(video.windows[0].width / cw, video.windows[0].height / ch);
+}
+
+void Screen_Free(void) {
+	Font_Free(&screen.font);
+	Buffer_Free(&screen.buffer);
+}
+
+static ColourRGB GetColour(bool fg, uint8_t mode, BufCol col) {
+	switch (mode) {
+		case BUF_DEFAULT: return fg? theme.fg : theme.bg;
+		case BUF_16COL:   return theme.pal16[col.idx % 16];
+		case BUF_256COL:  return theme.pal256[col.idx];
+		case BUF_TC:      return col.rgb;
+	}
+
+	assert(0);
+}
+
+void Screen_Render(void) {
+	int cw;
+	int ch;
+	Font_CharSize(&screen.font, &cw, &ch);
+
+	for (int y = 0; y < screen.buffer.height; ++ y) {
+		for (int x = 0; x < screen.buffer.width; ++ x) {
+			int cx = x * cw;
+			int cy = y * ch;
+
+			BufCell* cell = Buffer_Get(&screen.buffer, x, y);
+
+			ColourRGB fg = GetColour(true,  cell->fgMode, cell->fg);
+			ColourRGB bg = GetColour(false, cell->bgMode, cell->bg);
+
+			Rect   rect = {cx, cy, cw, ch};
+			Colour c    = (Colour) {bg.r, bg.g, bg.b, 255};
+			Backend_RenderRect(rect, c);
+
+			Font_RenderChar(&screen.font, cell->ch, cx, cy, fg);
+		}
+	}
+}




diff --git a/source/screen.h b/source/screen.h
new file mode 100644
index 0000000000000000000000000000000000000000..5cbe75da0bd9da871c2c05fd275d4413012d6b6b
--- /dev/null
+++ b/source/screen.h
@@ -0,0 +1,18 @@
+#ifndef YT_SCREEN_H
+#define YT_SCREEN_H
+
+#include "text.h"
+#include "buffer.h"
+
+typedef struct {
+	Buffer buffer;
+	Font   font;
+} Screen;
+
+extern Screen screen;
+
+void Screen_Init(void);
+void Screen_Free(void);
+void Screen_Render(void);
+
+#endif




diff --git a/source/text.c b/source/text.c
new file mode 100644
index 0000000000000000000000000000000000000000..2783f76001aef709349c90c1a73167b645ace6f1
--- /dev/null
+++ b/source/text.c
@@ -0,0 +1,55 @@
+#include <assert.h>
+#include "text.h"
+
+Font Font_FromBMFont(BMFont bm) {
+	Font ret;
+	ret.type = FONT_BITMAP;
+	ret.v.bm = bm;
+	return ret;
+}
+
+void Font_Free(Font* font) {
+	switch (font->type) {
+		case FONT_BITMAP: {
+			BMFont_Free(&font->v.bm);
+			break;
+		}
+		default: assert(0);
+	}
+}
+
+void Font_CharSize(Font* font, int* w, int* h) {
+	switch (font->type) {
+		case FONT_BITMAP: {
+			if (w) *w = font->v.bm.charWidth;
+			if (h) *h = font->v.bm.charHeight;
+			break;
+		}
+		default: assert(0);
+	}
+}
+
+void Font_RenderChar(Font* font, UChar ch, int x, int y, ColourRGB colour) {
+	switch (font->type) {
+		case FONT_BITMAP: {
+			if (ch > 255) {
+				ch = '?';
+			}
+
+			BMFont_RenderChar(&font->v.bm, (char) ch, x, y, colour);
+			break;
+		}
+		default: assert(0);
+	}
+}
+
+// void Font_RenderString(Font* font, const char* str, int x, int y) {
+// 	int cw;
+// 	Font_CharSize(font, &cw, NULL);
+// 
+// 	while (*str) {
+// 		Font_RenderChar(font, *str, x, y);
+// 		++ str;
+// 		x += cw;
+// 	}
+// }




diff --git a/source/text.h b/source/text.h
new file mode 100644
index 0000000000000000000000000000000000000000..a26131ef8fd1751c9fc90b9339645d768dc98dd3
--- /dev/null
+++ b/source/text.h
@@ -0,0 +1,25 @@
+#ifndef YT_TEXT_H
+#define YT_TEXT_H
+
+#include "char.h"
+#include "bitmapFont.h"
+
+enum {
+	FONT_BITMAP = 0,
+	FONT_TTF
+};
+
+typedef struct {
+	int type;
+
+	union {
+		BMFont bm;
+	} v;
+} Font;
+
+Font Font_FromBMFont(BMFont bm);
+void Font_Free(Font* font);
+void Font_CharSize(Font* font, int* w, int* h);
+void Font_RenderChar(Font* font, UChar ch, int x, int y, ColourRGB colour);
+
+#endif




diff --git a/source/theme.c b/source/theme.c
new file mode 100644
index 0000000000000000000000000000000000000000..661c6a251cd24257d9761ab8d7be65269213e0e3
--- /dev/null
+++ b/source/theme.c
@@ -0,0 +1,25 @@
+#include "theme.h"
+
+Theme theme;
+
+void Theme_Init(void) {
+	theme.pal16[0x0] = (ColourRGB) {0x21, 0x28, 0x30}; // black
+	theme.pal16[0x1] = (ColourRGB) {0xC5, 0x41, 0x33}; // red
+	theme.pal16[0x2] = (ColourRGB) {0x27, 0xAE, 0x60}; // green
+	theme.pal16[0x3] = (ColourRGB) {0xED, 0xB2, 0x0A}; // yellow
+	theme.pal16[0x4] = (ColourRGB) {0x24, 0x79, 0xD0}; // blue
+	theme.pal16[0x5] = (ColourRGB) {0x7D, 0x3E, 0xA0}; // magenta
+	theme.pal16[0x6] = (ColourRGB) {0x1D, 0x85, 0x79}; // cyan
+	theme.pal16[0x7] = (ColourRGB) {0xC9, 0xCC, 0xCD}; // white
+	theme.pal16[0x8] = (ColourRGB) {0x2F, 0x39, 0x43}; // grey
+	theme.pal16[0x9] = (ColourRGB) {0xE7, 0x4C, 0x3C}; // bright_red
+	theme.pal16[0xA] = (ColourRGB) {0x2E, 0xCC, 0x71}; // bright_green
+	theme.pal16[0xB] = (ColourRGB) {0xF1, 0xC4, 0x0F}; // bright_yellow
+	theme.pal16[0xC] = (ColourRGB) {0x34, 0x98, 0xDB}; // bright_blue
+	theme.pal16[0xD] = (ColourRGB) {0x9B, 0x59, 0xB6}; // bright_magenta
+	theme.pal16[0xE] = (ColourRGB) {0x2A, 0xA1, 0x98}; // bright_cyan
+	theme.pal16[0xF] = (ColourRGB) {0xEC, 0xF0, 0xF1}; // bright_white
+
+	theme.fg = (ColourRGB) {0xC9, 0xCC, 0xCD};
+	theme.bg = (ColourRGB) {0x16, 0x1C, 0x24};
+}




diff --git a/source/theme.h b/source/theme.h
new file mode 100644
index 0000000000000000000000000000000000000000..d0d1e650935ad72552ccf05f1c27bb605a907b58
--- /dev/null
+++ b/source/theme.h
@@ -0,0 +1,17 @@
+#ifndef YT_THEME_H
+#define YT_THEME_H
+
+#include "video.h"
+
+typedef struct {
+	ColourRGB pal16[16];
+	ColourRGB pal256[256];
+	ColourRGB fg;
+	ColourRGB bg;
+} Theme;
+
+extern Theme theme;
+
+void Theme_Init(void);
+
+#endif




diff --git a/source/video.c b/source/video.c
index b3595cafb47ea9807b7caeec0d31ff66ab7ee5be..3cbedc59d5b8d96eebd328df1f4134971909b6a8 100644
--- a/source/video.c
+++ b/source/video.c
@@ -19,18 +19,7 @@
 void Video_Init(const char* windowName) {
 	Backend_Init(true);
 
-	// options
-	video.fog = false;
-
-	int w;
-	int h;
-
-	w = 640;
-	h = 480;
-
-	video.windows[0]        = Window_Create(windowName, w, h);
-	video.windows[0].width  = w;
-	video.windows[0].height = h;
+	video.windows[0] = Window_Create(windowName, 640, 480);
 	Log("Created window 0");
 
 	Backend_Init(false);




diff --git a/source/video.h b/source/video.h
index 17618f53bdf71f0b5a2d0fdb908d62488a8dffa5..fee3c452964828ed8e559c0fe33093fd1b84b478 100644
--- a/source/video.h
+++ b/source/video.h
@@ -12,10 +12,12 @@ typedef struct {
 	uint8_t r, g, b, a;
 } Colour;
 
+typedef struct {
+	uint8_t r, g, b;
+} ColourRGB;
 
 typedef struct {
 	Window windows[WIN_NUM];
-	bool   fog;
 } Video;
 
 extern Video video;