Esempio n. 1
0
    def run_operation(
        self,
        operation: Callable[[], OperationReturnType],
        title="Amulet",
        msg="Running Operation",
        throw_exceptions=False,
    ) -> Any:
        def operation_wrapper():
            yield 0, "Disabling Threads"
            self.renderer.disable_threads()
            yield 0, msg
            op = operation()
            if isinstance(op, GeneratorType):
                yield from op
            yield 0, "Creating Undo Point"
            yield from self.create_undo_point_iter()
            return op

        err = None
        out = None
        try:
            out = show_loading_dialog(
                operation_wrapper,
                title,
                msg,
                self,
            )
        except OperationError as e:
            msg = f"Error running operation: {e}"
            log.info(msg)
            self.world.restore_last_undo_point()
            wx.MessageDialog(self, msg, style=wx.OK).ShowModal()
            err = e
        except OperationSuccessful as e:
            msg = str(e)
            log.info(msg)
            self.world.restore_last_undo_point()
            wx.MessageDialog(self, msg, style=wx.OK).ShowModal()
            err = e
        except OperationSilentAbort as e:
            self.world.restore_last_undo_point()
            err = e
        except Exception as e:
            log.error(traceback.format_exc())
            dialog = TracebackDialog(
                self,
                "Exception while running operation",
                str(e),
                traceback.format_exc(),
            )
            dialog.ShowModal()
            dialog.Destroy()
            err = e
            self.world.restore_last_undo_point()

        self.renderer.enable_threads()
        self.renderer.render_world.rebuild_changed()
        if err is not None and throw_exceptions:
            raise err
        return out
Esempio n. 2
0
 def create_geometry(self):
     try:
         chunk = self.chunk
     except ChunkDoesNotExist:
         self._create_empty_geometry()
         self._chunk_state = 0
     except ChunkLoadError:
         log.info(f"Error loading chunk {self.coords}", exc_info=True)
         self._create_error_geometry()
         self._chunk_state = 1
     else:
         self._changed_time = chunk.changed_time
         self._chunk_state = 2
         chunk_verts, chunk_verts_translucent = self._create_lod0_multi(
             self._sub_chunks(chunk.blocks))
         self._set_verts(chunk_verts, chunk_verts_translucent)
         if self._draw_floor or self._draw_ceil:
             plane = self._create_grid(
                 "amulet",
                 "amulet_ui/translucent_white",
                 (0.55, 0.5, 0.9) if (self.cx + self.cz) % 2 else
                 (0.4, 0.4, 0.85),
             )
             self.verts = numpy.concatenate([self.verts, plane.ravel()], 0)
             self.draw_count += len(plane)
     self._needs_rebuild = True
Esempio n. 3
0
 def _create_atlas(self):
     texture_atlas, self._texture_bounds, width, height = textureatlas.create_atlas(
         self._resource_pack.textures)
     glBindTexture(GL_TEXTURE_2D, self._gl_texture_atlas)
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
                  GL_UNSIGNED_BYTE, texture_atlas)
     log.info('Finished setting up texture atlas in OpenGL')
    def _setup_texture(self, context_id: str):
        """Set up the texture for a given context"""
        gl_texture = self._gl_textures[context_id] = glGenTextures(
            1
        )  # Create the texture location
        glBindTexture(GL_TEXTURE_2D, gl_texture)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)

        glBindTexture(GL_TEXTURE_2D, gl_texture)
        glTexImage2D(
            GL_TEXTURE_2D,
            0,
            GL_RGBA,
            self._image_width,
            self._image_height,
            0,
            GL_RGBA,
            GL_UNSIGNED_BYTE,
            self._image,
        )
        glBindTexture(GL_TEXTURE_2D, 0)
        log.info("Finished setting up texture atlas in OpenGL")
    def reload_operations(self):
        """Reload all operations and repopulate the UI."""
        # store the id of the old operation
        operation_id = self.active_operation_id

        # reload the operations
        self._operations.reload()

        # repopulate the selection
        self._operation_choice.SetItems(
            {op.identifier: op.name for op in self._operations.operations}
        )

        if operation_id:
            identifiers = self._operation_choice.values

            if identifiers:
                if operation_id in identifiers:
                    self._operation_choice.SetSelection(identifiers.index(operation_id))
                else:
                    log.info(f"Operation {operation_id} was not found.")
                    self._operation_choice.SetSelection(0)
            else:
                log.error("No operations found. Something has gone wrong.")

            self._setup_operation()
            self.canvas.reset_bound_events()
    def __init__(self, parent: wx.Window, world_dirs, open_world_callback, sort=True):
        super().__init__(parent)
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)

        self.worlds = []

        world_formats = []
        for world_path in world_dirs:
            if os.path.isdir(world_path):
                try:
                    world_formats.append(load_format(world_path))
                except FormatError as e:
                    log.info(f"Could not find loader for {world_path} {e}")
                except Exception:
                    log.error(
                        f"Error loading format wrapper for {world_path} {traceback.format_exc()}"
                    )
        if sort:
            world_formats = reversed(sorted(world_formats, key=lambda f: f.last_played))

        for world_format in world_formats:
            try:
                world_button = WorldUIButton(self, world_format, open_world_callback)
                sizer.Add(
                    world_button, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 5
                )
                self.worlds.append(world_button)
            except Exception as e:
                log.info(f"Failed to display world button for {world_format.path} {e}")

        self.Layout()
