convert line ends
[canaan.git] / prj / cam / src / sim / wrloop.cpp
blob232b02cd022b995cd66cecb3eb2fff212d4677b2
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/sim/wrloop.cpp,v 1.73 2000/03/18 15:20:54 adurant Exp $
8 #include <wrloop.h>
10 #include <lg.h>
11 #include <loopapi.h>
13 #include <brloop.h>
14 #include <dbasemsg.h>
15 #include <dispbase.h>
16 #include <loopmsg.h>
17 #include <objloop.h>
18 #include <rendloop.h>
20 #include <animlgt.h>
21 #include <csg.h>
22 #include <mprintf.h>
23 #include <physapi.h>
24 #include <tagfile.h>
25 #include <vernum.h>
26 #include <wr.h>
27 #include <wrmem.h>
28 #include <wrbsp.h>
29 #include <wrdbrend.h>
30 #include <editbr.h>
31 #include <gedit.h>
32 #include <ged_csg.h>
33 #include <medmotn.h>
34 #include <porthlpr.h>
35 #include <portal.h>
36 #include <family.h>
37 #include <objpos.h>
38 #include <texsave.h>
40 #include <config.h>
41 #include <cfgdbg.h>
42 #include <allocapi.h>
44 // Must be last header
45 #include <dbmem.h>
47 // This shouldn't be here either
48 EXTERN int *wr_brfaces[];
51 // Goofy Memory management
55 static struct sMemBuffer
57 uchar* buf; // the buffer
58 ulong size; // The buffer size;
59 uchar* next; // next available byte
60 ulong overflow; // how much we couldn't allocate
61 } MemBuf;
64 static void ClearMemBuf()
66 delete [] MemBuf.buf;
67 MemBuf.buf = NULL;
68 MemBuf.size = 0;
69 MemBuf.next = NULL;
70 MemBuf.overflow = 0;
73 static void AllocMemBuf(ulong n)
75 #ifdef EDITOR
76 MemBuf.buf = NULL;
77 MemBuf.size = 0;
78 #else
79 MemBuf.buf = new uchar[n];
80 MemBuf.size = n;
81 #endif
82 MemBuf.next = MemBuf.buf;
83 MemBuf.overflow = 0;
86 #define DoMalloc(x) (new char[x])
87 #define DoFree(x) (delete [] (char*)(x))
89 static void* wrAlloc(ulong size)
91 if (MemBuf.next == NULL || MemBuf.buf == NULL)
92 return DoMalloc(size);
93 if (MemBuf.next + size > MemBuf.buf + MemBuf.size)
95 if (MemBuf.overflow == 0)
96 Warning(("wrAlloc: need %d bytes, have %d\n",size,MemBuf.size - (MemBuf.next - MemBuf.buf)));
97 MemBuf.overflow += size;
98 return DoMalloc(size);
101 void* retval = MemBuf.next;
102 MemBuf.next += size;
103 return retval;
106 static void wrFree(void* ptr)
108 if (ptr < MemBuf.buf || ptr >= MemBuf.buf + MemBuf.size)
109 DoFree(ptr);
112 #ifndef SHIP
113 static void wrAllocPrintOverflow(void)
115 if (MemBuf.overflow != 0) {
116 mprintf("WARNING: %d bytes of worldrep not allocated from main block\n",
117 MemBuf.overflow);
118 } else if (MemBuf.next != MemBuf.buf + MemBuf.size) {
119 mprintf("WARNING: %d bytes of worldrep alloc unused.\n",
120 (MemBuf.next - MemBuf.buf) + MemBuf.size);
123 #endif
125 /////////////////////////////////////////////////////////////
126 // WORLD REP LOOP CLIENT
127 ////////////////////////////////////////////////////////////
129 //////////////////
130 // CONSTANTS
132 // These are just here to separate out boiler-plate code and leave it untouched
135 #define MY_GUID LOOPID_Wr
138 // My context data
139 typedef void Context;
141 // fields to this structure.
143 // My state
144 typedef struct _StateRecord
146 Context* context; // a pointer to the context data I got.
147 // State fields go here
148 } StateRecord;
150 ////////////////////////////////////////
151 // DATABASE MESSAGE HANDLER
154 typedef void (*PortalReadWrite) (void *buf, size_t elsize, size_t nelem);
156 void SpewCellPlanes(PortalCell *p)
158 int i;
159 mprintf("num_vertices:%d\n", p->num_vertices);
160 mprintf("num_polys:%d\n", p->num_polys);
161 mprintf("num_render_polys:%d\n", p->num_render_polys);
162 mprintf("num_portal_polys:%d\n", p->num_portal_polys);
163 for (i = 0; i < p->num_planes; i++)
164 mprintf("plane_list[i] %g,%g,%g, %g\n", p->plane_list[i].normal.x, p->plane_list[i].normal.y, p->plane_list[i].normal.z, p->plane_list[i].plane_constant);
167 void SpewCell(PortalCell *p)
169 int i;
171 mprintf("num_vertices:%d\n", p->num_vertices);
172 mprintf("num_polys:%d\n", p->num_polys);
173 mprintf("num_render_polys:%d\n", p->num_render_polys);
174 mprintf("num_portal_polys:%d\n", p->num_portal_polys);
176 mprintf("num_planes:%d\n", p->num_planes);
177 mprintf("medium:%d\n", p->medium);
178 mprintf("flags:%d\n", p->flags);
180 mprintf("portal_vertex_list:%d\n", p->portal_vertex_list);
182 //mprintf("refs:%d", p->refs);
184 mprintf("sphere_center:%g,%g,%g\n", p->sphere_center.x, p->sphere_center.y, p->sphere_center.z);
185 mprintf("sphere_radius:%g\n", p->sphere_radius);
187 for (i = 0; i < p->num_vertices; i++)
188 mprintf("vpool[i]:%g,%g,%g\n", p->vpool[i].x, p->vpool[i].y, p->vpool[i].z);
190 for (i = 0; i < p->num_polys; i++)
192 mprintf ("poly_list[i] flags:%d\n", p->poly_list[i].flags);
193 // should be more here....
196 mprintf ("portal_poly_list[0] flags:%d\n", p->portal_poly_list[0]);
198 for (i = 0; i < p->num_render_polys; i++)
200 mprintf("render_list u->raw:%g,%g,%g\n", p->render_list[i].tex_u.x, p->render_list[i].tex_u.y, p->render_list[i].tex_u.z);
201 mprintf("render_list v->raw:%g,%g,%g\n", p->render_list[i].tex_v.x, p->render_list[i].tex_v.y, p->render_list[i].tex_v.z);
202 mprintf("render_list u_base:%d\n", p->render_list[i].u_base);
203 mprintf("render_list v_base:%d\n", p->render_list[i].v_base);
204 mprintf("render_list texture_id:%d\n", p->render_list[i].texture_id);
205 mprintf("render_list texture_anchor:%d\n", p->render_list[i].texture_anchor);
206 mprintf("render_list cached_surface:%d\n", p->render_list[i].cached_surface);
209 int pi, voff = 0;
210 for (pi = 0; pi < p->num_polys; ++pi)
211 voff += p->poly_list[pi].num_vertices;
212 for (i = 0; i < voff; i++)
213 mprintf("vertex_list[i]:%d\n", p->vertex_list[i]);
215 for (i = 0; i < p->num_planes; i++)
216 mprintf("plane_list[i] normal %g,%g,%g\n", p->plane_list[i].normal.x, p->plane_list[i].normal.y, p->plane_list[i].normal.z);
218 // for (i = 0; i < xxxx; i++)
219 // mprintf("render_data[i]
221 for (i = 0; i < p->num_render_polys; i++)
223 mprintf("light_list[i] base_u:%d\n", p->light_list[i].base_u);
224 mprintf("light_list[i] base_u:%d\n", p->light_list[i].base_v);
225 mprintf("light_list[i] h:%d\n", p->light_list[i].h);
226 mprintf("light_list[i] w:%d\n", p->light_list[i].w);
227 mprintf("light_list[i] bits[0]:%d\n", p->light_list[i].data[0]);
228 mprintf("light_list[i] bits[h*w-1]:%d\n", p->light_list[i].data[p->light_list[i].h*p->light_list[i].w-1]);
231 for (i = 0; i < p->light_indices[0]; i++)
232 mprintf("light_indices[i]:%d\n", p->light_indices[i]);
235 void SpewAllCells(void)
237 int ci;
239 for (ci = 0; ci < wr_num_cells; ci++)
240 if (wr_cell[ci] != NULL)
241 SpewCell(wr_cell[ci]);
244 ulong ReadWriteNonPtrPortalCell(PortalReadWrite func, PortalCell *p)
246 ulong retval = 0;
247 (*func)(&(p->num_vertices), sizeof(uchar), 1);
248 (*func)(&(p->num_polys), sizeof(uchar), 1);
249 (*func)(&(p->num_render_polys), sizeof(uchar), 1);
250 (*func)(&(p->num_portal_polys), sizeof(uchar), 1);
251 retval += 4*sizeof(uchar);
253 (*func)(&(p->num_planes), sizeof(uchar), 1);
254 (*func)(&(p->medium), sizeof(uchar), 1);
255 (*func)(&(p->flags), sizeof(uchar), 1);
256 retval += 3* sizeof(uchar);
258 (*func)(&(p->portal_vertex_list), sizeof(int), 1);
259 retval += sizeof(int);
261 (*func)(&(p->num_vlist), sizeof(ushort), 1);
262 (*func)(&(p->num_anim_lights), sizeof(uchar), 1);
263 (*func)(&(p->motion_index), sizeof(uchar), 1);
264 retval += sizeof(ushort)+2*sizeof(uchar);
266 (*func)(&(p->sphere_center), sizeof(Vertex), 1);
267 (*func)(&(p->sphere_radius), sizeof(mxs_real), 1);
268 retval += sizeof(Vertex) + sizeof(mxs_real) ;
270 return retval;
273 #if 0
274 ulong WriteCachedVector(PortalReadWrite func, CachedVector *cv)
276 (*func)(&(cv->raw), sizeof(Vector), 1);
277 return sizeof(CachedVector);
278 // (*func)(cv->cached, sizeof(CachedData), 1);
281 void ReadAndAllocCachedVector(PortalReadWrite func, CachedVector **cv)
283 *cv = (CachedVector*) wrAlloc(sizeof(CachedVector));
284 (*func)(&((**cv).raw), sizeof(Vector), 1);
286 // (**cv).cached = (st_CachedData*) DoMalloc(sizeof(CachedData));
287 // (*func)((**cv).cached, sizeof(CachedData), 1);
289 #endif
293 // Free worldrep structures
295 // NOTE: This does NOT free wrBspTree. You must do this explicitly.
296 // The reason it doesn't is that FreeWR gets called at the
297 // beginning of each pass of the portalization, and we need
298 // to preserve wrBspTree through all passes.
300 // NOTE: FreeWR seems to be getting called twice in a row typically.
301 // Right now I'm not going to worry about it because it doesn't
302 // seem to be hurting anything, but be aware of it.
303 void FreeWR(void)
305 int ci, i;
306 PortalCell *p;
308 clear_surface_cache();
309 ObjDeleteAllRefs();
310 reset_dynamic_lights();
312 for (ci = 0; ci < wr_num_cells; ci++) {
313 if (wr_cell[ci] != NULL) {
314 p = wr_cell[ci];
316 if (p->vpool != NULL) wrFree(p->vpool);
317 if (p->poly_list != NULL) wrFree(p->poly_list);
318 if (p->render_list != NULL) {
319 wrFree(p->render_list);
321 if (p->vertex_list != NULL) wrFree(p->vertex_list);
322 if (p->plane_list != NULL) wrFree(p->plane_list);
324 if (p->render_data != NULL) wrFree(p->render_data);
325 if (p->anim_light_index_list != NULL) wrFree(p->anim_light_index_list);
326 if (p->light_list != NULL) {
327 for (i = 0; i < p->num_render_polys; i++) {
328 if (p->light_list[i].data != NULL) wrFree(p->light_list[i].data);
329 if (p->light_list[i].dynamic_light != NULL) wrFree(p->light_list[i].dynamic_light);
331 wrFree(p->light_list);
333 if (p->light_indices != NULL) wrFree(p->light_indices);
335 #ifdef EDITOR
336 if (wr_brfaces[ci] != NULL) wrFree(wr_brfaces[ci]);
337 #endif
340 wrFree(wr_cell[ci]);
341 wr_cell[ci] = NULL;
342 // NOTE: doesn't free refs
346 ClearMemBuf();
348 wr_num_cells = 0;
352 // Given a rendered non-portal polygon in a cell, how many lightmaps?
353 // There's always the static one. Each animated animated light which
354 // reaches this polygon contributes another.
355 static int lightmap_count(PortalCell *cell, int polygon_index)
357 int count = 1;
358 uint bitmask = cell->light_list[polygon_index].anim_light_bitmask;
360 while (bitmask) {
361 if (bitmask & 1)
362 count++;
363 bitmask >>= 1;
366 return count;
369 ulong WriteWR(PortalReadWrite func)
371 int ci, i; // portal cell index
372 int pi, voff, num_light_indices;
373 PortalCell *p;
375 ulong alloced_bytes_written = 0 ;
377 //SpewAllCells();
379 // write the number of portal cells to be written
380 (*func)(&wr_num_cells, sizeof(int), 1);
382 for (ci = 0; ci < wr_num_cells; ci++)
384 p = wr_cell[ci];
386 // write the portal cell
387 ReadWriteNonPtrPortalCell(func, p);
388 alloced_bytes_written += sizeof(*p);
390 // write the vpool
391 (*func)(p->vpool, sizeof(Vertex), p->num_vertices);
392 alloced_bytes_written += sizeof(Vertex)*p->num_vertices;
394 // write the poly_list
395 (*func)(p->poly_list, sizeof(PortalPolygonCore), p->num_polys);
396 alloced_bytes_written += sizeof(PortalPolygonCore)*p->num_polys;
398 // write render_list
399 (*func)(p->render_list, sizeof(PortalPolygonRenderInfo), p->num_render_polys);
400 alloced_bytes_written += sizeof(PortalPolygonRenderInfo)*p->num_render_polys;
402 // calculate the highest index into the vertex_list used,
403 // and then write the index, and then the vertex_list array.
404 voff = 0;
405 for (pi = 0; pi < p->num_polys; ++pi)
406 voff += p->poly_list[pi].num_vertices;
407 (*func)(&voff, sizeof(int), 1);
408 (*func)(p->vertex_list, sizeof(uchar), voff);
409 alloced_bytes_written += sizeof(uchar)*voff;
411 // write the plane_list
412 (*func)(p->plane_list, sizeof(PortalPlane), p->num_planes);
413 alloced_bytes_written += sizeof(PortalPlane)*p->num_planes;
415 if (p->num_anim_lights)
416 (*func)(p->anim_light_index_list, sizeof(ushort), p->num_anim_lights);
417 alloced_bytes_written += sizeof(ushort)*p->num_anim_lights;
419 // write the light_list and the sub field bits parameter
420 // zero out the pointers (.data, and .dynamic_light), since we
421 // zero them out on load anyway, and they are meaningless to save.
422 // If we don't, we keep getting a different WRRGB tag which sucks
423 // for missdiff.exe
424 PortalLightMap templist;
425 for (i = 0; i < p->num_render_polys; i++)
427 memcpy(&templist,&(p->light_list[i]),sizeof(PortalLightMap));
428 templist.data = 0;
429 templist.dynamic_light = 0;
430 (*func)(&templist,sizeof(PortalLightMap),1);
432 //(*func)(p->light_list, sizeof(PortalLightMap), p->num_render_polys);
433 alloced_bytes_written += sizeof(PortalLightMap) * p->num_render_polys;
434 for (i = 0; i < p->num_render_polys; i++)
436 int lightmap_size = (p->light_list[i].h)
437 * (p->light_list[i].pixel_row)
438 * sizeof(LightmapEntry)
439 * (lightmap_count(p, i));
441 (*func)(p->light_list[i].data, 1, lightmap_size);
442 alloced_bytes_written += /* sizeof(LightmapEntry) * */ lightmap_size;
445 // write the light_indices
446 num_light_indices = p->light_indices[0]+1;
447 if (num_light_indices>1024)
448 mprintf("ummm, dont take this the wrong way, but cell %d has %d light idx\n",ci,num_light_indices);
449 (*func)(&num_light_indices, sizeof(int), 1);
450 (*func)(p->light_indices, sizeof(ushort), num_light_indices);
451 // a little silly to write out the first field twice, oh well
452 alloced_bytes_written += sizeof(ushort) * (num_light_indices);
454 // pointers in struct that are not being written to disk yet......
455 //////////////////////////////////////////////////////////////////
456 // vertex_list_dynamic
457 // refs
458 // decal ptr and dynamic ptr in PortalLightMap (same place as bits)
461 wrBspTreeWrite(func);
463 return alloced_bytes_written;
467 void ReadWR(PortalReadWrite func)
469 int ci, i;
470 int num_vertex_list, num_light_indices;
471 PortalCell *p;
473 // read the number of portal cells to be read
474 (*func)(&wr_num_cells, sizeof(int), 1);
476 if (wr_num_cells > 0)
478 ged_validate_level(TRUE);
481 else
483 ged_validate_level(FALSE);
486 for (ci = 0; ci < wr_num_cells; ci++)
488 // alloc and read the portal cell
489 wr_cell[ci] = (PortalCell*) wrAlloc(sizeof(PortalCell));
490 p = wr_cell[ci];
491 ReadWriteNonPtrPortalCell(func, p);
493 // alloc and read the vpool
494 p->vpool = (Vertex*) wrAlloc(sizeof(Vertex) * p->num_vertices);
495 (*func)(p->vpool, sizeof(Vertex), p->num_vertices);
497 // alloc and read the poly_list
498 p->poly_list = (PortalPolygonCore*) wrAlloc(sizeof(PortalPolygonCore) * p->num_polys);
499 (*func)(p->poly_list, sizeof(PortalPolygonCore), p->num_polys);
501 // alloc and read the render_list
502 p->render_list = (PortalPolygonRenderInfo*) wrAlloc(sizeof(PortalPolygonRenderInfo)* p->num_render_polys);
503 (*func)(p->render_list, sizeof(PortalPolygonRenderInfo), p->num_render_polys);
504 for (i=0; i < p->num_render_polys; ++i)
505 p->render_list[i].cached_surface = 0;
507 // set the portal_list_ptr
508 p->portal_poly_list = p->poly_list + p->num_polys - p->num_portal_polys;
510 // read the size of the vertex_list and then alloc and read the array
511 (*func)(&num_vertex_list, sizeof(int), 1);
512 p->vertex_list = (uchar*) wrAlloc(sizeof(uchar) * num_vertex_list);
513 (*func)(p->vertex_list, sizeof(uchar), num_vertex_list);
515 // alloc and read the plane_list, and then read in the
516 // cached vectors inside the plane_list
517 p->plane_list = (PortalPlane*) wrAlloc(sizeof(PortalPlane) * p->num_planes);
518 (*func)(p->plane_list, sizeof(PortalPlane), p->num_planes);
520 #ifdef DEBUG
521 g_pMalloc->PushCredit("WR Light Maps",0);
522 #endif
524 // DoMalloc and read the anim_light_index_list
525 if (p->num_anim_lights) {
526 p->anim_light_index_list
527 = (ushort*) wrAlloc(sizeof(ushort) * p->num_anim_lights);
528 (*func)(p->anim_light_index_list, sizeof(ushort), p->num_anim_lights);
529 } else
530 p->anim_light_index_list = NULL;
532 // DoMalloc and read the light_list and the sub field bits pointer
533 p->light_list = (PortalLightMap*) wrAlloc(sizeof(PortalLightMap)
534 * p->num_render_polys);
535 (*func)(p->light_list, sizeof(PortalLightMap), p->num_render_polys);
537 for (i = 0; i < p->num_render_polys; i++)
539 int lightmap_size = (p->light_list[i].h)
540 * (p->light_list[i].pixel_row)
541 * sizeof(LightmapEntry)
542 * (lightmap_count(p, i));
544 p->light_list[i].data = (LightmapEntry*) wrAlloc(lightmap_size);
545 (*func)(p->light_list[i].data, 1 /* sizeof(LightmapEntry) */, lightmap_size);
547 p->light_list[i].dynamic_light = NULL;
550 // DoMalloc and read the light_indices
551 (*func)(&num_light_indices, sizeof(int), 1);
552 p->light_indices = (ushort*) wrAlloc(sizeof(ushort) * num_light_indices);
553 (*func)(p->light_indices, sizeof(ushort), num_light_indices);
555 // pointers in the struct which are not being read from disk yet....
556 /////////////////////////////////////////////////////////////////////
557 p->refs = NULL;
558 p->render_data = NULL;
559 p->changed_anim_light_bitmask = 0;
560 p->num_full_bright = 0;
561 // and decal and dynamic in PortalLightMap
563 #ifdef DEBUG
564 g_pMalloc->PopCredit();
565 #endif
568 #ifdef DEBUG
569 g_pMalloc->PushCredit("WR BSP",0);
570 #endif
572 wrBspTreeRead(func);
573 wrBspTreeRefCells(WRBSP_HEAD);
575 #ifdef DEBUG
576 g_pMalloc->PopCredit();
577 #endif
578 #ifndef SHIP
579 wrAllocPrintOverflow();
580 #endif
582 //SpewAllCells();
585 //////////////////////////////////////////////////
586 // World Rep Save/Load Stuff
588 //////////////////////////////////////////////////
589 // light save/load stuff -- anim light scripts are next
591 typedef void (*LightReadWrite) (void *buf, size_t elsize, size_t nelem);
593 #include <mlight.h>
595 #define MAX_STATIC 768
597 EXTERN int num_light;
598 EXTERN int num_dyn;
599 EXTERN mls_multi_light light_data[];
600 EXTERN mls_multi_light light_this[];
602 // @TODO: Shouldn't this be using num_light for the number of elements?
603 void ReadWriteLight(LightReadWrite func)
605 // object lighting
606 (*func)(&num_light, sizeof(int), 1);
607 (*func)(&num_dyn, sizeof(int), 1);
608 (*func)(light_data, sizeof(mls_multi_light), MAX_STATIC);
609 (*func)(light_this, sizeof(mls_multi_light), 32);
611 // mappings from animated lights to cells
612 (*func)(&g_iCurAnimLightToCell, sizeof(int), 1);
613 (*func)(&g_aAnimLightToCell[0], sizeof(sAnimLightToCell),
614 g_iCurAnimLightToCell);
617 // end of light save/load stuff
618 //////////////////////////////////////////////////
621 //////////////////////////////////////////////////
622 // management of PortalCellMotion structures
625 static void ReadWriteWaterMotion(PortalReadWrite func)
627 (*func)(portal_cell_motion,
628 sizeof(portal_cell_motion[0]), MAX_CELL_MOTION);
629 (*func)(g_aMedMoCellMotion,
630 sizeof(g_aMedMoCellMotion[0]), MAX_CELL_MOTION);
634 static void ClearWaterMotion()
636 memset(&g_aMedMoCellMotion[0], 0,
637 sizeof(g_aMedMoCellMotion[0]) * MAX_CELL_MOTION);
639 memset(&portal_cell_motion[0], 0,
640 sizeof(portal_cell_motion[0]) * MAX_CELL_MOTION);
642 for (int i = 0; i < MAX_CELL_MOTION; ++i) {
643 portal_cell_motion[i].major_axis = MEDIUM_AXIS_Z;
644 portal_cell_motion[i].in_motion = TRUE;
649 // end of management of PortalCellMotion structures
650 //////////////////////////////////////////////////
653 //////////////////////////////////////////////////
654 // management of fog
656 static void ReadWriteFog(PortalReadWrite func)
658 (*func)(portal_fog_color, sizeof(portal_fog_color), 1);
659 (*func)(&portal_fog_dist, sizeof(portal_fog_dist), 1);
662 static void ClearFog()
664 portal_fog_dist = 0;
665 portal_fog_color[0] = 128;
666 portal_fog_color[1] = 128;
667 portal_fog_color[2] = 128;
670 // end of management of fog
671 //////////////////////////////////////////////////
674 //////////////////////////////////////////////////
675 // Tag File Stuff
677 static ITagFile* tagfile = NULL;
678 static void movefunc(void *buf, size_t elsize, size_t nelem)
680 ITagFile_Move(tagfile,(char*)buf,elsize*nelem);
683 enum eMinorVersions
685 kSizeHeader = 18,
688 #ifdef RGB_LIGHTING
689 TagFileTag WrTag = { "WRRGB" };
690 #else
691 TagFileTag WrTag = { "WR" };
692 #endif
693 TagVersion WrVersion = { 0, 24 };
694 TagVersion AcceptWrVersion = { 0, 24 };
696 static BOOL setup_tagfile(ITagFile* file, TagFileTag *tag,
697 TagVersion *version, TagVersion* accept)
699 HRESULT result;
700 TagVersion old_version = *version;
701 tagfile = file;
703 result = file->OpenBlock(tag, version);
704 if (VersionNumsCompare(version,accept) < 0)
706 file->CloseBlock();
707 return FALSE;
710 return SUCCEEDED(result);
715 static void cleanup_tagfile(ITagFile* file)
717 file->CloseBlock();
720 //////////////////////////////////////////////////
721 // Tag File Stuff
723 //////////////////////////////////////////////////
724 // water tag file thingbobs
726 TagFileTag WaterMotionTag = { "CELL_MOTION" };
727 TagVersion WaterMotionVersion = { 0, 1 };
728 TagVersion AcceptWaterMotionVersion = { 0, 1 };
733 //////////////////////////////////////////////////
734 // fog tag file thingbobs
736 static TagFileTag FogTag = { "FOG" };
737 static TagVersion FogVersion = { 0, 1 };
738 static TagVersion AcceptFogVersion = { 0, 1 };
743 //////////////////////////////////////////////////
745 // @TODO: something more graceful here
746 extern "C"
748 BOOL wr_db_disabled = FALSE;
751 static void water_db_message(DispatchData* msg)
753 msgDatabaseData data;
754 data.raw = msg->data;
756 switch (DB_MSG(msg->subtype))
758 case kDatabaseReset:
759 ClearWaterMotion();
760 break;
762 case kDatabaseLoad:
763 case kDatabaseSave:
764 if (msg->subtype & kDBMap)
766 TagVersion v = WaterMotionVersion;
767 if (setup_tagfile(data.save, &WaterMotionTag, &v, &AcceptWaterMotionVersion) )
769 ReadWriteWaterMotion(movefunc);
770 cleanup_tagfile(data.save);
773 break;
778 static void db_message(DispatchData* msg)
780 msgDatabaseData data;
781 data.raw = msg->data;
783 if (wr_db_disabled)
784 return ;
786 switch (DB_MSG(msg->subtype))
788 case kDatabaseReset:
790 FreeWR();
792 wrBspTreeDeallocate();
794 #ifdef EDITOR
795 free_csg_internal_database();
796 #endif
798 AnimLightClear();
800 portal_cleanup_water_hack();
802 ClearFog();
804 family_clear_all();
805 break;
808 case kDatabaseSave:
810 if (msg->subtype & kDBMap) // Save world info into the MAP file.
812 if (!gedit_editted && wr_num_cells > 0)
814 ITagFile* file = data.save;
815 TagVersion v = WrVersion;
816 if (setup_tagfile(file, &WrTag, &v,&AcceptWrVersion))
818 ulong size = 0;
820 // make room for the size
821 file->Write((char*)&size,sizeof(size));
823 // write the world rep
824 size = WriteWR(movefunc);
826 // write the light stuff
827 ReadWriteLight(movefunc);
829 // write the csg editting stuff
830 #ifdef EDITOR
831 save_csg_internal_database(movefunc);
832 #endif
834 // backpatch the writen size
835 file->Seek(0,kTagSeekFromStart);
836 file->Write((char*)&size,sizeof(size));
838 cleanup_tagfile(data.save);
842 TagVersion v = FogVersion;
843 if (setup_tagfile(data.save, &FogTag, &v, &AcceptFogVersion))
845 ReadWriteFog(movefunc);
846 cleanup_tagfile(data.save);
849 texture_Save(data.save);
851 break;
854 case kDatabaseLoad:
856 if (msg->subtype & kDBMap) // Load world info from the MAP file.
858 ITagFile* file = data.load;
859 TagVersion v = WrVersion;
860 if (setup_tagfile(file, &WrTag, &v, &AcceptWrVersion))
862 ulong size;
863 if (v.minor >= kSizeHeader)
864 file->Read((char*)&size,sizeof(size));
865 else
866 size = file->BlockSize(&WrTag);
868 AllocMemBuf(size);
870 // load the world rep
871 ReadWR(movefunc);
873 // load the light stuff
874 ReadWriteLight(movefunc);
876 // load the csg editting type stuff
877 #ifdef EDITOR
878 load_csg_internal_database(movefunc);
879 #endif
881 cleanup_tagfile(data.load);
883 ConfigSpew("wr_load_spew",("Wr is %d bytes, %d bytes unused\n",MemBuf.next- MemBuf.buf,MemBuf.size - (MemBuf.next - MemBuf.buf)));
885 else
886 ged_validate_level(FALSE);
888 v = FogVersion;
889 if (setup_tagfile(data.load, &FogTag, &v, &AcceptFogVersion))
891 ReadWriteFog(movefunc);
892 cleanup_tagfile(data.load);
895 texture_Load(data.load);
898 break;
903 ////////////////////////////////////////
905 // LOOP/DISPATCH callback
906 // Here's where we do the dirty work.
909 #pragma off(unreferenced)
910 static eLoopMessageResult LGAPI _LoopFunc(void* data, eLoopMessage msg, tLoopMessageData hdata)
912 // useful stuff for most clients
913 eLoopMessageResult result = kLoopDispatchContinue;
914 StateRecord* state = (StateRecord*)data;
915 LoopMsg info;
917 info.raw = hdata;
920 switch(msg)
923 case kMsgDatabase:
924 db_message(info.dispatch);
925 water_db_message(info.dispatch);
926 break;
928 case kMsgAppInit:
929 family_init(); // a reset but an init
930 break;
932 case kMsgAppTerm:
933 family_term();
934 break;
936 case kMsgEnd:
937 DoFree(state);
938 break;
940 return result;
943 ////////////////////////////////////////////////////////////
945 // Loop client factory function.
948 #pragma off(unreferenced)
949 static ILoopClient* LGAPI _CreateClient(sLoopClientDesc * pDesc, tLoopClientData data)
951 StateRecord* state;
952 // allocate space for our state, and fill out the fields
953 state = (StateRecord*)DoMalloc(sizeof(StateRecord));
954 state->context = (Context*)data;
956 return CreateSimpleLoopClient(_LoopFunc,state,pDesc);
958 #pragma on(unreferenced)
960 ///////////////
961 // DESCRIPTOR
964 sLoopClientDesc WrLoopClientDesc =
966 &LOOPID_Wr, // GUID
967 "World Rep Client", // NAME
968 kPriorityNormal, // PRIORITY
969 kMsgEnd | kMsgDatabase | kMsgsAppOuter, // INTERESTS
971 kLCF_Callback,
972 _CreateClient,
974 NO_LC_DATA,
977 {kConstrainAfter, &LOOPID_Render, kMsgDatabase|kMsgAppTerm }, // for texture archetypes
978 {kNullConstraint} // terminator