OpenSource.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. #include "bsp.h"
  2. #include "cache.h"
  3. #include "collection.h"
  4. #include "mempools.h"
  5. #include "common.h"
  6. #include "texture.h"
  7. #include "profiler.h"
  8. #include "camera.h"
  9. #include "vmfparser.h"
  10. #include "atto/app.h"
  11. #include "atto/math.h"
  12. static char persistent_data[128*1024*1024];
  13. static char temp_data[128*1024*1024];
  14. static struct Stack stack_temp = {
  15. .storage = temp_data,
  16. .size = sizeof(temp_data),
  17. .cursor = 0
  18. };
  19. static struct Stack stack_persistent = {
  20. .storage = persistent_data,
  21. .size = sizeof(persistent_data),
  22. .cursor = 0
  23. };
  24. static struct Memories mem = {
  25. &stack_temp,
  26. &stack_persistent
  27. };
  28. typedef struct Map {
  29. char *name;
  30. int loaded;
  31. struct AVec3f offset;
  32. struct AVec3f debug_offset;
  33. struct BSPModel model;
  34. struct Map *next;
  35. } Map;
  36. typedef struct Patch {
  37. const char *map_name;
  38. int delete;
  39. BSPLandmark landmark;
  40. struct Patch *next;
  41. } Patch;
  42. static struct {
  43. struct Camera camera;
  44. int forward, right, run;
  45. struct AVec3f center;
  46. float R;
  47. struct ICollection *collection_chain;
  48. Patch *patches;
  49. Map *maps_begin, *maps_end;
  50. int maps_count, maps_limit;
  51. Map *selected_map;
  52. } g;
  53. void openSourceAddMap(const char* mapname, int mapname_length) {
  54. if (g.maps_count >= g.maps_limit) {
  55. PRINTF("Map limit reached, not trying to add map %.*s",
  56. mapname_length, mapname);
  57. return;
  58. }
  59. struct Map *map = g.maps_begin;
  60. while (map) {
  61. if (strncmp(map->name, mapname, mapname_length) == 0)
  62. return;
  63. map = map->next;
  64. }
  65. char *buffer = stackAlloc(&stack_persistent, sizeof(struct Map) + mapname_length + 1);
  66. if (!buffer) {
  67. PRINT("Not enough memory");
  68. return;
  69. }
  70. memcpy(buffer, mapname, mapname_length);
  71. buffer[mapname_length] = '\0';
  72. map = (void*)(buffer + mapname_length + 1);
  73. memset(map, 0, sizeof(*map));
  74. map->name = buffer;
  75. if (!g.maps_end)
  76. g.maps_begin = map;
  77. else
  78. g.maps_end->next = map;
  79. g.maps_end = map;
  80. ++g.maps_count;
  81. PRINTF("Added new map to the queue: %.*s", mapname_length, mapname);
  82. }
  83. static void mapUpdatePosition(Map *map) {
  84. if (map == g.maps_begin && map->model.landmarks_count == 0)
  85. return;
  86. for (struct Map *map2 = g.maps_begin; map2; map2 = map2->next) {
  87. if (map2 == map || map2->loaded != 1)
  88. continue;
  89. for (int j = 0; j < map2->model.landmarks_count; ++j) {
  90. const struct BSPLandmark *m2 = map2->model.landmarks + j;
  91. for (int k = 0; k < map->model.landmarks_count; ++k) {
  92. const struct BSPLandmark *m1 = map->model.landmarks + k;
  93. if (strcmp(m1->name, m2->name) == 0) {
  94. map->offset = aVec3fAdd(aVec3fAdd(map2->offset, map2->debug_offset), aVec3fSub(m2->origin, m1->origin));
  95. PRINTF("Map %s landmark %s parent map %s offset %f, %f, %f",
  96. map->name, m1->name, map2->name, map->offset.x, map->offset.y, map->offset.z);
  97. return;
  98. } // if landmarks match
  99. } // for all landmarks of map 1
  100. } // for all landmarks of map 2
  101. } // for all maps (2)
  102. }
  103. static enum BSPLoadResult loadMap(struct Map *map, struct ICollection *collection) {
  104. struct BSPLoadModelContext loadctx = {
  105. .collection = collection,
  106. .persistent = &stack_persistent,
  107. .tmp = &stack_temp,
  108. .model = &map->model
  109. };
  110. const enum BSPLoadResult result = bspLoadWorldspawn(loadctx, map->name);
  111. if (result != BSPLoadResult_Success) {
  112. PRINTF("Cannot load map \"%s\": %d", map->name, result);
  113. return result;
  114. }
  115. aAppDebugPrintf("Loaded %s to %u draw calls", map->name, map->model.detailed.draws_count);
  116. aAppDebugPrintf("AABB (%f, %f, %f) - (%f, %f, %f)",
  117. map->model.aabb.min.x,
  118. map->model.aabb.min.y,
  119. map->model.aabb.min.z,
  120. map->model.aabb.max.x,
  121. map->model.aabb.max.y,
  122. map->model.aabb.max.z);
  123. for (const Patch *p = g.patches; p; p = p->next) {
  124. if (p->delete || strcasecmp(p->map_name, map->name) != 0)
  125. continue;
  126. int found = 0;
  127. for (int i = 0; i < map->model.landmarks_count; ++i) {
  128. struct BSPLandmark *lm = map->model.landmarks + i;
  129. if (strcasecmp(p->landmark.name, lm->name) == 0) {
  130. found = 1;
  131. break;
  132. }
  133. }
  134. if (found)
  135. continue;
  136. if (map->model.landmarks_count == BSP_MAX_LANDMARKS) {
  137. PRINTF("Too many landmarks for map %s", map->name);
  138. break;
  139. }
  140. PRINTF("Injecting landmark %s %f %f %f to map %s",
  141. p->landmark.name,
  142. p->landmark.origin.x,
  143. p->landmark.origin.y,
  144. p->landmark.origin.z,
  145. map->name);
  146. memmove(map->model.landmarks + 1, map->model.landmarks, sizeof(BSPLandmark) * map->model.landmarks_count);
  147. map->model.landmarks[0] = p->landmark;
  148. ++map->model.landmarks_count;
  149. }
  150. PRINTF("Landmarks: %d", map->model.landmarks_count);
  151. for (int i = 0; i < map->model.landmarks_count; ++i) {
  152. struct BSPLandmark *lm = map->model.landmarks + i;
  153. int deleted = 0;
  154. for (const Patch *p = g.patches; p; p = p->next) {
  155. if (strcasecmp(p->map_name, map->name) == 0 && strcasecmp(p->landmark.name, lm->name) == 0) {
  156. if (p->delete) {
  157. PRINTF("Deleting landmark %s", p->landmark.name);
  158. --map->model.landmarks_count;
  159. memmove(lm, lm + 1, sizeof(BSPLandmark) * (map->model.landmarks_count - i));
  160. deleted = 1;
  161. } else {
  162. PRINTF("Modifying landmark %s %f %f %f -> %f %f %f of map %s",
  163. p->landmark.name,
  164. p->landmark.origin.x,
  165. p->landmark.origin.y,
  166. p->landmark.origin.z,
  167. lm->origin.x,
  168. lm->origin.y,
  169. lm->origin.z,
  170. map->name);
  171. lm->origin = p->landmark.origin;
  172. }
  173. continue;
  174. }
  175. }
  176. if (deleted) {
  177. --i;
  178. continue;
  179. }
  180. PRINTF("\t%d: %s -> (%f, %f, %f)", i + 1, lm->name,
  181. lm->origin.x, lm->origin.y, lm->origin.z);
  182. }
  183. map->offset = map->debug_offset = aVec3ff(0);
  184. map->loaded = 1;
  185. mapUpdatePosition(map);
  186. return BSPLoadResult_Success;
  187. }
  188. static void opensrcInit() {
  189. cacheInit(&stack_persistent);
  190. if (!renderInit()) {
  191. PRINT("Failed to initialize render");
  192. aAppTerminate(-1);
  193. }
  194. bspInit();
  195. if (BSPLoadResult_Success != loadMap(g.maps_begin, g.collection_chain))
  196. aAppTerminate(-2);
  197. g.center = aVec3fMulf(aVec3fAdd(g.maps_begin->model.aabb.min, g.maps_begin->model.aabb.max), .5f);
  198. g.R = aVec3fLength(aVec3fSub(g.maps_begin->model.aabb.max, g.maps_begin->model.aabb.min)) * .5f;
  199. aAppDebugPrintf("Center %f, %f, %f, R~=%f", g.center.x, g.center.y, g.center.z, g.R);
  200. const float t = 0;
  201. cameraLookAt(&g.camera,
  202. aVec3fAdd(g.center, aVec3fMulf(aVec3f(cosf(t*.5f), sinf(t*.5f), .25f), g.R*.5f)),
  203. g.center, aVec3f(0.f, 0.f, 1.f));
  204. }
  205. static void opensrcResize(ATimeUs timestamp, unsigned int old_w, unsigned int old_h) {
  206. (void)(timestamp); (void)(old_w); (void)(old_h);
  207. renderResize(a_app_state->width, a_app_state->height);
  208. cameraProjection(&g.camera, 1.f, g.R * 20.f, 3.1415926f/2.f, (float)a_app_state->width / (float)a_app_state->height);
  209. cameraRecompute(&g.camera);
  210. }
  211. static void opensrcPaint(ATimeUs timestamp, float dt) {
  212. (void)(timestamp); (void)(dt);
  213. float move = dt * (g.run?3000.f:300.f);
  214. cameraMove(&g.camera, aVec3f(g.right * move, 0.f, -g.forward * move));
  215. cameraRecompute(&g.camera);
  216. renderBegin();
  217. int triangles = 0;
  218. int can_load_map = 1;
  219. for (struct Map *map = g.maps_begin; map; map = map->next) {
  220. if (map->loaded < 0)
  221. continue;
  222. if (map->loaded == 0) {
  223. if (can_load_map) {
  224. if (BSPLoadResult_Success != loadMap(map, g.collection_chain))
  225. map->loaded = -1;
  226. }
  227. can_load_map = 0;
  228. continue;
  229. }
  230. const RDrawParams params = {
  231. .camera = &g.camera,
  232. .translation = aVec3fAdd(map->offset, map->debug_offset),
  233. .selected = map == g.selected_map
  234. };
  235. renderModelDraw(&params, &map->model);
  236. for (int i = 0; i < map->model.detailed.draws_count; ++i)
  237. triangles += map->model.detailed.draws[i].count / 3;
  238. }
  239. renderEnd(&g.camera);
  240. if (profilerFrame(&stack_temp)) {
  241. PRINTF("Total triangles: %d", triangles);
  242. }
  243. }
  244. static void opensrcKeyPress(ATimeUs timestamp, AKey key, int pressed) {
  245. (void)(timestamp); (void)(key); (void)(pressed);
  246. //printf("KEY %u %d %d\n", timestamp, key, pressed);
  247. struct AVec3f map_offset = aVec3ff(0);
  248. int moved_map = 0;
  249. switch (key) {
  250. case AK_Esc:
  251. if (!pressed) break;
  252. if (a_app_state->grabbed)
  253. aAppGrabInput(0);
  254. else
  255. aAppTerminate(0);
  256. break;
  257. case AK_W: g.forward += pressed?1:-1; break;
  258. case AK_S: g.forward += pressed?-1:1; break;
  259. case AK_A: g.right += pressed?-1:1; break;
  260. case AK_D: g.right += pressed?1:-1; break;
  261. case AK_LeftShift: g.run = pressed; break;
  262. default: break;
  263. }
  264. if (pressed) {
  265. switch(key) {
  266. case AK_Up: map_offset.x += 1.f; moved_map = 1; break;
  267. case AK_Down: map_offset.x -= 1.f; moved_map = 1; break;
  268. case AK_Left: map_offset.y -= 1.f; moved_map = 1; break;
  269. case AK_Right: map_offset.y += 1.f; moved_map = 1; break;
  270. case AK_PageUp: map_offset.z += 1.f; moved_map = 1; break;
  271. case AK_PageDown: map_offset.z -= 1.f; moved_map = 1; break;
  272. case AK_Tab:
  273. g.selected_map = g.selected_map ? g.selected_map->next : g.maps_begin;
  274. if (g.selected_map)
  275. PRINTF("Selected map %s", g.selected_map->name);
  276. break;
  277. case AK_Q:
  278. g.selected_map = NULL;
  279. break;
  280. default: break;
  281. }
  282. if (moved_map && g.selected_map) {
  283. Map *map = g.selected_map;
  284. if (g.run) {
  285. map_offset.x *= 100.f;
  286. map_offset.y *= 100.f;
  287. map_offset.z *= 100.f;
  288. }
  289. map->debug_offset = aVec3fAdd(map->debug_offset, map_offset);
  290. PRINTF("Map %s offset: %f %f %f", map->name, map->debug_offset.x, map->debug_offset.y, map->debug_offset.z);
  291. for (Map *m = map; m; m = m->next)
  292. mapUpdatePosition(m);
  293. }
  294. }
  295. }
  296. static void opensrcPointer(ATimeUs timestamp, int dx, int dy, unsigned int btndiff) {
  297. (void)(timestamp); (void)(dx); (void)(dy); (void)(btndiff);
  298. //printf("PTR %u %d %d %x\n", timestamp, dx, dy, btndiff);
  299. if (a_app_state->grabbed) {
  300. cameraRotatePitch(&g.camera, dy * -4e-3f);
  301. cameraRotateYaw(&g.camera, dx * -4e-3f);
  302. cameraRecompute(&g.camera);
  303. } else if (btndiff)
  304. aAppGrabInput(1);
  305. }
  306. static struct ICollection *addToCollectionChain(struct ICollection *chain, struct ICollection *next) {
  307. if (chain) {
  308. struct ICollection *coll = chain;
  309. while (coll->next)
  310. coll = coll->next;
  311. coll->next = next;
  312. return chain;
  313. }
  314. return next;
  315. }
  316. static void opensrcAddLandmarkPatch(StringView map, StringView key, StringView value) {
  317. if (key.length >= BSP_LANDMARK_NAME_LENGTH) {
  318. PRINTF(PRI_SV " is too long", PRI_SVV(key));
  319. return;
  320. }
  321. struct AVec3f origin = aVec3ff(0);
  322. // FIXME sscanf limit by value.length
  323. if (value.length >= 5 && 3 != sscanf(value.str, "%f %f %f", &origin.x, &origin.y, &origin.z)) {
  324. PRINTF(PRI_SV " format is wrong", PRI_SVV(value));
  325. return;
  326. }
  327. Patch *new_patch = stackAlloc(mem.persistent, sizeof(Patch));
  328. new_patch->next = g.patches;
  329. g.patches = new_patch;
  330. char *map_name = stackAlloc(mem.persistent, map.length + 1);
  331. memcpy(map_name, map.str, map.length);
  332. map_name[map.length] = '\0';
  333. new_patch->map_name = map_name;
  334. new_patch->delete = value.length < 5;
  335. memcpy(new_patch->landmark.name, key.str, key.length);
  336. new_patch->landmark.name[key.length] = '\0';
  337. new_patch->landmark.origin = origin;
  338. }
  339. typedef struct {
  340. StringView gamedir;
  341. StringView current_patched_map;
  342. } Config;
  343. static char *buildSteamPath(const StringView *gamedir, const StringView *path) {
  344. // FIXME windows and macos paths?
  345. const char *home_dir = getenv("HOME");
  346. const int home_dir_length = strlen(home_dir);
  347. const char steam_basedir[] = ".local/share/Steam/steamapps/common";
  348. const int steam_basedir_length = sizeof(steam_basedir) - 1;
  349. const int length = home_dir_length + steam_basedir_length + gamedir->length + path->length + 4;
  350. char *value = stackAlloc(&stack_temp, length);
  351. if (!value)
  352. return 0;
  353. int offset = 0;
  354. memcpy(value + offset, home_dir, home_dir_length); offset += home_dir_length;
  355. value[offset++] = '/';
  356. memcpy(value + offset, steam_basedir, steam_basedir_length); offset += steam_basedir_length;
  357. value[offset++] = '/';
  358. memcpy(value + offset, gamedir->str, gamedir->length); offset += gamedir->length;
  359. value[offset++] = '/';
  360. memcpy(value + offset, path->str, path->length); offset += path->length;
  361. value[offset] = '\0';
  362. return value;
  363. }
  364. static VMFAction configPatchCallback(VMFState *state, VMFEntryType entry, const VMFKeyValue *kv);
  365. static VMFAction configReadCallback(VMFState *state, VMFEntryType entry, const VMFKeyValue *kv);
  366. static VMFAction configLandmarkCallback(VMFState *state, VMFEntryType entry, const VMFKeyValue *kv) {
  367. Config *cfg = state->user_data;
  368. switch (entry) {
  369. case VMFEntryType_KeyValue:
  370. opensrcAddLandmarkPatch(cfg->current_patched_map, kv->key, kv->value);
  371. break;
  372. case VMFEntryType_SectionClose:
  373. cfg->current_patched_map.length = 0;
  374. state->callback = configPatchCallback;
  375. break;
  376. default:
  377. return VMFAction_SemanticError;
  378. }
  379. return VMFAction_Continue;
  380. }
  381. static VMFAction configPatchCallback(VMFState *state, VMFEntryType entry, const VMFKeyValue *kv) {
  382. Config *cfg = state->user_data;
  383. switch (entry) {
  384. case VMFEntryType_SectionOpen:
  385. if (kv->key.length < 1)
  386. return VMFAction_SemanticError;
  387. cfg->current_patched_map = kv->key;
  388. state->callback = configLandmarkCallback;
  389. break;
  390. case VMFEntryType_SectionClose:
  391. return VMFAction_Exit;
  392. default:
  393. return VMFAction_SemanticError;
  394. }
  395. return VMFAction_Continue;
  396. }
  397. static VMFAction configReadCallback(VMFState *state, VMFEntryType entry, const VMFKeyValue *kv) {
  398. Config *cfg = state->user_data;
  399. switch (entry) {
  400. case VMFEntryType_KeyValue:
  401. if (strncasecmp("gamedir", kv->key.str, kv->key.length) == 0) {
  402. cfg->gamedir = kv->value;
  403. } else if (strncasecmp("vpk", kv->key.str, kv->key.length) == 0) {
  404. char *value = buildSteamPath(&cfg->gamedir, &kv->value);
  405. g.collection_chain = addToCollectionChain(g.collection_chain, collectionCreateVPK(&mem, value));
  406. stackFreeUpToPosition(&stack_temp, value);
  407. } else if (strncasecmp("dir", kv->key.str, kv->key.length) == 0) {
  408. char *value = buildSteamPath(&cfg->gamedir, &kv->value);
  409. g.collection_chain = addToCollectionChain(g.collection_chain, collectionCreateFilesystem(&mem, value));
  410. stackFreeUpToPosition(&stack_temp, value);
  411. } else if (strncasecmp("max_maps", kv->key.str, kv->key.length) == 0) {
  412. // FIXME null-terminate
  413. g.maps_limit = atoi(kv->value.str);
  414. } else if (strncasecmp("map", kv->key.str, kv->key.length) == 0) {
  415. openSourceAddMap(kv->value.str, kv->value.length);
  416. }
  417. break;
  418. case VMFEntryType_SectionOpen:
  419. if (strncasecmp("patch_landmarks", kv->key.str, kv->key.length) != 0)
  420. return VMFAction_SemanticError;
  421. state->callback = configPatchCallback;
  422. break;
  423. default:
  424. return VMFAction_SemanticError;
  425. }
  426. return VMFAction_Continue;
  427. }
  428. static int configReadFile(const char *cfgfile) {
  429. AFile file;
  430. aFileReset(&file);
  431. if (AFile_Success != aFileOpen(&file, cfgfile))
  432. return 0;
  433. char *buffer = stackAlloc(&stack_temp, file.size);
  434. if (!buffer)
  435. return 0;
  436. if (file.size != aFileReadAtOffset(&file, 0, file.size, buffer))
  437. return 0;
  438. Config config = {
  439. .gamedir = { .str = NULL, .length = 0 }
  440. };
  441. VMFState pstate = {
  442. .user_data = &config,
  443. .data = { .str = buffer, .length = file.size },
  444. .callback = configReadCallback
  445. };
  446. aFileClose(&file);
  447. int result = VMFResult_Success == vmfParse(&pstate);
  448. stackFreeUpToPosition(&stack_temp, buffer);
  449. return result;
  450. }
  451. void attoAppInit(struct AAppProctable *proctable) {
  452. profilerInit();
  453. //aGLInit();
  454. g.collection_chain = NULL;
  455. g.patches = NULL;
  456. g.maps_limit = 1;
  457. g.maps_count = 0;
  458. g.selected_map = NULL;
  459. for (int i = 1; i < a_app_state->argc; ++i) {
  460. const char *argv = a_app_state->argv[i];
  461. if (strcmp(argv, "-c") == 0) {
  462. if (i == a_app_state->argc - 1) {
  463. aAppDebugPrintf("-c requires an argument");
  464. goto print_usage_and_exit;
  465. }
  466. const char *value = a_app_state->argv[++i];
  467. PRINTF("Reading config file %s", value);
  468. if (!configReadFile(value)) {
  469. PRINTF("Cannot read config file %s", value);
  470. goto print_usage_and_exit;
  471. }
  472. } else if (strcmp(argv, "-p") == 0) {
  473. if (i == a_app_state->argc - 1) {
  474. aAppDebugPrintf("-p requires an argument");
  475. goto print_usage_and_exit;
  476. }
  477. const char *value = a_app_state->argv[++i];
  478. PRINTF("Adding vpk collection at %s", value);
  479. g.collection_chain = addToCollectionChain(g.collection_chain, collectionCreateVPK(&mem, value));
  480. } else if (strcmp(argv, "-d") == 0) {
  481. if (i == a_app_state->argc - 1) {
  482. aAppDebugPrintf("-d requires an argument");
  483. goto print_usage_and_exit;
  484. }
  485. const char *value = a_app_state->argv[++i];
  486. PRINTF("Adding dir collection at %s", value);
  487. g.collection_chain = addToCollectionChain(g.collection_chain, collectionCreateFilesystem(&mem, value));
  488. } else if (strcmp(argv, "-n") == 0) {
  489. if (i == a_app_state->argc - 1) {
  490. aAppDebugPrintf("-p requires an argument");
  491. goto print_usage_and_exit;
  492. }
  493. const char *value = a_app_state->argv[++i];
  494. g.maps_limit = atoi(value);
  495. if (g.maps_limit < 1)
  496. g.maps_limit = 1;
  497. } else {
  498. openSourceAddMap(argv, strlen(argv));
  499. }
  500. }
  501. if (!g.maps_count || !g.collection_chain) {
  502. aAppDebugPrintf("At least one map and one collection required");
  503. goto print_usage_and_exit;
  504. }
  505. opensrcInit();
  506. proctable->resize = opensrcResize;
  507. proctable->paint = opensrcPaint;
  508. proctable->key = opensrcKeyPress;
  509. proctable->pointer = opensrcPointer;
  510. return;
  511. print_usage_and_exit:
  512. aAppDebugPrintf("usage: %s <-c config> <-p vpk> <-d path> ... <mapname0> <mapname1> ...", a_app_state->argv[0]);
  513. aAppTerminate(1);
  514. }