Esempio n. 7
0
 def create_geometry(self):
     try:
         chunk = self.chunk
     except ChunkDoesNotExist:
         self._create_empty_geometry()
         self._chunk_state = 0
     except ChunkLoadError:
         log.info(f"Error loading chunk {self.coords}", exc_info=True)
         self._create_error_geometry()
         self._chunk_state = 1
     else:
         self._changed_time = chunk.changed_time
         self._chunk_state = 2
         chunk_verts, chunk_verts_translucent = self._create_lod0_multi(
             self._sub_chunks(chunk.blocks))
         self._set_verts(chunk_verts, chunk_verts_translucent)
         if self._draw_floor:
             plane: numpy.ndarray = numpy.ones((self._vert_len * 12),
                                               dtype=numpy.float32).reshape(
                                                   (-1, self._vert_len))
             plane[:, :3], plane[:, 3:5] = self._create_chunk_plane(-0.01)
             plane[:, 5:9] = self.resource_pack.texture_bounds(
                 self.resource_pack.get_texture_path(
                     "amulet", "amulet_ui/translucent_white"))
             if (self.cx + self.cz) % 2:
                 plane[:, 9:12] = [0.55, 0.5, 0.9]
             else:
                 plane[:, 9:12] = [0.4, 0.4, 0.85]
             self.verts = numpy.concatenate([self.verts, plane.ravel()], 0)
             self.draw_count += 12
     self._rebuild = True
Esempio n. 8
0
 def _check_close_world(self) -> bool:
     """
     Check if it is safe to close the world and prompt the user if it is not.
     :return: True if the world can be closed, False otherwise
     """
     unsaved_changes = self._world.history_manager.unsaved_changes
     if unsaved_changes:
         msg = wx.MessageDialog(
             self,
             f"""There {
             'is' if unsaved_changes == 1 else 'are'
             } {unsaved_changes} unsaved change{
             's' if unsaved_changes >= 2 else ''
             } in {
             self._world.level_wrapper.level_name
             }. Would you like to save?""",
             style=wx.YES_NO | wx.CANCEL | wx.CANCEL_DEFAULT,
         )
         response = msg.ShowModal()
         if response == wx.ID_YES:
             self._canvas.save()
             return True
         elif response == wx.ID_NO:
             return True
         elif response == wx.ID_CANCEL:
             log.info(f"""Aborting closing world {
                 self._world.level_wrapper.level_name
                 } because the user pressed cancel.""")
             return False
     return True
