bsp.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058
  1. #include "bsp.h"
  2. #include "atlas.h"
  3. #include "vbsp.h"
  4. #include "collection.h"
  5. #include "mempools.h"
  6. #include "vmfparser.h"
  7. #include "common.h"
  8. // DEBUG
  9. #include "texture.h"
  10. #define R2S(r) bspLoadResultString(r)
  11. const char *bspLoadResultString(enum BSPLoadResult result) {
  12. switch(result) {
  13. case BSPLoadResult_Success: return "BSPLoadResult_Success";
  14. case BSPLoadResult_ErrorFileOpen: return "BSPLoadResult_ErrorFileOpen";
  15. case BSPLoadResult_ErrorFileFormat: return "BSPLoadResult_ErrorFileFormat";
  16. case BSPLoadResult_ErrorMemory: return "BSPLoadResult_ErrorMemory";
  17. case BSPLoadResult_ErrorTempMemory: return "BSPLoadResult_ErrorTempMemory";
  18. case BSPLoadResult_ErrorCapabilities: return "BSPLoadResult_ErrorCapabilities";
  19. default: return "UNKNOWN";
  20. }
  21. }
  22. struct AnyLump {
  23. const void *p;
  24. uint32_t n;
  25. };
  26. struct Lumps {
  27. uint32_t version;
  28. #define LIST_LUMPS \
  29. BSPLUMP(Entity, char, entities); \
  30. BSPLUMP(Plane, struct VBSPLumpPlane, planes); \
  31. BSPLUMP(TexData, struct VBSPLumpTexData, texdata); \
  32. BSPLUMP(Vertex, struct VBSPLumpVertex, vertices); \
  33. \
  34. BSPLUMP(Node, struct VBSPLumpNode, nodes); \
  35. BSPLUMP(TexInfo, struct VBSPLumpTexInfo, texinfos); \
  36. BSPLUMP(Face, struct VBSPLumpFace, faces); \
  37. BSPLUMP(LightMap, struct VBSPLumpLightMap, lightmaps); \
  38. \
  39. BSPLUMP(Leaf, struct VBSPLumpLeaf, leaves); \
  40. \
  41. BSPLUMP(Edge, struct VBSPLumpEdge, edges); \
  42. BSPLUMP(Surfedge, int32_t, surfedges); \
  43. BSPLUMP(Model, struct VBSPLumpModel, models); \
  44. \
  45. BSPLUMP(LeafFace, uint16_t, leaffaces); \
  46. \
  47. BSPLUMP(DispInfo, struct VBSPLumpDispInfo, dispinfos); \
  48. \
  49. BSPLUMP(DispVerts, struct VBSPLumpDispVert, dispverts); \
  50. \
  51. BSPLUMP(PakFile, uint8_t, pakfile); \
  52. \
  53. BSPLUMP(TexDataStringData, char, texdatastringdata); \
  54. BSPLUMP(TexDataStringTable, int32_t, texdatastringtable); \
  55. \
  56. BSPLUMP(FaceHDR, struct VBSPLumpFace, faces_hdr); \
  57. \
  58. BSPLUMP(LightMapHDR, struct VBSPLumpLightMap, lightmaps_hdr); \
  59. #define BSPLUMP(name,type,field) struct{const type *p;uint32_t n;} field
  60. LIST_LUMPS
  61. #undef BSPLUMP
  62. };
  63. /* data needed for making lightmap atlas */
  64. struct Face {
  65. const struct VBSPLumpFace *vface;
  66. /* read directly from lumps */
  67. int vertices;
  68. int indices;
  69. int width, height;
  70. const struct VBSPLumpLightMap *samples;
  71. const struct VBSPLumpTexInfo *texinfo;
  72. const struct VBSPLumpTexData *texdata;
  73. const struct VBSPLumpDispInfo *dispinfo;
  74. int dispquadvtx[4]; // filled only when displaced
  75. int dispstartvtx;
  76. const Material *material;
  77. /* filled as a result of atlas allocation */
  78. int atlas_x, atlas_y;
  79. };
  80. struct LoadModelContext {
  81. struct Stack *tmp;
  82. struct ICollection *collection;
  83. const struct Lumps *lumps;
  84. const struct VBSPLumpModel *model;
  85. struct Face *faces;
  86. int faces_count;
  87. int vertices;
  88. int indices;
  89. int max_draw_vertices;
  90. struct {
  91. int pixels;
  92. int max_width;
  93. int max_height;
  94. RTexture texture;
  95. } lightmap;
  96. };
  97. enum FacePreload {
  98. FacePreload_Ok,
  99. FacePreload_Skip,
  100. FacePreload_Inconsistent
  101. };
  102. static struct {
  103. const Material *coarse_material;
  104. struct {
  105. int color[256];
  106. int exponent[256];
  107. } lightmap_tables;
  108. } bsp_global;
  109. static inline int shouldSkipFace(const struct VBSPLumpFace *face, const struct Lumps *lumps) {
  110. (void)(face); (void)(lumps);
  111. //const struct VBSPLumpTexInfo *tinfo = lumps->texinfos.p + face->texinfo;
  112. return /*(tinfo->flags & (VBSP_Surface_NoDraw | VBSP_Surface_NoLight)) ||*/ face->lightmap_offset == 0xffffffffu
  113. || face->lightmap_offset < 4;
  114. }
  115. static enum FacePreload bspFacePreloadMetadata(struct LoadModelContext *ctx,
  116. struct Face *face, unsigned index) {
  117. const struct Lumps * const lumps = ctx->lumps;
  118. #define FACE_CHECK(cond) \
  119. if (!(cond)) { PRINTF("F%d: check failed: (%s)", index, #cond); return FacePreload_Inconsistent; }
  120. FACE_CHECK(index < lumps->faces.n);
  121. const struct VBSPLumpFace * const vface = lumps->faces.p + index;
  122. face->vface = vface;
  123. if (vface->texinfo < 0) return FacePreload_Skip;
  124. FACE_CHECK((unsigned)vface->texinfo < lumps->texinfos.n);
  125. face->texinfo = lumps->texinfos.p + vface->texinfo;
  126. if (shouldSkipFace(vface, lumps)) return FacePreload_Skip;
  127. FACE_CHECK(face->texinfo->texdata < lumps->texdata.n);
  128. face->texdata = lumps->texdata.p + face->texinfo->texdata;
  129. FACE_CHECK(face->texdata->name_string_table_id < lumps->texdatastringtable.n);
  130. const int32_t texdatastringdata_offset = lumps->texdatastringtable.p[face->texdata->name_string_table_id];
  131. FACE_CHECK(texdatastringdata_offset >= 0 && (uint32_t)texdatastringdata_offset < lumps->texdatastringdata.n);
  132. /* FIXME validate string: has \0 earlier than end */
  133. const char *texture = lumps->texdatastringdata.p + texdatastringdata_offset;
  134. //PRINTF("F%u: texture %s", index, face->texture);
  135. face->material = materialGet(texture, ctx->collection, ctx->tmp);
  136. if (!face->material)
  137. return FacePreload_Skip;
  138. if (vface->dispinfo >= 0) {
  139. FACE_CHECK((unsigned)vface->dispinfo < lumps->dispinfos.n);
  140. face->dispinfo = lumps->dispinfos.p + vface->dispinfo;
  141. const int side = (1 << face->dispinfo->power) + 1;
  142. FACE_CHECK(vface->num_edges == 4);
  143. face->vertices = side * side;
  144. face->indices = (side - 1) * (side - 1) * 6; /* triangle list */
  145. /* TODO
  146. * some of the episode 2 maps have the min_tess set to flag mode, and flags are 0xe
  147. *
  148. if (face->dispinfo->min_tess != 0) {
  149. if ((uint32_t)face->dispinfo->min_tess & 0x80000000u) {
  150. if ((uint32_t)face->dispinfo->min_tess & 0x7fffffffu)
  151. PRINTF("min_tess has flags: %x", (uint32_t)face->dispinfo->min_tess & 0x7fffffffu);
  152. } else
  153. PRINTF("Power: %d, min_tess: %d, vertices: %d",
  154. face->dispinfo->power, face->dispinfo->min_tess, face->vertices);
  155. }
  156. */
  157. face->dispstartvtx = 0;
  158. } else {
  159. face->dispinfo = 0;
  160. face->vertices = vface->num_edges;
  161. face->indices = (face->vertices - 2) * 3;
  162. }
  163. /* Check for basic reference consistency */
  164. FACE_CHECK(vface->plane < lumps->planes.n);
  165. FACE_CHECK(vface->num_edges > 2);
  166. FACE_CHECK(vface->first_edge < lumps->surfedges.n && lumps->surfedges.n - vface->first_edge >= (unsigned)vface->num_edges);
  167. FACE_CHECK(vface->lightmap_offset % sizeof(struct VBSPLumpLightMap) == 0);
  168. const int lm_width = vface->lightmap_size[0] + 1;
  169. const int lm_height = vface->lightmap_size[1] + 1;
  170. const unsigned lightmap_size = lm_width * lm_height;
  171. const unsigned sample_offset = vface->lightmap_offset / sizeof(struct VBSPLumpLightMap);
  172. FACE_CHECK(sample_offset < lumps->lightmaps.n && lumps->lightmaps.n - sample_offset >= lightmap_size);
  173. const int32_t *surfedges = lumps->surfedges.p + vface->first_edge;
  174. unsigned int prev_end = 0xffffffffu;
  175. for (int i = 0; i < vface->num_edges; ++i) {
  176. uint32_t edge_index;
  177. int istart;
  178. if (surfedges[i] >= 0) {
  179. edge_index = surfedges[i];
  180. istart = 0;
  181. } else {
  182. edge_index = -surfedges[i];
  183. istart = 1;
  184. }
  185. if (edge_index >= lumps->edges.n) {
  186. PRINTF("Error: face%u surfedge%u/%u references edge %u > max edges %u",
  187. index, i, vface->num_edges, edge_index, lumps->edges.n);
  188. return FacePreload_Inconsistent;
  189. }
  190. const unsigned int vstart = lumps->edges.p[edge_index].v[istart];
  191. const unsigned int vend = lumps->edges.p[edge_index].v[1^istart];
  192. if (face->dispinfo) {
  193. face->dispquadvtx[i] = vstart;
  194. if (fabs(lumps->vertices.p[vstart].x - face->dispinfo->start_pos.x) < .5f
  195. && fabs(lumps->vertices.p[vstart].y - face->dispinfo->start_pos.y) < .5f
  196. && fabs(lumps->vertices.p[vstart].z - face->dispinfo->start_pos.z) < .5f) {
  197. face->dispstartvtx = i;
  198. }
  199. }
  200. FACE_CHECK(vstart < lumps->vertices.n);
  201. FACE_CHECK(prev_end == 0xffffffffu || prev_end == vstart);
  202. prev_end = vend;
  203. }
  204. face->width = lm_width;
  205. face->height = lm_height;
  206. face->samples = lumps->lightmaps.p + sample_offset;
  207. if (lm_width > ctx->lightmap.max_width) ctx->lightmap.max_width = lm_width;
  208. if (lm_height > ctx->lightmap.max_height) ctx->lightmap.max_height = lm_height;
  209. ctx->lightmap.pixels += lightmap_size;
  210. ctx->vertices += face->vertices;
  211. ctx->indices += face->indices;
  212. ctx->faces_count++;
  213. return FacePreload_Ok;
  214. }
  215. const int c_max_draw_vertices = 65536;
  216. static int scaleLightmapColor(int c, int exp) {
  217. const int c2 =
  218. (bsp_global.lightmap_tables.exponent[exp+128] * bsp_global.lightmap_tables.color[c]) >> 12;
  219. //const int c1 = 255.f * pow(c * powf(2.f, exp) / 255.f, 1.0f / 2.2f) * .5f;
  220. //PRINTF("%d^%d => %d, %d => %d", c, exp, c1, c2, c2 - c1);
  221. return c2 < 255 ? c2 : 255;
  222. }
  223. static enum BSPLoadResult bspLoadModelPreloadFaces(struct LoadModelContext *ctx) {
  224. ctx->faces = stackGetCursor(ctx->tmp);
  225. int current_draw_vertices = 0;
  226. for (int i = 0; i < ctx->model->num_faces; ++i) {
  227. struct Face face;
  228. const enum FacePreload result = bspFacePreloadMetadata(ctx, &face, ctx->model->first_face + i);
  229. if (result == FacePreload_Ok) {
  230. current_draw_vertices += face.vertices;
  231. struct Face *stored_face = stackAlloc(ctx->tmp, sizeof(struct Face));
  232. if (!stored_face) {
  233. PRINTF("Error: cannot allocate %zu temp bytes", sizeof(struct Face));
  234. return BSPLoadResult_ErrorTempMemory;
  235. }
  236. *stored_face = face;
  237. continue;
  238. }
  239. if (result != FacePreload_Skip)
  240. return BSPLoadResult_ErrorFileFormat;
  241. }
  242. if (!ctx->faces_count) {
  243. PRINTF("Error: no visible faces found%s", "");
  244. return BSPLoadResult_ErrorFileFormat; /* FIXME handle this */
  245. }
  246. if (ctx->max_draw_vertices < current_draw_vertices)
  247. ctx->max_draw_vertices = current_draw_vertices;
  248. return BSPLoadResult_Success;
  249. }
  250. static enum BSPLoadResult bspLoadModelLightmaps(struct LoadModelContext *ctx) {
  251. /* TODO optional sort lightmaps */
  252. struct AtlasContext atlas_context;
  253. atlas_context.temp_storage.ptr = stackGetCursor(ctx->tmp);
  254. atlas_context.temp_storage.size = stackGetFree(ctx->tmp);
  255. atlas_context.width = 16; /* TODO opengl caps */
  256. atlas_context.height = 16;
  257. atlas_context.rects = (void*)(&ctx->faces[0].width);
  258. atlas_context.rects_count = ctx->faces_count;
  259. atlas_context.rects_stride = sizeof(ctx->faces[0]);
  260. atlas_context.pos = (void*)(&ctx->faces[0].atlas_x);
  261. atlas_context.pos_stride = sizeof(ctx->faces[0]);
  262. while (atlas_context.width < (unsigned)ctx->lightmap.max_width) atlas_context.width <<= 1;
  263. while (atlas_context.height < (unsigned)ctx->lightmap.max_height) atlas_context.height <<= 1;
  264. while (atlas_context.width * atlas_context.height < (unsigned)ctx->lightmap.pixels)
  265. if (atlas_context.width < atlas_context.height) atlas_context.width <<= 1; else atlas_context.height <<= 1;
  266. for(;;) {
  267. const enum AtlasResult result = atlasCompute(&atlas_context);
  268. PRINTF("atlas: %u %u %u", atlas_context.width, atlas_context.height, result);
  269. if (result == Atlas_Success)
  270. break;
  271. if (result == Atlas_ErrorInsufficientTemp)
  272. return BSPLoadResult_ErrorTempMemory;
  273. if (atlas_context.width < atlas_context.height) atlas_context.width <<= 1; else atlas_context.height <<= 1;
  274. if (atlas_context.width > 2048 || atlas_context.height > 2048) /* TODO limit based on GL driver caps */
  275. return BSPLoadResult_ErrorCapabilities;
  276. }
  277. /* Build an atlas texture based on calculated fragment positions */
  278. const size_t atlas_size = sizeof(uint16_t) * atlas_context.width * atlas_context.height;
  279. uint16_t *const pixels = stackAlloc(ctx->tmp, atlas_size);
  280. if (!pixels) return BSPLoadResult_ErrorTempMemory;
  281. memset(pixels, 0x0f, atlas_size); /* TODO debug pattern */
  282. for (int i = 0; i < ctx->faces_count; ++i) {
  283. const struct Face *const face = ctx->faces + i;
  284. ASSERT((unsigned)face->atlas_x + face->width <= atlas_context.width);
  285. ASSERT((unsigned)face->atlas_y + face->height <= atlas_context.height);
  286. for (int y = 0; y < face->height; ++y) {
  287. for (int x = 0; x < face->width; ++x) {
  288. const struct VBSPLumpLightMap *const pixel = face->samples + x + y * face->width;
  289. const unsigned int
  290. r = scaleLightmapColor(pixel->r, pixel->exponent),
  291. g = scaleLightmapColor(pixel->g, pixel->exponent),
  292. b = scaleLightmapColor(pixel->b, pixel->exponent);
  293. pixels[face->atlas_x + x + (face->atlas_y + y) * atlas_context.width]
  294. = ((r&0xf8) << 8) | ((g&0xfc) << 3) | (b >> 3);
  295. } /* for x */
  296. } /* for y */
  297. } /* fot all visible faces */
  298. RTextureUploadParams upload;
  299. upload.width = atlas_context.width;
  300. upload.height = atlas_context.height;
  301. upload.format = RTexFormat_RGB565;
  302. upload.pixels = pixels;
  303. upload.mip_level = -2;
  304. upload.type = RTexType_2D;
  305. upload.wrap = RTexWrap_Clamp;
  306. renderTextureInit(&ctx->lightmap.texture);
  307. renderTextureUpload(&ctx->lightmap.texture, upload);
  308. //ctx->lightmap.texture.min_filter = RTmF_Nearest;
  309. /* pixels buffer is not needed anymore */
  310. stackFreeUpToPosition(ctx->tmp, pixels);
  311. return BSPLoadResult_Success;
  312. }
  313. static inline struct AVec3f aVec3fLumpVec(struct VBSPLumpVertex v) { return aVec3f(v.x, v.y, v.z); }
  314. static inline float clamp(float x, float min, float max) {
  315. return x < min ? min : (x > max ? max : x);
  316. }
  317. #ifdef DEBUG_DISP_LIGHTMAP
  318. static int shouldSwapUV(struct AVec3f mapU, struct AVec3f mapV, const struct AVec3f *v) {
  319. float mappedU = 0.f, mappedV = 0.f;
  320. for (int i = 0; i < 4; ++i) {
  321. const float U = aVec3fDot(mapU, aVec3fSub(v[(i+1)%4], v[i]));
  322. if (U > mappedU) mappedU = U;
  323. const float V = aVec3fDot(mapV, aVec3fSub(v[(i+1)%4], v[i]));
  324. if (V > mappedV) mappedV = V;
  325. }
  326. const float dX1 = aVec3fLength2(aVec3fSub(v[3], v[0]));
  327. const float dX2 = aVec3fLength2(aVec3fSub(v[2], v[1]));
  328. const float dY1 = aVec3fLength2(aVec3fSub(v[1], v[0]));
  329. const float dY2 = aVec3fLength2(aVec3fSub(v[2], v[3]));
  330. const float maxDX = (dX1 > dX2) ? dX1 : dX2;
  331. const float maxDY = (dY1 > dY2) ? dY1 : dY2;
  332. //PRINTF("mappedU=%f mappedV=%f maxDX=%f, maxDY=%f", mappedU, mappedV, maxDX, maxDY);
  333. return (mappedU > mappedV) != (maxDX > maxDY);
  334. }
  335. #endif /* DEBUG_DISP_LIGHTMAP */
  336. static void bspLoadDisplacement(
  337. const struct LoadModelContext *ctx,
  338. const struct Face *face,
  339. struct BSPModelVertex *out_vertices, uint16_t *out_indices, int index_shift) {
  340. const int side = (1 << face->dispinfo->power) + 1;
  341. const struct VBSPLumpVertex *const vertices = ctx->lumps->vertices.p;
  342. const struct VBSPLumpTexInfo * const tinfo = face->texinfo;
  343. const struct VBSPLumpDispVert *const dispvert = ctx->lumps->dispverts.p + face->dispinfo->vtx_start;
  344. //if (face->dispstartvtx != 0) PRINTF("dispstartvtx = %d", face->dispstartvtx);
  345. const struct AVec3f vec[4] = { /* bl, tl, tr, br */
  346. aVec3fLumpVec(vertices[face->dispquadvtx[(face->dispstartvtx + 0)%4]]),
  347. aVec3fLumpVec(vertices[face->dispquadvtx[(face->dispstartvtx + 1)%4]]),
  348. aVec3fLumpVec(vertices[face->dispquadvtx[(face->dispstartvtx + 2)%4]]),
  349. aVec3fLumpVec(vertices[face->dispquadvtx[(face->dispstartvtx + 3)%4]])};
  350. /*
  351. const struct AVec3f ovec[4] = {
  352. aVec3fAdd(vec[0], aVec3fMulf(aVec3f(dispvert[0].x, dispvert[0].y, dispvert[0].z), dispvert[0].dist)),
  353. aVec3fAdd(vec[1], aVec3fMulf(aVec3f(dispvert[side*(side-1)].x, dispvert[side*(side-1)].y, dispvert[side*(side-1)].z), dispvert[side*(side-1)].dist)),
  354. aVec3fAdd(vec[2], aVec3fMulf(aVec3f(dispvert[side*side-1].x, dispvert[side*side-1].y, dispvert[side*side-1].z), dispvert[side*side-1].dist)),
  355. aVec3fAdd(vec[3], aVec3fMulf(aVec3f(dispvert[side-1].x, dispvert[side-1].y, dispvert[side-1].z), dispvert[side-1].dist))};
  356. */
  357. const struct AVec3f lm_map_u = aVec3f(
  358. tinfo->lightmap_vecs[0][0], tinfo->lightmap_vecs[0][1], tinfo->lightmap_vecs[0][2]);
  359. const float luxels_per_unit = aVec3fLength(lm_map_u);
  360. float length_lm_u = luxels_per_unit * floatMax(
  361. aVec3fLength(aVec3fSub(vec[3], vec[0])),
  362. aVec3fLength(aVec3fSub(vec[2], vec[1])));
  363. float length_lm_v = luxels_per_unit * floatMax(
  364. aVec3fLength(aVec3fSub(vec[1], vec[0])),
  365. aVec3fLength(aVec3fSub(vec[2], vec[3])));
  366. const struct AVec4f tex_map_u = aVec4f(
  367. tinfo->texture_vecs[0][0], tinfo->texture_vecs[0][1],
  368. tinfo->texture_vecs[0][2], tinfo->texture_vecs[0][3]);
  369. const struct AVec4f tex_map_v = aVec4f(
  370. tinfo->texture_vecs[1][0], tinfo->texture_vecs[1][1],
  371. tinfo->texture_vecs[1][2], tinfo->texture_vecs[1][3]);
  372. #ifdef DEBUG_DISP_LIGHTMAP
  373. const int swap = shouldSwapUV(
  374. aVec3f(tinfo->lightmap_vecs[0][0], tinfo->lightmap_vecs[0][1], tinfo->lightmap_vecs[0][2]),
  375. aVec3f(tinfo->lightmap_vecs[1][0], tinfo->lightmap_vecs[1][1], tinfo->lightmap_vecs[1][2]), vec);
  376. #endif /*ifdef DEBUG_DISP_LIGHTMAP*/
  377. const struct AVec2f atlas_scale = aVec2f(1.f / ctx->lightmap.texture.width, 1.f / ctx->lightmap.texture.height);
  378. const struct AVec2f atlas_offset = aVec2f(
  379. .5f + face->atlas_x /*+ tinfo->lightmap_vecs[0][3] - face->face->lightmap_min[0]*/,
  380. .5f + face->atlas_y /*+ tinfo->lightmap_vecs[1][3] - face->face->lightmap_min[1]*/);
  381. if (length_lm_u < 0. || length_lm_u >= face->width
  382. || length_lm_v < 0. || length_lm_v >= face->height) {
  383. PRINTF("LM OOB: (%f, %f) (%d, %d)", length_lm_u, length_lm_v, face->width, face->height);
  384. if (length_lm_u >= face->width) length_lm_u = (float)(face->width - 1);
  385. if (length_lm_v >= face->height) length_lm_v = (float)(face->height - 1);
  386. }
  387. /*
  388. PRINTF("%f %f %f %f",
  389. tinfo->lightmap_vecs[0][3] * atlas_scale.x, face->face->lightmap_min[0] * atlas_scale.x,
  390. tinfo->lightmap_vecs[1][3] * atlas_scale.y, face->face->lightmap_min[1] * atlas_scale.y);
  391. */
  392. const float div_side = 1.f / (side - 1);
  393. for (int y = 0; y < side; ++y) {
  394. const float ty = (float)y * div_side;
  395. const struct AVec3f vl = aVec3fMix(vec[0], vec[1], ty);
  396. const struct AVec3f vr = aVec3fMix(vec[3], vec[2], ty);
  397. for (int x = 0; x < side; ++x) {
  398. const float tx = (float)x * div_side;
  399. struct BSPModelVertex * const v = out_vertices + y * side + x;
  400. const struct VBSPLumpDispVert * const dv = dispvert + y * side + x;
  401. v->vertex = aVec3fMix(vl, vr, tx);
  402. v->lightmap_uv = aVec2f(tx * length_lm_u, ty * length_lm_v);
  403. v->tex_uv = aVec2f(
  404. aVec4fDot(aVec4f3(v->vertex, 1.f), tex_map_u),
  405. aVec4fDot(aVec4f3(v->vertex, 1.f), tex_map_v));
  406. v->vertex = aVec3fAdd(aVec3fMix(vl, vr, tx), aVec3fMulf(aVec3f(dv->x, dv->y, dv->z), dv->dist));
  407. if (v->lightmap_uv.x < 0 || v->lightmap_uv.y < 0 || v->lightmap_uv.x > face->width || v->lightmap_uv.y > face->height)
  408. PRINTF("Error: DISP OOB LM F:V%u: x=%f y=%f z=%f tx=%f, ty=%f u=%f v=%f w=%d h=%d",
  409. x + y * side, v->vertex.x, v->vertex.y, v->vertex.z, tx, ty, v->lightmap_uv.x, v->lightmap_uv.y, face->width, face->height);
  410. v->lightmap_uv = aVec2fMul(aVec2fAdd(v->lightmap_uv, atlas_offset), atlas_scale);
  411. #if 0
  412. #ifdef DEBUG_DISP_LIGHTMAP
  413. v->normal = aVec3f(face->dispstartvtx/3.f, swap, dv->dist / 100.f);
  414. #else
  415. /* FIXME normal */
  416. v->normal = aVec3ff(0.f);
  417. #endif
  418. #endif
  419. }
  420. }
  421. for (int y = 0; y < side - 1; ++y) {
  422. for (int x = 0; x < side - 1; ++x) {
  423. const int base = index_shift + y * side + x;
  424. *out_indices++ = base;
  425. *out_indices++ = base + side + 1;
  426. *out_indices++ = base + side;
  427. *out_indices++ = base;
  428. *out_indices++ = base + 1;
  429. *out_indices++ = base + side + 1;
  430. }
  431. }
  432. }
  433. static void bspLoadFace(
  434. const struct LoadModelContext *ctx,
  435. const struct Face *face,
  436. struct BSPModelVertex *out_vertices, uint16_t *out_indices, int index_shift) {
  437. const struct VBSPLumpFace *vface = face->vface;
  438. const struct VBSPLumpTexInfo * const tinfo = face->texinfo;
  439. struct AVec3f normal;
  440. normal.x = ctx->lumps->planes.p[vface->plane].x;
  441. normal.y = ctx->lumps->planes.p[vface->plane].y;
  442. normal.z = ctx->lumps->planes.p[vface->plane].z;
  443. if (vface->side) normal = aVec3fNeg(normal);
  444. const struct AVec4f lm_map_u = aVec4f(
  445. tinfo->lightmap_vecs[0][0], tinfo->lightmap_vecs[0][1],
  446. tinfo->lightmap_vecs[0][2], tinfo->lightmap_vecs[0][3] - vface->lightmap_min[0]);
  447. const struct AVec4f lm_map_v = aVec4f(
  448. tinfo->lightmap_vecs[1][0], tinfo->lightmap_vecs[1][1],
  449. tinfo->lightmap_vecs[1][2], tinfo->lightmap_vecs[1][3] - vface->lightmap_min[1]);
  450. const struct AVec4f tex_map_u = aVec4f(
  451. tinfo->texture_vecs[0][0], tinfo->texture_vecs[0][1],
  452. tinfo->texture_vecs[0][2], tinfo->texture_vecs[0][3]);
  453. const struct AVec4f tex_map_v = aVec4f(
  454. tinfo->texture_vecs[1][0], tinfo->texture_vecs[1][1],
  455. tinfo->texture_vecs[1][2], tinfo->texture_vecs[1][3]);
  456. const int32_t * const surfedges = ctx->lumps->surfedges.p + vface->first_edge;
  457. for (int iedge = 0; iedge < vface->num_edges; ++iedge) {
  458. const uint16_t vstart = (surfedges[iedge] >= 0)
  459. ? ctx->lumps->edges.p[surfedges[iedge]].v[0]
  460. : ctx->lumps->edges.p[-surfedges[iedge]].v[1];
  461. const struct VBSPLumpVertex * const lv = ctx->lumps->vertices.p + vstart;
  462. struct BSPModelVertex * const vertex = out_vertices + iedge;
  463. vertex->vertex = aVec3f(lv->x, lv->y, lv->z);
  464. //vertex->normal = normal;
  465. vertex->lightmap_uv = aVec2f(
  466. aVec4fDot(aVec4f3(vertex->vertex, 1.f), lm_map_u),
  467. aVec4fDot(aVec4f3(vertex->vertex, 1.f), lm_map_v));
  468. vertex->tex_uv = aVec2f(
  469. aVec4fDot(aVec4f3(vertex->vertex, 1.f), tex_map_u),
  470. aVec4fDot(aVec4f3(vertex->vertex, 1.f), tex_map_v));
  471. vertex->lightmap_uv.x = clamp(vertex->lightmap_uv.x, 0.f, face->width);
  472. vertex->lightmap_uv.y = clamp(vertex->lightmap_uv.y, 0.f, face->height);
  473. /*
  474. if (vertex->lightmap_uv.x < 0 || vertex->lightmap_uv.y < 0 || vertex->lightmap_uv.x > face->width || vertex->lightmap_uv.y > face->height)
  475. PRINTF("Error: OOB LM F:V%u: x=%f y=%f z=%f u=%f v=%f w=%d h=%d", iedge, lv->x, lv->y, lv->z, vertex->lightmap_uv.x, vertex->lightmap_uv.y, face->width, face->height);
  476. */
  477. vertex->lightmap_uv.x = (vertex->lightmap_uv.x + face->atlas_x + .5f) / ctx->lightmap.texture.width;
  478. vertex->lightmap_uv.y = (vertex->lightmap_uv.y + face->atlas_y + .5f) / ctx->lightmap.texture.height;
  479. if (iedge > 1) {
  480. out_indices[(iedge-2)*3+0] = index_shift + 0;
  481. out_indices[(iedge-2)*3+1] = index_shift + iedge;
  482. out_indices[(iedge-2)*3+2] = index_shift + iedge - 1;
  483. }
  484. }
  485. }
  486. static int faceMaterialCompare(const void *a, const void *b) {
  487. const struct Face *fa = a, *fb = b;
  488. if (fa->material == fb->material)
  489. return 0;
  490. return fa->material->base_texture.texture - fb->material->base_texture.texture;
  491. }
  492. static enum BSPLoadResult bspLoadModelDraws(const struct LoadModelContext *ctx, struct Stack *persistent,
  493. struct BSPModel *model) {
  494. void * const tmp_cursor = stackGetCursor(ctx->tmp);
  495. struct BSPModelVertex * const vertices_buffer
  496. = stackAlloc(ctx->tmp, sizeof(struct BSPModelVertex) * ctx->max_draw_vertices);
  497. if (!vertices_buffer) return BSPLoadResult_ErrorTempMemory;
  498. /* each vertex after second in a vface is a new triangle */
  499. uint16_t * const indices_buffer = stackAlloc(ctx->tmp, sizeof(uint16_t) * ctx->indices);
  500. if (!indices_buffer) return BSPLoadResult_ErrorTempMemory;
  501. qsort(ctx->faces, ctx->faces_count, sizeof(*ctx->faces), faceMaterialCompare);
  502. {
  503. int vbo_offset = 0, vertex_pos = 0;
  504. model->detailed.draws_count = 1;
  505. model->coarse.draws_count = 1;
  506. for (int iface = 0; iface < ctx->faces_count; ++iface) {
  507. const struct Face *face = ctx->faces + iface;
  508. const int update_vbo_offset = (vertex_pos - vbo_offset) + face->vertices >= c_max_draw_vertices;
  509. if (update_vbo_offset || (iface > 0 && faceMaterialCompare(ctx->faces+iface-1,face) != 0)) {
  510. //PRINTF("%p -> %p", (void*)ctx->faces[iface-1].material->base_texture[0], (void*)face->material->base_texture[0]);
  511. ++model->detailed.draws_count;
  512. }
  513. if (update_vbo_offset) {
  514. vbo_offset = vertex_pos;
  515. ++model->coarse.draws_count;
  516. }
  517. vertex_pos += face->vertices;
  518. }
  519. }
  520. PRINTF("Faces: %d -> %d detailed draws", ctx->faces_count, model->detailed.draws_count);
  521. model->detailed.draws = stackAlloc(persistent, sizeof(struct BSPDraw) * model->detailed.draws_count);
  522. model->coarse.draws = stackAlloc(persistent, sizeof(struct BSPDraw) * model->coarse.draws_count);
  523. int vertex_pos = 0;
  524. int draw_indices_start = 0, indices_pos = 0;
  525. int vbo_offset = 0;
  526. int idraw = 0;
  527. struct BSPDraw *detailed_draw = model->detailed.draws - 1,
  528. *coarse_draw = model->coarse.draws - 1;
  529. for (int iface = 0; iface < ctx->faces_count/* + 1*/; ++iface) {
  530. const struct Face *face = ctx->faces + iface;
  531. const int update_vbo_offset = (vertex_pos - vbo_offset) + face->vertices >= c_max_draw_vertices;
  532. if (update_vbo_offset) {
  533. PRINTF("vbo_offset %d -> %d", vbo_offset, vertex_pos);
  534. vbo_offset = vertex_pos;
  535. }
  536. if (update_vbo_offset || iface == 0 || faceMaterialCompare(ctx->faces+iface-1,face) != 0) {
  537. ++detailed_draw;
  538. detailed_draw->start = draw_indices_start;
  539. detailed_draw->count = 0;
  540. detailed_draw->vbo_offset = vbo_offset;
  541. detailed_draw->material = face->material;
  542. ++idraw;
  543. ASSERT(idraw <= model->detailed.draws_count);
  544. }
  545. if (update_vbo_offset || iface == 0) {
  546. ++coarse_draw;
  547. coarse_draw->start = draw_indices_start;
  548. coarse_draw->count = 0;
  549. coarse_draw->vbo_offset = vbo_offset;
  550. coarse_draw->material = bsp_global.coarse_material;
  551. }
  552. if (face->dispinfo) {
  553. bspLoadDisplacement(ctx, face, vertices_buffer + vertex_pos, indices_buffer + indices_pos, vertex_pos - vbo_offset);
  554. } else {
  555. bspLoadFace(ctx, face, vertices_buffer + vertex_pos, indices_buffer + indices_pos, vertex_pos - vbo_offset);
  556. }
  557. for (int i = 0; i < face->vertices; ++i) {
  558. vertices_buffer[vertex_pos + i].average_color.r =
  559. (uint8_t)(face->material->average_color.x * 255.f);
  560. vertices_buffer[vertex_pos + i].average_color.g =
  561. (uint8_t)(face->material->average_color.y * 255.f);
  562. vertices_buffer[vertex_pos + i].average_color.b =
  563. (uint8_t)(face->material->average_color.z * 255.f);
  564. }
  565. vertex_pos += face->vertices;
  566. indices_pos += face->indices;
  567. detailed_draw->count += indices_pos - draw_indices_start;
  568. coarse_draw->count += indices_pos - draw_indices_start;
  569. //vertex_pos = 0;
  570. draw_indices_start = indices_pos;
  571. }
  572. ASSERT(idraw == model->detailed.draws_count);
  573. renderBufferCreate(&model->ibo, RBufferType_Index, sizeof(uint16_t) * ctx->indices, indices_buffer);
  574. renderBufferCreate(&model->vbo, RBufferType_Vertex, sizeof(struct BSPModelVertex) * vertex_pos, vertices_buffer);
  575. stackFreeUpToPosition(ctx->tmp, tmp_cursor);
  576. return BSPLoadResult_Success;
  577. }
  578. static enum BSPLoadResult bspLoadModel(
  579. struct ICollection *collection, struct BSPModel *model, struct Stack *persistent, struct Stack *temp,
  580. const struct Lumps *lumps, unsigned index) {
  581. struct LoadModelContext context;
  582. memset(&context, 0, sizeof context);
  583. ASSERT(index < lumps->models.n);
  584. context.tmp = temp;
  585. context.collection = collection;
  586. context.lumps = lumps;
  587. context.model = lumps->models.p + index;
  588. /* Step 1. Collect lightmaps for all faces */
  589. enum BSPLoadResult result = bspLoadModelPreloadFaces(&context);
  590. if (result != BSPLoadResult_Success) {
  591. PRINTF("Error: bspLoadModelPreloadFaces() => %s", R2S(result));
  592. return result;
  593. }
  594. /* Step 2. Build an atlas of all lightmaps */
  595. result = bspLoadModelLightmaps(&context);
  596. if (result != BSPLoadResult_Success) {
  597. PRINTF("Error: bspLoadModelLightmaps() => %s", R2S(result));
  598. return result;
  599. }
  600. /* Step 3. Generate draw operations data */
  601. result = bspLoadModelDraws(&context, persistent, model);
  602. if (result != BSPLoadResult_Success) {
  603. //aGLTextureDestroy(&context.lightmap.texture);
  604. return result;
  605. }
  606. model->lightmap = context.lightmap.texture;
  607. model->aabb.min.x = context.model->min.x;
  608. model->aabb.min.y = context.model->min.y;
  609. model->aabb.min.z = context.model->min.z;
  610. model->aabb.max.x = context.model->max.x;
  611. model->aabb.max.y = context.model->max.y;
  612. model->aabb.max.z = context.model->max.z;
  613. return BSPLoadResult_Success;
  614. } // bspLoadModel()
  615. static const char *bsp_skybox_suffix[6] = {
  616. "rt", "lf", "ft", "bk", "up", "dn" };
  617. static void bspLoadSkybox(StringView name, ICollection *coll, Stack *tmp, struct BSPModel *model) {
  618. PRINTF("Loading skybox %.*s", name.length, name.str);
  619. char *zname = alloca(name.length + 3 + 7);
  620. memset(zname, 0, name.length + 3 + 7);
  621. memcpy(zname, "skybox/", 7);
  622. memcpy(zname + 7, name.str, name.length);
  623. for (int i = 0; i < 6; ++i) {
  624. memcpy(zname + name.length + 7, bsp_skybox_suffix[i], 2);
  625. model->skybox[i] = materialGet(zname, coll, tmp);
  626. }
  627. }
  628. typedef struct {
  629. const char *name;
  630. StringView value;
  631. } EntityProp;
  632. #define ENTITY_LIST_PROPS \
  633. ENTITY_PROP(ClassName, classname) \
  634. ENTITY_PROP(TargetName, targetname) \
  635. ENTITY_PROP(Origin, origin) \
  636. ENTITY_PROP(SkyName, skyname) \
  637. ENTITY_PROP(Landmark, landmark) \
  638. ENTITY_PROP(Map, map) \
  639. typedef enum {
  640. #define ENTITY_PROP(name, string) \
  641. EntityPropIndex_##name,
  642. ENTITY_LIST_PROPS
  643. #undef ENTITY_PROP
  644. } EntityPropIndex;
  645. typedef struct {
  646. BSPLoadModelContext *ctx;
  647. EntityProp *props;
  648. int props_count;
  649. } Entity;
  650. typedef BSPLoadResult (*BspProcessEntityProc)(BSPLoadModelContext *ctx, const Entity *entity);
  651. BSPLoadResult bspReadAndAddLandmark(BSPLoadModelContext *ctx, StringView target_name, StringView origin) {
  652. struct BSPModel *model = ctx->model;
  653. if (model->landmarks_count == BSP_MAX_LANDMARKS) {
  654. PRINT("Too many landmarks");
  655. return BSPLoadResult_ErrorMemory;
  656. }
  657. struct BSPLandmark *landmark = model->landmarks + model->landmarks_count;
  658. if (target_name.length >= (int)sizeof(landmark->name)) {
  659. PRINTF("Landmark name \"%.*s\" is too long",
  660. PRI_SVV(target_name));
  661. return BSPLoadResult_ErrorMemory;
  662. }
  663. memcpy(landmark->name, target_name.str, target_name.length);
  664. landmark->name[target_name.length] = '\0';
  665. // FIXME props[EntityPropIndex_Origin].value is not null-terminated suman
  666. if (3 != sscanf(origin.str, "%f %f %f",
  667. &landmark->origin.x,
  668. &landmark->origin.y,
  669. &landmark->origin.z))
  670. {
  671. PRINTF("Cannot read x, y, z from origin=\"%.*s\"", PRI_SVV(origin));
  672. return BSPLoadResult_ErrorFileFormat;
  673. }
  674. ++model->landmarks_count;
  675. return BSPLoadResult_Success;
  676. }
  677. static BSPLoadResult bspProcessEntityInfoLandmark(BSPLoadModelContext *ctx, const Entity *entity) {
  678. const StringView target_name = entity->props[EntityPropIndex_TargetName].value;
  679. const StringView origin = entity->props[EntityPropIndex_Origin].value;
  680. return bspReadAndAddLandmark(ctx, target_name, origin);
  681. }
  682. static BSPLoadResult bspProcessEntityInfoLandmarkEntry(BSPLoadModelContext *ctx, const Entity *entity) {
  683. const int landmark_name_length = ctx->prev_map_name.length + ctx->name.length + 5;
  684. char *landmark_name_buf = stackAlloc(ctx->tmp, landmark_name_length);
  685. memcpy(landmark_name_buf, ctx->prev_map_name.str, ctx->prev_map_name.length);
  686. memcpy(landmark_name_buf + ctx->prev_map_name.length, "_to_", 4);
  687. memcpy(landmark_name_buf + ctx->prev_map_name.length + 4, ctx->name.str, ctx->name.length);
  688. landmark_name_buf[landmark_name_length-1] = '\0';
  689. const StringView target_name = { .str = landmark_name_buf, .length = landmark_name_length };
  690. const StringView origin = entity->props[EntityPropIndex_Origin].value;
  691. const BSPLoadResult result = bspReadAndAddLandmark(ctx, target_name, origin);
  692. stackFreeUpToPosition(ctx->tmp, landmark_name_buf);
  693. return result;
  694. }
  695. static BSPLoadResult bspProcessEntityInfoLandmarkExit(BSPLoadModelContext *ctx, const Entity *entity) {
  696. const int landmark_name_length = ctx->next_map_name.length + ctx->name.length + 5;
  697. char *landmark_name_buf = stackAlloc(ctx->tmp, landmark_name_length);
  698. memcpy(landmark_name_buf, ctx->name.str, ctx->name.length);
  699. memcpy(landmark_name_buf + ctx->name.length, "_to_", 4);
  700. memcpy(landmark_name_buf + ctx->name.length + 4, ctx->next_map_name.str, ctx->next_map_name.length);
  701. landmark_name_buf[landmark_name_length-1] = '\0';
  702. const StringView target_name = { .str = landmark_name_buf, .length = landmark_name_length };
  703. const StringView origin = entity->props[EntityPropIndex_Origin].value;
  704. const BSPLoadResult result = bspReadAndAddLandmark(ctx, target_name, origin);
  705. stackFreeUpToPosition(ctx->tmp, landmark_name_buf);
  706. return result;
  707. }
  708. static BSPLoadResult bspProcessEntityTriggerChangelevel(struct BSPLoadModelContext *ctx, const Entity *entity) {
  709. (void)ctx;
  710. openSourceAddMap(entity->props[EntityPropIndex_Map].value);
  711. return BSPLoadResult_Success;
  712. }
  713. static BSPLoadResult bspProcessEntityWorldspawn(struct BSPLoadModelContext *ctx, const Entity *entity) {
  714. (void)ctx;
  715. const StringView skyname = entity->props[EntityPropIndex_SkyName].value;
  716. if (skyname.length > 0) {
  717. const StringView sky = { skyname.str, skyname.length };
  718. bspLoadSkybox(sky, ctx->collection, ctx->tmp, ctx->model);
  719. }
  720. return BSPLoadResult_Success;
  721. }
  722. static struct {
  723. const char *classname;
  724. BspProcessEntityProc proc;
  725. } entity_procs[] = {
  726. {"info_landmark", bspProcessEntityInfoLandmark},
  727. {"info_landmark_entry", bspProcessEntityInfoLandmarkEntry},
  728. {"info_landmark_exit", bspProcessEntityInfoLandmarkExit},
  729. {"trigger_changelevel", bspProcessEntityTriggerChangelevel},
  730. {"worldspawn", bspProcessEntityWorldspawn},
  731. };
  732. static VMFAction bspReadEntityProps(VMFState *state, VMFEntryType entry, const VMFKeyValue *kv) {
  733. Entity *entity = state->user_data;
  734. switch (entry) {
  735. case VMFEntryType_KeyValue:
  736. for (int i = 0; i < entity->props_count; ++i) {
  737. if (strncmp(entity->props[i].name, kv->key.str, kv->key.length) == 0) {
  738. entity->props[i].value = kv->value;
  739. break;
  740. }
  741. }
  742. break;
  743. case VMFEntryType_SectionOpen:
  744. for (int i = 0; i < entity->props_count; ++i) {
  745. entity->props[i].value.str = NULL;
  746. entity->props[i].value.length = 0;
  747. }
  748. break;
  749. case VMFEntryType_SectionClose:
  750. for (int i = 0; i < (int)COUNTOF(entity_procs); ++i) {
  751. const StringView classname = entity->props[EntityPropIndex_ClassName].value;
  752. if (strncmp(entity_procs[i].classname, classname.str, classname.length) == 0) {
  753. entity_procs[i].proc(entity->ctx, entity);
  754. break;
  755. }
  756. }
  757. break;
  758. }
  759. return VMFAction_Continue;
  760. }
  761. BSPLoadResult bspReadEntities(BSPLoadModelContext *ctx, const char *str, int length) {
  762. ctx->model->landmarks_count = 0;
  763. EntityProp props[] = {
  764. #define ENTITY_PROP(name, string) \
  765. {#string, {NULL, 0}},
  766. ENTITY_LIST_PROPS
  767. #undef ENTITY_PROP
  768. };
  769. Entity entity = {
  770. .ctx = ctx,
  771. .props = props,
  772. .props_count = COUNTOF(props),
  773. };
  774. VMFState parser_state = {
  775. .user_data = &entity,
  776. .data = { .str = str, .length = length },
  777. .callback = bspReadEntityProps,
  778. };
  779. return VMFResult_Success == vmfParse(&parser_state)
  780. ? BSPLoadResult_Success : BSPLoadResult_ErrorFileFormat;
  781. }
  782. static int lumpRead(const char *name, const struct VBSPLumpHeader *header,
  783. struct IFile *file, struct Stack *tmp,
  784. struct AnyLump *out_ptr, uint32_t item_size) {
  785. out_ptr->p = stackAlloc(tmp, header->size);
  786. if (!out_ptr->p) {
  787. PRINTF("Not enough temp memory to allocate storage for lump %s; need: %d (%x)", name, header->size, header->size);
  788. return -1;
  789. }
  790. const size_t bytes = file->read(file, header->file_offset, header->size, (void*)out_ptr->p);
  791. if (bytes != header->size) {
  792. PRINTF("Cannot read full lump %s, read only %zu bytes out of %u", name, bytes, header->size);
  793. return -1;
  794. }
  795. PRINTF("Read lump %s, offset %u, size %u bytes / %u item = %u elements",
  796. name, header->file_offset, header->size, item_size, header->size / item_size);
  797. out_ptr->n = header->size / item_size;
  798. return 1;
  799. }
  800. enum BSPLoadResult bspLoadWorldspawn(BSPLoadModelContext context) {
  801. enum BSPLoadResult result = BSPLoadResult_Success;
  802. struct IFile *file = 0;
  803. if (CollectionOpen_Success !=
  804. collectionChainOpen(context.collection, context.name.str /* FIXME assumes null-terminated string */, File_Map, &file)) {
  805. return BSPLoadResult_ErrorFileOpen;
  806. }
  807. void *tmp_cursor = stackGetCursor(context.tmp);
  808. struct ICollection *pakfile = NULL;
  809. struct VBSPHeader vbsp_header;
  810. size_t bytes = file->read(file, 0, sizeof vbsp_header, &vbsp_header);
  811. if (bytes < sizeof(vbsp_header)) {
  812. PRINTF("Size is too small: %zu <= %zu", bytes, sizeof(struct VBSPHeader));
  813. result = BSPLoadResult_ErrorFileFormat;
  814. goto exit;
  815. }
  816. if (vbsp_header.ident[0] != 'V' || vbsp_header.ident[1] != 'B' ||
  817. vbsp_header.ident[2] != 'S' || vbsp_header.ident[3] != 'P') {
  818. PRINTF("Error: invalid ident => %c%c%c%c != VBSP",
  819. vbsp_header.ident[0], vbsp_header.ident[1], vbsp_header.ident[2], vbsp_header.ident[3]);
  820. result = BSPLoadResult_ErrorFileFormat;
  821. goto exit;
  822. }
  823. if (vbsp_header.version < 19 && vbsp_header.version > 21) {
  824. PRINTF("Error: invalid version: %d != 19 or 20 or 21", vbsp_header.version);
  825. result = BSPLoadResult_ErrorFileFormat;
  826. goto exit;
  827. }
  828. PRINTF("VBSP version %u opened", vbsp_header.version);
  829. struct Lumps lumps;
  830. lumps.version = vbsp_header.version;
  831. #define BSPLUMP(name, type, field) \
  832. if (1 != lumpRead(#name, vbsp_header.lump_headers + VBSP_Lump_##name, file, context.tmp, \
  833. (struct AnyLump*)&lumps.field, sizeof(type))) { \
  834. result = BSPLoadResult_ErrorFileFormat; \
  835. goto exit; \
  836. }
  837. LIST_LUMPS
  838. #undef BSPLUMP
  839. if (lumps.lightmaps.n == 0) {
  840. memcpy(&lumps.lightmaps, &lumps.lightmaps_hdr, sizeof(lumps.lightmaps));
  841. memcpy(&lumps.faces, &lumps.faces_hdr, sizeof(lumps.faces));
  842. }
  843. if (lumps.pakfile.n > 0) {
  844. struct Memories memories = { context.tmp, context.tmp };
  845. pakfile = collectionCreatePakfile(&memories, lumps.pakfile.p, lumps.pakfile.n);
  846. if (pakfile)
  847. pakfile->next = context.collection;
  848. }
  849. result = bspLoadModel(pakfile ? pakfile : context.collection, context.model, context.persistent, context.tmp, &lumps, 0);
  850. if (result != BSPLoadResult_Success) {
  851. PRINTF("Error: bspLoadModel() => %s", R2S(result));
  852. goto exit;
  853. }
  854. result = bspReadEntities(&context, lumps.entities.p, lumps.entities.n);
  855. if (result != BSPLoadResult_Success)
  856. PRINTF("Error: bspReadEntities() => %s", R2S(result));
  857. exit:
  858. if (pakfile)
  859. pakfile->close(pakfile);
  860. stackFreeUpToPosition(context.tmp, tmp_cursor);
  861. if (file) file->close(file);
  862. return result;
  863. }
  864. void bspInit() {
  865. bsp_global.coarse_material = materialGet("opensource/coarse", NULL, NULL);
  866. const int scaling_factor = 4096;
  867. for (int i = 0; i < 256; ++i) {
  868. const int exp = i - 128;
  869. bsp_global.lightmap_tables.exponent[i] = (exp < -15 || exp > 15) ? 0 :
  870. (int)((float)scaling_factor * powf(2.f, (float)exp / 2.2f - 1.f));
  871. bsp_global.lightmap_tables.color[i] =
  872. (int)(255.f * powf((float)i / 255.f, 1.f / 2.2f));
  873. }
  874. }