mirror of
https://github.com/isledecomp/isle.pizza.git
synced 2026-03-01 14:27:38 +00:00
Preload default textures for instant texture picker opening
Fetch and parse .tex files in the background when a textured part loads, and pass the results to TexturePickerModal as a prop. The modal no longer fetches on mount, eliminating the loading delay.
This commit is contained in:
parent
c3083b02af
commit
8adeb9fed6
@ -1,18 +1,17 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { parseTex } from '../../core/formats/TexParser.js';
|
||||
import { quantizeImage, squareTexture } from '../../core/savegame/imageQuantizer.js';
|
||||
import { saveCustomTexture, listCustomTextures, deleteCustomTexture } from '../../core/savegame/textureStorage.js';
|
||||
import Carousel from '../Carousel.svelte';
|
||||
|
||||
export let textureInfo;
|
||||
export let palette = null;
|
||||
export let defaults = null;
|
||||
export let onSelect = () => {};
|
||||
export let onClose = () => {};
|
||||
|
||||
let defaults = [];
|
||||
let defaultTextures = [];
|
||||
let customTextures = [];
|
||||
let loadingDefaults = true;
|
||||
let fileInput;
|
||||
let activeTab = 'default';
|
||||
let selectedCustomId = null;
|
||||
@ -22,40 +21,20 @@
|
||||
let targetHeight = 128;
|
||||
|
||||
onMount(async () => {
|
||||
await loadDefaults();
|
||||
initDefaults();
|
||||
await loadCustomTextures();
|
||||
});
|
||||
|
||||
async function loadDefaults() {
|
||||
loadingDefaults = true;
|
||||
const loaded = [];
|
||||
|
||||
for (const texFile of textureInfo.texFiles) {
|
||||
try {
|
||||
const response = await fetch(`/${texFile}.tex`);
|
||||
if (!response.ok) continue;
|
||||
const buffer = await response.arrayBuffer();
|
||||
const parsed = parseTex(buffer);
|
||||
if (parsed.textures.length > 0) {
|
||||
const tex = parsed.textures[0];
|
||||
loaded.push({
|
||||
name: texFile,
|
||||
...tex,
|
||||
dataUrl: textureToDataUrl(tex)
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Failed to load ${texFile}.tex:`, e);
|
||||
}
|
||||
function initDefaults() {
|
||||
const source = defaults || [];
|
||||
defaultTextures = source.map(tex => ({
|
||||
...tex,
|
||||
dataUrl: textureToDataUrl(tex)
|
||||
}));
|
||||
if (defaultTextures.length > 0) {
|
||||
targetWidth = defaultTextures[0].width;
|
||||
targetHeight = defaultTextures[0].height;
|
||||
}
|
||||
|
||||
if (loaded.length > 0) {
|
||||
targetWidth = loaded[0].width;
|
||||
targetHeight = loaded[0].height;
|
||||
}
|
||||
|
||||
defaults = loaded;
|
||||
loadingDefaults = false;
|
||||
}
|
||||
|
||||
async function loadCustomTextures() {
|
||||
@ -127,7 +106,7 @@
|
||||
|
||||
// Use the WDB palette (passed as prop) — this is the palette the game's
|
||||
// DirectDraw surface actually uses. Fall back to first default's palette.
|
||||
const targetPalette = palette || defaults[0]?.palette;
|
||||
const targetPalette = palette || defaultTextures[0]?.palette;
|
||||
if (!targetPalette) return;
|
||||
|
||||
const img = new Image();
|
||||
@ -210,11 +189,8 @@
|
||||
|
||||
<div class="modal-body">
|
||||
{#if activeTab === 'default'}
|
||||
{#if loadingDefaults}
|
||||
<div class="loading">Loading textures...</div>
|
||||
{:else}
|
||||
<div class="texture-grid">
|
||||
{#each defaults as tex}
|
||||
{#each defaultTextures as tex}
|
||||
<button
|
||||
type="button"
|
||||
class="texture-thumb"
|
||||
@ -225,7 +201,6 @@
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
{#if customTextures.length > 0}
|
||||
<div class="custom-carousel">
|
||||
@ -333,13 +308,6 @@
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.85em;
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.texture-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
Act1PlaneIndices
|
||||
} from '../../core/savegame/constants.js';
|
||||
import { squareTexture } from '../../core/savegame/imageQuantizer.js';
|
||||
import { parseTex } from '../../core/formats/TexParser.js';
|
||||
import NavButton from '../NavButton.svelte';
|
||||
import ResetButton from '../ResetButton.svelte';
|
||||
import EditorTooltip from '../EditorTooltip.svelte';
|
||||
@ -45,6 +46,7 @@
|
||||
let showTextureModal = false;
|
||||
let texturePalette = null;
|
||||
let wdbTexture = null;
|
||||
let preloadedDefaults = null;
|
||||
|
||||
// Current part info from flat list
|
||||
$: currentEntry = allParts[globalIndex];
|
||||
@ -207,12 +209,36 @@
|
||||
// Load part with current color, textures, and parts map for shared LOD lookup
|
||||
renderer.loadPartWithColor(partRoi, currentColorValue, textures, partsMap)
|
||||
loadedPartKey = partKey;
|
||||
|
||||
// Preload default .tex files in background for the texture picker
|
||||
if (textureInfo) {
|
||||
preloadDefaultTextures(textureInfo);
|
||||
} else {
|
||||
preloadedDefaults = null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load part:', e);
|
||||
partError = e.message;
|
||||
}
|
||||
}
|
||||
|
||||
async function preloadDefaultTextures(info) {
|
||||
const loaded = [];
|
||||
for (const texFile of info.texFiles) {
|
||||
const response = await fetch(`/${texFile}.tex`);
|
||||
if (!response.ok) continue;
|
||||
const buffer = await response.arrayBuffer();
|
||||
const parsed = parseTex(buffer);
|
||||
if (parsed.textures.length > 0) {
|
||||
loaded.push({ name: texFile, ...parsed.textures[0] });
|
||||
}
|
||||
}
|
||||
// Only apply if textureInfo hasn't changed since we started
|
||||
if (textureInfo === info) {
|
||||
preloadedDefaults = loaded;
|
||||
}
|
||||
}
|
||||
|
||||
function prevPart() {
|
||||
globalIndex = globalIndex > 0 ? globalIndex - 1 : allParts.length - 1;
|
||||
loadedPartKey = null;
|
||||
@ -358,6 +384,7 @@
|
||||
<TexturePickerModal
|
||||
{textureInfo}
|
||||
palette={texturePalette}
|
||||
defaults={preloadedDefaults}
|
||||
onSelect={handleTextureSelect}
|
||||
onClose={() => showTextureModal = false}
|
||||
/>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user