Esempio n. 9
0
    def __init__(self, parent, world_dirs, open_world_callback, sort=True):
        super(WorldList, self).__init__(parent)

        self.worlds = []

        world_formats = []
        for world_path in world_dirs:
            if os.path.isdir(world_path):
                try:
                    world_formats.append(
                        world_interface.load_format(world_path))
                except Exception as e:
                    log.info(f"Could not find loader for {world_path} {e}")
        if sort:
            world_formats = reversed(
                sorted(world_formats, key=lambda f: f.last_played))

        for world_format in world_formats:
            try:
                world_button = WorldUIButton(self, world_format,
                                             open_world_callback)
                self.add_object(world_button, 0, wx.ALL | wx.EXPAND)
                self.worlds.append(world_button)
            except Exception as e:
                log.info(
                    f"Failed to display world button for {world_format.world_path} {e}"
                )

        self.Layout()
Esempio n. 10
0
 def is_closeable(self) -> bool:
     """
     Check if it is safe to close the UI.
     :return: True if the program can be closed, False otherwise
     """
     if self._canvas is not None:
         if self._canvas.is_closeable():
             return self._check_close_world()
         log.info(f"The canvas in edit for world {self._world.world_wrapper.world_name} was not closeable for some reason.")
         return False
     return not bool(self._world.chunk_history_manager.unsaved_changes)
Esempio n. 11
0
 def _on_close_app(self, evt):
     close = True
     for path, page in list(self._open_worlds.items()):
         page: CLOSEABLE_PAGE_TYPE
         if page.is_closeable():
             self.close_world(path)
         else:
             log.info(f"{page.world_name} cannot be closed.")
             close = False
     if close:
         evt.Skip()
     else:
         wx.MessageBox('A world is still being used. Please close it first')
Esempio n. 12
0
    def run_operation(self,
                      operation: Callable[[], OperationReturnType],
                      title="",
                      msg="",
                      throw_exceptions=False) -> Any:
        self._disable_threads()
        err = None
        out = None
        try:
            out = show_loading_dialog(
                operation,
                title,
                msg,
                self,
            )
            self.world.create_undo_point()
            wx.PostEvent(self, CreateUndoEvent())
        except OperationError as e:
            msg = f"Error running operation: {e}"
            log.info(msg)
            self.world.restore_last_undo_point()
            wx.MessageDialog(self, msg, style=wx.OK).ShowModal()
            err = e
        except OperationSuccessful as e:
            msg = str(e)
            log.info(msg)
            self.world.restore_last_undo_point()
            wx.MessageDialog(self, msg, style=wx.OK).ShowModal()
            err = e
        except OperationSilentAbort as e:
            self.world.restore_last_undo_point()
            err = e
        except Exception as e:
            self.world.restore_last_undo_point()
            log.error(traceback.format_exc())
            wx.MessageDialog(
                self,
                f"Exception running operation: {e}\nSee the console for more details",
                style=wx.OK).ShowModal()
            err = e

        self._enable_threads()
        if err is not None and throw_exceptions:
            raise err
        return out
Esempio n. 13
0
 def _convert_method(self):
     global work_count
     try:
         out_world = world_interface.load_format(self.out_world_path)
         log.info(f'Converting world {self.world.world_path} to {out_world.world_path}')
         out_world: WorldFormatWrapper
         out_world.open()
         self.world.save(out_world, self._update_loading_bar)
         out_world.close()
         message = 'World conversion completed'
         log.info(f'Finished converting world {self.world.world_path} to {out_world.world_path}')
     except Exception as e:
         message = f'Error during conversion\n{e}'
         log.error(message, exc_info=True)
     self._update_loading_bar(0, 100)
     self.convert_button.Enable()
     wx.MessageBox(
         message
     )
     work_count -= 1
Esempio n. 14
0
 def _convert_method(self):
     global work_count
     try:
         out_world = load_format(self.out_world_path)
         log.info(
             f"Converting world {self.world.level_path} to {out_world.path}"
         )
         out_world: WorldFormatWrapper
         out_world.open()
         self.world.save(out_world, self._update_loading_bar)
         out_world.close()
         message = lang.get("program_convert.conversion_completed")
         log.info(
             f"Finished converting world {self.world.level_path} to {out_world.path}"
         )
     except Exception as e:
         message = f"Error during conversion\n{e}"
         log.error(message, exc_info=True)
     self._update_loading_bar(0, 100)
     self.convert_button.Enable()
     wx.MessageBox(message)
     work_count -= 1
