//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_RT_AddParentLink( aas_area_childlocaldata_t *child, int parentindex, int childindex ) { aas_parent_link_t *oldparentlink; oldparentlink = child->parentlink; child->parentlink = (aas_parent_link_t *) AAS_RT_GetClearedMemory( sizeof( aas_parent_link_t ) ); child->parentlink->childindex = (unsigned short int)childindex; child->parentlink->parent = (unsigned short int)parentindex; child->parentlink->next = oldparentlink; }
void AAS_RT_BuildRouteTable(void) { int i, j, k; aas_area_t *srcarea; aas_areasettings_t *srcsettings; // vec3_t vec; unsigned int totalcount; unsigned int noroutecount; aas_area_buildlocalinfo_t **area_localinfos; aas_area_buildlocalinfo_t *localinfo; aas_area_childlocaldata_t **area_childlocaldata; aas_area_childlocaldata_t *child; aas_area_parent_t *area_parents[MAX_PARENTS]; aas_area_parent_t *thisparent; int bestchild, bestcount, bestparent, cnt; int memoryend; unsigned short int *visibleParents; #ifdef CHECK_TRAVEL_TIMES aas_rt_route_t **filteredroutetable; unsigned short int traveltime; #endif fileHandle_t fp; char filename[MAX_QPATH]; // not used anymore return; // create the routetable in this aasworld aasworld->routetable = (aas_rt_t *) AAS_RT_GetClearedMemory(sizeof(aas_rt_t)); // Try to load in a prepared route-table Com_sprintf(filename, MAX_QPATH, "maps/%s.rtb", (*aasworld).mapname); botimport.Print(PRT_MESSAGE, "\n---------------------------------\n"); botimport.Print(PRT_MESSAGE, "\ntrying to load %s\n", filename); botimport.FS_FOpenFile(filename, &fp, FS_READ); if (fp) { // read in the table.. if (AAS_RT_ReadRouteTable(fp)) { AAS_RT_PrintMemoryUsage(); botimport.Print(PRT_MESSAGE, "\nAAS Route-Table loaded.\n"); botimport.Print(PRT_MESSAGE, "---------------------------------\n\n"); return; } else { botimport.Print(PRT_MESSAGE, "\nUnable to load %s, building route-table..\n", filename); } } else { botimport.Print(PRT_MESSAGE, "file not found, building route-table\n\n"); } botimport.Print(PRT_MESSAGE, "\n-------------------------------------\nRoute-table memory usage figures..\n\n"); totalcount = 0; childcount = 0; noroutecount = 0; childcount = 0; num_parents = 0; memorycount = 0; cachememory = 0; filtered_areas = (unsigned short int *) AAS_RT_GetClearedMemory((*aasworld).numareas * sizeof(unsigned short int)); rev_filtered_areas = (unsigned short int *) AAS_RT_GetClearedMemory((*aasworld).numareas * sizeof(unsigned short int)); // to speed things up, build a list of FILTERED areas first // do this so we can check for filtered areas AAS_CreateAllRoutingCache(); for (i = 0; i < (*aasworld).numareas; i++) { srcarea = &(*aasworld).areas[i]; srcsettings = &(*aasworld).areasettings[i]; #ifdef FILTERAREAS if (!(srcsettings->areaflags & (AREA_USEFORROUTING))) { continue; } if (!(srcsettings->areaflags & (AREA_GROUNDED | AREA_LIQUID | AREA_LADDER))) { continue; } #endif rev_filtered_areas[i] = childcount + 1; filtered_areas[childcount++] = (unsigned short int)i; } #ifdef CHECK_TRAVEL_TIMES // allocate and calculate the travel times filteredroutetable = (aas_rt_route_t **) AAS_RT_GetClearedMemory(childcount * sizeof(aas_rt_route_t *)); for (i = 0; i < childcount; i++) filteredroutetable[i] = (aas_rt_route_t *) AAS_RT_GetClearedMemory(childcount * sizeof(aas_rt_route_t)); AAS_RT_CalculateRouteTable(filteredroutetable); #endif // CHECK_TRAVEL_TIMES // allocate for the temporary build local data area_localinfos = (aas_area_buildlocalinfo_t **) AAS_RT_GetClearedMemory(childcount * sizeof(aas_area_buildlocalinfo_t *)); for (i = 0; i < childcount; i++) { srcarea = &(*aasworld).areas[filtered_areas[i]]; srcsettings = &(*aasworld).areasettings[filtered_areas[i]]; // allocate memory for this area area_localinfos[i] = (aas_area_buildlocalinfo_t *) AAS_RT_GetClearedMemory(sizeof(aas_area_buildlocalinfo_t)); localinfo = area_localinfos[i]; for (j = 0; j < childcount; j++) { if (i == j) { continue; } #ifdef CHECK_TRAVEL_TIMES // make sure travel time is reasonable // Get the travel time from i to j traveltime = (int)filteredroutetable[i][j].travel_time; if (!traveltime) { noroutecount++; continue; } if (traveltime > MAX_LOCALTRAVELTIME) { continue; } #endif // CHECK_TRAVEL_TIMES // Add it to the list localinfo->visible[localinfo->numvisible++] = j; totalcount++; if (localinfo->numvisible >= MAX_VISIBLE_AREAS) { botimport.Print(PRT_MESSAGE, "MAX_VISIBLE_AREAS exceeded, lower MAX_VISIBLE_RANGE\n"); break; } } } // now calculate the best list of locale's // allocate for the long-term child data area_childlocaldata = (aas_area_childlocaldata_t **) AAS_RT_GetClearedMemory(childcount * sizeof(aas_area_childlocaldata_t *)); for (i = 0; i < childcount; i++) { area_childlocaldata[i] = (aas_area_childlocaldata_t *) AAS_RT_GetClearedMemory(sizeof(aas_area_childlocaldata_t)); area_childlocaldata[i]->areanum = filtered_areas[i]; } while (1) { bestchild = -1; bestcount = 99999; // find the area with the least number of visible areas for (i = 0; i < childcount; i++) { if (area_childlocaldata[i]->parentlink) { continue; // already has been allocated to a parent } cnt = AAS_RT_GetValidVisibleAreasCount(area_localinfos[i], area_childlocaldata); if (cnt < bestcount) { bestcount = area_localinfos[i]->numvisible; bestchild = i; } } if (bestchild < 0) { break; // our job is done } localinfo = area_localinfos[bestchild]; // look through this area's list of visible areas, and pick the one with the most VALID visible areas bestparent = bestchild; for (i = 0; i < localinfo->numvisible; i++) { if (area_childlocaldata[localinfo->visible[i]]->parentlink) { continue; // already has been allocated to a parent } // calculate how many of children are valid cnt = AAS_RT_GetValidVisibleAreasCount(area_localinfos[localinfo->visible[i]], area_childlocaldata); if (cnt > bestcount) { bestcount = cnt; bestparent = localinfo->visible[i]; } } // now setup this parent, and assign all it's children localinfo = area_localinfos[bestparent]; // we use all children now, not just valid ones bestcount = localinfo->numvisible; area_parents[num_parents] = (aas_area_parent_t *) AAS_RT_GetClearedMemory(sizeof(aas_area_parent_t)); thisparent = area_parents[num_parents]; thisparent->areanum = filtered_areas[bestparent]; thisparent->children = (unsigned short int *) AAS_RT_GetClearedMemory((localinfo->numvisible + 1) * sizeof(unsigned short int)); // first, add itself to the list (yes, a parent is a child of itself) child = area_childlocaldata[bestparent]; AAS_RT_AddParentLink(child, num_parents, thisparent->numchildren); thisparent->children[thisparent->numchildren++] = filtered_areas[bestparent]; // loop around all the parent's visible list, and make them children if they're aren't already assigned to a parent for (i = 0; i < localinfo->numvisible; i++) { // create the childlocaldata child = area_childlocaldata[localinfo->visible[i]]; // Ridah, only one parent per child in the new system if (child->parentlink) { continue; // already has been allocated to a parent } if (child->areanum != thisparent->areanum) { AAS_RT_AddParentLink(child, num_parents, thisparent->numchildren); thisparent->children[thisparent->numchildren++] = filtered_areas[localinfo->visible[i]]; } } // now setup the list of children and the route-tables for (i = 0; i < thisparent->numchildren; i++) { child = area_childlocaldata[-1 + rev_filtered_areas[thisparent->children[i]]]; localinfo = area_localinfos[-1 + rev_filtered_areas[thisparent->children[i]]]; child->parentlink->routeindexes = (unsigned short int *) AAS_RT_GetClearedMemory(thisparent->numchildren * sizeof(unsigned short int)); // now setup the indexes for (j = 0; j < thisparent->numchildren; j++) { // find this child in our list of visibles if (j == child->parentlink->childindex) { continue; } for (k = 0; k < localinfo->numvisible; k++) { if (thisparent->children[j] == filtered_areas[localinfo->visible[k]]) // found a match { child->parentlink->routeindexes[j] = (unsigned short int)k; break; } } if (k == localinfo->numvisible) // didn't find it, so add it to our list { if (localinfo->numvisible >= MAX_VISIBLE_AREAS) { botimport.Print(PRT_MESSAGE, "MAX_VISIBLE_AREAS exceeded, lower MAX_VISIBLE_RANGE\n"); } else { localinfo->visible[localinfo->numvisible] = -1 + rev_filtered_areas[thisparent->children[j]]; child->parentlink->routeindexes[j] = (unsigned short int)localinfo->numvisible; localinfo->numvisible++; } } } } num_parents++; } // place all the visible areas from each child, into their childlocaldata route-table for (i = 0; i < childcount; i++) { localinfo = area_localinfos[i]; child = area_childlocaldata[i]; child->numlocal = localinfo->numvisible; child->localroutes = (aas_rt_route_t *) AAS_RT_GetClearedMemory(localinfo->numvisible * sizeof(aas_rt_route_t)); for (j = 0; j < localinfo->numvisible; j++) { child->localroutes[j] = filteredroutetable[i][localinfo->visible[j]]; } child->parentroutes = (aas_rt_route_t *) AAS_RT_GetClearedMemory(num_parents * sizeof(aas_rt_route_t)); for (j = 0; j < num_parents; j++) { child->parentroutes[j] = filteredroutetable[i][-1 + rev_filtered_areas[area_parents[j]->areanum]]; } } // build the visibleParents lists visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory(num_parents * sizeof(unsigned short int)); for (i = 0; i < num_parents; i++) { area_parents[i]->numVisibleParents = 0; for (j = 0; j < num_parents; j++) { if (i == j) { continue; } if (!AAS_inPVS((*aasworld).areas[area_parents[i]->areanum].center, (*aasworld).areas[area_parents[j]->areanum].center)) { continue; } visibleParents[area_parents[i]->numVisibleParents] = j; area_parents[i]->numVisibleParents++; } // now copy the list over to the current src area area_parents[i]->visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory(area_parents[i]->numVisibleParents * sizeof(unsigned short int)); memcpy(area_parents[i]->visibleParents, visibleParents, area_parents[i]->numVisibleParents * sizeof(unsigned short int)); } AAS_RT_FreeMemory(visibleParents); // before we free the main childlocaldata, go through and assign the aas_area's to their appropriate childlocaldata // this would require modification of the aas_area_t structure, so for now, we'll just place them in a global array, for external reference // aasworld->routetable->area_childlocaldata_list = (aas_area_childlocaldata_t **) AAS_RT_GetClearedMemory( (*aasworld).numareas * sizeof(aas_area_childlocaldata_t *) ); // for (i=0; i<childcount; i++) // { // aasworld->routetable->area_childlocaldata_list[filtered_areas[i]] = area_childlocaldata[i]; // } // copy the list of parents to a global structure for now (should eventually go into the (*aasworld) structure // aasworld->routetable->area_parents_global = (aas_area_parent_t **) AAS_RT_GetClearedMemory( num_parents * sizeof(aas_area_parent_t *) ); // memcpy( aasworld->routetable->area_parents_global, area_parents, num_parents * sizeof(aas_area_parent_t *) ); // ................................................ // Convert the data into the correct format { aas_rt_t *rt; aas_rt_child_t *child; aas_rt_parent_t *parent; aas_rt_parent_link_t *plink; unsigned short int *psi; aas_area_childlocaldata_t *chloc; aas_area_parent_t *apar; aas_parent_link_t *oplink; int localRoutesCount, parentRoutesCount, parentChildrenCount, visibleParentsCount, parentLinkCount, routeIndexesCount; rt = (*aasworld).routetable; localRoutesCount = 0; parentRoutesCount = 0; parentChildrenCount = 0; visibleParentsCount = 0; parentLinkCount = 0; routeIndexesCount = 0; // areaChildIndexes rt->areaChildIndexes = (unsigned short int *) AAS_RT_GetClearedMemory((*aasworld).numareas * sizeof(unsigned short int)); for (i = 0; i < childcount; i++) { rt->areaChildIndexes[filtered_areas[i]] = i + 1; } // children rt->numChildren = childcount; rt->children = (aas_rt_child_t *) AAS_RT_GetClearedMemory(rt->numChildren * sizeof(aas_rt_child_t)); child = rt->children; for (i = 0; i < childcount; i++, child++) { chloc = area_childlocaldata[i]; child->areanum = chloc->areanum; child->numParentLinks = AAS_RT_NumParentLinks(chloc); child->startParentLinks = parentLinkCount; parentLinkCount += child->numParentLinks; } // parents rt->numParents = num_parents; rt->parents = (aas_rt_parent_t *) AAS_RT_GetClearedMemory(rt->numParents * sizeof(aas_rt_parent_t)); parent = rt->parents; for (i = 0; i < num_parents; i++, parent++) { apar = area_parents[i]; parent->areanum = apar->areanum; parent->numParentChildren = apar->numchildren; parent->numVisibleParents = apar->numVisibleParents; parent->startParentChildren = parentChildrenCount; parent->startVisibleParents = visibleParentsCount; parentChildrenCount += parent->numParentChildren; visibleParentsCount += parent->numVisibleParents; } // parentChildren rt->numParentChildren = parentChildrenCount; rt->parentChildren = (unsigned short int *) AAS_RT_GetClearedMemory(parentChildrenCount * sizeof(unsigned short int)); psi = rt->parentChildren; for (i = 0; i < num_parents; i++) { apar = area_parents[i]; for (j = 0; j < apar->numchildren; j++, psi++) { *psi = apar->children[j]; } } // visibleParents rt->numVisibleParents = visibleParentsCount; rt->visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory(rt->numVisibleParents * sizeof(unsigned short int)); psi = rt->visibleParents; for (i = 0; i < num_parents; i++) { apar = area_parents[i]; for (j = 0; j < apar->numVisibleParents; j++, psi++) { *psi = apar->visibleParents[j]; } } // parentLinks rt->numParentLinks = parentLinkCount; rt->parentLinks = (aas_rt_parent_link_t *) AAS_RT_GetClearedMemory(parentLinkCount * sizeof(aas_rt_parent_link_t)); plink = rt->parentLinks; for (i = 0; i < childcount; i++) { chloc = area_childlocaldata[i]; for (oplink = chloc->parentlink; oplink; plink++, oplink = oplink->next) { plink->childIndex = oplink->childindex; plink->parent = oplink->parent; } } } // ................................................ // write the newly created table AAS_RT_WriteRouteTable(); botimport.Print(PRT_MESSAGE, "Child Areas: %i\nTotal Parents: %i\nAverage VisAreas: %i\n", (int)childcount, num_parents, (int)(childcount / num_parents)); botimport.Print(PRT_MESSAGE, "NoRoute Ratio: %i%%\n", (int)((100.0 * noroutecount) / (1.0 * childcount * childcount))); memoryend = memorycount; // clear allocated memory // causes crashes in route-caching //#ifdef USE_ROUTECACHE // AAS_FreeRoutingCaches(); //#endif for (i = 0; i < childcount; i++) { AAS_RT_FreeMemory(area_localinfos[i]); #ifdef CHECK_TRAVEL_TIMES AAS_RT_FreeMemory(filteredroutetable[i]); #endif } { aas_parent_link_t *next, *trav; // kill the client areas for (i = 0; i < childcount; i++) { // kill the parent links next = area_childlocaldata[i]->parentlink; // TTimo gcc: suggests () around assignment used as truth value while ((trav = next)) { next = next->next; AAS_RT_FreeMemory(trav->routeindexes); AAS_RT_FreeMemory(trav); } AAS_RT_FreeMemory(area_childlocaldata[i]->localroutes); AAS_RT_FreeMemory(area_childlocaldata[i]->parentroutes); AAS_RT_FreeMemory(area_childlocaldata[i]); } // kill the parents for (i = 0; i < num_parents; i++) { AAS_RT_FreeMemory(area_parents[i]->children); AAS_RT_FreeMemory(area_parents[i]->visibleParents); AAS_RT_FreeMemory(area_parents[i]); } } AAS_RT_FreeMemory(area_localinfos); AAS_RT_FreeMemory(area_childlocaldata); AAS_RT_FreeMemory(filtered_areas); AAS_RT_FreeMemory(rev_filtered_areas); #ifdef CHECK_TRAVEL_TIMES AAS_RT_FreeMemory(filteredroutetable); #endif // check how much memory we've used, and intend to keep AAS_RT_PrintMemoryUsage(); botimport.Print(PRT_MESSAGE, "Route-Table Permanent Memory Usage: %i\n", memorycount); botimport.Print(PRT_MESSAGE, "Route-Table Calculation Usage: %i\n", memoryend + cachememory); botimport.Print(PRT_MESSAGE, "---------------------------------\n"); }
qboolean AAS_RT_ReadRouteTable(fileHandle_t fp) { int ident, version, i; unsigned short int crc, crc_aas; aas_rt_t *routetable; aas_rt_child_t *child; aas_rt_parent_t *parent; aas_rt_parent_link_t *plink; unsigned short int *psi; qboolean doswap; #ifdef DEBUG_READING_TIME int pretime; pretime = Sys_MilliSeconds(); #endif routetable = (*aasworld).routetable; doswap = (LittleLong(1) != 1); // check ident AAS_RT_DBG_Read(&ident, sizeof(ident), fp); ident = LittleLong(ident); if (ident != RTBID) { AAS_Error("File is not an RTB file\n"); botimport.FS_FCloseFile(fp); return qfalse; } // check version AAS_RT_DBG_Read(&version, sizeof(version), fp); version = LittleLong(version); if (version != RTBVERSION) { AAS_Error("File is version %i not %i\n", version, RTBVERSION); botimport.FS_FCloseFile(fp); return qfalse; } // read the CRC check on the AAS data AAS_RT_DBG_Read(&crc, sizeof(crc), fp); crc = LittleShort(crc); // calculate a CRC on the AAS areas crc_aas = CRC_ProcessString((unsigned char *)(*aasworld).areas, sizeof(aas_area_t) * (*aasworld).numareas); if (crc != crc_aas) { AAS_Error("Route-table is from different AAS file, ignoring.\n"); botimport.FS_FCloseFile(fp); return qfalse; } // read the route-table // children botimport.FS_Read(&routetable->numChildren, sizeof(int), fp); routetable->numChildren = LittleLong(routetable->numChildren); routetable->children = (aas_rt_child_t *) AAS_RT_GetClearedMemory(routetable->numChildren * sizeof(aas_rt_child_t)); botimport.FS_Read(routetable->children, routetable->numChildren * sizeof(aas_rt_child_t), fp); child = &routetable->children[0]; if (doswap) { for (i = 0; i < routetable->numChildren; i++, child++) { child->areanum = LittleShort(child->areanum); child->numParentLinks = LittleLong(child->numParentLinks); child->startParentLinks = LittleLong(child->startParentLinks); } } // parents botimport.FS_Read(&routetable->numParents, sizeof(int), fp); routetable->numParents = LittleLong(routetable->numParents); routetable->parents = (aas_rt_parent_t *) AAS_RT_GetClearedMemory(routetable->numParents * sizeof(aas_rt_parent_t)); botimport.FS_Read(routetable->parents, routetable->numParents * sizeof(aas_rt_parent_t), fp); parent = &routetable->parents[0]; if (doswap) { for (i = 0; i < routetable->numParents; i++, parent++) { parent->areanum = LittleShort(parent->areanum); parent->numParentChildren = LittleLong(parent->numParentChildren); parent->startParentChildren = LittleLong(parent->startParentChildren); parent->numVisibleParents = LittleLong(parent->numVisibleParents); parent->startVisibleParents = LittleLong(parent->startVisibleParents); } } // parentChildren botimport.FS_Read(&routetable->numParentChildren, sizeof(int), fp); routetable->numParentChildren = LittleLong(routetable->numParentChildren); routetable->parentChildren = (unsigned short int *) AAS_RT_GetClearedMemory(routetable->numParentChildren * sizeof(unsigned short int)); botimport.FS_Read(routetable->parentChildren, routetable->numParentChildren * sizeof(unsigned short int), fp); psi = &routetable->parentChildren[0]; if (doswap) { for (i = 0; i < routetable->numParentChildren; i++, psi++) { *psi = LittleShort(*psi); } } // visibleParents botimport.FS_Read(&routetable->numVisibleParents, sizeof(int), fp); routetable->numVisibleParents = LittleLong(routetable->numVisibleParents); routetable->visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory(routetable->numVisibleParents * sizeof(unsigned short int)); botimport.FS_Read(routetable->visibleParents, routetable->numVisibleParents * sizeof(unsigned short int), fp); psi = &routetable->visibleParents[0]; if (doswap) { for (i = 0; i < routetable->numVisibleParents; i++, psi++) { *psi = LittleShort(*psi); } } // parentLinks botimport.FS_Read(&routetable->numParentLinks, sizeof(int), fp); routetable->numParentLinks = LittleLong(routetable->numParentLinks); routetable->parentLinks = (aas_rt_parent_link_t *) AAS_RT_GetClearedMemory(routetable->numParentLinks * sizeof(aas_rt_parent_link_t)); botimport.FS_Read(routetable->parentLinks, routetable->numParentLinks * sizeof(aas_parent_link_t), fp); plink = &routetable->parentLinks[0]; if (doswap) { for (i = 0; i < routetable->numParentLinks; i++, plink++) { plink->childIndex = LittleShort(plink->childIndex); plink->parent = LittleShort(plink->parent); } } // build the areaChildIndexes routetable->areaChildIndexes = (unsigned short int *) AAS_RT_GetClearedMemory((*aasworld).numareas * sizeof(unsigned short int)); child = routetable->children; for (i = 0; i < routetable->numChildren; i++, child++) { routetable->areaChildIndexes[child->areanum] = i + 1; } botimport.Print(PRT_MESSAGE, "Total Parents: %d\n", routetable->numParents); botimport.Print(PRT_MESSAGE, "Total Children: %d\n", routetable->numChildren); botimport.Print(PRT_MESSAGE, "Total Memory Used: %d\n", memorycount); #ifdef DEBUG_READING_TIME botimport.Print(PRT_MESSAGE, "Route-Table read time: %i\n", Sys_MilliSeconds() - pretime); #endif botimport.FS_FCloseFile(fp); return qtrue; }