McRogueFace/tests/demo/viewport3d_demo.py

167 lines
5.5 KiB
Python

# viewport3d_demo.py - Visual demo of Viewport3D integration
# Shows the 3D viewport as a UIDrawable alongside 2D elements
import mcrfpy
import sys
import math
# Create demo scene
scene = mcrfpy.Scene("viewport3d_demo")
# Dark background frame
bg = mcrfpy.Frame(pos=(0, 0), size=(1024, 768), fill_color=mcrfpy.Color(20, 20, 30))
scene.children.append(bg)
# Title
title = mcrfpy.Caption(text="Viewport3D Demo - PS1-Style 3D Rendering", pos=(20, 10))
title.fill_color = mcrfpy.Color(255, 255, 255)
scene.children.append(title)
# Create the 3D viewport - this is the star of the show!
viewport = mcrfpy.Viewport3D(
pos=(50, 60),
size=(600, 450),
render_resolution=(320, 240), # PS1 resolution for that retro look
fov=60.0,
camera_pos=(5.0, 3.0, 5.0),
camera_target=(0.0, 0.0, 0.0),
bg_color=mcrfpy.Color(25, 25, 50) # Dark blue background
)
scene.children.append(viewport)
# Info panel on the right
info_panel = mcrfpy.Frame(pos=(670, 60), size=(330, 450),
fill_color=mcrfpy.Color(30, 30, 40),
outline_color=mcrfpy.Color(80, 80, 100),
outline=2.0)
scene.children.append(info_panel)
# Panel title
panel_title = mcrfpy.Caption(text="Viewport Properties", pos=(690, 70))
panel_title.fill_color = mcrfpy.Color(200, 200, 255)
scene.children.append(panel_title)
# Property labels
props = [
("Position:", f"({viewport.x}, {viewport.y})"),
("Size:", f"{viewport.w}x{viewport.h}"),
("Render Res:", f"{viewport.render_resolution[0]}x{viewport.render_resolution[1]}"),
("FOV:", f"{viewport.fov} degrees"),
("Camera Pos:", f"({viewport.camera_pos[0]:.1f}, {viewport.camera_pos[1]:.1f}, {viewport.camera_pos[2]:.1f})"),
("Camera Target:", f"({viewport.camera_target[0]:.1f}, {viewport.camera_target[1]:.1f}, {viewport.camera_target[2]:.1f})"),
("", ""),
("PS1 Effects:", ""),
(" Vertex Snap:", "ON" if viewport.enable_vertex_snap else "OFF"),
(" Affine Map:", "ON" if viewport.enable_affine else "OFF"),
(" Dithering:", "ON" if viewport.enable_dither else "OFF"),
(" Fog:", "ON" if viewport.enable_fog else "OFF"),
(" Fog Range:", f"{viewport.fog_near} - {viewport.fog_far}"),
]
y_offset = 100
for label, value in props:
if label:
cap = mcrfpy.Caption(text=f"{label} {value}", pos=(690, y_offset))
cap.fill_color = mcrfpy.Color(180, 180, 200)
scene.children.append(cap)
y_offset += 22
# Instructions at bottom
instructions = mcrfpy.Caption(
text="[1-4] Toggle PS1 effects | [WASD] Move camera | [Q/E] Camera height | [ESC] Quit",
pos=(20, 530)
)
instructions.fill_color = mcrfpy.Color(150, 150, 150)
scene.children.append(instructions)
# Status line
status = mcrfpy.Caption(text="Status: Viewport3D rendering PS1-style 3D cube", pos=(20, 555))
status.fill_color = mcrfpy.Color(100, 200, 100)
scene.children.append(status)
# Animation state
animation_time = [0.0]
camera_orbit = [True]
# Camera orbit animation
def update_camera(timer, runtime):
animation_time[0] += runtime / 1000.0
if camera_orbit[0]:
# Orbit camera around origin
angle = animation_time[0] * 0.5 # Slow rotation
radius = 7.0
height = 4.0 + math.sin(animation_time[0] * 0.3) * 2.0
x = math.cos(angle) * radius
z = math.sin(angle) * radius
viewport.camera_pos = (x, height, z)
# Key handler
def on_key(key, state):
if state != mcrfpy.InputState.PRESSED:
return
key_name = str(key)
# Toggle PS1 effects with number keys
if key == mcrfpy.Key.NUM_1:
viewport.enable_vertex_snap = not viewport.enable_vertex_snap
status.text = f"Vertex Snap: {'ON' if viewport.enable_vertex_snap else 'OFF'}"
elif key == mcrfpy.Key.NUM_2:
viewport.enable_affine = not viewport.enable_affine
status.text = f"Affine Mapping: {'ON' if viewport.enable_affine else 'OFF'}"
elif key == mcrfpy.Key.NUM_3:
viewport.enable_dither = not viewport.enable_dither
status.text = f"Dithering: {'ON' if viewport.enable_dither else 'OFF'}"
elif key == mcrfpy.Key.NUM_4:
viewport.enable_fog = not viewport.enable_fog
status.text = f"Fog: {'ON' if viewport.enable_fog else 'OFF'}"
# Camera controls
elif key == mcrfpy.Key.SPACE:
camera_orbit[0] = not camera_orbit[0]
status.text = f"Camera orbit: {'ON' if camera_orbit[0] else 'OFF (manual control)'}"
elif key == mcrfpy.Key.ESCAPE:
mcrfpy.exit()
# Manual camera movement (when orbit is off)
if not camera_orbit[0]:
pos = list(viewport.camera_pos)
speed = 0.5
if key == mcrfpy.Key.W:
pos[2] -= speed
elif key == mcrfpy.Key.S:
pos[2] += speed
elif key == mcrfpy.Key.A:
pos[0] -= speed
elif key == mcrfpy.Key.D:
pos[0] += speed
elif key == mcrfpy.Key.Q:
pos[1] -= speed
elif key == mcrfpy.Key.E:
pos[1] += speed
viewport.camera_pos = tuple(pos)
status.text = f"Camera: ({pos[0]:.1f}, {pos[1]:.1f}, {pos[2]:.1f})"
# Set up scene
scene.on_key = on_key
# Create timer for camera animation
timer = mcrfpy.Timer("camera_update", update_camera, 16) # ~60fps
# Activate scene
mcrfpy.current_scene = scene
print("Viewport3D Demo loaded!")
print("3D rendering enabled - spinning colored cube should be visible.")
print()
print("Controls:")
print(" [1-4] Toggle PS1 effects")
print(" [Space] Toggle camera orbit")
print(" [WASD/QE] Manual camera control (when orbit off)")
print(" [ESC] Quit")