Class: Doom::Render::ScreenMelt

Inherits:
Object
  • Object
show all
Defined in:
lib/doom/render/screen_melt.rb

Overview

DOOM’s screen melt/wipe effect from wipe.c. Each column slides down at a slightly different speed, revealing the new screen underneath.

Constant Summary collapse

WIDTH =
SCREEN_WIDTH
HEIGHT =
SCREEN_HEIGHT
MELT_SPEED =

~8 pixels per frame (Chocolate Doom does HEIGHT/15 at 35fps)

HEIGHT / 30

Instance Method Summary collapse

Constructor Details

#initialize(old_screen, new_screen) ⇒ ScreenMelt

Returns a new instance of ScreenMelt.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/doom/render/screen_melt.rb', line 13

def initialize(old_screen, new_screen)
  # Snapshot both screens (arrays of palette indices, 320x240)
  @old = old_screen.dup
  @new = new_screen.dup
  @done = false

  # Initialize column offsets (from wipe_initMelt in wipe.c)
  # Column 0 gets random negative offset, each subsequent column
  # varies by -1/0/+1 from previous, creating a jagged melt line
  @y = Array.new(WIDTH)
  @y[0] = -(rand(16))
  (1...WIDTH).each do |i|
    @y[i] = @y[i - 1] + (rand(3) - 1)
    @y[i] = -15 if @y[i] < -15
    @y[i] = 0 if @y[i] > 0
  end
end

Instance Method Details

#done?Boolean

Returns:

  • (Boolean)


31
32
33
# File 'lib/doom/render/screen_melt.rb', line 31

def done?
  @done
end

#update(framebuffer) ⇒ Object

Advance one tic. Returns the composited framebuffer.



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
# File 'lib/doom/render/screen_melt.rb', line 36

def update(framebuffer)
  all_done = true

  WIDTH.times do |x|
    if @y[x] < 0
      @y[x] += 1
      all_done = false
      # Column hasn't started melting yet - show old screen
      HEIGHT.times { |row| framebuffer[row * WIDTH + x] = @old[row * WIDTH + x] }
    elsif @y[x] < HEIGHT
      all_done = false
      dy = @y[x]

      # Top part: new screen revealed
      dy.times do |row|
        framebuffer[row * WIDTH + x] = @new[row * WIDTH + x]
      end

      # Bottom part: old screen shifted down
      (dy...HEIGHT).each do |row|
        src_row = row - dy
        framebuffer[row * WIDTH + x] = @old[src_row * WIDTH + x]
      end

      @y[x] += MELT_SPEED
    else
      # Column fully melted - show new screen
      HEIGHT.times { |row| framebuffer[row * WIDTH + x] = @new[row * WIDTH + x] }
    end
  end

  @done = all_done
end