aboutsummaryrefslogtreecommitdiff
path: root/src/wieldmesh.h
blob: d3946b4e09f0f3420799aa1d312e8cfd46f3b0de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
Minetest
Copyright (C) 2010-2014 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef WIELDMESH_HEADER
#define WIELDMESH_HEADER

#include <string>
#include "irrlichttypes_extrabloated.h"

struct ItemStack;
class Client;
class ITextureSource;
struct TileSpec;

struct ItemMesh
{
	scene::IMesh *mesh;
	/*!
	 * Stores the color of each mesh buffer.
	 * If the boolean is true, the color is fixed, else
	 * palettes can modify it.
	 */
	std::vector<std::pair<bool, video::SColor> > buffer_colors;

	ItemMesh() : mesh(NULL), buffer_colors() {}
};

/*
	Wield item scene node, renders the wield mesh of some item
*/
class WieldMeshSceneNode : public scene::ISceneNode
{
public:
	WieldMeshSceneNode(scene::ISceneNode *parent, scene::ISceneManager *mgr,
			s32 id = -1, bool lighting = false);
	virtual ~WieldMeshSceneNode();

	void setCube(const TileSpec tiles[6], v3f wield_scale, ITextureSource *tsrc);
	void setExtruded(const std::string &imagename, v3f wield_scale,
			ITextureSource *tsrc, u8 num_frames);
	void setItem(const ItemStack &item, Client *client);

	// Sets the vertex color of the wield mesh.
	// Must only be used if the constructor was called with lighting = false
	void setColor(video::SColor color);

	scene::IMesh *getMesh() { return m_meshnode->getMesh(); }

	virtual void render();

	virtual const aabb3f &getBoundingBox() const { return m_bounding_box; }

private:
	void changeToMesh(scene::IMesh *mesh);

	// Child scene node with the current wield mesh
	scene::IMeshSceneNode *m_meshnode;
	video::E_MATERIAL_TYPE m_material_type;

	// True if EMF_LIGHTING should be enabled.
	bool m_lighting;

	bool m_enable_shaders;
	bool m_anisotropic_filter;
	bool m_bilinear_filter;
	bool m_trilinear_filter;
	/*!
	 * Stores the colors of the mesh's mesh buffers.
	 * This does not include lighting.
	 */
	std::vector<video::SColor> m_colors;

	// Bounding box culling is disabled for this type of scene node,
	// so this variable is just required so we can implement
	// getBoundingBox() and is set to an empty box.
	aabb3f m_bounding_box;
};

void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result);

