mirror of https://github.com/hykilpikonna/AquaDX
refactor: move DDS cache
moved the DDS cache from dds.ts to ddsCache.ts and added caching for scaled images Co-authored-by: split / May <split@split.pet>pull/97/head
parent
ce95f2165d
commit
4d4335004f
|
@ -8,6 +8,8 @@ DDS header parsing based off of https://gist.github.com/brett19/13c83c2e5e389337
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import DDSCache from "./ddsCache";
|
||||||
|
|
||||||
function makeFourCC(string: string) {
|
function makeFourCC(string: string) {
|
||||||
return string.charCodeAt(0) +
|
return string.charCodeAt(0) +
|
||||||
(string.charCodeAt(1) << 8) +
|
(string.charCodeAt(1) << 8) +
|
||||||
|
@ -56,7 +58,7 @@ void main() {
|
||||||
|
|
||||||
export class DDS {
|
export class DDS {
|
||||||
constructor(db: IDBDatabase | undefined) {
|
constructor(db: IDBDatabase | undefined) {
|
||||||
this.db = db
|
this.cache = new DDSCache(db);
|
||||||
|
|
||||||
let gl = this.canvasGL.getContext("webgl");
|
let gl = this.canvasGL.getContext("webgl");
|
||||||
if (!gl) throw new Error("Failed to get WebGL rendering context") // TODO: make it switch to Classic userbox
|
if (!gl) throw new Error("Failed to get WebGL rendering context") // TODO: make it switch to Classic userbox
|
||||||
|
@ -200,20 +202,10 @@ export class DDS {
|
||||||
*/
|
*/
|
||||||
loadFile(path: string) : Promise<boolean> {
|
loadFile(path: string) : Promise<boolean> {
|
||||||
return new Promise(async r => {
|
return new Promise(async r => {
|
||||||
if (!this.db)
|
let file = await this.cache?.getFromDatabase(path)
|
||||||
return r(false);
|
if (file != null)
|
||||||
let transaction = this.db.transaction(["dds"], "readonly");
|
await this.fromBlob(file)
|
||||||
let objectStore = transaction.objectStore("dds");
|
r(file != null)
|
||||||
let request = objectStore.get(path);
|
|
||||||
request.onsuccess = async (e) => {
|
|
||||||
if (request.result)
|
|
||||||
if (request.result.blob) {
|
|
||||||
await this.fromBlob(request.result.blob)
|
|
||||||
return r(true);
|
|
||||||
}
|
|
||||||
r(false);
|
|
||||||
}
|
|
||||||
request.onerror = () => r(false);
|
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -224,17 +216,19 @@ export class DDS {
|
||||||
* @returns An object URL which correlates to a Blob
|
* @returns An object URL which correlates to a Blob
|
||||||
*/
|
*/
|
||||||
async getFile(path: string, fallback?: string) : Promise<string> {
|
async getFile(path: string, fallback?: string) : Promise<string> {
|
||||||
if (this.urlCache[path])
|
if (this.cache?.cached(path))
|
||||||
return this.urlCache[path]
|
return this.cache.find(path) ?? ""
|
||||||
if (!await this.loadFile(path))
|
if (!await this.loadFile(path))
|
||||||
if (fallback) {
|
if (fallback) {
|
||||||
if (!await this.loadFile(fallback))
|
if (!await this.loadFile(fallback))
|
||||||
return "";
|
return "";
|
||||||
} else
|
} else
|
||||||
return "";
|
return ""
|
||||||
let url = URL.createObjectURL(await this.getBlob("image/png") ?? new Blob([]));
|
let blob = await this.getBlob("image/png");
|
||||||
this.urlCache[path] = url;
|
if (!blob) return ""
|
||||||
return url
|
return this.cache?.save(
|
||||||
|
path, URL.createObjectURL(blob)
|
||||||
|
) ?? "";
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -254,6 +248,7 @@ export class DDS {
|
||||||
this.canvas2D.height = h * (s ?? 1);
|
this.canvas2D.height = h * (s ?? 1);
|
||||||
this.ctx.drawImage(this.canvasGL, x, y, w, h, 0, 0, w * (s ?? 1), h * (s ?? 1));
|
this.ctx.drawImage(this.canvasGL, x, y, w, h, 0, 0, w * (s ?? 1), h * (s ?? 1));
|
||||||
|
|
||||||
|
/* We don't want to cache this, it's a spritesheet piece. */
|
||||||
return URL.createObjectURL(await this.get2DBlob("image/png") ?? new Blob([]));
|
return URL.createObjectURL(await this.get2DBlob("image/png") ?? new Blob([]));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -265,8 +260,8 @@ export class DDS {
|
||||||
* @returns An object URL which correlates to a Blob
|
* @returns An object URL which correlates to a Blob
|
||||||
*/
|
*/
|
||||||
async getFileScaled(path: string, s: number, fallback?: string): Promise<string> {
|
async getFileScaled(path: string, s: number, fallback?: string): Promise<string> {
|
||||||
if (this.urlCache[path])
|
if (this.cache?.cached(path, s))
|
||||||
return this.urlCache[path]
|
return this.cache.find(path, s) ?? ""
|
||||||
if (!await this.loadFile(path))
|
if (!await this.loadFile(path))
|
||||||
if (fallback) {
|
if (fallback) {
|
||||||
if (!await this.loadFile(fallback))
|
if (!await this.loadFile(fallback))
|
||||||
|
@ -276,9 +271,8 @@ export class DDS {
|
||||||
this.canvas2D.width = this.canvasGL.width * (s ?? 1);
|
this.canvas2D.width = this.canvasGL.width * (s ?? 1);
|
||||||
this.canvas2D.height = this.canvasGL.height * (s ?? 1);
|
this.canvas2D.height = this.canvasGL.height * (s ?? 1);
|
||||||
this.ctx.drawImage(this.canvasGL, 0, 0, this.canvasGL.width, this.canvasGL.height, 0, 0, this.canvasGL.width * (s ?? 1), this.canvasGL.height * (s ?? 1));
|
this.ctx.drawImage(this.canvasGL, 0, 0, this.canvasGL.width, this.canvasGL.height, 0, 0, this.canvasGL.width * (s ?? 1), this.canvasGL.height * (s ?? 1));
|
||||||
let url = URL.createObjectURL(await this.get2DBlob("image/png") ?? new Blob([]));
|
|
||||||
this.urlCache[path] = url;
|
return this.cache?.save(path, URL.createObjectURL(await this.get2DBlob("image/png") ?? new Blob([])), s) ?? "";
|
||||||
return url;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -332,13 +326,11 @@ export class DDS {
|
||||||
|
|
||||||
canvas2D: HTMLCanvasElement = document.createElement("canvas");
|
canvas2D: HTMLCanvasElement = document.createElement("canvas");
|
||||||
canvasGL: HTMLCanvasElement = document.createElement("canvas");
|
canvasGL: HTMLCanvasElement = document.createElement("canvas");
|
||||||
urlCache: Record<string, string> = {};
|
|
||||||
|
|
||||||
|
cache: DDSCache | null;
|
||||||
ctx: CanvasRenderingContext2D;
|
ctx: CanvasRenderingContext2D;
|
||||||
|
|
||||||
gl: WebGLRenderingContext;
|
gl: WebGLRenderingContext;
|
||||||
ext: ReturnType<typeof this.gl.getExtension>;
|
ext: ReturnType<typeof this.gl.getExtension>;
|
||||||
shader: WebGLShader | null = null;
|
shader: WebGLShader | null = null;
|
||||||
|
|
||||||
db: IDBDatabase | undefined;
|
|
||||||
};
|
};
|
|
@ -0,0 +1,64 @@
|
||||||
|
export default class DDSCache {
|
||||||
|
constructor(db: IDBDatabase | undefined) {
|
||||||
|
this.db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Finds an object URL for the image with the specified path and scale
|
||||||
|
* @param path Image path
|
||||||
|
* @param scale Scale factor
|
||||||
|
*/
|
||||||
|
find(path: string, scale: number = 1): string | undefined {
|
||||||
|
return (this.urlCache.find(
|
||||||
|
p => p.path == path && p.scale == scale)?.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Checks whether an object URL is cached for the image with the specified path and scale
|
||||||
|
* @param path Image path
|
||||||
|
* @param scale Scale factor
|
||||||
|
*/
|
||||||
|
cached(path: string, scale: number = 1): boolean {
|
||||||
|
return this.urlCache.some(
|
||||||
|
p => p.path == path && p.scale == scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Save an object URL for the specified path and scale to the cache
|
||||||
|
* @param path Image path
|
||||||
|
* @param url Object URL
|
||||||
|
* @param scale Scale factor
|
||||||
|
*/
|
||||||
|
save(path: string, url: string, scale: number = 1) {
|
||||||
|
if (this.cached(path, scale)) {
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
return this.find(path, scale)
|
||||||
|
}
|
||||||
|
this.urlCache.push({path, url, scale})
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Retrieve a Blob from a database based on the specified path
|
||||||
|
* @param path Image path
|
||||||
|
*/
|
||||||
|
getFromDatabase(path: string): Promise<Blob | null> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!this.db)
|
||||||
|
return resolve(null);
|
||||||
|
let transaction = this.db.transaction(["dds"], "readonly");
|
||||||
|
let objectStore = transaction.objectStore("dds");
|
||||||
|
let request = objectStore.get(path);
|
||||||
|
request.onsuccess = async (e) => {
|
||||||
|
if (request.result)
|
||||||
|
if (request.result.blob)
|
||||||
|
return resolve(request.result.blob);
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
|
request.onerror = () => resolve(null);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
private urlCache: {scale: number, path: string, url: string}[] = [];
|
||||||
|
private db: IDBDatabase | undefined;
|
||||||
|
}
|
Loading…
Reference in New Issue