Exemple #1
0
  def do_render(id: str) -> None:
    nonlocal view

    if view is None:
      view = View(model)
    ig.push_id(id)

    log.timer.begin('render')
    view.render()
    log.timer.end()

    ig.pop_id()


    last_fps_time = use_state_with('last-fps-time', lambda: time.time())
    frame_count = use_state('frame-count', 0)
    fps = use_state('fps', 0.0)

    if hasattr(model, 'pipeline'):
      frame_count.value += 1
      if time.time() > last_fps_time.value + 5:
        fps.value = frame_count.value / (time.time() - last_fps_time.value)
        last_fps_time.value = time.time()
        frame_count.value = 0
        log.info(
          f'mspf: {int(1000 / fps.value * 10) / 10} ({int(fps.value)} fps)'
          f' - cache={model.pipeline.data_cache_size() // 1024}KB'
        )

      log.timer.begin('balance')
      model.pipeline.balance_distribution(1/120)
      log.timer.end()
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:
    ig.push_id(str(epoch))

    # if ig.is_key_pressed(ord('`')):
    #   self.show_debug_pane = not self.show_debug_pane

    self.handle_controller()

    prev_frame_time = use_state_with('prev-frame-time', time.time)
    accum_time = use_state('accum-time', 0.0)
    now = time.time()
    accum_time.value += now - prev_frame_time.value
    prev_frame_time.value = now

    play_speed = self.model.play_speed
    if play_speed == 0.0:
      accum_time.value = 0
    else:
      target_fps = 30 * abs(play_speed)
      target_dt = 1 / target_fps
      updates = 0
      while accum_time.value >= target_dt and updates < 20:
        accum_time.value -= target_dt
        self.model.selected_frame += 1 if play_speed > 0 else -1
        self.handle_controller()
        updates += 1

    ig_window_size = ig.get_window_size()
    window_size = (int(ig_window_size.x), int(ig_window_size.y))

    ig.columns(2)
    self.render_left_column(window_size)
    ig.next_column()
    self.render_right_column()
    ig.columns(1)

    ig.pop_id()
Exemple #4
0
  def handle_controller(self) -> None:
    ig.push_id('controller-inputs')

    buttons_enabled = use_state('buttons-enabled', False)
    stick_enabled = use_state('stick-enabled', False)

    def add_callbacks() -> Ref[bool]:
      input_edit = Ref(False)
      def disable_controller(*args, **kwargs) -> None:
        if not input_edit.value:
          buttons_enabled.value = False
          stick_enabled.value = False
      self.model.on_edit(disable_controller)

      def frame_change(*args, **kwargs) -> None:
        if self.model.play_speed == 0.0:
          disable_controller()
      self.model.on_selected_frame_change(frame_change)
      return input_edit
    input_edit = use_state_with('initialize', add_callbacks).value

    prev_play_speed = use_state('prev-play-speed', 0.0)
    if self.model.play_speed != prev_play_speed.value:
      buttons_enabled.value = False
      stick_enabled.value = False
    prev_play_speed.value = self.model.play_speed

    controller_button_values = {
      'input-button-a': input_down('n64-A'),
      'input-button-b': input_down('n64-B'),
      'input-button-z': input_down('n64-Z'),
      'input-button-s': input_down('n64-S'),
      'input-button-l': input_down('n64-L'),
      'input-button-r': input_down('n64-R'),
      'input-button-cu': input_down('n64-C^'),
      'input-button-cl': input_down('n64-C<'),
      'input-button-cr': input_down('n64-C>'),
      'input-button-cd': input_down('n64-Cv'),
      'input-button-du': input_down('n64-D^'),
      'input-button-dl': input_down('n64-D<'),
      'input-button-dr': input_down('n64-D>'),
      'input-button-dd': input_down('n64-Dv'),
    }
    if any(controller_button_values.values()):
      buttons_enabled.value = True
      stick_enabled.value = True
    for variable_name, new_button_value in controller_button_values.items():
      variable = Variable(variable_name).with_frame(self.model.selected_frame)
      button_value = self.model.get(variable)
      if buttons_enabled.value and button_value != new_button_value:
        input_edit.value = True
        self.model.set(variable, new_button_value)
        input_edit.value = False

    controller_stick_values = (
      input_float('n64->') - input_float('n64-<'),
      input_float('n64-^') - input_float('n64-v'),
    )
    # Require a larger magnitude for enabling controller since dead zone may be too small
    if any(abs(v) > 0.1 for v in controller_stick_values):
      stick_enabled.value = True
      buttons_enabled.value = True
    if stick_enabled.value:
      stick_x_var = Variable('input-stick-x').with_frame(self.model.selected_frame)
      stick_y_var = Variable('input-stick-y').with_frame(self.model.selected_frame)
      new_stick = self.compute_stick_from_controller(*controller_stick_values)
      stick = (self.model.get(stick_x_var), self.model.get(stick_y_var))
      if stick != new_stick:
        input_edit.value = True
        self.model.set(stick_x_var, new_stick[0])
        self.model.set(stick_y_var, new_stick[1])
        input_edit.value = False

    ig.pop_id()
