Skip to content

Instantly share code, notes, and snippets.

@amirrajan
Last active August 2, 2019 05:20
Show Gist options
  • Save amirrajan/3cbfb5275420846019da8bdb0e60f1d3 to your computer and use it in GitHub Desktop.
Save amirrajan/3cbfb5275420846019da8bdb0e60f1d3 to your computer and use it in GitHub Desktop.
dragonruby gtk faux 3D
def cos v
Math.cos v
end
def flr n
n.floor
end
def sin v
Math.sin v
end
def sqrt v
Math.sqrt v
end
class Game
def tick args
defaults args
init args
update args
draw args
end
def defaults args
args.state.cube ||= [
[[ -1, -1, 1 ],
[ 1, -1, 1 ],
[ -1, 1, 1 ]],
[[ 1, -1, 1 ],
[ 1, 1, 1 ],
[ -1, 1, 1 ]],
[[ -1, -1, -1 ],
[ -1, -1, 1 ],
[ -1, 1, -1 ]],
[[ -1, -1, 1 ],
[ -1, 1, 1 ],
[ -1, 1, -1 ]],
[[ 1, -1, 1 ],
[ 1, -1, -1 ],
[ 1, 1, 1 ]],
[[ 1, 1, 1 ],
[ 1, -1, -1 ],
[ 1, 1, -1 ]],
[[ -1, -1, -1 ],
[ -1, 1, -1 ],
[ 1, -1, -1 ]],
[[ 1, -1, -1 ],
[ -1, 1, -1 ],
[ 1, 1, -1 ]],
[[ -1, -1, 1 ],
[ -1, -1, -1 ],
[ 1, -1, -1 ]],
[[ 1, -1, -1 ],
[ 1, -1, 1 ],
[ -1, -1, 1 ]],
[[ -1, 1, 1 ],
[ 1, 1, -1 ],
[ -1, 1, -1 ]],
[[ 1, 1, -1 ],
[ -1, 1, 1 ],
[ 1, 1, 1 ]],
]
args.state.shapes ||= []
args.state.camera ||= args.state.new_entity_strict(:camera) do |c|
c.pos = [ 0, 0, 20 ]
c.dir = [ 1, 1, 1 ]
end
args.state.scale = 200
args.state.pitch ||= 0
args.state.yaw ||= 0
end
def init args
return if args.state.tick_count != 0
create_shape(args, args.state.cube, [ 0, 0, 0 ])
create_shape(args, args.state.cube, [ 10, 10, 0 ])
create_shape(args, args.state.cube, [ -10, 10, 0 ])
create_shape(args, args.state.cube, [ -10, -10, 0 ])
create_shape(args, args.state.cube, [ 10, -10, 0 ])
end
def update args
fps args, args.state.camera.pos, args.state.pitch, args.state.yaw
args.borders << args.grid.rect
move_camera(args, -0.1) if args.keyboard.key_held.j
move_camera(args, 0.1) if args.keyboard.key_held.k
args.state.pitch += 0.005 if args.keyboard.key_held.one
args.state.pitch -= 0.005 if args.keyboard.key_held.two
args.state.yaw -= 0.005 if args.keyboard.key_held.four
args.state.yaw += 0.005 if args.keyboard.key_held.five
args.state.camera.pos[0] -= 0.1 if args.keyboard.key_held.left
args.state.camera.pos[0] += 0.1 if args.keyboard.key_held.right
args.state.camera.pos[1] -= 0.1 if args.keyboard.key_held.up
args.state.camera.pos[1] += 0.1 if args.keyboard.key_held.down
args.state.camera.pos[2] -= 0.1 if args.keyboard.key_held.equal_sign
args.state.camera.pos[2] += 0.1 if args.keyboard.key_held.hyphen
for shape in args.state.shapes do
rotate_shape(shape, :x, 0.01)
rotate_shape(shape, :y, 0.01)
rotate_shape(shape, :z, 0.01)
rotate_shape(shape, :x, 0.01, [-1, 0, 0])
rotate_shape(shape, :y, 0.01, [-1, 0, 0])
rotate_shape(shape, :z, 0.01, [-1, 0, 0])
end
end
def draw args
args.state.shapes.each do |shape|
shape.triangles.each do |t|
args.lines << triangle_lines(args, [
add_vec(t[0], shape.pos),
add_vec(t[1], shape.pos),
add_vec(t[2], shape.pos),
])
end
end
end
def create_shape args, shape, pos
ns = args.state.new_entity_strict(:shape) do |s|
s.pos = pos
s.triangles = []
end
for tri in shape
nt = []
for i in 0..2
nt << [tri[i][0],tri[i][1],tri[i][2]]
end
ns.triangles << nt
end
args.state.shapes << ns
end
def move_camera args, d
dir = [
args.state.camera.dir[0],
args.state.camera.dir[1],
args.state.camera.dir[2]
]
pdir = args.state.camera.dir
rotate_point(dir, :x, args.state.pitch)
rotate_point(dir, :y, args.state.yaw)
dir = mul_vec(normalize(dir), d)
args.state.camera.pos = add_vec(args.state.camera.pos, dir)
args.state.camera.dir = pdir
end
def triangle_lines args, t
t1, t2, t3 = mul_view(args, t[0]), mul_view(args, t[1]), mul_view(args, t[2])
x1, y1 = project(args, t1)
x2, y2 = project(args, t2)
x3, y3 = project(args, t3)
[
[x1, y1, x2, y2],
[x2, y2, x3, y3],
[x3, y3, x1, y1],
].reject do |l|
l.x > 3000 ||
l.x2 > 3000 ||
l.y > 3000 ||
l.y2 > 3000
end
end
def project args, p
x = if p[2].abs <= 0.1
0
else
-args.state.scale * (p[0]) / (p[2])
end
y = if p[2].abs <= 0.1
0
else
-args.state.scale * (p[1]) / (p[2])
end
[x ,y]
end
def fps args, camera, pitch, yaw
cosp, sinp, cosy, siny = cos(pitch), sin(pitch), cos(yaw), sin(yaw)
x,y,z = [cosy, 0, -siny], [siny * sinp, cosp, cosy * sinp], [siny * cosp, -sinp, cosp * cosy]
args.state.viewmatrix = [ [ x[0], y[0], z[0], 0 ],
[ x[1], y[1], z[1], 0 ],
[ x[2], y[2], z[2], 0 ],
[ -dot_product(x, camera), -dot_product(y, camera), -dot_product(z, camera), 1 ] ]
end
def mul_view args, v
vm = args.state.viewmatrix
[
v[0] * vm[0][0] + v[1] * vm[1][0] + v[2] * vm[2][0] + vm[3][0],
v[0] * vm[0][1] + v[1] * vm[1][1] + v[2] * vm[2][1] + vm[3][1],
v[0] * vm[0][2] + v[1] * vm[1][2] + v[2] * vm[2][2] + vm[3][2],
v[0] * vm[0][3] + v[1] * vm[1][3] + v[2] * vm[2][3] + vm[3][3],
]
end
def length_vec(v)
sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2])
end
def normalize(v)
l = length_vec(v)
l == 0 && [ 0, 0, 0 ] || [ v[0] / l, v[1] / l, v[2] / l ]
end
def add_vec(v1, v2)
[ v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2] ]
end
def sub_vec(v1, v2)
[ v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2] ]
end
def mul_vec(v, a)
[ v[0] * a, v[1] * a,v[2] * a ]
end
def dot_product(v1, v2)
v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
end
def cross_product v1, v2
[ v1[1] * v2[2] - v1[2] * v2[1],
v1[2] * v2[0] - v1[0] * v2[2],
v1[0] * v2[1] - v1[1] * v2[0] ]
end
def rotate_shape s, a, r, offset = nil
for t in s.triangles
for p in 0..2
rotate_point(t[p], a, r, offset && sub_vec(offset, s.pos))
end
end
end
def rotate_point p, a, r, offset = nil
if offset
p[0] -= offset[0]
p[1] -= offset[1]
p[2] -= offset[2]
end
x, y, z = 0, 1, 2
if a == :z
x, y, z = 0, 1, 2
elsif a == :y
x, y, z = 2, 0, 1
elsif a == :x
x, y, z = 1, 2, 0
end
_x = cos(r)*(p[x]) - sin(r) * (p[y])
_y = sin(r)*(p[x]) + cos(r) * (p[y])
p[x] = _x
p[y] = _y
p[z] = p[z]
if offset then
p[0] += offset[0]
p[1] += offset[1]
p[2] += offset[2]
end
end
end
$game = Game.new
def tick args
$game.tick args
args.labels << [30, 700, "position: #{args.state.camera.pos.map { |n| "%2f" % n.to_f }.join(", ")}"]
args.labels << [30, 675, "pitch: %2f" % args.state.pitch]
args.labels << [30, 650, "yaw: %2f" % args.state.yaw]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment