new file structure

This commit is contained in:
Matei Adriel 2019-07-16 12:38:42 +03:00
parent 92937d16ce
commit a9bc28478e
16 changed files with 125 additions and 108 deletions

View file

@ -2,8 +2,10 @@ import React, { Component, createRef, Ref, RefObject } from 'react'
import FluidCanvas, { MouseEventInfo } from './FluidCanvas' import FluidCanvas, { MouseEventInfo } from './FluidCanvas'
import loop from 'mainloop.js' import loop from 'mainloop.js'
import { Gate } from '../../simulation/classes/Gate' import { Gate } from '../../simulation/classes/Gate'
import { SimulationRenderer } from '../../simulation/classes/SimulationRenderer' import { SimulationRenderer } from '../../simulationRenderer/classes/SimulationRenderer'
import { Subject } from 'rxjs' import { Subject } from 'rxjs'
import { renderSimulation } from '../../simulationRenderer/helpers/renderSimulation'
import { updateSimulation } from '../../simulationRenderer/helpers/updateSimulation'
class Canvas extends Component { class Canvas extends Component {
private canvasRef: RefObject<HTMLCanvasElement> = createRef() private canvasRef: RefObject<HTMLCanvasElement> = createRef()
@ -25,9 +27,10 @@ class Canvas extends Component {
this.renderer.simulation.push(foo, bar) this.renderer.simulation.push(foo, bar)
loop.setDraw(() => { loop.setDraw(() => {
if (this.renderingContext) if (this.renderingContext) {
this.renderer.render(this.renderingContext) renderSimulation(this.renderingContext, this.renderer)
}).setUpdate(delta => this.renderer.update(delta)) }
}).setUpdate(delta => updateSimulation(this.renderer, delta))
} }
public componentDidMount() { public componentDidMount() {

View file

@ -1 +0,0 @@
export type DeepPartial<T> = { [key in keyof T]?: DeepPartial<T[key]> }

View file

@ -1,4 +1,4 @@
import { Transform, vector2 } from './Transform' import { Transform, vector2 } from '../../simulation/classes/Transform'
import { Screen } from '../../core/classes/Screen' import { Screen } from '../../core/classes/Screen'
import { relativeTo } from '../../vector2/helpers/basic' import { relativeTo } from '../../vector2/helpers/basic'

View file

@ -1,9 +1,9 @@
import { Singleton } from '@eix-js/utils' import { Singleton } from '@eix-js/utils'
import { MouseSubject } from '../../core/types/MouseSubject' import { MouseSubject } from '../../core/types/MouseSubject'
import { clamp } from '../helpers/clamp' import { clamp } from '../../simulation/helpers/clamp'
@Singleton @Singleton
export class MouseManager { export class MouseVelocityManager {
private history: number[] = [] private history: number[] = []
private total = 0 private total = 0
private limit = 10 private limit = 10

View file

@ -1,63 +1,39 @@
import { Camera } from './Camera' import { Camera } from './Camera'
import { Simulation } from './Simulation' import { Simulation } from '../../simulation/classes/Simulation'
import { Subject } from 'rxjs' import { Subject } from 'rxjs'
import { MouseEventInfo } from '../../core/components/FluidCanvas' import { MouseEventInfo } from '../../core/components/FluidCanvas'
import { pointInSquare } from '../helpers/pointInSquare' import { pointInSquare } from '../helpers/pointInSquare'
import { vector2 } from './Transform' import { vector2 } from '../../simulation/classes/Transform'
import merge from 'deepmerge' import { MouseVelocityManager } from './MouseVelocityManager'
import { renderGate } from '../helpers/renderGate'
import { renderGateShadow } from '../helpers/renderGateShadow'
import { MouseManager } from './MouseManager'
import { Screen } from '../../core/classes/Screen' import { Screen } from '../../core/classes/Screen'
import { relativeTo, add, invert } from '../../vector2/helpers/basic' import { relativeTo, add, invert } from '../../vector2/helpers/basic'
import { SimulationRendererOptions } from '../types/SimulationRendererOptions'
export interface SimulationRendererOptions { import { defaultSimulationRendererOptions } from '../constants'
shadows: { import merge from 'deepmerge'
enabled: boolean
color: string
lightHeight: number
gateHeight: number
}
dnd: {
rotation: number
}
}
export const defaultSimulationRendererOptions: SimulationRendererOptions = {
shadows: {
enabled: true,
color: 'rgba(0,0,0,0.3)',
gateHeight: 10,
lightHeight: 100
},
dnd: {
rotation: Math.PI / 12 // 7.5 degrees
}
}
export class SimulationRenderer { export class SimulationRenderer {
public camera = new Camera()
public mouseDownOutput = new Subject<MouseEventInfo>() public mouseDownOutput = new Subject<MouseEventInfo>()
public mouseUpOutput = new Subject<MouseEventInfo>() public mouseUpOutput = new Subject<MouseEventInfo>()
public mouseMoveOutput = new Subject<MouseEventInfo>() public mouseMoveOutput = new Subject<MouseEventInfo>()
public selectedGate: number | null = null
public lastMousePosition: vector2 = [0, 0]
public movedSelection = false
// first bit = dragging // first bit = dragging
// second bit = moving around // second bit = moving around
private mouseState = 0b00 private mouseState = 0b00
private options: SimulationRendererOptions private selectedGate: number | null = null
private mouseManager = new MouseManager(this.mouseMoveOutput) private gateSelectionOffset: vector2 = [0, 0]
private screen = new Screen()
public movedSelection = false
public options: SimulationRendererOptions
public mouseManager = new MouseVelocityManager(this.mouseMoveOutput)
public screen = new Screen()
public camera = new Camera()
public constructor( public constructor(
options: Partial<SimulationRendererOptions> = {}, options: Partial<SimulationRendererOptions> = {},
public simulation = new Simulation() public simulation = new Simulation()
) { ) {
this.options = merge(options, defaultSimulationRendererOptions) this.options = merge(defaultSimulationRendererOptions, options)
this.init() this.init()
} }
@ -80,7 +56,7 @@ export class SimulationRenderer {
this.movedSelection = false this.movedSelection = false
this.selectedGate = id this.selectedGate = id
this.lastMousePosition = worldPosition.map( this.gateSelectionOffset = worldPosition.map(
(position, index) => (position, index) =>
position - transform.position[index] position - transform.position[index]
) as vector2 ) as vector2
@ -95,7 +71,7 @@ export class SimulationRenderer {
} }
} }
this.lastMousePosition = worldPosition this.gateSelectionOffset = worldPosition
this.mouseState |= 2 this.mouseState |= 2
}) })
@ -124,8 +100,8 @@ export class SimulationRenderer {
const transform = gate.data.transform const transform = gate.data.transform
transform.x = worldPosition[0] - this.lastMousePosition[0] transform.x = worldPosition[0] - this.gateSelectionOffset[0]
transform.y = worldPosition[1] - this.lastMousePosition[1] transform.y = worldPosition[1] - this.gateSelectionOffset[1]
if (!this.movedSelection) { if (!this.movedSelection) {
this.movedSelection = true this.movedSelection = true
@ -134,7 +110,7 @@ export class SimulationRenderer {
if ((this.mouseState >> 1) & 1) { if ((this.mouseState >> 1) & 1) {
const offset = invert( const offset = invert(
relativeTo(this.lastMousePosition, worldPosition) relativeTo(this.gateSelectionOffset, worldPosition)
) )
this.camera.transform.position = add( this.camera.transform.position = add(
@ -142,64 +118,17 @@ export class SimulationRenderer {
invert(offset) invert(offset)
) )
this.lastMousePosition = this.camera.toWordPostition( this.gateSelectionOffset = this.camera.toWordPostition(
event.position event.position
) )
} }
}) })
} }
public render(ctx: CanvasRenderingContext2D) {
this.clear(ctx)
ctx.translate(...this.camera.transform.position)
const center = relativeTo(
this.camera.transform.position,
this.screen.center
)
// render gates
for (const gate of this.simulation.gates) {
if (this.options.shadows.enabled) {
renderGateShadow(
ctx,
this.options.shadows.color,
gate,
this.options.shadows.gateHeight,
[center[0], center[1], this.options.shadows.lightHeight]
)
}
renderGate(ctx, gate)
}
ctx.translate(...invert(this.camera.transform.position))
}
public clear(ctx: CanvasRenderingContext2D) {
ctx.clearRect(0, 0, ...this.camera.transform.scale)
}
public getGateById(id: number) { public getGateById(id: number) {
return this.simulation.gates.get(id) return this.simulation.gates.get(id)
} }
public update(delta: number) {
const selected = this.getSelected()
if (selected && this.movedSelection) {
this.mouseManager.update()
selected.transform.rotation =
this.mouseManager.getDirection() * this.options.dnd.rotation
} else {
if (selected) {
selected.transform.rotation = 0
}
this.mouseManager.update()
}
}
public getSelected() { public getSelected() {
if (this.selectedGate === null) return null if (this.selectedGate === null) return null

View file

@ -0,0 +1,13 @@
import { SimulationRendererOptions } from './types/SimulationRendererOptions'
export const defaultSimulationRendererOptions: SimulationRendererOptions = {
shadows: {
enabled: true,
color: 'rgba(0,0,0,0.3)',
gateHeight: 10,
lightHeight: 100
},
dnd: {
rotation: Math.PI / 12 // 7.5 degrees
}
}

View file

@ -0,0 +1,8 @@
import { SimulationRenderer } from '../classes/SimulationRenderer'
export const clearCanvas = (
ctx: CanvasRenderingContext2D,
renderer: SimulationRenderer
) => {
ctx.clearRect(0, 0, ...renderer.camera.transform.scale)
}

View file

@ -1,4 +1,4 @@
import { vector2 } from '../classes/Transform' import { vector2 } from '../../simulation/classes/Transform'
export const drawPolygon = ( export const drawPolygon = (
ctx: CanvasRenderingContext2D, ctx: CanvasRenderingContext2D,

View file

@ -1,4 +1,4 @@
import { Transform } from '../classes/Transform' import { Transform } from '../../simulation/classes/Transform'
export const drawRotatedSquare = ( export const drawRotatedSquare = (
ctx: CanvasRenderingContext2D, ctx: CanvasRenderingContext2D,

View file

@ -1,5 +1,4 @@
import { vector2, Transform } from '../classes/Transform' import { vector2, Transform } from '../../simulation/classes/Transform'
import { LruCacheNode } from '@eix-js/utils'
export const pointInSquare = (point: vector2, square: Transform) => { export const pointInSquare = (point: vector2, square: Transform) => {
return ( return (

View file

@ -1,4 +1,4 @@
import { vector3, vector2 } from '../classes/Transform' import { vector3, vector2 } from '../../simulation/classes/Transform'
export const projectPointOnPlane = (point: vector3, light: vector3) => export const projectPointOnPlane = (point: vector3, light: vector3) =>
point.slice(0, 2).map((position, index) => { point.slice(0, 2).map((position, index) => {

View file

@ -1,4 +1,4 @@
import { Gate } from '../classes/Gate' import { Gate } from '../../simulation/classes/Gate'
import { drawRotatedSquare } from './drawRotatedSquare' import { drawRotatedSquare } from './drawRotatedSquare'
export const renderGate = (ctx: CanvasRenderingContext2D, gate: Gate) => { export const renderGate = (ctx: CanvasRenderingContext2D, gate: Gate) => {

View file

@ -1,7 +1,7 @@
import { Gate } from '../classes/Gate' import { Gate } from '../../simulation/classes/Gate'
import { projectPointOnPlane } from './projectPoint' import { projectPointOnPlane } from './projectPoint'
import { drawPolygon } from './drawPolygon' import { drawPolygon } from './drawPolygon'
import { vector3 } from '../classes/Transform' import { vector3 } from '../../simulation/classes/Transform'
export const renderGateShadow = ( export const renderGateShadow = (
ctx: CanvasRenderingContext2D, ctx: CanvasRenderingContext2D,

View file

@ -0,0 +1,36 @@
import { SimulationRenderer } from '../classes/SimulationRenderer'
import { relativeTo, invert } from '../../vector2/helpers/basic'
import { renderGateShadow } from './renderGateShadow'
import { renderGate } from './renderGate'
import { clearCanvas } from './clearCanvas'
export const renderSimulation = (
ctx: CanvasRenderingContext2D,
renderer: SimulationRenderer
) => {
clearCanvas(ctx, renderer)
ctx.translate(...renderer.camera.transform.position)
const center = relativeTo(
renderer.camera.transform.position,
renderer.screen.center
)
// render gates
for (const gate of renderer.simulation.gates) {
if (renderer.options.shadows.enabled) {
renderGateShadow(
ctx,
renderer.options.shadows.color,
gate,
renderer.options.shadows.gateHeight,
[center[0], center[1], renderer.options.shadows.lightHeight]
)
}
renderGate(ctx, gate)
}
ctx.translate(...invert(renderer.camera.transform.position))
}

View file

@ -0,0 +1,19 @@
import { SimulationRenderer } from '../classes/SimulationRenderer'
export const updateSimulation = (
renderer: SimulationRenderer,
delta: number
) => {
const selected = renderer.getSelected()
if (selected && renderer.movedSelection) {
renderer.mouseManager.update()
selected.transform.rotation =
renderer.mouseManager.getDirection() * renderer.options.dnd.rotation
} else {
if (selected) {
selected.transform.rotation = 0
}
renderer.mouseManager.update()
}
}

View file

@ -0,0 +1,11 @@
export interface SimulationRendererOptions {
shadows: {
enabled: boolean
color: string
lightHeight: number
gateHeight: number
}
dnd: {
rotation: number
}
}