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



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(-1..1)
    @y[i] = -15 if @y[i] < -15
    @y[i] = 0 if @y[i] > 0
  end
end

Instance Method Details

#done?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