diff options
| -rw-r--r-- | index.html | 17 | ||||
| -rw-r--r-- | src/RaytraceDispatcher.ts | 52 | ||||
| -rw-r--r-- | src/index.ts | 25 | ||||
| -rw-r--r-- | src/models/RaytraceContext.ts | 1 |
4 files changed, 73 insertions, 22 deletions
@@ -83,6 +83,20 @@ </div> <div class="form-group"> <label class="form-group"> + <label id="chunk-size-label" class="form-label label-sm" for="res">Chunk size</label> + <select id="chunk-size" class="form-select select-sm"> + <option value="0" selected>Auto</option> + <option value="8">8x8</option> + <option value="16">16x16</option> + <option value="32">32x32</option> + <option value="64">64x64</option> + <option value="128">128x128</option> + <option value="256">256x256</option> + </select> + </label> + </div> + <div class="form-group"> + <label class="form-group"> <label id="chunk-allocation-mode-label" class="form-label label-sm" for="res">Chunk allocation mode</label> <select id="chunk-allocation-mode" class="form-select select-sm"> <option value="SEQUENTIAL" selected>Sequential</option> @@ -106,7 +120,8 @@ </select> </div> <button id="render" class="btn btn-primary">Render</button> - <button id="view-full" class="btn btn-link">View full image</button> + <button id="stop-render" class="btn btn-link d-hide">Stop render</button> + <button id="view-full" class="btn btn-link d-hide">View full image</button> <pre class="code"><code id="console"></code></pre> </div> </div> diff --git a/src/RaytraceDispatcher.ts b/src/RaytraceDispatcher.ts index b8b5e6a..eeae5ce 100644 --- a/src/RaytraceDispatcher.ts +++ b/src/RaytraceDispatcher.ts @@ -12,7 +12,6 @@ export class RaytraceDispatcher { private readonly chunkQueue: FrameChunk[]; private readonly raytraceWorkers: Worker[]; private completedWorkers = 0; - private chunkBorderWidth = 1; constructor( readonly framebuffer: Framebuffer, @@ -27,25 +26,14 @@ export class RaytraceDispatcher { } requestRender() { - let chunkHeight, chunkWidth; - - if (this.context.height <= 720) { - chunkHeight = 64; - chunkWidth = 64; - this.chunkBorderWidth = 2; - } else { - chunkHeight = 128; - chunkWidth = 128; - this.chunkBorderWidth = 5; - } - // Process scene into chunks - for (let y = 0; y < this.context.height; y+= chunkHeight) { - for (let x = 0 ; x < this.context.width; x+= chunkWidth) { - this.chunkQueue.push(new FrameChunk(x, y, chunkWidth, chunkHeight)); + const chunkSize = this.getChunkSize(); + for (let y = 0; y < this.context.height; y+= chunkSize) { + for (let x = 0 ; x < this.context.width; x+= chunkSize) { + this.chunkQueue.push(new FrameChunk(x, y, chunkSize, chunkSize)); } } - this.logger.log(`Scene split into ${this.chunkQueue.length} chunks of ${chunkWidth}x${chunkHeight}`); + this.logger.log(`Scene split into ${this.chunkQueue.length} chunks of ${chunkSize}x${chunkSize}`); // Spawn worker threads for (let n = 0; n < this.context.options.numThreads; n++) { @@ -61,9 +49,15 @@ export class RaytraceDispatcher { } } + public stopRender() { + for (let worker of this.raytraceWorkers) { + worker.terminate(); + } + } + private raytraceNextChunk(worker: Worker) { const chunk = this.getNextChunk(); - this.drawChunkBorder(chunk, this.chunkBorderWidth); + this.drawChunkBorder(chunk); worker.postMessage({ type: 'raytraceStart', chunk: chunk, @@ -145,10 +139,17 @@ export class RaytraceDispatcher { this.framebuffer.flush(); } - private drawChunkBorder(chunk: FrameChunk, borderWidth: number) { + private drawChunkBorder(chunk: FrameChunk) { const width = chunk.width; const height = chunk.height; + let borderWidth = 0; + if (this.context.height <= 720) { + borderWidth = 2; + } else { + borderWidth = 5; + } + const borderColour = new Colour(220, 128, 128); const unrenderedAreaColour = new Colour(160, 160, 160); @@ -166,4 +167,17 @@ export class RaytraceDispatcher { this.framebuffer.flush(); } + + private getChunkSize(): number { + if (this.context.options.chunkSize === 0) { + // Auto sizing based on scene height + if (this.context.height <= 720) { + return 64; + } else { + return 128; + } + } else { + return this.context.options.chunkSize; + } + } } diff --git a/src/index.ts b/src/index.ts index f58cc5b..3dab80f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,12 +8,21 @@ import {ChunkAllocationMode, RaytraceContext, RaytracerOptions} from './models/R import {Vector} from './models/Vector'; import {Logger} from './Logger'; +let dispatcher: RaytraceDispatcher; + function render() { getRenderButton().classList.add('loading'); - const dispatcher = initDispatcher(parseOptions()); + getStopRenderButton().classList.remove('d-hide'); + getViewFullButton().classList.add('d-hide'); + dispatcher = initDispatcher(parseOptions()); dispatcher.requestRender(); } +function stopRender() { + dispatcher.stopRender(); + onRenderComplete(); +} + function initDispatcher(options: RaytracerOptions): RaytraceDispatcher { const {width, height} = parseResolution(); @@ -110,6 +119,7 @@ function parseOptions(): RaytracerOptions { maxRecurseDepth: 5, maxDrawDistance: 1000, directMemoryTransfer: getInputElement('direct-transfer').checked, + chunkSize: parseInt(getInputElement('chunk-size').value, 10), chunkAllocationMode: getChunkAllocationMode() }; } @@ -148,8 +158,9 @@ function getChunkAllocationMode(): ChunkAllocationMode { function registerEventListeners() { getRenderButton().addEventListener('click', render); + getStopRenderButton().addEventListener('click', stopRender); - document.getElementById('view-full')!.addEventListener('click', () => { + getViewFullButton().addEventListener('click', () => { const canvas = document.getElementById( 'render-output' ) as HTMLCanvasElement; @@ -177,12 +188,22 @@ function getDesiredThreadCount(): number { function onRenderComplete() { getRenderButton().classList.remove('loading'); + getStopRenderButton().classList.add('d-hide'); + getViewFullButton().classList.remove('d-hide'); } function getRenderButton(): HTMLElement { return document.getElementById('render')!; } +function getStopRenderButton(): HTMLElement { + return document.getElementById('stop-render')!; +} + +function getViewFullButton(): HTMLElement { + return document.getElementById('view-full')!; +} + function getInputElement(elementId: string) { return document.getElementById(elementId) as HTMLInputElement; } diff --git a/src/models/RaytraceContext.ts b/src/models/RaytraceContext.ts index d028c1a..1f22d32 100644 --- a/src/models/RaytraceContext.ts +++ b/src/models/RaytraceContext.ts @@ -39,6 +39,7 @@ export interface RaytracerOptions { maxRecurseDepth: number; maxDrawDistance: number; directMemoryTransfer: boolean; + chunkSize: number; chunkAllocationMode: ChunkAllocationMode; } |