Index: renderer/r_entity.c =================================================================== --- renderer/r_entity.c (revision 16404) +++ renderer/r_entity.c (working copy) @@ -184,6 +184,52 @@ } /** + * @brief Draws a marker on the ground to indicate pathing CL_AddTargeting + * @sa CL_AddPathing + * @sa RF_BOX + */ +static void R_DrawFloor (const entity_t * e) +{ + vec3_t upper, lower; + float dx; + const vec4_t color = {e->angles[0], e->angles[1], e->angles[2], e->alpha}; + + qglDisable(GL_TEXTURE_2D); + /* + if (!r_wire->integer) + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + */ + qglEnable(GL_LINE_SMOOTH); + + R_Color(color); + + VectorCopy(e->origin, lower); + VectorCopy(e->origin, upper); + + dx = PLAYER_WIDTH * 2; + upper[1] += PLAYER_WIDTH * 2; + + qglBegin(GL_QUAD_STRIP); + qglVertex3fv(lower); + qglVertex3fv(upper); + lower[0] += dx; + upper[0] += dx; + qglVertex3fv(lower); + qglVertex3fv(upper); + qglEnd(); + + qglDisable(GL_LINE_SMOOTH); + /* + if (!r_wire->integer) + qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + */ + + qglEnable(GL_TEXTURE_2D); + + R_Color(NULL); +} + +/** * @brief Draws shadow and highlight effects for the entities (actors) * @note The origins are already transformed */ @@ -302,6 +348,8 @@ while (e) { if (e->flags & RF_BOX) { R_DrawBox(e); + } else if (e->flags & RF_PATH) { + R_DrawFloor(e); } else { switch (e->model->type) { case mod_alias_dpm: @@ -505,7 +553,7 @@ R_CalcTransform(e); if (!e->model) { - if (e->flags & RF_BOX) + if (e->flags & RF_BOX || e->flags & RF_PATH) chain = &r_alpha_mesh_entities; else chain = &r_null_entities; Index: shared/shared.h =================================================================== --- shared/shared.h (revision 16404) +++ shared/shared.h (working copy) @@ -224,4 +224,6 @@ #define MAX_TOKEN_CHARS 256 /* max length of an individual token */ +#define DIST_EPSILON (0.03125) + #endif Index: game/q_shared.h =================================================================== --- game/q_shared.h (revision 16404) +++ game/q_shared.h (working copy) @@ -283,6 +283,8 @@ /** entity->flags (render flags) */ #define RF_TRANSLUCENT 0x00000001 #define RF_BOX 0x00000002 /**< actor selection box */ +#define RF_PATH 0x01000000 /**< pathing marker, debugging only */ + /** the following ent flags also draw entity effects */ #define RF_SHADOW 0x00000004 /**< shadow (when living) for this entity */ #define RF_BLOOD 0x00000008 /**< blood (when dead) for this entity */ Index: client/cl_actor.c =================================================================== --- client/cl_actor.c (revision 16404) +++ client/cl_actor.c (working copy) @@ -5066,7 +5066,66 @@ } } +static const vec3_t boxShift = { PLAYER_WIDTH, PLAYER_WIDTH, UNIT_HEIGHT / 2 - 1 }; + /** + * @brief create a targeting box at the given position + * @sa CL_ParseClientinfo + */ +static void CL_AddPathingBox (pos3_t pos) +{ + entity_t ent; + + memset(&ent, 0, sizeof(entity_t)); + ent.flags = RF_PATH; + + Grid_PosToVec(&clMap, pos, ent.origin); + VectorSubtract(ent.origin, boxShift, ent.origin); + + /** + * Paint the box green if it is reachable, + * yellow if it can be entered but is too far, + * or red if it cannot be entered ever. + */ + if (Grid_Fall(&clMap, pos, 1) < pos[2] - 1) { + VectorSet(ent.angles, 0, 0, 0); /* Can't enter - black */ + } else { + /** + * Can reach - green + * Passable but unreachable - yellow + * Not passable - red + */ + const int TUs = Grid_MoveLength(&clMap, pos, qfalse); + VectorSet(ent.angles, (TUs > CL_UsableTUs(selActor)), (TUs != ROUTING_NOT_REACHABLE), 0); + } + + ent.alpha = 0.25; + + /* add it */ + R_AddEntity(&ent); +} + +/** + * @brief Adds a pathing marker to the current floor when we render the world. + * @sa V_RenderView + * Draws the tracer (red, yellow, green box) on the grid + */ +void CL_AddPathing (void) +{ + pos3_t pos, mins, maxs; + + VecToPos(map_min, mins); + VecToPos(map_max, maxs); + + pos[2] = cl_worldlevel->integer; + for (pos[1] = max(mousePos[1] - 8, 0); pos[1] <= min(mousePos[1] + 8, PATHFINDING_WIDTH - 1); pos[1]++) + for (pos[0] = max(mousePos[0] - 8, 0); pos[0] <= min(mousePos[0] + 8, PATHFINDING_WIDTH - 1); pos[0]++) + CL_AddPathingBox(pos); +} + + + +/** * @brief Plays various sounds on actor action. * @param[in] category * @param[in] gender Index: client/cl_view.c =================================================================== --- client/cl_view.c (revision 16404) +++ client/cl_view.c (working copy) @@ -332,6 +332,7 @@ refdef.worldlevel = cl_worldlevel->integer; } + /** * @sa SCR_UpdateScreen */ @@ -368,6 +369,9 @@ LM_AddToScene(); /* add local entities to the renderer chain */ LE_AddToScene(); + /* adds pathing data */ + if (developer->integer & DEBUG_CLIENT) + CL_AddPathing(); /* adds target cursor */ CL_AddTargeting(); break; Index: client/cl_actor.h =================================================================== --- client/cl_actor.h (revision 16404) +++ client/cl_actor.h (working copy) @@ -132,6 +132,7 @@ qboolean CL_AddUGV(le_t * le, entity_t * ent); void CL_AddTargeting(void); +void CL_AddPathing(void); void CL_ActorTargetAlign_f(void); void CL_ActorInventoryOpen_f(void);