Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wind Waker: Add black bars to top and bottom during demos #736

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 96 additions & 58 deletions src/ZeldaWindWaker/Main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

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

import ArrayBufferSlice from '../ArrayBufferSlice.js';
import { DataFetcher } from '../DataFetcher.js';
Expand Down Expand Up @@ -202,6 +202,94 @@ export class dGlobals {
}
}

const enum CameraMode {
Default,
Cinematic
}

class dCamera_c {
// For people to play around with.
public cameraFrozen = false;

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

private static trimHeightCinematic = 65.0;

public execute(globals: dGlobals, viewerInput: Viewer.ViewerRenderInput) {
// Near/far planes are decided by the stage data.
const stag = globals.dStage_dt.stag;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of splitting dCamera_c out to a separate class, but I believe we should replace globals.camera with it. Search for setupFromCamera to see other examples of how I do this elsewhere.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! It turned out to be a bit messier than the other users of setFromCamera because there are several places in src/Common/ and src/gx/ that use viewerInput.camera directly. To work around this without doing some bigger refactoring, I made dCamera_c extend Camera.

I think we'd be better off if Camera wasn't used anywhere in src/Common, and we just passed in matrices, frustums, etc or abstracted whatever is using those up to a higher level. But take a look through this and let me know what you think . And feel free to either make changes directly in the branch too.


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

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

globals.camera.setClipPlanes(nearPlane, farPlane);

// noclip modification: if we're paused, allow noclip camera control during demos
const isPaused = 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) {
let viewPos = globals.cameraPosition;
let targetPos = vec3.add(scratchVec3a, globals.cameraPosition, globals.cameraFwd);
let upVec = vec3.set(scratchVec3b, 0, 1, 0);
let roll = 0.0;

// TODO: Blend between these camera params when switching camera modes, instead of the sudden snap.

if (demoCam.flags & EDemoCamFlags.HasTargetPos) { targetPos = demoCam.targetPosition; }
if (demoCam.flags & EDemoCamFlags.HasEyePos) { viewPos = demoCam.viewPosition; }
if (demoCam.flags & EDemoCamFlags.HasUpVec) { upVec = demoCam.upVector; }
if (demoCam.flags & EDemoCamFlags.HasFovY) { globals.camera.fovY = demoCam.fovY * MathConstants.DEG_TO_RAD; }
if (demoCam.flags & EDemoCamFlags.HasRoll) { roll = demoCam.roll * MathConstants.DEG_TO_RAD; }
if (demoCam.flags & EDemoCamFlags.HasAspect) { debugger; /* Untested. Remove once confirmed working */ }
if (demoCam.flags & EDemoCamFlags.HasNearZ) { globals.camera.near = demoCam.projNear; }
if (demoCam.flags & EDemoCamFlags.HasFarZ) { globals.camera.far = demoCam.projFar; }

mat4.targetTo(globals.camera.worldMatrix, viewPos, targetPos, upVec);
mat4.rotateZ(globals.camera.worldMatrix, globals.camera.worldMatrix, roll);
globals.camera.setClipPlanes(globals.camera.near, globals.camera.far);
globals.camera.worldMatrixUpdated();

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

// From dCamera_c::CalcTrimSize()
// Animate up to the trim size for the current mode.
if(this.cameraMode == CameraMode.Cinematic) {
themikelester marked this conversation as resolved.
Show resolved Hide resolved
this.trimHeight += (dCamera_c.trimHeightCinematic - this.trimHeight) * 0.25;
} else {
this.trimHeight += -this.trimHeight * 0.25;
themikelester marked this conversation as resolved.
Show resolved Hide resolved
}

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

if (!this.cameraFrozen) {
mat4.getTranslation(globals.cameraPosition, globals.camera.worldMatrix);
getMatrixAxisZ(globals.cameraFwd, globals.camera.worldMatrix);
vec3.negate(globals.cameraFwd, globals.cameraFwd);
// Update the "player position" from the camera.
vec3.copy(globals.playerPosition, globals.cameraPosition);
}
}

public applyScissor(pass: GfxRenderPass) {
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 @@ -322,6 +410,7 @@ export class WindWakerRenderer implements Viewer.SceneGfx {
private mainColorDesc = new GfxrRenderTargetDescription(GfxFormat.U8_RGBA_RT);
private mainDepthDesc = new GfxrRenderTargetDescription(GfxFormat.D32F);
private opaqueSceneTextureMapping = new TextureMapping();
private camera = new dCamera_c();

public renderHelper: GXRenderHelperGfx;

Expand Down Expand Up @@ -402,9 +491,6 @@ export class WindWakerRenderer implements Viewer.SceneGfx {
return [roomsPanel, scenarioPanel, renderHacksPanel];
}

// For people to play around with.
public cameraFrozen = false;

private getRoomStatus(ac: fopAc_ac_c): dStage_roomStatus_c | null {
if (ac.roomNo === -1)
return null;
Expand Down Expand Up @@ -450,59 +536,8 @@ export class WindWakerRenderer implements Viewer.SceneGfx {
}
}

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

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

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

viewerInput.camera.setClipPlanes(nearPlane, farPlane);

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

// TODO: Determine the correct place for this
// dCamera_c::Store() sets the camera params if the demo camera is active
const demoCam = this.globals.scnPlay.demo.getSystem().getCamera();
if (demoCam && !isPaused) {
let viewPos = this.globals.cameraPosition;
let targetPos = vec3.add(scratchVec3a, this.globals.cameraPosition, this.globals.cameraFwd);
let upVec = vec3.set(scratchVec3b, 0, 1, 0);
let roll = 0.0;

if (demoCam.flags & EDemoCamFlags.HasTargetPos) { targetPos = demoCam.targetPosition; }
if (demoCam.flags & EDemoCamFlags.HasEyePos) { viewPos = demoCam.viewPosition; }
if (demoCam.flags & EDemoCamFlags.HasUpVec) { upVec = demoCam.upVector; }
if (demoCam.flags & EDemoCamFlags.HasFovY) { viewerInput.camera.fovY = demoCam.fovY * MathConstants.DEG_TO_RAD; }
if (demoCam.flags & EDemoCamFlags.HasRoll) { roll = demoCam.roll * MathConstants.DEG_TO_RAD; }
if (demoCam.flags & EDemoCamFlags.HasAspect) { debugger; /* Untested. Remove once confirmed working */ }
if (demoCam.flags & EDemoCamFlags.HasNearZ) { viewerInput.camera.near = demoCam.projNear; }
if (demoCam.flags & EDemoCamFlags.HasFarZ) { viewerInput.camera.far = demoCam.projFar; }

mat4.targetTo(viewerInput.camera.worldMatrix, viewPos, targetPos, upVec);
mat4.rotateZ(viewerInput.camera.worldMatrix, viewerInput.camera.worldMatrix, roll);
viewerInput.camera.setClipPlanes(viewerInput.camera.near, viewerInput.camera.far);
viewerInput.camera.worldMatrixUpdated();

this.globals.context.inputManager.isMouseEnabled = false;
} else {
this.globals.context.inputManager.isMouseEnabled = true;
}

if (!this.cameraFrozen) {
mat4.getTranslation(this.globals.cameraPosition, viewerInput.camera.worldMatrix);
getMatrixAxisZ(this.globals.cameraFwd, viewerInput.camera.worldMatrix);
vec3.negate(this.globals.cameraFwd, this.globals.cameraFwd);
// Update the "player position" from the camera.
vec3.copy(this.globals.playerPosition, this.globals.cameraPosition);
}

this.globals.camera = viewerInput.camera;
this.camera.execute(this.globals, viewerInput);

// Not sure exactly where this is ordered...
dKy_setLight(this.globals);
Expand Down Expand Up @@ -577,6 +612,7 @@ export class WindWakerRenderer implements Viewer.SceneGfx {
const skyboxDepthTargetID = builder.createRenderTargetID(this.mainDepthDesc, 'Skybox Depth');
pass.attachRenderTargetID(GfxrAttachmentSlot.DepthStencil, skyboxDepthTargetID);
pass.exec((passRenderer) => {
this.camera.applyScissor(passRenderer);
this.executeListSet(passRenderer, dlst.sky);
});
});
Expand All @@ -589,6 +625,8 @@ export class WindWakerRenderer implements Viewer.SceneGfx {
pass.attachRenderTargetID(GfxrAttachmentSlot.Color0, mainColorTargetID);
pass.attachRenderTargetID(GfxrAttachmentSlot.DepthStencil, mainDepthTargetID);
pass.exec((passRenderer) => {
this.camera.applyScissor(passRenderer);

this.executeList(passRenderer, dlst.sea);
this.executeListSet(passRenderer, dlst.bg);

Expand Down Expand Up @@ -1018,7 +1056,7 @@ class DemoDesc extends SceneDesc implements Viewer.SceneDesc {
console.debug(`Loading stage demo file: ${globals.roomCtrl.demoArcName}`);

globals.modelCache.fetchObjectData(globals.roomCtrl.demoArcName).catch(e => {
// @TODO: Better error handling. This does not prevent a debugger break.
// TODO: Better error handling. This does not prevent a debugger break.
console.log(`Failed to load stage demo file: ${globals.roomCtrl.demoArcName}`, e);
})
}
Expand All @@ -1037,7 +1075,7 @@ class DemoDesc extends SceneDesc implements Viewer.SceneDesc {
setTimeout(waitForActors, 30);
})(); });

// @TODO: Set noclip layer visiblity based on this.layer
// TODO: Set noclip layer visiblity based on this.layer

// From dEvDtStaff_c::specialProcPackage()
let demoData;
Expand Down
7 changes: 6 additions & 1 deletion src/ZeldaWindWaker/d_place_name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ export class d_place_name extends msg_class {

const screen = globals.resCtrl.getObjectRes(ResType.Blo, `PName`, 0x04);

// @TODO: If we're on Outset Island (0), don't load any textures. Add support for BLO loading the default textures.

// The Outset Island image lives inside the arc. All others are loose files in 'res/placename/'
let img: BTIData;
if (globals.scnPlay.placenameIndex === Placename.OutsetIsland) {
Expand All @@ -114,7 +116,10 @@ export class d_place_name extends msg_class {

public override draw(globals: dGlobals, renderInstManager: GfxRenderInstManager, viewerInput: ViewerRenderInput): void {
renderInstManager.setCurrentList(globals.dlst.ui[0]);
this.screen.draw(renderInstManager, viewerInput, null);

// @TODO: This will be needed when drawing all Wind Waker 2D elements. It should be in dComIfG_play_c.
const ctx = new J2DGrafContext(globals.context.device, 0.0, 0.0, 608.0, 448.0, -1.0, 0.0);
this.screen.draw(renderInstManager, viewerInput, ctx);
themikelester marked this conversation as resolved.
Show resolved Hide resolved
}

public override execute(globals: dGlobals, deltaTimeFrames: number): void {
Expand Down
Loading