Hosting code to git for the first time.
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Ray Lay Renderer Debugger</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/source/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"private": "true",
|
||||
"name": "@ray-lab/renderer-debugger",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"dev": "vite"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@ray-lab/renderer-virtual": "workspace:*",
|
||||
"@ray-lab/renderer-webgl": "workspace:*",
|
||||
"vue": "^3.2.45"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.11.18",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"typescript": "^4.9.4",
|
||||
"vite": "^4.0.4",
|
||||
"vite-plugin-vue-setup-extend": "^0.4.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div ref="contentRef" class="content"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { WebGLCanvas, EventEmitter } from "@ray-lab/renderer-webgl";
|
||||
|
||||
const contentRef = ref<HTMLDivElement>();
|
||||
const canvasEle = document.createElement("canvas");
|
||||
|
||||
onMounted(() => {
|
||||
const c = new WebGLCanvas({
|
||||
canvas: canvasEle,
|
||||
container: contentRef.value,
|
||||
autoResize: true,
|
||||
width: 800,
|
||||
height: 600
|
||||
});
|
||||
// c.on("resize", () => { console.log(c.canvas.width, c.canvas.height) });
|
||||
if (contentRef.value) {
|
||||
contentRef.value.appendChild(canvasEle);
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.content {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,5 @@
|
||||
import { createApp } from "vue";
|
||||
import AppVue from "./App.vue";
|
||||
|
||||
const oneMapApp = createApp(AppVue);
|
||||
oneMapApp.mount("#app");
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.web.json",
|
||||
|
||||
"include": [
|
||||
"./source/**/*",
|
||||
"./source/**/*.vue"
|
||||
],
|
||||
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"build"
|
||||
],
|
||||
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"alwaysStrict": true,
|
||||
"baseUrl": "./",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"useDefineForClassFields": true,
|
||||
},
|
||||
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.vite.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.node.json",
|
||||
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { defineConfig, type UserConfig, type ConfigEnv } from "vite";
|
||||
import { default as vuePlugin } from "@vitejs/plugin-vue";
|
||||
import { default as VueSetupExtend } from 'vite-plugin-vue-setup-extend';
|
||||
import { resolve } from "path";
|
||||
|
||||
const projectPath = resolve(__dirname, "./");
|
||||
const buildPath = resolve(projectPath, "./build");
|
||||
|
||||
async function viteConfig({ command, mode }: ConfigEnv): Promise<UserConfig> {
|
||||
|
||||
return {
|
||||
root: projectPath,
|
||||
build: {
|
||||
outDir: buildPath,
|
||||
},
|
||||
plugins: [vuePlugin(), VueSetupExtend()]
|
||||
}
|
||||
}
|
||||
|
||||
export default defineConfig(viteConfig);
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "@ray-lab/renderer-virtual",
|
||||
"version": "1.0.0",
|
||||
"description": "Renderer Common Interface.",
|
||||
"scripts": {
|
||||
"build": "rollup -c rollup.config.js"
|
||||
},
|
||||
"type": "module",
|
||||
"types": "./build/virtual-renderer.d.ts",
|
||||
"keywords": [
|
||||
"renderer-virtual",
|
||||
"renderer"
|
||||
],
|
||||
"author": "MrKBear",
|
||||
"devDependencies": {
|
||||
"rollup": "^3.9.1",
|
||||
"rollup-plugin-ts": "^3.0.2",
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import tsPlugin from "rollup-plugin-ts";
|
||||
|
||||
/**
|
||||
* @type {import("rollup").RollupOptions}
|
||||
*/
|
||||
const rollupConfig = {
|
||||
|
||||
input: "./source/virtual-renderer.ts",
|
||||
|
||||
output: [
|
||||
{
|
||||
file: "./build/virtual-renderer.d.ts",
|
||||
format: "esm"
|
||||
}
|
||||
],
|
||||
|
||||
plugins: [tsPlugin()],
|
||||
};
|
||||
|
||||
export default rollupConfig;
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Command } from "./Command";
|
||||
import type { CommandType } from "./CommandType";
|
||||
|
||||
interface ClearCommand extends Command {
|
||||
|
||||
type: CommandType.Clear
|
||||
}
|
||||
|
||||
export type { ClearCommand };
|
||||
@@ -0,0 +1,16 @@
|
||||
import type { CommandTypeSet } from "./CommandType";
|
||||
|
||||
interface Command {
|
||||
|
||||
/**
|
||||
* Define the type of command.
|
||||
*/
|
||||
type: CommandTypeSet;
|
||||
|
||||
/**
|
||||
* Unique identification of the command for feedback.
|
||||
*/
|
||||
id?: string | number;
|
||||
}
|
||||
|
||||
export type { Command };
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { RenderCommand } from "./RenderCommand";
|
||||
import type { ClearCommand } from "./ClearCommand";
|
||||
|
||||
type CommandSet = RenderCommand | ClearCommand;
|
||||
|
||||
export type { CommandSet };
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
namespace CommandType {
|
||||
|
||||
export type Render = "RENDER" | 100_001;
|
||||
|
||||
export type Resource = "RESOURCE" | 100_002;
|
||||
|
||||
export type Clear = "CLEAR" | 100_003;
|
||||
|
||||
export type Execute = "EXECUTE" | 100_004;
|
||||
}
|
||||
|
||||
type CommandTypeSet = CommandType.Render | CommandType.Resource | CommandType.Clear | CommandType.Execute;
|
||||
|
||||
export type { CommandType, CommandTypeSet };
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { Command } from "./Command";
|
||||
import type { CommandType } from "./CommandType";
|
||||
|
||||
/**
|
||||
* Rendering command are used to execute gl programs.
|
||||
*/
|
||||
interface RenderCommand extends Command {
|
||||
|
||||
type: CommandType.Render
|
||||
}
|
||||
|
||||
export type { RenderCommand };
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { CommandSet } from "command/CommandSet"
|
||||
|
||||
interface Renderer {
|
||||
|
||||
executeCommand: (commands: CommandSet[] | CommandSet) => void;
|
||||
}
|
||||
|
||||
export type { Renderer };
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { ResourceSet } from "./ResourceType";
|
||||
|
||||
interface Resource {
|
||||
|
||||
type: ResourceSet;
|
||||
|
||||
id: string | number;
|
||||
}
|
||||
|
||||
export type { Resource };
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
namespace ResourceType {
|
||||
|
||||
export type Shader = "SHADER" | 100_001;
|
||||
}
|
||||
|
||||
type ResourceSet = ResourceType.Shader;
|
||||
|
||||
export type { ResourceType, ResourceSet };
|
||||
@@ -0,0 +1,7 @@
|
||||
export * from "command/Command";
|
||||
export * from "command/CommandSet";
|
||||
export * from "command/CommandType";
|
||||
export * from "command/RenderCommand";
|
||||
export * from "command/ClearCommand";
|
||||
export * from "resource/Resource";
|
||||
export * from "resource/ResourceType";
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"declarationDir": "build",
|
||||
"baseUrl": "./",
|
||||
"lib": [
|
||||
"ESNext"
|
||||
],
|
||||
"paths": {
|
||||
"command/*": ["./source/command/*"],
|
||||
"common/*": ["./source/common/*"],
|
||||
"resource/*": ["./source/resource/*"],
|
||||
"renderer/*": ["./source/renderer/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"./source/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"build"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "@ray-lab/renderer-webgl",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "./build/webgl-renderer.js",
|
||||
"scripts": {
|
||||
"build": "rollup -c rollup.config.js"
|
||||
},
|
||||
"type": "module",
|
||||
"types": "./build/webgl-renderer.d.ts",
|
||||
"keywords": [],
|
||||
"author": "MrKBear",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@juggle/resize-observer": "^3.4.0",
|
||||
"@ray-lab/renderer-virtual": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"rollup": "^3.9.1",
|
||||
"rollup-plugin-ts": "^3.0.2",
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import tsPlugin from "rollup-plugin-ts";
|
||||
|
||||
/**
|
||||
* @type {import("rollup").RollupOptions}
|
||||
*/
|
||||
const rollupConfig = {
|
||||
|
||||
input: "./source/webgl-renderer.ts",
|
||||
|
||||
output: [
|
||||
{
|
||||
file: "./build/webgl-renderer.js",
|
||||
format: "esm"
|
||||
}
|
||||
],
|
||||
|
||||
plugins: [tsPlugin()],
|
||||
};
|
||||
|
||||
export default rollupConfig;
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
class CommandHandler {
|
||||
|
||||
}
|
||||
|
||||
export { CommandHandler };
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { CommandHandler } from "./CommandHandler";
|
||||
|
||||
class CommandInterpreter {
|
||||
|
||||
public addCommandHandler(commandHandler: CommandHandler) {
|
||||
|
||||
}
|
||||
|
||||
public removeCommandHandler() {}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
|
||||
/**
|
||||
* Allowed event name.
|
||||
*/
|
||||
type EventName = string | number | symbol;
|
||||
type EventHandler<Value> = (value?: Value) => any;
|
||||
|
||||
/**
|
||||
* An internally used event emitter model.
|
||||
*/
|
||||
class EventEmitter<EventMap extends Record<EventName, any> = {}> {
|
||||
|
||||
private eventMap = new Map<keyof EventMap, Set<Function>>;
|
||||
|
||||
/**
|
||||
* Add a listener for a given event.
|
||||
* @param event - event name.
|
||||
* @param handler - event handler.
|
||||
*/
|
||||
public addListener<T extends keyof EventMap>(event: T, handler: EventHandler<EventMap[T]>): void {
|
||||
let handlerSet = this.eventMap.get(event);
|
||||
if (!handlerSet) {
|
||||
handlerSet = new Set();
|
||||
this.eventMap.set(event, handlerSet);
|
||||
}
|
||||
handlerSet.add(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of `EventEmitter.addListener`.
|
||||
*/
|
||||
public declare on: <T extends keyof EventMap>(event: T, handler: EventHandler<EventMap[T]>) => void;
|
||||
|
||||
/**
|
||||
* Remove the listeners of a given event.
|
||||
* @param event - event name.
|
||||
* @param handler - event handler.
|
||||
*/
|
||||
public removeListener<T extends keyof EventMap>(event: T, handler: EventHandler<EventMap[T]>) {
|
||||
let handlerSet = this.eventMap.get(event);
|
||||
if (handlerSet) {
|
||||
handlerSet.delete(handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of `EventEmitter.removeListener`.
|
||||
*/
|
||||
public declare off: <T extends keyof EventMap>(event: T, handler: EventHandler<EventMap[T]>) => void;
|
||||
|
||||
/**
|
||||
* Remove all listeners of a given event.
|
||||
* @param event - event name.
|
||||
* @param handler - event handler.
|
||||
*/
|
||||
public removeAllListener<T extends keyof EventMap>(event: T) {
|
||||
this.eventMap.set(event, new Set());
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of `EventEmitter.removeAllListener`.
|
||||
*/
|
||||
public declare offAll: <T extends keyof EventMap>(event: T) => void;
|
||||
|
||||
/**
|
||||
* emit event.
|
||||
*/
|
||||
public emit<T extends keyof EventMap>(...param: EventMap[T] extends void ? [T] : [T, EventMap[T]]) {
|
||||
let handlerSet = this.eventMap.get(param[0]);
|
||||
if (handlerSet) {
|
||||
for (const handler of handlerSet) {
|
||||
handler(param[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all listeners.
|
||||
*/
|
||||
public clearAllListener() {
|
||||
this.eventMap.clear();
|
||||
this.eventMap = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of listeners for a given event.
|
||||
* @param event - event name.
|
||||
*/
|
||||
public listenerCount<T extends keyof EventMap>(event: T): number {
|
||||
let handlerSet = this.eventMap.get(event);
|
||||
if (handlerSet) {
|
||||
return handlerSet.size;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register alias.
|
||||
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
||||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
||||
EventEmitter.prototype.offAll = EventEmitter.prototype.removeAllListener;
|
||||
|
||||
export { EventEmitter };
|
||||
@@ -0,0 +1,335 @@
|
||||
import { ResizeObserver as ResizeObserverPolyfill } from '@juggle/resize-observer';
|
||||
import { EventEmitter } from "./EventEmitter";
|
||||
|
||||
const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
|
||||
|
||||
interface WebGLCanvasOption {
|
||||
|
||||
/**
|
||||
* Canvas element for outputting renderer images.
|
||||
* If a string is passed in:
|
||||
* Here will try `document.getElementById` and then `document.querySelector`
|
||||
* until a valid canvas element is found.
|
||||
*/
|
||||
canvas?: HTMLCanvasElement | OffscreenCanvas | string;
|
||||
|
||||
/**
|
||||
* Initialize with WebGL context.
|
||||
*/
|
||||
context?: WebGLRenderingContext | WebGL2RenderingContext;
|
||||
|
||||
/**
|
||||
* Parent node of canvas.
|
||||
*/
|
||||
container?: HTMLElement | string;
|
||||
|
||||
/**
|
||||
* Automatically adjust width and height to parent node width and height.
|
||||
*/
|
||||
autoResize?: boolean;
|
||||
|
||||
/**
|
||||
* Width of Canvas.
|
||||
* It will become invalid when autoResize is set.
|
||||
*/
|
||||
width?: number;
|
||||
|
||||
/**
|
||||
* Height of Canvas.
|
||||
* It will become invalid when autoResize is set.
|
||||
*/
|
||||
height?: number;
|
||||
|
||||
/**
|
||||
* Whether to use offline canvas.
|
||||
*/
|
||||
isOffScreen?: boolean;
|
||||
|
||||
/**
|
||||
* WebGL context attributes.
|
||||
*/
|
||||
contextAttributes?: WebGLContextAttributes;
|
||||
}
|
||||
|
||||
type WebGLCanvasEventMap = {
|
||||
|
||||
/**
|
||||
* Emit When the canvas size changes.
|
||||
*/
|
||||
"resize": void;
|
||||
};
|
||||
|
||||
class WebGLCanvas extends EventEmitter<WebGLCanvasEventMap> {
|
||||
|
||||
public readonly canvas: HTMLCanvasElement | OffscreenCanvas;
|
||||
|
||||
public readonly context: WebGLRenderingContext | WebGL2RenderingContext;
|
||||
|
||||
public readonly glVersion: 0 | 1 | 2;
|
||||
|
||||
public readonly isOffScreen: boolean;
|
||||
|
||||
public constructor(userOption?: WebGLCanvasOption) {
|
||||
|
||||
super();
|
||||
|
||||
const option: WebGLCanvasOption = userOption ?? {};
|
||||
|
||||
let targetCanvas: HTMLCanvasElement | OffscreenCanvas | undefined = void 0;
|
||||
let targetContext: WebGLRenderingContext | WebGL2RenderingContext | undefined = void 0;
|
||||
let targetGLVersion: 0 | 1 | 2 = 0;
|
||||
let targetIsOffScreen: boolean = false;
|
||||
|
||||
if (option.canvas instanceof HTMLCanvasElement || option.canvas instanceof OffscreenCanvas) {
|
||||
targetCanvas = option.canvas;
|
||||
}
|
||||
|
||||
else if (typeof option.canvas === "string") {
|
||||
|
||||
let findTarget: HTMLElement | null = null;
|
||||
|
||||
findTarget = document.getElementById(option.canvas);
|
||||
|
||||
if (findTarget instanceof HTMLCanvasElement) {
|
||||
targetCanvas = findTarget;
|
||||
}
|
||||
|
||||
else {
|
||||
findTarget = document.querySelector(option.canvas);
|
||||
|
||||
if (findTarget instanceof HTMLCanvasElement) {
|
||||
targetCanvas = findTarget;
|
||||
}
|
||||
|
||||
else {
|
||||
console.warn(
|
||||
`[ray-lab Renderer] Unable to search any valid canvas through "${option.canvas}". \r\n` +
|
||||
"Created internal canvas instead..."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (option.context) {
|
||||
|
||||
if (targetCanvas && targetCanvas !== option.context.canvas) {
|
||||
console.warn(
|
||||
"[ray-lab Renderer] The `canvas` element does not match the `context.canvas`: \r\n" +
|
||||
"The `canvas` option will be ignored. \r\n" +
|
||||
"Please do not use `canvas` and `context` at the same time!"
|
||||
);
|
||||
}
|
||||
|
||||
targetCanvas = option.context.canvas;
|
||||
targetContext = option.context;
|
||||
}
|
||||
|
||||
if (targetCanvas) {
|
||||
|
||||
if (targetCanvas instanceof HTMLCanvasElement) {
|
||||
|
||||
if (option.isOffScreen) {
|
||||
|
||||
if (OffscreenCanvas) {
|
||||
targetCanvas = targetCanvas.transferControlToOffscreen();
|
||||
targetIsOffScreen = true;
|
||||
}
|
||||
|
||||
else {
|
||||
targetIsOffScreen = false;
|
||||
console.warn(
|
||||
"[ray-lab Renderer] The target environment does not support OffscreenCanvas \r\n" +
|
||||
"`isOffScreen` is ignored!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
targetIsOffScreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
else if (targetCanvas instanceof OffscreenCanvas) {
|
||||
targetIsOffScreen = true;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
if (option.isOffScreen) {
|
||||
|
||||
if (OffscreenCanvas) {
|
||||
targetIsOffScreen = true;
|
||||
targetCanvas = new OffscreenCanvas(option.width ?? 300, option.height ?? 150);
|
||||
}
|
||||
|
||||
else {
|
||||
targetIsOffScreen = false;
|
||||
targetCanvas = document.createElement("canvas");
|
||||
console.warn(
|
||||
"[ray-lab Renderer] The target environment does not support OffscreenCanvas \r\n" +
|
||||
"`isOffScreen` is ignored!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
targetIsOffScreen = false;
|
||||
targetCanvas = document.createElement("canvas");
|
||||
}
|
||||
}
|
||||
|
||||
if (targetContext) {
|
||||
|
||||
if (targetCanvas instanceof WebGL2RenderingContext) {
|
||||
targetGLVersion = 2;
|
||||
}
|
||||
|
||||
else if (targetCanvas instanceof WebGLRenderingContext) {
|
||||
targetGLVersion = 1;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
let getContext: OffscreenRenderingContext | RenderingContext | null;
|
||||
|
||||
getContext = targetCanvas.getContext("webgl2", option.contextAttributes);
|
||||
|
||||
if (!getContext) {
|
||||
getContext = targetCanvas.getContext("webgl", option.contextAttributes);
|
||||
}
|
||||
|
||||
if (WebGL2RenderingContext && (getContext instanceof WebGL2RenderingContext)) {
|
||||
targetContext = getContext;
|
||||
targetGLVersion = 2;
|
||||
}
|
||||
|
||||
else if (getContext instanceof WebGLRenderingContext) {
|
||||
targetContext = getContext;
|
||||
targetGLVersion = 1;
|
||||
}
|
||||
|
||||
else {
|
||||
throw new Error("[ray-lab Renderer] The target environment does not support WebGL :(");
|
||||
}
|
||||
}
|
||||
|
||||
this.canvas = targetCanvas;
|
||||
this.context = targetContext;
|
||||
this.glVersion = targetGLVersion;
|
||||
this.isOffScreen = targetIsOffScreen;
|
||||
|
||||
if (option.autoResize) {
|
||||
this.enableAutoResize(option.container);
|
||||
}
|
||||
|
||||
else {
|
||||
this.resize(option.width, option.height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the canvas size.
|
||||
* @param width - canvas width.
|
||||
* @param height - canvas height.
|
||||
*/
|
||||
public resize(width?: number, height?: number) {
|
||||
|
||||
let hasResized = false;
|
||||
|
||||
if (width !== void 0) {
|
||||
this.canvas.width = width;
|
||||
hasResized = true;
|
||||
}
|
||||
|
||||
if (height !== void 0) {
|
||||
this.canvas.height = height;
|
||||
hasResized = true;
|
||||
}
|
||||
|
||||
if (hasResized) {
|
||||
this.emit("resize");
|
||||
}
|
||||
}
|
||||
|
||||
private resizeObserver: ResizeObserver | undefined;
|
||||
|
||||
/**
|
||||
* enable auto resize.
|
||||
* @param container - Parent node of canvas.
|
||||
*/
|
||||
public enableAutoResize(container?: HTMLElement | string) {
|
||||
let targetcontainer: HTMLElement | null = null;
|
||||
|
||||
if (container instanceof HTMLElement) {
|
||||
targetcontainer = container;
|
||||
}
|
||||
|
||||
else if (typeof container === "string") {
|
||||
|
||||
targetcontainer = document.getElementById(container);
|
||||
|
||||
if (targetcontainer === null) {
|
||||
targetcontainer = document.querySelector(container);
|
||||
|
||||
if (targetcontainer === null) {
|
||||
console.warn(
|
||||
`[ray-lab Renderer] Unable to search any valid container through "${container}".`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetcontainer === null && this.canvas instanceof HTMLCanvasElement) {
|
||||
targetcontainer = this.canvas.parentElement;
|
||||
}
|
||||
|
||||
if (targetcontainer === null) {
|
||||
console.warn(
|
||||
`[ray-lab Renderer] Unable to enable auto resize. \r\n` +
|
||||
`Because a suitable container could not be found.`
|
||||
);
|
||||
}
|
||||
|
||||
else {
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.contentRect) {
|
||||
this.resize(entry.contentRect.width, entry.contentRect.height);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (this.resizeObserver) {
|
||||
this.resizeObserver.disconnect();
|
||||
}
|
||||
|
||||
this.resizeObserver = resizeObserver;
|
||||
|
||||
if (this.canvas instanceof HTMLElement) {
|
||||
this.canvas.style.width = "100%";
|
||||
this.canvas.style.height = "100%";
|
||||
this.canvas.style.boxSizing = "border-box";
|
||||
this.canvas.style.display = "block";
|
||||
}
|
||||
|
||||
resizeObserver.observe(targetcontainer);
|
||||
this.resize(targetcontainer.offsetWidth, targetcontainer.offsetHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* disable auto resize.
|
||||
*/
|
||||
public disableAutoResize() {
|
||||
if (this.resizeObserver) {
|
||||
this.resizeObserver.disconnect();
|
||||
}
|
||||
|
||||
this.resizeObserver = void 0;
|
||||
}
|
||||
}
|
||||
|
||||
export { WebGLCanvas };
|
||||
export type { WebGLCanvasOption };
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
class WebGLRenderer {
|
||||
|
||||
public constructor() {}
|
||||
}
|
||||
|
||||
export { WebGLRenderer };
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "kernel/WebGLCanvas";
|
||||
export * from "kernel/EventEmitter";
|
||||
export * from "renderer/WebGLRenderer";
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"baseUrl": "./",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"target": "ESNext",
|
||||
"declaration": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable",
|
||||
"ESNext"
|
||||
],
|
||||
"paths": {
|
||||
"kernel/*": ["./source/kernel/*"],
|
||||
"renderer/*": ["./source/renderer/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user