UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

206 lines (190 loc) 6.07 kB
import {RGBAFormat, FloatType} from 'three'; import {DataTexture} from 'three'; import {CubicInterpolant} from 'three'; import {TypedParam} from './_Base'; import {RampValue, RampPoint, RampValueJson, RampInterpolation} from './ramp/RampValue'; import {ParamType} from '../poly/ParamType'; import {ParamInitValuesTypeMap} from './types/ParamInitValuesTypeMap'; import {ParamValuesTypeMap} from './types/ParamValuesTypeMap'; import {ParamEvent} from '../poly/ParamEvent'; const STRIDE = 4; const TEXTURE_WIDTH = 1024; const TEXTURE_HEIGHT = 1; const TEXTURE_SIZE = TEXTURE_WIDTH * TEXTURE_HEIGHT; const TEXTURE_BYTES_MULT = 1; export class RampParam extends TypedParam<ParamType.RAMP> { static override type() { return ParamType.RAMP; } private _rampInterpolant: CubicInterpolant | undefined; private _textureData = new Float32Array(STRIDE * TEXTURE_SIZE); private _rampTexture = new DataTexture(this._textureData, TEXTURE_WIDTH, TEXTURE_HEIGHT, RGBAFormat, FloatType); static DEFAULT_VALUE = new RampValue(RampInterpolation.CUBIC, [new RampPoint(0, 0), new RampPoint(1, 1)]); static DEFAULT_VALUE_JSON: RampValueJson = RampParam.DEFAULT_VALUE.toJSON(); override defaultValueSerialized() { if (this._default_value instanceof RampValue) { return this._default_value.toJSON(); } else { return this._default_value; } } protected override _cloneRawInput(raw_input: ParamInitValuesTypeMap[ParamType.RAMP]) { if (raw_input instanceof RampValue) { return raw_input.clone(); } else { return RampValue.fromJSON(raw_input).toJSON(); } } override rawInputSerialized() { if (this._raw_input instanceof RampValue) { return this._raw_input.toJSON(); } else { return RampValue.fromJSON(this._raw_input).toJSON(); } } override valueSerialized() { return this.value.toJSON(); } protected override _copyValue(param: RampParam) { this.set(param.valueSerialized()); } static override areRawInputEqual( raw_input1: ParamInitValuesTypeMap[ParamType.RAMP], raw_input2: ParamInitValuesTypeMap[ParamType.RAMP] ) { if (raw_input1 instanceof RampValue) { if (raw_input2 instanceof RampValue) { return raw_input1.isEqual(raw_input2); } else { return raw_input1.isEqualJSON(raw_input2); } } else { if (raw_input2 instanceof RampValue) { return raw_input2.isEqualJSON(raw_input1); } else { return RampValue.are_json_equal(raw_input1, raw_input2); } } } static override areValuesEqual(val1: ParamValuesTypeMap[ParamType.RAMP], val2: ParamValuesTypeMap[ParamType.RAMP]) { return val1.isEqual(val2); } // initialize_param() { // this.addPostDirtyHook( // '_reset_ramp_interpolant_and_texture', // this.reset_ramp_interpolant.bind(this) // ); // } // accepts_visitor(visitor: RampParamVisitor) { // return visitor.visit_ramp_param(this); // } override isDefault(): boolean { if (this._default_value instanceof RampValue) { return this.value.isEqual(this._default_value); } else { return this.value.isEqualJSON(this._default_value); } } protected override processRawInput() { if (this._raw_input instanceof RampValue) { if (!this._value) { this._value = this._raw_input; } else { this._value.copy(this._raw_input); } } else { if (!this._value) { this._value = RampValue.fromJSON(this._raw_input); } else { this._value.fromJSON(this._raw_input); } } this._resetRampInterpolant(); this._updateRampTexture(); this.options.executeCallback(); this.emitController.emit(ParamEvent.VALUE_UPDATED); this.setSuccessorsDirty(this); } // convert_value(v) { // let is_json = false // if (isString(v)) { // v = JSON.parse(v) // is_json = true // } // if (!is_json) { // if (v.interpolation && v.points) { // if (isArray(v.points)) { // is_json = true // } // } // } // if (is_json) { // v = RampValue.from_json(v) // } // return v // } // convert_default_value(v) { // return this.convert_value(v) // } override hasExpression() { return false; } private _resetRampInterpolant() { this._rampInterpolant = undefined; // this._ramp_texture = undefined; } rampTexture() { return this._rampTexture; } private _updateRampTexture() { this._updateRampTextureData(); this.rampTexture().needsUpdate = true; } private _updateRampTextureData() { let stride = 0; let position = 0; let value = 0; // we set the bounds at [-1:2] // so that we can have the ramp go 1 unit below and above the range [0:1] // so -1 becomes R=0, G=0, B=0 // so -0.5 becomes R=0.5, G=0, B=0 // so 0 becomes R=1, G=0, B=0 // so 0.5 becomes R=1, G=0.5, B=0 // so 1 becomes R=1, G=1, B=0 // so 1.5 becomes R=1, G=1, B=0.5 // so 2 becomes R=1, G=1, B=1 for (var i = 0; i < TEXTURE_SIZE; i++) { stride = i * STRIDE; position = i / TEXTURE_WIDTH; value = this.valueAtPosition(position); this._textureData[stride + 0] = value * TEXTURE_BYTES_MULT; this._textureData[stride + 1] = 0; this._textureData[stride + 2] = 0; // if (value <= 0) { // // if I set 256, a value of 1 will become 0 // this._textureData[stride + 0] = (clamp(value, -1, 0) + 1) * TEXTURE_BYTES_MULT; // this._textureData[stride + 1] = 0; // this._textureData[stride + 2] = 0; // } else { // if (value <= 1) { // this._textureData[stride + 0] = TEXTURE_BYTES_MULT; // this._textureData[stride + 1] = clamp(value, 0, 1) * TEXTURE_BYTES_MULT; // this._textureData[stride + 2] = 0; // } else { // this._textureData[stride + 0] = TEXTURE_BYTES_MULT; // this._textureData[stride + 1] = TEXTURE_BYTES_MULT; // this._textureData[stride + 2] = (clamp(value, 1, 2) - 1) * TEXTURE_BYTES_MULT; // } // } } } interpolant() { return (this._rampInterpolant = this._rampInterpolant || this._createInterpolant()); } private _createInterpolant() { return this.value.createInterpolant(); } valueAtPosition(position: number): number { return (<unknown>this.interpolant().evaluate(position)[0]) as number; } }