aboutsummaryrefslogtreecommitdiff
path: root/src/RaytraceDispatcher.ts
blob: 866d2d10d2c36c9bbc03b57c5258fa726d421410 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import {Colour} from './Colour';
import {Framebuffer} from './Framebuffer';
import {RaytraceContext} from './RaytraceContext';
import {instanceToPlain} from 'class-transformer';
import 'reflect-metadata';

export class RaytraceDispatcher {
  private renderStartMs: number;
  private responsesReceived = 0;
  constructor(
    readonly framebuffer: Framebuffer,
    readonly context: RaytraceContext
  ) {
    this.renderStartMs = new Date().getTime();
  }

  requestRender() {
    // Assumes height and threads are always even
    const rowBatchSize = this.context.height / this.context.options.numThreads;

    for (let y = 0; y < this.context.height; y += rowBatchSize) {
      const rowStartIndex = y;
      const rowEndIndex = y + rowBatchSize - 1;
      this.dispatchRaytraceWorker(rowStartIndex, rowEndIndex, this.context);
    }
  }

  private dispatchRaytraceWorker(
    rowStartIndex: number,
    rowEndIndex: number,
    context: RaytraceContext
  ) {
    console.log(
      `Dispatching worker for lines ${rowStartIndex} to ${rowEndIndex}`
    );

    const raytracer = new Worker(new URL('./Raytracer.ts', import.meta.url));

    raytracer.postMessage({
      type: 'raytraceStart',
      rowStartIndex: rowStartIndex,
      rowEndIndex: rowEndIndex,
      context: JSON.stringify(instanceToPlain(context)),
    });

    raytracer.onmessage = ({data}) => {
      if (data.type === 'raytraceResultRow') {
        this.processResponse(data.rowIndex, data.resultBuffer);
      }
      if (data.type === 'raytraceComplete') {
        this.handleWorkerComplete();
      }
    };
  }

  private handleWorkerComplete() {
    if (++this.responsesReceived === this.context.options.numThreads) {
      console.log(
        `Render completed in ${new Date().getTime() - this.renderStartMs}ms`
      );
    }
  }

  private processResponse(rowIndex: number, rowData: Colour[]) {
    for (let x = 0; x < this.framebuffer.width; x++) {
      this.framebuffer.writePixelAt(x, rowIndex, rowData[x]);
    }
    this.framebuffer.flush();
  }
}