def render_input_tab(self, tab: TabId) -> None:
        column_sizes = [170, 370, 200]

        ig.set_next_window_content_size(sum(column_sizes), 0)
        ig.begin_child('##input', flags=ig.WINDOW_HORIZONTAL_SCROLLING_BAR)
        ig.columns(3)

        for i, w in enumerate(column_sizes):
            ig.set_column_width(i, w)

        def render_button(button: str) -> None:
            self.render_variable(
                tab,
                Variable('input-button-' + button).with_frame(
                    self.model.selected_frame),
                10,
                25,
            )

        ig.dummy(1, 3)
        render_button('a')
        ig.same_line()
        render_button('b')
        ig.same_line()
        render_button('z')
        ig.dummy(1, 5)
        render_button('s')
        ig.same_line()
        ig.dummy(43, 1)
        ig.same_line()
        render_button('r')
        ig.dummy(1, 5)
        ig.dummy(43, 1)
        ig.same_line()
        render_button('cu')
        ig.dummy(17, 1)
        ig.same_line()
        render_button('cl')
        ig.same_line()
        render_button('cr')
        ig.dummy(43, 1)
        ig.same_line()
        render_button('cd')

        ig.next_column()
        self.render_intended_stick_control('intended')
        ig.next_column()
        self.render_stick_control('joystick', tab)

        ig.columns(1)
        ig.end_child()
Exemple #2
0
    def render_right_column(self) -> None:
        total_height = ig.get_window_height()

        if self.show_debug_pane:
            ig.push_id('debug-pane')
            ig.begin_child('##pane', height=int(ig.get_window_height() * 0.15))
            ig.columns(2)
            ig.set_column_width(-1, ig.get_window_width() - 300)

            ig.begin_child('##log')

            def init_log() -> List[str]:
                messages = []
                log.subscribe(lambda msg: messages.append(str(msg)))
                return messages

            messages = use_state_with('messages', init_log).value
            prev_length = use_state('prev-length', 0)
            total_height -= ig.get_window_height()
            if prev_length.value != len(messages):
                prev_length.value = len(messages)
                ig.set_scroll_y(ig.get_scroll_max_y() + ig.get_window_height())
            for message in messages:
                ig.text(message)
            ig.end_child()

            ig.next_column()

            for line in log.timer.format(log.timer.get_summaries()):
                ig.text(line)

            ig.columns(1)
            ig.end_child()
            ig.pop_id()

        log.timer.begin('fsheet')
        frame_sheet = self.frame_sheets[0]
        ig.set_next_window_content_size(frame_sheet.get_content_width(), 0)
        ig.begin_child(
            'Frame Sheet##' + str(epoch) + '-0',
            height=int(total_height * 0.7),
            flags=ig.WINDOW_HORIZONTAL_SCROLLING_BAR,
        )
        frame_sheet.render()
        ig.end_child()

        if ig.begin_drag_drop_target():
            payload = ig.accept_drag_drop_payload('ve-var')
            if payload is not None:
                frame_sheet.append_variable(Variable.from_bytes(payload))
            ig.end_drag_drop_target()
        log.timer.end()

        log.timer.begin('varexp')
        ig.begin_child('Variable Explorer', border=True)
        self.variable_explorer.render('variable-explorer')
        ig.end_child()
        log.timer.end()
Exemple #3
0
    def render(self) -> None:
        self.render_headers()
        # TODO: Make the vertical scrollbar always visible?

        ig.begin_child('Frame Sheet Rows',
                       flags=ig.WINDOW_ALWAYS_VERTICAL_SCROLLBAR)
        self.update_scolling()
        min_frame = int(ig.get_scroll_y()) // self.row_height - 1
        self.sequence.set_hotspot('frame-sheet-min', max(min_frame, 0))

        if self.dragging and not ig.is_mouse_down():
            self.drag_handler.release_drag()
            self.dragging = False
        self.render_rows()

        ig.end_child()

        self.columns = list(self.next_columns)
