Last active
August 2, 2019 05:20
-
-
Save amirrajan/3cbfb5275420846019da8bdb0e60f1d3 to your computer and use it in GitHub Desktop.
dragonruby gtk faux 3D
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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