diff --git a/app.c b/app.c index 52166d2..d9d328c 100644 --- a/app.c +++ b/app.c @@ -7,11 +7,14 @@ #include "physics.h" #include "player.h" #include "types.h" +#include "render_bundle.h" #include #include App *app_NewApp() { + render_LoadBundle("bundles.txt"); + App *app = malloc(sizeof(App)); app->input = input_NewSystem(app); diff --git a/bundles.txt b/bundles.txt new file mode 100644 index 0000000..d477d3a --- /dev/null +++ b/bundles.txt @@ -0,0 +1,21 @@ +BUNDLE info_plate +PRIM LINES +FG ffffff +BG 000000 +P 123 456 +P 456 789 +P 324 123 +P 432 123 +ENDPRIM +ENDBUNDLE + +BUNDLE info_plate2 +PRIM LINES +FG ffffff +BG 000000 +P 123 456 +P 456 789 +P 324 123 +P 432 123 +ENDPRIM +ENDBUNDLE diff --git a/main.cpp b/main.cpp index 6ba0367..7ff085d 100644 --- a/main.cpp +++ b/main.cpp @@ -56,6 +56,7 @@ int main() { } closegraph(); + app_DeleteApp(app); printf("%.6lf seconds has elapsed\n", duration_Seconds(time_Since(startup))); return 0; } diff --git a/render_bundle.c b/render_bundle.c new file mode 100644 index 0000000..009cd06 --- /dev/null +++ b/render_bundle.c @@ -0,0 +1,46 @@ + +#include "render_bundle.h" +#include "types.h" +#include "util/vector.h" + + +/* +render_Primitive *render_NewPrimitive(render_PrimitiveType type) { + render_Primitive *p = malloc(sizeof(render_Primitive)); + + p->type = type; + p->points = vector_Create(sizeof(Vec2)); + return p; +} + +void render_DeletePrimitive(render_Primitive *p) { + vector_Destroy(p->points); + free(p); +} +*/ + +void render_Push(render_Primitive *p, Vec2 point) { + vector_Push(p->points, &point); +} + + +render_Bundle *render_NewBundle(const char *name) { + render_Bundle *b = malloc(sizeof(render_Bundle)); + b->name = copy_malloc(name); + b->prims = vector_Create(sizeof(render_Primitive)); + return b; +} +void render_DeleteBundle(render_Bundle *b) { + for (int i = 0; i < vector_Size(b->prims); i++) { + render_Primitive *p = vector_At(b->prims, i); + if (p->points) + vector_Destroy(p->points); + } + vector_Destroy(b->prims); + free(b); +} + +void render_DrawBundleW(App *app, render_Bundle *b, Vec2 offset) { + for (int i = 0; i < vector_Size(b->prims); i++) + render_DrawPrimitiveW(app, vector_At(b->prims, i), offset); +} diff --git a/render_bundle.h b/render_bundle.h new file mode 100644 index 0000000..a65cbd6 --- /dev/null +++ b/render_bundle.h @@ -0,0 +1,65 @@ +#pragma once + +#include "render_util.h" +#include "types.h" +#include "util/vector.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + render_Lines, // Individial lines + render_LineStrip, // Connected lines + render_Polygon // Filled polygon +} render_PrimitiveType; + + +// render_Primitive describes one render operation. +typedef struct { + FillMode mode; // fill mode + uint32_t fg, bg; // foreground & background colors + + render_PrimitiveType type; + vector_Vector *points; // Vector of Vec2 +} render_Primitive; + +// render_Primitive *render_NewPrimitive(render_PrimitiveType type); +// void render_DeletePrimitive(render_Primitive *p); + +void render_Push(render_Primitive *p, Vec2 point); + + +typedef struct _App App; + +// Draws a primitive with the given offset in screen space. +void render_DrawPrimitiveW(App *app, render_Primitive *p, Vec2 offset); + + +// render_Bundle is a list of Primitives +typedef struct { + char *name; // Name, malloc & copied + vector_Vector *prims; // Vector of render_Primitive +} render_Bundle; + +// Creates a new bundle. Name is copied into a malloc'ed string. +render_Bundle *render_NewBundle(const char *name); +void render_DeleteBundle(render_Bundle *b); + +// Draws the bundle with the given offset in screen space. +void render_DrawBundleW(App *app, render_Bundle *b, Vec2 offset); + + +// Global bundles identified by name +extern vector_Vector *render_Bundles; + +// Appends the global bundle list with this file. +void render_LoadBundle(const char *filename); +// Finds the first bundle with this name, or NULL otherwise. +render_Bundle *render_FindBundle(const char *name); + + +#ifdef __cplusplus +} +#endif diff --git a/render_bundle_draw.cpp b/render_bundle_draw.cpp new file mode 100644 index 0000000..a03d64c --- /dev/null +++ b/render_bundle_draw.cpp @@ -0,0 +1,63 @@ + +#include "camera.h" +#include "render_bundle.h" +#include "app.h" +#include "util/vector.h" +#include "util/assert.h" +#include +#include +#include + + +namespace { +vector_Vector *buff; +} + + +extern "C" void render_DrawPrimitiveW(App *app, render_Primitive *p, Vec2 offset) { + if (buff == NULL) + buff = vector_Create(sizeof(POINT)); + vector_Clear(buff); + + // Construct the points in screen space + for (int i = 0; i < vector_Size(p->points); i++) { + Vec2 realpos = vec2_Add(*((Vec2 *)vector_At(p->points, i)), offset); + Vec2 screenpos; + if (!app->camera) { + // Really weird + fprintf(stderr, "[WARN][render_DrawPrimitiveW] called without a Camera system\n"); + screenpos = realpos; + } else + screenpos = camera_TransformVec2(app->camera, realpos); + + // Round the screen position to ints + POINT rounded; + rounded.x = (LONG)round(screenpos.x); + rounded.y = (LONG)round(screenpos.y); + vector_Push(buff, &rounded); + } + + // Set the colors + setlinecolor(p->fg); + setfillcolor(p->fg); + setbkcolor(p->bg); + + // Draw the converted primitive + switch (p->type) { + case render_Lines: + if (vector_Size(buff) % 2 != 0) + fprintf(stderr, "[WARN][render_DrawPrimitiveW] render_Lines drawed odd numbers of points"); + for (int i = 0; i < vector_Size(buff); i += 2) { + POINT p0 = *(POINT *)vector_At(buff, i); + POINT p1 = *(POINT *)vector_At(buff, i + 1); + line(p0.x, p0.y, p1.x, p1.y); + } + break; + case render_LineStrip: + polyline((POINT *)vector_Data(buff), vector_Size(buff)); + break; + case render_Polygon: + fillpolygon((POINT *)vector_Data(buff), vector_Size(buff)); + break; + } +} diff --git a/render_bundle_file.c b/render_bundle_file.c new file mode 100644 index 0000000..0aa2172 --- /dev/null +++ b/render_bundle_file.c @@ -0,0 +1,126 @@ + +#include "render_bundle.h" +#include "util/vector.h" +#include +#include +#include + + +vector_Vector *render_Bundles; +static render_Bundle *_tmpb; +static render_Primitive *_tmpp; + +// Subsequent tokens can be read by strtok(NULL, " ") +static void _render_BundleCommand(char *cmd) { + // convert CMD to upper case + for (int i = 0; i < strlen(cmd); i++) + cmd[i] = toupper(cmd[i]); + +#define CMD(str) (strcmp(cmd, str) == 0) + // Find the command + if (CMD("BUNDLE")) { + // Start a bundle + if (_tmpb != NULL) { + WARN("_tmpb!=0, you forgot to use ENDBUNDLE for the last bundle, discarding", 0); + free(_tmpb); + } + _tmpb = render_NewBundle(strtok(NULL, " ")); + + + } else if (CMD("ENDBUNDLE")) { + // commit the bundle + if (_tmpb) { + fprintf(stderr, "[_render_BundleCommand] Commiting bundle %s with %d primitives\n", _tmpb->name, vector_Size(_tmpb->prims)); + vector_Push(render_Bundles, &_tmpb); + _tmpb = NULL; + } else + WARN("_tmpb==0, ENDBUNDLE without BUNDLE first", 0); + + + } else if (CMD("PRIM")) { + // start a primitive + if (_tmpp != NULL) { + WARN("_tmpp!=0, you forgot to ENDPRIM for the last primitive, discarding", 0); + if (_tmpp->points) + vector_Destroy(_tmpp->points); + free(_tmpp); + } + _tmpp = malloc(sizeof(render_Primitive)); + _tmpp->points = vector_Create(sizeof(Vec2)); + _tmpp->fg = 0xffffff; + _tmpp->bg = 0; + + // parse the type + char *type = strtok(NULL, " "); + if (strcmp(type, "LINES")) + _tmpp->type = render_Lines; + else if (strcmp(type, "LINESTRIP")) + _tmpp->type = render_LineStrip; + else if (strcmp(type, "POLY")) + _tmpp->type = render_Polygon; + + + } else if (CMD("ENDPRIM")) { + // commit the primitive + if (_tmpb && _tmpp) { + fprintf(stderr, "[_render_BundleCommand] Commiting primitive type %d with %d points\n", _tmpp->type, vector_Size(_tmpp->points)); + vector_Push(_tmpb->prims, _tmpp); + free(_tmpp); + _tmpp = NULL; + } else + WARN("tmpb=%x, tmpp=%x, ENDPRIM when one of them is NULL", _tmpb, _tmpp); + + + } else if (CMD("P")) { + // Add a Vec2 + if (_tmpp) { + Vec2 v = vec2(strtod(strtok(NULL, " "), NULL), strtod(strtok(NULL, " "), NULL)); + vector_Push(_tmpp->points, &v); + } else + WARN("P without PRIM first", 0); + } else { + WARN("unknown command %s", cmd); + } +#undef CMD +} + + +static char linebuf[512]; + +void render_LoadBundle(const char *filename) { + if (!render_Bundles) + render_Bundles = vector_Create(sizeof(render_Bundle *)); + + FILE *f = fopen(filename, "r"); + if (!f) { + WARN("failed to open file\"%s\"", filename); + return; + } + + while (!feof(f) && fgets(linebuf, sizeof(linebuf), f)) { + while (linebuf[strlen(linebuf) - 1] == '\n') + linebuf[strlen(linebuf) - 1] = '\0'; + + char *cmd = strtok(linebuf, " "); + if (cmd == NULL) + continue; + _render_BundleCommand(cmd); + } +} + +render_Bundle *render_FindBundle(const char *name) { + if (!render_Bundles) { + WARN("called with render_Bundles=NULL (name=%s)", name); + return NULL; + } + + // brute force search. could be slow + for (int i = 0; i < vector_Size(render_Bundles); i++) { + render_Bundle *b = *(render_Bundle **)vector_At(render_Bundles, i); + if (strcmp(name, b->name) == 0) + return b; + } + + WARN("bundle \"%s\" not found", name); + return NULL; +} diff --git a/types.h b/types.h index 662c9d3..1a00d71 100644 --- a/types.h +++ b/types.h @@ -14,6 +14,8 @@ extern "C" { #define SCREEN_WIDTH 1280 #define SCREEN_HEIGHT 720 +#define WARN(fmt, ...) fprintf(stderr, "[WARN][%s] " fmt "\n", __func__, __VA_ARGS__) + static inline void *zero_malloc(size_t size) { void *d = malloc(size); @@ -21,6 +23,13 @@ static inline void *zero_malloc(size_t size) { return d; } +static inline char *copy_malloc(const char *src) { + size_t len = strlen(src); + char *p = (char *)malloc(len + 1); + memcpy(p, src, len + 1); + return p; +} + // A 2d vector of double. typedef struct {