Example #1
0
 def apply_default(self):
     self.map = VXLData()
     self.slice_map(show_dialog = False)
     bottom_layer = self.layers[63]
     bottom_layer.fill(WATER_PEN.rgba())
     bottom_layer.dirty = True
     self.edit_widget.map_updated(self.map)
     self.set_dirty(False)
Example #2
0
 def open_selected(self):
     name = QtGui.QFileDialog.getOpenFileName(self,
         'Open', self.path, filter = '*.vxl')[0]
     if not name:
         return
     self.filename = name
     self.map = VXLData(open(name, 'rb'))
     self.slice_map()
     self.edit_widget.map_updated(self.map)
     self.set_dirty(False)
Example #3
0
 def load_vxl(self, rot_info):
     try:
         fp = open(rot_info.get_map_filename(self.load_dir), 'rb')
     except OSError:
         raise MapNotFound(rot_info.name)
     self.data = VXLData(fp)
     fp.close()
Example #4
0
 def get_map(self, name):
     map = protocol.get_map(self, name)
     if config.get('load_saved_map', False):
         cached_path = get_name(map)
         if os.path.isfile(cached_path):
             map.data = VXLData(open(cached_path, 'rb'))
     return map
Example #5
0
 def apply_default(self):
     self.map = VXLData()
     self.slice_map(show_dialog = False)
     bottom_layer = self.layers[63]
     bottom_layer.fill(WATER_PEN.rgba())
     bottom_layer.dirty = True
     self.edit_widget.map_updated(self.map)
     self.set_dirty(False)
Example #6
0
 def get_map(self, name):
     map = protocol.get_map(self, name)
     if LOAD_SAVED_MAP_OPTION.get():
         cached_path = get_name(map)
         print("Loading saved map for {} from {}".format(name, cached_path))
         if os.path.isfile(cached_path):
             map.data = VXLData(open(cached_path, 'rb'))
             print("Saved map loaded")
     return map
Example #7
0
 def open_selected(self):
     name = QtGui.QFileDialog.getOpenFileName(self,
         'Open', self.path, filter = '*.vxl')[0]
     if not name:
         return
     self.filename = name
     self.map = VXLData(open(name, 'rb'))
     self.slice_map()
     self.edit_widget.map_updated(self.map)
     self.set_dirty(False)
Example #8
0
 def load_map(self, name):
     try:
         data = VXLData(open('../feature_server/maps/%s.vxl' % name, 'rb'))
     except (IOError):
         print "Couldn't open map '%s'" % name
         return False
     current_time = time()
     self.navigation = Navigation(data)
     dt = time() - current_time
     print 'Navgraph contains %s nodes. Generation took %s' % (
         self.navigation.get_node_count(), dt)
     return True
