chiark / gitweb /
8de170129604d65e853d46f331bdcaab51b7d1f7
[cura.git] / Cura / gui / tools / minecraftImport.py
1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
3
4 import wx
5 import glob
6 import os
7 import numpy
8
9 from Cura.util import mesh
10 from Cura.util.meshLoaders import stl
11 from Cura.util.pymclevel import mclevel
12
13 def hasMinecraft():
14         return os.path.isdir(mclevel.saveFileDir)
15
16 class minecraftImportWindow(wx.Frame):
17         def __init__(self, parent):
18                 super(minecraftImportWindow, self).__init__(parent, title='Cura - Minecraft import')
19
20                 saveFileList = map(os.path.basename, glob.glob(mclevel.saveFileDir + "/*"))
21
22                 self.panel = wx.Panel(self, -1)
23                 self.SetSizer(wx.BoxSizer())
24                 self.GetSizer().Add(self.panel, 1, wx.EXPAND)
25
26                 sizer = wx.GridBagSizer(2, 2)
27
28                 self.saveListBox = wx.ListBox(self.panel, -1, choices=saveFileList)
29                 sizer.Add(self.saveListBox, (0,0), span=(2,1), flag=wx.EXPAND)
30                 self.playerListBox = wx.ListBox(self.panel, -1, choices=[])
31                 sizer.Add(self.playerListBox, (0,1), span=(2,1), flag=wx.EXPAND)
32
33                 self.previewPanel = wx.Panel(self.panel, -1)
34                 self.previewPanel.SetMinSize((512, 512))
35                 sizer.Add(self.previewPanel, (0,2), flag=wx.EXPAND)
36
37                 self.importButton = wx.Button(self.panel, -1, 'Import')
38                 sizer.Add(self.importButton, (1,2))
39
40                 sizer.AddGrowableRow(1)
41
42                 self.panel.SetSizer(sizer)
43
44                 self.saveListBox.Bind(wx.EVT_LISTBOX, self.OnSaveSelect)
45                 self.playerListBox.Bind(wx.EVT_LISTBOX, self.OnPlayerSelect)
46                 self.importButton.Bind(wx.EVT_BUTTON, self.OnImport)
47
48                 self.previewPanel.Bind(wx.EVT_PAINT, self.OnPaintPreview)
49                 self.previewPanel.Bind(wx.EVT_SIZE, self.OnSizePreview)
50                 self.previewPanel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackgroundPreview)
51                 self.previewPanel.Bind(wx.EVT_MOTION, self.OnMotion)
52
53                 self.level = None
54                 self.previewImage = None
55                 self.renderList = []
56                 self.selectArea = None
57                 self.draggingArea = False
58
59                 self.Layout()
60                 self.Fit()
61
62                 self.gravelPen = wx.Pen(wx.Colour(128, 128, 128))
63                 self.sandPen = wx.Pen(wx.Colour(192, 192, 0))
64                 self.grassPen = []
65                 self.waterPen = []
66                 for z in xrange(0, 256):
67                         self.waterPen.append(wx.Pen(wx.Colour(0,0,min(z+64, 255))))
68                         self.grassPen.append(wx.Pen(wx.Colour(0,min(64+z,255),0)))
69
70                 self.isSolid = [True] * 256
71                 self.isSolid[0] = False #Air
72                 self.isSolid[8] = False #Water
73                 self.isSolid[9] = False #Water
74                 self.isSolid[10] = False #Lava
75                 self.isSolid[11] = False #Lava
76                 self.isSolid[50] = False #Torch
77                 self.isSolid[51] = False #Fire
78
79         def OnSaveSelect(self, e):
80                 if self.saveListBox.Selection < 0:
81                         return
82                 self.level = mclevel.loadWorld(self.saveListBox.GetItems()[self.saveListBox.Selection])
83                 self.playerListBox.Clear()
84                 for player in self.level.players:
85                         self.playerListBox.Append(player)
86
87         def OnPlayerSelect(self, e):
88                 playerName = self.playerListBox.GetItems()[self.playerListBox.Selection]
89                 self.playerPos = map(lambda n: int(n / 16), self.level.getPlayerPosition(playerName))[0::2]
90
91                 self.previewImage = wx.EmptyBitmap(512, 512)
92                 for i in xrange(0, 16):
93                         for j in xrange(1, i * 2 + 1):
94                                 self.renderList.insert(0, (15 - i, 16 + i - j))
95                         for j in xrange(0, i * 2 + 1):
96                                 self.renderList.insert(0, (15 + j - i, 15 - i))
97                         for j in xrange(0, i * 2 + 1):
98                                 self.renderList.insert(0, (16 + i, 15 + j - i))
99                         for j in xrange(0, i * 2 + 2):
100                                 self.renderList.insert(0, (16 + i - j, 16 + i))
101                 self.previewPanel.Refresh()
102
103         def OnPaintPreview(self, e):
104                 if len(self.renderList) > 0:
105                         cx, cy = self.renderList.pop()
106                         dc = wx.MemoryDC()
107                         dc.SelectObject(self.previewImage)
108                         chunk = self.level.getChunk(cx + self.playerPos[0] - 16, cy + self.playerPos[1] - 16)
109                         dc.SetPen(wx.Pen(wx.Colour(255,0,0)))
110                         for x in xrange(0, 16):
111                                 for y in xrange(0, 16):
112                                         z = numpy.max(numpy.where(chunk.Blocks[x, y] != 0))
113                                         type = chunk.Blocks[x, y, z]
114                                         if type == 1:    #Stone
115                                                 dc.SetPen(wx.Pen(wx.Colour(z,z,z)))
116                                         elif type == 2:    #Grass
117                                                 dc.SetPen(self.grassPen[z])
118                                         elif type == 8 or type == 9: #Water
119                                                 dc.SetPen(self.waterPen[z])
120                                         elif type == 10 or type == 11: #Lava
121                                                 dc.SetPen(wx.Pen(wx.Colour(min(z+64, 255),0,0)))
122                                         elif type == 12 or type == 24: #Sand/Standstone
123                                                 dc.SetPen(self.sandPen)
124                                         elif type == 13: #Gravel
125                                                 dc.SetPen(self.gravelPen)
126                                         elif type == 18: #Leaves
127                                                 dc.SetPen(wx.Pen(wx.Colour(0,max(z-32, 0),0)))
128                                         else:
129                                                 dc.SetPen(wx.Pen(wx.Colour(z,z,z)))
130                                         dc.DrawPoint(cx * 16 + x, cy * 16 + y)
131                         dc.SelectObject(wx.NullBitmap)
132                         wx.CallAfter(self.previewPanel.Refresh)
133
134                 dc = wx.BufferedPaintDC(self.previewPanel)
135                 dc.SetBackground(wx.Brush(wx.BLACK))
136                 dc.Clear()
137                 if self.previewImage is not None:
138                         dc.DrawBitmap(self.previewImage, 0, 0)
139                 if self.selectArea is not None:
140                         dc.SetPen(wx.Pen(wx.Colour(255,0,0)))
141                         dc.SetBrush(wx.Brush(None, style=wx.TRANSPARENT))
142                         dc.DrawRectangle(self.selectArea[0], self.selectArea[1], self.selectArea[2] - self.selectArea[0] + 1, self.selectArea[3] - self.selectArea[1] + 1)
143
144         def OnSizePreview(self, e):
145                 self.previewPanel.Refresh()
146                 self.previewPanel.Update()
147
148         def OnEraseBackgroundPreview(self, e):
149                 pass
150
151         def OnMotion(self, e):
152                 if e.Dragging():
153                         if not self.draggingArea:
154                                 self.draggingArea = True
155                                 self.selectArea = [e.GetX(), e.GetY(), e.GetX(), e.GetY()]
156                         self.selectArea[2] = e.GetX()
157                         self.selectArea[3] = e.GetY()
158                         self.previewPanel.Refresh()
159                 else:
160                         self.draggingArea = False
161
162         def OnImport(self, e):
163                 if self.level is None or self.selectArea is None:
164                         return
165
166                 xMin = min(self.selectArea[0], self.selectArea[2]) + (self.playerPos[0] - 16) * 16
167                 xMax = max(self.selectArea[0], self.selectArea[2]) + (self.playerPos[0] - 16) * 16
168                 yMin = min(self.selectArea[1], self.selectArea[3]) + (self.playerPos[1] - 16) * 16
169                 yMax = max(self.selectArea[1], self.selectArea[3]) + (self.playerPos[1] - 16) * 16
170
171                 sx = (xMax - xMin + 1)
172                 sy = (yMax - yMin + 1)
173                 blocks = numpy.zeros((sx, sy, 256), numpy.int32)
174
175                 cxMin = int(xMin / 16)
176                 cxMax = int((xMax + 15) / 16)
177                 cyMin = int(yMin / 16)
178                 cyMax = int((yMax + 15) / 16)
179
180                 for cx in xrange(cxMin, cxMax + 1):
181                         for cy in xrange(cyMin, cyMax + 1):
182                                 chunk = self.level.getChunk(cx, cy)
183                                 for x in xrange(0, 16):
184                                         bx = x + cx * 16
185                                         if xMin <= bx <= xMax:
186                                                 for y in xrange(0, 16):
187                                                         by = y + cy * 16
188                                                         if yMin <= by <= yMax:
189                                                                 blocks[bx - xMin, by - yMin] = chunk.Blocks[x, y]
190                 minZ = 256
191                 maxZ = 0
192                 for x in xrange(0, sx):
193                         for y in xrange(0, sy):
194                                 minZ = min(minZ, numpy.max(numpy.where(blocks[x, y] != 0)))
195                                 maxZ = max(maxZ, numpy.max(numpy.where(blocks[x, y] != 0)))
196                 minZ += 1
197
198                 faceCount = 0
199                 for x in xrange(0, sx):
200                         for y in xrange(0, sy):
201                                 for z in xrange(minZ, maxZ + 1):
202                                         if self.isSolid[blocks[x, y, z]]:
203                                                 if z == maxZ or not self.isSolid[blocks[x, y, z + 1]]:
204                                                         faceCount += 1
205                                                 if z == minZ or not self.isSolid[blocks[x, y, z - 1]]:
206                                                         faceCount += 1
207                                                 if x == 0 or not self.isSolid[blocks[x - 1, y, z]]:
208                                                         faceCount += 1
209                                                 if x == sx - 1 or not self.isSolid[blocks[x + 1, y, z]]:
210                                                         faceCount += 1
211                                                 if y == 0 or not self.isSolid[blocks[x, y - 1, z]]:
212                                                         faceCount += 1
213                                                 if y == sy - 1 or not self.isSolid[blocks[x, y + 1, z]]:
214                                                         faceCount += 1
215
216                 obj = mesh.printableObject(None)
217                 m = obj._addMesh()
218                 m._prepareFaceCount(faceCount * 2)
219                 for x in xrange(0, sx):
220                         for y in xrange(0, sy):
221                                 for z in xrange(minZ, maxZ + 1):
222                                         if self.isSolid[blocks[x, y, z]]:
223                                                 if z == maxZ or not self.isSolid[blocks[x, y, z + 1]]:
224                                                         m._addFace(x, y, z+1, x+1, y, z+1, x, y+1, z+1)
225
226                                                         m._addFace(x+1, y+1, z+1, x, y+1, z+1, x+1, y, z+1)
227
228                                                 if z == minZ or not self.isSolid[blocks[x, y, z - 1]]:
229                                                         m._addFace(x, y, z, x, y+1, z, x+1, y, z)
230
231                                                         m._addFace(x+1, y+1, z, x+1, y, z, x, y+1, z)
232
233                                                 if x == 0 or not self.isSolid[blocks[x - 1, y, z]]:
234                                                         m._addFace(x, y, z, x, y, z+1, x, y+1, z)
235
236                                                         m._addFace(x, y+1, z+1, x, y+1, z, x, y, z+1)
237
238                                                 if x == sx - 1 or not self.isSolid[blocks[x + 1, y, z]]:
239                                                         m._addFace(x+1, y, z, x+1, y+1, z, x+1, y, z+1)
240
241                                                         m._addFace(x+1, y+1, z+1, x+1, y, z+1, x+1, y+1, z)
242
243                                                 if y == 0 or not self.isSolid[blocks[x, y - 1, z]]:
244                                                         m._addFace(x, y, z, x+1, y, z, x, y, z+1)
245
246                                                         m._addFace(x+1, y, z+1, x, y, z+1, x+1, y, z)
247
248                                                 if y == sy - 1 or not self.isSolid[blocks[x, y + 1, z]]:
249                                                         m._addFace(x, y+1, z, x, y+1, z+1, x+1, y+1, z)
250
251                                                         m._addFace(x+1, y+1, z+1, x+1, y+1, z, x, y+1, z+1)
252
253                 obj._postProcessAfterLoad()
254                 self.GetParent().scene._scene.add(obj)