scene::IMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename);
#endif
num">16).."_"..((conns.conn1+4*i)%16)]={name=nodename, param2=i} end tp.tracks[nnprefix].modify[nodename]=true end function tp.add_single_conn(nnprefix, suffix, rotation, conns) local nodename=nnprefix.."_"..suffix..rotation for i=0,3 do tp.tracks[nnprefix].single_conn[((conns.conn1+4*i)%16)]={name=nodename, param2=i} tp.tracks[nnprefix].single_conn[((conns.conn2+4*i)%16)]={name=nodename, param2=i} end tp.tracks[nnprefix].modify[nodename]=true end function tp.add_worked(nnprefix, suffix, rotation, cycle_follows) tp.tracks[nnprefix].twcycle[suffix]=cycle_follows if not tp.tracks[nnprefix].twrotate[suffix] then tp.tracks[nnprefix].twrotate[suffix]={} end table.insert(tp.tracks[nnprefix].twrotate[suffix], rotation) end --[[ rewrite algorithm. selection criteria: these will never be changed or even selected: - tracks being already connected on both sides - tracks that are already connected on one side but are not bendable to the desired position the following situations can occur: 1. there are two more than two rails around 1.1 there is one or more subset(s) that can be directly connected -> choose the first possibility 2.2 not -> choose the first one and orient straight 2. there's exactly 1 rail around -> choose and orient straight 3. there's no rail around -> set straight ]] function tp.find_already_connected(pos)--TODO vertical calculations(check node below) local function istrackandbc(pos, conn) local cnode=minetest.get_node(advtrains.dirCoordSet(pos, conn)) local bconn=(conn+8)%16 if advtrains.is_track_and_drives_on(cnode.name, advtrains.all_tracktypes) then local cconn1, cconn2=advtrains.get_track_connections(cnode.name, cnode.param2) return cconn1==bconn or cconn2==bconn end return false end local dnode=minetest.get_node(pos) local dconn1, dconn2=advtrains.get_track_connections(dnode.name, dnode.param2) local t={[true]="true", [false]="false"} if istrackandbc(pos, dconn1) and istrackandbc(pos, dconn2) then return dconn1, dconn2 elseif istrackandbc(pos, dconn1) then return dconn1 elseif istrackandbc(pos, dconn2) then return dconn2 end return nil end function tp.rail_and_can_be_bent(originpos, conn, nnpref) local pos=advtrains.dirCoordSet(originpos, conn) local newdir=(conn+8)%16 local node=minetest.get_node(pos) local tr=tp.tracks[nnpref] if not advtrains.is_track_and_drives_on(node.name, advtrains.all_tracktypes) then return false end --rail at other end? local adj1, adj2=tp.find_already_connected(pos) if adj1 and adj2 then return false--dont destroy existing track elseif adj1 and not adj2 then if tr.double_conn[adj1.."_"..newdir] then return true--if exists, connect new rail and old end end return false else if tr.single_conn[newdir] then--just rotate old rail to right orientation return true end return false end end function tp.bend_rail(originpos, conn, nnpref) local pos=advtrains.dirCoordSet(originpos, conn) local newdir=(conn+8)%16 local node=minetest.get_node(pos) local tr=tp.tracks[nnpref] --is rail already connected? no need to bend. local conn1, conn2=advtrains.get_track_connections(node.name, node.param2) if newdir==conn1 or newdir==conn2 then return end --rail at other end? local adj1, adj2=tp.find_already_connected(pos) if adj1 and adj2 then return false--dont destroy existing track elseif adj1 and not adj2 then if tr.double_conn[adj1.."_"..newdir] then minetest.set_node(pos, tr.double_conn[adj1.."_"..newdir]) return true--if exists, connect new rail and old end end return false else if tr.single_conn[newdir] then--just rotate old rail to right orientation minetest.set_node(pos, tr.single_conn[newdir]) return true end return false end end function tp.placetrack(pos, nnpref) --1. find all rails that are likely to be connected local tr=tp.tracks[nnpref] local p_rails={} for i=0,15 do if tp.rail_and_can_be_bent(pos, i, nnpref) then p_rails[#p_rails+1]=i end end if #p_rails==0 then minetest.set_node(pos, {name=nnpref.."_"..tr.default}) elseif #p_rails==1 then tp.bend_rail(pos, p_rails[1], nnpref) minetest.set_node(pos, tr.single_conn[p_rails[1]]) else --iterate subsets for k1, conn1 in ipairs(p_rails) do for k2, conn2 in ipairs(p_rails) do if k1~=k2 then if (tr.double_conn[conn1.."_"..conn2]) then tp.bend_rail(pos, conn1, nnpref) tp.bend_rail(pos, conn2, nnpref) minetest.set_node(pos, tr.double_conn[conn1.."_"..conn2]) return end end end end --not found tp.bend_rail(pos, p_rails[1], nnpref) minetest.set_node(pos, tr.single_conn[p_rails[1]]) end end function tp.register_track_placer(nnprefix, imgprefix, dispname) minetest.register_craftitem(nnprefix.."_placer",{ description = dispname, inventory_image = imgprefix.."_placer.png", wield_image = imgprefix.."_placer.png", groups={}, on_place = function(itemstack, placer, pointed_thing) local name = placer:get_player_name() if not name then return itemstack end if pointed_thing.type=="node" then local pos=pointed_thing.above local upos=pointed_thing.under if minetest.is_protected(pos,name) and minetest.is_protected(upos,name) then return itemstack end if minetest.registered_nodes[minetest.get_node(pos).name] and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to and minetest.registered_nodes[minetest.get_node(upos).name] and minetest.registered_nodes[minetest.get_node(upos).name].walkable then tp.placetrack(pos, nnprefix) if not minetest.setting_getbool("creative_mode") then itemstack:take_item() end end end return itemstack end, }) end minetest.register_craftitem("advtrains:trackworker",{ description = "Track Worker Tool\n\nLeft-click: change rail type (straight/curve/switch)\nRight-click: rotate rail/bumper/signal/etc.", groups = {cracky=1}, -- key=name, value=rating; rating=1..3. inventory_image = "advtrains_trackworker.png", wield_image = "advtrains_trackworker.png", stack_max = 1, on_place = function(itemstack, placer, pointed_thing) local name = placer:get_player_name() if not name then return end if pointed_thing.type=="node" then local pos=pointed_thing.under if minetest.is_protected(pos, name) then return end local node=minetest.get_node(pos) --if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end if advtrains.is_train_at_pos(pos) then return end local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$") --print(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation) if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$") rotation = "" if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then minetest.chat_send_player(placer:get_player_name(), "This node can't be rotated using the trackworker!") return end end local modext=tp.tracks[nnprefix].twrotate[suffix] if rotation==modext[#modext] then --increase param2 minetest.set_node(pos, {name=nnprefix.."_"..suffix..modext[1], param2=(node.param2+1)%4}) return else local modpos for k,v in pairs(modext) do if v==rotation then modpos=k end end if not modpos then minetest.chat_send_player(placer:get_player_name(), "This node can't be rotated using the trackworker!") return end minetest.set_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2}) end advtrains.invalidate_all_paths() end end, on_use=function(itemstack, user, pointed_thing) local name = user:get_player_name() if not name then return end if pointed_thing.type=="node" then local pos=pointed_thing.under local node=minetest.get_node(pos) if minetest.is_protected(pos, name) then return end --if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end if advtrains.is_train_at_pos(pos) then return end local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$") --print(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation) if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$") rotation = "" if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then minetest.chat_send_player(user:get_player_name(), "This node can't be changed using the trackworker!") return end end local nextsuffix=tp.tracks[nnprefix].twcycle[suffix] minetest.set_node(pos, {name=nnprefix.."_"..nextsuffix..rotation, param2=node.param2}) --invalidate trains advtrains.invalidate_all_paths() else print(name, dump(tp.tracks)) end end, }) --putting into right place advtrains.trackplacer=tp