Esempio n. 15
0
def create_atlas_iter(
    texture_tuple: Tuple[str, ...]
) -> Generator[float, None, Tuple[numpy.ndarray, Dict[Any, Tuple[
        float, float, float, float]], int, int], ]:
    log.info("Creating texture atlas")
    # Parse texture names
    textures = []
    for texture_index, texture in enumerate(texture_tuple):
        if not texture_index % 100:
            yield texture_index / (len(texture_tuple) * 2)
        # Look for a texture name
        name, frames = texture, [texture]

        # Build frame objects
        frames = [Frame(f) for f in frames]

        # Add frames to texture object list
        textures.append(Texture(name, frames))

    # Sort textures by perimeter size in non-increasing order
    textures = sorted(textures,
                      key=lambda i: i.frames[0].perimeter,
                      reverse=True)

    height = 0
    width = 0
    pixels = 0
    for t in textures:
        for f in t.frames:
            height = max(f.height, height)
            width = max(f.width, width)
            pixels += f.height * f.width

    size = max(height, width, 1 << (math.ceil(pixels**0.5) - 1).bit_length())

    atlas_created = False
    atlas = None
    while not atlas_created:
        try:
            # Create the atlas and pack textures in
            log.info(
                f"Trying to pack textures into image of size {size}x{size}")
            atlas = TextureAtlas(size, size)

            for texture_index, texture in enumerate(textures):
                if not texture_index % 30:
                    yield 0.5 + texture_index / (len(textures) / 2)
                atlas.pack(texture)
            atlas_created = True
        except AtlasTooSmall:
            log.info(f"Image was too small. Trying with a larger area")
            size *= 2

    log.info(
        f"Successfully packed textures into an image of size {size}x{size}")

    texture_atlas = numpy.array(atlas.generate("RGBA"), numpy.uint8).ravel()

    texture_bounds = atlas.to_dict()
    texture_bounds = {
        texture_path: texture_bounds[texture_path]
        for texture_path in texture_tuple
    }

    log.info("Finished creating texture atlas")
    return texture_atlas, texture_bounds, atlas.width, atlas.height
Esempio n. 16
0
 def is_closeable(self):
     if work_count:
         log.info(f'World {self.world.world_path} is still being converted. Please let it finish before closing')
     return work_count == 0
Esempio n. 17
0
def create_atlas(
    texture_dict: Dict[Any, str]
) -> Tuple[numpy.ndarray, Dict[Any, Tuple[float, float, float, float]], int,
           int]:
    log.info('Creating texture atlas')
    # Parse texture names
    textures = []
    for texture in texture_dict.values():
        # Look for a texture name
        name, frames = texture, [texture]

        # Build frame objects
        frames = [Frame(f) for f in frames]

        # Add frames to texture object list
        textures.append(Texture(name, frames))

    # Sort textures by perimeter size in non-increasing order
    textures = sorted(textures,
                      key=lambda i: i.frames[0].perimeter,
                      reverse=True)

    height = 0
    width = 0
    pixels = 0
    for t in textures:
        for f in t.frames:
            height = max(f.height, height)
            width = max(f.width, width)
            pixels += f.height * f.width

    size = max(height, width, 1 << (math.ceil(pixels**0.5) - 1).bit_length())

    atlas_created = False
    atlas = None
    while not atlas_created:
        try:
            # Create the atlas and pack textures in
            log.info(
                f'Trying to pack textures into image of size {size}x{size}')
            atlas = TextureAtlas(size, size)

            for texture in textures:
                atlas.pack(texture)
            atlas_created = True
        except AtlasTooSmall:
            log.info(f'Image was too small. Trying with a larger area')
            size *= 2

    log.info(
        f'Successfully packed textures into an image of size {size}x{size}')

    texture_atlas = numpy.array(atlas.generate('RGBA'), numpy.uint8).ravel()

    texture_bounds = atlas.to_dict()
    texture_bounds = {
        tex_id: texture_bounds[texture_path]
        for tex_id, texture_path in texture_dict.items()
    }

    log.info('Finished creating texture atlas')
    return texture_atlas, texture_bounds, atlas.width, atlas.height