2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // world.c -- world query functions
26 entities never clip against themselves, or their owner
28 line of sight checks trace->inopen and trace->inwater, but bullets don't
37 //============================================================================
39 // World_ClearLink is used for new headnodes
40 void World_ClearLink (link_t *l)
43 l->prev = l->next = l;
46 void World_RemoveLink (link_t *l)
48 l->next->prev = l->prev;
49 l->prev->next = l->next;
52 void World_InsertLinkBefore (link_t *l, link_t *before, int entitynumber)
54 l->entitynumber = entitynumber;
56 l->prev = before->prev;
62 ===============================================================================
66 ===============================================================================
69 void World_PrintAreaStats(world_t *world, const char *worldname)
71 Con_Printf("%s areagrid check stats: %d calls %d nodes (%f per call) %d entities (%f per call)\n", worldname, world->areagrid_stats_calls, world->areagrid_stats_nodechecks, (double) world->areagrid_stats_nodechecks / (double) world->areagrid_stats_calls, world->areagrid_stats_entitychecks, (double) world->areagrid_stats_entitychecks / (double) world->areagrid_stats_calls);
72 world->areagrid_stats_calls = 0;
73 world->areagrid_stats_nodechecks = 0;
74 world->areagrid_stats_entitychecks = 0;
83 void World_SetSize(world_t *world, const char *filename, const vec3_t mins, const vec3_t maxs)
87 strlcpy(world->filename, filename, sizeof(world->filename));
88 VectorCopy(mins, world->mins);
89 VectorCopy(maxs, world->maxs);
91 // the areagrid_marknumber is not allowed to be 0
92 if (world->areagrid_marknumber < 1)
93 world->areagrid_marknumber = 1;
94 // choose either the world box size, or a larger box to ensure the grid isn't too fine
95 world->areagrid_size[0] = max(world->areagrid_maxs[0] - world->areagrid_mins[0], AREA_GRID * sv_areagrid_mingridsize.value);
96 world->areagrid_size[1] = max(world->areagrid_maxs[1] - world->areagrid_mins[1], AREA_GRID * sv_areagrid_mingridsize.value);
97 world->areagrid_size[2] = max(world->areagrid_maxs[2] - world->areagrid_mins[2], AREA_GRID * sv_areagrid_mingridsize.value);
98 // figure out the corners of such a box, centered at the center of the world box
99 world->areagrid_mins[0] = (world->areagrid_mins[0] + world->areagrid_maxs[0] - world->areagrid_size[0]) * 0.5f;
100 world->areagrid_mins[1] = (world->areagrid_mins[1] + world->areagrid_maxs[1] - world->areagrid_size[1]) * 0.5f;
101 world->areagrid_mins[2] = (world->areagrid_mins[2] + world->areagrid_maxs[2] - world->areagrid_size[2]) * 0.5f;
102 world->areagrid_maxs[0] = (world->areagrid_mins[0] + world->areagrid_maxs[0] + world->areagrid_size[0]) * 0.5f;
103 world->areagrid_maxs[1] = (world->areagrid_mins[1] + world->areagrid_maxs[1] + world->areagrid_size[1]) * 0.5f;
104 world->areagrid_maxs[2] = (world->areagrid_mins[2] + world->areagrid_maxs[2] + world->areagrid_size[2]) * 0.5f;
105 // now calculate the actual useful info from that
106 VectorNegate(world->areagrid_mins, world->areagrid_bias);
107 world->areagrid_scale[0] = AREA_GRID / world->areagrid_size[0];
108 world->areagrid_scale[1] = AREA_GRID / world->areagrid_size[1];
109 world->areagrid_scale[2] = AREA_GRID / world->areagrid_size[2];
110 World_ClearLink(&world->areagrid_outside);
111 for (i = 0;i < AREA_GRIDNODES;i++)
112 World_ClearLink(&world->areagrid[i]);
113 if (developer.integer >= 10)
114 Con_Printf("areagrid settings: divisions %ix%ix1 : box %f %f %f : %f %f %f size %f %f %f grid %f %f %f (mingrid %f)\n", AREA_GRID, AREA_GRID, world->areagrid_mins[0], world->areagrid_mins[1], world->areagrid_mins[2], world->areagrid_maxs[0], world->areagrid_maxs[1], world->areagrid_maxs[2], world->areagrid_size[0], world->areagrid_size[1], world->areagrid_size[2], 1.0f / world->areagrid_scale[0], 1.0f / world->areagrid_scale[1], 1.0f / world->areagrid_scale[2], sv_areagrid_mingridsize.value);
123 void World_UnlinkAll(world_t *world)
127 // unlink all entities one by one
128 grid = &world->areagrid_outside;
129 while (grid->next != grid)
130 World_UnlinkEdict(PRVM_EDICT_NUM(grid->next->entitynumber));
131 for (i = 0, grid = world->areagrid;i < AREA_GRIDNODES;i++, grid++)
132 while (grid->next != grid)
133 World_UnlinkEdict(PRVM_EDICT_NUM(grid->next->entitynumber));
141 void World_UnlinkEdict(prvm_edict_t *ent)
144 for (i = 0;i < ENTITYGRIDAREAS;i++)
146 if (ent->priv.server->areagrid[i].prev)
148 World_RemoveLink (&ent->priv.server->areagrid[i]);
149 ent->priv.server->areagrid[i].prev = ent->priv.server->areagrid[i].next = NULL;
154 int World_EntitiesInBox(world_t *world, const vec3_t mins, const vec3_t maxs, int maxlist, prvm_edict_t **list)
160 int igrid[3], igridmins[3], igridmaxs[3];
162 // FIXME: if areagrid_marknumber wraps, all entities need their
163 // ent->priv.server->areagridmarknumber reset
164 world->areagrid_stats_calls++;
165 world->areagrid_marknumber++;
166 igridmins[0] = (int) floor((mins[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]);
167 igridmins[1] = (int) floor((mins[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]);
168 //igridmins[2] = (int) ((mins[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]);
169 igridmaxs[0] = (int) floor((maxs[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]) + 1;
170 igridmaxs[1] = (int) floor((maxs[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]) + 1;
171 //igridmaxs[2] = (int) ((maxs[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]) + 1;
172 igridmins[0] = max(0, igridmins[0]);
173 igridmins[1] = max(0, igridmins[1]);
174 //igridmins[2] = max(0, igridmins[2]);
175 igridmaxs[0] = min(AREA_GRID, igridmaxs[0]);
176 igridmaxs[1] = min(AREA_GRID, igridmaxs[1]);
177 //igridmaxs[2] = min(AREA_GRID, igridmaxs[2]);
180 // add entities not linked into areagrid because they are too big or
181 // outside the grid bounds
182 if (world->areagrid_outside.next != &world->areagrid_outside)
184 grid = &world->areagrid_outside;
185 for (l = grid->next;l != grid;l = l->next)
187 ent = PRVM_EDICT_NUM(l->entitynumber);
188 if (ent->priv.server->areagridmarknumber != world->areagrid_marknumber)
190 ent->priv.server->areagridmarknumber = world->areagrid_marknumber;
191 if (!ent->priv.server->free && BoxesOverlap(mins, maxs, ent->priv.server->areamins, ent->priv.server->areamaxs))
193 if (numlist < maxlist)
197 world->areagrid_stats_entitychecks++;
201 // add grid linked entities
202 for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++)
204 grid = world->areagrid + igrid[1] * AREA_GRID + igridmins[0];
205 for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++)
207 if (grid->next != grid)
209 for (l = grid->next;l != grid;l = l->next)
211 ent = PRVM_EDICT_NUM(l->entitynumber);
212 if (ent->priv.server->areagridmarknumber != world->areagrid_marknumber)
214 ent->priv.server->areagridmarknumber = world->areagrid_marknumber;
215 if (!ent->priv.server->free && BoxesOverlap(mins, maxs, ent->priv.server->areamins, ent->priv.server->areamaxs))
217 if (numlist < maxlist)
221 //Con_Printf("%d %f %f %f %f %f %f : %d : %f %f %f %f %f %f\n", BoxesOverlap(mins, maxs, ent->priv.server->areamins, ent->priv.server->areamaxs), ent->priv.server->areamins[0], ent->priv.server->areamins[1], ent->priv.server->areamins[2], ent->priv.server->areamaxs[0], ent->priv.server->areamaxs[1], ent->priv.server->areamaxs[2], PRVM_NUM_FOR_EDICT(ent), mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]);
223 world->areagrid_stats_entitychecks++;
231 void World_LinkEdict_AreaGrid(world_t *world, prvm_edict_t *ent)
234 int igrid[3], igridmins[3], igridmaxs[3], gridnum, entitynumber = PRVM_NUM_FOR_EDICT(ent);
236 if (entitynumber <= 0 || entitynumber >= prog->max_edicts || PRVM_EDICT_NUM(entitynumber) != ent)
238 Con_Printf ("SV_LinkEdict_AreaGrid: invalid edict %p (edicts is %p, edict compared to prog->edicts is %i)\n", (void *)ent, (void *)prog->edicts, entitynumber);
242 igridmins[0] = (int) floor((ent->priv.server->areamins[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]);
243 igridmins[1] = (int) floor((ent->priv.server->areamins[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]);
244 //igridmins[2] = (int) floor((ent->priv.server->areamins[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]);
245 igridmaxs[0] = (int) floor((ent->priv.server->areamaxs[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]) + 1;
246 igridmaxs[1] = (int) floor((ent->priv.server->areamaxs[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]) + 1;
247 //igridmaxs[2] = (int) floor((ent->priv.server->areamaxs[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]) + 1;
248 if (igridmins[0] < 0 || igridmaxs[0] > AREA_GRID || igridmins[1] < 0 || igridmaxs[1] > AREA_GRID || ((igridmaxs[0] - igridmins[0]) * (igridmaxs[1] - igridmins[1])) > ENTITYGRIDAREAS)
250 // wow, something outside the grid, store it as such
251 World_InsertLinkBefore (&ent->priv.server->areagrid[0], &world->areagrid_outside, entitynumber);
256 for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++)
258 grid = world->areagrid + igrid[1] * AREA_GRID + igridmins[0];
259 for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++, gridnum++)
260 World_InsertLinkBefore (&ent->priv.server->areagrid[gridnum], grid, entitynumber);
270 void World_LinkEdict(world_t *world, prvm_edict_t *ent, const vec3_t mins, const vec3_t maxs)
272 // unlink from old position first
273 if (ent->priv.server->areagrid[0].prev)
274 World_UnlinkEdict(ent);
276 // don't add the world
277 if (ent == prog->edicts)
280 // don't add free entities
281 if (ent->priv.server->free)
284 VectorCopy(mins, ent->priv.server->areamins);
285 VectorCopy(maxs, ent->priv.server->areamaxs);
286 World_LinkEdict_AreaGrid(world, ent);