Example #9
0
class MapEditor(QtGui.QMainWindow):
    path = None
    filename = None
    voxed_filename = None
    layers = None
    dirty = False
    
    def __init__(self, app, *arg, **kw):
        super(MapEditor, self).__init__(*arg, **kw)
        
        self.app = app
        self.app.setApplicationName('pyspades map editor')
        self.setWindowTitle('pyspades map editor')
        self.clipboard = app.clipboard()
        
        menu = self.menuBar()
        
        self.file = menu.addMenu('&File')
        
        self.new_action = QtGui.QAction('&New', self,
            shortcut = QtGui.QKeySequence('Ctrl+N'), 
            triggered = self.new_selected)
        self.file.addAction(self.new_action)
        
        self.open_action = QtGui.QAction('&Open...', self,
            shortcut = QtGui.QKeySequence('Ctrl+O'), 
            triggered = self.open_selected)
        self.file.addAction(self.open_action)
        
        self.file.addSeparator()
        
        self.save_action = QtGui.QAction('&Save', self, 
            shortcut = QtGui.QKeySequence.Save, triggered = self.save_selected)
        self.save_action.setEnabled(False)
        self.file.addAction(self.save_action)
        
        self.save_as_action = QtGui.QAction('Save &As...', self, 
            shortcut = QtGui.QKeySequence('Ctrl+Shift+S'), 
            triggered = self.save_as_selected)
        self.file.addAction(self.save_as_action)
        
        self.file.addSeparator()
        
        self.import_menu = self.file.addMenu('&Import')
        
        self.import_image_sequence_menu = QtGui.QAction('Image &sequence...', self, 
            triggered = self.import_image_sequence)
        self.import_menu.addAction(self.import_image_sequence_menu)
        
        self.export = self.file.addMenu('&Export')
        
        self.color_map = QtGui.QAction('&Colormap...', self, 
            triggered = self.export_color_map)
        self.export.addAction(self.color_map)
        
        self.height_map = QtGui.QAction('&Heightmap...', self, 
            triggered = self.export_height_map)
        self.export.addAction(self.height_map)
        
        self.export_image_sequence_menu = QtGui.QAction('Image &sequence...', self, 
            triggered = self.export_image_sequence)
        self.export.addAction(self.export_image_sequence_menu)
        
        self.file.addSeparator()
        
        self.voxed_action = QtGui.QAction('Open in &VOXED', 
            self, shortcut = QtGui.QKeySequence('F5'), triggered = self.open_voxed)
        self.file.addAction(self.voxed_action)
        
        self.file.addSeparator()
        
        self.quit_action = QtGui.QAction('E&xit', 
            self, shortcut = QtGui.QKeySequence('Ctrl+Q'), 
            triggered = self.quit)
        self.file.addAction(self.quit_action)
        
        self.edit = menu.addMenu('&Edit')
        
        self.copy_action = QtGui.QAction('C&opy', self,
            shortcut = QtGui.QKeySequence.Copy, triggered = self.copy_selected)
        self.edit.addAction(self.copy_action)
        
        self.paste_action = QtGui.QAction('P&aste', self,
            shortcut = QtGui.QKeySequence.Paste, 
            triggered = self.paste_selected)
        self.edit.addAction(self.paste_action)
        
        self.copy_action_external = QtGui.QAction('&Copy External', self,
            shortcut = QtGui.QKeySequence('Ctrl+Shift+C'),
            triggered = self.copy_external_selected)
        self.edit.addAction(self.copy_action_external)
        
        self.paste_action_external = QtGui.QAction('&Paste External', self,
            shortcut = QtGui.QKeySequence('Ctrl+Shift+V'), 
            triggered = self.paste_external_selected)
        self.edit.addAction(self.paste_action_external)
        
        self.clear_action = QtGui.QAction('Cl&ear', self,
            shortcut = QtGui.QKeySequence.Delete, 
            triggered = self.clear_selected)
        self.edit.addAction(self.clear_action)
        
        self.transform = menu.addMenu('&Transform')
        
        self.shift_up_action = QtGui.QAction('Shift layers &upward', self,
            shortcut = QtGui.QKeySequence('Ctrl+Shift+Q'),
            triggered = self.shift_up)
        self.transform.addAction(self.shift_up_action)
        
        self.shift_down_action = QtGui.QAction('Shift layers &downward', self,
            shortcut = QtGui.QKeySequence('Ctrl+Shift+A'),
            triggered = self.shift_down)
        self.transform.addAction(self.shift_down_action)
        
        self.transform.addSeparator()
        
        self.mirror_horizontal_action = QtGui.QAction('Mirror &horizontal', self,
            triggered = self.mirror_horizontal)
        self.transform.addAction(self.mirror_horizontal_action)
        
        self.mirror_vertical_action = QtGui.QAction('Mirror &vertical', self,
            triggered = self.mirror_vertical)
        self.transform.addAction(self.mirror_vertical_action)
        
        self.mirror_both_action = QtGui.QAction('Mirror &both', self,
            triggered = self.mirror_both)
        self.transform.addAction(self.mirror_both_action)
        
        self.mirror_z_action = QtGui.QAction('Mirror &Z', self,
            triggered = self.mirror_z)
        self.transform.addAction(self.mirror_z_action)
        
        self.transform.addSeparator()
        
        self.rotate_90_CW_action = QtGui.QAction('Rotate &90\xb0 CW', self,
            triggered = self.rotate_90_CW)
        self.transform.addAction(self.rotate_90_CW_action)
        
        self.rotate_90_CCW_action = QtGui.QAction('Rotate 9&0\xb0 CCW', self,
            triggered = self.rotate_90_CCW)
        self.transform.addAction(self.rotate_90_CCW_action)
        
        self.rotate_180_action = QtGui.QAction('Rotate &180\xb0', self,
            triggered = self.rotate_180)
        self.transform.addAction(self.rotate_180_action)
        
        self.heightmap = menu.addMenu('&Heightmap')
        
        self.additive_heightmap_action = QtGui.QAction('&Additive...', self,
            triggered = self.generate_heightmap)
        self.heightmap.addAction(self.additive_heightmap_action)
        
        self.subtractive_heightmap_action = QtGui.QAction('&Subtractive...', self,
            triggered = self.subtractive_heightmap)
        self.heightmap.addAction(self.subtractive_heightmap_action)
        
        self.scroll_view = ScrollArea(self)
        self.edit_widget = EditWidget(self)
        self.scroll_view.setWidget(self.edit_widget)
        self.setCentralWidget(self.scroll_view)
        self.scroll_view.setAlignment(Qt.AlignCenter)
        
        self.apply_default()
        self.path = DEFAULT_PATH
        self.filename = None
        
        self.settings_dock = QtGui.QDockWidget(self)
        self.settings_dock.setWidget(Settings(self))
        self.settings_dock.setWindowTitle('Settings')
        
        for item in (self.settings_dock,):
            self.addDockWidget(Qt.RightDockWidgetArea, item)
    
    def set_dirty(self, value = True):
        if self.dirty == value:
            return
        self.dirty = value
        self.save_action.setEnabled(value)
    
    def new_selected(self):
        msgBox = QMessageBox()
        msgBox.setText("Do you want to discard your changes?")
        msgBox.setStandardButtons(QMessageBox.Discard | QMessageBox.Cancel)
        msgBox.setDefaultButton(QMessageBox.Cancel)
        ret = msgBox.exec_()
        if ret == QMessageBox.Cancel:
            return
        self.filename = None
        self.apply_default()
    
    def open_selected(self):
        name = QtGui.QFileDialog.getOpenFileName(self,
            'Open', self.path, filter = '*.vxl')[0]
        if not name:
            return
        self.filename = name
        self.map = VXLData(open(name, 'rb'))
        self.slice_map()
        self.edit_widget.map_updated(self.map)
        self.set_dirty(False)
    
    def apply_default(self):
        self.map = VXLData()
        self.slice_map(show_dialog = False)
        bottom_layer = self.layers[63]
        bottom_layer.fill(WATER_PEN.rgba())
        bottom_layer.dirty = True
        self.edit_widget.map_updated(self.map)
        self.set_dirty(False)
    
    def slice_map(self, show_dialog = True):
        self.layers = []
        if show_dialog:
            progress = progress_dialog(self.edit_widget, 0, 63, 'Slicing...', 
                can_abort = False)
        for z in xrange(0, 64):
            if show_dialog:
                progress.setValue(z)
            self.layers.append(MapImage(self.map.get_overview(z), 512, 512,
                QImage.Format_ARGB32))
    
    def save_selected(self):
        if self.filename is None:
            return self.save_as_selected()
        name = os.path.join(self.path, self.filename)
        self.save(name)
        return name
    
    def save_as_selected(self):
        path = os.path.join(self.path, self.filename or DEFAULT_FILENAME)
        name = QtGui.QFileDialog.getSaveFileName(self,
            'Save As', path, filter = '*.vxl')[0]
        if not name:
            return
        self.path, self.filename = os.path.split(name)
        self.save(name)
        return name
    
    def save(self, filename):
        for z in xrange(0, 64):
            layer = self.layers[z]
            if layer.dirty:
                self.map.set_overview(layer.data, z)
                layer.dirty = False
        open(filename, 'wb').write(self.map.generate())
        self.set_dirty(False)
    
    def open_voxed(self):
        name = self.save_selected()
        if not name:
            return
        if self.voxed_filename is None:
            default_path = 'C:\\Ace of Spades\\voxed.exe'
            if os.path.exists(default_path):
                self.voxed_filename = default_path
            else:
                exename = QtGui.QFileDialog.getOpenFileName(self,
                    'Select VOXED.EXE', filter = '*.exe')[0]
                if not exename:
                    return
                self.voxed_filename = exename
        subprocess.call([self.voxed_filename, name])
    
    def import_image_sequence(self):
        name = QtGui.QFileDialog.getOpenFileName(self,
            'Import image sequence (select any file from the sequence)', filter = IMAGE_OPEN_FILTER)[0]
        if not name:
            return
        root, ext = os.path.splitext(name)
        head, tail = os.path.split(root)
        path = os.path.join(root, head, tail[:-2])
        old_z = self.edit_widget.z
        progress = progress_dialog(self.edit_widget, 0, 63, 'Importing images...')
        for z in xrange(0, 64):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            image = QImage(path + format(z, '02d') + ext)
            if not image:
                continue
            interpret_colorkey(image)
            self.layers[63 - z].set_image(image)
        self.edit_widget.repaint()
        self.set_dirty()
    
    def export_color_map(self):
        name = QtGui.QFileDialog.getSaveFileName(self,
            'Export Colormap', filter = IMAGE_SAVE_FILTER)[0]
        if not name:
            return
        color_image = QImage(512, 512, QImage.Format_ARGB32)
        color_lines = []
        height_found = []
        for y in xrange(0, 512):
            color_lines.append(color_image.scanLine(y))
            height_found.append([])
            for x in xrange(0, 512):
                height_found[y].append(False)
        progress = progress_dialog(self.edit_widget, 0, 63, 'Exporting Colormap...')
        for z in xrange(0, 64):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            image = self.layers[z]
            for y in xrange(0, 512):
                image_line = image.scanLine(y)
                color_line = color_lines[y]
                for x in xrange(0, 512):
                    if height_found[y][x] is False:
                        s = x * 4
                        image_pixel = image_line[s:s + 4]
                        if image_pixel != TRANSPARENT_PACKED:
                            height_found[y][x] = True
                            color_line[s:s + 4] = image_pixel
        color_image.save(name)
    
    def export_height_map(self):
        name = QtGui.QFileDialog.getSaveFileName(self,
            'Export Heightmap', filter = IMAGE_SAVE_FILTER)[0]
        if not name:
            return
        height_packed = []
        for z in xrange(0, 64):
            height = (63 - z) * 4
            height_packed.append(struct.pack('I', QtGui.qRgba(height, height, height, 255)))
        height_image = QImage(512, 512, QImage.Format_ARGB32)
        height_lines = []
        height_found = []
        for y in xrange(0, 512):
            height_lines.append(height_image.scanLine(y))
            height_found.append([])
            for x in xrange(0, 512):
                height_found[y].append(False)
        progress = progress_dialog(self.edit_widget, 0, 63, 'Exporting Heightmap...')
        for z in xrange(0, 64):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            packed_value = height_packed[z]
            image = self.layers[z]
            for y in xrange(0, 512):
                image_line = image.scanLine(y)
                height_line = height_lines[y]
                for x in xrange(0, 512):
                    if height_found[y][x] is False:
                        s = x * 4
                        if image_line[s:s + 4] != TRANSPARENT_PACKED:
                            height_found[y][x] = True
                            height_line[s:s + 4] = packed_value
        height_image.save(name)
    
    def export_image_sequence(self):
        name = QtGui.QFileDialog.getSaveFileName(self,
            'Export image sequence (select base filename)', filter = IMAGE_SAVE_FILTER)[0]
        if not name:
            return
        root, ext = os.path.splitext(name)
        progress = progress_dialog(self.edit_widget, 0, 63, 'Exporting images...')
        for z in xrange(0, 64):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            image = self.layers[63 - z]
            new_image = make_colorkey(image)
            new_image.save(root + format(z, '02d') + ext)
    
    def copy_selected(self):
        self.clipboard.setImage(self.edit_widget.image)
    
    def paste_selected(self):
        image = self.clipboard.image()
        if not image:
            return
        self.edit_widget.set_image(image)
        self.set_dirty()
    
    def copy_external_selected(self):
        image = self.edit_widget.image
        new_image = make_colorkey(image)
        self.clipboard.setImage(new_image)
    
    def paste_external_selected(self):
        image = self.clipboard.image()
        if not image:
            return
        image = image.convertToFormat(QImage.Format_ARGB32)
        interpret_colorkey(image)
        self.edit_widget.set_image(image)
        self.set_dirty()
    
    def mirror(self, hor, ver):
        progress = progress_dialog(self.edit_widget, 0, 63, 'Mirroring...')
        for z in xrange(0, 64):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            layer = self.layers[z]
            layer.set_image(layer.mirrored(hor, ver))
        self.edit_widget.repaint()
        self.set_dirty()
    
    def mirror_horizontal(self):
        self.mirror(True, False)
    
    def mirror_vertical(self):
        self.mirror(False, True)
    
    def mirror_both(self):
        self.mirror(True, True)
    
    def mirror_z(self):
        self.layers.reverse()
        for layer in self.layers:
            layer.dirty = True
        self.edit_widget.layers_updated()
        self.set_dirty()
    
    def rotate(self, angle):
        progress = progress_dialog(self.edit_widget, 0, 63, 'Rotating...')
        transform = QtGui.QTransform()
        transform.rotate(angle)
        for z in xrange(0, 64):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            layer = self.layers[z]
            layer.set_image(layer.transformed(transform))
        self.edit_widget.repaint()
        self.set_dirty()
    
    def rotate_90_CW(self):
        self.rotate(90)

    def rotate_90_CCW(self):
        self.rotate(-90)
    
    def rotate_180(self):
        self.rotate(180)
    
    def cycle_layers(self, n):
        self.layers = self.layers[n:] + self.layers[:n]
        for layer in self.layers:
            layer.dirty = True
        self.edit_widget.layers_updated()
        self.set_dirty()
    
    def shift_up(self):
        self.cycle_layers(1)
    
    def shift_down(self):
        self.cycle_layers(-1)
    
    def clear_selected(self):
        self.edit_widget.clear()
        self.set_dirty()
    
    def get_height(self, color):
        return int(math.floor((float(QtGui.qRed(color)) + float(QtGui.qGreen(color)) + 
                    float(QtGui.qBlue(color)))/12.0))
    
    def generate_heightmap(self, delete = False):
        h_name = QtGui.QFileDialog.getOpenFileName(self,
            'Select heightmap file', filter = IMAGE_OPEN_FILTER)[0]
        if not h_name:
            return
        h_image = QImage(h_name)
        if not delete:
            c_name = QtGui.QFileDialog.getOpenFileName(self,
                'Select colormap file', filter = IMAGE_OPEN_FILTER)[0]
            if not c_name:
                return
            c_image = QImage(c_name)
        height_values = []
        color_lines = []
        for y in xrange(0, 512):
            height_values.append([])
            height_line = h_image.scanLine(y)
            if not delete:
                color_lines.append(c_image.scanLine(y))
            for x in xrange(0,512):
                height_values[y].append(self.get_height(struct.unpack('I', height_line[x * 4:x * 4 + 4])[0]))
        progress = progress_dialog(self.edit_widget, 0, 63, 'Generating from heightmap...')
        for z in xrange(0, 64):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            if z == 0 and delete:
                continue
            image = self.layers[63 - z]
            for y in xrange(0, 512):
                image_line = image.scanLine(y)
                if not delete:
                    color_line = color_lines[y]
                for x in xrange(0, 512):
                    if z <= height_values[y][x]:
                        s = x * 4
                        if not delete:
                            image_line[s:s + 4] = color_line[s:s + 4]
                        else:
                            image_line[s:s + 4] = TRANSPARENT_PACKED
            image.dirty = True
        self.set_dirty()
    
    def subtractive_heightmap(self):
        return self.generate_heightmap(True)
    
    def quit(self):
        if self.dirty:
            text = ('Save changes to ' + (self.filename or DEFAULT_FILENAME) +
                ' before closing?')
            reply = QMessageBox.warning(self, self.app.applicationName(), text,
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
                QMessageBox.Yes)
            if reply == QMessageBox.Yes:
                if not self.save_selected():
                    return
            elif reply == QMessageBox.Cancel:
                return
        self.app.exit()
