polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
200 lines (182 loc) • 5.8 kB
text/typescript
import {RGBFormat} from 'three/src/constants';
import {DataTexture} from 'three/src/textures/DataTexture';
import {CubicInterpolant} from 'three/src/math/interpolants/CubicInterpolant';
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';
import {ArrayUtils} from '../../core/ArrayUtils';
// interface RampParamVisitor extends TypedParamVisitor {
// visit_ramp_param: (param: RampParam) => any;
// }
const TEXTURE_WIDTH = 1024;
const TEXTURE_HEIGHT = 1;
const TEXTURE_SIZE = TEXTURE_WIDTH * TEXTURE_HEIGHT;
export class RampParam extends TypedParam<ParamType.RAMP> {
static type() {
return ParamType.RAMP;
}
private _ramp_interpolant: CubicInterpolant | undefined;
private _texture_data = new Uint8Array(3 * TEXTURE_SIZE);
private _ramp_texture = new DataTexture(this._texture_data, TEXTURE_WIDTH, TEXTURE_HEIGHT, RGBFormat);
static DEFAULT_VALUE = new RampValue(RampInterpolation.LINEAR, [new RampPoint(0, 0), new RampPoint(1, 1)]);
static DEFAULT_VALUE_JSON: RampValueJson = RampParam.DEFAULT_VALUE.toJSON();
get default_value_serialized() {
if (this.default_value instanceof RampValue) {
return this.default_value.toJSON();
} else {
return this.default_value;
}
}
protected _clone_raw_input(raw_input: ParamInitValuesTypeMap[ParamType.RAMP]) {
if (raw_input instanceof RampValue) {
return raw_input.clone();
} else {
return RampValue.from_json(raw_input).toJSON();
}
}
get raw_input_serialized() {
if (this._raw_input instanceof RampValue) {
return this._raw_input.toJSON();
} else {
return RampValue.from_json(this._raw_input).toJSON();
}
}
get value_serialized() {
return this.value.toJSON();
}
protected _copy_value(param: RampParam) {
this.set(param.value_serialized);
}
static are_raw_input_equal(
raw_input1: ParamInitValuesTypeMap[ParamType.RAMP],
raw_input2: ParamInitValuesTypeMap[ParamType.RAMP]
) {
if (raw_input1 instanceof RampValue) {
if (raw_input2 instanceof RampValue) {
return raw_input1.is_equal(raw_input2);
} else {
return raw_input1.is_equal_json(raw_input2);
}
} else {
if (raw_input2 instanceof RampValue) {
return raw_input2.is_equal_json(raw_input1);
} else {
return RampValue.are_json_equal(raw_input1, raw_input2);
}
}
}
static are_values_equal(val1: ParamValuesTypeMap[ParamType.RAMP], val2: ParamValuesTypeMap[ParamType.RAMP]) {
return val1.is_equal(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);
// }
get is_default(): boolean {
if (this.default_value instanceof RampValue) {
return this.value.is_equal(this.default_value);
} else {
return this.value.is_equal_json(this.default_value);
}
}
protected process_raw_input() {
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.from_json(this._raw_input);
} else {
this._value.from_json(this._raw_input);
}
}
this._reset_ramp_interpolant();
this._update_ramp_texture();
this.options.execute_callback();
this.emitController.emit(ParamEvent.VALUE_UPDATED);
this.setSuccessorsDirty(this);
}
// convert_value(v) {
// let is_json = false
// if (CoreType.isString(v)) {
// v = JSON.parse(v)
// is_json = true
// }
// if (!is_json) {
// if (v.interpolation && v.points) {
// if (CoreType.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)
// }
has_expression() {
return false;
}
private _reset_ramp_interpolant() {
this._ramp_interpolant = undefined;
// this._ramp_texture = undefined;
}
ramp_texture() {
return this._ramp_texture;
}
private _update_ramp_texture() {
this._update_ramp_texture_data();
this.ramp_texture().needsUpdate = true;
}
private _update_ramp_texture_data() {
let stride = 0;
let position = 0;
let value = 0;
for (var i = 0; i < TEXTURE_SIZE; i++) {
stride = i * 3;
position = i / TEXTURE_WIDTH;
value = this.value_at_position(position);
this._texture_data[stride] = value * 255; // if I set 256, a value of 1 will become 0
// data[ stride+1 ] = 1
// data[ stride+2 ] = 2
}
}
static create_interpolant(positions: Float32Array, values: Float32Array) {
const values_count = 1;
const interpolated_values = new Float32Array(values_count);
return new CubicInterpolant(positions, values, values_count, interpolated_values);
}
interpolant() {
return (this._ramp_interpolant = this._ramp_interpolant || this._create_interpolant());
}
_create_interpolant() {
const points = this.value.points;
const sorted_points = ArrayUtils.sortBy(points, (point) => point.position);
const positions = new Float32Array(sorted_points.length);
const values = new Float32Array(sorted_points.length);
let i = 0;
for (let sorted_point of sorted_points) {
positions[i] = sorted_point.position;
values[i] = sorted_point.value;
i++;
}
return RampParam.create_interpolant(positions, values);
}
value_at_position(position: number): number {
return (<unknown>this.interpolant().evaluate(position)[0]) as number;
}
}