123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164 |
- #pragma warning(disable:4018)
- #include "bsp5.h"
- int g_maxnode_size = DEFAULT_MAXNODE_SIZE;
- static bool g_reportProgress = false;
- static int g_numProcessed = 0;
- static int g_numReported = 0;
- static void ResetStatus(bool report_progress)
- {
- g_reportProgress = report_progress;
- g_numProcessed = g_numReported = 0;
- }
- static void UpdateStatus(void)
- {
- if(g_reportProgress)
- {
- ++g_numProcessed;
- if((g_numProcessed / 500) > g_numReported)
- {
- g_numReported = (g_numProcessed / 500);
- Log("%d...",g_numProcessed);
- }
- }
- }
- static int FaceSide(face_t* in, const dplane_t* const split)
- {
- int frontcount, backcount;
- vec_t dot;
- int i;
- vec_t* p;
- frontcount = backcount = 0;
-
- if (split->type <= last_axial)
- {
- vec_t splitGtEp = split->dist + ON_EPSILON;
- vec_t splitLtEp = split->dist - ON_EPSILON;
- for (i = 0, p = in->pts[0] + split->type; i < in->numpoints; i++, p += 3)
- {
- if (*p > splitGtEp)
- {
- if (backcount)
- {
- return SIDE_ON;
- }
- frontcount = 1;
- }
- else if (*p < splitLtEp)
- {
- if (frontcount)
- {
- return SIDE_ON;
- }
- backcount = 1;
- }
- }
- }
- else
- {
-
- for (i = 0, p = in->pts[0]; i < in->numpoints; i++, p += 3)
- {
- dot = DotProduct(p, split->normal);
- dot -= split->dist;
- if (dot > ON_EPSILON)
- {
- if (backcount)
- {
- return SIDE_ON;
- }
- frontcount = 1;
- }
- else if (dot < -ON_EPSILON)
- {
- if (frontcount)
- {
- return SIDE_ON;
- }
- backcount = 1;
- }
- }
- }
- if (!frontcount)
- {
- return SIDE_BACK;
- }
- if (!backcount)
- {
- return SIDE_FRONT;
- }
- return SIDE_ON;
- }
- static surface_t* ChooseMidPlaneFromList(surface_t* surfaces, const vec3_t mins, const vec3_t maxs)
- {
- int j, l;
- surface_t* p;
- surface_t* bestsurface;
- vec_t bestvalue;
- vec_t value;
- vec_t dist;
- dplane_t* plane;
-
-
-
- bestvalue = 6 * 8192 * 8192;
- bestsurface = NULL;
- for (p = surfaces; p; p = p->next)
- {
- if (p->onnode)
- {
- continue;
- }
- plane = &g_dplanes[p->planenum];
-
- l = plane->type;
- if (l > last_axial)
- {
- continue;
- }
-
-
-
- value = 0;
- dist = plane->dist * plane->normal[l];
- for (j = 0; j < 3; j++)
- {
- if (j == l)
- {
- value += (maxs[l] - dist) * (maxs[l] - dist);
- value += (dist - mins[l]) * (dist - mins[l]);
- }
- else
- {
- value += 2 * (maxs[j] - mins[j]) * (maxs[j] - mins[j]);
- }
- }
- if (value > bestvalue)
- {
- continue;
- }
-
-
-
- bestvalue = value;
- bestsurface = p;
- }
- if (!bestsurface)
- {
- for (p = surfaces; p; p = p->next)
- {
- if (!p->onnode)
- {
- return p;
- }
- }
- Error("ChooseMidPlaneFromList: no valid planes");
- }
- return bestsurface;
- }
- static surface_t* ChoosePlaneFromList(surface_t* surfaces, const vec3_t mins, const vec3_t maxs)
- {
- int j;
- int k;
- int l;
- surface_t* p;
- surface_t* p2;
- surface_t* bestsurface;
- vec_t bestvalue;
- vec_t bestdistribution;
- vec_t value;
- vec_t dist;
- dplane_t* plane;
- face_t* f;
-
-
-
- #define UNDESIREABLE_HINT_FACTOR 10000
- #define WORST_VALUE 100000000
- bestvalue = WORST_VALUE;
- bestsurface = NULL;
- bestdistribution = 9e30;
- for (p = surfaces; p; p = p->next)
- {
- if (p->onnode)
- {
- continue;
- }
- #ifdef ZHLT_DETAIL
- if (g_bDetailBrushes)
- {
-
-
- for (face_t* f = p->faces; f; f = f->next)
- {
- if (f->contents == CONTENTS_DETAIL)
- {
-
- continue;
- }
- }
- }
- #endif
-
- plane = &g_dplanes[p->planenum];
- k = 0;
- for (p2 = surfaces; p2; p2 = p2->next)
- {
- if (p2 == p)
- {
- continue;
- }
- if (p2->onnode)
- {
- continue;
- }
- for (f = p2->faces; f; f = f->next)
- {
-
- if (f->facestyle == face_hint)
- {
- k += UNDESIREABLE_HINT_FACTOR;
- hlassert(k < WORST_VALUE);
- if (k >= WORST_VALUE)
- {
- Warning("::ChoosePlaneFromList() surface fragmentation undesireability exceeded WORST_VALUE");
- k = WORST_VALUE - 1;
- }
- }
- if (FaceSide(f, plane) == SIDE_ON)
- {
- k++;
- if (k >= bestvalue)
- {
- break;
- }
- }
- }
- if (k > bestvalue)
- {
- break;
- }
- }
- if (k > bestvalue)
- {
- continue;
- }
-
- if (k < bestvalue || (k == bestvalue && (plane->type <= last_axial)))
- {
-
- l = plane->type;
- if (l <= last_axial)
- {
-
-
-
- value = 0;
- for (j = 0; j < 3; j++)
- {
- if (j == l)
- {
- dist = plane->dist * plane->normal[l];
- value += (maxs[l] - dist) * (maxs[l] - dist);
- value += (dist - mins[l]) * (dist - mins[l]);
- }
- else
- {
- value += 2 * (maxs[j] - mins[j]) * (maxs[j] - mins[j]);
- }
- }
- if (value > bestdistribution && k == bestvalue)
- {
- continue;
- }
- bestdistribution = value;
- }
-
-
-
- bestvalue = k;
- bestsurface = p;
- }
- }
- return bestsurface;
- }
- static surface_t* SelectPartition(surface_t* surfaces, const node_t* const node, const bool usemidsplit)
- {
- int i;
- surface_t* p;
- surface_t* bestsurface;
-
-
-
- i = 0;
- bestsurface = NULL;
- for (p = surfaces; p; p = p->next)
- {
- if (!p->onnode)
- {
- #ifdef ZHLT_DETAIL
- if (g_bDetailBrushes)
- {
-
-
- for (face_t* f = p->faces; f; f = f->next)
- {
- if (f->contents == CONTENTS_DETAIL)
- {
-
- continue;
- }
- }
- }
- #endif
- i++;
- bestsurface = p;
- }
- }
- if (i == 0)
- {
- return NULL;
- }
- if (i == 1)
- {
- return bestsurface;
- }
- if (usemidsplit)
- {
-
- return ChooseMidPlaneFromList(surfaces, node->mins, node->maxs);
- }
- else
- {
-
- return ChoosePlaneFromList(surfaces, node->mins, node->maxs);
- }
- }
- static void CalcSurfaceInfo(surface_t* surf)
- {
- int i;
- int j;
- face_t* f;
- hlassume(surf->faces != NULL, assume_ValidPointer);
-
-
-
- for (i = 0; i < 3; i++)
- {
- surf->mins[i] = 99999;
- surf->maxs[i] = -99999;
- }
- for (f = surf->faces; f; f = f->next)
- {
- if (f->contents >= 0)
- {
- Error("Bad contents");
- }
- for (i = 0; i < f->numpoints; i++)
- {
- for (j = 0; j < 3; j++)
- {
- if (f->pts[i][j] < surf->mins[j])
- {
- surf->mins[j] = f->pts[i][j];
- }
- if (f->pts[i][j] > surf->maxs[j])
- {
- surf->maxs[j] = f->pts[i][j];
- }
- }
- }
- }
- }
- static void DivideSurface(surface_t* in, const dplane_t* const split, surface_t** front, surface_t** back)
- {
- face_t* facet;
- face_t* next;
- face_t* frontlist;
- face_t* backlist;
- face_t* frontfrag;
- face_t* backfrag;
- surface_t* news;
- dplane_t* inplane;
- inplane = &g_dplanes[in->planenum];
-
- if (inplane->normal[0] == split->normal[0]
- && inplane->normal[1] == split->normal[1]
- && inplane->normal[2] == split->normal[2])
- {
- if (inplane->dist > split->dist)
- {
- *front = in;
- *back = NULL;
- }
- else if (inplane->dist < split->dist)
- {
- *front = NULL;
- *back = in;
- }
- else
- {
- frontlist = NULL;
- backlist = NULL;
- for (facet = in->faces; facet; facet = next)
- {
- next = facet->next;
- if (facet->planenum & 1)
- {
- facet->next = backlist;
- backlist = facet;
- }
- else
- {
- facet->next = frontlist;
- frontlist = facet;
- }
- }
- goto makesurfs;
- }
- return;
- }
-
-
- frontlist = NULL;
- backlist = NULL;
- for (facet = in->faces; facet; facet = next)
- {
- next = facet->next;
- SplitFace(facet, split, &frontfrag, &backfrag);
- if (frontfrag)
- {
- frontfrag->next = frontlist;
- frontlist = frontfrag;
- }
- if (backfrag)
- {
- backfrag->next = backlist;
- backlist = backfrag;
- }
- }
-
- makesurfs:
- if (frontlist == NULL)
- {
- *front = NULL;
- *back = in;
- in->faces = backlist;
- return;
- }
- if (backlist == NULL)
- {
- *front = in;
- *back = NULL;
- in->faces = frontlist;
- return;
- }
-
- news = AllocSurface();
- *news = *in;
- news->faces = backlist;
- *back = news;
- in->faces = frontlist;
- *front = in;
-
- CalcSurfaceInfo(news);
- CalcSurfaceInfo(in);
- }
- static void SplitNodeSurfaces(surface_t* surfaces, const node_t* const node)
- {
- surface_t* p;
- surface_t* next;
- surface_t* frontlist;
- surface_t* backlist;
- surface_t* frontfrag;
- surface_t* backfrag;
- dplane_t* splitplane;
- splitplane = &g_dplanes[node->planenum];
- frontlist = NULL;
- backlist = NULL;
- for (p = surfaces; p; p = next)
- {
- next = p->next;
- DivideSurface(p, splitplane, &frontfrag, &backfrag);
- if (frontfrag)
- {
- if (!frontfrag->faces)
- {
- Error("surface with no faces");
- }
- frontfrag->next = frontlist;
- frontlist = frontfrag;
- }
- if (backfrag)
- {
- if (!backfrag->faces)
- {
- Error("surface with no faces");
- }
- backfrag->next = backlist;
- backlist = backfrag;
- }
- }
- node->children[0]->surfaces = frontlist;
- node->children[1]->surfaces = backlist;
- }
- static int RankForContents(const int contents)
- {
-
- switch (contents)
- {
- #ifdef ZHLT_NULLTEX
- case CONTENTS_NULL:
-
-
- return -2;
- #endif
- case CONTENTS_EMPTY:
-
- return 0;
- case CONTENTS_WATER:
-
- return 1;
- case CONTENTS_TRANSLUCENT:
-
- return 2;
- case CONTENTS_CURRENT_0:
-
- return 3;
- case CONTENTS_CURRENT_90:
-
- return 4;
- case CONTENTS_CURRENT_180:
-
- return 5;
- case CONTENTS_CURRENT_270:
-
- return 6;
- case CONTENTS_CURRENT_UP:
-
- return 7;
- case CONTENTS_CURRENT_DOWN:
-
- return 8;
- case CONTENTS_SLIME:
-
- return 9;
- case CONTENTS_LAVA:
-
- return 10;
- case CONTENTS_SKY:
-
- return 11;
- case CONTENTS_SOLID:
-
- return 12;
- #ifdef ZHLT_DETAIL
- case CONTENTS_DETAIL:
- return 13;
-
- #endif
- default:
- hlassert(false);
- Error("RankForContents: bad contents %i (Possibly non-solid entity with clip-brush)", contents);
- }
- return -1;
- }
- static int ContentsForRank(const int rank)
- {
- switch (rank)
- {
- #ifdef ZHLT_NULLTEX
- case -2:
- return CONTENTS_NULL;
- #endif
- case -1:
- return CONTENTS_SOLID;
- case 0:
- return CONTENTS_EMPTY;
- case 1:
- return CONTENTS_WATER;
- case 2:
- return CONTENTS_TRANSLUCENT;
- case 3:
- return CONTENTS_CURRENT_0;
- case 4:
- return CONTENTS_CURRENT_90;
- case 5:
- return CONTENTS_CURRENT_180;
- case 6:
- return CONTENTS_CURRENT_270;
- case 7:
- return CONTENTS_CURRENT_UP;
- case 8:
- return CONTENTS_CURRENT_DOWN;
- case 9:
- return CONTENTS_SLIME;
- case 10:
- return CONTENTS_LAVA;
- case 11:
- return CONTENTS_SKY;
- case 12:
- return CONTENTS_SOLID;
- #ifdef ZHLT_DETAIL
- case 13:
- return CONTENTS_DETAIL;
- #endif
- default:
- hlassert(false);
- Error("ContentsForRank: bad rank %i", rank);
- }
- return -1;
- }
- static void FreeLeafSurfs(node_t* leaf)
- {
- surface_t* surf;
- surface_t* snext;
- face_t* f;
- face_t* fnext;
- for (surf = leaf->surfaces; surf; surf = snext)
- {
- snext = surf->next;
- for (f = surf->faces; f; f = fnext)
- {
- fnext = f->next;
- FreeFace(f);
- }
- FreeSurface(surf);
- }
- leaf->surfaces = NULL;
- }
- #define MAX_LEAF_FACES 1024
- static void LinkLeafFaces(surface_t* planelist, node_t* leafnode)
- {
- face_t* f;
- surface_t* surf;
- int rank, r;
- int nummarkfaces;
- face_t* markfaces[MAX_LEAF_FACES];
- leafnode->faces = NULL;
- leafnode->planenum = -1;
- rank = -1;
- for (surf = planelist; surf; surf = surf->next)
- {
- for (f = surf->faces; f; f = f->next)
- {
- if ((f->contents == CONTENTS_HINT))
- {
- f->contents = CONTENTS_EMPTY;
- }
- r = RankForContents(f->contents);
- if (r > rank)
- {
- rank = r;
- }
- }
- }
- leafnode->contents = ContentsForRank(rank);
- if (leafnode->contents != CONTENTS_SOLID)
- {
- nummarkfaces = 0;
- for (surf = leafnode->surfaces; surf; surf = surf->next)
- {
- for (f = surf->faces; f; f = f->next)
- {
- hlassume(nummarkfaces < MAX_LEAF_FACES, assume_MAX_LEAF_FACES);
- markfaces[nummarkfaces++] = f->original;
- }
- }
- markfaces[nummarkfaces] = NULL;
- nummarkfaces++;
- leafnode->markfaces = (face_t**)malloc(nummarkfaces * sizeof(*leafnode->markfaces));
- memcpy(leafnode->markfaces, markfaces, nummarkfaces * sizeof(*leafnode->markfaces));
- }
- FreeLeafSurfs(leafnode);
- leafnode->surfaces = NULL;
- }
- static void MakeNodePortal(node_t* node)
- {
- portal_t* new_portal;
- portal_t* p;
- dplane_t* plane;
- dplane_t clipplane;
- Winding * w;
- int side = 0;
- plane = &g_dplanes[node->planenum];
- w = new Winding(*plane);
- new_portal = AllocPortal();
- new_portal->plane = *plane;
- new_portal->onnode = node;
- for (p = node->portals; p; p = p->next[side])
- {
- clipplane = p->plane;
- if (p->nodes[0] == node)
- {
- side = 0;
- }
- else if (p->nodes[1] == node)
- {
- clipplane.dist = -clipplane.dist;
- VectorSubtract(vec3_origin, clipplane.normal, clipplane.normal);
- side = 1;
- }
- else
- {
- Error("MakeNodePortal: mislinked portal");
- }
- w->Clip(clipplane, true);
- if (!w)
- {
- Warning("MakeNodePortal:new portal was clipped away from node@(%.0f,%.0f,%.0f)-(%.0f,%.0f,%.0f)",
- node->mins[0], node->mins[1], node->mins[2], node->maxs[0], node->maxs[1], node->maxs[2]);
- FreePortal(new_portal);
- return;
- }
- }
- new_portal->winding = w;
- AddPortalToNodes(new_portal, node->children[0], node->children[1]);
- }
- static void SplitNodePortals(node_t *node)
- {
- portal_t* p;
- portal_t* next_portal;
- portal_t* new_portal;
- node_t* f;
- node_t* b;
- node_t* other_node;
- int side = 0;
- dplane_t* plane;
- Winding* frontwinding;
- Winding* backwinding;
- plane = &g_dplanes[node->planenum];
- f = node->children[0];
- b = node->children[1];
- for (p = node->portals; p; p = next_portal)
- {
- if (p->nodes[0] == node)
- {
- side = 0;
- }
- else if (p->nodes[1] == node)
- {
- side = 1;
- }
- else
- {
- Error("SplitNodePortals: mislinked portal");
- }
- next_portal = p->next[side];
- other_node = p->nodes[!side];
- RemovePortalFromNode(p, p->nodes[0]);
- RemovePortalFromNode(p, p->nodes[1]);
-
- p->winding->Divide(*plane, &frontwinding, &backwinding);
- if (!frontwinding)
- {
- if (side == 0)
- {
- AddPortalToNodes(p, b, other_node);
- }
- else
- {
- AddPortalToNodes(p, other_node, b);
- }
- continue;
- }
- if (!backwinding)
- {
- if (side == 0)
- {
- AddPortalToNodes(p, f, other_node);
- }
- else
- {
- AddPortalToNodes(p, other_node, f);
- }
- continue;
- }
-
- new_portal = AllocPortal();
- *new_portal = *p;
- new_portal->winding = backwinding;
- delete p->winding;
- p->winding = frontwinding;
- if (side == 0)
- {
- AddPortalToNodes(p, f, other_node);
- AddPortalToNodes(new_portal, b, other_node);
- }
- else
- {
- AddPortalToNodes(p, other_node, f);
- AddPortalToNodes(new_portal, other_node, b);
- }
- }
- node->portals = NULL;
- }
- static bool CalcNodeBounds(node_t* node)
- {
- int i;
- int j;
- vec_t v;
- portal_t* p;
- portal_t* next_portal;
- int side = 0;
- node->mins[0] = node->mins[1] = node->mins[2] = 9999;
- node->maxs[0] = node->maxs[1] = node->maxs[2] = -9999;
- for (p = node->portals; p; p = next_portal)
- {
- if (p->nodes[0] == node)
- {
- side = 0;
- }
- else if (p->nodes[1] == node)
- {
- side = 1;
- }
- else
- {
- Error("CalcNodeBounds: mislinked portal");
- }
- next_portal = p->next[side];
- for (i = 0; i < p->winding->m_NumPoints; i++)
- {
- for (j = 0; j < 3; j++)
- {
- v = p->winding->m_Points[i][j];
- if (v < node->mins[j])
- {
- node->mins[j] = v;
- }
- if (v > node->maxs[j])
- {
- node->maxs[j] = v;
- }
- }
- }
- }
- for (i = 0; i < 3; i++)
- {
- if (node->maxs[i] - node->mins[i] > g_maxnode_size)
- {
- return true;
- }
- }
- return false;
- }
- static void CopyFacesToNode(node_t* node, surface_t* surf)
- {
- face_t** prevptr;
- face_t* f;
- face_t* newf;
-
- MergePlaneFaces(surf);
-
- prevptr = &surf->faces;
- while (1)
- {
- f = *prevptr;
- if (!f)
- {
- break;
- }
- SubdivideFace(f, prevptr);
- f = *prevptr;
- prevptr = &f->next;
- }
-
- node->surfaces = NULL;
- node->faces = NULL;
- for (f = surf->faces; f; f = f->next)
- {
- if (f->contents != CONTENTS_SOLID)
- {
- newf = AllocFace();
- *newf = *f;
- f->original = newf;
- newf->next = node->faces;
- node->faces = newf;
- }
- }
- }
- static void BuildBspTree_r(node_t* node)
- {
- surface_t* split;
- bool midsplit;
- surface_t* allsurfs;
- midsplit = CalcNodeBounds(node);
- split = SelectPartition(node->surfaces, node, midsplit);
- if (!split)
- {
- node->planenum = PLANENUM_LEAF;
- LinkLeafFaces(node->surfaces, node);
- return;
- }
-
- split->onnode = node;
- allsurfs = node->surfaces;
- node->planenum = split->planenum;
- node->faces = NULL;
- CopyFacesToNode(node, split);
- node->children[0] = AllocNode();
- node->children[1] = AllocNode();
-
- SplitNodeSurfaces(allsurfs, node);
-
- MakeNodePortal(node);
-
- SplitNodePortals(node);
-
- BuildBspTree_r(node->children[0]);
- BuildBspTree_r(node->children[1]);
- UpdateStatus();
- }
- node_t* SolidBSP(const surfchain_t* const surfhead, bool report_progress)
- {
- node_t* headnode;
- ResetStatus(report_progress);
- double start_time = I_FloatTime();
- if(report_progress)
- {
- Log("SolidBSP [hull %d] ",g_hullnum);
- }
- else
- {
- Verbose("----- SolidBSP -----\n");
- }
- headnode = AllocNode();
- headnode->surfaces = surfhead->surfaces;
- if (!surfhead->surfaces)
- {
-
- headnode->planenum = -1;
- headnode->contents = CONTENTS_EMPTY;
- return headnode;
- }
-
- MakeHeadnodePortals(headnode, surfhead->mins, surfhead->maxs);
-
- BuildBspTree_r(headnode);
- double end_time = I_FloatTime();
- if(report_progress)
- {
- Log("%d (%.2f seconds)\n",++g_numProcessed,(end_time - start_time));
- }
- return headnode;
- }
|