-
Notifications
You must be signed in to change notification settings - Fork 10
/
build_chest_preview_image.lua
250 lines (226 loc) · 7.28 KB
/
build_chest_preview_image.lua
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
build_chest.preview_image_draw_tile = function( content_id, image, x, z, dx, dz, tile_nr )
if( not( image )) then
local node_name = minetest.get_name_from_content_id( content_id );
if( not( node_name )) then
return '';
end
local node_def = handle_schematics.node_defined( node_name );
if( not( node_def )) then
return '';
end
local tiles = node_def.tiles;
if( not( tiles ) and node_def.tile_images) then
tiles = node_def.tile_images;
end
local tile = nil;
if( tiles ~= nil ) then
if( not(tile_nr) or tile_nr > #tiles or tile_nr < 1 ) then
tile_nr = 1;
end
tile = tiles[tile_nr];
end
if type(tile)=="table" then
tile=tile["name"]
end
image = tile;
if( not( image )) then
image = "unknown_object.png";
end
end
return "image["..tostring(x)..",".. tostring(z) ..";"..dx..','..dz..";" .. image .."]";
end
-- creates a 2d preview image (or rather, the data structure for it) of the building
-- internal function
build_chest.preview_image_create_one_view = function( data, side )
local params = {1, data.size.x, 1, 1, data.size.z, 1, 0, 0};
if( side==1 ) then
params = {1, data.size.x, 1, 1, data.size.z, 1, 0, 0};
elseif( side==2 ) then
params = {1, data.size.z, 1, 1, data.size.x, 1, 1, 1};
elseif( side==3 ) then
params = {1, data.size.x, 1, data.size.z, 0, -1, 0, 1};
elseif( side==4 ) then
params = {1, data.size.z, 1, data.size.x, 0, -1, 1, 0};
end
-- do not create preview images for buildings that are too big
if( params[2] * params[4] > 2500 ) then
return nil;
end
local preview = {};
for y = 1, data.size.y do
preview[ y ] = {};
for x = params[1], params[2], params[3] do
local found = nil;
local z = params[4];
local target_x = x;
if( params[8]==1 ) then
target_x = math.max( params[1],params[2] )- x+1;
end
while( not( found ) and z~= params[5]) do
local node = -1;
if( params[7]==0 ) then
node = data.scm_data_cache[y][x][z];
else
node = data.scm_data_cache[y][z][x];
end
if( node and node[1]
and data.nodenames[ node[1] ]
and data.nodenames[ node[1] ] ~= 'air'
and data.nodenames[ node[1] ] ~= 'ignore'
and data.nodenames[ node[1] ] ~= 'mg:ignore'
and data.nodenames[ node[1] ] ~= 'default:torch' ) then
-- a preview node is only set if there's no air there
preview[y][target_x] = node[1];
found = 1;
end
z = z+params[6];
end
if( not( found )) then
preview[y][target_x] = -1;
end
end
end
return preview;
end
-- internal function
build_chest.preview_image_create_view_from_top = function( data, y_top )
-- no view from top if the image is too big
if( data.size.z * data.size.y > 2500 ) then
return nil;
end
local preview = {};
for z = 1, data.size.z do
preview[ z ] = {};
for x = 1, data.size.x do
local found = nil;
local y = y_top;
while( not( found ) and y > 0) do
local node = data.scm_data_cache[y][x][z];
if( node and node[1]
and data.nodenames[ node[1] ]
and data.nodenames[ node[1] ] ~= 'air'
and data.nodenames[ node[1] ] ~= 'ignore'
and data.nodenames[ node[1] ] ~= 'mg:ignore'
and data.nodenames[ node[1] ] ~= 'default:torch' ) then
-- a preview node is only set if there's no air there
preview[z][x] = node[1];
found = 1;
end
y = y-1;
end
if( not( found )) then
preview[z][x] = -1;
end
end
end
return preview;
end
-- function called by the build chest to display one view
build_chest.preview_image_formspec = function( building_name, replacements, side_name )
if( not( building_name )
or not( build_chest.building[ building_name ] )
or not( build_chest.building[ building_name ].preview )) then
return "";
end
local side_names = {"front","right","back","left","top","floor"};
local side = 1;
for i,v in ipairs( side_names ) do
if( side_name and side_name==v ) then
side = i;
end
end
local formspec = "";
for i=1,#side_names do
if( i ~= side ) then
formspec = formspec.."button["..tostring(3.3+1.2*(i-1))..
",2.2;1,0.5;preview;"..side_names[i].."]";
else
formspec = formspec.."label["..tostring(3.3+1.2*(i-1))..",2.2;"..side_names[i].."]";
end
end
local data = build_chest.building[ building_name ];
-- the draw_tile function is based on content_id
local content_ids = {};
for i,v in ipairs( data.nodenames ) do
local found = false;
for j,w in ipairs( replacements ) do
if( w and w[1] and w[1]==v) then
found = true;
if( handle_schematics.node_defined( w[2] )) then
content_ids[ i ] = minetest.get_content_id( w[2] );
end
end
end
if( not( found )) then
if( handle_schematics.node_defined( v )) then
content_ids[ i ] = minetest.get_content_id( v );
elseif( v ~= 'air' ) then
content_ids[ i ] = -1;
end
end
end
local scale = 0.5;
local tile_nr = 6; -- view that works best with roofs and the like
if( side ~= 5 and side ~= 6) then
local scale_y = 6.0/data.size.y;
local scale_z = 10.0/data.size.z;
if( scale_y > scale_z) then
scale = scale_z;
else
scale = scale_y;
end
else
local scale_x = 10.0/data.size.x; -- only relevant for view from top
local scale_z = 6.0/data.size.z;
if( scale_x > scale_z) then
scale = scale_z;
else
scale = scale_x;
end
tile_nr = 1; -- view from top
end
if( not( side )) then
side = 1;
end
local preview = data.preview[ side ];
if( not( preview )) then
formspec = formspec.."label[3,3;Sorry, this schematic is too big for a preview image.]";
return formspec;
end
for y,y_values in ipairs( preview ) do
for l,v in ipairs( y_values ) do
-- air, ignore and mg:ignore are not stored
if( v and content_ids[ v ]==-1 ) then
formspec = formspec..build_chest.preview_image_draw_tile( nil, "unknown_node.png", (l*scale), 9-(y*scale), scale*1.3, scale*1.2, tile_nr);
elseif( v and v>0 and content_ids[v]) then
formspec = formspec..build_chest.preview_image_draw_tile( content_ids[ v ], nil, (l*scale), 9-(y*scale), scale*1.3, scale*1.2, tile_nr);
end
end
end
return formspec;
end
-- create all five preview images
build_chest.preview_image_create_views = function( res, orients )
-- create a 2d overview image (or rather, the data structure for it)
local preview = {
build_chest.preview_image_create_one_view( res, 2 ),
build_chest.preview_image_create_one_view( res, 1 ),
build_chest.preview_image_create_one_view( res, 4 ),
build_chest.preview_image_create_one_view( res, 3 )};
-- the building might be stored in rotated form
if( res and res.rotated) then
if( res.rotated and res.rotated==90) then
preview = {preview[2],preview[3],preview[4],preview[1]};
elseif( res.rotated and res.rotated==180) then
preview = {preview[3],preview[4],preview[1],preview[2]};
elseif( res.rotated and res.rotated==270) then
preview = {preview[4],preview[1],preview[2],preview[3]};
end
end
-- ...and add a preview image from top
preview[5] = build_chest.preview_image_create_view_from_top( res, res.size.y );
-- add the floor plan (the node at ground level and the node one above ground level are of intrest)
preview[6] = build_chest.preview_image_create_view_from_top( res, math.min(2-res.yoff, res.size.y));
return preview;
end
-- this function makes sure that the building will always extend to the right and in front of the build chest