-
Notifications
You must be signed in to change notification settings - Fork 3
/
notes
199 lines (161 loc) · 7.02 KB
/
notes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
----------------------------------------------------------
Doom!
Start at top of BSP, traverse in nearest-first order (always to end)
- draw things in BSP node, (subsector: optional)
- traverse "front" (side the camera is on)
- maybe traverse "back" (if bbox visible)
Drawing a subsector:
- determine floor and ceiling height , set planes up (these will be added to during draw seg)
- add all sprites inside this subsector
- for each line, R_AddLine
Drawing a line:
- seems to use angles? hmm (divide and tan-table lookup per pt)
- clipangle = half fieldofview angle
- TODO: work out what all the tspan stuff is doing
- Backface cull, clip left and right edge
- determine x range on screen (discard if small)
- uses tables to map view-relative angles to x positions
- either clip wall segment (for steps/ceiling) or clip solid (for end walls)
ClipSolid:
- keeps track of "solidsegs": linked list of solid areas, initialised to
<---] [---> solid either side of screen.
- no need to track "Z"; if something is "solid" we saw it in nearest-to-camera-first
order thanks to BSP traversal
- clips [left, right] against solid areas, updates and inserts solid blocks, and calls
R_StoreWallRange to note what to draw.
Clip_not_solid: TODO
R_StoreWallRange:
- lots of state in "curline" global...
- ds_p is freshly allocated drawseg
- calculates rw_distance:
- calculates "hyp" - dist to first point from viewpoint (via r_PointToDist())
- distangle = 90 - abs(curline->angle + 90 - rw_angle1) (TODO: draw and work out)
- rw_angle1 is the angle to the first point from view as latched in R_DrawLine
- rw_distance = hyp * sin(distangle)
- seems to be "parallel distance to line" but needs geometry check
- calcs scale1 (rw_scale) as R_ScaleFromGlobalAngle(viewAng + xToView[start])
- that is, get the actual angle to the clipped start position
- R_ScaleFromGA returns "texture mapping scale for current line" at the given angle
- TODO: work out geometry here (r_main.c)
- calcs scale2 similarly (for end)
- works out "top" and "bottom" - sector's ceiling and floor adjusted for view height
- for single-sided lines (i.e. fully opaque walls):
- fills in various flags, sprite clip arrays, bsilheight and tsilheight
- for double-sided lines
- LOTS of code. TODO
- if needs texturing
- rw_offset = hyp * sin(rw_normalangle-rw+angle1)
- rw_offset += side->textofset + curline->offset
- some lighting simple calc (walllights = something)
- init topstep/topfrac & bottomstep/bottomfrac:
- rw_scalestep * world{top,bottom} ; centrerfrac - world{top, bottom} * rw_scale
- set ceiling & floor planes with R_CheckPlane
- call R_RenderSegLoop()
- save some silhouette info for sprites
R_RenderSegLoop:
- ends up calling colfunc() which is dynamically R_DrawColumn or R_DrawColumnLow (vs detailshift - latter doubles up pixels)
R_DrawColumn:
- actual ASM (though not in the linux version)
- super simple lookup to get y addr (avoiding multiply) then DDA *foo = map[*bar]; foo += screenw; bar += step;
----------------------------------------------------------
* Wolf3d
* Ray casting
* like ray tracing, but one ray per pixel column
* map stored as an array of 64*64 tiles
* basic overview of process
* fisheye
* now practicalities of doing it on 286
* 16-bit integer math only, no divides.
finetangents=tan(X) and 1/tan(X) backwards from FINEANGLES/8
the 1/tan(X) used for 'opposite side' step
spotvis = is this place visible from plyer?
self modifying code (search cs: in WL_DR_A.ASM)
--process
determine quadrant
initialize xtilestep and ytilestep (+/-1 trivially from quadrant)
initialize xstep and ystep
compute via tan(X) and 1/tan(X) as appropriate
again from quadrant and +/i lookuptable and 1/lookup
read xpartialup and ypartialdown into xpartial and ypartial?
*partial is "how far is it to the next unit" line, accounting for direction
patch code in hot loop for jge/jle based on xtilestep and ytilestep
initvars:
yintercept = xpartialbyystep() + viewy // ystep * xpartial (a fraction, 0.0 - 0.999 between tile)
xtile = focaltx + xtilestep
xspot = (xtile << 6) + yinttile [top bits of yintercept] ; left in si
xintercept = ypartialbyxstep() + viewx
(cx = top bits of x intercept)
ytile = focalty+ytilestep
yspot = (xinttile<<6) + ytile
CORE LOOP!
; AX : scratch
; BX : xtile
; CX : high word of xintercept (aka xinttile)
; DX : high word of yintercept (aka yinttile)
; SI : xspot (yinttile<<6)+xtile (index into tilemap and spotvis)
; DI : yspot (xinttile<<6)+ytile (index into tilemap and spotvis)
; BP : ytile
; ES : screenseg
vert:
if (high(yintercept) <= ytile) goto horiz;
if (tilemap[xspot]) goto hitvert;
mark this spot visible
xtile += xtilestep
yintercept += ystep
xspot = (xtile<<6)+yinttline
goto vert;
hitvert:
tilehit = tilemap[xpot]
handle door vs not door...
call HitVertWall if wall
else...special dor handling
horiz:
if (high(xintercept) <= xtile) goto vert;
as above, but s/x/y
[TODO] then HitHorizWall etc
-> checks 'texture' (seemingly the U coord) and optimizes (maybe incorrect?) after calling CalcHeight() U coord = (intercept>>4) & 0xfc0
ScalePost draws 1, 2 and 3 byte "strips". VGA masks let us write to 4 planes at once. Tables sort out which bytes get written to which planes.
height shared amongst several pixels; bespoke scalers built. walls all 64-pixels high
CalcHeight:
gxt = viewcos * (xintercept - viewx)
gyt = viewsin * (yintercept - viewy)
nx = max(mindist, gxt-gyt)
return heightnumerator / nx;
implies xintercept/yintercept are the location of the hit
d' = sqrt(dx*dx+dy*dy)
d = d' cos (hitAngle - theta)
a'd cos x-y = d' ( cosxcosy + sinx siny )
= d' ( cos(hitAngle) * cos(theta)
+ sin(hitAngle) * sin(theta) )
= d' cos(HitAngle) * cos(theta)
+ d sin(hitAngle) * sin(theta)
dx = d' cos hitAngle
dy = d' sin hitAngle
= dx * cos(theta) + dy * sin(theta)
EXCEPT IT'S BLOODY minus in the wofl code
Needs to be drawn out with full theta to e certain. Suspect it's a thingy where y is upside down or something
ahh... viewx = player->x - focal * cos
viewy = player->x + focal * sin (wtf!)
-> implies "sin" is "wrong sign" (or cos)
--> means dy * sin(theta) should be -dy * sin(theta)
OK 0 is [-1,0], 45deg is [-0.7, 0.7] etc:
viewx/viewy is actually player MINUS a short distance...
so...for projectiles etc moving "forward"
-- 0 is [1,0], 45 deg is [0.7, -0.7] so anticlockwise
.....
with Z = ???
p = d sin (Z - theta)
sin(a-b) = sin(a)cos(b) - cos(a)sin(b)
p = d [ sin(Z)cos(theta) - cos(Z)sin(theta) ]
now to prove d sin(Z) = dx
d cos(Z) = dy ?
and to work out what Z is??!
alternatively
p = d cos (L + theta)
p = d [ cos(L)cos(theta) - sin(L)sin(theta) ]
then to prove
d cos(L) = dx
d sin(L) = dy
---------
all nonsense!! :)
dy is "upside down". I've been drawing dy as being from bottom to top; but of course it's the other way around!!! that means dy above should be -dy! HOORAY