Exemple #4
0
  def render_left_column(self, framebuffer_size: Tuple[int, int]) -> None:
    total_height = ig.get_window_height() - ig.get_frame_height() # subtract menu bar
    slider_space = 45

    wall_hitbox_radius = use_state('wall-hitbox-radius', 50)
    wall_hitbox_options = [0, 24, 50, 110]

    hovered_surface: Ref[Optional[int]] = use_state('hovered-surface', None)
    new_hovered_surface: Optional[int] = None
    hidden_surfaces_by_area = \
      use_state('hidden-surfaces', cast(Dict[Tuple[int, int], Set[int]], {})).value

    current_area = (
      dcast(int, self.model.get(Variable('level-num').with_frame(self.model.selected_frame))),
      dcast(int, self.model.get(Variable('area-index').with_frame(self.model.selected_frame))),
    )
    hidden_surfaces = hidden_surfaces_by_area.setdefault(current_area, set())

    log.timer.begin('gview1')
    ig.begin_child(
      'Game View 1',
      height=int(total_height // 2) - slider_space // 2,
      border=True,
    )
    hovered_surface_1 = ui.render_game_view_rotate(
      'game-view-1',
      framebuffer_size,
      self.model,
      wall_hitbox_radius.value,
      hovered_surface.value,
      hidden_surfaces,
    )

    ig.set_cursor_pos((10.0, ig.get_window_height() - 30))
    ig.text('wall radius')
    ig.same_line()
    ig.push_item_width(50)
    _, index = ig.combo(
      '##wall-hitbox-radius',
      wall_hitbox_options.index(wall_hitbox_radius.value),
      list(map(str, wall_hitbox_options)),
    )
    wall_hitbox_radius.value = wall_hitbox_options[index]
    ig.pop_item_width()

    ig.end_child()
    log.timer.end()

    log.timer.begin('gview2')
    ig.begin_child(
      'Game View 2',
      height=int(total_height // 2) - slider_space // 2,
      border=True,
    )
    hovered_surface_2 = ui.render_game_view_birds_eye(
      'game-view-2',
      framebuffer_size,
      self.model,
      wall_hitbox_radius.value,
      hovered_surface.value,
      hidden_surfaces,
    )
    ig.end_child()
    log.timer.end()

    new_hovered_surface = hovered_surface_1 or hovered_surface_2
    if new_hovered_surface is not None and ig.is_mouse_clicked(1):
      ig.open_popup('surface-ctx')
      hovered_surface.value = new_hovered_surface

    if ig.begin_popup('surface-ctx'):
      if hovered_surface.value is not None:
        if hovered_surface.value in hidden_surfaces:
          if ig.menu_item('Show')[0]:
            hidden_surfaces.remove(hovered_surface.value)
        else:
          if ig.menu_item('Hide')[0]:
            hidden_surfaces.add(hovered_surface.value)
        if ig.menu_item('Properties')[0]:
          self.variable_explorer.open_surface_tab(hovered_surface.value)
      ig.end_popup()
    else:
      hovered_surface.value = new_hovered_surface

    if hovered_surface.value is not None and ig.is_mouse_clicked(2):
      if hovered_surface.value in hidden_surfaces:
        hidden_surfaces.remove(hovered_surface.value)
      else:
        hidden_surfaces.add(hovered_surface.value)


    speed_options = [0.05, 0.25, 0.5, 1, 2, 4]
    saved_play_direction = use_state('saved-play-direction', 0)
    saved_speed_index = use_state('saved-speed-index', 3)

    play_direction = saved_play_direction.value
    speed_index = saved_speed_index.value

    if play_direction == 0:
      frame_advance = 0
      play_override = 0

      def control(name: str, speed: int) -> None:
        nonlocal frame_advance, play_override
        x = input_down_gradual(name, 0.25)
        if x == 1.0:
          play_override = speed
        elif input_pressed(name):
          frame_advance += speed
      control('frame-next', 1)
      control('frame-next-alt', 1)
      control('frame-prev', -1)
      control('frame-prev-alt', -1)
      control('frame-next-fast', 10)
      control('frame-prev-fast', -10)

      if play_override != 0:
        if abs(play_override) in speed_options:
          speed_index = speed_options.index(abs(play_override))
        else:
          speed_index = len(speed_options) - 1
        play_direction = 1 if play_override > 0 else -1
      else:
        self.model.selected_frame += frame_advance

    else:
      if input_down('frame-next') or input_down('frame-next-alt'):
        if play_direction == 1:
          speed_index += 1
        else:
          play_direction = -play_direction
      elif input_down('frame-prev') or input_down('frame-prev-alt'):
        if play_direction == -1:
          speed_index += 1
        else:
          play_direction = -play_direction
      elif input_down('frame-next-fast'):
        if play_direction == 1:
          speed_index += 2
        else:
          play_direction = -play_direction
          speed_index += 1
      elif input_down('frame-prev-fast'):
        if play_direction == -1:
          speed_index += 2
        else:
          play_direction = -play_direction
          speed_index += 1
      speed_index = min(max(speed_index, 0), len(speed_options) - 1)

    self.model.play_speed = play_direction * speed_options[speed_index]
    self.model.playback_mode = saved_play_direction.value != 0

    def play_button(label: str, direction: int) -> None:
      disabled = play_direction == direction
      if ig.disableable_button(label, enabled=play_direction != direction):
        saved_play_direction.value = direction

    play_button('<|', -1)
    ig.same_line()
    play_button('||', 0)
    ig.same_line()
    play_button('|>', 1)
    ig.same_line()

    ig.push_item_width(63)
    changed, new_index = ig.combo(
      '##speed-option',
      speed_index,
      [str(s) + 'x' for s in speed_options],
    )
    ig.pop_item_width()
    if changed:
      saved_speed_index.value = new_index

    if input_pressed('playback-play'):
      if saved_play_direction.value == 0:
        saved_play_direction.value = 1
      else:
        saved_play_direction.value = 0
    if input_pressed('playback-rewind'):
      if saved_play_direction.value == 0:
        saved_play_direction.value = -1
      else:
        saved_play_direction.value = 0
    if input_pressed('playback-speed-up'):
      saved_speed_index.value = min(saved_speed_index.value + 1, len(speed_options) - 1)
    if input_pressed('playback-slow-down'):
      saved_speed_index.value = max(saved_speed_index.value - 1, 0)


    ig.same_line()
    new_frame = ui.render_frame_slider(
      'frame-slider',
      self.model.selected_frame,
      self.model.max_frame - 1,
      self.model.pipeline.cached_frames() if self.show_debug_pane else [],
    )
    if new_frame is not None:
      self.model.selected_frame = new_frame.value
Exemple #5
0
def render_game_view_birds_eye(
    id: str,
    framebuffer_size: Tuple[int, int],
    model: Model,
    wall_hitbox_radius: float,
    hovered_surface: Optional[int],
    hidden_surfaces: Set[int],
) -> Optional[int]:
    ig.push_id(id)

    # TODO: Should zoom in on mouse when uncentered
    mouse_state = use_state('mouse-state', MouseTracker()).value
    zoom = use_state('zoom', -4.5)
    target: Ref[Optional[Tuple[float, float]]] = use_state('target', None)
    pos_y: Ref[Optional[float]] = use_state('pos-y', None)

    drag_amount = mouse_state.get_drag_amount()
    zoom.value += mouse_state.get_wheel_amount() / 5
    world_span_x = 200 / math.pow(2, zoom.value)

    viewport = get_viewport(framebuffer_size)

    mario_pos = get_mario_pos(model)

    # Camera xz

    camera_xz = (mario_pos[0], mario_pos[2])
    if target.value is not None:
        camera_xz = target.value

    if drag_amount != (0.0, 0.0):
        world_span_z = world_span_x * viewport.width / viewport.height
        if target.value is None:
            target.value = (mario_pos[0], mario_pos[2])
        target.value = (
            camera_xz[0] + drag_amount[1] * world_span_x / viewport.height,
            camera_xz[1] - drag_amount[0] * world_span_z / viewport.width,
        )
        camera_xz = target.value

    if ig.disableable_button('Lock to Mario', enabled=target.value
                             is not None):
        target.value = None

    # Camera y

    camera_y = mario_pos[1] + 500 if pos_y.value is None else pos_y.value

    ig.set_cursor_pos((viewport.width - 100, 10))
    ig.begin_child('##y-slider')
    new_y, reset = render_pos_y_slider('y-slider', camera_y, mario_pos[1])
    if reset:
        pos_y.value = None
    elif new_y is not None:
        pos_y.value = new_y
        camera_y = pos_y.value
    ig.end_child()

    camera = core.BirdsEyeCamera()
    camera.pos = (camera_xz[0], camera_y, camera_xz[1])
    camera.span_y = world_span_x

    # Mouse xz
    mouse_world_pos = get_mouse_world_pos_birds_eye(camera)
    mouse_ray: Optional[Tuple[Vec3f, Vec3f]]
    if mouse_world_pos is not None:
        ig.set_cursor_pos((10, viewport.height - 25))
        ig.text('(x, z) = (%.3f, %.3f)' % mouse_world_pos)
        mouse_ray = ((mouse_world_pos[0], camera.pos[1], mouse_world_pos[1]),
                     (0, -1, 0))
    else:
        mouse_ray = None

    if mouse_ray is None:
        new_hovered_surface = None
    else:
        new_hovered_surface = trace_ray(model, mouse_ray)

    render_game(
        model,
        viewport,
        camera,
        False,
        wall_hitbox_radius,
        hovered_surface=hovered_surface,
        hidden_surfaces=hidden_surfaces,
    )

    ig.pop_id()
    return new_hovered_surface
Exemple #6
0
def render_tabs(
    id: str,
    tabs: List[TabInfo],
    open_tab_index: Optional[int] = None,
    allow_windowing=False,
) -> Tuple[Optional[int], Optional[int]]:
    ig.push_id(id)
    root_id = get_local_state_id_stack()
    ig.columns(2)

    closed_tab = None

    rendered = use_state('rendered', False)
    if not rendered.value:
        rendered.value = True
        ig.set_column_width(-1, 120)

    if len(tabs) == 0:
        ig.pop_id()
        return None, closed_tab

    selected_tab_index = use_state_with('selected-tab-index',
                                        lambda: open_tab_index or 0)
    selected_tab_id = use_state_with('selected-tab',
                                     lambda: tabs[selected_tab_index.value].id)

    if open_tab_index is not None:
        selected_tab_index.value = open_tab_index
        selected_tab_id.value = tabs[open_tab_index].id

    windowed_tabs = use_state('windowed-tabs', cast(Set[str], set())).value

    # TODO: Change selected tab if windowed

    # Handle deletion/insertion
    if selected_tab_index.value >= len(tabs):
        selected_tab_index.value = len(tabs) - 1
    if tabs[selected_tab_index.value].id != selected_tab_id.value:
        matching_indices = [
            i for i in range(len(tabs)) if tabs[i].id == selected_tab_id.value
        ]
        if len(matching_indices) > 0:
            selected_tab_index.value = matching_indices[0]
        else:
            selected_tab_id.value = tabs[selected_tab_index.value].id

    ig.begin_child('tabs')
    for i, tab in enumerate(tabs):
        if tab.id in windowed_tabs:
            continue

        _, selected = ig.selectable(
            tab.label + '##tab-' + tab.id,
            selected_tab_id.value == tab.id,
        )
        if selected:
            selected_tab_index.value = i
            selected_tab_id.value = tab.id

        if tab.closable and ig.is_item_hovered() and ig.is_mouse_clicked(2):
            closed_tab = i

        if allow_windowing or tab.closable:
            if ig.begin_popup_context_item(f'##ctx-{tab.id}'):
                if allow_windowing and ig.selectable('Pop out')[0]:
                    windowed_tabs.add(tab.id)
                if tab.closable and ig.selectable('Close')[0]:
                    closed_tab = i
                ig.end_popup_context_item()

    ig.end_child()

    ig.next_column()

    ig.begin_child('content', flags=ig.WINDOW_HORIZONTAL_SCROLLING_BAR)
    tab = tabs[selected_tab_index.value]
    if tab.id not in windowed_tabs:
        push_local_state_rebase(('rebase-tabs', ) + root_id)
        tab.render(tab.id)  # type: ignore
        pop_local_state_rebase()
    ig.end_child()

    ig.columns(1)

    for tab_id in set(windowed_tabs):
        matching = [tab for tab in tabs if tab.id == tab_id]
        if len(matching) == 0:
            windowed_tabs.remove(tab.id)
            continue
        tab = matching[0]

        ig.set_next_window_size(*ig.get_window_size(), ig.ONCE)
        ig.set_next_window_position(*ig.get_window_position(), ig.ONCE)

        ig.push_style_color(ig.COLOR_WINDOW_BACKGROUND, 0.06, 0.06, 0.06, 0.94)
        _, opened = ig.begin(
            tab.label + '##window-' + tab.id,
            closable=True,
            flags=ig.WINDOW_HORIZONTAL_SCROLLING_BAR,
        )
        push_local_state_rebase(('rebase-tabs', ) + root_id)
        tab.render(tab.id)  # type: ignore
        pop_local_state_rebase()
        ig.end()
        ig.pop_style_color()

        if not opened:
            windowed_tabs.remove(tab.id)

    ig.pop_id()
    return (
        None if open_tab_index == selected_tab_index.value else
        selected_tab_index.value,
        closed_tab,
    )