Class: Quake::Renderer::GLWater

Inherits:
Object
  • Object
show all
Defined in:
lib/quake/renderer/gl_water.rb

Overview

Renders turbulent water/lava/slime surfaces with sine-wave warping. Quake liquid textures have names starting with ‘*’.

Constant Summary collapse

TURBSCALE =

~40.74

256.0 / (2.0 * ::Math::PI)
SUBDIVIDE_SIZE =
64.0

Instance Method Summary collapse

Constructor Details

#initialize(level, texture_manager) ⇒ GLWater

Returns a new instance of GLWater.



14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/quake/renderer/gl_water.rb', line 14

def initialize(level, texture_manager)
  @level = level
  @texture_manager = texture_manager
  @water_surfaces = []
  @time = 0.0

  # Precompute 256-entry sine table matching Quake's turbsin
  @turbsin = Array.new(256) do |i|
    (::Math.sin(i * 2.0 * ::Math::PI / 256.0) * 8.0)
  end

  precompute_water_surfaces
end

Instance Method Details

#render(alpha: 1.0) ⇒ Object

Render water surfaces with turbulent sine-wave warp. alpha: 1.0 = fully opaque (GLQuake default r_wateralpha).

Values < 1.0 enable semi-transparent water.


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
# File 'lib/quake/renderer/gl_water.rb', line 35

def render(alpha: 1.0)
  return if @water_surfaces.empty?

  GL.Enable(GL::TEXTURE_2D)
  # Quake BSP stores liquid surfaces as front/back face pairs on the
  # same plane so the surface is visible from above and below. Without
  # culling both copies rasterize at the same depth, z-fight, and (with
  # alpha < 1) double-blend, producing flicker. Match TyrQuake:
  # glCullFace(GL_FRONT) with default CCW front face.
  GL.Enable(GL::CULL_FACE)
  GL.CullFace(GL::FRONT)

  if alpha < 1.0
    GL.Enable(GL::BLEND)
    GL.BlendFunc(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA)
    GL.TexEnvi(GL::TEXTURE_ENV, GL::TEXTURE_ENV_MODE, GL::MODULATE)
    GL.Color4f(1.0, 1.0, 1.0, alpha)
  else
    GL.TexEnvi(GL::TEXTURE_ENV, GL::TEXTURE_ENV_MODE, GL::REPLACE)
  end

  @water_surfaces.each do |ws|
    @texture_manager.bind(ws[:miptex_index])

    ws[:faces].each do |face_data|
      GL.Begin(GL::TRIANGLE_FAN)
      face_data[:verts].each_with_index do |v, i|
        os, ot = face_data[:texcoords][i]

        # Cross-modulated sine warp
        s = os + @turbsin[((ot * 0.125 + @time) * TURBSCALE).to_i & 255]
        s /= 64.0

        t = ot + @turbsin[((os * 0.125 + @time) * TURBSCALE).to_i & 255]
        t /= 64.0

        GL.TexCoord2f(s, t)
        GL.Vertex3f(v.x, v.y, v.z)
      end
      GL.End
    end
  end

  GL.Disable(GL::CULL_FACE)

  if alpha < 1.0
    GL.Disable(GL::BLEND)
    GL.Color4f(1.0, 1.0, 1.0, 1.0)
  end
  GL.TexEnvi(GL::TEXTURE_ENV, GL::TEXTURE_ENV_MODE, GL::MODULATE)
end

#update(dt) ⇒ Object



28
29
30
# File 'lib/quake/renderer/gl_water.rb', line 28

def update(dt)
  @time += dt
end