Exemple #5
0
def use_rotational_camera(
    framebuffer_size: Tuple[int, int],
    model: Model,
) -> Tuple[core.RotateCamera, bool]:
    mouse_state = use_state('mouse-state', MouseTracker()).value
    target: Ref[Optional[Vec3f]] = use_state('target', None)
    target_vel: Ref[Optional[Vec3f]] = use_state('target-vel', None)
    pitch = use_state('pitch', 0.0)
    yaw = use_state('yaw', 0.0)
    zoom = use_state('zoom', 0.0)
    prev_frame_time = use_state_with('prev-frame-time', time.time)
    lock_to_in_game = use_state('lock-to-in-game', False)

    delta_time = time.time() - prev_frame_time.value
    prev_frame_time.value = time.time()

    drag_amount = mouse_state.get_drag_amount()
    pitch.value -= drag_amount[1] / 200
    yaw.value -= drag_amount[0] / 200
    wheel_amount = mouse_state.get_wheel_amount()
    zoom.value += wheel_amount / 5
    zoom.value = min(zoom.value, 7.0)

    mario_pos = get_mario_pos(model)
    target_pos = mario_pos if target.value is None else target.value

    fov_y = math.radians(45)

    if drag_amount != (0.0, 0.0) or wheel_amount != 0.0:
        lock_to_in_game.value = False

    if lock_to_in_game.value:
        target_pos = cast(
            Vec3f, model.get(model.selected_frame, 'gLakituState.focus'))
        target.value = target_pos
        camera_pos = cast(Vec3f,
                          model.get(model.selected_frame, 'gLakituState.pos'))
        dpos = (
            target_pos[0] - camera_pos[0],
            target_pos[1] - camera_pos[1],
            target_pos[2] - camera_pos[2],
        )
        pitch.value, yaw.value = direction_to_angle(dpos)
        offset = math.sqrt(sum(c**2 for c in dpos))
        if offset > 0.001:
            zoom.value = math.log(offset / 1500, 0.5)
        fov_y = math.radians(
            cast(float, model.get(model.selected_frame, 'sFOVState.fov')))

    offset = 1500 * math.pow(0.5, zoom.value)
    face_direction = angle_to_direction(pitch.value, yaw.value)

    move = [0.0, 0.0, 0.0]  # forward, up, right
    move[0] += input_float('3d-camera-move-f')
    move[0] -= input_float('3d-camera-move-b')
    move[1] += input_float('3d-camera-move-u')
    move[1] -= input_float('3d-camera-move-d')
    move[2] += input_float('3d-camera-move-r')
    move[2] -= input_float('3d-camera-move-l')

    if move != [0.0, 0.0, 0.0] or (target.value is not None
                                   and not lock_to_in_game.value):
        mag = math.sqrt(sum(c**2 for c in move))
        if mag > 1:
            move = [c / mag for c in move]

        max_speed = 50.0 * delta_time * math.sqrt(offset)
        f = (math.sin(yaw.value), 0, math.cos(yaw.value))
        u = (0, 1, 0)
        r = (-f[2], 0, f[0])
        end_vel = cast(
            Vec3f,
            tuple(max_speed * move[0] * f[i] + max_speed * move[1] * u[i] +
                  max_speed * move[2] * r[i] for i in range(3)))

        accel = 10.0 * delta_time * math.sqrt(offset)
        current_vel = target_vel.value or (0.0, 0.0, 0.0)
        target_vel.value = move_toward(current_vel, end_vel, accel)
        target.value = (
            target_pos[0] + target_vel.value[0],
            target_pos[1] + target_vel.value[1],
            target_pos[2] + target_vel.value[2],
        )
        target_pos = target.value
        lock_to_in_game.value = False

    if ig.disableable_button('Lock to Mario', enabled=target.value
                             is not None):
        target.value = None
        target_vel.value = None
        lock_to_in_game.value = False
    ig.same_line()
    if ig.disableable_button('Lakitu', enabled=not lock_to_in_game.value):
        lock_to_in_game.value = True

    camera_pos = (
        target_pos[0] - offset * face_direction[0],
        target_pos[1] - offset * face_direction[1],
        target_pos[2] - offset * face_direction[2],
    )

    camera = core.RotateCamera()
    camera.pos = camera_pos
    camera.target = target_pos
    camera.fov_y = fov_y

    show_camera_target = target.value is not None and not lock_to_in_game.value

    return camera, show_camera_target
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,
    )