summary refs log tree commit diff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c114
1 files changed, 89 insertions, 25 deletions
diff --git a/src/main.c b/src/main.c
index f86ed0b..922ca20 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,8 +4,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <inttypes.h>
-#include <errno.h>
+#include <errno.h> // ENOENT
+#include <math.h> // used by vk2dSleep
 
 #include "input.h"
 #include "loader.h"
@@ -14,8 +14,8 @@
 
 #include "tilemap.h"
 
-#include "incbin.h"
-#include "libplum.h"
+#include "incbin.h" // game icon
+#include "libplum.h" // decoding game icon
 
 #include "main.h"
 
@@ -240,10 +240,19 @@ int game_load_level(char *level) {
 
 			game_state = STATE_FADE_OUT;
 			fade = 255;
-			int x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2);
-			int y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2);
-			if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
-			if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
+			int x, y;
+			if (tilemap->width < WINDOW_WIDTH / 8) {
+				x = -((WINDOW_WIDTH - tilemap->width * 8) / 2);
+			} else {
+				x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2);
+				if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
+			}
+			if (tilemap->height <= WINDOW_HEIGHT / 8) {
+				y = -((WINDOW_HEIGHT - tilemap->height * 8) / 2);
+			} else {
+				y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2);
+				if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
+			}
 			
 			game_render(framebuffer, x, y);
 			SDL_SetRenderTarget(renderer, NULL);
@@ -264,6 +273,27 @@ void game_render_flush(SDL_Texture *framebuffer) {
 	SDL_RenderPresent(renderer);
 }
 
+// from libertea / <https://github.com/PaoloMazzon>
+double getTime(void) {
+  static double time = -1;
+  if (time == -1)
+    time = SDL_GetPerformanceCounter();
+  return (double)(SDL_GetPerformanceCounter() - time) / SDL_GetPerformanceFrequency();
+}
+
+// also from libertea / <https://github.com/PaoloMazzon>
+void vk2dSleep(double seconds) {
+    if (seconds <= 0)
+        return;
+    double start = SDL_GetPerformanceCounter();
+    double milliseconds = floor(seconds * 1000);
+    SDL_Delay(milliseconds);
+    while ((SDL_GetPerformanceCounter() - start) / (double)SDL_GetPerformanceFrequency() < seconds) {
+        volatile int i = 0;
+        (void) i;
+    }
+}
+
 int main(int const argc, char *const *const argv) {
 	save_file_name = SDL_GetPrefPath("sylvie", "game");
 	save_file_name = SDL_realloc(save_file_name, strlen(save_file_name) + strlen("save.sav") + 1);
@@ -349,12 +379,13 @@ int main(int const argc, char *const *const argv) {
 	#if defined(__EMSCRIPTEN__)
 	scale = 1;
 	#else
-	if (scale <= 0) { // this looks very wrong
+	if (scale <= 0) { // because we used atoi, the user can set scale to -1 or something
 		SDL_DisplayMode dm;
 		if (SDL_GetDesktopDisplayMode(0, &dm) != 0) {
-			SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "couldnt get desktop size", SDL_GetError(), NULL);
-			fprintf(stderr, "info: couldnt get desktop size %s\n", SDL_GetError());
+			SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "couldnt get desktop size", SDL_GetError(), NULL);
+			fprintf(stderr, "warn: couldnt get desktop size %s\n", SDL_GetError());
 			flags |= SDL_WINDOW_RESIZABLE;
+			scale = 3;
 		} else {
 			int x = dm.w / 2 / WINDOW_WIDTH;
 			int y = dm.h / 2 / WINDOW_HEIGHT;
@@ -366,8 +397,10 @@ int main(int const argc, char *const *const argv) {
 			if (scale == 0) {
 				scale = 1;
 			}
-			if (dm.refresh_rate != 60) {
-				SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "refresh rate", "this game currently only runs well on 60Hz displays", NULL);
+			if (dm.refresh_rate < 59) {
+				SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "refresh rate", "your monitor appears to have a refresh rate below 60Hz, the game will run slower\n"
+				"you can compile the game from source to disable vsync, unlocking the framerate\n"
+				"TODO: disabling vsync without a recompile", NULL);
 			}
 		}
 	}
@@ -375,12 +408,15 @@ int main(int const argc, char *const *const argv) {
 	
 	window = SDL_CreateWindow(":3", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH * scale, WINDOW_HEIGHT * scale, flags | SDL_WINDOW_HIDDEN);
 	if (window == NULL) {
+		fprintf(stderr, "failed to create the game window: %s\n", SDL_GetError());
 		goto end;
 	}
 
+	SDL_SetWindowMinimumSize(window, WINDOW_WIDTH, WINDOW_HEIGHT);
 	SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); // hack, i dont wanna deal with windows discarding render textures
 	renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_PRESENTVSYNC);
 	if (renderer == NULL) {
+		fprintf(stderr, "failed to create a rendering context: %s\n", SDL_GetError());
 		goto end;
 	}
 	SDL_RenderSetLogicalSize(renderer, WINDOW_WIDTH, WINDOW_HEIGHT);
@@ -410,18 +446,23 @@ int main(int const argc, char *const *const argv) {
 		
 		particle_tex = res_get_texture("particles").data;
 
-		player_new(&next_entities);
 		FILE *file = fopen(save_file_name, "rb");
 		if (file == NULL) {
 			if (errno != ENOENT) {
 				perror(save_file_name);
 				goto end;
 			}
+			player_new(&next_entities);
 			player_property(next_entities.player, "x", "40");
 			player_property(next_entities.player, "y", "64");
 			game_load_level("untitled");
 		} else {
-			game_load(file);
+			if (game_load(file)) {
+				fputs("the save file is corrupt!\n", stderr);
+				player_property(next_entities.player, "x", "40");
+				player_property(next_entities.player, "y", "64");
+				game_load_level("untitled");
+			}
 		}
 		#if 0
 		struct blob blob = res_get_map("untitled");
@@ -477,6 +518,8 @@ void main_loop(void) {
 	int x = 0, y = 0;
 	while (1) {
 #endif
+		double const begin_time = getTime();
+
 		input_pressed = input_held;
 		SDL_Event evt;
 		while (SDL_PollEvent(&evt)) {
@@ -546,7 +589,7 @@ void main_loop(void) {
 					i = evt.tfinger.fingerId;
 					touch.positions[i].x = evt.tfinger.x;
 					touch.positions[i].y = evt.tfinger.y;
-					printf("%" PRIu64 " %" PRIu64 " %f %f\n", evt.tfinger.touchId, evt.tfinger.fingerId, evt.tfinger.x, evt.tfinger.y);
+					//printf("%" PRIu64 " %" PRIu64 " %f %f\n", evt.tfinger.touchId, evt.tfinger.fingerId, evt.tfinger.x, evt.tfinger.y);
 					reset_touch:
 					touch.input_touch = 0;
 					for (size_t i = 0; i < touch.allocated; i++) {
@@ -642,14 +685,25 @@ void main_loop(void) {
 						player_property(next_entities.player, "y", "64");
 						game_load_level("untitled");
 					} else {
-						game_load(file);
+						if (game_load(file)) {
+							fputs("the save file somehow corrupted itself!\n", stderr);
+							goto end; // better than freezing if the save file magically corrupts
+						}
 					}
 				}
 				
-				x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2);
-				y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2);
-				if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
-				if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
+				if (tilemap->width < WINDOW_WIDTH / 8) {
+					x = -((WINDOW_WIDTH - tilemap->width * 8) / 2);
+				} else {
+					x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2);
+					if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
+				}
+				if (tilemap->height <= WINDOW_HEIGHT / 8) {
+					y = -((WINDOW_HEIGHT - tilemap->height * 8) / 2);
+				} else {
+					y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2);
+					if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
+				}
 				
 				game_render(framebuffer, x, y);
 				game_render_flush(framebuffer);
@@ -667,10 +721,18 @@ void main_loop(void) {
 				if (fade == 255) {
 					if (game_load_level(game_next_level)) {
 						game_state = STATE_FADE_OUT;
-						x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2);
-						y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2);
-						if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
-						if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
+						if (tilemap->width < WINDOW_WIDTH / 8) {
+							x = -((WINDOW_WIDTH - tilemap->width * 8) / 2);
+						} else {
+							x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2);
+							if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
+						}
+						if (tilemap->height <= WINDOW_HEIGHT / 8) {
+							y = -((WINDOW_HEIGHT - tilemap->height * 8) / 2);
+						} else {
+							y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2);
+							if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
+						}
 						
 						game_render(framebuffer, x, y);
 						SDL_SetRenderTarget(renderer, NULL);
@@ -697,6 +759,8 @@ void main_loop(void) {
 #if defined(__EMSCRIPTEN__)
 	return;
 #else
+		double const end_time = getTime();
+		vk2dSleep(1.0/60.0 - (end_time - begin_time));
 	}
 #endif