mirror of
https://github.com/exogen/t2-mapper.git
synced 2026-01-19 20:25:01 +00:00
fix texture lookup - try .jpg and .bmp too
This commit is contained in:
parent
5d0a8a3fab
commit
5f48c1c2d2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -2,7 +2,7 @@
|
|||
2:I[9766,[],""]
|
||||
3:I[8924,[],""]
|
||||
4:I[1959,[],"ClientPageRoot"]
|
||||
5:I[8283,["367","static/chunks/b536a0f1-05ee2c75df4a3b9d.js","831","static/chunks/bd904a5c-3aea2adebde6f067.js","664","static/chunks/a3cd4a83-5c5b758da206345b.js","794","static/chunks/f6211eb1-4f3105d2434536dc.js","413","static/chunks/1329d575-16915d95397758f8.js","331","static/chunks/331-37e8e553d8a20c21.js","974","static/chunks/app/page-f60b39f483c86849.js"],"default"]
|
||||
5:I[8283,["367","static/chunks/b536a0f1-05ee2c75df4a3b9d.js","831","static/chunks/bd904a5c-3aea2adebde6f067.js","664","static/chunks/a3cd4a83-5c5b758da206345b.js","794","static/chunks/f6211eb1-4f3105d2434536dc.js","413","static/chunks/1329d575-16915d95397758f8.js","331","static/chunks/331-37e8e553d8a20c21.js","974","static/chunks/app/page-562a5e5ed29fb045.js"],"default"]
|
||||
8:I[4431,[],"OutletBoundary"]
|
||||
a:I[5278,[],"AsyncMetadataOutlet"]
|
||||
c:I[4431,[],"ViewportBoundary"]
|
||||
|
|
@ -10,7 +10,7 @@ e:I[4431,[],"MetadataBoundary"]
|
|||
f:"$Sreact.suspense"
|
||||
11:I[7150,[],""]
|
||||
:HL["/t2-mapper/_next/static/css/e7a9161e212d890f.css","style"]
|
||||
0:{"P":null,"b":"1kiuXQr5AbGwVAE5IklXM","p":"/t2-mapper","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/t2-mapper/_next/static/css/e7a9161e212d890f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L4",null,{"Component":"$5","searchParams":{},"params":{},"promises":["$@6","$@7"]}],null,["$","$L8",null,{"children":["$L9",["$","$La",null,{"promise":"$@b"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Lc",null,{"children":"$Ld"}],null],["$","$Le",null,{"children":["$","div",null,{"hidden":true,"children":["$","$f",null,{"fallback":null,"children":"$L10"}]}]}]]}],false]],"m":"$undefined","G":["$11",[]],"s":false,"S":true}
|
||||
0:{"P":null,"b":"JA8GPtPjSEu8NmS5GBeMX","p":"/t2-mapper","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/t2-mapper/_next/static/css/e7a9161e212d890f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L4",null,{"Component":"$5","searchParams":{},"params":{},"promises":["$@6","$@7"]}],null,["$","$L8",null,{"children":["$L9",["$","$La",null,{"promise":"$@b"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Lc",null,{"children":"$Ld"}],null],["$","$Le",null,{"children":["$","div",null,{"hidden":true,"children":["$","$f",null,{"fallback":null,"children":"$L10"}]}]}]]}],false]],"m":"$undefined","G":["$11",[]],"s":false,"S":true}
|
||||
6:{}
|
||||
7:"$0:f:0:1:2:children:1:props:children:0:props:params"
|
||||
d:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
||||
|
|
|
|||
|
|
@ -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} />;
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue