Created
December 3, 2024 20:08
-
-
Save amirrajan/f020517ae6dccf69106683806b1c4cb8 to your computer and use it in GitHub Desktop.
DragonRuby Game Toolkit - FF8 Rinoa
This file contains hidden or 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 tick args | |
if Kernel.tick_count == 0 | |
r = read_obj_raw 'models/rinoa.obj' | |
end | |
args.grid.origin_center! | |
args.state.obj ||= read_obj_raw 'models/rinoa.obj' | |
args.state.triangles ||= read_obj 'models/rinoa.obj' | |
args.state.target_triangles_start ||= 0 | |
args.state.target_triangles_end ||= 952 | |
args.state.target_triangles ||= (read_obj 'models/rinoa.obj')[args.state.target_triangles_start..args.state.target_triangles_end] | |
movement_multiplier = 1000 | |
args.state.cam_y ||= 100.0 | |
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 | |
args.state.cam_angle_z ||= 0 | |
if args.inputs.keyboard.c | |
args.state.cam_angle_z += 0.1 | |
elsif args.inputs.keyboard.z | |
args.state.cam_angle_z -= 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 -= 1.8 * y_change_rate | |
else | |
args.state.cam_angle_y += 1.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 += 1.8 * x_change_rate | |
else | |
args.state.cam_angle_x -= 1.8 * x_change_rate | |
end | |
end | |
args.state.cam_z ||= 1200 | |
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 ||= -4 | |
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), | |
(rotate_z args.state.cam_angle_z) | |
args.state.perspective_target_triangles = args.state.target_triangles.map do |t| | |
per = { p1: perspective(Matrix.mul(t.v[0], camera_matrix)), | |
p2: perspective(Matrix.mul(t.v[1], camera_matrix)), | |
p3: perspective(Matrix.mul(t.v[2], camera_matrix)), | |
source: t } | |
per.z_avg = (per.p1.z + per.p2.z + per.p3.z) / 3 | |
per | |
end | |
args.state.perspective_target_triangles.sort_by { |t| t.z_avg }.each do |triangle| | |
if triangle.p1 && triangle.p2 && triangle.p3 | |
args.state.sprite_sizes ||= {} | |
p1 = triangle.p1 | |
p2 = triangle.p2 | |
p3 = triangle.p3 | |
path = if triangle.source.vt[0].usemtl | |
args.state.obj.mtl[triangle.source.vt[0].usemtl].map_Kd | |
else | |
:solid | |
end | |
if path != :solid | |
args.state.sprite_sizes[path] ||= args.gtk.calcspritebox path | |
sprite_w, sprite_h = args.state.sprite_sizes[path] | |
source_x = triangle.source.vt[0].u * sprite_w | |
source_y = if triangle.source.vt[0].v < -1 | |
(triangle.source.vt[0].v + 2) * sprite_h | |
elsif triangle.source.vt[0].v < 0 | |
(triangle.source.vt[0].v + 1) * sprite_h | |
elsif triangle.source.vt[0].v > 1 | |
(triangle.source.vt[0].v - 1) * sprite_h | |
else | |
triangle.source.vt[0].v * -sprite_h | |
end | |
source_x2 = triangle.source.vt[1].u * sprite_w | |
source_y2 = if triangle.source.vt[1].v < -1 | |
(triangle.source.vt[1].v + 2) * sprite_h | |
elsif triangle.source.vt[1].v < 0 | |
(triangle.source.vt[1].v + 1) * sprite_h | |
elsif triangle.source.vt[1].v > 1 | |
(triangle.source.vt[1].v - 1) * sprite_h | |
else | |
triangle.source.vt[1].v * sprite_h | |
end | |
source_x3 = triangle.source.vt[2].u * sprite_w | |
source_y3 = if triangle.source.vt[2].v < -1 | |
(triangle.source.vt[2].v + 2) * sprite_h | |
elsif triangle.source.vt[2].v < 0 | |
(triangle.source.vt[2].v + 1) * sprite_h | |
elsif triangle.source.vt[2].v > 1 | |
(triangle.source.vt[2].v - 1) * sprite_h | |
else | |
triangle.source.vt[2].v * sprite_h | |
end | |
r = 255 | |
g = 255 | |
b = 255 | |
a = 255 | |
else | |
source_x = 0 | |
source_y = 0 | |
source_x2 = 100 | |
source_y2 = 0 | |
source_x3 = 100 | |
source_y3 = 100 | |
r = 255 | |
g = 0 | |
b = 0 | |
a = 80 | |
end | |
args.outputs.sprites << { | |
x: p1.x, | |
y: p1.y, | |
x2: p2.x, | |
y2: p2.y, | |
x3: p3.x, | |
y3: p3.y, | |
source_x: source_x, | |
source_y: source_y, | |
source_x2: source_x2, | |
source_y2: source_y2, | |
source_x3: source_x3, | |
source_y3: source_y3, | |
path: path, | |
r: r, g: g, b: b, a: a | |
} | |
end | |
end | |
# args.outputs.watch "#{args.state.cam_x}" | |
# args.outputs.watch "#{args.state.cam_y}" | |
# args.outputs.watch "#{args.state.cam_z}" | |
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.vec4(r.x, r.y, r.z, r.w) | |
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 scale sx, sy, sz | |
(Matrix.mat4 sx, 0, 0, 0, | |
0, sy, 0, 0, | |
0, 0, sz, 0, | |
0, 0, 0, 1) | |
end | |
def rotate_z angle_d | |
cos_t = Math.cos angle_d.to_radians | |
sin_t = Math.sin angle_d.to_radians | |
(Matrix.mat4 cos_t, -sin_t, 0, 0, | |
sin_t, cos_t, 0, 0, | |
0, 0, 1, 0, | |
0, 0, 0, 1) | |
end | |
def read_obj_raw path | |
contents = ($gtk.read_file path) | |
root = { | |
v: [], | |
f: [], | |
vt: [], | |
vn: [], | |
groups: { default: {} }, | |
mtllib: [], | |
mtl: {} | |
} | |
current_group = root[:groups][:default] | |
contents.each_line do |l| | |
if l.strip.start_with? "v " | |
x, y, z = l.strip.split(' ')[1..-1].map { |t| t.to_f } | |
root.v << { x: x, y: y, z: z } | |
elsif l.strip.start_with? "usemtl " | |
name = l.strip.split(' ')[1] | |
current_group[:usemtl] = name | |
elsif l.strip.start_with? "f " | |
a, b, c = l.strip.split(' ')[1..-1] | |
as = a.split('/') | |
a_v = as[0] ? as[0].to_i - 1 : nil | |
a_vt = as[1] ? as[1].to_i - 1 : nil | |
a_vn = as[2] ? as[2].to_i - 1 : nil | |
bs = b.split('/') | |
b_v = bs[0] ? bs[0].to_i - 1 : nil | |
b_vt = bs[1] ? bs[1].to_i - 1 : nil | |
b_vn = bs[2] ? bs[2].to_i - 1 : nil | |
cs = c.split('/') | |
c_v = cs[0] ? cs[0].to_i - 1 : nil | |
c_vt = cs[1] ? cs[1].to_i - 1 : nil | |
c_vn = cs[2] ? cs[2].to_i - 1 : nil | |
root.f << { a: { v: a_v, vt: a_vt, vn: a_vn }, | |
b: { v: b_v, vt: b_vt, vn: b_vn }, | |
c: { v: c_v, vt: c_vt, vn: c_vn }, | |
group: current_group } | |
elsif l.strip.start_with? "g " | |
name = l.strip.split(' ')[1] || "" | |
root[:groups][name] ||= {} | |
current_group = root[:groups][name] | |
elsif l.strip.start_with? "mtllib " | |
name = l.strip.split(' ')[1] | |
root[:mtllib] << name | |
elsif l.strip.start_with? "vt " | |
u, v, w = l.strip.split(' ')[1..-1].map { |t| t.to_f } | |
root[:vt] ||= [] | |
root[:vt] << { u: u, v: v, w: w } | |
elsif l.strip.start_with? "vn " | |
x, y, z = l.strip.split(' ')[1..-1].map { |t| t.to_f } | |
root[:vn] ||= [] | |
root[:vn] << { x: x, y: y, z: z } | |
end | |
end | |
root.mtllib.each do |v| | |
contents = ($gtk.read_file File.dirname(path) + "/" + v) | |
current_mtl = nil | |
contents.each_line do |l| | |
if l.strip.start_with? "#" | |
next | |
elsif l.strip.start_with? "newmtl " | |
name = l.strip.split(' ')[1] | |
root.mtl[name] = {} | |
current_mtl = root.mtl[name] | |
elsif l.strip.start_with? "Kd " | |
r, g, b = l.strip.split(' ')[1..-1].map { |t| t.to_f } | |
current_mtl[:Kd] = { r: r, g: g, b: b } | |
elsif l.strip.start_with? "Ks " | |
r, g, b = l.strip.split(' ')[1..-1].map { |t| t.to_f } | |
current_mtl[:Ks] = { r: r, g: g, b: b } | |
elsif l.strip.start_with? "Ns " | |
ns = l.strip.split(' ')[1].to_f | |
current_mtl[:Ns] = ns | |
elsif l.strip.start_with? "map_Kd " | |
map_kd = l.strip.split(' ')[1] | |
current_mtl[:map_Kd] = File.dirname(path) + "/" + map_kd | |
end | |
end | |
end | |
root | |
end | |
def read_obj path | |
obj = read_obj_raw path | |
triangles = obj.f.map do |f| | |
{ | |
v: [ | |
Matrix.mul(Matrix.mul(Matrix.vec4(obj.v[f.a.v].x, obj.v[f.a.v].y, obj.v[f.a.v].z, 1), (rotate_z -180)), (scale 0.01, 0.01, 0.01)), | |
Matrix.mul(Matrix.mul(Matrix.vec4(obj.v[f.b.v].x, obj.v[f.b.v].y, obj.v[f.b.v].z, 1), (rotate_z -180)), (scale 0.01, 0.01, 0.01)), | |
Matrix.mul(Matrix.mul(Matrix.vec4(obj.v[f.c.v].x, obj.v[f.c.v].y, obj.v[f.c.v].z, 1), (rotate_z -180)), (scale 0.01, 0.01, 0.01)) | |
], | |
vt: [ | |
f.a.vt ? obj.vt[f.a.vt].merge(f.group) : nil, | |
f.b.vt ? obj.vt[f.b.vt].merge(f.group) : nil, | |
f.c.vt ? obj.vt[f.c.vt].merge(f.group) : nil, | |
], | |
vn: [ | |
f.a.vn ? obj.vn[f.a.vn] : nil, | |
f.b.vn ? obj.vn[f.b.vn] : nil, | |
f.c.vn ? obj.vn[f.c.vn] : nil | |
], | |
} | |
end | |
triangles | |
end | |
# $gtk.reset |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment