Skip to content

Instantly share code, notes, and snippets.

@amirrajan
Last active May 7, 2022 14:57
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amirrajan/20aa5ae329035ac8439beeb49fecff4b to your computer and use it in GitHub Desktop.
Save amirrajan/20aa5ae329035ac8439beeb49fecff4b to your computer and use it in GitHub Desktop.
DragonRuby Game Toolkit: Loading an OBJ file and rendering triangles.
def tick args
args.grid.origin_center!
args.state.triangles ||= read_obj 'models/mario.obj'
movement_multiplier = 1000
args.outputs.labels << { x: 0,
y: 30.from_top,
text: "W,A,S,D to move. Mouse to look. Triangles is a Indie/Pro Feature and will be ignored in Standard.",
alignment_enum: 1 }
args.state.cam_y ||= 0.00
if args.inputs.keyboard.i
args.state.cam_y += 0.01
elsif args.inputs.keyboard.k
args.state.cam_y -= 0.01
end
args.state.cam_angle_y ||= 0
if args.inputs.keyboard.q
args.state.cam_angle_y += 0.25
elsif args.inputs.keyboard.e
args.state.cam_angle_y -= 0.25
end
args.state.cam_angle_x ||= 0
if args.inputs.keyboard.u
args.state.cam_angle_x += 0.1
elsif args.inputs.keyboard.o
args.state.cam_angle_x -= 0.1
end
if args.inputs.mouse.has_focus
y_change_rate = (args.inputs.mouse.x / 640) ** 2
if args.inputs.mouse.x < 0
args.state.cam_angle_y -= 0.8 * y_change_rate
else
args.state.cam_angle_y += 0.8 * y_change_rate
end
x_change_rate = (args.inputs.mouse.y / 360) ** 2
if args.inputs.mouse.y < 0
args.state.cam_angle_x += 0.8 * x_change_rate
else
args.state.cam_angle_x -= 0.8 * x_change_rate
end
end
args.state.cam_z ||= 6.4
if args.inputs.keyboard.up
point_1 = { x: 0, y: 0.02 }
point_r = args.geometry.rotate_point point_1, args.state.cam_angle_y
args.state.cam_x -= point_r.x * movement_multiplier
args.state.cam_z -= point_r.y * movement_multiplier
elsif args.inputs.keyboard.down
point_1 = { x: 0, y: -0.02 }
point_r = args.geometry.rotate_point point_1, args.state.cam_angle_y
args.state.cam_x -= point_r.x * movement_multiplier
args.state.cam_z -= point_r.y * movement_multiplier
end
args.state.cam_x ||= 0.00
if args.inputs.keyboard.right
point_1 = { x: -0.02, y: 0 }
point_r = args.geometry.rotate_point point_1, args.state.cam_angle_y
args.state.cam_x -= point_r.x * movement_multiplier
args.state.cam_z -= point_r.y * movement_multiplier
elsif args.inputs.keyboard.left
point_1 = { x: 0.02, y: 0 }
point_r = args.geometry.rotate_point point_1, args.state.cam_angle_y
args.state.cam_x -= point_r.x * movement_multiplier
args.state.cam_z -= point_r.y * movement_multiplier
end
if args.inputs.keyboard.key_down.r || args.inputs.keyboard.key_down.zero
args.state.cam_x = 0.00
args.state.cam_y = 0.00
args.state.cam_z = 1.00
args.state.cam_angle_y = 0
args.state.cam_angle_x = 0
end
camera_matrix = Matrix.mul (translate -args.state.cam_x, -args.state.cam_y, -args.state.cam_z),
(rotate_y args.state.cam_angle_y),
(rotate_x args.state.cam_angle_x)
args.state.perspective_triangles = args.state.triangles.map do |t|
{ p1: perspective(Matrix.mul(t[0], camera_matrix)),
p2: perspective(Matrix.mul(t[1], camera_matrix)),
p3: perspective(Matrix.mul(t[2], camera_matrix)) }
end
args.state.perspective_triangles.each do |triangle|
if triangle.p1 && triangle.p2 && triangle.p3
p1 = triangle.p1
p2 = triangle.p2
p3 = triangle.p3
args.outputs.sprites << {
x: p1.x,
y: p1.y,
x2: p2.x,
y2: p2.y,
x3: p3.x,
y3: p3.y,
source_x: 0,
source_y: 0,
source_x2: 100,
source_y2: 0,
source_x3: 100,
source_y3: 100,
path: :pixel,
r: 0, g: 0, b: 0, a: 80
}
end
end
end
def perspective vec
left = 100.0
right = -100.0
bottom = 100.0
top = -100.0
near = 3000.0
far = 8000.0
sx = 2 * near / (right - left)
sy = 2 * near / (top - bottom)
c2 = - (far + near) / (far - near)
c1 = 2 * near * far / (near - far)
tx = -near * (left + right) / (right - left)
ty = -near * (bottom + top) / (top - bottom)
p = Matrix.mat4 sx, 0, 0, tx,
0, sy, 0, ty,
0, 0, c2, c1,
0, 0, -1, 0
r = Matrix.mul vec, p
return nil if r.w < 0
r.x *= r.z / r.w / 100
r.y *= r.z / r.w / 100
Matrix.vec2(r.x, r.y)
end
def translate dx, dy, dz
Matrix.mat4 1, 0, 0, dx,
0, 1, 0, dy,
0, 0, 1, dz,
0, 0, 0, 1
end
def rotate_y angle_d
cos_t = Math.cos angle_d.to_radians
sin_t = Math.sin angle_d.to_radians
(Matrix.mat4 cos_t, 0, sin_t, 0,
0, 1, 0, 0,
-sin_t, 0, cos_t, 0,
0, 0, 0, 1)
end
def rotate_x angle_d
cos_t = Math.cos angle_d.to_radians
sin_t = Math.sin angle_d.to_radians
(Matrix.mat4 1, 0, 0, 0,
0, cos_t, -sin_t, 0,
0, sin_t, cos_t, 0,
0, 0, 0, 1)
end
def read_obj path
contents = ($gtk.read_file path)
verticies = contents.each_line
.find_all do |l|
l.strip.start_with? "v "
end.map do |l|
x, y, z = l.strip.split(' ')[1..-1].map { |t| t.to_f }
{ x: x, y: y, z: z }
end
faces = contents.each_line
.find_all do |l|
l.strip.start_with? "f "
end.map do |l|
a, b, c = l.strip.split(' ')[1..-1]
{ a: a.split('/')[0].to_i - 1,
b: b.split('/')[0].to_i - 1,
c: c.split('/')[0].to_i - 1 }
end
triangles = faces.map do |f|
[
Matrix.vec4(verticies[f.a].x, verticies[f.a].y, verticies[f.a].z, 1),
Matrix.vec4(verticies[f.b].x, verticies[f.b].y, verticies[f.b].z, 1),
Matrix.vec4(verticies[f.c].x, verticies[f.c].y, verticies[f.c].z, 1)
]
end
triangles
end
$gtk.reset
cubeworld-1.mp4
cubeworld.1.mp4
cubeworld.2.mp4
@mlanca
Copy link

mlanca commented Apr 18, 2022

Impressive, thanks.

@ps-ruby
Copy link

ps-ruby commented Apr 21, 2022

Loved it
Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment