Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
298 serge 1
// Emacs style mode select   -*- C++ -*-
2
//-----------------------------------------------------------------------------
3
//
4
// $Id:$
5
//
6
// Copyright (C) 1993-1996 by id Software, Inc.
7
//
8
// This source is available for distribution and/or modification
9
// only under the terms of the DOOM Source Code License as
10
// published by id Software. All rights reserved.
11
//
12
// The source is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15
// for more details.
16
//
17
// $Log:$
18
//
19
// DESCRIPTION:
20
//	LineOfSight/Visibility checks, uses REJECT Lookup Table.
21
//
22
//-----------------------------------------------------------------------------
23
 
24
static const char
25
rcsid[] = "$Id: p_sight.c,v 1.3 1997/01/28 22:08:28 b1 Exp $";
26
 
27
 
28
#include "doomdef.h"
29
 
30
#include "i_system.h"
31
#include "p_local.h"
32
 
33
// State.
34
#include "r_state.h"
35
 
36
//
37
// P_CheckSight
38
//
39
fixed_t		sightzstart;		// eye z of looker
40
fixed_t		topslope;
41
fixed_t		bottomslope;		// slopes to top and bottom of target
42
 
43
divline_t	strace;			// from t1 to t2
44
fixed_t		t2x;
45
fixed_t		t2y;
46
 
47
int		sightcounts[2];
48
 
49
 
50
//
51
// P_DivlineSide
52
// Returns side 0 (front), 1 (back), or 2 (on).
53
//
54
int
55
P_DivlineSide
56
( fixed_t	x,
57
  fixed_t	y,
58
  divline_t*	node )
59
{
60
    fixed_t	dx;
61
    fixed_t	dy;
62
    fixed_t	left;
63
    fixed_t	right;
64
 
65
    if (!node->dx)
66
    {
67
	if (x==node->x)
68
	    return 2;
69
 
70
	if (x <= node->x)
71
	    return node->dy > 0;
72
 
73
	return node->dy < 0;
74
    }
75
 
76
    if (!node->dy)
77
    {
78
	if (x==node->y)
79
	    return 2;
80
 
81
	if (y <= node->y)
82
	    return node->dx < 0;
83
 
84
	return node->dx > 0;
85
    }
86
 
87
    dx = (x - node->x);
88
    dy = (y - node->y);
89
 
90
    left =  (node->dy>>FRACBITS) * (dx>>FRACBITS);
91
    right = (dy>>FRACBITS) * (node->dx>>FRACBITS);
92
 
93
    if (right < left)
94
	return 0;	// front side
95
 
96
    if (left == right)
97
	return 2;
98
    return 1;		// back side
99
}
100
 
101
 
102
//
103
// P_InterceptVector2
104
// Returns the fractional intercept point
105
// along the first divline.
106
// This is only called by the addthings and addlines traversers.
107
//
108
fixed_t
109
P_InterceptVector2
110
( divline_t*	v2,
111
  divline_t*	v1 )
112
{
113
    fixed_t	frac;
114
    fixed_t	num;
115
    fixed_t	den;
116
 
117
    den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy);
118
 
119
    if (den == 0)
120
	return 0;
121
    //	I_Error ("P_InterceptVector: parallel");
122
 
123
    num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy) +
124
	FixedMul ( (v2->y - v1->y)>>8 , v1->dx);
125
    frac = FixedDiv (num , den);
126
 
127
    return frac;
128
}
129
 
