forked from Ports/goldeneye-pc-port
feat(D211-D213): PC QoL image options — FOV slider, anisotropic filtering, on-screen FPS
Three port-only knobs, each defaulting to byte-identical behaviour: - Video.FovScale (D211): multiplicative half-angle scale on every perspective projection matrix as it is loaded (gfx_apply_fov_scale, gfx_pc.cpp). Columns 0+1 scaled together so H/V FOV widen uniformly and aspect is preserved; ortho (HUD/menu) matrices untouched. Composes with the game's per-frame aim-zoom rewrites for free. Percent of vertical FOV, 50-150, default 100 => guarded early-return (zero FP ops, golden dumps byte-identical). WIDESCREEN-FOV-PLAN Phase 4, landed standalone. - Video.Anisotropy (D212): expose fast3d's already-implemented GL anisotropy hook as config (1-16). New gfx_set_anisotropy_level() extern-C wrapper clamps to the GL max. Default 4 = the value fast3d already hardcoded => no delta. - Video.DisplayFPS (D213): PD-parity top-right FPS readout, sampled once per emitted frame (optionsoverlay.c fpsTick). Config-only; default 0 => emit still returns NULL with the panel closed. F10 overlay gains 'Anisotropic' and 'FOV scale %' rows (DisplayFPS is file-only - the panel is at its 13-row layout limit, matching PD). Build clean (ntsc-final); bunker1 framediff worst_cell 12.219 vs 12.221 baseline = render noise, no-op confirmed. Interactive eyeballs owed (see docs/HANDOFF.md M-83). findings.md: D211-D213 rows + index regen. WIDESCREEN-FOV-PLAN Phase 4 and QOL-INVENTORY rows marked done.
This commit is contained in:
1 parent
8742b93f29
commit
7bcfbf313c
8 files changed
+159
-10
No files matched your search
@@ -1,7 +1,10 @@
|
||||
# QoL Inventory — PD-vs-GE options diff
|
||||
|
||||
Status: **read-only research, parked** (input to project Phase 4). No code
|
||||
changed. Companion to `WIDESCREEN-FOV-PLAN.md` and `UNLOCKED-FPS-PLAN.md`.
|
||||
Status: **partially implemented.** M-83 landed three port-only quick wins —
|
||||
DisplayFPS (D213), anisotropic filtering (D212), and the FOV slider (D211, via
|
||||
`WIDESCREEN-FOV-PLAN.md` Phase 4). Rebinding / SkipIntro / per-pad tuning /
|
||||
window HiDpi still open. Companion to `WIDESCREEN-FOV-PLAN.md` and
|
||||
`UNLOCKED-FPS-PLAN.md`.
|
||||
|
||||
Method: diffed the config surface of both ports — every `configRegister*`
|
||||
key in `pd_port/port/src/*.c` vs `port/src/config.c` + the F10 overlay
|
||||
@@ -27,8 +30,8 @@ ScreenShakeIntensity. Debug: FrameDump, InputLog.
|
||||
|---|---|---|---|---|
|
||||
| **Key rebinding** (config-string binds per controller/action) | `input.c:69,627-675,1548` (`bindStrs`, `inputParseBindString`) | P | M | **High.** Explicit Phase 4 debt ("rebinding UI" — note PD has *no* UI either; config-file driven). Port-only in `port/src/input.c`. |
|
||||
| **SkipIntro** | `main.c:139` (STAGE_TITLE → STAGE_CITRAINING) | P | S | **High.** GE analogue: stage-override path already exists (`boss.c:385-393`, `g_StageNum = LEVELID_TITLE` at :98); wire a flag + arg. 10-min check on what feeds `tokenFindLevel`. |
|
||||
| **DisplayFPS** (+ interval) | config `Video.DisplayFPS(Interval)` | P | S | Cheap; useful for FPS-plan verification too. |
|
||||
| **Anisotropic filtering** (≤16×), MipmapFilter, TextureFilter2D | `gfx_opengl` texparam path | P | S–M | **High at 4K.** GE's `gfx_opengl.cpp` has mipmap nY but no aniso (`GL_TEXTURE_MAX_ANISOTROPY_EXT`). Port-only. |
|
||||
| **DisplayFPS** _(DONE M-83, D213)_ | config `Video.DisplayFPS` | P | S | Top-right readout, config-only; ~0.5 s sample window. |
|
||||
| **Anisotropic filtering** _(DONE M-83, D212)_ | `Video.Anisotropy` (1–16, dflt 4) | P | S | fast3d already had the GL hook + a hardcoded 4×; M-83 exposed it as config. MipmapFilter / TextureFilter2D still not surfaced. |
|
||||
| Per-pad tuning: per-stick deadzones, stick scale, rumble scale, device index, swap sticks, C-button mapping | `input.c` padsCfg block | P | M | Medium. Matters for real-controller users; PD pattern is a config section per pad. |
|
||||
| FakeGamepads / FirstGamepadNum / UseHIDAPI | `input.c` | P | S–M | Niche (local MP on PC); defer until MP is actually played. |
|
||||
| Window polish: DefaultFullscreen/Maximize, CenterWindow, AllowHiDpi, ExclusiveFullscreen | `video.c` vid* block | P | S | HiDpi + center are the useful ones on modern Windows. |
|
||||
|
||||
@@ -213,10 +213,17 @@ reason. Whole-feature fallback to A only if B fails verification overall.
|
||||
verification at 4:3 + 16:9, finding entry. Fallback-to-A decisions
|
||||
happen here, per surface, with documented reason.
|
||||
|
||||
### Phase 4 — FOV slider (port-only)
|
||||
### Phase 4 — FOV slider (port-only) — **LANDED (M-83, D211)**
|
||||
|
||||
- [ ] RSP projection post-scale; `Video.FovScale` config + F10 overlay;
|
||||
verify composition with aim zoom at non-100 scale.
|
||||
- [x] RSP projection post-scale (`gfx_apply_fov_scale()` in
|
||||
`port/fast3d/gfx_pc.cpp`, load-path only); `Video.FovScale` config
|
||||
(percent of vertical FOV, 50–150, default 100 = byte-identical) + F10
|
||||
overlay row. Perspective-only (ortho/HUD untouched); columns 0+1 scaled
|
||||
together so aspect is preserved. Build clean, `bunker1` no-op confirmed.
|
||||
- [ ] Owed: interactive eyeball of composition with aim-zoom at scale ≠ 100.
|
||||
|
||||
This phase does **not** depend on the Phase 2/3 game-code exception — it
|
||||
shipped standalone ahead of the rest of the plan.
|
||||
|
||||
### Phase 5 — Verification & sign-off
|
||||
|
||||
|
||||
@@ -53,6 +53,9 @@ D179,FIXED,Packaged build crashes after the logos —,"Diagnosed, not fixed —"
|
||||
D180,PARTIAL,"Native-PC input pass (M-XX QoL run, qol/native-pc-input-menu, port-only).","LANDED, port-only, no #ifdef PORT."
|
||||
D181,PARTIAL,Game.ScreenShakeIntensity —,"LANDED behind config, default = original."
|
||||
D184,PARTIAL,F10 port-layer options overlay —,"LANDED, port-only, no #ifdef PORT in src/."
|
||||
D211,PARTIAL,"PC FOV slider — Video.FovScale (M-83 QoL wave, port-only, WIDESCREEN-FOV-PLAN.md Phase 4).","LANDED, port-only, no #ifdef PORT."
|
||||
D212,PARTIAL,Anisotropic-filtering config wiring —,"LANDED, port-only. Build clean."
|
||||
D213,PARTIAL,On-screen FPS readout —,"LANDED, port-only. Build clean; bunker1 no-op confirmed."
|
||||
D85,OPEN,room primary/secondary DL → texLoadFromGdl garbage,"OPEN (safety-netted; widen/pool fixes landed, geometry now renders)"
|
||||
D86 · D87,RESOLVED,modelInitRwData truncated ptr · attract-demo BE ramromfilestructure,resolved
|
||||
D88.4,RESOLVED,propDefs polymorphic record stream not byteswapped → setupDoor crash,resolved (d88_propdefs.py); layout audit M-20 → D132
|
||||
|
||||
|
@@ -427,6 +427,9 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
|
||||
| D180 | **Native-PC input pass (M-XX QoL run, `qol/native-pc-input-menu`, port-only).** Three parts, all config-gated with default = prior behaviour: **(WI-1) `Input.MouseCaptureMode`** (0 = legacy always-grab; 1 = Quake-style click-to-lock) in `port/src/input.c` + `port/src/video.c` — in mode 1 the OS cursor is free until a click lands in the game window (`SDL_MOUSEBUTTONDOWN` → `inputNotifyClick`), and ESC / focus-loss / entering any front-end menu (`current_menu != MENU_RUN_STAGE`) frees it again; re-entering a stage while still "armed" re-locks so unpausing needs no click. `reconcileGrab()` runs once per controller-0 poll. Mouse buttons are suppressed from the game while the cursor is free in-stage (no phantom fire). Controller paths untouched. **(WI-2) absolute-cursor menu tracking** — when capture mode is on and the cursor is free in a menu, the D165/D169 pointer P-controller takes its target from the real cursor's absolute window position mapped onto the live virtual front-end rect (`getPlayer_c_screen*`), giving true 1:1 tracking instead of the relative-delta estimator. Relative path unchanged for legacy/grabbed. **(B3) `Input.MouseAimSpeed` default 25 → 16** (aim mode still overshot at 25 per the backlog). | LANDED, port-only, no `#ifdef PORT`. Build 241/241, `-level_09` framediff 3/3 within threshold (unregressed), `GE_STARTMENU` menu boot crash-free. **Feel-checks owed** (headless can't drive the mouse): click-to-lock ergonomics, absolute menu tracking, the new aim-speed default. |
|
||||
| D181 | **`Game.ScreenShakeIntensity` — first route-(b) `src/` gameplay-cosmetic hook (M-XX QoL run).** `src/fr.c viShake()` gains a single `#ifdef PORT` line — `intensity *= portScreenShakeScale;` (extern `f32`, defined + `configRegisterFloat`'d 0.0–10.0 in `port/src/video.c`) — before the existing clamp. Default `1.0f` ⇒ exact no-op, every headless golden dump byte-unaffected; `0.0` disables explosion/effect screen shake, up to `10.0` exaggerates it. N64 build (no `-DPORT`) keeps the original line verbatim. Precedent per `docs/BACKLOG.md` "Fun features → screen-shake intensity slider" and AGENTS.md #2's documented-exception path. Same policy class as a future FOV hook. | LANDED behind config, default = original. Build green. |
|
||||
| D184 | **F10 port-layer options overlay — the approach-(C) surface from `OPTIONS-MENU-PLAN.md` (M-37).** New `port/src/optionsoverlay.c` + `port/include/optionsoverlay.h`: an immediate-mode overlay drawn as its own fast3d 2D DL, appended after the game DL in `gfx_pc.cpp gfx_run()` (`optionsOverlayEmit()` → NULL when closed ⇒ **zero bytes appended, golden dumps byte-identical**). F10 toggles (`video.c videoPumpEvents`, next to F12); while open, `input.c inputComputePad(0)` returns a neutral pad and routes arrows/enter/wheel/mouse-buttons to `optionsOverlayHandleInput()` (mirrors the WI-1/D180 swallow). ESC closes; `configSave()` on close. `config.c` gains `configForEachOption()` + a `configSetOptionMeta()` label/step/enum side table (no per-key knowledge in config.c). Live knobs (VSync/FpsCap/TextureFilter via `videoRequestLiveConfig()`; mouse + screen-shake via the registered pointer) apply immediately; MSAA tagged "(restart)". v1 rows per plan §3: VSync, FpsCap, MSAA, TextureFilter, MouseAimSpeed, MouseTurnSpeed, MouseInvertY, MouseCaptureMode, ScreenShakeIntensity. | **LANDED, port-only, no `#ifdef PORT` in `src/`.** Build links 241/241. **Runtime verification NOT run this session** — the headless env kills the GUI process after ~8 s and `gfx_opengl_dump_bound_fbo` writes 0-byte PPMs here, so framediff / 60 s soak / overlay-frame eyeball are all owed on an interactive machine. Overlay-closed no-op is code-evident (emit returns NULL before touching the DL buffer). |
|
||||
| D211 | **PC FOV slider — `Video.FovScale` (M-83 QoL wave, port-only, `WIDESCREEN-FOV-PLAN.md` Phase 4).** fast3d applies a multiplicative half-angle scale to every *perspective* projection matrix as it is loaded (`gfx_apply_fov_scale()` in `gfx_pc.cpp gfx_sp_matrix`, on the `G_MTX_PROJECTION | G_MTX_LOAD` path only — GE always reloads its view projection via `guPerspectiveF` at `fr.c:725`, so a relative `G_MTX_MUL` onto an already-scaled matrix cannot compound). Columns 0 and 1 are scaled by the same factor `tan(half_orig)/tan(half_adj)` → H and V FOV widen uniformly, aspect ratio exactly preserved (no stretch), and because the game rewrites fovy every frame for aim-zoom the scale composes with zoom for free. Ortho matrices (`P[3][3]==1`) are left untouched so HUD/menu 2D is unaffected. `Video.FovScale` = percent of the original vertical FOV, 50–150, **default 100 ⇒ `g_fov_scale == 1.0f` ⇒ guarded early-return, zero FP ops on the matrix ⇒ golden dumps byte-identical**. F10 overlay row "FOV scale %". Math checked offline (`s=1.25 → fovy 60°→75°`, aspect held at 1.3333). | **LANDED, port-only, no `#ifdef PORT`.** Build clean; `bunker1` framediff worst_cell 12.219 vs 12.221 baseline (= render noise, no-op confirmed). **Owed:** an interactive eyeball at FovScale ≠ 100 (world widens, HUD unmoved, aim-zoom still composes). |
|
||||
| D212 | **Anisotropic-filtering config wiring — `Video.Anisotropy` (M-83 QoL wave, port-only).** The fast3d GL backend already implemented `set_anisotropy_level` / `get_max_anisotropy_level` and applied `GL_TEXTURE_MAX_ANISOTROPY` on mipmapped tiles with a hardcoded `current_anisotropy_level = 4`; there was no way to configure it. Added the `gfx_set_anisotropy_level()` extern-C wrapper in `gfx_pc.cpp` (clamps to `[1, GL max]`, `reset_texture_state()` so live changes take), declared in `gfx_api.h`, and `Video.Anisotropy` (1–16) in `port/src/video.c` wired through `videoApplyImageOptions()` on init + live-config. **Default 4 = the value fast3d already applied ⇒ no visual delta at defaults.** F10 overlay row "Anisotropic". | **LANDED, port-only.** Build clean. **Owed:** eyeball at 16× on a grazing surface (Depot roof / Dam walkway) vs 1×. |
|
||||
| D213 | **On-screen FPS readout — `Video.DisplayFPS` (M-83 QoL wave, port-only, PD parity).** `port/src/optionsoverlay.c` samples frame time once per emitted frame (`fpsTick()` via `sysGetMicroseconds()`, ~0.5 s window) and, when enabled, emits a small top-right green "N FPS" DL even while the F10 panel is closed. Config-only knob (kept off the 13-row panel, which is at its documented layout limit — matches PD, whose `DisplayFPS` is also file-only). **Default 0 ⇒ `optionsOverlayEmit()` still returns NULL when the panel is closed ⇒ golden dumps byte-identical.** | **LANDED, port-only.** Build clean; `bunker1` no-op confirmed. **Owed:** eyeball that the counter reads a sane ~30 and doesn't overlap the HUD. |
|
||||
| D85 | room primary/secondary DL → `texLoadFromGdl` garbage | OPEN (safety-netted; widen/pool fixes landed, geometry now renders) |
|
||||
| D86 · D87 | modelInitRwData truncated ptr · attract-demo BE `ramromfilestructure` | resolved |
|
||||
| D88.1–D88.3 · D88.5–D88.6 | `Usetup*Z` header + sub-table width/endian conversion (`d88_emit.py`) | resolved |
|
||||
|
||||
@@ -48,6 +48,8 @@ void gfx_set_texture_filter(enum FilteringMode mode);
|
||||
void gfx_set_mipmap_filter(enum MipmapFilteringMode mode);
|
||||
void gfx_set_fix_mip_textures(int on);
|
||||
void gfx_set_wrap_fix(int on);
|
||||
void gfx_set_fov_scale(float scale); /* D211: 1.0 = original vertical FOV */
|
||||
void gfx_set_anisotropy_level(int level); /* 1 = off; clamped to GL max */
|
||||
void gfx_texture_cache_clear(void);
|
||||
void gfx_texture_cache_delete(const uint8_t *orig_addr);
|
||||
void gfx_texture_cache_delete_range(const uint8_t *start, const uint8_t *end);
|
||||
|
||||
@@ -916,6 +916,50 @@ bool g_fix_mip_textures = true;
|
||||
* off. Video.WrapFix = 1. */
|
||||
bool g_wrap_fix = false;
|
||||
|
||||
/* D211 port-only FOV slider. Multiplies the half-angle of every *perspective*
|
||||
* projection matrix as it is loaded, so it composes with the game's per-frame
|
||||
* aim-zoom rewrites for free (see docs/dev/WIDESCREEN-FOV-PLAN.md "FOV
|
||||
* adjustment design"). 1.0 = byte-identical to the original (guarded skip);
|
||||
* Video.FovScale is a percent, 100 = 1.0. */
|
||||
static float g_fov_scale = 1.0f;
|
||||
|
||||
extern "C" void gfx_set_fov_scale(float s) {
|
||||
if (!(s > 0.4f) || !(s < 2.01f)) {
|
||||
s = 1.0f;
|
||||
}
|
||||
g_fov_scale = s;
|
||||
}
|
||||
|
||||
/* Widen/narrow a freshly-loaded projection matrix in place. No-op unless the
|
||||
* matrix is a perspective projection (row-vector guPerspective layout: only
|
||||
* P[2][3] == -1, P[3][3] == 0 — an ortho matrix has P[3][3] == 1 and is left
|
||||
* alone so HUD/menu 2D is untouched). Scaling columns 0 and 1 by the same
|
||||
* factor scales the effective cotangent, i.e. widens H and V FOV uniformly —
|
||||
* aspect ratio is preserved, no stretch. */
|
||||
static void gfx_apply_fov_scale(float m[4][4]) {
|
||||
if (g_fov_scale == 1.0f) {
|
||||
return;
|
||||
}
|
||||
if (!(fabsf(m[3][3]) < 0.01f) || !(fabsf(m[2][3] + 1.0f) < 0.05f)) {
|
||||
return; /* not a perspective projection */
|
||||
}
|
||||
const float cot = m[1][1];
|
||||
if (!(cot > 1e-4f)) {
|
||||
return;
|
||||
}
|
||||
const float half = atanf(1.0f / cot);
|
||||
float nhalf = half * g_fov_scale;
|
||||
const float LIMIT = 1.48f; /* ~85 deg half-angle; keep cot well away from 0 */
|
||||
if (nhalf > LIMIT) {
|
||||
nhalf = LIMIT;
|
||||
}
|
||||
const float f = tanf(half) / tanf(nhalf);
|
||||
for (int k = 0; k < 4; k++) {
|
||||
m[k][0] *= f;
|
||||
m[k][1] *= f;
|
||||
}
|
||||
}
|
||||
|
||||
/* D183 source-pitch de-stride (see import_texture). Default on;
|
||||
* GE_TEXPITCH=0 restores the old flat read for A/B. */
|
||||
static bool gfx_tex_pitch_fix(void) {
|
||||
@@ -1212,6 +1256,11 @@ static void gfx_sp_matrix(uint8_t parameters, const int32_t* addr) {
|
||||
if (parameters & G_MTX_PROJECTION) {
|
||||
if (parameters & G_MTX_LOAD) {
|
||||
memcpy(rsp.P_matrix, matrix, sizeof(matrix));
|
||||
/* D211: apply the FOV slider on the load path only. GE always
|
||||
* (re)loads its view projection with G_MTX_LOAD (src/fr.c:725), so
|
||||
* a relative G_MTX_MUL onto an already-scaled matrix never
|
||||
* happens and cannot compound. */
|
||||
gfx_apply_fov_scale(rsp.P_matrix);
|
||||
} else {
|
||||
gfx_matrix_mul(rsp.P_matrix, matrix, rsp.P_matrix);
|
||||
}
|
||||
@@ -3227,6 +3276,20 @@ extern "C" void gfx_set_mipmap_filter(enum MipmapFilteringMode mode) {
|
||||
}
|
||||
|
||||
extern "C" void gfx_set_fix_mip_textures(int on) { g_fix_mip_textures = !!on; }
|
||||
|
||||
/* D212: expose the (already-implemented) rendering-API anisotropy hook to the
|
||||
* port layer. Clamp to [1, GL max] so a stale ini value can't feed an invalid
|
||||
* GL_TEXTURE_MAX_ANISOTROPY. 1 = isotropic (driver default). */
|
||||
extern "C" void gfx_set_anisotropy_level(int level) {
|
||||
reset_texture_state();
|
||||
int max = gfx_rapi->get_max_anisotropy_level ? gfx_rapi->get_max_anisotropy_level() : 1;
|
||||
if (max < 1) max = 1;
|
||||
if (level < 1) level = 1;
|
||||
if (level > max) level = max;
|
||||
if (gfx_rapi->set_anisotropy_level) {
|
||||
gfx_rapi->set_anisotropy_level(level);
|
||||
}
|
||||
}
|
||||
extern "C" void gfx_set_wrap_fix(int on) {
|
||||
const char* e = getenv("GE_WRAPFIX"); /* RC3 test override */
|
||||
g_wrap_fix = e ? (atoi(e) != 0) : !!on;
|
||||
|
||||
@@ -100,6 +100,8 @@ static struct Row rows[] = {
|
||||
{ "Video.FpsCap", "Frame cap", ROW_SLIDER, 10, NULL, 0, 0, 360, 0,0,0,0,0 },
|
||||
{ "Video.MSAA", "MSAA", ROW_MSAA, 0, NULL, 1, 0, 0, 0,0,0,0,0 },
|
||||
{ "Video.TextureFilter", "Texture filter", ROW_ENUM, 1, kTexFilter, 0, 0, 0, 0,0,0,0,0 },
|
||||
{ "Video.Anisotropy", "Anisotropic", ROW_SLIDER, 1, NULL, 0, 0, 0, 0,0,0,0,0 },
|
||||
{ "Video.FovScale", "FOV scale %", ROW_SLIDER, 5, NULL, 0, 0, 0, 0,0,0,0,0 },
|
||||
{ "Input.MouseAimSpeed", "Mouse aim speed", ROW_SLIDER, 1, NULL, 0, 0, 100, 0,0,0,0,0 },
|
||||
{ "Input.MouseTurnSpeed", "Mouse turn speed", ROW_SLIDER, 1, NULL, 0, 0, 100, 0,0,0,0,0 },
|
||||
{ "Input.MouseInvertY", "Mouse invert Y", ROW_TOGGLE, 1, kOnOff, 0, 0, 0, 0,0,0,0,0 },
|
||||
@@ -112,6 +114,40 @@ static int s_inited = 0;
|
||||
static volatile int s_open = 0;
|
||||
static int s_sel = 0;
|
||||
|
||||
/* D213: optional on-screen FPS readout (PD parity: Video.DisplayFPS). Drawn
|
||||
* top-right whenever enabled, independent of the F10 panel. Config-only knob
|
||||
* (kept off the 13-row panel, which is at its layout limit) -- matches PD,
|
||||
* whose DisplayFPS is also file-only. Default 0 => emit path unchanged =>
|
||||
* golden dumps byte-identical. */
|
||||
static int s_showFps = 0;
|
||||
static char s_fpsText[16] = "";
|
||||
|
||||
PD_CONSTRUCTOR static void overlayConfigInit(void)
|
||||
{
|
||||
configRegisterInt("Video.DisplayFPS", &s_showFps, 0, 1);
|
||||
}
|
||||
|
||||
/* Sampled once per emitted frame; recomputes the string every ~0.5 s. */
|
||||
static void fpsTick(void)
|
||||
{
|
||||
static uint64_t winStartUs = 0;
|
||||
static int frames = 0;
|
||||
|
||||
uint64_t nowUs = sysGetMicroseconds();
|
||||
if (winStartUs == 0) {
|
||||
winStartUs = nowUs;
|
||||
return;
|
||||
}
|
||||
frames++;
|
||||
uint64_t dtUs = nowUs - winStartUs;
|
||||
if (dtUs >= 500000) {
|
||||
int fps = (int)((double)frames * 1e6 / (double)dtUs + 0.5);
|
||||
snprintf(s_fpsText, sizeof(s_fpsText), "%d FPS", fps);
|
||||
winStartUs = nowUs;
|
||||
frames = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Layout (game 2D pixel space = viGetX() x viGetY(), ~320x240). Shared by the
|
||||
* emit path and the mouse hit-testing in optionsOverlayHandleInput().
|
||||
* BankGothic caps are ~9 units tall here, so rows need ~16 units of pitch and
|
||||
@@ -543,8 +579,26 @@ Gfx *optionsOverlayEmit(void)
|
||||
if (!s_inited) {
|
||||
overlayInit();
|
||||
}
|
||||
|
||||
fpsTick();
|
||||
|
||||
if (!s_open) {
|
||||
return NULL; /* nothing appended -> golden dumps byte-identical */
|
||||
if (!s_showFps || !s_fpsText[0]) {
|
||||
return NULL; /* nothing appended -> golden dumps byte-identical */
|
||||
}
|
||||
/* D213: FPS-only mini DL (top-right), panel closed. */
|
||||
const s32 fw = viGetX();
|
||||
const s32 fh = viGetY();
|
||||
Gfx *fgdl = s_buf;
|
||||
gDPPipeSync(fgdl++);
|
||||
gDPSetCycleType(fgdl++, G_CYC_1CYCLE);
|
||||
gDPSetTexturePersp(fgdl++, G_TP_NONE);
|
||||
gDPSetScissor(fgdl++, G_SC_NON_INTERLACE, 0, 0, fw, fh);
|
||||
fgdl = microcode_constructor(fgdl);
|
||||
fgdl = drawTextR(fgdl, fw - 6, 6, s_fpsText, 0x40ff60ff);
|
||||
gDPPipeSync(fgdl++);
|
||||
gSPEndDisplayList(fgdl++);
|
||||
return s_buf;
|
||||
}
|
||||
|
||||
const s32 W = viGetX();
|
||||
|
||||
+16
-2
@@ -58,6 +58,8 @@ static int cfgMSAA = 1; /* 1/2/4/8 samples; 1 = off
|
||||
static int cfgTexFilter = 1; /* 0 = nearest, 1 = bilinear (default), 2 = N64 3-point + trilinear */
|
||||
static int cfgFixMipTex = 1; /* RC2: clip mip-contaminated texture uploads to base height */
|
||||
static int cfgWrapFix = 0; /* D74 sub-tile UV pre-wrap + RC3/D167 non-PoT mask-period wrap (opt-in; GE_WRAPFIX env overrides) */
|
||||
static int cfgFovScale = 100; /* D211: percent of the original vertical FOV; 100 = unchanged (byte-identical) */
|
||||
static int cfgAniso = 4; /* D212: anisotropic filtering samples; 4 = the value fast3d already applied (no visual delta at default) */
|
||||
static int cfgFullscreen = 0; /* 0 = windowed, 1 = borderless fullscreen */
|
||||
|
||||
/*
|
||||
@@ -89,6 +91,8 @@ PD_CONSTRUCTOR static void videoConfigInit(void)
|
||||
configRegisterInt("Video.TextureFilter", &cfgTexFilter, 0, 2);
|
||||
configRegisterInt("Video.FixMipTextures", &cfgFixMipTex, 0, 1);
|
||||
configRegisterInt("Video.WrapFix", &cfgWrapFix, 0, 1);
|
||||
configRegisterInt("Video.FovScale", &cfgFovScale, 50, 150);
|
||||
configRegisterInt("Video.Anisotropy", &cfgAniso, 1, 16);
|
||||
configRegisterInt("Video.Fullscreen", &cfgFullscreen, 0, 1);
|
||||
configRegisterInt("Window.Width", &cfgWinW, 0, 16384);
|
||||
configRegisterInt("Window.Height", &cfgWinH, 0, 16384);
|
||||
@@ -101,6 +105,14 @@ PD_CONSTRUCTOR static void videoConfigInit(void)
|
||||
* scheduler thread in videoStartFrame() where the GL context is bound. */
|
||||
static volatile int liveCfgDirty = 0;
|
||||
|
||||
/* D211/D212: push the port-only image knobs into fast3d. Both are safe to
|
||||
* call every frame; gfx_set_fov_scale(1.0) is a guarded no-op. */
|
||||
static void videoApplyImageOptions(void)
|
||||
{
|
||||
gfx_set_fov_scale((float)cfgFovScale / 100.0f);
|
||||
gfx_set_anisotropy_level(cfgAniso);
|
||||
}
|
||||
|
||||
static void videoApplyTexFilter(void)
|
||||
{
|
||||
if (cfgTexFilter >= 2) {
|
||||
@@ -271,6 +283,7 @@ int videoInit(void)
|
||||
gfx_set_wrap_fix(cfgWrapFix);
|
||||
|
||||
videoApplyTexFilter();
|
||||
videoApplyImageOptions();
|
||||
|
||||
/* The GL context is currently current on this (host main) thread, but all
|
||||
* rendering happens on the game's scheduler thread. WGL only allows a
|
||||
@@ -311,9 +324,10 @@ void videoStartFrame(void)
|
||||
wmAPI->set_swap_interval(cfgVSync ? 1 : 0);
|
||||
gfx_set_target_fps(cfgFpsCap); /* 0 = uncapped */
|
||||
videoApplyTexFilter();
|
||||
videoApplyImageOptions();
|
||||
sysLogPrintf(LOG_INFO, "video: live config applied "
|
||||
"(vsync=%d fpscap=%d texfilter=%d)",
|
||||
cfgVSync, cfgFpsCap, cfgTexFilter);
|
||||
"(vsync=%d fpscap=%d texfilter=%d fov=%d aniso=%d)",
|
||||
cfgVSync, cfgFpsCap, cfgTexFilter, cfgFovScale, cfgAniso);
|
||||
}
|
||||
|
||||
gfx_start_frame();
|
||||
|
||||
Reference in new issue
Block a user