Skip to content

Commit

Permalink
Wind Waker: Move dCamera_c to d_camera.ts
Browse files Browse the repository at this point in the history
No logic changes
  • Loading branch information
themikelester committed Dec 28, 2024
1 parent 778e86a commit e6f8d8e
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 178 deletions.
184 changes: 8 additions & 176 deletions src/ZeldaWindWaker/Main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import { mat4, vec3, vec4 } from 'gl-matrix';
import { mat4, vec3 } from 'gl-matrix';

import ArrayBufferSlice from '../ArrayBufferSlice.js';
import { DataFetcher } from '../DataFetcher.js';
Expand All @@ -10,32 +10,28 @@ import * as BYML from '../byml.js';
import * as UI from '../ui.js';
import * as Viewer from '../viewer.js';

import { Camera, texProjCameraSceneTex } from '../Camera.js';
import { texProjCameraSceneTex } from '../Camera.js';
import { TransparentBlack } from '../Color.js';
import * as Yaz0 from '../Common/Compression/Yaz0.js';
import { J3DModelInstance } from '../Common/JSYSTEM/J3D/J3DGraphBase.js';
import * as JPA from '../Common/JSYSTEM/JPA.js';
import { BTIData } from '../Common/JSYSTEM/JUTTexture.js';
import { dfRange } from '../DebugFloaters.js';
import { Frustum } from '../Geometry.js';
import { MathConstants, clamp, getMatrixAxisZ, getMatrixTranslation, lerp, projectionMatrixForFrustum, range } from '../MathHelpers.js';
import { range } from '../MathHelpers.js';
import { SceneContext } from '../SceneBase.js';
import { TextureMapping } from '../TextureHolder.js';
import { projectionMatrixConvertClipSpaceNearZ } from '../gfx/helpers/ProjectionHelpers.js';
import { setBackbufferDescSimple, standardFullClearRenderPassDescriptor } from '../gfx/helpers/RenderGraphHelpers.js';
import { projectionMatrixReverseDepth } from '../gfx/helpers/ReversedDepthHelpers.js';
import { GfxClipSpaceNearZ, GfxDevice, GfxFormat, GfxRenderPass, GfxTexture, makeTextureDescriptor2D } from '../gfx/platform/GfxPlatform.js';
import { GfxDevice, GfxFormat, GfxRenderPass, GfxTexture, makeTextureDescriptor2D } from '../gfx/platform/GfxPlatform.js';
import { GfxRenderCache } from '../gfx/render/GfxRenderCache.js';
import { GfxrAttachmentSlot, GfxrRenderTargetDescription } from '../gfx/render/GfxRenderGraph.js';
import { GfxRenderInstList, GfxRenderInstManager } from '../gfx/render/GfxRenderInstManager.js';
import { GX_Program } from '../gx/gx_material.js';
import { GXRenderHelperGfx, SceneParams, calcLODBias, fillSceneParamsData, ub_SceneParamsBufferSize } from '../gx/gx_render.js';
import { GXRenderHelperGfx } from '../gx/gx_render.js';
import { FlowerPacket, GrassPacket, TreePacket } from './Grass.js';
import { LegacyActor__RegisterFallbackConstructor } from './LegacyActor.js';
import { dDlst_2DStatic_c, d_a__RegisterConstructors } from './d_a.js';
import { d_a_sea } from './d_a_sea.js';
import { dBgS } from './d_bg.js';
import { EDemoCamFlags, EDemoMode, dDemo_manager_c } from './d_demo.js';
import { EDemoMode, dDemo_manager_c } from './d_demo.js';
import { dDlst_list_Set, dDlst_list_c } from './d_drawlist.js';
import { dKankyo_create, dKy__RegisterConstructors, dKy_setLight, dScnKy_env_light_c } from './d_kankyo.js';
import { dKyw__RegisterConstructors } from './d_kankyo_wether.js';
Expand All @@ -46,8 +42,9 @@ import { ResType, dRes_control_c } from './d_resorce.js';
import { dStage_dt_c_roomLoader, dStage_dt_c_roomReLoader, dStage_dt_c_stageInitLoader, dStage_dt_c_stageLoader, dStage_roomControl_c, dStage_roomStatus_c, dStage_stageDt_c } from './d_stage.js';
import { WoodPacket } from './d_wood.js';
import { fopAcM_create, fopAcM_searchFromName, fopAc_ac_c } from './f_op_actor.js';
import { cPhs__Status, fGlobals, fopDwTg_ToDrawQ, fopDw_Draw, fopScn, fpcCt_Handler, fpcLy_SetCurrentLayer, fpcM_Management, fpcPf__Register, fpcSCtRq_Request, fpc_pc__ProfileList, leafdraw_class } from './framework.js';
import { cPhs__Status, fGlobals, fopDw_Draw, fopScn, fpcCt_Handler, fpcLy_SetCurrentLayer, fpcM_Management, fpcPf__Register, fpcSCtRq_Request, fpc_pc__ProfileList, leafdraw_class } from './framework.js';
import { J2DGrafContext } from '../Common/JSYSTEM/J2Dv1.js';
import { dCamera_c } from './d_camera.js';

