doom 0.6.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +17 -0
- data/README.md +65 -4
- data/bin/doom +138 -25
- data/lib/doom/benchmark.rb +282 -0
- data/lib/doom/game/animations.rb +9 -2
- data/lib/doom/game/combat.rb +377 -105
- data/lib/doom/game/framebuffer_blitter.rb +38 -0
- data/lib/doom/game/geometry.rb +68 -0
- data/lib/doom/game/intermission.rb +231 -0
- data/lib/doom/game/item_pickup.rb +108 -60
- data/lib/doom/game/menu.rb +347 -0
- data/lib/doom/game/monster_ai.rb +304 -91
- data/lib/doom/game/player.rb +105 -0
- data/lib/doom/game/player_physics.rb +384 -0
- data/lib/doom/game/player_state.rb +47 -64
- data/lib/doom/game/random.rb +82 -0
- data/lib/doom/game/sector_actions.rb +466 -29
- data/lib/doom/game/sector_effects.rb +25 -18
- data/lib/doom/game/snapshot.rb +584 -0
- data/lib/doom/game/sound_engine.rb +176 -0
- data/lib/doom/game/state_hash.rb +125 -0
- data/lib/doom/game/ticcmd.rb +61 -0
- data/lib/doom/game/world.rb +420 -0
- data/lib/doom/map/data.rb +95 -0
- data/lib/doom/net/client.rb +204 -0
- data/lib/doom/net/desync_monitor.rb +101 -0
- data/lib/doom/net/game_server.rb +232 -0
- data/lib/doom/net/lockstep.rb +170 -0
- data/lib/doom/net/protocol.rb +350 -0
- data/lib/doom/net/session.rb +282 -0
- data/lib/doom/net/transport.rb +110 -0
- data/lib/doom/platform/gosu_window.rb +820 -640
- data/lib/doom/platform/sdl.rb +74 -0
- data/lib/doom/platform/window_logic.rb +61 -0
- data/lib/doom/render/font.rb +80 -0
- data/lib/doom/render/hardware_renderer.rb +547 -0
- data/lib/doom/render/ray_tracing/bvh.rb +103 -0
- data/lib/doom/render/ray_tracing/material_state.rb +66 -0
- data/lib/doom/render/ray_tracing/texture_atlas.rb +78 -0
- data/lib/doom/render/ray_tracing_renderer.rb +940 -0
- data/lib/doom/render/renderer.rb +684 -330
- data/lib/doom/render/renderer_factory.rb +50 -0
- data/lib/doom/render/screen_melt.rb +71 -0
- data/lib/doom/render/spinel_native/kernel.rb +780 -0
- data/lib/doom/render/spinel_native_renderer.rb +162 -0
- data/lib/doom/render/status_bar.rb +14 -10
- data/lib/doom/render/weapon_renderer.rb +15 -17
- data/lib/doom/render/world_mesh.rb +270 -0
- data/lib/doom/render/zbuffer_renderer.rb +151 -0
- data/lib/doom/version.rb +1 -1
- data/lib/doom/wad/flat.rb +1 -1
- data/lib/doom/wad/hud_graphics.rb +7 -3
- data/lib/doom/wad/palette.rb +3 -3
- data/lib/doom/wad/patch.rb +1 -1
- data/lib/doom/wad/reader.rb +59 -10
- data/lib/doom/wad/sound.rb +93 -0
- data/lib/doom/wad/sprite.rb +60 -34
- data/lib/doom/wad/texture.rb +5 -5
- data/lib/doom/wad_downloader.rb +38 -56
- data/lib/doom.rb +235 -12
- metadata +100 -7
|
@@ -0,0 +1,780 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Load the spinel_native gem. Prefer the local research checkout (it carries
|
|
4
|
+
# the native_prelude / native_state extensions this branch relies on) over any
|
|
5
|
+
# installed gem.
|
|
6
|
+
local_sn = File.expand_path("~/Projects/spin/spinel_native/lib")
|
|
7
|
+
$LOAD_PATH.unshift(local_sn) if File.directory?(local_sn) && !$LOAD_PATH.include?(local_sn)
|
|
8
|
+
require "spinel/native"
|
|
9
|
+
|
|
10
|
+
module Doom
|
|
11
|
+
module Render
|
|
12
|
+
module SpinelNative
|
|
13
|
+
# The classic renderer's hot path, ported to spinel_native. Each method
|
|
14
|
+
# mirrors a method of lib/doom/render/renderer.rb; the object graph is
|
|
15
|
+
# replaced by flat Integer/Float arrays kept as module state INSIDE the
|
|
16
|
+
# compiled kernel (native_state), exactly like renderer.rb keeps @map /
|
|
17
|
+
# @framebuffer / @ceiling_clip in ivars. `load_map` uploads the flattened
|
|
18
|
+
# map/textures once; `render` then draws a frame per call and returns the
|
|
19
|
+
# framebuffer -- no per-frame re-copy of the map across the boundary.
|
|
20
|
+
#
|
|
21
|
+
# Visplanes are filled inline (sn_flat_span / sn_sky_span) instead of being
|
|
22
|
+
# deferred through visplane objects -- the per-pixel sampling is identical,
|
|
23
|
+
# so the output matches the reference renderer.
|
|
24
|
+
#
|
|
25
|
+
# The whole module is one kernel (native_state), so every native method
|
|
26
|
+
# carries a signature. With SPINEL_NATIVE=off the same bodies run as plain
|
|
27
|
+
# Ruby against the module's own ivars, which is how the port is verified
|
|
28
|
+
# against renderer.rb before it is compiled.
|
|
29
|
+
module Kernel
|
|
30
|
+
extend Spinel::Native
|
|
31
|
+
|
|
32
|
+
PROJECTION = 160.0
|
|
33
|
+
SKY_XSCALE = 512.0 / Math::PI
|
|
34
|
+
SKY_YSCALE = 200.0 / 240.0
|
|
35
|
+
|
|
36
|
+
native_prelude <<~SRC
|
|
37
|
+
PROJECTION = 160.0
|
|
38
|
+
SKY_XSCALE = 512.0 / 3.14159265358979
|
|
39
|
+
SKY_YSCALE = 200.0 / 240.0
|
|
40
|
+
SRC
|
|
41
|
+
|
|
42
|
+
native_state do
|
|
43
|
+
@nodes = [0.0]; @verts = [0]; @segs = [0]; @subs = [0]
|
|
44
|
+
@lines = [0]; @sides = [0]; @secs = [0]
|
|
45
|
+
@wpx = [0]; @wtab = [0]; @fpx = [0]; @cmap = [0]
|
|
46
|
+
@fb = Array.new(76800, 0)
|
|
47
|
+
@cclip = Array.new(320, -1)
|
|
48
|
+
@fclip = Array.new(320, 240)
|
|
49
|
+
@wdepth = Array.new(320, 1.0e30)
|
|
50
|
+
@cdepth = Array.new(320, 1.0e30)
|
|
51
|
+
@fdepth = Array.new(320, 1.0e30)
|
|
52
|
+
@ccos = Array.new(320, 0.0)
|
|
53
|
+
@csin = Array.new(320, 0.0)
|
|
54
|
+
@cds = Array.new(320, 0.0)
|
|
55
|
+
@px = 0.0; @py = 0.0; @pz = 41.0; @ang = 0.0; @sina = 0.0; @cosa = 1.0
|
|
56
|
+
@ncount = 0; @skytex = 0
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# load_map/render are called from Ruby; the getters hand back the wall
|
|
60
|
+
# pass's clip rows so the game's sprite code (kept in Ruby) can occlude
|
|
61
|
+
# sprites against the walls. Everything else stays internal to the kernel.
|
|
62
|
+
native_entries :load_map, :render, :get_cclip, :get_fclip, :get_wdepth
|
|
63
|
+
|
|
64
|
+
# Final ceiling/floor clip rows and per-column nearest-wall depth after a
|
|
65
|
+
# render, for the Ruby sprite pass (@sprite_ceiling_clip etc.).
|
|
66
|
+
native "() -> Array[Integer]"
|
|
67
|
+
def get_cclip
|
|
68
|
+
out = Array.new(320, 0)
|
|
69
|
+
i = 0
|
|
70
|
+
while i < 320
|
|
71
|
+
out[i] = @cclip[i]
|
|
72
|
+
i += 1
|
|
73
|
+
end
|
|
74
|
+
out
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
native "() -> Array[Integer]"
|
|
78
|
+
def get_fclip
|
|
79
|
+
out = Array.new(320, 0)
|
|
80
|
+
i = 0
|
|
81
|
+
while i < 320
|
|
82
|
+
out[i] = @fclip[i]
|
|
83
|
+
i += 1
|
|
84
|
+
end
|
|
85
|
+
out
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
native "() -> Array[Float]"
|
|
89
|
+
def get_wdepth
|
|
90
|
+
out = Array.new(320, 0.0)
|
|
91
|
+
i = 0
|
|
92
|
+
while i < 320
|
|
93
|
+
out[i] = @wdepth[i]
|
|
94
|
+
i += 1
|
|
95
|
+
end
|
|
96
|
+
out
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# Upload the flattened map/textures once (kept in kernel state).
|
|
101
|
+
native "(Array[Float], Array[Integer], Array[Integer], Array[Integer], Array[Integer], " \
|
|
102
|
+
"Array[Integer], Array[Integer], Array[Integer], Array[Integer], Array[Integer], " \
|
|
103
|
+
"Array[Integer], Integer, Integer) -> Integer"
|
|
104
|
+
def load_map(nodes, verts, segs, subs, lines, sides, secs, wpx, wtab, fpx, cmap, ncount, skytex)
|
|
105
|
+
@nodes = nodes; @verts = verts; @segs = segs; @subs = subs
|
|
106
|
+
@lines = lines; @sides = sides; @secs = secs
|
|
107
|
+
@wpx = wpx; @wtab = wtab; @fpx = fpx; @cmap = cmap
|
|
108
|
+
@ncount = ncount; @skytex = skytex
|
|
109
|
+
@nodes.length
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Render one frame; returns the framebuffer (76800 palette indices).
|
|
113
|
+
native "(Integer, Integer, Integer, Float) -> Array[Integer]"
|
|
114
|
+
def render(px, py, pz, angle)
|
|
115
|
+
@px = px.to_f; @py = py.to_f; @pz = pz.to_f
|
|
116
|
+
@ang = angle
|
|
117
|
+
@sina = Math.sin(angle)
|
|
118
|
+
@cosa = Math.cos(angle)
|
|
119
|
+
i = 0
|
|
120
|
+
while i < 76800
|
|
121
|
+
@fb[i] = 0
|
|
122
|
+
i += 1
|
|
123
|
+
end
|
|
124
|
+
i = 0
|
|
125
|
+
while i < 320
|
|
126
|
+
@cclip[i] = -1
|
|
127
|
+
@fclip[i] = 240
|
|
128
|
+
@wdepth[i] = 1.0e30
|
|
129
|
+
i += 1
|
|
130
|
+
end
|
|
131
|
+
sn_precompute
|
|
132
|
+
sn_bsp(@ncount - 1)
|
|
133
|
+
# Return a locally-built copy with a concrete Array[Integer] type;
|
|
134
|
+
# spinel will not cross the boundary with an ivar of inferred (poly) type.
|
|
135
|
+
out = Array.new(76800, 0)
|
|
136
|
+
j = 0
|
|
137
|
+
while j < 76800
|
|
138
|
+
out[j] = @fb[j]
|
|
139
|
+
j += 1
|
|
140
|
+
end
|
|
141
|
+
out
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# mirrors precompute_column_data (+ column_distscale from setup)
|
|
145
|
+
native "() -> Integer"
|
|
146
|
+
def sn_precompute
|
|
147
|
+
x = 0
|
|
148
|
+
while x < 320
|
|
149
|
+
ca = @ang - Math.atan2((x - 160).to_f, PROJECTION)
|
|
150
|
+
@ccos[x] = Math.cos(ca)
|
|
151
|
+
@csin[x] = Math.sin(ca)
|
|
152
|
+
dxx = (x - 160).to_f
|
|
153
|
+
@cds[x] = Math.sqrt(dxx * dxx + PROJECTION * PROJECTION) / PROJECTION
|
|
154
|
+
x += 1
|
|
155
|
+
end
|
|
156
|
+
0
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# mirrors render_bsp_node (front-to-back), iterative with an explicit stack
|
|
160
|
+
native "(Integer) -> Integer"
|
|
161
|
+
def sn_bsp(root)
|
|
162
|
+
stack = Array.new(2048, 0)
|
|
163
|
+
sp = 0
|
|
164
|
+
stack[sp] = root
|
|
165
|
+
sp = sp + 1
|
|
166
|
+
while sp > 0
|
|
167
|
+
sp = sp - 1
|
|
168
|
+
ni = stack[sp]
|
|
169
|
+
if (ni & 0x8000) != 0
|
|
170
|
+
sn_subsector(ni & 0x7FFF)
|
|
171
|
+
else
|
|
172
|
+
b = ni * 6
|
|
173
|
+
dx = @px - @nodes[b]
|
|
174
|
+
dy = @py - @nodes[b + 1]
|
|
175
|
+
left_v = dy * @nodes[b + 2]
|
|
176
|
+
right_v = dx * @nodes[b + 3]
|
|
177
|
+
if right_v >= left_v
|
|
178
|
+
stack[sp] = @nodes[b + 5].to_i
|
|
179
|
+
sp = sp + 1
|
|
180
|
+
stack[sp] = @nodes[b + 4].to_i
|
|
181
|
+
sp = sp + 1
|
|
182
|
+
else
|
|
183
|
+
stack[sp] = @nodes[b + 4].to_i
|
|
184
|
+
sp = sp + 1
|
|
185
|
+
stack[sp] = @nodes[b + 5].to_i
|
|
186
|
+
sp = sp + 1
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
0
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# mirrors render_subsector
|
|
194
|
+
native "(Integer) -> Integer"
|
|
195
|
+
def sn_subsector(index)
|
|
196
|
+
first = @subs[index * 2]
|
|
197
|
+
count = @subs[index * 2 + 1]
|
|
198
|
+
i = 0
|
|
199
|
+
while i < count
|
|
200
|
+
sn_seg(first + i)
|
|
201
|
+
i += 1
|
|
202
|
+
end
|
|
203
|
+
0
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# mirrors render_seg: transform, near-clip, project, backface, dispatch
|
|
207
|
+
native "(Integer) -> Integer"
|
|
208
|
+
def sn_seg(seg_i)
|
|
209
|
+
v1i = @segs[seg_i * 5]
|
|
210
|
+
v2i = @segs[seg_i * 5 + 1]
|
|
211
|
+
dx1 = @verts[v1i * 2].to_f - @px
|
|
212
|
+
dy1 = @verts[v1i * 2 + 1].to_f - @py
|
|
213
|
+
x1 = dx1 * @sina - dy1 * @cosa
|
|
214
|
+
y1 = dx1 * @cosa + dy1 * @sina
|
|
215
|
+
dx2 = @verts[v2i * 2].to_f - @px
|
|
216
|
+
dy2 = @verts[v2i * 2 + 1].to_f - @py
|
|
217
|
+
x2 = dx2 * @sina - dy2 * @cosa
|
|
218
|
+
y2 = dx2 * @cosa + dy2 * @sina
|
|
219
|
+
|
|
220
|
+
if y1 <= 0.0 && y2 <= 0.0
|
|
221
|
+
return 0
|
|
222
|
+
end
|
|
223
|
+
near = 1.0
|
|
224
|
+
if y1 < near || y2 < near
|
|
225
|
+
if y1 < near && y2 < near
|
|
226
|
+
return 0
|
|
227
|
+
elsif y1 < near
|
|
228
|
+
t = (near - y1) / (y2 - y1)
|
|
229
|
+
x1 = x1 + t * (x2 - x1)
|
|
230
|
+
y1 = near
|
|
231
|
+
elsif y2 < near
|
|
232
|
+
t = (near - y1) / (y2 - y1)
|
|
233
|
+
x2 = x1 + t * (x2 - x1)
|
|
234
|
+
y2 = near
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
sx1 = 160.0 + x1 * PROJECTION / y1
|
|
239
|
+
sx2 = 160.0 + x2 * PROJECTION / y2
|
|
240
|
+
if sx1 >= sx2
|
|
241
|
+
return 0
|
|
242
|
+
end
|
|
243
|
+
if sx2 < 0.0 || sx1 >= 320.0
|
|
244
|
+
return 0
|
|
245
|
+
end
|
|
246
|
+
x1i = sx1.to_i
|
|
247
|
+
if x1i < 0
|
|
248
|
+
x1i = 0
|
|
249
|
+
end
|
|
250
|
+
x2i = sx2.to_i
|
|
251
|
+
if x2i > 319
|
|
252
|
+
x2i = 319
|
|
253
|
+
end
|
|
254
|
+
if x1i > x2i
|
|
255
|
+
return 0
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
ldi = @segs[seg_i * 5 + 2]
|
|
259
|
+
dir = @segs[seg_i * 5 + 3]
|
|
260
|
+
sd_idx = dir == 0 ? @lines[ldi * 3] : @lines[ldi * 3 + 1]
|
|
261
|
+
if sd_idx < 0
|
|
262
|
+
return 0
|
|
263
|
+
end
|
|
264
|
+
fsec = @sides[sd_idx * 6]
|
|
265
|
+
flags = @lines[ldi * 3 + 2]
|
|
266
|
+
back_sd = -1
|
|
267
|
+
if (flags & 4) != 0
|
|
268
|
+
bsi = dir == 0 ? @lines[ldi * 3 + 1] : @lines[ldi * 3]
|
|
269
|
+
if bsi >= 0
|
|
270
|
+
back_sd = bsi
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
segdx = (@verts[v2i * 2] - @verts[v1i * 2]).to_f
|
|
275
|
+
segdy = (@verts[v2i * 2 + 1] - @verts[v1i * 2 + 1]).to_f
|
|
276
|
+
seg_len = Math.sqrt(segdx * segdx + segdy * segdy)
|
|
277
|
+
|
|
278
|
+
sn_seg_range(x1i, x2i, sx1, sx2, y1, y2, fsec, back_sd, sd_idx, flags, seg_i, seg_len)
|
|
279
|
+
0
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# mirrors draw_seg_range (texture-column coefficients, per-column loop)
|
|
283
|
+
native "(Integer, Integer, Float, Float, Float, Float, Integer, Integer, Integer, Integer, Integer, Float) -> Integer"
|
|
284
|
+
def sn_seg_range(x1, x2, sx1, sx2, dist1, dist2, fsec, back_sd, sd_idx, flags, seg_i, seg_len)
|
|
285
|
+
v1i = @segs[seg_i * 5]
|
|
286
|
+
v2i = @segs[seg_i * 5 + 1]
|
|
287
|
+
segdx = (@verts[v2i * 2] - @verts[v1i * 2]).to_f
|
|
288
|
+
segdy = (@verts[v2i * 2 + 1] - @verts[v1i * 2 + 1]).to_f
|
|
289
|
+
pxr = @px - @verts[v1i * 2].to_f
|
|
290
|
+
pyr = @py - @verts[v1i * 2 + 1].to_f
|
|
291
|
+
sin_a = @sina
|
|
292
|
+
cos_a = @cosa
|
|
293
|
+
c1 = cos_a * PROJECTION - sin_a * 160.0
|
|
294
|
+
c2 = sin_a * PROJECTION + cos_a * 160.0
|
|
295
|
+
tex_a = segdy * sin_a + segdx * cos_a
|
|
296
|
+
tex_b = segdy * c1 - segdx * c2
|
|
297
|
+
tex_e = pyr * sin_a + pxr * cos_a
|
|
298
|
+
tex_f = pyr * c1 - pxr * c2
|
|
299
|
+
tex_offset = @segs[seg_i * 5 + 4] + @sides[sd_idx * 6 + 4]
|
|
300
|
+
|
|
301
|
+
f_floor = @secs[fsec * 7]
|
|
302
|
+
f_ceil = @secs[fsec * 7 + 1]
|
|
303
|
+
f_csky = @secs[fsec * 7 + 5]
|
|
304
|
+
has_ceil = 0
|
|
305
|
+
if f_ceil.to_f > @pz
|
|
306
|
+
has_ceil = 1
|
|
307
|
+
end
|
|
308
|
+
if f_csky != 0
|
|
309
|
+
has_ceil = 1
|
|
310
|
+
end
|
|
311
|
+
has_floor = 0
|
|
312
|
+
if f_floor.to_f < @pz
|
|
313
|
+
has_floor = 1
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
x = x1
|
|
317
|
+
while x <= x2
|
|
318
|
+
if @cclip[x] < @fclip[x] - 1
|
|
319
|
+
t = 0.0
|
|
320
|
+
if sx2 != sx1
|
|
321
|
+
t = (x.to_f - sx1) / (sx2 - sx1)
|
|
322
|
+
end
|
|
323
|
+
if t < 0.0
|
|
324
|
+
t = 0.0
|
|
325
|
+
end
|
|
326
|
+
if t > 1.0
|
|
327
|
+
t = 1.0
|
|
328
|
+
end
|
|
329
|
+
dist = dist1
|
|
330
|
+
if dist1 > 0.0 && dist2 > 0.0
|
|
331
|
+
inv = (1.0 - t) / dist1 + t / dist2
|
|
332
|
+
dist = 1.0 / inv
|
|
333
|
+
else
|
|
334
|
+
if dist1 > 0.0
|
|
335
|
+
dist = dist1
|
|
336
|
+
else
|
|
337
|
+
dist = dist2
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
denom = tex_a * x.to_f + tex_b
|
|
341
|
+
ss = 0.0
|
|
342
|
+
da = denom
|
|
343
|
+
if da < 0.0
|
|
344
|
+
da = -da
|
|
345
|
+
end
|
|
346
|
+
if da >= 0.001
|
|
347
|
+
ss = (tex_e * x.to_f + tex_f) / denom
|
|
348
|
+
end
|
|
349
|
+
tex_col = (tex_offset.to_f + ss * seg_len).to_i
|
|
350
|
+
if dist >= 1.0
|
|
351
|
+
scale = PROJECTION / dist
|
|
352
|
+
front_floor = f_floor.to_f - @pz
|
|
353
|
+
front_ceil = f_ceil.to_f - @pz
|
|
354
|
+
fcf = 120.0 - front_ceil * scale
|
|
355
|
+
front_ceil_y = fcf.to_i
|
|
356
|
+
if fcf > front_ceil_y.to_f
|
|
357
|
+
front_ceil_y = front_ceil_y + 1
|
|
358
|
+
end
|
|
359
|
+
front_floor_y = (120.0 - front_floor * scale).to_i
|
|
360
|
+
ceil_y = front_ceil_y
|
|
361
|
+
if @cclip[x] + 1 > ceil_y
|
|
362
|
+
ceil_y = @cclip[x] + 1
|
|
363
|
+
end
|
|
364
|
+
floor_y = front_floor_y
|
|
365
|
+
if @fclip[x] - 1 < floor_y
|
|
366
|
+
floor_y = @fclip[x] - 1
|
|
367
|
+
end
|
|
368
|
+
if back_sd >= 0
|
|
369
|
+
sn_two_sided(x, ceil_y, floor_y, scale, dist, tex_col, fsec, back_sd, sd_idx, flags, has_ceil, has_floor)
|
|
370
|
+
else
|
|
371
|
+
sn_one_sided(x, ceil_y, floor_y, scale, dist, tex_col, fsec, sd_idx, flags, has_ceil, has_floor)
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
x += 1
|
|
376
|
+
end
|
|
377
|
+
0
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# mirrors draw_one_sided_seg_column
|
|
381
|
+
native "(Integer, Integer, Integer, Float, Float, Integer, Integer, Integer, Integer, Integer, Integer) -> Integer"
|
|
382
|
+
def sn_one_sided(x, ceil_y, floor_y, scale, dist, tex_col, fsec, sd_idx, flags, has_ceil, has_floor)
|
|
383
|
+
f_floor = @secs[fsec * 7]
|
|
384
|
+
f_ceil = @secs[fsec * 7 + 1]
|
|
385
|
+
f_light = @secs[fsec * 7 + 2]
|
|
386
|
+
f_ff = @secs[fsec * 7 + 3]
|
|
387
|
+
f_cf = @secs[fsec * 7 + 4]
|
|
388
|
+
f_csky = @secs[fsec * 7 + 5]
|
|
389
|
+
f_fsky = @secs[fsec * 7 + 6]
|
|
390
|
+
|
|
391
|
+
if has_ceil != 0
|
|
392
|
+
mt = @cclip[x] + 1
|
|
393
|
+
mb = ceil_y - 1
|
|
394
|
+
if @fclip[x] - 1 < mb
|
|
395
|
+
mb = @fclip[x] - 1
|
|
396
|
+
end
|
|
397
|
+
if mt <= mb
|
|
398
|
+
if f_csky != 0
|
|
399
|
+
sn_sky_span(x, mt, mb)
|
|
400
|
+
else
|
|
401
|
+
sn_flat_span(x, mt, mb, f_ceil, f_light, f_cf)
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
if has_floor != 0
|
|
407
|
+
mt = floor_y + 1
|
|
408
|
+
if @cclip[x] + 1 > mt
|
|
409
|
+
mt = @cclip[x] + 1
|
|
410
|
+
end
|
|
411
|
+
mb = @fclip[x] - 1
|
|
412
|
+
if mt <= mb
|
|
413
|
+
if f_fsky != 0
|
|
414
|
+
sn_sky_span(x, mt, mb)
|
|
415
|
+
else
|
|
416
|
+
sn_flat_span(x, mt, mb, f_floor, f_light, f_ff)
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
mid = @sides[sd_idx * 6 + 3]
|
|
422
|
+
yoff = @sides[sd_idx * 6 + 5]
|
|
423
|
+
if (flags & 16) != 0
|
|
424
|
+
th = 128
|
|
425
|
+
if mid >= 0
|
|
426
|
+
th = @wtab[mid * 3 + 2]
|
|
427
|
+
end
|
|
428
|
+
mid_tex_y = yoff + th - (f_ceil - f_floor)
|
|
429
|
+
else
|
|
430
|
+
mid_tex_y = yoff
|
|
431
|
+
end
|
|
432
|
+
sn_wall_column(x, ceil_y, floor_y, mid, dist, f_light, tex_col, mid_tex_y, scale, f_ceil.to_f)
|
|
433
|
+
|
|
434
|
+
if dist < @wdepth[x]
|
|
435
|
+
@wdepth[x] = dist
|
|
436
|
+
end
|
|
437
|
+
@cclip[x] = 240
|
|
438
|
+
@fclip[x] = -1
|
|
439
|
+
0
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# mirrors draw_two_sided_seg_column
|
|
443
|
+
native "(Integer, Integer, Integer, Float, Float, Integer, Integer, Integer, Integer, Integer, Integer, Integer) -> Integer"
|
|
444
|
+
def sn_two_sided(x, ceil_y, floor_y, scale, dist, tex_col, fsec, back_sd, sd_idx, flags, has_ceil, has_floor)
|
|
445
|
+
f_floor = @secs[fsec * 7]
|
|
446
|
+
f_ceil = @secs[fsec * 7 + 1]
|
|
447
|
+
f_light = @secs[fsec * 7 + 2]
|
|
448
|
+
f_ff = @secs[fsec * 7 + 3]
|
|
449
|
+
f_cf = @secs[fsec * 7 + 4]
|
|
450
|
+
f_csky = @secs[fsec * 7 + 5]
|
|
451
|
+
f_fsky = @secs[fsec * 7 + 6]
|
|
452
|
+
bsec = @sides[back_sd * 6]
|
|
453
|
+
b_floor = @secs[bsec * 7]
|
|
454
|
+
b_ceil = @secs[bsec * 7 + 1]
|
|
455
|
+
b_light = @secs[bsec * 7 + 2]
|
|
456
|
+
b_ff = @secs[bsec * 7 + 3]
|
|
457
|
+
b_cf = @secs[bsec * 7 + 4]
|
|
458
|
+
b_csky = @secs[bsec * 7 + 5]
|
|
459
|
+
|
|
460
|
+
back_floor = b_floor.to_f - @pz
|
|
461
|
+
back_ceil = b_ceil.to_f - @pz
|
|
462
|
+
back_ceil_y = (120.0 - back_ceil * scale).to_i
|
|
463
|
+
bfy = 120.0 - back_floor * scale
|
|
464
|
+
back_floor_y = bfy.to_i
|
|
465
|
+
if bfy > back_floor_y.to_f
|
|
466
|
+
back_floor_y = back_floor_y + 1
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
closed_door = 0
|
|
470
|
+
if b_ceil <= f_floor
|
|
471
|
+
closed_door = 1
|
|
472
|
+
end
|
|
473
|
+
if b_floor >= f_ceil
|
|
474
|
+
closed_door = 1
|
|
475
|
+
end
|
|
476
|
+
both_sky = 0
|
|
477
|
+
if f_csky != 0 && b_csky != 0
|
|
478
|
+
both_sky = 1
|
|
479
|
+
end
|
|
480
|
+
eff_front_ceil = f_ceil
|
|
481
|
+
if both_sky != 0
|
|
482
|
+
eff_front_ceil = b_ceil
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
should_mark_ceiling = 0
|
|
486
|
+
should_mark_floor = 0
|
|
487
|
+
if closed_door != 0
|
|
488
|
+
should_mark_ceiling = 1
|
|
489
|
+
should_mark_floor = 1
|
|
490
|
+
else
|
|
491
|
+
if eff_front_ceil != b_ceil
|
|
492
|
+
should_mark_ceiling = 1
|
|
493
|
+
end
|
|
494
|
+
if f_cf != b_cf
|
|
495
|
+
should_mark_ceiling = 1
|
|
496
|
+
end
|
|
497
|
+
if f_light != b_light
|
|
498
|
+
should_mark_ceiling = 1
|
|
499
|
+
end
|
|
500
|
+
if f_floor != b_floor
|
|
501
|
+
should_mark_floor = 1
|
|
502
|
+
end
|
|
503
|
+
if f_ff != b_ff
|
|
504
|
+
should_mark_floor = 1
|
|
505
|
+
end
|
|
506
|
+
if f_light != b_light
|
|
507
|
+
should_mark_floor = 1
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
if has_ceil != 0 && should_mark_ceiling != 0
|
|
512
|
+
mt = @cclip[x] + 1
|
|
513
|
+
mb = ceil_y - 1
|
|
514
|
+
if @fclip[x] - 1 < mb
|
|
515
|
+
mb = @fclip[x] - 1
|
|
516
|
+
end
|
|
517
|
+
if mt <= mb
|
|
518
|
+
if f_csky != 0
|
|
519
|
+
sn_sky_span(x, mt, mb)
|
|
520
|
+
else
|
|
521
|
+
sn_flat_span(x, mt, mb, f_ceil, f_light, f_cf)
|
|
522
|
+
end
|
|
523
|
+
end
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
if has_floor != 0 && should_mark_floor != 0
|
|
527
|
+
mt = floor_y + 1
|
|
528
|
+
mb = @fclip[x] - 1
|
|
529
|
+
if @cclip[x] + 1 > mt
|
|
530
|
+
mt = @cclip[x] + 1
|
|
531
|
+
end
|
|
532
|
+
if mt <= mb
|
|
533
|
+
if f_fsky != 0
|
|
534
|
+
sn_sky_span(x, mt, mb)
|
|
535
|
+
else
|
|
536
|
+
sn_flat_span(x, mt, mb, f_floor, f_light, f_ff)
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
if both_sky == 0 && f_ceil > b_ceil
|
|
542
|
+
upper = @sides[sd_idx * 6 + 1]
|
|
543
|
+
yoff = @sides[sd_idx * 6 + 5]
|
|
544
|
+
if (flags & 8) != 0
|
|
545
|
+
upper_tex_y = yoff
|
|
546
|
+
else
|
|
547
|
+
th = 128
|
|
548
|
+
if upper >= 0
|
|
549
|
+
th = @wtab[upper * 3 + 2]
|
|
550
|
+
end
|
|
551
|
+
upper_tex_y = yoff + b_ceil - f_ceil + th
|
|
552
|
+
end
|
|
553
|
+
sn_wall_column(x, ceil_y, back_ceil_y, upper, dist, f_light, tex_col, upper_tex_y, scale, f_ceil.to_f)
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
if f_floor < b_floor
|
|
557
|
+
lower = @sides[sd_idx * 6 + 2]
|
|
558
|
+
yoff = @sides[sd_idx * 6 + 5]
|
|
559
|
+
if (flags & 16) != 0
|
|
560
|
+
lower_tex_y = yoff + f_ceil - b_floor
|
|
561
|
+
else
|
|
562
|
+
lower_tex_y = yoff
|
|
563
|
+
end
|
|
564
|
+
sn_wall_column(x, back_floor_y, floor_y, lower, dist, f_light, tex_col, lower_tex_y, scale, b_floor.to_f)
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
if closed_door != 0
|
|
568
|
+
if dist < @wdepth[x]
|
|
569
|
+
@wdepth[x] = dist
|
|
570
|
+
end
|
|
571
|
+
@cclip[x] = 240
|
|
572
|
+
@fclip[x] = -1
|
|
573
|
+
else
|
|
574
|
+
if eff_front_ceil > b_ceil
|
|
575
|
+
if back_ceil_y > @cclip[x]
|
|
576
|
+
@cclip[x] = back_ceil_y
|
|
577
|
+
end
|
|
578
|
+
elsif eff_front_ceil < b_ceil
|
|
579
|
+
if ceil_y - 1 > @cclip[x]
|
|
580
|
+
@cclip[x] = ceil_y - 1
|
|
581
|
+
end
|
|
582
|
+
else
|
|
583
|
+
if f_cf != b_cf || f_light != b_light
|
|
584
|
+
if ceil_y - 1 > @cclip[x]
|
|
585
|
+
@cclip[x] = ceil_y - 1
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
if f_floor < b_floor
|
|
590
|
+
if back_floor_y < @fclip[x]
|
|
591
|
+
@fclip[x] = back_floor_y
|
|
592
|
+
end
|
|
593
|
+
elsif f_floor > b_floor
|
|
594
|
+
if floor_y + 1 < @fclip[x]
|
|
595
|
+
@fclip[x] = floor_y + 1
|
|
596
|
+
end
|
|
597
|
+
else
|
|
598
|
+
if f_ff != b_ff || f_light != b_light
|
|
599
|
+
if floor_y + 1 < @fclip[x]
|
|
600
|
+
@fclip[x] = floor_y + 1
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
0
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
# mirrors draw_wall_column_ex (top-pegged texel walk, transparent skip)
|
|
609
|
+
native "(Integer, Integer, Integer, Integer, Float, Integer, Integer, Integer, Float, Float) -> Integer"
|
|
610
|
+
def sn_wall_column(x, y1, y2, tex, dist, light, tex_col, tex_y_start, scale, world_top)
|
|
611
|
+
if y1 > y2
|
|
612
|
+
return 0
|
|
613
|
+
end
|
|
614
|
+
if tex < 0
|
|
615
|
+
return 0
|
|
616
|
+
end
|
|
617
|
+
clip_top = @cclip[x] + 1
|
|
618
|
+
clip_bot = @fclip[x] - 1
|
|
619
|
+
if y1 < clip_top
|
|
620
|
+
y1 = clip_top
|
|
621
|
+
end
|
|
622
|
+
if y2 > clip_bot
|
|
623
|
+
y2 = clip_bot
|
|
624
|
+
end
|
|
625
|
+
if y1 > y2
|
|
626
|
+
return 0
|
|
627
|
+
end
|
|
628
|
+
base = @wtab[tex * 3]
|
|
629
|
+
tw = @wtab[tex * 3 + 1]
|
|
630
|
+
th = @wtab[tex * 3 + 2]
|
|
631
|
+
wlnum = light >> 4
|
|
632
|
+
if wlnum > 15
|
|
633
|
+
wlnum = 15
|
|
634
|
+
end
|
|
635
|
+
if wlnum < 0
|
|
636
|
+
wlnum = 0
|
|
637
|
+
end
|
|
638
|
+
wstart = (15 - wlnum) * 4
|
|
639
|
+
wsi = 47
|
|
640
|
+
if dist > 0.0
|
|
641
|
+
wsi = (2560.0 / dist).to_i
|
|
642
|
+
end
|
|
643
|
+
if wsi > 47
|
|
644
|
+
wsi = 47
|
|
645
|
+
end
|
|
646
|
+
if wsi < 0
|
|
647
|
+
wsi = 0
|
|
648
|
+
end
|
|
649
|
+
lvl = wstart - wsi / 2
|
|
650
|
+
if lvl < 0
|
|
651
|
+
lvl = 0
|
|
652
|
+
end
|
|
653
|
+
if lvl > 31
|
|
654
|
+
lvl = 31
|
|
655
|
+
end
|
|
656
|
+
tex_x = tex_col % tw
|
|
657
|
+
if tex_x < 0
|
|
658
|
+
tex_x = tex_x + tw
|
|
659
|
+
end
|
|
660
|
+
tex_step = 1.0 / scale
|
|
661
|
+
unclipped_y1 = 120.0 - (world_top - @pz) * scale
|
|
662
|
+
tex_y_at_y1 = tex_y_start.to_f + (y1.to_f - unclipped_y1) * tex_step
|
|
663
|
+
y = y1
|
|
664
|
+
while y <= y2
|
|
665
|
+
off = y - y1
|
|
666
|
+
ty = (tex_y_at_y1 + off.to_f * tex_step).to_i % th
|
|
667
|
+
if ty < 0
|
|
668
|
+
ty = ty + th
|
|
669
|
+
end
|
|
670
|
+
c = @wpx[base + tex_x * th + ty]
|
|
671
|
+
if c >= 0
|
|
672
|
+
@fb[y * 320 + x] = @cmap[lvl * 256 + c]
|
|
673
|
+
end
|
|
674
|
+
y += 1
|
|
675
|
+
end
|
|
676
|
+
0
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
# mirrors draw_span's per-pixel flat sampling, done per column inline
|
|
680
|
+
native "(Integer, Integer, Integer, Integer, Integer, Integer) -> Integer"
|
|
681
|
+
def sn_flat_span(x, y1, y2, plane_h, light, flat_idx)
|
|
682
|
+
if y1 > y2
|
|
683
|
+
return 0
|
|
684
|
+
end
|
|
685
|
+
ph = plane_h.to_f - @pz
|
|
686
|
+
if ph < 0.0
|
|
687
|
+
ph = -ph
|
|
688
|
+
end
|
|
689
|
+
if ph == 0.0
|
|
690
|
+
return 0
|
|
691
|
+
end
|
|
692
|
+
lnum = light >> 4
|
|
693
|
+
if lnum > 15
|
|
694
|
+
lnum = 15
|
|
695
|
+
end
|
|
696
|
+
if lnum < 0
|
|
697
|
+
lnum = 0
|
|
698
|
+
end
|
|
699
|
+
startmap = (15 - lnum) * 4
|
|
700
|
+
fbase = flat_idx * 4096
|
|
701
|
+
y = y1
|
|
702
|
+
if y < 0
|
|
703
|
+
y = 0
|
|
704
|
+
end
|
|
705
|
+
yy2 = y2
|
|
706
|
+
if yy2 > 239
|
|
707
|
+
yy2 = 239
|
|
708
|
+
end
|
|
709
|
+
while y <= yy2
|
|
710
|
+
dy = y - 120
|
|
711
|
+
if dy != 0
|
|
712
|
+
absdy = dy
|
|
713
|
+
if absdy < 0
|
|
714
|
+
absdy = -absdy
|
|
715
|
+
end
|
|
716
|
+
perp = ph * PROJECTION / absdy.to_f
|
|
717
|
+
rd = perp * @cds[x]
|
|
718
|
+
tx = (@px + rd * @ccos[x]).to_i & 63
|
|
719
|
+
ty = (0.0 - @py - rd * @csin[x]).to_i & 63
|
|
720
|
+
zc = (perp / 16.0).to_i
|
|
721
|
+
if zc > 127
|
|
722
|
+
zc = 127
|
|
723
|
+
end
|
|
724
|
+
if zc < 0
|
|
725
|
+
zc = 0
|
|
726
|
+
end
|
|
727
|
+
lvl = (startmap.to_f - 10.0 / (zc + 1).to_f).to_i
|
|
728
|
+
if lvl < 0
|
|
729
|
+
lvl = 0
|
|
730
|
+
end
|
|
731
|
+
if lvl > 31
|
|
732
|
+
lvl = 31
|
|
733
|
+
end
|
|
734
|
+
@fb[y * 320 + x] = @cmap[lvl * 256 + @fpx[fbase + ty * 64 + tx]]
|
|
735
|
+
end
|
|
736
|
+
y += 1
|
|
737
|
+
end
|
|
738
|
+
0
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
# mirrors draw_sky_plane's per-column sky sampling (full bright)
|
|
742
|
+
native "(Integer, Integer, Integer) -> Integer"
|
|
743
|
+
def sn_sky_span(x, y1, y2)
|
|
744
|
+
if y1 > y2
|
|
745
|
+
return 0
|
|
746
|
+
end
|
|
747
|
+
off = @wtab[@skytex * 3]
|
|
748
|
+
sw = @wtab[@skytex * 3 + 1]
|
|
749
|
+
sh = @wtab[@skytex * 3 + 2]
|
|
750
|
+
ca = @ang - Math.atan2((x - 160).to_f, PROJECTION)
|
|
751
|
+
sx = (ca * SKY_XSCALE).to_i % sw
|
|
752
|
+
if sx < 0
|
|
753
|
+
sx = sx + sw
|
|
754
|
+
end
|
|
755
|
+
y = y1
|
|
756
|
+
if y < 0
|
|
757
|
+
y = 0
|
|
758
|
+
end
|
|
759
|
+
yy2 = y2
|
|
760
|
+
if yy2 > 239
|
|
761
|
+
yy2 = 239
|
|
762
|
+
end
|
|
763
|
+
while y <= yy2
|
|
764
|
+
ty = (100.0 + (y - 120).to_f * SKY_YSCALE).to_i % sh
|
|
765
|
+
if ty < 0
|
|
766
|
+
ty = ty + sh
|
|
767
|
+
end
|
|
768
|
+
c = @wpx[off + sx * sh + ty]
|
|
769
|
+
if c >= 0
|
|
770
|
+
@fb[y * 320 + x] = c
|
|
771
|
+
end
|
|
772
|
+
y += 1
|
|
773
|
+
end
|
|
774
|
+
0
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
end
|
|
780
|
+
end
|