mirror of
https://github.com/DaanVandenBosch/phantasmal-world.git
synced 2025-04-05 07:18:29 +08:00
98 lines
3.1 KiB
TypeScript
98 lines
3.1 KiB
TypeScript
import { Disposer } from "../../core/observable/Disposer";
|
|
import { LogManager } from "../../core/Logger";
|
|
import { TextureController } from "../controllers/TextureController";
|
|
import { WebglRenderer } from "../../core/rendering/webgl/WebglRenderer";
|
|
import { XvrTexture } from "../../core/data_formats/parsing/ninja/texture";
|
|
import { TranslateTransform } from "../../core/rendering/Transform";
|
|
import { VertexFormat } from "../../core/rendering/VertexFormat";
|
|
import { Texture, TextureFormat } from "../../core/rendering/Texture";
|
|
import { WebglMesh } from "../../core/rendering/webgl/WebglMesh";
|
|
|
|
const logger = LogManager.get("viewer/rendering/TextureWebglRenderer");
|
|
|
|
export class TextureWebglRenderer extends WebglRenderer {
|
|
private readonly disposer = new Disposer();
|
|
|
|
constructor(ctrl: TextureController) {
|
|
super();
|
|
|
|
this.disposer.add_all(
|
|
ctrl.textures.observe(({ value: textures }) => {
|
|
this.scene.delete();
|
|
this.camera.reset();
|
|
this.create_quads(textures);
|
|
this.schedule_render();
|
|
}),
|
|
);
|
|
}
|
|
|
|
dispose(): void {
|
|
super.dispose();
|
|
this.disposer.dispose();
|
|
}
|
|
|
|
private create_quads(textures: readonly XvrTexture[]): void {
|
|
let total_width = 10 * (textures.length - 1); // 10px spacing between textures.
|
|
let total_height = 0;
|
|
|
|
for (const tex of textures) {
|
|
total_width += tex.width;
|
|
total_height = Math.max(total_height, tex.height);
|
|
}
|
|
|
|
let x = -Math.floor(total_width / 2);
|
|
const y = -Math.floor(total_height / 2);
|
|
|
|
for (const tex of textures) {
|
|
try {
|
|
const quad_mesh = this.create_quad(tex);
|
|
|
|
this.scene.root_node.add_child(
|
|
quad_mesh,
|
|
new TranslateTransform(x, y + (total_height - tex.height) / 2, 0),
|
|
);
|
|
} catch (e) {
|
|
logger.error("Couldn't create quad for texture.", e);
|
|
}
|
|
|
|
x += 10 + tex.width;
|
|
}
|
|
}
|
|
|
|
private create_quad(tex: XvrTexture): WebglMesh {
|
|
return this.mesh_builder(VertexFormat.PosTex)
|
|
.vertex(0, 0, 0, 0, 1)
|
|
.vertex(tex.width, 0, 0, 1, 1)
|
|
.vertex(tex.width, tex.height, 0, 1, 0)
|
|
.vertex(0, tex.height, 0, 0, 0)
|
|
|
|
.triangle(0, 1, 2)
|
|
.triangle(2, 3, 0)
|
|
|
|
.texture(xvr_texture_to_texture(tex))
|
|
|
|
.build();
|
|
}
|
|
}
|
|
|
|
function xvr_texture_to_texture(tex: XvrTexture): Texture {
|
|
let format: TextureFormat;
|
|
let data_size: number;
|
|
|
|
// Ignore mipmaps.
|
|
switch (tex.format[1]) {
|
|
case 6:
|
|
format = TextureFormat.RGBA_S3TC_DXT1;
|
|
data_size = (tex.width * tex.height) / 2;
|
|
break;
|
|
case 7:
|
|
format = TextureFormat.RGBA_S3TC_DXT3;
|
|
data_size = tex.width * tex.height;
|
|
break;
|
|
default:
|
|
throw new Error(`Format ${tex.format.join(", ")} not supported.`);
|
|
}
|
|
|
|
return new Texture(tex.width, tex.height, format, tex.data.slice(0, data_size));
|
|
}
|