130
//
131
// P_CrossSubsector
132
// Returns true
133
//  if strace crosses the given subsector successfully.
134
//
135
boolean P_CrossSubsector (int num)
136
{
137
    seg_t*		seg;
138
    line_t*		line;
139
    int			s1;
140
    int			s2;
141
    int			count;
142
    subsector_t*	sub;
143
    sector_t*		front;
144
    sector_t*		back;
145
    fixed_t		opentop;
146
    fixed_t		openbottom;
147
    divline_t		divl;
148
    vertex_t*		v1;
149
    vertex_t*		v2;
150
    fixed_t		frac;
151
    fixed_t		slope;
152
 
153
#ifdef RANGECHECK
154
    if (num>=numsubsectors)
155
	I_Error ("P_CrossSubsector: ss %i with numss = %i",
156
		 num,
157
		 numsubsectors);
158
#endif
159
 
160
    sub = &subsectors[num];
161
 
162
    // check lines
163
    count = sub->numlines;
164
    seg = &segs[sub->firstline];
165
 
166
    for ( ; count ; seg++, count--)
167
    {
168
	line = seg->linedef;
169
 
170
	// allready checked other side?
171
	if (line->validcount == validcount)
172
	    continue;
173
 
174
	line->validcount = validcount;
175
 
176
	v1 = line->v1;
177
	v2 = line->v2;
178
	s1 = P_DivlineSide (v1->x,v1->y, &strace);
179
	s2 = P_DivlineSide (v2->x, v2->y, &strace);
180
 
181
	// line isn't crossed?
182
	if (s1 == s2)
183
	    continue;
184
 
185
	divl.x = v1->x;
186
	divl.y = v1->y;
187
	divl.dx = v2->x - v1->x;
188
	divl.dy = v2->y - v1->y;
189
	s1 = P_DivlineSide (strace.x, strace.y, &divl);
190
	s2 = P_DivlineSide (t2x, t2y, &divl);
191
 
192
	// line isn't crossed?
193
	if (s1 == s2)
194
	    continue;
195
 
196
	// stop because it is not two sided anyway
197
	// might do this after updating validcount?
198
	if ( !(line->flags & ML_TWOSIDED) )
199
	    return false;
200
 
201
	// crosses a two sided line
202
	front = seg->frontsector;
203
	back = seg->backsector;
204
 
205
	// no wall to block sight with?
206
	if (front->floorheight == back->floorheight
207
	    && front->ceilingheight == back->ceilingheight)
208
	    continue;
209
 
210
	// possible occluder
211
	// because of ceiling height differences
212
	if (front->ceilingheight < back->ceilingheight)
213
	    opentop = front->ceilingheight;
214
	else
215
	    opentop = back->ceilingheight;
216
 
217
	// because of ceiling height differences
218
	if (front->floorheight > back->floorheight)
219
	    openbottom = front->floorheight;
220
	else
221
	    openbottom = back->floorheight;
222
 
223
	// quick test for totally closed doors
224
	if (openbottom >= opentop)
225
	    return false;		// stop
226
 
227
	frac = P_InterceptVector2 (&strace, &divl);
228
 
229
	if (front->floorheight != back->floorheight)
230
	{
231
	    slope = FixedDiv (openbottom - sightzstart , frac);
232
	    if (slope > bottomslope)
233
		bottomslope = slope;
234
	}
235
 
236
	if (front->ceilingheight != back->ceilingheight)
237
	{
238
	    slope = FixedDiv (opentop - sightzstart , frac);
239
	    if (slope < topslope)
240
		topslope = slope;
241
	}
242
 
243
	if (topslope <= bottomslope)
244
	    return false;		// stop
245
    }
246
    // passed the subsector ok
247
    return true;
248
}
249
 
250
 
251
 
252
//
253
// P_CrossBSPNode
254
// Returns true
255
//  if strace crosses the given node successfully.
256
//
257
boolean P_CrossBSPNode (int bspnum)
258
{
259
    node_t*	bsp;
260
    int		side;
261
 
262
    if (bspnum & NF_SUBSECTOR)
263
    {
264
	if (bspnum == -1)
265
	    return P_CrossSubsector (0);
266
	else
267
	    return P_CrossSubsector (bspnum&(~NF_SUBSECTOR));
268
    }
269
 
270
    bsp = &nodes[bspnum];
271
 
272
    // decide which side the start point is on
273
    side = P_DivlineSide (strace.x, strace.y, (divline_t *)bsp);
274
    if (side == 2)
275
	side = 0;	// an "on" should cross both sides
276
 
277
    // cross the starting side
278
    if (!P_CrossBSPNode (bsp->children[side]) )
279
	return false;
280
 
281
    // the partition plane is crossed here
282
    if (side == P_DivlineSide (t2x, t2y,(divline_t *)bsp))
283
    {
284
	// the line doesn't touch the other side
285
	return true;
286
    }
287
 
288
    // cross the ending side
289
    return P_CrossBSPNode (bsp->children[side^1]);
290
}
291
 
292
 
293
//
294
// P_CheckSight
295
// Returns true
296
//  if a straight line between t1 and t2 is unobstructed.
297
// Uses REJECT.
298
//
299
boolean
300
P_CheckSight
301
( mobj_t*	t1,
302
  mobj_t*	t2 )
303
{
304
    int		s1;
305
    int		s2;
306
    int		pnum;
307
    int		bytenum;
308
    int		bitnum;
309
 
310
    // First check for trivial rejection.
311
 
312
    // Determine subsector entries in REJECT table.
313
    s1 = (t1->subsector->sector - sectors);
314
    s2 = (t2->subsector->sector - sectors);
315
    pnum = s1*numsectors + s2;
316
    bytenum = pnum>>3;
317
    bitnum = 1 << (pnum&7);
318
 
319
    // Check in REJECT table.
320
    if (rejectmatrix[bytenum]&bitnum)
321
    {
322
	sightcounts[0]++;
323
 
324
	// can't possibly be connected
325
	return false;
326
    }
327
 
328
    // An unobstructed LOS is possible.
329
    // Now look from eyes of t1 to any part of t2.
330
    sightcounts[1]++;
331
 
332
    validcount++;
333
 
334
    sightzstart = t1->z + t1->height - (t1->height>>2);
335
    topslope = (t2->z+t2->height) - sightzstart;
336
    bottomslope = (t2->z) - sightzstart;
337
 
338
    strace.x = t1->x;
339
    strace.y = t1->y;
340
    t2x = t2->x;
341
    t2y = t2->y;
342
    strace.dx = t2->x - t1->x;
343
    strace.dy = t2->y - t1->y;
344
 
345
    // the head node is the last node output
346
    return P_CrossBSPNode (numnodes-1);
347
}
348