fix texture lookup - try .jpg and .bmp too

This commit is contained in:
Brian Beck 2025-12-03 05:57:16 -08:00
parent 5d0a8a3fab
commit 5f48c1c2d2
12 changed files with 95 additions and 46 deletions

View file

@ -1,10 +1,6 @@
import { memo, Suspense, useMemo, useRef, useEffect } from "react";
import { useGLTF, useTexture } from "@react-three/drei";
import {
FALLBACK_TEXTURE_URL,
shapeTextureToUrl,
shapeToUrl,
} from "../loaders";
import { FALLBACK_TEXTURE_URL, textureToUrl, shapeToUrl } from "../loaders";
import { filterGeometryByVertexGroups, getHullBoneIndices } from "../meshUtils";
import {
createAlphaAsRoughnessMaterial,
@ -73,7 +69,7 @@ function StaticTexture({ material, shapeName }) {
}
return resourcePath
? // Use custom `resource_path` added by forked io_dts3d Blender add-on
shapeTextureToUrl(resourcePath)
textureToUrl(resourcePath)
: FALLBACK_TEXTURE_URL;
}, [material, resourcePath, shapeName]);

View file

@ -2,7 +2,7 @@ import { memo, Suspense, useMemo } from "react";
import { ErrorBoundary } from "react-error-boundary";
import { Mesh } from "three";
import { useGLTF, useTexture } from "@react-three/drei";
import { interiorTextureToUrl, interiorToUrl } from "../loaders";
import { textureToUrl, interiorToUrl } from "../loaders";
import type { TorqueObject } from "../torqueScript";
import { getPosition, getProperty, getRotation, getScale } from "../mission";
import { setupColor } from "../textureUtils";
@ -18,7 +18,7 @@ function useInterior(interiorFile: string) {
}
function InteriorTexture({ materialName }: { materialName: string }) {
const url = interiorTextureToUrl(materialName);
const url = textureToUrl(materialName);
const texture = useTexture(url, (texture) => setupColor(texture));
return <meshStandardMaterial map={texture} side={2} />;

View file

@ -5,10 +5,10 @@ import { Color, ShaderMaterial, BackSide, Euler } from "three";
import type { TorqueObject } from "../torqueScript";
import { getFloat, getProperty } from "../mission";
import { useSettings } from "./SettingsProvider";
import { BASE_URL, getUrlForPath, loadDetailMapList } from "../loaders";
import { BASE_URL, loadDetailMapList, textureToUrl } from "../loaders";
import { useThree } from "@react-three/fiber";
const FALLBACK_URL = `${BASE_URL}/black.png`;
const FALLBACK_TEXTURE_URL = `${BASE_URL}/black.png`;
/**
* Load a .dml file, used to list the textures for different faces of a skybox.
@ -35,20 +35,20 @@ export function SkyBox({
() =>
detailMapList
? [
getUrlForPath(detailMapList[1], FALLBACK_URL), // +x
getUrlForPath(detailMapList[3], FALLBACK_URL), // -x
getUrlForPath(detailMapList[4], FALLBACK_URL), // +y
getUrlForPath(detailMapList[5], FALLBACK_URL), // -y
getUrlForPath(detailMapList[0], FALLBACK_URL), // +z
getUrlForPath(detailMapList[2], FALLBACK_URL), // -z
textureToUrl(detailMapList[1]), // +x
textureToUrl(detailMapList[3]), // -x
textureToUrl(detailMapList[4]), // +y
textureToUrl(detailMapList[5]), // -y
textureToUrl(detailMapList[0]), // +z
textureToUrl(detailMapList[2]), // -z
]
: [
FALLBACK_URL,
FALLBACK_URL,
FALLBACK_URL,
FALLBACK_URL,
FALLBACK_URL,
FALLBACK_URL,
FALLBACK_TEXTURE_URL,
FALLBACK_TEXTURE_URL,
FALLBACK_TEXTURE_URL,
FALLBACK_TEXTURE_URL,
FALLBACK_TEXTURE_URL,
FALLBACK_TEXTURE_URL,
],
[detailMapList],
);
@ -146,6 +146,22 @@ export function Sky({ object }: { object: TorqueObject }) {
// Skybox textures.
const materialList = getProperty(object, "materialList");
const skySolidColor = useMemo(() => {
const colorString = getProperty(object, "SkySolidColor");
if (colorString) {
// `colorString` might specify an alpha value, but three.js doesn't
// support opacity on fog or scene backgrounds, so ignore it.
// Note: This is a space-separated string, so we split and parse each component.
const [r, g, b] = colorString
.split(" ")
.map((s: string) => parseFloat(s));
return [
new Color().setRGB(r, g, b),
new Color().setRGB(r, g, b).convertSRGBToLinear(),
];
}
}, [object]);
// Fog parameters.
// TODO: There can be multiple fog volumes/layers. Render simple fog for now.
const fogDistance = getFloat(object, "fogDistance");
@ -166,8 +182,10 @@ export function Sky({ object }: { object: TorqueObject }) {
}
}, [object]);
const backgroundColor = fogColor ? (
<color attach="background" args={[fogColor[0]]} />
const skyColor = skySolidColor || fogColor;
const backgroundColor = skyColor ? (
<color attach="background" args={[skyColor[0]]} />
) : null;
return (

View file

@ -3,9 +3,9 @@ import {
getActualResourceKey,
getMissionInfo,
getSourceAndPath,
getStandardTextureResourceKey,
} from "./manifest";
import { parseMissionScript } from "./mission";
import { normalizePath } from "./stringUtils";
import { parseTerrainBuffer } from "./terrain";
export const BASE_URL = "/t2-mapper";
@ -46,25 +46,20 @@ export function shapeToUrl(name: string) {
export function terrainTextureToUrl(name: string) {
name = name.replace(/^terrain\./, "");
return getUrlForPath(`textures/terrain/${name}.png`, FALLBACK_TEXTURE_URL);
}
export function interiorTextureToUrl(name: string) {
// name = name.replace(/\.\d+$/, "");
return getUrlForPath(`textures/${name}.png`, FALLBACK_TEXTURE_URL);
const resourceKey = getStandardTextureResourceKey(`textures/terrain/${name}`);
return getUrlForPath(resourceKey, FALLBACK_TEXTURE_URL);
}
export function textureFrameToUrl(fileName: string) {
return getUrlForPath(`textures/skins/${fileName}`, FALLBACK_TEXTURE_URL);
}
export function shapeTextureToUrl(name: string) {
// name = name.replace(/\.\d+$/, "");
return getUrlForPath(`textures/${name}.png`, FALLBACK_TEXTURE_URL);
const resourceKey = getStandardTextureResourceKey(
`textures/skins/${fileName}`,
);
return getUrlForPath(resourceKey, FALLBACK_TEXTURE_URL);
}
export function textureToUrl(name: string) {
return getUrlForPath(`textures/${name}.png`, FALLBACK_TEXTURE_URL);
const resourceKey = getStandardTextureResourceKey(`textures/${name}`);
return getUrlForPath(resourceKey, FALLBACK_TEXTURE_URL);
}
export function audioToUrl(fileName: string) {
@ -76,8 +71,14 @@ export async function loadDetailMapList(name: string) {
const res = await fetch(url);
const text = await res.text();
return text
.split(/(?:\r\n|\n|\r)/)
.map((line) => `textures/${line.trim().replace(/\.png$/i, "")}.png`);
.split(/(?:\r\n|\r|\n)/)
.map((line) => {
line = line.trim();
if (!line.startsWith(";")) {
return line;
}
})
.filter(Boolean);
}
export async function loadMission(name: string) {

View file

@ -88,6 +88,40 @@ export function getResourceList(): string[] {
return Object.keys(manifest.resources);
}
/**
* Standard texture file extension loading order:
*
* 1. "" (no extension - exact filename match)
* 2. .jpg
* 3. .png
* 4. .gif
* 5. .bmp
*/
const standardTextureExt = ["", ".jpg", ".png", ".gif", ".bmp"];
export function getStandardTextureResourceKey(resourcePath: string) {
const baseResourceKey = getResourceKey(resourcePath);
for (const ext of standardTextureExt) {
const resourceKey = `${baseResourceKey}${ext}`;
if (manifest.resources[resourceKey]) {
return resourceKey;
}
}
return baseResourceKey;
}
/**
* Paletted texture file extension loading order:
*
* 1. "" (no extension - exact filename match)
* 2. .bm8
* 3. .bmp
* 4. .jpg
* 5. .png
* 6. .gif
*/
// Not used for now!
const palettedTextureExt = ["", ".bm8", ".bmp", ".jpg", ".png", ".gif"];
export function getLocalFilePath(resourcePath: string): string {
const resourceKey = getResourceKey(resourcePath);
const [sourcePath, actualPath] = getSourceAndPath(resourceKey);