00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "../game/q_shared.h"
00033 #include "l_memory.h"
00034 #include "l_script.h"
00035 #include "l_precomp.h"
00036 #include "l_struct.h"
00037 #ifndef BSPC
00038 #include "l_libvar.h"
00039 #endif
00040 #include "aasfile.h"
00041 #include "../game/botlib.h"
00042 #include "../game/be_aas.h"
00043 #include "be_interface.h"
00044 #include "be_aas_funcs.h"
00045 #include "be_aas_def.h"
00046
00047 extern botlib_import_t botimport;
00048
00049
00050
00051 #define BBOX_NORMAL_EPSILON 0.001
00052
00053 #define ON_EPSILON 0 //0.0005
00054
00055 #define TRACEPLANE_EPSILON 0.125
00056
00057 typedef struct aas_tracestack_s
00058 {
00059 vec3_t start;
00060 vec3_t end;
00061 int planenum;
00062 int nodenum;
00063 } aas_tracestack_t;
00064
00065 int numaaslinks;
00066
00067
00068
00069
00070
00071
00072
00073 void AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs)
00074 {
00075 int index;
00076
00077 vec3_t boxmins[3] = {{0, 0, 0}, {-15, -15, -24}, {-15, -15, -24}};
00078 vec3_t boxmaxs[3] = {{0, 0, 0}, { 15, 15, 32}, { 15, 15, 8}};
00079
00080 if (presencetype == PRESENCE_NORMAL) index = 1;
00081 else if (presencetype == PRESENCE_CROUCH) index = 2;
00082 else
00083 {
00084 botimport.Print(PRT_FATAL, "AAS_PresenceTypeBoundingBox: unknown presence type\n");
00085 index = 2;
00086 }
00087 VectorCopy(boxmins[index], mins);
00088 VectorCopy(boxmaxs[index], maxs);
00089 }
00090
00091
00092
00093
00094
00095
00096 void AAS_InitAASLinkHeap(void)
00097 {
00098 int i, max_aaslinks;
00099
00100 max_aaslinks = aasworld.linkheapsize;
00101
00102 if (!aasworld.linkheap)
00103 {
00104 #ifdef BSPC
00105 max_aaslinks = 6144;
00106 #else
00107 max_aaslinks = (int) LibVarValue("max_aaslinks", "6144");
00108 #endif
00109 if (max_aaslinks < 0) max_aaslinks = 0;
00110 aasworld.linkheapsize = max_aaslinks;
00111 aasworld.linkheap = (aas_link_t *) GetHunkMemory(max_aaslinks * sizeof(aas_link_t));
00112 }
00113
00114 aasworld.linkheap[0].prev_ent = NULL;
00115 aasworld.linkheap[0].next_ent = &aasworld.linkheap[1];
00116 for (i = 1; i < max_aaslinks-1; i++)
00117 {
00118 aasworld.linkheap[i].prev_ent = &aasworld.linkheap[i - 1];
00119 aasworld.linkheap[i].next_ent = &aasworld.linkheap[i + 1];
00120 }
00121 aasworld.linkheap[max_aaslinks-1].prev_ent = &aasworld.linkheap[max_aaslinks-2];
00122 aasworld.linkheap[max_aaslinks-1].next_ent = NULL;
00123
00124 aasworld.freelinks = &aasworld.linkheap[0];
00125
00126 numaaslinks = max_aaslinks;
00127 }
00128
00129
00130
00131
00132
00133
00134 void AAS_FreeAASLinkHeap(void)
00135 {
00136 if (aasworld.linkheap) FreeMemory(aasworld.linkheap);
00137 aasworld.linkheap = NULL;
00138 aasworld.linkheapsize = 0;
00139 }
00140
00141
00142
00143
00144
00145
00146 aas_link_t *AAS_AllocAASLink(void)
00147 {
00148 aas_link_t *link;
00149
00150 link = aasworld.freelinks;
00151 if (!link)
00152 {
00153 #ifndef BSPC
00154 if (bot_developer)
00155 #endif
00156 {
00157 botimport.Print(PRT_FATAL, "empty aas link heap\n");
00158 }
00159 return NULL;
00160 }
00161 if (aasworld.freelinks) aasworld.freelinks = aasworld.freelinks->next_ent;
00162 if (aasworld.freelinks) aasworld.freelinks->prev_ent = NULL;
00163 numaaslinks--;
00164 return link;
00165 }
00166
00167
00168
00169
00170
00171
00172 void AAS_DeAllocAASLink(aas_link_t *link)
00173 {
00174 if (aasworld.freelinks) aasworld.freelinks->prev_ent = link;
00175 link->prev_ent = NULL;
00176 link->next_ent = aasworld.freelinks;
00177 link->prev_area = NULL;
00178 link->next_area = NULL;
00179 aasworld.freelinks = link;
00180 numaaslinks++;
00181 }
00182
00183
00184
00185
00186
00187
00188 void AAS_InitAASLinkedEntities(void)
00189 {
00190 if (!aasworld.loaded) return;
00191 if (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities);
00192 aasworld.arealinkedentities = (aas_link_t **) GetClearedHunkMemory(
00193 aasworld.numareas * sizeof(aas_link_t *));
00194 }
00195
00196
00197
00198
00199
00200
00201 void AAS_FreeAASLinkedEntities(void)
00202 {
00203 if (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities);
00204 aasworld.arealinkedentities = NULL;
00205 }
00206
00207
00208
00209
00210
00211
00212
00213 int AAS_PointAreaNum(vec3_t point)
00214 {
00215 int nodenum;
00216 vec_t dist;
00217 aas_node_t *node;
00218 aas_plane_t *plane;
00219
00220 if (!aasworld.loaded)
00221 {
00222 botimport.Print(PRT_ERROR, "AAS_PointAreaNum: aas not loaded\n");
00223 return 0;
00224 }
00225
00226
00227 nodenum = 1;
00228 while (nodenum > 0)
00229 {
00230
00231 #ifdef AAS_SAMPLE_DEBUG
00232 if (nodenum >= aasworld.numnodes)
00233 {
00234 botimport.Print(PRT_ERROR, "nodenum = %d >= aasworld.numnodes = %d\n", nodenum, aasworld.numnodes);
00235 return 0;
00236 }
00237 #endif //AAS_SAMPLE_DEBUG
00238 node = &aasworld.nodes[nodenum];
00239 #ifdef AAS_SAMPLE_DEBUG
00240 if (node->planenum < 0 || node->planenum >= aasworld.numplanes)
00241 {
00242 botimport.Print(PRT_ERROR, "node->planenum = %d >= aasworld.numplanes = %d\n", node->planenum, aasworld.numplanes);
00243 return 0;
00244 }
00245 #endif //AAS_SAMPLE_DEBUG
00246 plane = &aasworld.planes[node->planenum];
00247 dist = DotProduct(point, plane->normal) - plane->dist;
00248 if (dist > 0) nodenum = node->children[0];
00249 else nodenum = node->children[1];
00250 }
00251 if (!nodenum)
00252 {
00253 #ifdef AAS_SAMPLE_DEBUG
00254 botimport.Print(PRT_MESSAGE, "in solid\n");
00255 #endif //AAS_SAMPLE_DEBUG
00256 return 0;
00257 }
00258 return -nodenum;
00259 }
00260
00261
00262
00263
00264
00265
00266 int AAS_PointReachabilityAreaIndex( vec3_t origin )
00267 {
00268 int areanum, cluster, i, index;
00269
00270 if (!aasworld.initialized)
00271 return 0;
00272
00273 if ( !origin )
00274 {
00275 index = 0;
00276 for (i = 0; i < aasworld.numclusters; i++)
00277 {
00278 index += aasworld.clusters[i].numreachabilityareas;
00279 }
00280 return index;
00281 }
00282
00283 areanum = AAS_PointAreaNum( origin );
00284 if ( !areanum || !AAS_AreaReachability(areanum) )
00285 return 0;
00286 cluster = aasworld.areasettings[areanum].cluster;
00287 areanum = aasworld.areasettings[areanum].clusterareanum;
00288 if (cluster < 0)
00289 {
00290 cluster = aasworld.portals[-cluster].frontcluster;
00291 areanum = aasworld.portals[-cluster].clusterareanum[0];
00292 }
00293
00294 index = 0;
00295 for (i = 0; i < cluster; i++)
00296 {
00297 index += aasworld.clusters[i].numreachabilityareas;
00298 }
00299 index += areanum;
00300 return index;
00301 }
00302
00303
00304
00305
00306
00307
00308 int AAS_AreaCluster(int areanum)
00309 {
00310 if (areanum <= 0 || areanum >= aasworld.numareas)
00311 {
00312 botimport.Print(PRT_ERROR, "AAS_AreaCluster: invalid area number\n");
00313 return 0;
00314 }
00315 return aasworld.areasettings[areanum].cluster;
00316 }
00317
00318
00319
00320
00321
00322
00323
00324 int AAS_AreaPresenceType(int areanum)
00325 {
00326 if (!aasworld.loaded) return 0;
00327 if (areanum <= 0 || areanum >= aasworld.numareas)
00328 {
00329 botimport.Print(PRT_ERROR, "AAS_AreaPresenceType: invalid area number\n");
00330 return 0;
00331 }
00332 return aasworld.areasettings[areanum].presencetype;
00333 }
00334
00335
00336
00337
00338
00339
00340
00341 int AAS_PointPresenceType(vec3_t point)
00342 {
00343 int areanum;
00344
00345 if (!aasworld.loaded) return 0;
00346
00347 areanum = AAS_PointAreaNum(point);
00348 if (!areanum) return PRESENCE_NONE;
00349 return aasworld.areasettings[areanum].presencetype;
00350 }
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366 vec_t AAS_BoxOriginDistanceFromPlane(vec3_t normal, vec3_t mins, vec3_t maxs, int side)
00367 {
00368 vec3_t v1, v2;
00369 int i;
00370
00371
00372 if (side)
00373 {
00374
00375
00376 for (i = 0; i < 3; i++)
00377 {
00378 if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = maxs[i];
00379 else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = mins[i];
00380 else v1[i] = 0;
00381 }
00382 }
00383 else
00384 {
00385
00386
00387 for (i = 0; i < 3; i++)
00388 {
00389 if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = mins[i];
00390 else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = maxs[i];
00391 else v1[i] = 0;
00392 }
00393 }
00394
00395 VectorCopy(normal, v2);
00396 VectorInverse(v2);
00397
00398 return DotProduct(v1, v2);
00399 }
00400
00401
00402
00403
00404
00405
00406 qboolean AAS_AreaEntityCollision(int areanum, vec3_t start, vec3_t end,
00407 int presencetype, int passent, aas_trace_t *trace)
00408 {
00409 int collision;
00410 vec3_t boxmins, boxmaxs;
00411 aas_link_t *link;
00412 bsp_trace_t bsptrace;
00413
00414 AAS_PresenceTypeBoundingBox(presencetype, boxmins, boxmaxs);
00415
00416 Com_Memset(&bsptrace, 0, sizeof(bsp_trace_t));
00417
00418 bsptrace.fraction = 1;
00419 collision = qfalse;
00420 for (link = aasworld.arealinkedentities[areanum]; link; link = link->next_ent)
00421 {
00422
00423 if (link->entnum == passent) continue;
00424
00425 if (AAS_EntityCollision(link->entnum, start, boxmins, boxmaxs, end,
00426 CONTENTS_SOLID|CONTENTS_PLAYERCLIP, &bsptrace))
00427 {
00428 collision = qtrue;
00429 }
00430 }
00431 if (collision)
00432 {
00433 trace->startsolid = bsptrace.startsolid;
00434 trace->ent = bsptrace.ent;
00435 VectorCopy(bsptrace.endpos, trace->endpos);
00436 trace->area = 0;
00437 trace->planenum = 0;
00438 return qtrue;
00439 }
00440 return qfalse;
00441 }
00442
00443
00444
00445
00446
00447
00448
00449 aas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype,
00450 int passent)
00451 {
00452 int side, nodenum, tmpplanenum;
00453 float front, back, frac;
00454 vec3_t cur_start, cur_end, cur_mid, v1, v2;
00455 aas_tracestack_t tracestack[127];
00456 aas_tracestack_t *tstack_p;
00457 aas_node_t *aasnode;
00458 aas_plane_t *plane;
00459 aas_trace_t trace;
00460
00461
00462 Com_Memset(&trace, 0, sizeof(aas_trace_t));
00463
00464 if (!aasworld.loaded) return trace;
00465
00466 tstack_p = tracestack;
00467
00468 VectorCopy(start, tstack_p->start);
00469 VectorCopy(end, tstack_p->end);
00470 tstack_p->planenum = 0;
00471
00472 tstack_p->nodenum = 1;
00473 tstack_p++;
00474
00475 while (1)
00476 {
00477
00478 tstack_p--;
00479
00480
00481 if (tstack_p < tracestack)
00482 {
00483 tstack_p++;
00484
00485 trace.startsolid = qfalse;
00486 trace.fraction = 1.0;
00487
00488 VectorCopy(end, trace.endpos);
00489
00490 trace.ent = 0;
00491 trace.area = 0;
00492 trace.planenum = 0;
00493 return trace;
00494 }
00495
00496 nodenum = tstack_p->nodenum;
00497
00498 if (nodenum < 0)
00499 {
00500 #ifdef AAS_SAMPLE_DEBUG
00501 if (-nodenum > aasworld.numareasettings)
00502 {
00503 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: -nodenum out of range\n");
00504 return trace;
00505 }
00506 #endif //AAS_SAMPLE_DEBUG
00507
00508
00509 if (!(aasworld.areasettings[-nodenum].presencetype & presencetype))
00510 {
00511
00512
00513
00514 if (tstack_p->start[0] == start[0] &&
00515 tstack_p->start[1] == start[1] &&
00516 tstack_p->start[2] == start[2])
00517 {
00518 trace.startsolid = qtrue;
00519 trace.fraction = 0.0;
00520 VectorClear(v1);
00521 }
00522 else
00523 {
00524 trace.startsolid = qfalse;
00525 VectorSubtract(end, start, v1);
00526 VectorSubtract(tstack_p->start, start, v2);
00527 trace.fraction = VectorLength(v2) / VectorNormalize(v1);
00528 VectorMA(tstack_p->start, -0.125, v1, tstack_p->start);
00529 }
00530 VectorCopy(tstack_p->start, trace.endpos);
00531 trace.ent = 0;
00532 trace.area = -nodenum;
00533
00534 trace.planenum = tstack_p->planenum;
00535
00536 plane = &aasworld.planes[trace.planenum];
00537 if (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1;
00538 return trace;
00539 }
00540 else
00541 {
00542 if (passent >= 0)
00543 {
00544 if (AAS_AreaEntityCollision(-nodenum, tstack_p->start,
00545 tstack_p->end, presencetype, passent,
00546 &trace))
00547 {
00548 if (!trace.startsolid)
00549 {
00550 VectorSubtract(end, start, v1);
00551 VectorSubtract(trace.endpos, start, v2);
00552 trace.fraction = VectorLength(v2) / VectorLength(v1);
00553 }
00554 return trace;
00555 }
00556 }
00557 }
00558 trace.lastarea = -nodenum;
00559 continue;
00560 }
00561
00562 if (!nodenum)
00563 {
00564
00565
00566
00567 if (tstack_p->start[0] == start[0] &&
00568 tstack_p->start[1] == start[1] &&
00569 tstack_p->start[2] == start[2])
00570 {
00571 trace.startsolid = qtrue;
00572 trace.fraction = 0.0;
00573 VectorClear(v1);
00574 }
00575 else
00576 {
00577 trace.startsolid = qfalse;
00578 VectorSubtract(end, start, v1);
00579 VectorSubtract(tstack_p->start, start, v2);
00580 trace.fraction = VectorLength(v2) / VectorNormalize(v1);
00581 VectorMA(tstack_p->start, -0.125, v1, tstack_p->start);
00582 }
00583 VectorCopy(tstack_p->start, trace.endpos);
00584 trace.ent = 0;
00585 trace.area = 0;
00586
00587 trace.planenum = tstack_p->planenum;
00588
00589 plane = &aasworld.planes[trace.planenum];
00590 if (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1;
00591 return trace;
00592 }
00593 #ifdef AAS_SAMPLE_DEBUG
00594 if (nodenum > aasworld.numnodes)
00595 {
00596 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: nodenum out of range\n");
00597 return trace;
00598 }
00599 #endif //AAS_SAMPLE_DEBUG
00600
00601 aasnode = &aasworld.nodes[nodenum];
00602
00603 VectorCopy(tstack_p->start, cur_start);
00604
00605 VectorCopy(tstack_p->end, cur_end);
00606
00607 plane = &aasworld.planes[aasnode->planenum];
00608
00609 switch(plane->type)
00610 {
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630 default:
00631 {
00632 front = DotProduct(cur_start, plane->normal) - plane->dist;
00633 back = DotProduct(cur_end, plane->normal) - plane->dist;
00634 break;
00635 }
00636 }
00637
00638
00639
00640 if ((front >= -ON_EPSILON && back >= -ON_EPSILON))
00641 {
00642
00643
00644 tstack_p->nodenum = aasnode->children[0];
00645 tstack_p++;
00646 if (tstack_p >= &tracestack[127])
00647 {
00648 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n");
00649 return trace;
00650 }
00651 }
00652
00653
00654 else if ((front < ON_EPSILON && back < ON_EPSILON))
00655 {
00656
00657
00658 tstack_p->nodenum = aasnode->children[1];
00659 tstack_p++;
00660 if (tstack_p >= &tracestack[127])
00661 {
00662 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n");
00663 return trace;
00664 }
00665 }
00666
00667 else
00668 {
00669 tmpplanenum = tstack_p->planenum;
00670
00671 if ( front == back ) front -= 0.001f;
00672
00673
00674 if (front < 0) frac = (front + TRACEPLANE_EPSILON)/(front-back);
00675 else frac = (front - TRACEPLANE_EPSILON)/(front-back);
00676
00677 if (frac < 0)
00678 frac = 0.001f;
00679 else if (frac > 1)
00680 frac = 0.999f;
00681
00682
00683 cur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac;
00684 cur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac;
00685 cur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac;
00686
00687
00688
00689 side = front < 0;
00690
00691 VectorCopy(cur_mid, tstack_p->start);
00692
00693
00694 tstack_p->planenum = aasnode->planenum;
00695 tstack_p->nodenum = aasnode->children[!side];
00696 tstack_p++;
00697 if (tstack_p >= &tracestack[127])
00698 {
00699 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n");
00700 return trace;
00701 }
00702
00703
00704
00705 VectorCopy(cur_start, tstack_p->start);
00706 VectorCopy(cur_mid, tstack_p->end);
00707 tstack_p->planenum = tmpplanenum;
00708 tstack_p->nodenum = aasnode->children[side];
00709 tstack_p++;
00710 if (tstack_p >= &tracestack[127])
00711 {
00712 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n");
00713 return trace;
00714 }
00715 }
00716 }
00717
00718 }
00719
00720
00721
00722
00723
00724
00725
00726 int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas)
00727 {
00728 int side, nodenum, tmpplanenum;
00729 int numareas;
00730 float front, back, frac;
00731 vec3_t cur_start, cur_end, cur_mid;
00732 aas_tracestack_t tracestack[127];
00733 aas_tracestack_t *tstack_p;
00734 aas_node_t *aasnode;
00735 aas_plane_t *plane;
00736
00737 numareas = 0;
00738 areas[0] = 0;
00739 if (!aasworld.loaded) return numareas;
00740
00741 tstack_p = tracestack;
00742
00743 VectorCopy(start, tstack_p->start);
00744 VectorCopy(end, tstack_p->end);
00745 tstack_p->planenum = 0;
00746
00747 tstack_p->nodenum = 1;
00748 tstack_p++;
00749
00750 while (1)
00751 {
00752
00753 tstack_p--;
00754
00755
00756 if (tstack_p < tracestack)
00757 {
00758 return numareas;
00759 }
00760
00761 nodenum = tstack_p->nodenum;
00762
00763 if (nodenum < 0)
00764 {
00765 #ifdef AAS_SAMPLE_DEBUG
00766 if (-nodenum > aasworld.numareasettings)
00767 {
00768 botimport.Print(PRT_ERROR, "AAS_TraceAreas: -nodenum = %d out of range\n", -nodenum);
00769 return numareas;
00770 }
00771 #endif //AAS_SAMPLE_DEBUG
00772
00773 areas[numareas] = -nodenum;
00774 if (points) VectorCopy(tstack_p->start, points[numareas]);
00775 numareas++;
00776 if (numareas >= maxareas) return numareas;
00777 continue;
00778 }
00779
00780 if (!nodenum)
00781 {
00782 continue;
00783 }
00784 #ifdef AAS_SAMPLE_DEBUG
00785 if (nodenum > aasworld.numnodes)
00786 {
00787 botimport.Print(PRT_ERROR, "AAS_TraceAreas: nodenum out of range\n");
00788 return numareas;
00789 }
00790 #endif //AAS_SAMPLE_DEBUG
00791
00792 aasnode = &aasworld.nodes[nodenum];
00793
00794 VectorCopy(tstack_p->start, cur_start);
00795
00796 VectorCopy(tstack_p->end, cur_end);
00797
00798 plane = &aasworld.planes[aasnode->planenum];
00799
00800 switch(plane->type)
00801 {
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821 default:
00822 {
00823 front = DotProduct(cur_start, plane->normal) - plane->dist;
00824 back = DotProduct(cur_end, plane->normal) - plane->dist;
00825 break;
00826 }
00827 }
00828
00829
00830
00831 if (front > 0 && back > 0)
00832 {
00833
00834
00835 tstack_p->nodenum = aasnode->children[0];
00836 tstack_p++;
00837 if (tstack_p >= &tracestack[127])
00838 {
00839 botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n");
00840 return numareas;
00841 }
00842 }
00843
00844
00845 else if (front <= 0 && back <= 0)
00846 {
00847
00848
00849 tstack_p->nodenum = aasnode->children[1];
00850 tstack_p++;
00851 if (tstack_p >= &tracestack[127])
00852 {
00853 botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n");
00854 return numareas;
00855 }
00856 }
00857
00858 else
00859 {
00860 tmpplanenum = tstack_p->planenum;
00861
00862
00863 if (front < 0) frac = (front)/(front-back);
00864 else frac = (front)/(front-back);
00865 if (frac < 0) frac = 0;
00866 else if (frac > 1) frac = 1;
00867
00868
00869 cur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac;
00870 cur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac;
00871 cur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac;
00872
00873
00874
00875 side = front < 0;
00876
00877 VectorCopy(cur_mid, tstack_p->start);
00878
00879
00880 tstack_p->planenum = aasnode->planenum;
00881 tstack_p->nodenum = aasnode->children[!side];
00882 tstack_p++;
00883 if (tstack_p >= &tracestack[127])
00884 {
00885 botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n");
00886 return numareas;
00887 }
00888
00889
00890
00891 VectorCopy(cur_start, tstack_p->start);
00892 VectorCopy(cur_mid, tstack_p->end);
00893 tstack_p->planenum = tmpplanenum;
00894 tstack_p->nodenum = aasnode->children[side];
00895 tstack_p++;
00896 if (tstack_p >= &tracestack[127])
00897 {
00898 botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n");
00899 return numareas;
00900 }
00901 }
00902 }
00903
00904 }
00905
00906
00907
00908
00909
00910
00911
00912
00913 #define AAS_OrthogonalToVectors(v1, v2, res) \
00914 (res)[0] = ((v1)[1] * (v2)[2]) - ((v1)[2] * (v2)[1]);\
00915 (res)[1] = ((v1)[2] * (v2)[0]) - ((v1)[0] * (v2)[2]);\
00916 (res)[2] = ((v1)[0] * (v2)[1]) - ((v1)[1] * (v2)[0]);
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926 qboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon)
00927 {
00928 int i, firstvertex, edgenum;
00929 vec3_t v0;
00930 vec3_t edgevec, pointvec, sepnormal;
00931 aas_edge_t *edge;
00932 #ifdef AAS_SAMPLE_DEBUG
00933 int lastvertex = 0;
00934 #endif //AAS_SAMPLE_DEBUG
00935
00936 if (!aasworld.loaded) return qfalse;
00937
00938 for (i = 0; i < face->numedges; i++)
00939 {
00940 edgenum = aasworld.edgeindex[face->firstedge + i];
00941 edge = &aasworld.edges[abs(edgenum)];
00942
00943 firstvertex = edgenum < 0;
00944 VectorCopy(aasworld.vertexes[edge->v[firstvertex]], v0);
00945
00946 VectorSubtract(aasworld.vertexes[edge->v[!firstvertex]], v0, edgevec);
00947
00948 #ifdef AAS_SAMPLE_DEBUG
00949 if (lastvertex && lastvertex != edge->v[firstvertex])
00950 {
00951 botimport.Print(PRT_MESSAGE, "winding not counter clockwise\n");
00952 }
00953 lastvertex = edge->v[!firstvertex];
00954 #endif //AAS_SAMPLE_DEBUG
00955
00956 VectorSubtract(point, v0, pointvec);
00957
00958
00959
00960
00961
00962 AAS_OrthogonalToVectors(edgevec, pnormal, sepnormal);
00963
00964
00965
00966
00967
00968 if (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse;
00969 }
00970 return qtrue;
00971 }
00972
00973
00974
00975
00976
00977
00978 qboolean AAS_PointInsideFace(int facenum, vec3_t point, float epsilon)
00979 {
00980 int i, firstvertex, edgenum;
00981 vec_t *v1, *v2;
00982 vec3_t edgevec, pointvec, sepnormal;
00983 aas_edge_t *edge;
00984 aas_plane_t *plane;
00985 aas_face_t *face;
00986
00987 if (!aasworld.loaded) return qfalse;
00988
00989 face = &aasworld.faces[facenum];
00990 plane = &aasworld.planes[face->planenum];
00991
00992 for (i = 0; i < face->numedges; i++)
00993 {
00994 edgenum = aasworld.edgeindex[face->firstedge + i];
00995 edge = &aasworld.edges[abs(edgenum)];
00996
00997 firstvertex = edgenum < 0;
00998 v1 = aasworld.vertexes[edge->v[firstvertex]];
00999 v2 = aasworld.vertexes[edge->v[!firstvertex]];
01000
01001 VectorSubtract(v2, v1, edgevec);
01002
01003 VectorSubtract(point, v1, pointvec);
01004
01005 CrossProduct(edgevec, plane->normal, sepnormal);
01006
01007 if (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse;
01008 }
01009 return qtrue;
01010 }
01011
01012
01013
01014
01015
01016
01017
01018 aas_face_t *AAS_AreaGroundFace(int areanum, vec3_t point)
01019 {
01020 int i, facenum;
01021 vec3_t up = {0, 0, 1};
01022 vec3_t normal;
01023 aas_area_t *area;
01024 aas_face_t *face;
01025
01026 if (!aasworld.loaded) return NULL;
01027
01028 area = &aasworld.areas[areanum];
01029 for (i = 0; i < area->numfaces; i++)
01030 {
01031 facenum = aasworld.faceindex[area->firstface + i];
01032 face = &aasworld.faces[abs(facenum)];
01033
01034 if (face->faceflags & FACE_GROUND)
01035 {
01036
01037 if (aasworld.planes[face->planenum].normal[2] < 0) VectorNegate(up, normal);
01038 else VectorCopy(up, normal);
01039
01040 if (AAS_InsideFace(face, normal, point, 0.01f)) return face;
01041 }
01042 }
01043 return NULL;
01044 }
01045
01046
01047
01048
01049
01050
01051
01052 void AAS_FacePlane(int facenum, vec3_t normal, float *dist)
01053 {
01054 aas_plane_t *plane;
01055
01056 plane = &aasworld.planes[aasworld.faces[facenum].planenum];
01057 VectorCopy(plane->normal, normal);
01058 *dist = plane->dist;
01059 }
01060
01061
01062
01063
01064
01065
01066
01067 aas_face_t *AAS_TraceEndFace(aas_trace_t *trace)
01068 {
01069 int i, facenum;
01070 aas_area_t *area;
01071 aas_face_t *face, *firstface = NULL;
01072
01073 if (!aasworld.loaded) return NULL;
01074
01075
01076 if (trace->startsolid) return NULL;
01077
01078 area = &aasworld.areas[trace->lastarea];
01079
01080 for (i = 0; i < area->numfaces; i++)
01081 {
01082 facenum = aasworld.faceindex[area->firstface + i];
01083 face = &aasworld.faces[abs(facenum)];
01084
01085 if ((face->planenum & ~1) == (trace->planenum & ~1))
01086 {
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115 if (AAS_InsideFace(face,
01116 aasworld.planes[face->planenum].normal, trace->endpos, 0.01f)) return face;
01117 }
01118 }
01119 return firstface;
01120 }
01121
01122
01123
01124
01125
01126
01127 int AAS_BoxOnPlaneSide2(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p)
01128 {
01129 int i, sides;
01130 float dist1, dist2;
01131 vec3_t corners[2];
01132
01133 for (i = 0; i < 3; i++)
01134 {
01135 if (p->normal[i] < 0)
01136 {
01137 corners[0][i] = absmins[i];
01138 corners[1][i] = absmaxs[i];
01139 }
01140 else
01141 {
01142 corners[1][i] = absmins[i];
01143 corners[0][i] = absmaxs[i];
01144 }
01145 }
01146 dist1 = DotProduct(p->normal, corners[0]) - p->dist;
01147 dist2 = DotProduct(p->normal, corners[1]) - p->dist;
01148 sides = 0;
01149 if (dist1 >= 0) sides = 1;
01150 if (dist2 < 0) sides |= 2;
01151
01152 return sides;
01153 }
01154
01155
01156
01157
01158
01159
01160
01161 #define AAS_BoxOnPlaneSide(absmins, absmaxs, p) (\
01162 ( (p)->type < 3) ?\
01163 (\
01164 ( (p)->dist <= (absmins)[(p)->type]) ?\
01165 (\
01166 1\
01167 )\
01168 :\
01169 (\
01170 ( (p)->dist >= (absmaxs)[(p)->type]) ?\
01171 (\
01172 2\
01173 )\
01174 :\
01175 (\
01176 3\
01177 )\
01178 )\
01179 )\
01180 :\
01181 (\
01182 AAS_BoxOnPlaneSide2((absmins), (absmaxs), (p))\
01183 )\
01184 ) //end of the function AAS_BoxOnPlaneSide
01185
01186
01187
01188
01189
01190
01191
01192 void AAS_UnlinkFromAreas(aas_link_t *areas)
01193 {
01194 aas_link_t *link, *nextlink;
01195
01196 for (link = areas; link; link = nextlink)
01197 {
01198
01199 nextlink = link->next_area;
01200
01201 if (link->prev_ent) link->prev_ent->next_ent = link->next_ent;
01202 else aasworld.arealinkedentities[link->areanum] = link->next_ent;
01203 if (link->next_ent) link->next_ent->prev_ent = link->prev_ent;
01204
01205 AAS_DeAllocAASLink(link);
01206 }
01207 }
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218 typedef struct
01219 {
01220 int nodenum;
01221 } aas_linkstack_t;
01222
01223 aas_link_t *AAS_AASLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum)
01224 {
01225 int side, nodenum;
01226 aas_linkstack_t linkstack[128];
01227 aas_linkstack_t *lstack_p;
01228 aas_node_t *aasnode;
01229 aas_plane_t *plane;
01230 aas_link_t *link, *areas;
01231
01232 if (!aasworld.loaded)
01233 {
01234 botimport.Print(PRT_ERROR, "AAS_LinkEntity: aas not loaded\n");
01235 return NULL;
01236 }
01237
01238 areas = NULL;
01239
01240 lstack_p = linkstack;
01241
01242
01243 lstack_p->nodenum = 1;
01244 lstack_p++;
01245
01246 while (1)
01247 {
01248
01249 lstack_p--;
01250
01251
01252 if (lstack_p < linkstack) break;
01253
01254 nodenum = lstack_p->nodenum;
01255
01256 if (nodenum < 0)
01257 {
01258
01259
01260 for (link = aasworld.arealinkedentities[-nodenum]; link; link = link->next_ent)
01261 {
01262 if (link->entnum == entnum) break;
01263 }
01264 if (link) continue;
01265
01266 link = AAS_AllocAASLink();
01267 if (!link) return areas;
01268 link->entnum = entnum;
01269 link->areanum = -nodenum;
01270
01271 link->prev_area = NULL;
01272 link->next_area = areas;
01273 if (areas) areas->prev_area = link;
01274 areas = link;
01275
01276 link->prev_ent = NULL;
01277 link->next_ent = aasworld.arealinkedentities[-nodenum];
01278 if (aasworld.arealinkedentities[-nodenum])
01279 aasworld.arealinkedentities[-nodenum]->prev_ent = link;
01280 aasworld.arealinkedentities[-nodenum] = link;
01281
01282 continue;
01283 }
01284
01285 if (!nodenum) continue;
01286
01287 aasnode = &aasworld.nodes[nodenum];
01288
01289 plane = &aasworld.planes[aasnode->planenum];
01290
01291 side = AAS_BoxOnPlaneSide2(absmins, absmaxs, plane);
01292
01293 if (side & 1)
01294 {
01295 lstack_p->nodenum = aasnode->children[0];
01296 lstack_p++;
01297 }
01298 if (lstack_p >= &linkstack[127])
01299 {
01300 botimport.Print(PRT_ERROR, "AAS_LinkEntity: stack overflow\n");
01301 break;
01302 }
01303
01304 if (side & 2)
01305 {
01306 lstack_p->nodenum = aasnode->children[1];
01307 lstack_p++;
01308 }
01309 if (lstack_p >= &linkstack[127])
01310 {
01311 botimport.Print(PRT_ERROR, "AAS_LinkEntity: stack overflow\n");
01312 break;
01313 }
01314 }
01315 return areas;
01316 }
01317
01318
01319
01320
01321
01322
01323 aas_link_t *AAS_LinkEntityClientBBox(vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype)
01324 {
01325 vec3_t mins, maxs;
01326 vec3_t newabsmins, newabsmaxs;
01327
01328 AAS_PresenceTypeBoundingBox(presencetype, mins, maxs);
01329 VectorSubtract(absmins, maxs, newabsmins);
01330 VectorSubtract(absmaxs, mins, newabsmaxs);
01331
01332 return AAS_AASLinkEntity(newabsmins, newabsmaxs, entnum);
01333 }
01334
01335
01336
01337
01338
01339
01340 int AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas)
01341 {
01342 aas_link_t *linkedareas, *link;
01343 int num;
01344
01345 linkedareas = AAS_AASLinkEntity(absmins, absmaxs, -1);
01346 num = 0;
01347 for (link = linkedareas; link; link = link->next_area)
01348 {
01349 areas[num] = link->areanum;
01350 num++;
01351 if (num >= maxareas)
01352 break;
01353 }
01354 AAS_UnlinkFromAreas(linkedareas);
01355 return num;
01356 }
01357
01358
01359
01360
01361
01362
01363 int AAS_AreaInfo( int areanum, aas_areainfo_t *info )
01364 {
01365 aas_areasettings_t *settings;
01366 if (!info)
01367 return 0;
01368 if (areanum <= 0 || areanum >= aasworld.numareas)
01369 {
01370 botimport.Print(PRT_ERROR, "AAS_AreaInfo: areanum %d out of range\n", areanum);
01371 return 0;
01372 }
01373 settings = &aasworld.areasettings[areanum];
01374 info->cluster = settings->cluster;
01375 info->contents = settings->contents;
01376 info->flags = settings->areaflags;
01377 info->presencetype = settings->presencetype;
01378 VectorCopy(aasworld.areas[areanum].mins, info->mins);
01379 VectorCopy(aasworld.areas[areanum].maxs, info->maxs);
01380 VectorCopy(aasworld.areas[areanum].center, info->center);
01381 return sizeof(aas_areainfo_t);
01382 }
01383
01384
01385
01386
01387
01388
01389 aas_plane_t *AAS_PlaneFromNum(int planenum)
01390 {
01391 if (!aasworld.loaded) return 0;
01392
01393 return &aasworld.planes[planenum];
01394 }