Implemented automatic collision box
- tweaked passing of canvas data around - added ability to specify custom node properties to be passed to register_node() from .obj.dat structuremaster
parent
0ead6905fe
commit
1f45d74322
|
@ -74,6 +74,11 @@ By default, four versions of each mesh will be available:
|
||||||
Sample of natural terrain capture:
|
Sample of natural terrain capture:
|
||||||
![Non wool capture](/screenshots/non-wool-capture.png)
|
![Non wool capture](/screenshots/non-wool-capture.png)
|
||||||
|
|
||||||
|
Collision boxes will be built automatically depending on the extent of your mesh:
|
||||||
|
![Auto collision box](/screenshots/auto-collision-box.png)
|
||||||
|
|
||||||
|
Collision boxes are simple cuboids so you cannot create stairs (but you can create slabs, frames, carpets and so forth).
|
||||||
|
|
||||||
Such new blocks can't be crafted (I plan to make sort of a crafting station where you put some material and chose the model you want to craft), so you either need to give them to yourself or to find them in the Creative inventory. All such meshes show up if you filter for either "wesh" or "mesh".
|
Such new blocks can't be crafted (I plan to make sort of a crafting station where you put some material and chose the model you want to craft), so you either need to give them to yourself or to find them in the Creative inventory. All such meshes show up if you filter for either "wesh" or "mesh".
|
||||||
|
|
||||||
![Creative search](/screenshots/creative-search.png)
|
![Creative search](/screenshots/creative-search.png)
|
||||||
|
@ -83,7 +88,7 @@ Looking at the filename (or knowing how the name gets converted) you can also wo
|
||||||
- resulting filename: "mesh_test_one.obj"
|
- resulting filename: "mesh_test_one.obj"
|
||||||
- resulting nodename: "wesh:mesh_test_one_VERSION" where "VERSION" will actually be something like "wool" or "plainborder" or whatever other variant has been enabled (see the following section for details about this)
|
- resulting nodename: "wesh:mesh_test_one_VERSION" where "VERSION" will actually be something like "wool" or "plainborder" or whatever other variant has been enabled (see the following section for details about this)
|
||||||
|
|
||||||
# Using custom textures
|
# Specifying custom properties
|
||||||
In the .dat file of each mesh you'll find something like this:
|
In the .dat file of each mesh you'll find something like this:
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -112,6 +117,8 @@ For example, here we remove all but the "plain" version and add a custom one:
|
||||||
|
|
||||||
Have a look at "wool-72.png" to see where each color goes, or use the included [textures-72.xcf](/textures/textures-72.xcf) file (GIMP format) which has layers for adding the borders as well.
|
Have a look at "wool-72.png" to see where each color goes, or use the included [textures-72.xcf](/textures/textures-72.xcf) file (GIMP format) which has layers for adding the borders as well.
|
||||||
|
|
||||||
|
You can as well override any property you would normally pass to node_register(), such as "walkable", "groups", "collision_box", "selection_box" and so forth. The only property that doesn't get really overridden but just "mangled" according to the variants is the "description" one. You shouldn't even be overriding "tiles" cause they will be built according to the "variants" property (which is specific to this mod).
|
||||||
|
|
||||||
A couple considerations:
|
A couple considerations:
|
||||||
- the bottom-right transparent area never gets used
|
- the bottom-right transparent area never gets used
|
||||||
- the used texture for each face will actually be a bit smaller (in the "wool-72.png" file the squares are 18 pixels in side, but the texture will only use a 16x16 square inside of it)
|
- the used texture for each face will actually be a bit smaller (in the "wool-72.png" file the squares are 18 pixels in side, but the texture will only use a 16x16 square inside of it)
|
||||||
|
|
91
init.lua
91
init.lua
|
@ -219,28 +219,29 @@ function wesh.on_receive_fields(player, formname, fields)
|
||||||
canvas.node = minetest.get_node_or_nil(canvas.pos)
|
canvas.node = minetest.get_node_or_nil(canvas.pos)
|
||||||
if not canvas.node then return end
|
if not canvas.node then return end
|
||||||
|
|
||||||
local canv_size = canvas.node.name:gsub(".*(%d%d)$", "%1")
|
canvas.size = canvas.node.name:gsub(".*(%d%d)$", "%1")
|
||||||
if not canv_size then canv_size = 16 end
|
canvas.size = tonumber(canvas.size)
|
||||||
|
local valid = { [2] = true, [4] = true, [8] = true, [32] = true}
|
||||||
canv_size = tonumber(canv_size)
|
if not valid[canvas.size] then
|
||||||
if canv_size ~= 2 and canv_size ~= 4 and canv_size ~= 8 and canv_size ~= 32 then
|
canvas.size = 16
|
||||||
canv_size = 16
|
|
||||||
end
|
end
|
||||||
|
|
||||||
wesh.save_new_mesh(canvas.pos, canv_size, canvas.facedir, player, fields.meshname)
|
canvas.collision = {}
|
||||||
|
wesh.save_new_mesh(canvas, player, fields.meshname)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function wesh.save_new_mesh(canvas_pos, canv_size, facedir, player, description)
|
function wesh.save_new_mesh(canvas, player, description)
|
||||||
|
|
||||||
-- empty all helper variables
|
-- empty all helper variables
|
||||||
wesh._reset_geometry(canv_size)
|
wesh._reset_geometry(canvas.size)
|
||||||
|
|
||||||
-- read all nodes from the canvas space in the world
|
-- read all nodes from the canvas space in the world
|
||||||
-- extract the colors and put them into a helper matrix of color voxels
|
-- extract the colors and put them into a helper matrix of color voxels
|
||||||
wesh.traverse_matrix(wesh.node_to_voxel, canv_size, canv_size, canvas_pos, facedir)
|
wesh.traverse_matrix(wesh.node_to_voxel, canvas.size, canvas)
|
||||||
|
|
||||||
-- generate faces according to voxels
|
-- generate faces according to voxels
|
||||||
wesh.traverse_matrix(wesh.voxel_to_faces, canv_size, canv_size)
|
wesh.traverse_matrix(wesh.voxel_to_faces, canvas.size, canvas)
|
||||||
|
|
||||||
-- this will be the actual content of the .obj file
|
-- this will be the actual content of the .obj file
|
||||||
local vt_section = wesh.vertex_textures
|
local vt_section = wesh.vertex_textures
|
||||||
|
@ -249,14 +250,14 @@ function wesh.save_new_mesh(canvas_pos, canv_size, facedir, player, description)
|
||||||
local f_section = table.concat(wesh.faces, "\n")
|
local f_section = table.concat(wesh.faces, "\n")
|
||||||
local meshdata = vt_section .. v_section .. vn_section .. f_section
|
local meshdata = vt_section .. v_section .. vn_section .. f_section
|
||||||
|
|
||||||
wesh.save_mesh_to_file(meshdata, description, player)
|
wesh.save_mesh_to_file(meshdata, description, player, canvas)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ========================================================================
|
-- ========================================================================
|
||||||
-- mesh management helpers
|
-- mesh management helpers
|
||||||
-- ========================================================================
|
-- ========================================================================
|
||||||
|
|
||||||
function wesh.save_mesh_to_file(meshdata, description, player)
|
function wesh.save_mesh_to_file(meshdata, description, player, canvas)
|
||||||
local sanitized_meshname = wesh.check_plain(description)
|
local sanitized_meshname = wesh.check_plain(description)
|
||||||
if sanitized_meshname:len() < 3 then
|
if sanitized_meshname:len() < 3 then
|
||||||
wesh.notify(player, "Mesh name too short, try again (min. 3 chars)")
|
wesh.notify(player, "Mesh name too short, try again (min. 3 chars)")
|
||||||
|
@ -289,7 +290,7 @@ function wesh.save_mesh_to_file(meshdata, description, player)
|
||||||
wesh.notify(player, "Unable to write to file '" .. data_filename .. "' from '" .. wesh.temp_path .. "' - error: " .. errmsg)
|
wesh.notify(player, "Unable to write to file '" .. data_filename .. "' from '" .. wesh.temp_path .. "' - error: " .. errmsg)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
file:write(wesh.prepare_data_file(description))
|
file:write(wesh.prepare_data_file(description, canvas))
|
||||||
file:close()
|
file:close()
|
||||||
|
|
||||||
-- save .matrix.dat file
|
-- save .matrix.dat file
|
||||||
|
@ -323,7 +324,9 @@ function wesh.get_all_files()
|
||||||
return all
|
return all
|
||||||
end
|
end
|
||||||
|
|
||||||
function wesh.prepare_data_file(description)
|
function wesh.prepare_data_file(description, canvas)
|
||||||
|
local min = canvas.collision.min
|
||||||
|
local max = canvas.collision.max
|
||||||
local output = [[
|
local output = [[
|
||||||
return {
|
return {
|
||||||
description = ]] .. ("%q"):format(description) .. [[,
|
description = ]] .. ("%q"):format(description) .. [[,
|
||||||
|
@ -333,6 +336,15 @@ return {
|
||||||
wool = "wool-72.png",
|
wool = "wool-72.png",
|
||||||
woolborder = "wool-border-72.png",
|
woolborder = "wool-border-72.png",
|
||||||
},
|
},
|
||||||
|
collision_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {
|
||||||
|
{
|
||||||
|
]] .. min.x .. [[, ]] .. min.y .. [[, ]] .. min.z .. [[,
|
||||||
|
]] .. max.x .. [[, ]] .. max.y .. [[, ]] .. max.z .. [[,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
]]
|
]]
|
||||||
return output
|
return output
|
||||||
|
@ -371,7 +383,7 @@ function wesh._load_mesh(obj_filename)
|
||||||
local nodename = obj_filename:gsub("[^%w]+", "_"):gsub("_obj", "")
|
local nodename = obj_filename:gsub("[^%w]+", "_"):gsub("_obj", "")
|
||||||
|
|
||||||
for variant, tile in pairs(variants) do
|
for variant, tile in pairs(variants) do
|
||||||
minetest.register_node("wesh:" .. nodename .. "_" .. variant, {
|
local props = {
|
||||||
drawtype = "mesh",
|
drawtype = "mesh",
|
||||||
mesh = obj_filename,
|
mesh = obj_filename,
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
|
@ -379,7 +391,16 @@ function wesh._load_mesh(obj_filename)
|
||||||
tiles = { tile },
|
tiles = { tile },
|
||||||
walkable = true,
|
walkable = true,
|
||||||
groups = { dig_immediate = 3 },
|
groups = { dig_immediate = 3 },
|
||||||
})
|
}
|
||||||
|
for prop, value in pairs(data) do
|
||||||
|
if prop ~= "variants" and prop ~= "description" then
|
||||||
|
props[prop] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if props.collision_box and not props.selection_box then
|
||||||
|
props.selection_box = props.collision_box
|
||||||
|
end
|
||||||
|
minetest.register_node("wesh:" .. nodename .. "_" .. variant, props)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -387,6 +408,31 @@ end
|
||||||
-- mesh generation helpers
|
-- mesh generation helpers
|
||||||
-- ========================================================================
|
-- ========================================================================
|
||||||
|
|
||||||
|
function wesh.update_collision_bounds(rel_pos, canvas)
|
||||||
|
local min = {}
|
||||||
|
local max = {}
|
||||||
|
min.x = (rel_pos.x - 1) / canvas.size - 0.5
|
||||||
|
min.y = (rel_pos.y - 1) / canvas.size - 0.5
|
||||||
|
min.z = (rel_pos.z - 1) / canvas.size - 0.5
|
||||||
|
max.x = rel_pos.x / canvas.size - 0.5
|
||||||
|
max.y = rel_pos.y / canvas.size - 0.5
|
||||||
|
max.z = rel_pos.z / canvas.size - 0.5
|
||||||
|
if not canvas.collision.min then
|
||||||
|
canvas.collision.min = min
|
||||||
|
else
|
||||||
|
canvas.collision.min.x = math.min(min.x, canvas.collision.min.x)
|
||||||
|
canvas.collision.min.y = math.min(min.y, canvas.collision.min.y)
|
||||||
|
canvas.collision.min.z = math.min(min.z, canvas.collision.min.z)
|
||||||
|
end
|
||||||
|
if not canvas.collision.max then
|
||||||
|
canvas.collision.max = max
|
||||||
|
else
|
||||||
|
canvas.collision.max.x = math.max(max.x, canvas.collision.max.x)
|
||||||
|
canvas.collision.max.y = math.max(max.y, canvas.collision.max.y)
|
||||||
|
canvas.collision.max.z = math.max(max.z, canvas.collision.max.z)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function wesh.construct_face(rel_pos, canv_size, texture_vertices, facename, vertices, normal_index)
|
function wesh.construct_face(rel_pos, canv_size, texture_vertices, facename, vertices, normal_index)
|
||||||
local normal = wesh.face_normals[normal_index]
|
local normal = wesh.face_normals[normal_index]
|
||||||
local hider_pos = vector.add(rel_pos, normal)
|
local hider_pos = vector.add(rel_pos, normal)
|
||||||
|
@ -443,18 +489,21 @@ function wesh.transform(facedir, pos)
|
||||||
return (wesh._transfunc[facedir + 1] or wesh._transfunc[1])(pos)
|
return (wesh._transfunc[facedir + 1] or wesh._transfunc[1])(pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
function wesh.node_to_voxel(rel_pos, canv_size, canvas_pos, facedir)
|
function wesh.node_to_voxel(rel_pos, canvas)
|
||||||
local abs_pos = wesh.make_absolute(canvas_pos, canv_size, facedir, rel_pos)
|
local abs_pos = wesh.make_absolute(canvas.pos, canvas.size, canvas.facedir, rel_pos)
|
||||||
local color = wesh.get_node_color(abs_pos)
|
local color = wesh.get_node_color(abs_pos)
|
||||||
|
if color ~= "air" then
|
||||||
|
wesh.update_collision_bounds(rel_pos, canvas)
|
||||||
|
end
|
||||||
wesh.set_voxel_color(rel_pos, color)
|
wesh.set_voxel_color(rel_pos, color)
|
||||||
end
|
end
|
||||||
|
|
||||||
function wesh.voxel_to_faces(rel_pos, canv_size)
|
function wesh.voxel_to_faces(rel_pos, canvas)
|
||||||
local color = wesh.get_voxel_color(rel_pos)
|
local color = wesh.get_voxel_color(rel_pos)
|
||||||
if color == "air" then return end
|
if color == "air" then return end
|
||||||
for facename, facedata in pairs(wesh.face_construction) do
|
for facename, facedata in pairs(wesh.face_construction) do
|
||||||
local texture_vertices = wesh.get_texture_vertices(color)
|
local texture_vertices = wesh.get_texture_vertices(color)
|
||||||
wesh.construct_face(rel_pos, canv_size, texture_vertices, facename, facedata.vertices, facedata.normal)
|
wesh.construct_face(rel_pos, canvas.size, texture_vertices, facename, facedata.vertices, facedata.normal)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 393 KiB |
Loading…
Reference in New Issue