Browse Source

support for grabbing and rebuilding with any node

- moved libraries to dedicated folder
- added dummy "faces" block to help during debug
master
entuland 4 years ago
parent
commit
d09d0c3bb0
  1. 454
      init.lua
  2. 1251
      lib/matrix.lua
  3. 0
      lib/smartfs.lua
  4. 48
      models/zzz_faces.obj
  5. BIN
      textures/faces-96x64.png
  6. BIN
      textures/faces-96x64.xcf

454
init.lua

@ -11,8 +11,9 @@ wesh = {
}
wesh.models_path = wesh.mod_path .. "/models/"
local smartfs = dofile(wesh.mod_path .. "/smartfs.lua")
local storage = dofile(wesh.mod_path .. "/storage.lua")
local matrix = dofile(wesh.mod_path .. "/lib/matrix.lua")
local smartfs = dofile(wesh.mod_path .. "/lib/smartfs.lua")
-- ========================================================================
-- initialization functions
@ -185,57 +186,94 @@ function wesh.init_transforms()
local dir = {}
-- no rotation
rot[0] = {{ 1, 0, 0},
{ 0, 1, 0},
{ 0, 0, 1}}
rot[0] = matrix{{ 1, 0, 0},
{ 0, 1, 0},
{ 0, 0, 1}}
-- 90 degrees clockwise
rot[1] = {{ 0, 0, 1},
{ 0, 1, 0},
{ -1, 0, 0}}
rot[1] = matrix{{ 0, 0, 1},
{ 0, 1, 0},
{ -1, 0, 0}}
-- 180 degrees
rot[2] = {{ -1, 0, 0},
{ 0, 1, 0},
{ 0, 0, -1}}
rot[2] = matrix{{ -1, 0, 0},
{ 0, 1, 0},
{ 0, 0, -1}}
-- 270 degrees clockwise
rot[3] = {{ 0, 0, -1},
{ 0, 1, 0},
{ 1, 0, 0}}
rot[3] = matrix{{ 0, 0, -1},
{ 0, 1, 0},
{ 1, 0, 0}}
-- directions
-- Y+
dir[0] = {{ 1, 0, 0},
{ 0, 1, 0},
{ 0, 0, 1}}
dir[0] = matrix{{ 1, 0, 0},
{ 0, 1, 0},
{ 0, 0, 1}}
-- Z+
dir[1] = {{ 1, 0, 0},
{ 0, 0, -1},
{ 0, 1, 0}}
dir[1] = matrix{{ 1, 0, 0},
{ 0, 0, -1},
{ 0, 1, 0}}
-- Z-
dir[2] = {{ 1, 0, 0},
{ 0, 0, 1},
{ 0, -1, 0}}
dir[2] = matrix{{ 1, 0, 0},
{ 0, 0, 1},
{ 0, -1, 0}}
-- X+
dir[3] = {{ 0, 1, 0},
{ -1, 0, 0},
{ 0, 0, 1}}
dir[3] = matrix{{ 0, 1, 0},
{ -1, 0, 0},
{ 0, 0, 1}}
-- X-
dir[4] = {{ 0, -1, 0},
{ 1, 0, 0},
{ 0, 0, 1}}
dir[4] = matrix{{ 0, -1, 0},
{ 1, 0, 0},
{ 0, 0, 1}}
-- Y-
dir[5] = {{ -1, 0, 0},
{ 0, -1, 0},
{ 0, 0, 1}}
wesh.facedir_transform = {}
dir[5] = matrix{{ -1, 0, 0},
{ 0, -1, 0},
{ 0, 0, 1}}
wesh._facedir_transform = {}
wesh._matrix_to_facedir = {}
for facedir = 0, 23 do
local direction = math.floor(facedir / 4)
local rotation = facedir % 4
wesh.facedir_transform[facedir] = wesh.matrix_multiply(dir[direction], rot[rotation])
local transform = dir[direction] * rot[rotation]
wesh._facedir_transform[facedir] = transform
wesh._matrix_to_facedir[transform:tostring():gsub("%-0", "0")] = facedir
end
end
function wesh.get_facedir_transform(facedir)
return wesh._facedir_transform[facedir] or wesh._facedir_transform[0]
end
function wesh.matrix_to_facedir(mtx)
local key = mtx:tostring():gsub("%-0", "0")
if not wesh._matrix_to_facedir[key] then
error("Unsupported matrix:\n" .. key)
end
return wesh._matrix_to_facedir[key]
end
function wesh.transform_facedir(canvas_facedir, node_facedir, invert_canvas)
if not wesh.transform_cache then
wesh.transform_cache = {}
end
local cache_key = canvas_facedir .. "," .. node_facedir .. "," .. (invert_canvas and 1 or 0)
print(cache_key)
if not wesh.transform_cache[cache_key] then
local canvas_transform = wesh.get_facedir_transform(canvas_facedir)
local node_transform = wesh.get_facedir_transform(node_facedir)
if invert_canvas then
canvas_transform = canvas_transform:invert()
end
local transform = canvas_transform * node_transform
wesh.transform_cache[cache_key] = wesh.matrix_to_facedir(transform)
end
print(cache_key .. " == " .. wesh.transform_cache[cache_key])
return wesh.transform_cache[cache_key]
end
function wesh.init_variants()
local variants_filename = "nodevariants.lua"
local default_variants_filename = "default." .. variants_filename
@ -302,7 +340,7 @@ function wesh.register_canvas_nodes()
output = "wesh:canvas" .. size,
recipe = {
{"group:wool", "group:wool", "group:wool"},
{"group:wool", inner, "group:wool"},
{"group:wool", inner, "group:wool"},
{"group:wool", "group:wool", "group:wool"},
}
})
@ -336,20 +374,57 @@ function wesh.register_canvas_nodes()
wesh.valid_canvas_sizes[tonumber(size)] = true
register_canvas(index, size, inner)
end
minetest.register_alias("wesh:canvas", "wesh:canvas16")
minetest.register_craft({
output = "wesh:faces",
recipe = {
{"group:wool", "", "group:wool"},
{"", "group:wool", ""},
{"group:wool", "", "group:wool"},
}
})
minetest.register_node("wesh:faces", {
drawtype = "mesh",
mesh = "zzz_faces.obj",
tiles = { "faces-96x64.png" },
paramtype2 = "facedir",
description = "Woolen Mesh Orientation Block",
walkable = true,
groups = { snappy = 2, choppy = 2, oddly_breakable_by_hand = 3 },
})
end
function wesh.reset_geometry(canvas)
canvas.matrix = {}
canvas.node_matrix = {}
canvas.vertices = {}
canvas.vertices_indices = {}
canvas.faces = {}
canvas.voxel_count = 0
canvas.nodename_count = 0
local function reset(p)
if not canvas.matrix[p.x] then canvas.matrix[p.x] = {} end
if not canvas.matrix[p.x][p.y] then canvas.matrix[p.x][p.y] = {} end
if not canvas.matrix[p.x] then
canvas.matrix[p.x] = {}
canvas.node_matrix[p.x] = {}
end
if not canvas.matrix[p.x][p.y] then
canvas.matrix[p.x][p.y] = {}
canvas.node_matrix[p.x][p.y] = {}
end
canvas.matrix[p.x][p.y][p.z] = "air"
canvas.node_matrix[p.x][p.y][p.z] = {
name = "air",
param2 = 0,
}
end
wesh.traverse_matrix(reset, canvas.size)
end
@ -548,12 +623,14 @@ wesh.forms.giveme_meshes = smartfs.create("wesh.forms.giveme_meshes", function(s
end)
wesh.forms.import_matrix = smartfs.create("wesh.forms.import_matrix", function(state)
state:size(8, 8)
state:size(8, 9)
local canvas = wesh.player_canvas[state.player]
local stored_matrices = wesh.filter_non_matrix(wesh.get_stored_files())
local temp_matrices = wesh.filter_non_matrix(wesh.get_temp_files())
local stored_matrices = wesh.filter_non_matrix(wesh.get_stored_files(), canvas)
local temp_matrices = wesh.filter_non_matrix(wesh.get_temp_files(), canvas)
local matrices_list = state:listbox(0.5, 0.5, 7, 5, "matrices_list")
local matrices_list = state:listbox(0.5, 0.5, 7, 4.5, "matrices_list")
for _, matrix_filename in pairs(stored_matrices) do
matrices_list:addItem(matrix_filename)
@ -563,13 +640,33 @@ wesh.forms.import_matrix = smartfs.create("wesh.forms.import_matrix", function(s
matrices_list:addItem(matrix_filename)
end
local original_check = state:checkbox(0.5, 5.2, "original_check", "Import original nodes (if available)")
local negative_check = state:checkbox(0.5, 6.2, "negative_check", "Invert")
local mononode_check = state:checkbox(2.3, 6.2, "mononode_check", "Mononode")
original_check:onToggle(function()
negative_check:setValue(false)
mononode_check:setValue(false)
end)
negative_check:onToggle(function()
original_check:setValue(false)
mononode_check:setValue(false)
end)
mononode_check:onToggle(function()
negative_check:setValue(false)
original_check:setValue(false)
end)
local nodename_field = state:field(4.5, 6.5, 3.5, 1, "nodename", "'modname:nodename' or 'air'")
state:label(4.3, 7, "label_nodename", "('Invert' or 'Mononode' only)")
nodename_field:setCloseOnEnter(false)
nodename_field:setText("air")
local import_button = state:button(0.5, 7.2, 3, 1, "import", "Import selected")
local import_button = state:button(0.5, 8.2, 3, 1, "import", "Import selected")
import_button:onClick(function()
local full_matrix_filename = false
local selected_matrix_filename = matrices_list:getSelectedItem()
@ -588,15 +685,16 @@ wesh.forms.import_matrix = smartfs.create("wesh.forms.import_matrix", function(s
end
local negative = negative_check:getValue()
local mononode = mononode_check:getValue()
local original = original_check:getValue()
local nodename = nodename_field:getText()
if wesh.import_matrix(full_matrix_filename, state.player, negative, mononode, nodename) then
if wesh.import_matrix(full_matrix_filename, state.player, original, negative, mononode, nodename) then
minetest.after(0, function()
minetest.close_formspec(state.player, "wesh.forms.import_matrix")
end)
end
end)
local close_button = state:button(5.5, 7.2, 2, 1, "close", "Close")
local close_button = state:button(5.5, 8.2, 2, 1, "close", "Close")
close_button:setClose(true)
end)
@ -675,7 +773,13 @@ function wesh.mesh_capture_confirmed(button_or_field, state)
if wesh.save_new_mesh(canvas, playername, meshname) then
minetest.close_formspec(playername, "wesh.forms.capture")
end
wesh.player_canvas[playername] = {}
wesh.player_canvas[playername] = {
pos = canvas.pos,
facedir = canvas.facedir,
node = canvas.node,
size = canvas.size,
}
end
function wesh.save_new_mesh(canvas, playername, description)
@ -695,33 +799,44 @@ function wesh.save_new_mesh(canvas, playername, description)
-- empty all helper variables
wesh.reset_geometry(canvas)
canvas.voxel_count = 0
-- read all nodes from the canvas space in the world
-- extract the colors and put them into a helper matrix of color voxels
-- generate primary boundary
wesh.traverse_matrix(wesh.node_to_voxel, canvas.size, canvas)
-- generate secondary boundaries
wesh.generate_secondary_boundaries(canvas)
-- generate faces according to voxels
local success, err = pcall(function()
wesh.traverse_matrix(wesh.voxel_to_faces, canvas.size, canvas)
end)
canvas.generate_obj = true
if not success then
wesh.notify(playername, err.msg)
return false
end
local meshdata = ""
if canvas.voxel_count == 0 then
canvas.generate_obj = false
if canvas.generate_matrix and canvas.nodename_count == 0 then
wesh.notify(playername, "Empty canvas, nothing to do")
return false
end
wesh.notify(playername, "WARNING: no 'colored' nodes found, mesh file will not be generated")
else
-- generate secondary boundaries
wesh.generate_secondary_boundaries(canvas)
-- this will be the actual content of the .obj file
local vt_section = wesh.vertex_textures
local v_section = wesh.vertices_to_string(canvas)
local vn_section = wesh.normals_to_string()
local f_section = table.concat(canvas.faces, "\n")
local meshdata = vt_section .. v_section .. vn_section .. f_section
-- generate faces according to voxels
local success, err = pcall(function()
wesh.traverse_matrix(wesh.voxel_to_faces, canvas.size, canvas)
end)
if not success then
wesh.notify(playername, err.msg)
return false
end
-- this will be the actual content of the .obj file
local vt_section = wesh.vertex_textures
local v_section = wesh.vertices_to_string(canvas)
local vn_section = wesh.normals_to_string()
local f_section = table.concat(canvas.faces, "\n")
meshdata = vt_section .. v_section .. vn_section .. f_section
end
return wesh.save_mesh_to_file(obj_filename, meshdata, description, playername, canvas)
end
@ -754,43 +869,53 @@ end
function wesh.save_mesh_to_file(obj_filename, meshdata, description, playername, canvas)
-- save .obj file
local full_filename = wesh.temp_path .. "/" .. obj_filename
local file, errmsg = io.open(full_filename, "wb")
if not file then
wesh.notify(playername, "Unable to write to file '" .. obj_filename .. "' from '" .. wesh.temp_path .. "' - error: " .. errmsg)
return false
end
file:write(meshdata)
file:close()
-- save .dat file
local data_filename = obj_filename .. ".dat"
local full_data_filename = wesh.temp_path .. "/" .. data_filename
local file, errmsg = io.open(full_data_filename, "wb")
if not file then
wesh.notify(playername, "Unable to write to file '" .. data_filename .. "' from '" .. wesh.temp_path .. "' - error: " .. errmsg)
return false
if canvas.generate_obj then
-- save .obj file
local full_filename = wesh.temp_path .. "/" .. obj_filename
local file, errmsg = io.open(full_filename, "wb")
if not file then
wesh.notify(playername, "Unable to write to file '" .. obj_filename .. "' from '" .. wesh.temp_path .. "' - error: " .. errmsg)
return false
end
file:write(meshdata)
file:close()
-- save .dat file
local data_filename = obj_filename .. ".dat"
local full_data_filename = wesh.temp_path .. "/" .. data_filename
local file, errmsg = io.open(full_data_filename, "wb")
if not file then
wesh.notify(playername, "Unable to write to file '" .. data_filename .. "' from '" .. wesh.temp_path .. "' - error: " .. errmsg)
return false
end
file:write(wesh.prepare_data_file(description, canvas))
file:close()
wesh.notify(playername, "Mesh saved to '" .. obj_filename .. "' in '" .. wesh.temp_path .. "'")
wesh.notify(playername, "Reload the world to move newly created mesh to the mod folder")
wesh.notify(playername, "Mesh stats: " .. canvas.voxel_count .. " voxels, " .. #canvas.vertices .. " vertices, " .. #canvas.faces .. " faces, " .. canvas.nodename_count .. " nodenames")
end
file:write(wesh.prepare_data_file(description, canvas))
file:close()
if canvas.generate_matrix then
-- save .matrix.dat file
local matrix_data_filename = obj_filename .. ".matrix.dat"
local matrix_data_filename = obj_filename .. ".matrix" .. canvas.size .. ".dat"
local full_matrix_data_filename = wesh.temp_path .. "/" .. matrix_data_filename
local file, errmsg = io.open(full_matrix_data_filename, "wb")
if not file then
wesh.notify(playername, "Unable to write to file '" .. matrix_data_filename .. "' from '" .. wesh.temp_path .. "' - error: " .. errmsg)
return false
end
file:write(minetest.serialize(canvas.matrix))
local matrix_data = {
colors = canvas.matrix,
nodes = canvas.node_matrix,
}
file:write(minetest.serialize(matrix_data))
file:close()
wesh.notify(playername, "Matrix file saved to '" .. matrix_data_filename .. "' in '" .. wesh.temp_path .. "'")
wesh.notify(playername, "Reload the world to move newly created matrix to the mod folder")
end
wesh.notify(playername, "Mesh saved to '" .. obj_filename .. "' in '" .. wesh.temp_path .. "'")
wesh.notify(playername, "Reload the world to move newly created mesh to the mod folder")
wesh.notify(playername, "Mesh stats: " .. canvas.voxel_count .. " voxels, " .. #canvas.vertices .. " vertices, " .. #canvas.faces .. " faces")
return true
end
@ -808,10 +933,10 @@ function wesh.filter_non_obj(filelist)
return list
end
function wesh.filter_non_matrix(filelist)
function wesh.filter_non_matrix(filelist, canvas)
local list = {}
for _, filename in pairs(filelist) do
if wesh.is_valid_matrix_filename(filename) then
if wesh.is_valid_matrix_filename(filename, canvas) then
table.insert(list, filename)
end
end
@ -861,8 +986,10 @@ function wesh.is_valid_obj_filename(obj_filename)
return obj_filename:match("^" .. wesh.gen_prefix .. ".-%.obj$")
end
function wesh.is_valid_matrix_filename(matrix_filename)
return matrix_filename:match("^" .. wesh.gen_prefix .. ".-%.obj%.matrix%.dat$")
function wesh.is_valid_matrix_filename(matrix_filename, canvas)
local pattern = "^" .. wesh.gen_prefix .. ".-%.obj%.matrix(%d*)%.dat$"
local result = matrix_filename:match(pattern)
return tonumber(result) == canvas.size or result == ""
end
-- ========================================================================
@ -907,7 +1034,10 @@ end
function wesh.delete_obj_fileset(full_obj_filename)
os.remove(full_obj_filename)
os.remove(full_obj_filename .. ".dat")
os.remove(full_obj_filename .. ".matrix.dat")
os.remove(full_obj_filename .. ".matrix.dat")
for size, _ in ipairs(wesh.valid_canvas_sizes) do
os.remove(full_obj_filename .. ".matrix" .. size .. ".dat")
end
end
function wesh.delete_temp_obj(obj_filename)
@ -1017,7 +1147,7 @@ function wesh.get_content_id(nodename)
return wesh.content_ids[nodename]
end
function wesh.import_matrix(full_matrix_filename, playername, negative, mononode, nodename)
function wesh.import_matrix(full_matrix_filename, playername, original, negative, mononode, nodename)
if not full_matrix_filename then
wesh.notify(playername, "Please select a matrix to import")
return false
@ -1037,12 +1167,31 @@ function wesh.import_matrix(full_matrix_filename, playername, negative, mononode
wesh.notify(playername, "Unable to open file " .. full_matrix_filename)
return false
end
local matrix = minetest.deserialize(file:read("*all"))
if not matrix or type(matrix) ~= "table" then
local matrix_all = minetest.deserialize(file:read("*all"))
if not matrix_all or type(matrix_all) ~= "table" then
wesh.notify(playername, "Invalid matrix data inside " .. full_matrix_filename)
return false
end
local matrix_data = matrix_all.colors or matrix_all
local matrix_nodes = matrix_all.nodes or false
if not matrix_nodes and original then
wesh.notify(playername, "Old matrix without original nodes " .. full_matrix_filename)
return false
end
if original and (negative or mononode) then
wesh.notify(playername, "Can't import ORIGINAL nodes in INVERT mode or in MONONODE mode")
return false
end
if original then
matrix_data = matrix_nodes
end
local canvas = wesh.player_canvas[playername]
local function invalid_size(axis, size)
@ -1054,7 +1203,7 @@ function wesh.import_matrix(full_matrix_filename, playername, negative, mononode
return false
end
if invalid_size("x", #matrix) or invalid_size("y", #matrix[1]) or invalid_size("z", #matrix[1][1]) then
if invalid_size("x", #matrix_data) or invalid_size("y", #matrix_data[1]) or invalid_size("z", #matrix_data[1][1]) then
return false
end
@ -1070,20 +1219,38 @@ function wesh.import_matrix(full_matrix_filename, playername, negative, mononode
}
local data = vm:get_data()
local data2 = false
if original then
data2 = vm:get_param2_data()
end
local air_id = wesh.get_content_id("air")
for x = 1, #matrix do
for y = 1, #matrix[x] do
for z = 1, #matrix[x][y] do
local color = matrix[x][y][z]
for x = 1, #matrix_data do
for y = 1, #matrix_data[x] do
for z = 1, #matrix_data[x][y] do
local cell = matrix_data[x][y][z]
local param2 = 0
local final_id = false
if negative then
if color == "air" then
final_id = nodename_id
if original then
if cell[1] ~= "air" then
final_id = wesh.get_content_id(cell[1])
param2 = wesh.transform_facedir(canvas.facedir, cell[2] or 0)
end
else
local color = cell
if negative then
if color == "air" then
final_id = nodename_id
end
elseif color ~= "air" then
final_id = mononode and nodename_id or wesh.get_content_id("wool:" .. color)
end
elseif color ~= "air" then
final_id = mononode and nodename_id or wesh.get_content_id("wool:" .. color)
end
if final_id then
@ -1091,12 +1258,20 @@ function wesh.import_matrix(full_matrix_filename, playername, negative, mononode
local abs_pos = wesh.make_absolute(rel_pos, canvas)
local vi = a:index(abs_pos.x, abs_pos.y, abs_pos.z)
data[vi] = final_id
if data2 then
data2[vi] = param2
end
end
end
end
end
vm:set_data(data)
if data2 then
vm:set_param2_data(data2)
end
vm:write_to_map(true)
return true
@ -1318,12 +1493,6 @@ function wesh.construct_face(rel_pos, canvas, texture_vertices, facename, vertic
end
end
function wesh.get_node_color(pos)
local node = minetest.get_node_or_nil(pos)
if not node then return "air" end
return wesh.nodename_to_color[node.name] or "air"
end
function wesh.get_texture_vertices(color)
if not wesh.color_vertices[color] then
return wesh.color_vertices.air
@ -1377,27 +1546,43 @@ function wesh.make_absolute(rel_pos, canvas)
}
-- transform according to canvas facedir
local transformed_pos = wesh.transform(canvas.facedir, shifted_pos)
local transformed_pos = wesh.apply_transform(shifted_pos, wesh.get_facedir_transform(canvas.facedir))
-- translate to absolute according to canvas position
local abs_pos = vector.add(canvas.pos, transformed_pos)
return abs_pos
end
function wesh.set_voxel_color(pos, color, canvas)
if not wesh.color_vertices[color] then color = "air" end
canvas.matrix[pos.x][pos.y][pos.z] = color
end
function wesh.node_to_voxel(rel_pos, canvas)
local abs_pos = wesh.make_absolute(rel_pos, canvas)
local color = wesh.get_node_color(abs_pos)
local node = minetest.get_node_or_nil(abs_pos)
local nodedata = {
node and node.name or "air"
}
local paramtype2 = node and wesh.get_nodedef_field(node.name, "paramtype2")
if paramtype2 == "facedir" then
nodedata[2] = wesh.transform_facedir(canvas.facedir, node.param2, true)
end
local nodename = nodedata[1]
local color = wesh.nodename_to_color[nodename] or "air"
if color ~= "air" then
canvas.voxel_count = canvas.voxel_count + 1
wesh.update_collision_box(rel_pos, canvas.boundary)
end
wesh.set_voxel_color(rel_pos, color, canvas)
if nodename ~= "air" then
canvas.nodename_count = canvas.nodename_count + 1
end
canvas.matrix[rel_pos.x][rel_pos.y][rel_pos.z] = color
canvas.node_matrix[rel_pos.x][rel_pos.y][rel_pos.z] = nodedata
end
function wesh.normals_to_string()
@ -1459,19 +1644,11 @@ function wesh.check_plain(text)
return text:gsub("[^%w]+", "_"):lower()
end
function wesh.matrix_multiply(a, b)
local res = {}
for row = 1, #a do
res[row] = {}
for col = 1, #b[1] do
local num = a[row][1] * b[1][col]
for i = 2, #a[1] do
num = num + a[row][i] * b[i][col]
end
res[row][col] = num
end
function wesh.get_nodedef_field(nodename, fieldname)
if not minetest.registered_nodes[nodename] then
return nil
end
return res
return minetest.registered_nodes[nodename][fieldname]
end
function wesh.merge_tables(t1, t2)
@ -1550,10 +1727,6 @@ function wesh.serialize(object, max_wrapping)
return "return " .. helper(object, max_wrapping)
end
function wesh.transform(facedir, pos)
return wesh.apply_transform(pos, wesh.facedir_transform[facedir])
end
function wesh.traverse_matrix(callback, boundary, ...)
if type(boundary) == "table" then
for x = boundary.min.x, boundary.max.x do
@ -1574,4 +1747,5 @@ function wesh.traverse_matrix(callback, boundary, ...)
end
end
wesh.init()

1251
lib/matrix.lua

File diff suppressed because it is too large Load Diff

0
smartfs.lua → lib/smartfs.lua

48
models/zzz_faces.obj

@ -0,0 +1,48 @@
# Blender v2.79 (sub 0) OBJ File: 'faces.blend'
# www.blender.org
mtllib zzz_faces.mtl
o Cube
v -0.500000 -0.500000 0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v -0.499999 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v 0.500000 0.500000 0.500000
vt 0.666667 -0.000000
vt 0.666667 0.500000
vt 0.333333 0.500000
vt 0.333333 -0.000000
vt 0.666667 1.000000
vt 0.333333 1.000000
vt 0.333333 0.500000
vt 0.666667 0.500000
vt 0.333333 0.500000
vt 0.333333 1.000000
vt -0.000000 1.000000
vt 0.000000 0.500000
vt 1.000000 0.000000
vt 1.000000 0.500000
vt 0.666667 0.500000
vt 0.666667 -0.000000
vt 0.333333 -0.000000
vt 0.000000 0.500000
vt -0.000000 -0.000000
vt 0.666667 0.500000
vt 1.000000 0.500000
vt 1.000000 1.000000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 -0.0000
vn 0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 0.0000
vn -0.0000 0.0000 1.0000
usemtl Material
s off
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 8/6/2 7/7/2 6/8/2
f 1/9/3 5/10/3 6/11/3 2/12/3
f 2/13/4 6/14/4 7/15/4 3/16/4
f 3/17/5 7/7/5 8/18/5 4/19/5
f 5/5/6 1/20/6 4/21/6 8/22/6

BIN
textures/faces-96x64.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 945 B

BIN
textures/faces-96x64.xcf

Binary file not shown.
Loading…
Cancel
Save