Class: Quake::Camera

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

Constant Summary collapse

SPEED =

units per second (Quake run speed)

320.0
SENSITIVITY =

degrees per pixel

0.15
MAX_MOUSE_DELTA =

clamp insane deltas (e.g. first frame warp)

50

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(position: Math::Vec3::ORIGIN, yaw: 0.0, pitch: 0.0, fov: 90.0, near: 4.0, far: 6144.0) ⇒ Camera

Returns a new instance of Camera.



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

def initialize(position: Math::Vec3::ORIGIN, yaw: 0.0, pitch: 0.0,
               fov: 90.0, near: 4.0, far: 6144.0)
  @position = position
  @yaw = yaw
  @pitch = pitch
  @roll = 0.0
  @fov = fov
  @near = near
  @far = far
  @ignore_mouse = 2  # skip first N motion events (SDL warp artifacts)
end

Instance Attribute Details

#farObject (readonly)

Returns the value of attribute far.



9
10
11
# File 'lib/quake/camera.rb', line 9

def far
  @far
end

#fovObject (readonly)

Returns the value of attribute fov.



9
10
11
# File 'lib/quake/camera.rb', line 9

def fov
  @fov
end

#nearObject (readonly)

Returns the value of attribute near.



9
10
11
# File 'lib/quake/camera.rb', line 9

def near
  @near
end

#pitchObject

Returns the value of attribute pitch.



8
9
10
# File 'lib/quake/camera.rb', line 8

def pitch
  @pitch
end

#positionObject

Returns the value of attribute position.



8
9
10
# File 'lib/quake/camera.rb', line 8

def position
  @position
end

#rollObject

Returns the value of attribute roll.



8
9
10
# File 'lib/quake/camera.rb', line 8

def roll
  @roll
end

#yawObject

Returns the value of attribute yaw.



8
9
10
# File 'lib/quake/camera.rb', line 8

def yaw
  @yaw
end

Instance Method Details

#apply_glObject



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/quake/camera.rb', line 101

def apply_gl
  GL.MatrixMode(GL::MODELVIEW)
  GL.LoadIdentity

  # Quake coords (X-forward, Y-left, Z-up) -> GL coords (X-right, Y-up, Z-backward)
  # Rotate -90 around X to convert Z-up to Y-up
  # Rotate 90 around Z to convert X-forward to -Z-backward
  GL.Rotatef(-90.0, 1.0, 0.0, 0.0)  # Z-up -> Y-up
  GL.Rotatef(90.0, 0.0, 0.0, 1.0)   # X-forward -> GL

  GL.Rotatef(-@roll, 1.0, 0.0, 0.0)
  GL.Rotatef(-@pitch, 0.0, 1.0, 0.0)
  GL.Rotatef(-@yaw, 0.0, 0.0, 1.0)
  GL.Translatef(-@position.x, -@position.y, -@position.z)
end

#apply_projection_gl(aspect) ⇒ Object



63
64
65
66
67
# File 'lib/quake/camera.rb', line 63

def apply_projection_gl(aspect)
  GL.MatrixMode(GL::PROJECTION)
  GL.LoadIdentity
  GLU.Perspective(fov_y(aspect), aspect, @near, @far)
end

#forwardObject



27
28
29
# File 'lib/quake/camera.rb', line 27

def forward
  quake_angle_vectors.fetch(:forward)
end

#fov_x(aspect) ⇒ Object

Actual horizontal FOV for a given aspect (follows from fov_y)



78
79
80
# File 'lib/quake/camera.rb', line 78

def fov_x(aspect)
  2.0 * ::Math.atan(::Math.tan(deg2rad(fov_y) / 2.0) * aspect) * 180.0 / ::Math::PI
end

#fov_y(_aspect = nil) ⇒ Object

Quake's fov cvar is the horizontal FOV on a 4:3 screen. Like Quakespasm's fov_adapt (Hor+), the vertical FOV stays at its 4:3 value on wide screens and the horizontal FOV widens instead -- otherwise widescreen crops the view and the weapon model.



73
74
75
# File 'lib/quake/camera.rb', line 73

def fov_y(_aspect = nil)
  2.0 * ::Math.atan(::Math.tan(deg2rad(@fov) / 2.0) * 0.75) * 180.0 / ::Math::PI
end

#frustum_planes(aspect) ⇒ Object

R_SetFrustum: 4 view-frustum planes as [normal, dist] pairs, where a point is inside when normal.dot(point) - dist >= 0.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/quake/camera.rb', line 84

def frustum_planes(aspect)
  vecs = quake_angle_vectors
  forward = vecs.fetch(:forward)
  right = vecs.fetch(:right)
  up = vecs.fetch(:up)

  fx = fov_x(aspect)
  fy = fov_y
  normals = [
    rotate_around_axis(forward, up, -(90.0 - fx / 2.0)),
    rotate_around_axis(forward, up, 90.0 - fx / 2.0),
    rotate_around_axis(forward, right, 90.0 - fy / 2.0),
    rotate_around_axis(forward, right, -(90.0 - fy / 2.0))
  ]
  normals.map { |normal| [normal, normal.dot(@position)] }
end

#move_forward(dt) ⇒ Object



39
40
41
# File 'lib/quake/camera.rb', line 39

def move_forward(dt)
  @position = @position + forward * (SPEED * dt)
end

#move_right(dt) ⇒ Object



43
44
45
# File 'lib/quake/camera.rb', line 43

def move_right(dt)
  @position = @position + right * (SPEED * dt)
end

#move_up(dt) ⇒ Object



47
48
49
# File 'lib/quake/camera.rb', line 47

def move_up(dt)
  @position = @position + up * (SPEED * dt)
end

#rightObject



31
32
33
# File 'lib/quake/camera.rb', line 31

def right
  quake_angle_vectors.fetch(:right)
end

#rotate(dx, dy) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
# File 'lib/quake/camera.rb', line 51

def rotate(dx, dy)
  if @ignore_mouse > 0
    @ignore_mouse -= 1
    return
  end
  dx = dx.clamp(-MAX_MOUSE_DELTA, MAX_MOUSE_DELTA)
  dy = dy.clamp(-MAX_MOUSE_DELTA, MAX_MOUSE_DELTA)
  @yaw -= dx * SENSITIVITY
  @pitch += dy * SENSITIVITY
  @pitch = @pitch.clamp(-89.0, 89.0)
end

#upObject



35
36
37
# File 'lib/quake/camera.rb', line 35

def up
  quake_angle_vectors.fetch(:up)
end