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;