Example #10
0
# pyspades is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# pyspades 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 General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with pyspades.  If not, see <http://www.gnu.org/licenses/>.

from pyspades.vxl import VXLData

map = VXLData()

for x in xrange(50, 512 - 50):
    for y in xrange(50, 512 - 50):
        for z in xrange(20, 58):
            map.set_point(x, y, z, (20, 20, 30, 40))

for x in range(512):
    for y in xrange(512):
        map.set_point(x, y, 62, (20, 20, 30, 40))
        map.set_point(x, y, 63, (20, 20, 30, 40))

for z in range(5, 64):
    map.set_point(256, 256, z, (20, 20, 30, 40))

print 'generating'
Example #11
0
class MapEditor(QtGui.QMainWindow):
    path = None
    filename = None
    voxed_filename = None
    layers = None
    dirty = False
    
    def __init__(self, app, *arg, **kw):
        super(MapEditor, self).__init__(*arg, **kw)
        
        self.app = app
        self.app.setApplicationName('pyspades map editor')
        self.setWindowTitle('pyspades map editor')
        self.clipboard = app.clipboard()
        
        menu = self.menuBar()
        
        self.file = menu.addMenu('&File')
        
        self.new_action = QtGui.QAction('&New', self,
            shortcut = QtGui.QKeySequence('Ctrl+N'), 
            triggered = self.new_selected)
        self.file.addAction(self.new_action)
        
        self.open_action = QtGui.QAction('&Open...', self,
            shortcut = QtGui.QKeySequence('Ctrl+O'), 
            triggered = self.open_selected)
        self.file.addAction(self.open_action)
        
        self.file.addSeparator()
        
        self.save_action = QtGui.QAction('&Save', self, 
            shortcut = QtGui.QKeySequence.Save, triggered = self.save_selected)
        self.save_action.setEnabled(False)
        self.file.addAction(self.save_action)
        
        self.save_as_action = QtGui.QAction('Save &As...', self, 
            shortcut = QtGui.QKeySequence('Ctrl+Shift+S'), 
            triggered = self.save_as_selected)
        self.file.addAction(self.save_as_action)
        
        self.file.addSeparator()
        
        self.import_menu = self.file.addMenu('&Import')
        
        self.import_image_sequence_menu = QtGui.QAction('Image &sequence...', self, 
            triggered = self.import_image_sequence)
        self.import_menu.addAction(self.import_image_sequence_menu)
        
        self.export = self.file.addMenu('&Export')
        
        self.color_map = QtGui.QAction('&Colormap...', self, 
            triggered = self.export_color_map)
        self.export.addAction(self.color_map)
        
        self.height_map = QtGui.QAction('&Heightmap...', self, 
            triggered = self.export_height_map)
        self.export.addAction(self.height_map)
        
        self.export_image_sequence_menu = QtGui.QAction('Image &sequence...', self, 
            triggered = self.export_image_sequence)
        self.export.addAction(self.export_image_sequence_menu)
        
        self.file.addSeparator()
        
        self.bake_voxed_action = QtGui.QAction(
            '&Calculate shadows and open in VOXED', self,
            shortcut = QtGui.QKeySequence('F5'),
            triggered = self.bake_shadows_open_voxed)
        self.file.addAction(self.bake_voxed_action)
        
        self.voxed_action = QtGui.QAction('Open in &VOXED', self,
            shortcut = QtGui.QKeySequence('Shift+F5'),
            triggered = self.open_voxed)
        self.file.addAction(self.voxed_action)
        
        self.file.addSeparator()
        
        self.quit_action = QtGui.QAction('E&xit', 
            self, shortcut = QtGui.QKeySequence('Ctrl+Q'), 
            triggered = self.quit)
        self.file.addAction(self.quit_action)
        
        self.edit = menu.addMenu('&Edit')
        
        self.copy_action = QtGui.QAction('C&opy', self,
            shortcut = QtGui.QKeySequence.Copy, triggered = self.copy_selected)
        self.edit.addAction(self.copy_action)
        
        self.paste_action = QtGui.QAction('P&aste', self,
            shortcut = QtGui.QKeySequence.Paste, 
            triggered = self.paste_selected)
        self.edit.addAction(self.paste_action)
        
        self.copy_action_external = QtGui.QAction('&Copy External', self,
            shortcut = QtGui.QKeySequence('Ctrl+Shift+C'),
            triggered = self.copy_external_selected)
        self.edit.addAction(self.copy_action_external)
        
        self.paste_action_external = QtGui.QAction('&Paste External', self,
            shortcut = QtGui.QKeySequence('Ctrl+Shift+V'), 
            triggered = self.paste_external_selected)
        self.edit.addAction(self.paste_action_external)
        
        self.clear_action = QtGui.QAction('Cl&ear', self,
            shortcut = QtGui.QKeySequence.Delete, 
            triggered = self.clear_selected)
        self.edit.addAction(self.clear_action)
        
        self.transform = menu.addMenu('&Transform')
        
        self.shift_up_action = QtGui.QAction('Shift layers &upward', self,
            shortcut = QtGui.QKeySequence('Ctrl+Shift+Q'),
            triggered = self.shift_up)
        self.transform.addAction(self.shift_up_action)
        
        self.shift_down_action = QtGui.QAction('Shift layers &downward', self,
            shortcut = QtGui.QKeySequence('Ctrl+Shift+A'),
            triggered = self.shift_down)
        self.transform.addAction(self.shift_down_action)
        
        self.transform.addSeparator()
        
        self.mirror_horizontal_action = QtGui.QAction('Mirror &horizontal', self,
            triggered = self.mirror_horizontal)
        self.transform.addAction(self.mirror_horizontal_action)
        
        self.mirror_vertical_action = QtGui.QAction('Mirror &vertical', self,
            triggered = self.mirror_vertical)
        self.transform.addAction(self.mirror_vertical_action)
        
        self.mirror_both_action = QtGui.QAction('Mirror &both', self,
            triggered = self.mirror_both)
        self.transform.addAction(self.mirror_both_action)
        
        self.mirror_z_action = QtGui.QAction('Mirror &Z', self,
            triggered = self.mirror_z)
        self.transform.addAction(self.mirror_z_action)
        
        self.transform.addSeparator()
        
        self.rotate_90_CW_action = QtGui.QAction('Rotate &90\xb0 CW', self,
            triggered = self.rotate_90_CW)
        self.transform.addAction(self.rotate_90_CW_action)
        
        self.rotate_90_CCW_action = QtGui.QAction('Rotate 9&0\xb0 CCW', self,
            triggered = self.rotate_90_CCW)
        self.transform.addAction(self.rotate_90_CCW_action)
        
        self.rotate_180_action = QtGui.QAction('Rotate &180\xb0', self,
            triggered = self.rotate_180)
        self.transform.addAction(self.rotate_180_action)
        
        self.heightmap = menu.addMenu('&Heightmap')
        
        self.additive_heightmap_action = QtGui.QAction('&Additive...', self,
            triggered = self.generate_heightmap)
        self.heightmap.addAction(self.additive_heightmap_action)
        
        self.subtractive_heightmap_action = QtGui.QAction('&Subtractive...', self,
            triggered = self.subtractive_heightmap)
        self.heightmap.addAction(self.subtractive_heightmap_action)
        
        self.scroll_view = ScrollArea(self)
        self.edit_widget = EditWidget(self)
        self.scroll_view.setWidget(self.edit_widget)
        self.setCentralWidget(self.scroll_view)
        self.scroll_view.setAlignment(Qt.AlignCenter)
        
        self.apply_default()
        self.path = DEFAULT_PATH
        self.filename = None
        
        self.settings_dock = QtGui.QDockWidget(self)
        self.settings_dock.setWidget(Settings(self))
        self.settings_dock.setWindowTitle('Settings')
        
        for item in (self.settings_dock,):
            self.addDockWidget(Qt.RightDockWidgetArea, item)
    
    def set_dirty(self, value = True):
        if self.dirty == value:
            return
        self.dirty = value
        self.save_action.setEnabled(value)
    
    def new_selected(self):
        msgBox = QMessageBox()
        msgBox.setText("Do you want to discard your changes?")
        msgBox.setStandardButtons(QMessageBox.Discard | QMessageBox.Cancel)
        msgBox.setDefaultButton(QMessageBox.Cancel)
        ret = msgBox.exec_()
        if ret == QMessageBox.Cancel:
            return
        self.filename = None
        self.apply_default()
    
    def open_selected(self):
        name = QtGui.QFileDialog.getOpenFileName(self,
            'Open', self.path, filter = '*.vxl')[0]
        if not name:
            return
        self.filename = name
        self.map = VXLData(open(name, 'rb'))
        self.slice_map()
        self.edit_widget.map_updated(self.map)
        self.set_dirty(False)
    
    def apply_default(self):
        self.map = VXLData()
        self.slice_map(show_dialog = False)
        bottom_layer = self.layers[63]
        bottom_layer.fill(WATER_PEN.rgba())
        bottom_layer.dirty = True
        self.edit_widget.map_updated(self.map)
        self.set_dirty(False)
    
    def slice_map(self, show_dialog = True):
        self.layers = []
        if show_dialog:
            progress = progress_dialog(self.edit_widget, 0, 63, 'Slicing...', 
                can_abort = False)
        for z in xrange(0, 64):
            if show_dialog:
                progress.setValue(z)
            self.layers.append(MapImage(self.map.get_overview(z), 512, 512,
                QImage.Format_ARGB32))
    
    def save_selected(self):
        if self.filename is None:
            return self.save_as_selected()
        name = os.path.join(self.path, self.filename)
        self.save(name)
        return name
    
    def save_as_selected(self):
        path = os.path.join(self.path, self.filename or DEFAULT_FILENAME)
        name = QtGui.QFileDialog.getSaveFileName(self,
            'Save As', path, filter = '*.vxl')[0]
        if not name:
            return
        self.path, self.filename = os.path.split(name)
        self.save(name)
        return name
    
    def update_map(self):
        for z, layer in enumerate(self.layers):
            if layer.dirty:
                self.map.set_overview(layer.data, z)
                layer.dirty = False
    
    def save(self, filename):
        self.update_map()
        open(filename, 'wb').write(self.map.generate())
        self.set_dirty(False)
    
    def open_voxed(self):
        name = self.save_selected()
        if not name:
            return
        if self.voxed_filename is None:
            default_path = 'C:\\Ace of Spades\\voxed.exe'
            if os.path.exists(default_path):
                self.voxed_filename = default_path
            else:
                exename = QtGui.QFileDialog.getOpenFileName(self,
                    'Select VOXED.EXE', filter = '*.exe')[0]
                if not exename:
                    return
                self.voxed_filename = exename
        subprocess.call([self.voxed_filename, name])
    
    def bake_shadows_open_voxed(self):
        self.update_map()
        self.map.update_shadows()
        self.open_voxed()
    
    def import_image_sequence(self):
        name = QtGui.QFileDialog.getOpenFileName(self,
            'Import image sequence (select any file from the sequence)',
            filter = IMAGE_OPEN_FILTER)[0]
        if not name:
            return
        root, ext = os.path.splitext(name)
        head, tail = os.path.split(root)
        path = os.path.join(root, head, tail[:-2])
        old_z = self.edit_widget.z
        progress = progress_dialog(self.edit_widget, 0, 63, 'Importing images...')
        for z, layer in enumerate(reversed(self.layers)):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            image = QImage(path + format(z, '02d') + ext)
            if not image:
                continue
            interpret_colorkey(image)
            layer.set_image(image)
        self.edit_widget.repaint()
        self.set_dirty()
    
    def export_color_map(self):
        name = QtGui.QFileDialog.getSaveFileName(self,
            'Export Colormap', filter = IMAGE_SAVE_FILTER)[0]
        if not name:
            return
        color_image = QImage(512, 512, QImage.Format_ARGB32)
        color_lines = []
        height_found = []
        for y in xrange(0, 512):
            color_lines.append(color_image.scanLine(y))
            height_found.append([])
            for x in xrange(0, 512):
                height_found[y].append(False)
        progress = progress_dialog(self.edit_widget, 0, 63, 'Exporting Colormap...')
        for z, image in enumerate(self.layers):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            for y in xrange(0, 512):
                image_line = image.scanLine(y)
                color_line = color_lines[y]
                for x in xrange(0, 512):
                    if height_found[y][x] is False:
                        s = x * 4
                        image_pixel = image_line[s:s + 4]
                        if image_pixel != TRANSPARENT_PACKED:
                            height_found[y][x] = True
                            color_line[s:s + 4] = image_pixel
        color_image.save(name)
    
    def export_height_map(self):
        name = QtGui.QFileDialog.getSaveFileName(self,
            'Export Heightmap', filter = IMAGE_SAVE_FILTER)[0]
        if not name:
            return
        height_packed = []
        for z in xrange(0, 64):
            height = (63 - z) * 4
            height_packed.append(struct.pack('I',
                QtGui.qRgba(height, height, height, 255)))
        height_image = QImage(512, 512, QImage.Format_ARGB32)
        height_lines = []
        height_found = []
        for y in xrange(0, 512):
            height_lines.append(height_image.scanLine(y))
            height_found.append([])
            for x in xrange(0, 512):
                height_found[y].append(False)
        progress = progress_dialog(self.edit_widget, 0, 63, 'Exporting Heightmap...')
        for z, image in enumerate(self.layers):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            packed_value = height_packed[z]
            for y in xrange(0, 512):
                image_line = image.scanLine(y)
                height_line = height_lines[y]
                for x in xrange(0, 512):
                    if height_found[y][x] is False:
                        s = x * 4
                        if image_line[s:s + 4] != TRANSPARENT_PACKED:
                            height_found[y][x] = True
                            height_line[s:s + 4] = packed_value
        height_image.save(name)
    
    def export_image_sequence(self):
        name = QtGui.QFileDialog.getSaveFileName(self,
            'Export image sequence (select base filename)',
            filter = IMAGE_SAVE_FILTER)[0]
        if not name:
            return
        root, ext = os.path.splitext(name)
        head, tail = os.path.split(root)
        path = os.path.join(root, head, re.sub('\d{2}$', '', tail))
        progress = progress_dialog(self.edit_widget, 0, 63, 'Exporting images...')
        for z, image in enumerate(reversed(self.layers)):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            new_image = make_colorkey(image)
            new_image.save(path + format(z, '02d') + ext)
    
    def copy_selected(self):
        self.clipboard.setImage(self.edit_widget.image)
    
    def paste_selected(self):
        image = self.clipboard.image()
        if not image:
            return
        self.edit_widget.set_image(image)
        self.set_dirty()
    
    def copy_external_selected(self):
        image = self.edit_widget.image
        new_image = make_colorkey(image)
        self.clipboard.setImage(new_image)
    
    def paste_external_selected(self):
        image = self.clipboard.image()
        if not image:
            return
        image = image.convertToFormat(QImage.Format_ARGB32)
        interpret_colorkey(image)
        self.edit_widget.set_image(image)
        self.set_dirty()
    
    def mirror(self, hor, ver):
        progress = progress_dialog(self.edit_widget, 0, 63, 'Mirroring...')
        for z, layer in enumerate(self.layers):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            layer.set_image(layer.mirrored(hor, ver))
        self.edit_widget.repaint()
        self.set_dirty()
    
    def mirror_horizontal(self):
        self.mirror(True, False)
    
    def mirror_vertical(self):
        self.mirror(False, True)
    
    def mirror_both(self):
        self.mirror(True, True)
    
    def mirror_z(self):
        self.layers.reverse()
        for layer in self.layers:
            layer.dirty = True
        self.edit_widget.layers_updated()
        self.set_dirty()
    
    def rotate(self, angle):
        progress = progress_dialog(self.edit_widget, 0, 63, 'Rotating...')
        transform = QtGui.QTransform()
        transform.rotate(angle)
        for z, layer in enumerate(self.layers):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            layer.set_image(layer.transformed(transform))
        self.edit_widget.repaint()
        self.set_dirty()
    
    def rotate_90_CW(self):
        self.rotate(90)

    def rotate_90_CCW(self):
        self.rotate(-90)
    
    def rotate_180(self):
        self.rotate(180)
    
    def cycle_layers(self, n):
        self.layers = self.layers[n:] + self.layers[:n]
        for layer in self.layers:
            layer.dirty = True
        self.edit_widget.layers_updated()
        self.set_dirty()
    
    def shift_up(self):
        self.cycle_layers(1)
    
    def shift_down(self):
        self.cycle_layers(-1)
    
    def clear_selected(self):
        self.edit_widget.clear()
        self.set_dirty()
    
    def get_height(self, color):
        return int(math.floor((float(QtGui.qRed(color)) +
            float(QtGui.qGreen(color)) + float(QtGui.qBlue(color))) / 12.0))
    
    def generate_heightmap(self, delete = False):
        h_name = QtGui.QFileDialog.getOpenFileName(self,
            'Select heightmap file', filter = IMAGE_OPEN_FILTER)[0]
        if not h_name:
            return
        h_image = QImage(h_name)
        if not delete:
            c_name = QtGui.QFileDialog.getOpenFileName(self,
                'Select colormap file', filter = IMAGE_OPEN_FILTER)[0]
            if not c_name:
                return
            c_image = QImage(c_name)
        height_values = []
        color_lines = []
        for y in xrange(0, 512):
            height_values.append([])
            height_line = h_image.scanLine(y)
            if not delete:
                color_lines.append(c_image.scanLine(y))
            for x in xrange(0,512):
                height_values[y].append(self.get_height(
                    struct.unpack('I', height_line[x * 4:x * 4 + 4])[0]))
        progress = progress_dialog(self.edit_widget, 0, 63,
            'Generating from heightmap...')
        for z, image in enumerate(reversed(self.layers)):
            if progress.wasCanceled():
                break
            progress.setValue(z)
            if z == 0 and delete:
                continue
            for y in xrange(0, 512):
                image_line = image.scanLine(y)
                if not delete:
                    color_line = color_lines[y]
                for x in xrange(0, 512):
                    if z <= height_values[y][x]:
                        s = x * 4
                        if not delete:
                            image_line[s:s + 4] = color_line[s:s + 4]
                        else:
                            image_line[s:s + 4] = TRANSPARENT_PACKED
            image.dirty = True
        self.set_dirty()
    
    def subtractive_heightmap(self):
        return self.generate_heightmap(True)
    
    def quit(self):
        if self.dirty:
            text = ('Save changes to ' + (self.filename or DEFAULT_FILENAME) +
                ' before closing?')
            reply = QMessageBox.warning(self, self.app.applicationName(), text,
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
                QMessageBox.Yes)
            if reply == QMessageBox.Cancel:
                return
            elif reply == QMessageBox.Yes and not self.save_selected():
                return
        self.app.exit()
Example #12
0
from pyglet.window import key
import math
from pyglet.gl import *

fp = None
for name in ('../feature_server/maps/pyspades.vxl', 
             './feature_server/maps/pyspades.vxl'):
    try:
        fp = open(name, 'rb')
    except IOError:
        pass

if fp is None:
    raise SystemExit('no map file found')

map = VXLData(fp)
fp.close()

def on_fall(damage):
    print 'on fall:', damage

new_world = world.World()
new_world.map = map
character = new_world.create_object(world.Character,
    Vertex3(20.0, 20.0, 5.0), Vertex3(0.999992012978, 0.0, -0.00399998947978),
    on_fall)

window = pyglet.window.Window(width = 600, height = 600,
    resizable=True)

keyboard = key.KeyStateHandler()
Example #13
0
def load_map_from_path(path):
    with open(path, 'rb') as f:
        return VXLData(f)