commit b47747cd7e322292fc65e24858b2bac6839652fa
parent 6282e42d22db93c841e2fd8137c20ff2bf1c2b6e
Author: hhvn <dev@hhvn.uk>
Date: Fri, 19 Aug 2022 13:57:43 +0100
Smooth & performant orbits
Diffstat:
A | README | | | 18 | ++++++++++++++++++ |
M | data/Makefile | | | 4 | +++- |
M | src/data.c | | | 6 | +++--- |
A | src/db.c | | | 112 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/main.c | | | 44 | +++++++++++++++++++++++++++++++++----------- |
M | src/main.h | | | 48 | ++++++++++++++++++++++++++++++++++++++---------- |
M | src/maths.h | | | 2 | ++ |
M | src/save.c | | | 44 | +++++++++++++++++++++++++++++--------------- |
M | src/str.c | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
M | src/struct.h | | | 29 | ++++++++++++++++++++++++++++- |
M | src/style.h | | | 36 | +++++++++++++++--------------------- |
M | src/system.c | | | 57 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
M | src/ui.c | | | 470 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
A | src/views.h | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
14 files changed, 761 insertions(+), 223 deletions(-)
diff --git a/README b/README
@@ -0,0 +1,18 @@
+Concessions
+===========
+
+Aurora and this game have both made many concessions when it comes to physics
+and astronomy in order to make something playable. Some of them are listed here
+(excluding fictional tech like jump points).
+
+Physics:
+ - The movement of ships solely relies on their max speed: there is no
+ acceleration, nor gravitational effect.
+
+Astronomy:
+ - Retrograde orbits are not modelled. (Where they exist in the solar system:
+ eg, Triton and Phoebe, they are modelled as prograde orbits).
+ - All system bodies are assumed to be spherical.
+ - All oribts (excluding comets) are assumed to be spherical.
+ - Comets "orbit" in a straight line extending outward from the centre of a
+ star.
diff --git a/data/Makefile b/data/Makefile
@@ -7,7 +7,9 @@ all: $(HEADERS) sol
sol: worlds.tsv worlds-parse.awk
rm -rf sol
./worlds-parse.awk < $<
- printf "main\tsol\n" > sol/index
+ printf "main\tSol\n" > sol/index
+ printf "x\t0\n" >> sol/index
+ printf "y\t0\n" >> sol/index
# Thanks Jonathan
worlds.tsv:
diff --git a/src/data.c b/src/data.c
@@ -44,7 +44,8 @@ unsigned char settings_png[] = {
#define IMAGE_LOAD(name) \
raw_image_##name = LoadImageFromMemory(".png", \
name##_png, sizeof(name##_png)); \
- image_##name = LoadTextureFromImage(raw_image_##name)
+ image_##name = LoadTextureFromImage(raw_image_##name); \
+ UnloadImage(raw_image_##name)
void
data_load(void) {
@@ -59,8 +60,7 @@ data_load(void) {
}
#define IMAGE_UNLOAD(name) \
- UnloadTexture(image_##name); \
- UnloadImage(raw_image_##name);
+ UnloadTexture(image_##name)
void
data_unload(void) {
diff --git a/src/db.c b/src/db.c
@@ -0,0 +1,112 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "main.h"
+
+int
+vdbsetf(char *dir, char *group, char *key, char *fmt, va_list args) {
+ va_list ap;
+ char *str;
+ int ret;
+
+ va_copy(ap, args);
+ str = vsmprintf(fmt, ap);
+ va_end(ap);
+ ret = dbset(dir, group, key, str);
+ free(str);
+ return ret;
+}
+
+int
+dbsetf(char *dir, char *group, char *key, char *fmt, ...) {
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vdbsetf(dir, group, key, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+int
+dbsetint(char *dir, char *group, char *key, int val) {
+ return dbsetf(dir, group, key, "%d", val);
+}
+
+int
+dbsetfloat(char *dir, char *group, char *key, float val) {
+ return dbsetf(dir, group, key, "%f", val);
+}
+
+void
+dbsetbody(System *sys, Body *body) {
+ char *group;
+ char *parent;
+ enum BodyType type;
+
+ group = smprintf("%s/%s", sys->name, body->name);
+
+ if (body->parent)
+ parent = body->parent->name;
+ else
+ parent = sys->name;
+ dbset(save->db.systems, group, "parent", parent);
+
+ dbset(save->db.systems, group, "type", bodytype_strify(body));
+ dbsetfloat(save->db.systems, group, "radius", body->radius);
+ dbsetfloat(save->db.systems, group, "mass", body->mass);
+ dbsetfloat(save->db.systems, group, "orbdays", body->orbdays);
+ if (body->type == BODY_COMET) {
+ dbsetfloat(save->db.systems, group, "mindist", 0 - body->mindist); /* see sys_load() */
+ dbsetfloat(save->db.systems, group, "maxdist", body->maxdist);
+ dbsetfloat(save->db.systems, group, "curdist", body->curdist);
+ dbsetfloat(save->db.systems, group, "theta", body->theta);
+ dbsetfloat(save->db.systems, group, "inward", body->inward);
+ } else {
+ dbsetfloat(save->db.systems, group, "dist", body->dist);
+ dbsetfloat(save->db.systems, group, "curtheta", body->curtheta);
+ }
+ free(group);
+}
+
+int
+vdbgetf(char *dir, char *group, char *key, char *fmt, va_list args) {
+ va_list ap;
+ char *str;
+ int ret;
+
+ str = dbget(dir, group, key);
+ if (!str)
+ return EOF;
+ va_copy(ap, args);
+ ret = vsscanf(str, fmt, ap);
+ va_end(ap);
+ free(str);
+ return ret;
+}
+
+int
+dbgetf(char *dir, char *group, char *key, char *fmt, ...) {
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vdbgetf(dir, group, key, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+int
+dbgetint(char *dir, char *group, char *key) {
+ int ret;
+
+ dbgetf(dir, group, key, "%d", &ret);
+ return ret;
+}
+
+float
+dbgetfloat(char *dir, char *group, char *key) {
+ float ret;
+
+ dbgetf(dir, group, key, "%f", &ret);
+ return ret;
+}
diff --git a/src/main.c b/src/main.c
@@ -1,4 +1,5 @@
#include <stdio.h>
+#include <time.h>
#include <raylib.h>
#include "main.h"
@@ -8,18 +9,23 @@ Save *save = NULL;
int
main(void) {
- char *system;
+ int draw;
+ int view_prev = -1;
+ time_t lastevent;
ui_init();
data_load();
+ save_read(TESTSAVE);
- save = save_init(TESTSAVE);
- system = dbget(save->db.dir, "index", "selsystem");
- if (!system) system = "Sol"; /* TODO: 1. selsystem, 2. player home, 3. uhh? */
- save->system = sys_load(NULL, system);
+ lastevent = time(NULL);
+
+ ui_update_screen();
while (!WindowShouldClose()) {
- ui_clickable_update();
+ ffree();
+
+ if (IsWindowResized())
+ ui_update_screen();
if (IsKeyDown(KEY_LEFT_ALT) || IsKeyDown(KEY_RIGHT_ALT)) {
/* AAAAAAAAAAHHHHHHHHHHHH. WHY NOT JUST USE KEY_1, KEY_2..! */
@@ -31,18 +37,34 @@ main(void) {
else if (IsKeyPressed(KEY_SIX)) view_tabs.sel = 5;
}
- view_handlers[view_tabs.sel]();
+ draw = view_handlers[view_tabs.sel](view_prev != view_tabs.sel);
+
+ if (lastevent == time(NULL))
+ draw = 1;
+
+ view_prev = view_tabs.sel;
+
+ if (view_prev != view_tabs.sel ||
+ GetMouseWheelMove() ||
+ IsWindowResized() ||
+ ui_clickable_update() ||
+ IsMouseButtonDown(MOUSE_BUTTON_LEFT) ||
+ IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
+ lastevent = time(NULL);
BeginDrawing();
- ClearBackground(COL_BG);
- view_drawers[view_tabs.sel]();
+ if (draw) {
+ ClearBackground(COL_BG);
+ ui_clickable_clear();
+ view_drawers[view_tabs.sel]();
+ }
ui_draw_views();
EndDrawing();
}
+ data_unload();
ui_deinit();
-
- save_write(save);
+ save_write();
dbcleanup();
return 0;
}
diff --git a/src/main.h b/src/main.h
@@ -12,6 +12,10 @@
extern Save *save;
/* str.c */
+void * falloc(size_t size);
+void ffree(void);
+char * vsfprintf(char *fmt, va_list args);
+char * sfprintf(char *fmt, ...); /* return string allocated for current frame */
char * vsmprintf(char *fmt, va_list args);
char * smprintf(char *fmt, ...); /* return allocated string */
char * nstrdup(char *str); /* NULL-safe */
@@ -25,18 +29,27 @@ float strnum(char *str);
/* ui.c */
extern Tabs view_tabs;
-extern void (*view_handlers[UI_VIEW_LAST])(void);
+extern int (*view_handlers[UI_VIEW_LAST])(int);
extern void (*view_drawers[UI_VIEW_LAST])(void);
+extern Rect screen_rect;
+extern View_main view_main;
+extern View_sys view_sys;
void ui_init(void);
+void ui_update_screen(void);
void ui_deinit(void);
void ui_print(int x, int y, Color col, char *format, ...);
int ui_textsize(char *text);
int ui_collides(Rect rect, Vector2 point);
+int ui_onscreen(Vector2 point);
+int ui_onscreen_ring(Vector2 centre, float r);
+int ui_onscreen_circle(Vector2 centre, float r);
void ui_clickable_register(int x, int y, int w, int h, enum UiElements type, void *elem);
void ui_clickable_handle(Vector2 mouse, MouseButton button, Clickable *clickable);
-void ui_clickable_update(void);
+int ui_clickable_update(void);
+void ui_clickable_clear(void);
void ui_draw_views(void);
void ui_draw_border(int x, int y, int w, int h, int px);
+void ui_draw_ring(int x, int y, float r, Color col);
void ui_draw_tabs(int x, int y, int w, int h, Tabs *tabs);
void ui_draw_tabbed_window(int x, int y, int w, int h, Tabs *tabs);
void ui_draw_checkbox(int x, int y, Checkbox *checkbox);
@@ -46,12 +59,12 @@ Vector2 ui_vectordiff(Vector2 a, Vector2 b);
float ui_vectordist(Vector2 a, Vector2 b);
int ui_should_draw_body(Body *body, int orbit);
void ui_draw_body(Body *body);
-void ui_handle_view_main(void);
-void ui_handle_view_colonies(void);
-void ui_handle_view_fleets(void);
-void ui_handle_view_design(void);
-void ui_handle_view_sys(void);
-void ui_handle_view_settings(void);
+int ui_handle_view_main(int nowsel);
+int ui_handle_view_colonies(int nowsel);
+int ui_handle_view_fleets(int nowsel);
+int ui_handle_view_design(int nowsel);
+int ui_handle_view_sys(int nowsel);
+int ui_handle_view_settings(int nowsel);
void ui_draw_view_main(void);
void ui_draw_view_colonies(void);
void ui_draw_view_fleets(void);
@@ -65,15 +78,19 @@ char * bodytype_strify(Body *body);
Vector2 sys_vectorize(Polar polar);
Vector2 sys_vectorize_around(Vector2 around, Polar polar);
Polar sys_polarize(Vector2 vector);
+Polar sys_polarize_around(Vector2 around, Vector2 vector);
Polar sys_sum_polar(Polar absolute, Polar relative);
Vector2 sys_get_vector(Body *body);
Polar sys_get_polar(Body *body);
+float sys_add_theta(float theta, float add);
System *sys_init(char *name);
System *sys_load(System *s, char *name);
+System *sys_get(char *name);
+System *sys_default(void);
/* save.c */
-Save * save_init(char *savedir);
-void save_write(Save *s);
+void save_read(char *dir);
+void save_write(void);
/* data.c */
extern Font font;
@@ -85,3 +102,14 @@ extern Texture image_sys;
extern Texture image_settings;
void data_load(void);
void data_unload(void);
+
+/* db.c */
+int vdbsetf(char *dir, char *group, char *key, char *fmt, va_list args);
+int dbsetf(char *dir, char *group, char *key, char *fmt, ...);
+int dbsetint(char *dir, char *group, char *key, int val);
+int dbsetfloat(char *dir, char *group, char *key, float val);
+void dbsetbody(System *sys, Body *body);
+int vdbgetf(char *dir, char *group, char *key, char *fmt, va_list args);
+int dbgetf(char *dir, char *group, char *key, char *fmt, ...);
+int dbgetint(char *dir, char *group, char *key);
+float dbgetfloat(char *dir, char *group, char *key);
diff --git a/src/maths.h b/src/maths.h
@@ -16,3 +16,5 @@
#define WEEK_LEN (7 * DAY_LEN)
#define YEAR_LEN (365.25 * DAY_LEN)
#define MONTH_APPROX (YEAR_LEN / 12)
+
+#define SQUARE(a) (a * a)
diff --git a/src/save.c b/src/save.c
@@ -2,25 +2,39 @@
#include <string.h>
#include "main.h"
-Save *
-save_init(char *dir) {
- Save *ret;
+static void
+save_free(void) {
+ free(save->db.dir);
+ free(save->db.races);
+ free(save->db.systems);
+ free(save->db.fleets);
+ /* free systems? */
+ free(save);
+}
+
+void
+save_read(char *dir) {
+ char *str;
+
+ if (save)
+ save_free();
- if (!dir || !(ret = malloc(sizeof(Save))))
- return NULL;
+ if (!dir || !(save = malloc(sizeof(Save))))
+ return;
dbdeclare(dir);
- ret->db.dir = nstrdup(dir);
- ret->db.races = smprintf("%s/Races", dir);
- ret->db.systems = smprintf("%s/Systems", dir);
- ret->db.fleets = smprintf("%s/Fleets", dir);
- ret->system = NULL;
- return ret;
+ save->db.dir = nstrdup(dir);
+ save->db.races = smprintf("%s/Races", dir);
+ save->db.systems = smprintf("%s/Systems", dir);
+ save->db.fleets = smprintf("%s/Fleets", dir);
+ if ((str = dbget(save->db.dir, "index", "homesystem")))
+ save->homesys = sys_get(str);
+ return;
};
void
-save_write(Save *s) {
- if (s->system && s->system->name)
- dbset(save->db.dir, "index", "selsystem", s->system->name);
- dbwrite(s->db.dir);
+save_write(void) {
+ if (view_main.sys)
+ dbset(save->db.dir, "index", "selsystem", view_main.sys->name);
+ dbwrite(save->db.dir);
}
diff --git a/src/str.c b/src/str.c
@@ -7,6 +7,50 @@
#include <math.h>
#include "main.h"
+#define FMEMMAX 1024
+
+static void *fmem[FMEMMAX] = {NULL};
+static int fmemi = 0;
+
+/* allocate for a frame */
+void *
+falloc(size_t size) {
+ if (fmemi + 1 == FMEMMAX) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return (fmem[fmemi++] = malloc(size));
+}
+
+void
+ffree(void) {
+ while (fmemi--) {
+ free(fmem[fmemi]);
+ fmem[fmemi] = NULL;
+ }
+ fmemi = 0;
+}
+
+char *
+vsfprintf(char *fmt, va_list ap) {
+ if (fmemi + 1 == FMEMMAX) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return (fmem[fmemi++] = vsmprintf(fmt, ap));
+}
+
+char *
+sfprintf(char *fmt, ...) {
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = vsfprintf(fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
char *
vsmprintf(char *fmt, va_list args) {
va_list ap;
@@ -51,41 +95,30 @@ nstrdup(char *str) {
char *
strkmdist(float km) {
- static char *ret = NULL;
-
- free(ret);
-
if (km > GIGA)
- ret = smprintf("%.2fb km", km / GIGA);
+ return sfprintf("%.2fb km", km / GIGA);
else if (km > MEGA)
- ret = smprintf("%.2fm km", km / MEGA);
+ return sfprintf("%.2fm km", km / MEGA);
else if (km > KILO)
- ret = smprintf("%.2fk km", km / KILO);
+ return sfprintf("%.2fk km", km / KILO);
else
- ret = smprintf("%.2f km", km);
-
- return ret;
+ return sfprintf("%.2f km", km);
}
char *
strlightdist(float km) {
- static char *ret = NULL;
float ls = km * KILO / C_MS;
- free(ret);
-
if (ls > YEAR_LEN)
- ret = smprintf("%.2f ly", ls / YEAR_LEN);
+ return sfprintf("%.2f ly", ls / YEAR_LEN);
else if (ls > DAY_LEN)
- ret = smprintf("%.2f ld", ls / DAY_LEN);
+ return sfprintf("%.2f ld", ls / DAY_LEN);
else if (ls > HOUR_LEN)
- ret = smprintf("%.2f lh", ls / HOUR_LEN);
+ return sfprintf("%.2f lh", ls / HOUR_LEN);
else if (ls > MIN_LEN)
- ret = smprintf("%.2f lm", ls / MIN_LEN);
+ return sfprintf("%.2f lm", ls / MIN_LEN);
else
- ret = smprintf("%.2f ls", ls);
-
- return ret;
+ return sfprintf("%.2f ls", ls);
}
int
diff --git a/src/struct.h b/src/struct.h
@@ -56,6 +56,15 @@ typedef struct {
char *name;
Body **bodies;
size_t bodies_len;
+ Body *furthest_body;
+ struct {
+ int stars;
+ int planets;
+ int asteroids;
+ int comets;
+ int moons;
+ } num;
+ Vector2 lypos;
} System;
/* save.c */
@@ -66,7 +75,7 @@ typedef struct {
char *systems;
char *fleets;
} db;
- System *system;
+ System *homesys;
} Save;
/* ui.c */
@@ -76,6 +85,13 @@ typedef struct {
int w, h;
} Rect;
+typedef struct {
+ float w, h;
+ float diag;
+ Vector2 centre;
+ Rect rect; /* for passing to functions */
+} Screen;
+
#define TABS_MAX 16
typedef struct {
int n;
@@ -88,6 +104,7 @@ typedef struct {
} Tabs;
typedef struct {
+ int enabled;
int val;
char *label;
} Checkbox;
@@ -113,3 +130,13 @@ typedef struct {
enum UiElements type;
void *elem;
} Clickable;
+
+#include "views.h" /* unique structures */
+
+/* maths.c */
+typedef struct {
+ float median;
+ float uquart;
+ float lquart;
+ size_t elems;
+} Nstats;
diff --git a/src/style.h b/src/style.h
@@ -26,27 +26,15 @@
#undef MAGENTA
#undef RAYWHITE
-#define X_PUREWHITE 0xffffffff
-#define X_WHITE 0xe6e6e6ff
-#define X_AURORA_GREY 0x1e1e1eff
-#define X_AURORA_BLUE 0x00003cff
-#define X_DARKBLUE 0x00002cff
-#define X_AURORA_GREEN 0x649696ff
-#define X_TRANSPARENT 0x00000000
-
-#define UNHEX(col) ((Color){ \
- ((col & (0xff << 24)) >> 24), \
- ((col & (0xff << 16)) >> 16), \
- ((col & (0xff << 8)) >> 8), \
- (col & 0xff)})
-
-#define PUREWHITE UNHEX(X_PUREWHITE)
-#define WHITE UNHEX(X_WHITE)
-#define AURORA_GREY UNHEX(X_AURORA_GREY)
-#define AURORA_BLUE UNHEX(X_AURORA_BLUE)
-#define DARKBLUE UNHEX(X_DARKBLUE)
-#define AURORA_GREEN UNHEX(X_AURORA_GREEN)
-#define TRANSPARENT UNHEX(X_TRANSPARENT)
+#define PUREWHITE ((Color){ 0xff, 0xff, 0xff, 0xff })
+#define WHITE ((Color){ 0xe6, 0xe6, 0xe6, 0xff })
+#define AURORA_GREY ((Color){ 0x1e, 0x1e, 0x1e, 0xff })
+#define AURORA_BLUE ((Color){ 0x00, 0x00, 0x3c, 0xff })
+#define DARKBLUE ((Color){ 0x00, 0x00, 0x2c, 0xff })
+#define AURORA_GREEN ((Color){ 0x64, 0x96, 0x96, 0xff })
+#define TRANSPARENT ((Color){ 0x00, 0x00, 0x00, 0x00 })
+#define DUSTORANGE ((Color){ 0xbb, 0x88, 0x44, 0xff })
+#define ICEBLUE ((Color){ 0x77, 0x77, 0xff, 0xff })
/* colours */
#define COL_FG WHITE
@@ -55,6 +43,12 @@
#define COL_BORDER AURORA_GREY
#define COL_INFO AURORA_GREEN
#define COL_ORBIT AURORA_GREEN
+#define COL_STAR DUSTORANGE
+#define COL_COMET ICEBLUE
+#define COL_PLANET WHITE
+#define COL_MOON WHITE
+#define COL_DWARF WHITE
+#define COL_ASTEROID AURORA_GREEN
/* font */
#define FONT_SIZE 10
diff --git a/src/system.c b/src/system.c
@@ -4,7 +4,7 @@
#include "raylib.h"
#include "main.h"
-char *bodytype_names[BODY_LAST] = {
+static char *bodytype_names[BODY_LAST] = {
[BODY_STAR] = "Star",
[BODY_PLANET] = "Planet",
[BODY_DWARF] = "Dwarf planet",
@@ -67,6 +67,12 @@ sys_polarize(Vector2 vector) {
}
Polar
+sys_polarize_around(Vector2 around, Vector2 vector) {
+ Vector2 v = {vector.y - around.y, vector.x - around.x};
+ return sys_polarize(v);
+}
+
+Polar
sys_sum_polar(Polar absolute, Polar relative) {
return sys_polarize(sys_vectorize_around(sys_vectorize(absolute), relative));
}
@@ -106,6 +112,17 @@ sys_get_polar(Body *body) {
return polar;
}
+float
+sys_add_theta(float theta, float add) {
+ float ret;
+ ret = theta + add;
+ while (ret > 360)
+ ret -= 360;
+ while (ret < 0)
+ ret += 360;
+ return ret;
+}
+
System *
sys_init(char *name) {
System *ret = malloc(sizeof(System));
@@ -113,6 +130,8 @@ sys_init(char *name) {
ret->name = nstrdup(name);
ret->bodies = NULL;
ret->bodies_len = 0;
+ ret->furthest_body = NULL;
+ memset(&ret->num, 0, sizeof(ret->num));
return ret;
}
@@ -138,6 +157,9 @@ sys_load(System *s, char *name) {
if (!s) s = sys_init(name);
+ s->lypos.x = strnum(dbget(save->db.systems, name, "x"));
+ s->lypos.y = strnum(dbget(save->db.systems, name, "y"));
+
dir = smprintf("%s/", s->name);
s->bodies_len = blen = dblistgroups_f(&bname, save->db.systems, &filter_bodyinsystem, dir);
if (!bname) return NULL;
@@ -156,6 +178,14 @@ sys_load(System *s, char *name) {
tmp = dbget(save->db.systems, bname[i], "type");
s->bodies[i]->type = bodytype_enumify(tmp);
+ switch (s->bodies[i]->type) {
+ case BODY_STAR: s->num.stars++; break;
+ case BODY_PLANET: s->num.planets++; break;
+ case BODY_ASTEROID: s->num.asteroids++; break;
+ case BODY_COMET: s->num.comets++; break;
+ case BODY_MOON: s->num.moons++; break;
+ }
+
s->bodies[i]->radius = strnum(dbget(save->db.systems, bname[i], "radius"));
s->bodies[i]->mass = strnum(dbget(save->db.systems, bname[i], "mass"));
s->bodies[i]->orbdays = strnum(dbget(save->db.systems, bname[i], "orbdays"));
@@ -190,6 +220,14 @@ sys_load(System *s, char *name) {
sys_get_polar(s->bodies[i]); /* Builds the cache for us: this is more
efficient as it can cache the parent too */
s->bodies[i]->vector = sys_vectorize(s->bodies[i]->polar);
+
+ /* This could deal with moons, but that's probably not useful.
+ * What about multiple stars in a system? That may need to be
+ * addressed in future */
+ if (s->bodies[i]->parent && s->bodies[i]->parent->type == BODY_STAR && (!s->furthest_body ||
+ (s->bodies[i]->type == BODY_COMET ? s->bodies[i]->maxdist : s->bodies[i]->dist) >
+ (s->furthest_body->type == BODY_COMET ? s->furthest_body->maxdist : s->furthest_body->dist)))
+ s->furthest_body = s->bodies[i];
}
for (i = 0; i < blen; i++) {
@@ -201,3 +239,20 @@ sys_load(System *s, char *name) {
return s;
}
+
+System *
+sys_get(char *name) {
+ /* For now, call sys_load. In future, get the system via save. */
+ return sys_load(NULL, name);
+}
+
+System *
+sys_default(void) {
+ char *str;
+ if (view_main.sys)
+ return view_main.sys;
+ else if ((str = dbget(save->db.dir, "index", "selsystem")))
+ return sys_get(str);
+ else
+ return save->homesys;
+}
diff --git a/src/ui.c b/src/ui.c
@@ -1,4 +1,5 @@
#include <math.h>
+#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <raylib.h>
@@ -8,12 +9,31 @@
#define VIEWS_HEIGHT 25
#define WINDOW_TAB_HEIGHT 20
#define TARGET_FPS 60
-#define MIN_BODY_DIAM 3
-#define SCREEN_RECT() ((Rect){0, 0, GetScreenWidth(), GetScreenHeight()})
+#define EXPLODE_RECT(rect) rect.x, rect.y, rect.w, rect.h
+#define RLIFY_RECT(rect) ((Rectangle){ EXPLODE_RECT(rect) })
static Clickable clickable[CLICKABLE_MAX];
-void (*view_handlers[UI_VIEW_LAST])(void) = {
+static float min_body_rad[] = {
+ [BODY_STAR] = 4,
+ [BODY_PLANET] = 3,
+ [BODY_COMET] = 2.5,
+ [BODY_DWARF] = 2,
+ [BODY_ASTEROID] = 1,
+ [BODY_MOON] = 1,
+};
+
+static Color body_col[] = {
+ [BODY_STAR] = COL_STAR,
+ [BODY_PLANET] = COL_PLANET,
+ [BODY_COMET] = COL_COMET,
+ [BODY_DWARF] = COL_DWARF,
+ [BODY_ASTEROID] = COL_ASTEROID,
+ [BODY_MOON] = COL_MOON,
+};
+
+/* Return 1 for redraw, 0 to keep prev */
+int (*view_handlers[UI_VIEW_LAST])(int) = {
[UI_VIEW_MAIN] = ui_handle_view_main,
[UI_VIEW_COLONIES] = ui_handle_view_colonies,
[UI_VIEW_FLEETS] = ui_handle_view_fleets,
@@ -31,6 +51,8 @@ void (*view_drawers[UI_VIEW_LAST])(void) = {
[UI_VIEW_SETTINGS] = ui_draw_view_settings,
};
+Screen screen = { 0 };
+
Tabs view_tabs = {
/* Tactical is the terminology used in Aurora, so I decided to use it
* in the ui; in the code it's just called 'main' for my fingers' sake */
@@ -42,48 +64,24 @@ Tabs view_tabs = {
{&image_settings, "Settings", 0}}
};
-static struct {
- struct {
- Tabs tabs;
- struct {
- Checkbox dwarf;
- Checkbox asteroid;
- Checkbox comet;
- } names;
- struct {
- Checkbox dwarf;
- Checkbox asteroid;
- Checkbox comet;
- } orbit;
- Rect geom;
- } infobox;
- int pan;
- struct {
- int held;
- Vector2 origin;
- } ruler;
- float kmx, kmy;
- float kmperpx;
- struct {
- int x, y; /* real y = GetScreenHeight() - y */
- int w, h;
- } scale;
- System *system;
-} view_main = {
+View_main view_main = {
.infobox = {
.tabs = {
2, 0, {{NULL, "Display", 0}, {NULL, "Minerals", 0}}
},
.names = {
- .dwarf = {1, "Name: dwarf planets"},
- .asteroid = {0, "Name: asteroid"},
- .comet = {1, "Name: comet"},
+ .dwarf = {1, 1, "Name: dwarf planets"},
+ .dwarfn = {1, 0, "Name: numbered dwarf planets"}, /* TODO */
+ .asteroid = {1, 0, "Name: asteroids"},
+ .asteroidn = {1, 0, "Name: numbered asteroids"}, /* TODO */
+ .comet = {1, 1, "Name: comets"},
},
.orbit = {
- .dwarf = {0, "Orbit: dwarf planets"},
- .asteroid = {0, "Orbit: asteroid"},
- .comet = {0, "Orbit: comet"},
+ .dwarf = {1, 0, "Orbit: dwarf planets"},
+ .asteroid = {1, 0, "Orbit: asteroids"},
+ .comet = {1, 0, "Orbit: comets"},
},
+ .comettail = {1, 1, "Comet tails"}, /* TODO */
.geom = {
.x = 10,
.y = VIEWS_HEIGHT + 10,
@@ -102,14 +100,42 @@ static struct {
.w = 50,
.h = 3,
},
- .system = NULL,
+ .sys = NULL,
+};
+
+View_sys view_sys = {
+ .info = {
+ .geom = {
+ .x = 0,
+ .y = VIEWS_HEIGHT,
+ .w = 300,
+ .h = 0, /* see ui_handle_view_sys() */
+ },
+ },
+ .pan = 0,
+ .off = {
+ .x = 0,
+ .y = 0,
+ },
+ .lytopx = 0.025,
+ .sel = NULL,
};
void
ui_init(void) {
- InitWindow(500, 500, "testing raylib");
+ InitWindow(500, 500, "");
SetWindowState(FLAG_WINDOW_RESIZABLE);
SetTargetFPS(TARGET_FPS);
+ SetExitKey(KEY_NULL);
+}
+
+void
+ui_update_screen(void) {
+ screen.w = screen.rect.w = GetScreenWidth();
+ screen.h = screen.rect.h = GetScreenHeight();
+ screen.centre.x = screen.w / 2;
+ screen.centre.y = screen.h / 2;
+ screen.diag = sqrt(SQUARE(screen.w) + SQUARE(screen.h));
}
void
@@ -134,21 +160,14 @@ ui_print(int x, int y, Color col, char *fmt, ...) {
void
ui_title(char *fmt, ...) {
- static char *last = NULL;
char *title;
va_list ap;
va_start(ap, fmt);
title = vsmprintf(fmt, ap);
va_end(ap);
-
- if (!streq(title, last)) {
- SetWindowTitle(title);
- free(last);
- last = title;
- } else {
- free(title);
- }
+ SetWindowTitle(title);
+ free(title);
}
int
@@ -165,6 +184,43 @@ ui_collides(Rect rect, Vector2 point) {
return 0;
}
+int
+ui_onscreen(Vector2 point) {
+ return ui_collides(screen.rect, point);
+}
+
+int
+ui_ring_rect_collides(Vector2 centre, float r, Rect rect) {
+ Vector2 rcent = {rect.x + rect.w / 2, rect.y + rect.h / 2};
+ Vector2 d;
+
+ d.x = fabsf(centre.x - rcent.x);
+ d.y = fabsf(centre.y - rcent.y);
+
+ if (d.x > (rect.w / 2 + r)) return 0;
+ if (d.y > (rect.h / 2 + r)) return 0;
+
+ if (d.x <= (rect.w / 2)) return 1;
+ if (d.y <= (rect.h / 2)) return 1;
+
+ return ((d.x - rect.w / 2) * (d.x - rect.w / 2) +
+ (d.y - rect.h / 2) * (d.y - rect.h / 2)) <= r * r;
+}
+
+int
+ui_onscreen_ring(Vector2 centre, float r) {
+ float d = ui_vectordist(centre, screen.centre);
+
+ if (d + screen.diag / 2 < r)
+ return 0;
+ return CheckCollisionCircleRec(centre, r, RLIFY_RECT(screen.rect));
+}
+
+int
+ui_onscreen_circle(Vector2 centre, float r) {
+ return CheckCollisionCircleRec(centre, r, RLIFY_RECT(screen.rect));
+}
+
void
ui_clickable_register(int x, int y, int w, int h, enum UiElements type, void *elem) {
int i;
@@ -225,11 +281,12 @@ ui_clickable_handle(Vector2 mouse, MouseButton button, Clickable *clickable) {
}
}
-void
+int
ui_clickable_update(void) {
Vector2 mouse;
MouseButton button;
int i;
+ int ret = 0;
mouse = GetMousePosition();
/* I wish there was a: int GetMouseButton(void) */
@@ -239,10 +296,20 @@ ui_clickable_update(void) {
else button = -1;
for (i = 0; i < CLICKABLE_MAX; i++) {
- if (clickable[i].elem && ui_collides(clickable[i].geom, mouse))
+ if (clickable[i].elem && ui_collides(clickable[i].geom, mouse)) {
ui_clickable_handle(mouse, button, &clickable[i]);
- clickable[i].elem = NULL;
+ ret = 1;
+ }
}
+
+ return ret;
+}
+
+void
+ui_clickable_clear(void) {
+ int i;
+ for (i = 0; i < CLICKABLE_MAX; i++)
+ clickable[i].elem = NULL;
}
void
@@ -260,6 +327,42 @@ ui_draw_border(int x, int y, int w, int h, int px) {
DrawRectangle(x + w - px, y, px, h, COL_BORDER); /* right */
}
+#define SEGMAX 2500
+
+void
+ui_draw_ring(int x, int y, float r, Color col) {
+ Vector2 v = {x, y};
+ Polar p;
+ float s;
+ float prec = screen.diag * 2 / (PI * 2 * r) * 360;
+ float sdeg = 0, edeg = 360;
+ float deg;
+
+ if (!ui_onscreen_ring(v, r))
+ return;
+
+ p = sys_polarize_around(v, screen.centre);
+ deg = p.theta * RAD2DEG;
+
+ /* Draw the section of the ring (+ wriggle room) that will be onscreen
+ * be (start/end)ing prec degrees before/after the screen's centre
+ * relative to the ring's centre. */
+ sdeg = deg + prec;
+ edeg = deg - prec;
+
+ if (r < 100)
+ s = r;
+ else if (r < SEGMAX)
+ s = r / log10(r);
+ else
+ s = SEGMAX;
+
+ /* Less segments are needed if there is less ring to place them in. */
+ s *= (sdeg - edeg) / 360;
+
+ DrawRing(v, r - 1, r, sdeg, edeg, s, col);
+}
+
void
ui_draw_tabs(int x, int y, int w, int h, Tabs *tabs) {
int fw, fn, ftabw;
@@ -328,9 +431,11 @@ ui_draw_checkbox(int x, int y, Checkbox *box) {
w = h = FONT_SIZE;
ui_draw_border(x, y, w, h, 1);
- DrawRectangle(x + 1, y + 1, w - 2, h - 2, box->val ? COL_FG : COL_BG);
+ DrawRectangle(x + 1, y + 1, w - 2, h - 2,
+ box->enabled ? (box->val ? COL_FG : COL_BG) : COL_BORDER);
ui_print(x + w + (w / 2), y + (h / 6), COL_FG, "%s", box->label);
- ui_clickable_register(x, y, w + (w / 2) + ui_textsize(box->label), h, UI_CHECKBOX, box);
+ if (box->enabled)
+ ui_clickable_register(x, y, w + (w / 2) + ui_textsize(box->label), h, UI_CHECKBOX, box);
}
Vector2
@@ -373,19 +478,27 @@ ui_draw_tabbed_window(int x, int y, int w, int h, Tabs *tabs) {
ui_draw_border(x, y, w, h, 2);
}
-void
-ui_handle_view_main(void) {
+int
+ui_handle_view_main(int nowsel) {
Vector2 mouse = GetMousePosition();
Vector2 delta = GetMouseDelta();
float wheel = GetMouseWheelMove();
float diff;
- int i;
+ Body *furth;
+
+ if (view_main.sys)
+ furth = view_main.sys->furthest_body;
#define SCROLL_DIVISOR 10
- diff = wheel * (view_main.kmperpx/SCROLL_DIVISOR);
- view_main.kmperpx -= diff;
- view_main.kmx += (mouse.x - GetScreenWidth() / 2) * diff;
- view_main.kmy += (mouse.y - GetScreenHeight() / 2) * diff;
+ if (wheel) {
+ diff = wheel * (view_main.kmperpx/SCROLL_DIVISOR);
+ if (diff > 0 || !furth || view_main.kmperpx * GetScreenHeight() <
+ 2 * (furth->type == BODY_COMET ? furth->maxdist : furth->dist)) {
+ view_main.kmperpx -= diff;
+ view_main.kmx += (mouse.x - GetScreenWidth() / 2) * diff;
+ view_main.kmy += (mouse.y - GetScreenHeight() / 2) * diff;
+ }
+ }
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
if (view_main.pan) {
@@ -394,77 +507,134 @@ ui_handle_view_main(void) {
} else if (!ui_collides(view_main.infobox.geom, mouse)) {
view_main.pan = 1;
}
- } else view_main.pan = 0;
+ } else {
+ view_main.pan = 0;
+ }
if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT) && !view_main.ruler.held &&
!ui_collides(view_main.infobox.geom, mouse)) {
view_main.ruler.held = 1;
view_main.ruler.origin = ui_pxtokm(mouse);
- } else if (IsMouseButtonUp(MOUSE_BUTTON_RIGHT))
+ } else if (IsMouseButtonUp(MOUSE_BUTTON_RIGHT)) {
view_main.ruler.held = 0;
+ }
- if (view_main.system != save->system) {
- view_main.system = save->system;
-
- ui_title("Tactical: %s", save->system->name);
+ if (!view_main.sys) {
+ view_main.sys = sys_default();
}
+ if (nowsel)
+ ui_title("Tactical: %s", view_main.sys->name);
+
+ view_main.infobox.names.dwarfn.enabled = view_main.infobox.names.dwarf.val;
+ view_main.infobox.names.asteroidn.enabled = view_main.infobox.names.asteroid.val;
+
+ /* so that the debug stuff prints */
+ if (delta.x || delta.y)
+ return 1;
+ return 0;
}
-void
-ui_handle_view_colonies(void) {
- ui_title("Colonies");
+int
+ui_handle_view_colonies(int nowsel) {
+ if (nowsel)
+ ui_title("Colonies");
+ return 1;
}
-void
-ui_handle_view_fleets(void) {
- ui_title("Fleets");
+int
+ui_handle_view_fleets(int nowsel) {
+ if (nowsel)
+ ui_title("Fleets");
+ return 1;
}
-void
-ui_handle_view_design(void) {
- ui_title("Design");
+int
+ui_handle_view_design(int nowsel) {
+ if (nowsel)
+ ui_title("Design");
+ return 1;
}
-void
-ui_handle_view_sys(void) {
- ui_title("Systems");
+int
+ui_handle_view_sys(int nowsel) {
+ if (nowsel)
+ ui_title("Systems");
+ view_sys.info.geom.h = GetScreenHeight() - VIEWS_HEIGHT;
+ if (!view_sys.sel)
+ view_sys.sel = sys_default();
+ return 1;
}
-void
-ui_handle_view_settings(void) {
- ui_title("Settings");
+int
+ui_handle_view_settings(int nowsel) {
+ if (nowsel)
+ ui_title("Settings");
+ return 1;
+}
+
+static int
+ui_should_draw_body_checkbox(Body *body, int type, Checkbox *box) {
+ if ((body->type == type || (body->parent &&
+ body->parent->type == type)) &&
+ !box->val)
+ return 0;
+ return 1;
}
int
ui_should_draw_body(Body *body, int orbit) {
- if (!orbit && !ui_collides(SCREEN_RECT(), body->pxloc))
- return 0;
- if (!orbit && body->type != BODY_STAR &&
- (body->type == BODY_COMET ? body->maxdist : body->dist) / view_main.kmperpx < ui_textsize(body->name))
- return 0;
- if (!orbit && body->parent && body->type != BODY_STAR &&
- ui_vectordist(body->vector, body->parent->vector) < MIN_BODY_DIAM * view_main.kmperpx)
- return 0;
- if ((body->type == BODY_DWARF || (body->parent && body->parent->type == BODY_DWARF)) &&
- (!orbit || !view_main.infobox.orbit.dwarf.val) &&
- (orbit || !view_main.infobox.names.dwarf.val))
- return 0;
- if ((body->type == BODY_ASTEROID || (body->parent && body->parent->type == BODY_ASTEROID)) &&
- (!orbit || !view_main.infobox.orbit.asteroid.val) &&
- (orbit || !view_main.infobox.names.asteroid.val))
- return 0;
- if ((body->type == BODY_COMET || (body->parent && body->parent->type == BODY_COMET)) &&
- (!orbit || !view_main.infobox.orbit.comet.val) &&
- (orbit || !view_main.infobox.names.comet.val))
- return 0;
+ if (orbit) {
+ if (!body->parent)
+ return 0;
+ if (orbit < min_body_rad[body->parent->type])
+ return 0;
+ if (!ui_should_draw_body_checkbox(body, BODY_DWARF,
+ &view_main.infobox.orbit.dwarf))
+ return 0;
+ if (!ui_should_draw_body_checkbox(body, BODY_ASTEROID,
+ &view_main.infobox.orbit.asteroid))
+ return 0;
+ if (!ui_should_draw_body_checkbox(body, BODY_COMET,
+ &view_main.infobox.orbit.comet))
+ return 0;
+ } else {
+ if (!ui_onscreen(body->pxloc))
+ return 0;
+ if (body->type != BODY_STAR &&
+ (body->type == BODY_COMET ? body->maxdist : body->dist)
+ / view_main.kmperpx < ui_textsize(body->name))
+ return 0;
+ if (body->parent && body->type != BODY_STAR &&
+ ui_vectordist(body->vector, body->parent->vector) <
+ min_body_rad[body->type] * view_main.kmperpx)
+ return 0;
+ if (isdigit(*body->name) || *body->name == '(') {
+ if (!ui_should_draw_body_checkbox(body, BODY_DWARF,
+ &view_main.infobox.names.dwarfn))
+ return 0;
+ if (!ui_should_draw_body_checkbox(body, BODY_ASTEROID,
+ &view_main.infobox.names.asteroidn))
+ return 0;
+ }
+ if (!ui_should_draw_body_checkbox(body, BODY_DWARF,
+ &view_main.infobox.names.dwarf))
+ return 0;
+ if (!ui_should_draw_body_checkbox(body, BODY_ASTEROID,
+ &view_main.infobox.names.asteroid))
+ return 0;
+ if (!ui_should_draw_body_checkbox(body, BODY_COMET,
+ &view_main.infobox.names.comet))
+ return 0;
+ }
return 1;
}
void
ui_draw_body(Body *body) {
Vector2 parent;
+ float pxrad;
int w;
if (body->parent) {
@@ -474,19 +644,24 @@ ui_draw_body(Body *body) {
parent.y = 0;
}
- if (ui_should_draw_body(body, 1)) {
- if (body->parent && body->type == BODY_COMET)
- DrawLineV(parent, body->pxloc, COL_ORBIT);
- else if (body->parent)
- DrawCircleLines(parent.x, parent.y,
- ui_vectordist(parent, body->pxloc),
- COL_ORBIT);
+ if (body->parent) {
+ pxrad = ui_vectordist(parent, body->pxloc);
+ if (ui_should_draw_body(body, pxrad)) {
+ if (body->type == BODY_COMET)
+ DrawLineV(parent, body->pxloc, COL_ORBIT);
+ else
+ ui_draw_ring(parent.x, parent.y, pxrad, COL_ORBIT);
+ }
}
- if (body->radius / view_main.kmperpx > MIN_BODY_DIAM)
+ if (body->radius / view_main.kmperpx > min_body_rad[body->type])
w = body->radius / view_main.kmperpx;
else
- w = MIN_BODY_DIAM;
- DrawCircle(body->pxloc.x, body->pxloc.y, w, COL_FG);
+ w = min_body_rad[body->type];
+ DrawCircle(body->pxloc.x, body->pxloc.y, w, body_col[body->type]);
+ if (body->type == BODY_COMET && view_main.infobox.comettail.val &&
+ 10 * view_main.kmperpx < body->curdist)
+ DrawLineV(body->pxloc, sys_vectorize_around(body->pxloc,
+ (Polar){11, body->theta} /* I have no fucking clue what is going on here. How does this end up correct, but not when I add 180? That theta isn't even pointing away from the sun!!! WHAT?!? */), COL_COMET);
if (ui_should_draw_body(body, 0))
ui_print(body->pxloc.x + w + 2, body->pxloc.y + w + 2,
COL_FG, "%s", body->name);
@@ -497,24 +672,22 @@ ui_draw_view_main(void) {
Vector2 mouse = GetMousePosition();
Vector2 mousekm = ui_pxtokm(mouse);
Vector2 ruler;
- Vector2 km;
- Polar polar;
Body *body;
- float *massa;
- size_t massi;
float dist;
size_t i;
+ float x, y;
/* debug info */
- ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 10, COL_FG, "Xoff: %f | Yoff: %f | km/px: %f",
+ ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 10, COL_FG, "W: %f | H: %f", (float)screen.w, (float)screen.h);
+ ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 20, COL_FG, "Xoff: %f | Yoff: %f | km/px: %f",
view_main.kmx, view_main.kmy, view_main.kmperpx);
- ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 20, COL_FG, "X: %f | Y: %f",
+ ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 30, COL_FG, "X: %f | Y: %f",
mousekm.x, mousekm.y);
- ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 30, COL_FG, "FPS: %d (target: %d)", GetFPS(), TARGET_FPS);
+ ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 40, COL_FG, "FPS: %d (target: %d)", GetFPS(), TARGET_FPS);
/* draw system bodies */
- for (i = 0; i < save->system->bodies_len; i++) {
- body = save->system->bodies[i];
+ for (i = 0; i < view_main.sys->bodies_len; i++) {
+ body = view_main.sys->bodies[i];
body->pxloc = ui_kmtopx(body->vector);
ui_draw_body(body);
}
@@ -546,24 +719,17 @@ ui_draw_view_main(void) {
ui_draw_tabbed_window(view_main.infobox.geom.x, view_main.infobox.geom.y,
view_main.infobox.geom.w, view_main.infobox.geom.h,
&view_main.infobox.tabs);
- ui_draw_checkbox(view_main.infobox.geom.x + FONT_SIZE,
- view_main.infobox.geom.y + WINDOW_TAB_HEIGHT + FONT_SIZE*1.5,
- &view_main.infobox.names.dwarf);
- ui_draw_checkbox(view_main.infobox.geom.x + FONT_SIZE,
- view_main.infobox.geom.y + WINDOW_TAB_HEIGHT + FONT_SIZE*3,
- &view_main.infobox.names.asteroid);
- ui_draw_checkbox(view_main.infobox.geom.x + FONT_SIZE,
- view_main.infobox.geom.y + WINDOW_TAB_HEIGHT + FONT_SIZE*4.5,
- &view_main.infobox.names.comet);
- ui_draw_checkbox(view_main.infobox.geom.x + FONT_SIZE,
- view_main.infobox.geom.y + WINDOW_TAB_HEIGHT + FONT_SIZE*6,
- &view_main.infobox.orbit.dwarf);
- ui_draw_checkbox(view_main.infobox.geom.x + FONT_SIZE,
- view_main.infobox.geom.y + WINDOW_TAB_HEIGHT + FONT_SIZE*7.5,
- &view_main.infobox.orbit.asteroid);
- ui_draw_checkbox(view_main.infobox.geom.x + FONT_SIZE,
- view_main.infobox.geom.y + WINDOW_TAB_HEIGHT + FONT_SIZE*9,
- &view_main.infobox.orbit.comet);
+ x = view_main.infobox.geom.x + FONT_SIZE;
+ y = view_main.infobox.geom.y + WINDOW_TAB_HEIGHT;
+ ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.dwarf);
+ ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.dwarfn);
+ ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.asteroid);
+ ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.asteroidn);
+ ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.comet);
+ ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.dwarf);
+ ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.asteroid);
+ ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.comet);
+ ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.comettail);
}
void
@@ -590,8 +756,32 @@ ui_draw_view_design(void) {
void
ui_draw_view_sys(void) {
- ui_print(10, GetScreenHeight() / 2, COL_FG, "System info/settings menu");
- ui_print(GetScreenWidth() / 2, GetScreenHeight() / 2, COL_FG, "Pannable system view");
+ int x, y;
+
+ x = view_sys.info.geom.x + view_sys.info.geom.w;
+ y = view_sys.info.geom.y;
+
+ /* draw map */
+
+ /* draw divider */
+ DrawLine(x, y, x, y + view_sys.info.geom.h, COL_BORDER);
+
+ /* draw info */
+ x = view_sys.info.geom.x + 10;
+ y += 10;
+ if (view_sys.sel) {
+ ui_print(x, y, COL_FG, "%s", view_sys.sel->name);
+ DrawLine(x, y + FONT_SIZE, x + view_sys.info.geom.w - 20,
+ y + FONT_SIZE, COL_BORDER);
+ y += 30;
+ ui_print(x, y, COL_FG, "Stars: %d", view_sys.sel->num.stars);
+ ui_print(x, y + 10, COL_FG, "Planets: %d", view_sys.sel->num.planets);
+ ui_print(x, y + 20, COL_FG, "Asteroids: %d", view_sys.sel->num.asteroids);
+ ui_print(x, y + 30, COL_FG, "Comets: %d", view_sys.sel->num.comets);
+ ui_print(x, y + 40, COL_FG, "Moons: %d", view_sys.sel->num.moons);
+ DrawLine(x, y + 52, x + 85, y + 52, COL_FG);
+ ui_print(x, y + 55, COL_FG, "Total: %d", view_sys.sel->bodies_len);
+ }
}
void
diff --git a/src/views.h b/src/views.h
@@ -0,0 +1,41 @@
+typedef struct {
+ struct {
+ Tabs tabs;
+ struct {
+ Checkbox dwarf;
+ Checkbox dwarfn;
+ Checkbox asteroid;
+ Checkbox asteroidn;
+ Checkbox comet;
+ } names;
+ struct {
+ Checkbox dwarf;
+ Checkbox asteroid;
+ Checkbox comet;
+ } orbit;
+ Checkbox comettail;
+ Rect geom;
+ } infobox;
+ int pan;
+ struct {
+ int held;
+ Vector2 origin;
+ } ruler;
+ float kmx, kmy;
+ float kmperpx;
+ struct {
+ int x, y; /* real y = GetScreenHeight() - y */
+ int w, h;
+ } scale;
+ System *sys;
+} View_main;
+
+typedef struct {
+ struct {
+ Rect geom;
+ } info;
+ int pan;
+ Vector2 off;
+ float lytopx;
+ System *sel;
+} View_sys;