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 structure
master
entuland 2018-06-02 17:58:57 +02:00
parent 0ead6905fe
commit 1f45d74322
3 changed files with 78 additions and 22 deletions

View File

@ -74,6 +74,11 @@ By default, four versions of each mesh will be available:
Sample of natural terrain capture:
![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".
![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 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:
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.
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:
- 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)

View File

@ -219,28 +219,29 @@ function wesh.on_receive_fields(player, formname, fields)
canvas.node = minetest.get_node_or_nil(canvas.pos)
if not canvas.node then return end
local canv_size = canvas.node.name:gsub(".*(%d%d)$", "%1")
if not canv_size then canv_size = 16 end
canv_size = tonumber(canv_size)
if canv_size ~= 2 and canv_size ~= 4 and canv_size ~= 8 and canv_size ~= 32 then
canv_size = 16
canvas.size = canvas.node.name:gsub(".*(%d%d)$", "%1")
canvas.size = tonumber(canvas.size)
local valid = { [2] = true, [4] = true, [8] = true, [32] = true}
if not valid[canvas.size] then
canvas.size = 16
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
function wesh.save_new_mesh(canvas_pos, canv_size, facedir, player, description)
function wesh.save_new_mesh(canvas, player, description)
-- empty all helper variables
wesh._reset_geometry(canv_size)
wesh._reset_geometry(canvas.size)
-- read all nodes from the canvas space in the world
-- 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
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
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 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
-- ========================================================================
-- 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)
if sanitized_meshname:len() < 3 then
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)
return
end
file:write(wesh.prepare_data_file(description))
file:write(wesh.prepare_data_file(description, canvas))
file:close()
-- save .matrix.dat file
@ -323,7 +324,9 @@ function wesh.get_all_files()
return all
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 = [[
return {
description = ]] .. ("%q"):format(description) .. [[,
@ -333,6 +336,15 @@ return {
wool = "wool-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
@ -371,7 +383,7 @@ function wesh._load_mesh(obj_filename)
local nodename = obj_filename:gsub("[^%w]+", "_"):gsub("_obj", "")
for variant, tile in pairs(variants) do
minetest.register_node("wesh:" .. nodename .. "_" .. variant, {
local props = {
drawtype = "mesh",
mesh = obj_filename,
paramtype2 = "facedir",
@ -379,7 +391,16 @@ function wesh._load_mesh(obj_filename)
tiles = { tile },
walkable = true,
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
@ -387,6 +408,31 @@ end
-- 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)
local normal = wesh.face_normals[normal_index]
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)
end
function wesh.node_to_voxel(rel_pos, canv_size, canvas_pos, facedir)
local abs_pos = wesh.make_absolute(canvas_pos, canv_size, facedir, rel_pos)
function wesh.node_to_voxel(rel_pos, canvas)
local abs_pos = wesh.make_absolute(canvas.pos, canvas.size, canvas.facedir, rel_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)
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)
if color == "air" then return end
for facename, facedata in pairs(wesh.face_construction) do
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 KiB