2 Tool to import sections of minecraft levels into Cura.
3 This makes use of the pymclevel module from David Rio Vierra
5 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
12 from Cura.util import printableObject
13 from Cura.util.meshLoaders import stl
14 from Cura.util.pymclevel import mclevel
17 return os.path.isdir(mclevel.saveFileDir)
19 class minecraftImportWindow(wx.Frame):
20 def __init__(self, parent):
21 super(minecraftImportWindow, self).__init__(parent, title='Cura - Minecraft import')
23 saveFileList = map(os.path.basename, glob.glob(mclevel.saveFileDir + "/*"))
25 self.panel = wx.Panel(self, -1)
26 self.SetSizer(wx.BoxSizer())
27 self.GetSizer().Add(self.panel, 1, wx.EXPAND)
29 sizer = wx.GridBagSizer(2, 2)
31 self.saveListBox = wx.ListBox(self.panel, -1, choices=saveFileList)
32 sizer.Add(self.saveListBox, (0,0), span=(2,1), flag=wx.EXPAND)
33 self.playerListBox = wx.ListBox(self.panel, -1, choices=[])
34 sizer.Add(self.playerListBox, (0,1), span=(2,1), flag=wx.EXPAND)
36 self.previewPanel = wx.Panel(self.panel, -1)
37 self.previewPanel.SetMinSize((512, 512))
38 sizer.Add(self.previewPanel, (0,2), flag=wx.EXPAND)
40 self.importButton = wx.Button(self.panel, -1, 'Import')
41 sizer.Add(self.importButton, (1,2))
43 sizer.AddGrowableRow(1)
45 self.panel.SetSizer(sizer)
47 self.saveListBox.Bind(wx.EVT_LISTBOX, self.OnSaveSelect)
48 self.playerListBox.Bind(wx.EVT_LISTBOX, self.OnPlayerSelect)
49 self.importButton.Bind(wx.EVT_BUTTON, self.OnImport)
51 self.previewPanel.Bind(wx.EVT_PAINT, self.OnPaintPreview)
52 self.previewPanel.Bind(wx.EVT_SIZE, self.OnSizePreview)
53 self.previewPanel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackgroundPreview)
54 self.previewPanel.Bind(wx.EVT_MOTION, self.OnMotion)
57 self.previewImage = None
59 self.selectArea = None
60 self.draggingArea = False
65 self.gravelPen = wx.Pen(wx.Colour(128, 128, 128))
66 self.sandPen = wx.Pen(wx.Colour(192, 192, 0))
69 for z in xrange(0, 256):
70 self.waterPen.append(wx.Pen(wx.Colour(0,0,min(z+64, 255))))
71 self.grassPen.append(wx.Pen(wx.Colour(0,min(64+z,255),0)))
73 self.isSolid = [True] * 256
74 self.isSolid[0] = False #Air
75 self.isSolid[8] = False #Water
76 self.isSolid[9] = False #Water
77 self.isSolid[10] = False #Lava
78 self.isSolid[11] = False #Lava
79 self.isSolid[50] = False #Torch
80 self.isSolid[51] = False #Fire
82 def OnSaveSelect(self, e):
83 if self.saveListBox.Selection < 0:
85 self.level = mclevel.loadWorld(self.saveListBox.GetItems()[self.saveListBox.Selection])
86 self.playerListBox.Clear()
87 for player in self.level.players:
88 self.playerListBox.Append(player)
90 def OnPlayerSelect(self, e):
91 playerName = self.playerListBox.GetItems()[self.playerListBox.Selection]
92 self.playerPos = map(lambda n: int(n / 16), self.level.getPlayerPosition(playerName))[0::2]
94 self.previewImage = wx.EmptyBitmap(512, 512)
95 for i in xrange(0, 16):
96 for j in xrange(1, i * 2 + 1):
97 self.renderList.insert(0, (15 - i, 16 + i - j))
98 for j in xrange(0, i * 2 + 1):
99 self.renderList.insert(0, (15 + j - i, 15 - i))
100 for j in xrange(0, i * 2 + 1):
101 self.renderList.insert(0, (16 + i, 15 + j - i))
102 for j in xrange(0, i * 2 + 2):
103 self.renderList.insert(0, (16 + i - j, 16 + i))
104 self.previewPanel.Refresh()
106 def OnPaintPreview(self, e):
107 if len(self.renderList) > 0:
108 cx, cy = self.renderList.pop()
110 dc.SelectObject(self.previewImage)
111 chunk = self.level.getChunk(cx + self.playerPos[0] - 16, cy + self.playerPos[1] - 16)
112 dc.SetPen(wx.Pen(wx.Colour(255,0,0)))
113 for x in xrange(0, 16):
114 for y in xrange(0, 16):
115 z = numpy.max(numpy.where(chunk.Blocks[x, y] != 0))
116 type = chunk.Blocks[x, y, z]
118 dc.SetPen(wx.Pen(wx.Colour(z,z,z)))
119 elif type == 2: #Grass
120 dc.SetPen(self.grassPen[z])
121 elif type == 8 or type == 9: #Water
122 dc.SetPen(self.waterPen[z])
123 elif type == 10 or type == 11: #Lava
124 dc.SetPen(wx.Pen(wx.Colour(min(z+64, 255),0,0)))
125 elif type == 12 or type == 24: #Sand/Standstone
126 dc.SetPen(self.sandPen)
127 elif type == 13: #Gravel
128 dc.SetPen(self.gravelPen)
129 elif type == 18: #Leaves
130 dc.SetPen(wx.Pen(wx.Colour(0,max(z-32, 0),0)))
132 dc.SetPen(wx.Pen(wx.Colour(z,z,z)))
133 dc.DrawPoint(cx * 16 + x, cy * 16 + y)
134 dc.SelectObject(wx.NullBitmap)
135 wx.CallAfter(self.previewPanel.Refresh)
137 dc = wx.BufferedPaintDC(self.previewPanel)
138 dc.SetBackground(wx.Brush(wx.BLACK))
140 if self.previewImage is not None:
141 dc.DrawBitmap(self.previewImage, 0, 0)
142 if self.selectArea is not None:
143 dc.SetPen(wx.Pen(wx.Colour(255,0,0)))
144 dc.SetBrush(wx.Brush(None, style=wx.TRANSPARENT))
145 dc.DrawRectangle(self.selectArea[0], self.selectArea[1], self.selectArea[2] - self.selectArea[0] + 1, self.selectArea[3] - self.selectArea[1] + 1)
147 def OnSizePreview(self, e):
148 self.previewPanel.Refresh()
149 self.previewPanel.Update()
151 def OnEraseBackgroundPreview(self, e):
154 def OnMotion(self, e):
156 if not self.draggingArea:
157 self.draggingArea = True
158 self.selectArea = [e.GetX(), e.GetY(), e.GetX(), e.GetY()]
159 self.selectArea[2] = e.GetX()
160 self.selectArea[3] = e.GetY()
161 self.previewPanel.Refresh()
163 self.draggingArea = False
165 def OnImport(self, e):
166 if self.level is None or self.selectArea is None:
169 xMin = min(self.selectArea[0], self.selectArea[2]) + (self.playerPos[0] - 16) * 16
170 xMax = max(self.selectArea[0], self.selectArea[2]) + (self.playerPos[0] - 16) * 16
171 yMin = min(self.selectArea[1], self.selectArea[3]) + (self.playerPos[1] - 16) * 16
172 yMax = max(self.selectArea[1], self.selectArea[3]) + (self.playerPos[1] - 16) * 16
174 sx = (xMax - xMin + 1)
175 sy = (yMax - yMin + 1)
176 blocks = numpy.zeros((sx, sy, 256), numpy.int32)
178 cxMin = int(xMin / 16)
179 cxMax = int((xMax + 15) / 16)
180 cyMin = int(yMin / 16)
181 cyMax = int((yMax + 15) / 16)
183 for cx in xrange(cxMin, cxMax + 1):
184 for cy in xrange(cyMin, cyMax + 1):
185 chunk = self.level.getChunk(cx, cy)
186 for x in xrange(0, 16):
188 if xMin <= bx <= xMax:
189 for y in xrange(0, 16):
191 if yMin <= by <= yMax:
192 blocks[bx - xMin, by - yMin] = chunk.Blocks[x, y]
195 for x in xrange(0, sx):
196 for y in xrange(0, sy):
197 minZ = min(minZ, numpy.max(numpy.where(blocks[x, y] != 0)))
198 maxZ = max(maxZ, numpy.max(numpy.where(blocks[x, y] != 0)))
202 for x in xrange(0, sx):
203 for y in xrange(0, sy):
204 for z in xrange(minZ, maxZ + 1):
205 if self.isSolid[blocks[x, y, z]]:
206 if z == maxZ or not self.isSolid[blocks[x, y, z + 1]]:
208 if z == minZ or not self.isSolid[blocks[x, y, z - 1]]:
210 if x == 0 or not self.isSolid[blocks[x - 1, y, z]]:
212 if x == sx - 1 or not self.isSolid[blocks[x + 1, y, z]]:
214 if y == 0 or not self.isSolid[blocks[x, y - 1, z]]:
216 if y == sy - 1 or not self.isSolid[blocks[x, y + 1, z]]:
219 obj = printableObject.printableObject(None)
221 m._prepareFaceCount(faceCount * 2)
222 for x in xrange(0, sx):
223 for y in xrange(0, sy):
224 for z in xrange(minZ, maxZ + 1):
225 if self.isSolid[blocks[x, y, z]]:
226 if z == maxZ or not self.isSolid[blocks[x, y, z + 1]]:
227 m._addFace(x, y, z+1, x+1, y, z+1, x, y+1, z+1)
229 m._addFace(x+1, y+1, z+1, x, y+1, z+1, x+1, y, z+1)
231 if z == minZ or not self.isSolid[blocks[x, y, z - 1]]:
232 m._addFace(x, y, z, x, y+1, z, x+1, y, z)
234 m._addFace(x+1, y+1, z, x+1, y, z, x, y+1, z)
236 if x == 0 or not self.isSolid[blocks[x - 1, y, z]]:
237 m._addFace(x, y, z, x, y, z+1, x, y+1, z)
239 m._addFace(x, y+1, z+1, x, y+1, z, x, y, z+1)
241 if x == sx - 1 or not self.isSolid[blocks[x + 1, y, z]]:
242 m._addFace(x+1, y, z, x+1, y+1, z, x+1, y, z+1)
244 m._addFace(x+1, y+1, z+1, x+1, y, z+1, x+1, y+1, z)
246 if y == 0 or not self.isSolid[blocks[x, y - 1, z]]:
247 m._addFace(x, y, z, x+1, y, z, x, y, z+1)
249 m._addFace(x+1, y, z+1, x, y, z+1, x+1, y, z)
251 if y == sy - 1 or not self.isSolid[blocks[x, y + 1, z]]:
252 m._addFace(x, y+1, z, x, y+1, z+1, x+1, y+1, z)
254 m._addFace(x+1, y+1, z+1, x+1, y+1, z, x, y+1, z+1)
256 obj._postProcessAfterLoad()
257 self.GetParent().scene._scene.add(obj)