Skip to content
Extraits de code Groupes Projets
Valider ff84aec4 rédigé par ultrakatiz's avatar ultrakatiz
Parcourir les fichiers

files

parent 2aef2c24
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
require("kara3d.vector")
require("kara3d.matrix")
require("kara3d.quaternion")
require("kara3d.transform")
require("kara3d.shape")
require("kara3d.vector")
matrix = {class = "matrix"}
matrix.__index = matrix
function matrix.new(r, c, vals)
local m = {rows = r or 1, cols = c or 1, values = {}}
vals = vals or {}
for i = 1, r*c do
m.values[i] = i <= #vals and vals[i] or 0
end
setmetatable(m, matrix)
return m
end
function matrix:tostring()
local str = self.rows .. " x " .. self.cols .. "\n"
for i = 1, self.rows do
for j = 1, self.cols do
str = str .. self:get(i, j) .. (j < self.cols and "\t" or "\n")
end
end
return str
end
function matrix.identity(r, c)
local m = matrix.new(r, c)
for i = 1, math.min(r, c) do m:set(i, i, 1) end
return m
end
function matrix:clone()
return matrix.new(self.rows, self.cols, self.values)
end
function matrix:get(i, j)
if (i <= 0 or i > self.rows) then return 0 end
if (j <= 0 or j > self.cols) then return 0 end
local n = (i-1) * self.cols + j
return n > #self.values and 0 or self.values[n]
end
function matrix:column(i)
if (i <= 0 or i > self.cols) then return vector.zero(self.rows) end
local vals = {}
for j = 1, self.rows do vals[j] = self:get(j, i) end
return vector.new(self.rows, vals)
end
function matrix:set(i, j, value)
self.values[(i-1) * self.cols + j] = value
return self
end
function matrix.__add(m1, m2)
if (m1.rows ~= m2.rows or m1.cols ~= m2.cols) then return m1 end
local m = m1:clone()
for i = 1, #(m.values) do
m.values[i] = m.values[i] + m2.values[i]
end
return m
end
function matrix.__unm(m)
local n = matrix.new(m.rows, m.cols)
for i = 1, #(n.values) do
n.values[i] = -m.values[i]
end
return n
end
function matrix.__sub(m1, m2)
if (m1.rows ~= m2.rows or m1.cols ~= m2.cols) then return m1 end
local m = matrix.new(m1.rows, m1.cols)
for i = 1, #(m.values) do
m.values[i] = m1.values[i] - m2.values[i]
end
return m
end
function matrix.mul_matrix(m1, m2)
if (type(m1) == "number") then return matrix.mul_scalar(m2, m1) end
if (type(m2) == "number") then return matrix.mul_scalar(m1, m2) end
if (m1.cols ~= m2.rows) then return m1 end
local m = matrix.new(m1.rows, m2.cols)
for i = 1, m1.rows do
for j = 1, m2.cols do
local sum = 0
for k = 1, m1.cols do
sum = sum + m1:get(i, k) * m2:get(k, j)
end
m:set(i, j, sum)
end
end
return m
end
function matrix.mul_vector(m, v)
if (m.cols ~= v.size) then return v end
local vals = {}
for i = 1, m.rows do
local sum = 0
for j = 1, m.cols do
sum = sum + m:get(i, j) * v:get(j)
end
vals[i] = sum
end
return vector.new(m.rows, vals)
end
function matrix.mul_scalar(m, s)
local r = matrix.new(m.rows, m.cols)
for i = 1, #(r.values) do
r.values[i] = s * m.values[i]
end
return r
end
function matrix.__mul(m, o)
if (getmetatable(o) == matrix) then return matrix.mul_matrix(m, o)
elseif (getmetatable(o) == vector) then return matrix.mul_vector(m, o)
elseif (type(o) == "number") then return matrix.mul_scalar(m, o) end
return m
end
function matrix.__eq(m1, m2)
if (m1.rows ~= m2.rows or m1.cols ~= m2.cols) then return false end
for i = 1, #(m1.values) do
if (m1.values[i] ~= m2.values[i]) then return false end
end
return true
end
require("kara3d.vector")
require("kara3d.matrix")
quaternion = {class = "quaternion"}
quaternion.__index = quaternion
function quaternion.new(a, b, c, d)
local q = {x = a or 0, y = b or 0, z = c or 0, w = d or 1}
setmetatable(q, quaternion)
return q
end
function quaternion:inv()
return quaternion.new(-self.x, -self.y, -self.z, -self.w)
end
function quaternion:tostring()
return self.x .. ", " .. self.y .. ", " .. self.z .. ", " .. self.w
end
function quaternion:set(x, y, z, w)
if (type(x) == "table" and x.class == "quaternion") then
self.x = x.x
self.y = x.y
self.z = x.z
self.w = x.w
else
self.x = x or 0
self.y = y or 0
self.z = z or 0
self.w = w or 1
end
return self
end
function quaternion.mul_quaternion(q1, q2)
local b, c, d, a = q1:unpack()
local f, g, h, e = q2:unpack()
return quaternion.new(a*e - b*f - c*g - d*h,
a*f + b*e + c*h - d*g,
a*g + c*e + d*f - b*h,
a*h + d*e + b*g - c*f)
end
function quaternion.mul_vector(q, v)
local v3 = vector.new(3, v.values)
local u1 = vector.new(3, {q.x, q.y, q.z})
local u2 = vector.new(3, {-q.x, -q.y, -q.z})
local d = vector.dot(u1, v3)
local c = vector.cross(u1, v3)
return 2*d * u1 + (q.w*q.w - u1:length2()) * v3 + 2*q.w * c
end
function quaternion.from_to_rotation(from, to)
local v0 = from:normalized()
local v1 = to:normalized()
local d = v0:dot(v1)
if (math.abs(d) < 0.001) then return quaternion.identity() end
return quaternion.axis_angle(vector.cross(v0, v1):normalize(), math.acos(d))
end
function quaternion.axis_angle(axis, angle)
angle = angle or axis:length()
local naxis = axis:normalized()
local hcos = math.cos(0.5 * angle)
local hsin = math.sin(0.5 * angle)
return quaternion.new(naxis:x() * hsin, naxis:y() * hsin, naxis:z() * hsin, hcos)
end
function quaternion:unpack()
return self.x, self.y, self.z, self.w
end
function quaternion:normalize()
local len = self:length()
if len ~= 0 and len ~= 1 then
self.x = self.x / len
self.y = self.y / len
self.z = self.z / len
self.w = self.w / len
end
return self
end
function quaternion:normalized()
local q = self:clone()
q:normalize()
return q
end
function quaternion:clone()
return quaternion.new(self.x, self.y, self.z, self.w)
end
function quaternion:length2()
return self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w
end
function quaternion:length()
return math.sqrt(self:length2())
end
function quaternion.identity() return quaternion.new() end
function quaternion:to_matrix()
local x, y, z, w = self:unpack()
local m = matrix.new(4, 4,
{1 - 2*y*y - 2*z*z, 2*x*y - 2*w*z, 2*w*y + 2*x*z, 0,
2*w*z + 2*x*y, 1 - 2*x*x - 2*z*z, 2*y*z - 2*w*x, 0,
2*x*z - 2*w*y, 2*w*x + 2*y*z, 1 - 2*x*x - 2*y*y, 0,
0, 0, 0, 1})
return m
end
require("kara3d.vector")
require("kara3d.matrix")
require("kara3d.quaternion")
require("kara3d.transform")
require("utils")
shape = {class = "shape"}
shape.__index = shape
face = {class = "face"}
face.__index = face
function face.new(v, n, t)
local f = {vertices = v or {}, normal = n or -vector.cardinal(3, 3), tags = t}
setmetatable(f, face)
return f
end
function shape.new(t, f)
local s = {transform = t, faces = f or {}}
setmetatable(s, shape)
return s
end
function shape:clone()
return shape.new(self.transform, table.copy(self.faces))
end
function shape:draw(subs, line, tags, cull)
local l = table.copy(line)
local p = self.transform:position(true)
local r = self.transform:rotation(true)
local m = self.transform:matrix(true)
local c = vector.cardinal(4, 4)
local return_str = nil
for i = 1, #self.faces do
local face = self.faces[i]
local n = quaternion.mul_vector(r, face.normal)
if not (cull and n:z() <= 0) then
local vs = face.vertices
local v = matrix.mul_vector(m, vs[#vs] + c) - p
local str = (tags and "{" .. tags .. "}" or "")
.. (face.tags and "{" .. face.tags .. "}" or "")
.. "{\\an7\\pos(" .. p:x() .. ", " .. p:y() .. ")\\p1}"
.. "m " .. v:x() .. " " .. v:y() .. " "
for i = 1, #vs do
v = matrix.mul_vector(m, vs[i] + c) - p
str = str .. "l " .. v:x() .. " " .. v:y() .. " "
end
l.text = str
l.effect = "fx"
subs.append(l)
end
end
return ""
end
--[[
1________5
/| /|
2/__|____/6 | Y
| 3|_ _|_ _|7 |__ X
| / | / /
4|/______|/8 Z
]]--
function shape.cube(t, size)
local hs = size / 2
local vs = {vector.new(3, {-hs, -hs, -hs}), vector.new(3, {-hs, -hs, hs}),
vector.new(3, {-hs, hs, -hs}), vector.new(3, {-hs, hs, hs}),
vector.new(3, { hs, -hs, -hs}), vector.new(3, { hs, -hs, hs}),
vector.new(3, { hs, hs, -hs}), vector.new(3, { hs, hs, hs})}
local left = face.new({vs[1], vs[2], vs[4], vs[3]}, -vector.cardinal(3, 1))
local right = face.new({vs[5], vs[6], vs[8], vs[7]}, vector.cardinal(3, 1))
local bottom = face.new({vs[1], vs[2], vs[6], vs[5]}, -vector.cardinal(3, 2))
local top = face.new({vs[3], vs[4], vs[8], vs[7]}, vector.cardinal(3, 2))
local back = face.new({vs[1], vs[5], vs[7], vs[3]}, -vector.cardinal(3, 3))
local front = face.new({vs[2], vs[6], vs[8], vs[4]}, vector.cardinal(3, 3))
return shape.new(t, {left, right, bottom, top, back, front})
end
require("kara3d.vector")
require("kara3d.matrix")
require("kara3d.quaternion")
transform = {class = "transform"}
transform.__index = transform
function transform.new(p, r, s, par)
p = p or vector.zero(3)
r = r or quaternion.identity()
s = s or vector.one(3)
local t = {pos = p, rot = r, scl = s, parent = par}
setmetatable(t, transform)
return t
end
function transform:tostring()
return "(pos = (" .. self.pos:tostring() .. "), "
.. "rot = (" .. self.rot:tostring() .. "), "
.. "scl = (" .. self.scl:tostring() .. "), "
.. (self.parent and "has parent" or "no parent") .. ")"
end
function transform:rotate(axis, angle)
self.rot = quaternion.axis_angle(axis, angle) * self.rot
return self
end
function transform:position(global)
local p = self.pos:clone()
if (p.size > 4) then p:set_size(4) end
if (p.size < 4) then p:set_size(4) p:set(4, 1) end
if (global and self.parent) then
p = matrix.mul_vector(self.parent:matrix(true), p)
end
return p:set_size(3)
end
function transform:rotation(global)
local q = self.rot:normalized()
if (global and self.parent) then
q = quaternion.mul_quaternion(self.parent:rotation(true), q):normalize()
end
return q
end
function transform:scale(global)
local s = self.scl:clone()
if (global and self.parent) then
local m = self:matrix(true)
s:set(1, m:column(1):set_size(3):length())
s:set(2, m:column(2):set_size(3):length())
s:set(3, m:column(3):set_size(3):length())
end
return s
end
function transform:matrix(global)
local translation = matrix.new(4, 4,
{1, 0, 0, self.pos:get(1),
0, 1, 0, self.pos:get(2),
0, 0, 1, self.pos:get(3),
0, 0, 0, 1})
local rotation = self.rot:normalized():to_matrix()
local scale = matrix.new(4, 4,
{self.scl:get(1), 0, 0, 0,
0, self.scl:get(2), 0, 0,
0, 0, self.scl:get(3), 0,
0, 0, 0, 1})
local m = translation * rotation * scale
if (global and self.parent ~= nil) then
m = self.parent:matrix(true) * m
end
return m
end
vector = {class = "vector"}
vector.__index = vector
function vector.new(n, vals)
if (type(n) == "table") then vals = n n = #n end
vals = vals or {}
local v = {size = n or 3, values = {}}
for i = 1, v.size do
v.values[i] = i <= #vals and vals[i] or 0
end
setmetatable(v, vector)
return v
end
-- operator overloading
function vector.__add(a, b)
local small = a.size < b.size and a or b
local big = a.size < b.size and b or a
local r = big:clone()
for i = 1, small.size do r:set(i, r:get(i) + small:get(i)) end
return r
end
function vector.__unm(a)
local r = vector.new(a.size)
for i = 1, r.size do r:set(i, -(a:get(i))) end
return r
end
function vector.__sub(a, b)
local oppb = -b
return a + oppb
end
function vector.__mul(a, b)
if type(a) == "number" and type(b) ~= "number" then
local r = vector.new(b.size)
for i = 1, r.size do r:set(i, a * b:get(i)) end
return r
elseif type(a) ~= "number" and type(b) == "number" then
local r = vector.new(a.size)
for i = 1, r.size do r:set(i, a:get(i) * b) end
return r
elseif type(a) ~= "number" and type(b) ~= "number" then
local small = a.size < b.size and a or b
local big = a.size < b.size and b or a
local r = vector.new(big.size)
for i = 1, small.size do r:set(i, small:get(i) * big:get(i)) end
return r
else
return a * b
end
end
function vector.__eq(a, b)
if (a.size ~= b.size) then return false end
for i = 1, a.size do if (a:get(i) ~= b:get(i)) then return false end end
return true
end
-- actual functions
function vector:tostring()
local str = ""
for i = 1, self.size - 1 do
str = str .. self:get(i) .. ", "
end
return str .. self:get(self.size)
end
function vector:clone() return vector.new(self.size, self.values) end
function vector:length2()
local sum = 0
for i = 1, self.size do sum = sum + self:get(i) * self:get(i) end
return sum
end
function vector:length() return math.sqrt(self:length2()) end
function vector:is_unit() return self:length2() == 1 end
function vector:normalize()
local len = self:length()
if len == 0 or len == 1 then return self end
for i = 1, self.size do self:set(i, self:get(i) / len) end
return self
end
function vector:normalized() return self:clone():normalize() end
function vector.project_vector(from, to) return (vector.dot(from, to) / to:length2()) * to end
function vector.project_plane(from, normal) return from - vector.project_vector(from, normal) end
function vector.dot(a, b)
local min_size = math.min(a.size, b.size)
local sum = 0
for i = 1, min_size do sum = sum + a.values[i] * b.values[i] end
return sum
end
function vector.distance2(a, b) return (a - b):length2() end
function vector.distance(a, b) return (a - b):length() end
function vector.angle(from, to) return math.acos(vector.dot(from, to) / (from:length() * to:length())) end
function vector.lerp(from, to, t) return t * from + (1 - t) * to end
function vector:set_values(vals)
vals = vals or {}
for i = 1, #vals do self.values[i] = vals[i] end
for i = #vals + 1, self.size do self.values[i] = nil end
self.size = #vals
return self
end
function vector:set_size(n)
if (self.size == n) then return self end
for i = n + 1, self.size do self:set(i, nil) end
for i = self.size + 1, n do self:set(i, 0) end
self.size = n
return self
end
function vector.cross(a, b)
return vector.new(3, {a.values[2] * b.values[3] - a.values[3] * b.values[2],
a.values[3] * b.values[1] - a.values[1] * b.values[3],
a.values[1] * b.values[2] - a.values[2] * b.values[1]})
end
function vector.zero(size) return vector.new(size) end
function vector.one(size)
local vals = {}
for i = 1, size do vals[i] = 1 end
return vector.new(size, vals)
end
function vector.cardinal(size, index)
local vals = {}
for i = 1, size do vals[i] = i == index and 1 or 0 end
return vector.new(size, vals)
end
function vector:get(index) return self.values[index] end
function vector:set(index, value)
self.values[index] = value
return self
end
function vector:x() return self.values[1] end
function vector:y() return self.values[2] end
function vector:z() return self.values[3] end
function vector:w() return self.values[4] end
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter