Prechádzať zdrojové kódy

add game config file and map moving support

Ivan Avdeev 6 rokov pred
rodič
commit
35e2c089ec
6 zmenil súbory, kde vykonal 201 pridanie a 42 odobranie
  1. 3 5
      Makefile
  2. 13 0
      hl2.cfg
  3. 170 34
      src/OpenSource.c
  4. 2 2
      src/filemap.h
  5. 12 0
      src/render.c
  6. 1 1
      src/render.h

+ 3 - 5
Makefile

@@ -1,10 +1,8 @@
 .SUFFIXES:
 MAKEOPTS+=-r
 
-MAP ?= d1_trainstation_01
-VPKDIR ?= ~/.local/share/Steam/steamapps/common/Half-Life\ 2/hl2
 MAX_MAPS ?= 99
-ARGS ?= -p $(VPKDIR)/hl2_textures_dir.vpk -p $(VPKDIR)/hl2_misc_dir.vpk -p $(VPKDIR)/hl2_pak_dir.vpk -d $(VPKDIR) -n $(MAX_MAPS)
+ARGS ?= -n $(MAX_MAPS) -c hl2.cfg
 
 CFLAGS += -Wall -Wextra -D_GNU_SOURCE -Isrc/atto -fPIE
 BUILDDIR ?= build
@@ -94,9 +92,9 @@ clean:
 	rm -f $(OBJECTS) $(DEPS) $(EXE)
 
 run: $(EXE)
-	$(EXE) $(ARGS) $(MAP)
+	$(EXE) $(ARGS)
 
 debug: $(EXE)
-	gdb --args $(EXE) $(ARGS) $(MAP)
+	gdb --args $(EXE) $(ARGS)
 
 .PHONY: all clean run_tool debug_tool

+ 13 - 0
hl2.cfg

@@ -0,0 +1,13 @@
+gamedir "Half-Life 2/hl2"
+vpk "hl2_textures_dir.vpk"
+vpk "hl2_misc_dir.vpk"
+vpk "hl2_pak_dir.vpk"
+dir ""
+max_maps 99
+
+map d1_trainstation_01
+
+patch_landmarks {
+	map "d1_trainstation_05"
+	"landmark_trainstation_04-05" "0 0 0"
+}

+ 170 - 34
src/OpenSource.c

@@ -6,6 +6,7 @@
 #include "texture.h"
 #include "profiler.h"
 #include "camera.h"
+#include "vmfparser.h"
 
 #include "atto/app.h"
 #include "atto/math.h"
@@ -25,24 +26,29 @@ static struct Stack stack_persistent = {
 	.cursor = 0
 };
 
-struct Map {
+static struct Memories mem = {
+	&stack_temp,
+	&stack_persistent
+};
+
+typedef struct Map {
 	char *name;
 	int loaded;
 	struct AVec3f offset;
 	struct BSPModel model;
 	struct Map *next;
-};
+} Map;
 
 static struct {
 	struct Camera camera;
 	int forward, right, run;
 	struct AVec3f center;
 	float R;
-	float lmn;
 
 	struct ICollection *collection_chain;
-	struct Map *maps_begin, *maps_end;
+	Map *maps_begin, *maps_end;
 	int maps_count, maps_limit;
+	Map *selected_map;
 } g;
 
 void openSourceAddMap(const char* mapname, int mapname_length) {
@@ -59,18 +65,18 @@ void openSourceAddMap(const char* mapname, int mapname_length) {
 		map = map->next;
 	}
 
-	char *mem = stackAlloc(&stack_persistent, sizeof(struct Map) + mapname_length + 1);
-	if (!mem) {
+	char *buffer = stackAlloc(&stack_persistent, sizeof(struct Map) + mapname_length + 1);
+	if (!buffer) {
 		PRINT("Not enough memory");
 		return;
 	}
 
-	memcpy(mem, mapname, mapname_length);
-	mem[mapname_length] = '\0';
+	memcpy(buffer, mapname, mapname_length);
+	buffer[mapname_length] = '\0';
 
-	map = (void*)(mem + mapname_length + 1);
+	map = (void*)(buffer + mapname_length + 1);
 	memset(map, 0, sizeof(*map));
-	map->name = mem;
+	map->name = buffer;
 
 	if (!g.maps_end)
 		g.maps_begin = map;
@@ -139,7 +145,7 @@ static enum BSPLoadResult loadMap(struct Map *map, struct ICollection *collectio
 	return BSPLoadResult_Success;
 }
 
-static void opensrcInit(const char *map, int max_maps) {
+static void opensrcInit() {
 	cacheInit(&stack_persistent);
 
 	if (!renderInit()) {
@@ -149,10 +155,6 @@ static void opensrcInit(const char *map, int max_maps) {
 
 	bspInit();
 
-	g.maps_limit = max_maps > 0 ? max_maps : 1;
-	g.maps_count = 0;
-	openSourceAddMap(map, strlen(map));
-
 	if (BSPLoadResult_Success != loadMap(g.maps_begin, g.collection_chain))
 		aAppTerminate(-2);
 
@@ -203,7 +205,7 @@ static void opensrcPaint(ATimeUs timestamp, float dt) {
 		const RDrawParams params = {
 			.camera = &g.camera,
 			.translation = map->offset,
-			.lmn = g.lmn
+			.selected = map == g.selected_map
 		};
 
 		renderModelDraw(&params, &map->model);
@@ -222,6 +224,10 @@ static void opensrcPaint(ATimeUs timestamp, float dt) {
 static void opensrcKeyPress(ATimeUs timestamp, AKey key, int pressed) {
 	(void)(timestamp); (void)(key); (void)(pressed);
 	//printf("KEY %u %d %d\n", timestamp, key, pressed);
+
+	struct AVec3f map_offset = aVec3ff(0);
+	int moved_map = 0;
+
 	switch (key) {
 	case AK_Esc:
 		if (!pressed) break;
@@ -235,9 +241,39 @@ static void opensrcKeyPress(ATimeUs timestamp, AKey key, int pressed) {
 	case AK_A: g.right += pressed?-1:1; break;
 	case AK_D: g.right += pressed?1:-1; break;
 	case AK_LeftShift: g.run = pressed; break;
-	case AK_E: g.lmn = (float)pressed; break;
+
 	default: break;
 	}
+
+	if (pressed) {
+		switch(key) {
+		case AK_Up: map_offset.x += 1.f; moved_map = 1; break;
+		case AK_Down: map_offset.x -= 1.f; moved_map = 1; break;
+		case AK_Left: map_offset.y -= 1.f; moved_map = 1; break;
+		case AK_Right: map_offset.y += 1.f; moved_map = 1; break;
+		case AK_PageUp: map_offset.z += 1.f; moved_map = 1; break;
+		case AK_PageDown: map_offset.z -= 1.f; moved_map = 1; break;
+		case AK_Tab:
+			g.selected_map = g.selected_map ? g.selected_map->next : g.maps_begin;
+			break;
+		case AK_Q:
+			g.selected_map = NULL;
+			break;
+		default: break;
+		}
+
+		if (moved_map && g.selected_map) {
+			Map *map = g.selected_map;
+			if (g.run) {
+				map_offset.x *= 100.f;
+				map_offset.y *= 100.f;
+				map_offset.z *= 100.f;
+			}
+			PRINTF("Map offset: %f %f %f", map_offset.x, map_offset.y, map_offset.z);
+			map->offset = aVec3fAdd(map->offset, map_offset);
+			PRINTF("Map offset: %f %f %f", map->offset.x, map->offset.y, map->offset.z);
+		}
+	}
 }
 
 static void opensrcPointer(ATimeUs timestamp, int dx, int dy, unsigned int btndiff) {
@@ -263,21 +299,123 @@ static struct ICollection *addToCollectionChain(struct ICollection *chain, struc
 	return next;
 }
 
+typedef struct {
+	StringView gamedir;
+} Config;
+
+static char *buildSteamPath(const StringView *gamedir, const StringView *path) {
+	// FIXME windows and macos paths?
+	const char *home_dir = getenv("HOME");
+	const int home_dir_length = strlen(home_dir);
+
+	const char steam_basedir[] = ".local/share/Steam/steamapps/common";
+	const int steam_basedir_length = sizeof(steam_basedir) - 1;
+
+	const int length = home_dir_length + steam_basedir_length + gamedir->length + path->length + 4;
+	char *value = stackAlloc(&stack_temp, length);
+	if (!value)
+		return 0;
+
+	int offset = 0;
+	memcpy(value + offset, home_dir, home_dir_length); offset += home_dir_length;
+	value[offset++] = '/';
+	memcpy(value + offset, steam_basedir, steam_basedir_length); offset += steam_basedir_length;
+	value[offset++] = '/';
+	memcpy(value + offset, gamedir->str, gamedir->length); offset += gamedir->length; 
+	value[offset++] = '/';
+	memcpy(value + offset, path->str, path->length); offset += path->length;
+	value[offset] = '\0';
+
+	return value;
+}
+
+static VMFAction configReadCallback(VMFState *state, VMFEntryType entry, const VMFKeyValue *kv) {
+	Config *cfg = state->user_data;
+
+	switch (entry) {
+	case VMFEntryType_KeyValue:
+		if (strncasecmp("gamedir", kv->key.str, kv->key.length) == 0) {
+			cfg->gamedir = kv->value;
+		} else if (strncasecmp("vpk", kv->key.str, kv->key.length) == 0) {
+			char *value = buildSteamPath(&cfg->gamedir, &kv->value);
+			g.collection_chain = addToCollectionChain(g.collection_chain, collectionCreateVPK(&mem, value));
+			stackFreeUpToPosition(&stack_temp, value);
+		} else if (strncasecmp("dir", kv->key.str, kv->key.length) == 0) {
+			char *value = buildSteamPath(&cfg->gamedir, &kv->value);
+			g.collection_chain = addToCollectionChain(g.collection_chain, collectionCreateFilesystem(&mem, value));
+			stackFreeUpToPosition(&stack_temp, value);
+		} else if (strncasecmp("max_maps", kv->key.str, kv->key.length) == 0) {
+			// FIXME null-terminate
+			g.maps_limit = atoi(kv->value.str);
+		} else if (strncasecmp("map", kv->key.str, kv->key.length) == 0) {
+			openSourceAddMap(kv->value.str, kv->value.length);
+		} 
+		break;
+	case VMFEntryType_SectionOpen:
+		return VMFAction_Exit;
+		break;
+
+	default:
+		return VMFAction_SemanticError;
+	}
+
+	return VMFAction_Continue;
+}
+
+static int configReadFile(const char *cfgfile) {
+	AFile file;
+	aFileReset(&file);
+	if (AFile_Success != aFileOpen(&file, cfgfile))
+		return 0;
+
+	char *buffer = stackAlloc(&stack_temp, file.size); 
+	if (!buffer)
+		return 0;
+
+	if (file.size != aFileReadAtOffset(&file, 0, file.size, buffer))
+		return 0;
+
+	Config config = {
+		.gamedir = { .str = NULL, .length = 0 }
+	};
+
+	VMFState pstate = {
+		.user_data = &config,
+		.data = { .str = buffer, .length = file.size },
+		.callback = configReadCallback
+	};
+
+	aFileClose(&file);
+
+	int result = VMFResult_Success == vmfParse(&pstate);
+
+	stackFreeUpToPosition(&stack_temp, buffer);
+	return result;
+}
+
 void attoAppInit(struct AAppProctable *proctable) {
 	profilerInit();
 	//aGLInit();
-	const char *map = 0;
-	int max_maps = 1;
 	g.collection_chain = NULL;
-
-	struct Memories mem = {
-		&stack_temp,
-		&stack_persistent
-	};
+	g.maps_limit = 1;
+	g.maps_count = 0;
+	g.selected_map = NULL;
 
 	for (int i = 1; i < a_app_state->argc; ++i) {
 		const char *argv = a_app_state->argv[i];
-		if (strcmp(argv, "-p") == 0) {
+		if (strcmp(argv, "-c") == 0) {
+			if (i == a_app_state->argc - 1) {
+				aAppDebugPrintf("-c requires an argument");
+				goto print_usage_and_exit;
+			}
+			const char *value = a_app_state->argv[++i];
+
+			PRINTF("Reading config file %s", value);
+			if (!configReadFile(value)) {
+				PRINTF("Cannot read config file %s", value);
+				goto print_usage_and_exit;
+			}
+		} else if (strcmp(argv, "-p") == 0) {
 			if (i == a_app_state->argc - 1) {
 				aAppDebugPrintf("-p requires an argument");
 				goto print_usage_and_exit;
@@ -302,22 +440,20 @@ void attoAppInit(struct AAppProctable *proctable) {
 			}
 			const char *value = a_app_state->argv[++i];
 
-			max_maps = atoi(value);
+			g.maps_limit = atoi(value);
+			if (g.maps_limit < 1)
+				g.maps_limit = 1;
 		} else {
-			if (map) {
-				aAppDebugPrintf("Only one map can be specified");
-				goto print_usage_and_exit;
-			}
-			map = argv;
+			openSourceAddMap(argv, strlen(argv));
 		}
 	}
 
-	if (!map || !g.collection_chain) {
+	if (!g.maps_count || !g.collection_chain) {
 		aAppDebugPrintf("At least one map and one collection required");
 		goto print_usage_and_exit;
 	}
 
-	opensrcInit(map, max_maps);
+	opensrcInit();
 
 	proctable->resize = opensrcResize;
 	proctable->paint = opensrcPaint;
@@ -326,6 +462,6 @@ void attoAppInit(struct AAppProctable *proctable) {
 	return;
 
 print_usage_and_exit:
-	aAppDebugPrintf("usage: %s <-d path> ... mapname", a_app_state->argv[0]);
+	aAppDebugPrintf("usage: %s <-c config> <-p vpk> <-d path> ... <mapname0> <mapname1> ...", a_app_state->argv[0]);
 	aAppTerminate(1);
 }

+ 2 - 2
src/filemap.h

@@ -2,7 +2,7 @@
 
 #include "libc.h"
 
-struct AFile {
+typedef struct AFile {
 	size_t size;
 	struct {
 #ifndef _WIN32
@@ -11,7 +11,7 @@ struct AFile {
 		HANDLE handle;
 #endif
 	} impl_;
-};
+} AFile;
 
 #define AFileError ((size_t)-1)
 

+ 12 - 0
src/render.c

@@ -682,10 +682,22 @@ void renderModelDraw(const RDrawParams *params, const struct BSPModel *model) {
 		r.closest_map.model = model;
 	}
 
+	if (params->selected) {
+		GL_CALL(glEnable(GL_BLEND));
+		GL_CALL(glBlendColor(1, 1, 1, .5f));
+		//GL_CALL(glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE));
+		GL_CALL(glBlendFunc(GL_ONE, GL_CONSTANT_ALPHA));
+		GL_CALL(glBlendEquation(GL_FUNC_ADD));
+	}
+
 	if (distance < 5000.f)
 		renderDrawSet(model, &model->detailed);
 	else
 		renderDrawSet(model, &model->coarse);
+
+	if (params->selected) {
+		GL_CALL(glDisable(GL_BLEND));
+	}
 }
 
 void renderResize(int w, int h) {

+ 1 - 1
src/render.h

@@ -62,7 +62,7 @@ void renderBegin();
 typedef struct {
 	const struct Camera *camera;
 	struct AVec3f translation;
-	float lmn;
+	int selected;
 } RDrawParams;
 
 void renderModelDraw(const RDrawParams *params, const struct BSPModel *model);