type SymbolData = { Filename: string, SymbolName: string, Data: ArrayBufferSlice };
type SymbolMapData = { SymbolData: SymbolData[] };
Expand Down Expand Up @@ -127,8 +124,6 @@ class RenderHacks {
public renderHacksChanged = false;
}

const sceneParams = new SceneParams();

export class dGlobals {
public g_env_light = new dScnKy_env_light_c();
public dlst: dDlst_list_c;
Expand Down Expand Up @@ -207,168 +202,6 @@ export class dGlobals {
}
}

const enum CameraMode {
Default,
Cinematic
}

export class dCamera_c extends leafdraw_class {
public static PROCESS_NAME = dProcName_e.d_camera;

public viewFromWorldMatrix = mat4.create(); // aka viewMatrix
public worldFromViewMatrix = mat4.create(); // aka worldMatrix
public clipFromWorldMatrix = mat4.create();
public clipFromViewMatrix = mat4.create(); // aka projectionMatrix

public clipSpaceNearZ: GfxClipSpaceNearZ;

// Frustum is stored in Wind Waker engine world space.
public frustum = new Frustum();
public aspect = 1.0;
public fovY = 0.0;
public near = 0.0;
public far = 0.0;

// The current camera position, in Wind Waker engine world space.
public cameraPos = vec3.create();
public cameraFwd = vec3.create();
public cameraTarget = vec3.create();
public cameraUp = vec3.fromValues(0, 1, 0);
public roll = 0.0;

// For people to play around with.
public frozen = false;
public enableLetterboxing = true;

private cameraMode: CameraMode = CameraMode.Default;
private cameraModeBlendVal = 0;
private demoFov = 0;
private demoRoll = 0;
private trimHeight = 0;
private scissor = vec4.create();

private static trimHeightCinematic = 65.0;

public finishSetup(): void {
mat4.invert(this.viewFromWorldMatrix, this.worldFromViewMatrix);
mat4.mul(this.clipFromWorldMatrix, this.clipFromViewMatrix, this.viewFromWorldMatrix);
getMatrixTranslation(this.cameraPos, this.worldFromViewMatrix);
getMatrixAxisZ(this.cameraFwd, this.worldFromViewMatrix);
vec3.negate(this.cameraFwd, this.cameraFwd);
this.frustum.updateClipFrustum(this.clipFromWorldMatrix, this.clipSpaceNearZ);
}

public setupFromCamera(camera: Camera): void {
this.clipSpaceNearZ = camera.clipSpaceNearZ;
this.aspect = camera.aspect;
this.fovY = camera.fovY;
this.roll = 0;

getMatrixTranslation(this.cameraPos, camera.worldMatrix);
getMatrixAxisZ(this.cameraFwd, camera.worldMatrix);
vec3.negate(this.cameraFwd, this.cameraFwd);
this.cameraTarget = vec3.scaleAndAdd(scratchVec3a, this.cameraPos, this.cameraFwd, 1000);

mat4.copy(this.worldFromViewMatrix, camera.worldMatrix);
mat4.copy(this.clipFromViewMatrix, camera.projectionMatrix);
this.finishSetup();
}

public override load(globals: dGlobals, userData: any): cPhs__Status {
globals.camera = this;
fopDwTg_ToDrawQ(globals.frameworkGlobals, this, this.drawPriority);
return cPhs__Status.Next;
}

// Executes after the demo manager and other systems that can modify the camera
public override execute(globals: dGlobals, deltaTimeFrames: number): void {
this.setupFromCamera(globals.sceneContext.viewerInput.camera);

// Near/far planes are decided by the stage data.
const stag = globals.dStage_dt.stag;

// Pull in the near plane to decrease Z-fighting, some stages set it far too close...
this.near = Math.max(stag.nearPlane, 5);
this.far = stag.farPlane;

// noclip modification: if this is the sea map, push our far plane out a bit.
if (globals.stageName === 'sea')
this.far *= 2;

// noclip modification: if we're paused, allow noclip camera control during demos
const isPaused = globals.sceneContext.viewerInput.deltaTime === 0;

// dCamera_c::Store() sets the camera params if the demo camera is active
const demoCam = globals.scnPlay.demo.getSystem().getCamera();
if (demoCam && !isPaused) {
if (demoCam.flags & EDemoCamFlags.HasTargetPos) { vec3.copy(this.cameraTarget, demoCam.targetPosition); }
if (demoCam.flags & EDemoCamFlags.HasEyePos) { vec3.copy(this.cameraPos, demoCam.viewPosition); }
if (demoCam.flags & EDemoCamFlags.HasUpVec) { vec3.copy(this.cameraUp, demoCam.upVector); }
if (demoCam.flags & EDemoCamFlags.HasFovY) { this.demoFov = demoCam.fovY * MathConstants.DEG_TO_RAD; }
if (demoCam.flags & EDemoCamFlags.HasRoll) { this.demoRoll = demoCam.roll; }
if (demoCam.flags & EDemoCamFlags.HasAspect) { debugger; /* Untested. Remove once confirmed working */ }
if (demoCam.flags & EDemoCamFlags.HasNearZ) { this.near = demoCam.projNear; }
if (demoCam.flags & EDemoCamFlags.HasFarZ) { this.far = demoCam.projFar; }

this.cameraMode = CameraMode.Cinematic;
globals.sceneContext.inputManager.isMouseEnabled = false;
} else {
this.cameraMode = CameraMode.Default;
globals.sceneContext.inputManager.isMouseEnabled = true;
}

// Adapted from dCamera_c::CalcTrimSize()
// When switching between Cinematic and Regular camera modes (e.g. when pausing a cutscene),
// blend the camera parameters smoothly. This accounts for deltaTime, but still works when paused.
deltaTimeFrames = clamp(deltaTimeFrames, 0.5, 1);
this.cameraModeBlendVal += (this.cameraMode - this.cameraModeBlendVal) * 0.25 * deltaTimeFrames;
this.trimHeight = lerp(0, dCamera_c.trimHeightCinematic, this.cameraModeBlendVal);
this.fovY = lerp(this.fovY, this.demoFov, this.cameraModeBlendVal);
this.roll = lerp(this.roll, this.demoRoll, this.cameraModeBlendVal);

mat4.targetTo(this.worldFromViewMatrix, this.cameraPos, this.cameraTarget, this.cameraUp);
mat4.rotateZ(this.worldFromViewMatrix, this.worldFromViewMatrix, this.roll * MathConstants.DEG_TO_RAD);

// Keep noclip and demo cameras in sync. Ensures that when the user pauses, the camera doesn't snap to an old location
mat4.copy(globals.sceneContext.viewerInput.camera.worldMatrix, this.worldFromViewMatrix);
globals.sceneContext.viewerInput.camera.worldMatrixUpdated();

// Compute updated projection matrix
const nearY = Math.tan(this.fovY * 0.5) * this.near;
const nearX = nearY * this.aspect;
projectionMatrixForFrustum(this.clipFromViewMatrix, -nearX, nearX, -nearY, nearY, this.near, this.far);
projectionMatrixReverseDepth(this.clipFromViewMatrix);
projectionMatrixConvertClipSpaceNearZ(this.clipFromViewMatrix, this.clipSpaceNearZ, GfxClipSpaceNearZ.NegativeOne);

// Scissor setup
const trimPx = (this.trimHeight / 480) * globals.sceneContext.viewerInput.backbufferHeight;
vec4.set(this.scissor, 0, trimPx, globals.sceneContext.viewerInput.backbufferWidth, globals.sceneContext.viewerInput.backbufferHeight - 2 * trimPx);

this.finishSetup();

if (!this.frozen) {
// Update the "player position" from the camera.
vec3.copy(globals.playerPosition, this.cameraPos);
}
}

// Executes before any other draw in other systems
override draw(globals: dGlobals, renderInstManager: GfxRenderInstManager, viewerInput: Viewer.ViewerRenderInput): void {
const template = renderInstManager.pushTemplate();

mat4.copy(sceneParams.u_Projection, globals.camera.clipFromViewMatrix);
sceneParams.u_SceneTextureLODBias = calcLODBias(viewerInput.backbufferWidth, viewerInput.backbufferHeight);
const d = template.allocateUniformBufferF32(GX_Program.ub_SceneParams, ub_SceneParamsBufferSize);
fillSceneParamsData(d, 0, sceneParams);
}

public applyScissor(pass: GfxRenderPass) {
if(this.enableLetterboxing) {
pass.setScissor(this.scissor[0], this.scissor[1], this.scissor[2], this.scissor[3]);
}
}
}

function gain(v: number, k: number): number {
const a = 0.5 * Math.pow(2*((v < 0.5) ? v : 1.0 - v), k);
return v < 0.5 ? a : 1.0 - a;
Expand Down Expand Up @@ -483,7 +316,6 @@ const enum EffectDrawGroup {
}

const scratchMatrix = mat4.create();
const scratchVec3a = vec3.create();
export class WindWakerRenderer implements Viewer.SceneGfx {
private mainColorDesc = new GfxrRenderTargetDescription(GfxFormat.U8_RGBA_RT);
private mainDepthDesc = new GfxrRenderTargetDescription(GfxFormat.D32F);
Expand Down
Loading

0 comments on commit e6f8d8e

Please sign in to comment.