Initial
This commit is contained in:
178
resources/app/client/pixi/perception/vision-mode.js
Normal file
178
resources/app/client/pixi/perception/vision-mode.js
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* A special subclass of DataField used to reference an AbstractBaseShader definition.
|
||||
*/
|
||||
class ShaderField extends foundry.data.fields.DataField {
|
||||
|
||||
/** @inheritdoc */
|
||||
static get _defaults() {
|
||||
const defaults = super._defaults;
|
||||
defaults.nullable = true;
|
||||
defaults.initial = undefined;
|
||||
return defaults;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_cast(value) {
|
||||
if ( !foundry.utils.isSubclass(value, AbstractBaseShader) ) {
|
||||
throw new Error("The value provided to a ShaderField must be an AbstractBaseShader subclass.");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Vision Mode which can be selected for use by a Token.
|
||||
* The selected Vision Mode alters the appearance of various aspects of the canvas while that Token is the POV.
|
||||
*/
|
||||
class VisionMode extends foundry.abstract.DataModel {
|
||||
/**
|
||||
* Construct a Vision Mode using provided configuration parameters and callback functions.
|
||||
* @param {object} data Data which fulfills the model defined by the VisionMode schema.
|
||||
* @param {object} [options] Additional options passed to the DataModel constructor.
|
||||
*/
|
||||
constructor(data={}, options={}) {
|
||||
super(data, options);
|
||||
this.animated = options.animated ?? false;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
const shaderSchema = () => new fields.SchemaField({
|
||||
shader: new ShaderField(),
|
||||
uniforms: new fields.ObjectField()
|
||||
});
|
||||
const lightingSchema = () => new fields.SchemaField({
|
||||
visibility: new fields.NumberField({
|
||||
initial: this.LIGHTING_VISIBILITY.ENABLED,
|
||||
choices: Object.values(this.LIGHTING_VISIBILITY)
|
||||
}),
|
||||
postProcessingModes: new fields.ArrayField(new fields.StringField()),
|
||||
uniforms: new fields.ObjectField()
|
||||
});
|
||||
|
||||
// Return model schema
|
||||
return {
|
||||
id: new fields.StringField({blank: false}),
|
||||
label: new fields.StringField({blank: false}),
|
||||
tokenConfig: new fields.BooleanField({initial: true}),
|
||||
canvas: new fields.SchemaField({
|
||||
shader: new ShaderField(),
|
||||
uniforms: new fields.ObjectField()
|
||||
}),
|
||||
lighting: new fields.SchemaField({
|
||||
background: lightingSchema(),
|
||||
coloration: lightingSchema(),
|
||||
illumination: lightingSchema(),
|
||||
darkness: lightingSchema(),
|
||||
levels: new fields.ObjectField({
|
||||
validate: o => {
|
||||
const values = Object.values(CONST.LIGHTING_LEVELS);
|
||||
return Object.entries(o).every(([k, v]) => values.includes(Number(k)) && values.includes(v));
|
||||
},
|
||||
validationError: "may only contain a mapping of keys from VisionMode.LIGHTING_LEVELS"
|
||||
}),
|
||||
multipliers: new fields.ObjectField({
|
||||
validate: o => {
|
||||
const values = Object.values(CONST.LIGHTING_LEVELS);
|
||||
return Object.entries(o).every(([k, v]) => values.includes(Number(k)) && Number.isFinite(v));
|
||||
},
|
||||
validationError: "must provide a mapping of keys from VisionMode.LIGHTING_LEVELS to numeric multiplier values"
|
||||
})
|
||||
}),
|
||||
vision: new fields.SchemaField({
|
||||
background: shaderSchema(),
|
||||
coloration: shaderSchema(),
|
||||
illumination: shaderSchema(),
|
||||
darkness: new fields.SchemaField({
|
||||
adaptive: new fields.BooleanField({initial: true})
|
||||
}),
|
||||
defaults: new fields.SchemaField({
|
||||
color: new fields.ColorField({required: false, initial: undefined}),
|
||||
attenuation: new fields.AlphaField({required: false, initial: undefined}),
|
||||
brightness: new fields.NumberField({required: false, initial: undefined, nullable: false, min: -1, max: 1}),
|
||||
saturation: new fields.NumberField({required: false, initial: undefined, nullable: false, min: -1, max: 1}),
|
||||
contrast: new fields.NumberField({required: false, initial: undefined, nullable: false, min: -1, max: 1})
|
||||
}),
|
||||
preferred: new fields.BooleanField({initial: false})
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The lighting illumination levels which are supported.
|
||||
* @enum {number}
|
||||
*/
|
||||
static LIGHTING_LEVELS = CONST.LIGHTING_LEVELS;
|
||||
|
||||
/**
|
||||
* Flags for how each lighting channel should be rendered for the currently active vision modes:
|
||||
* - Disabled: this lighting layer is not rendered, the shaders does not decide.
|
||||
* - Enabled: this lighting layer is rendered normally, and the shaders can choose if they should be rendered or not.
|
||||
* - Required: the lighting layer is rendered, the shaders does not decide.
|
||||
* @enum {number}
|
||||
*/
|
||||
static LIGHTING_VISIBILITY = {
|
||||
DISABLED: 0,
|
||||
ENABLED: 1,
|
||||
REQUIRED: 2
|
||||
};
|
||||
|
||||
/**
|
||||
* A flag for whether this vision source is animated
|
||||
* @type {boolean}
|
||||
*/
|
||||
animated = false;
|
||||
|
||||
/**
|
||||
* Does this vision mode enable light sources?
|
||||
* True unless it disables lighting entirely.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get perceivesLight() {
|
||||
const {background, illumination, coloration} = this.lighting;
|
||||
return !!(background.visibility || illumination.visibility || coloration.visibility);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special activation handling that could be implemented by VisionMode subclasses
|
||||
* @param {VisionSource} source Activate this VisionMode for a specific source
|
||||
* @abstract
|
||||
*/
|
||||
_activate(source) {}
|
||||
|
||||
/**
|
||||
* Special deactivation handling that could be implemented by VisionMode subclasses
|
||||
* @param {VisionSource} source Deactivate this VisionMode for a specific source
|
||||
* @abstract
|
||||
*/
|
||||
_deactivate(source) {}
|
||||
|
||||
/**
|
||||
* Special handling which is needed when this Vision Mode is activated for a VisionSource.
|
||||
* @param {VisionSource} source Activate this VisionMode for a specific source
|
||||
*/
|
||||
activate(source) {
|
||||
if ( source._visionModeActivated ) return;
|
||||
source._visionModeActivated = true;
|
||||
this._activate(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special handling which is needed when this Vision Mode is deactivated for a VisionSource.
|
||||
* @param {VisionSource} source Deactivate this VisionMode for a specific source
|
||||
*/
|
||||
deactivate(source) {
|
||||
if ( !source._visionModeActivated ) return;
|
||||
source._visionModeActivated = false;
|
||||
this._deactivate(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* An animation function which runs every frame while this Vision Mode is active.
|
||||
* @param {number} dt The deltaTime passed by the PIXI Ticker
|
||||
*/
|
||||
animate(dt) {
|
||||
return foundry.canvas.sources.PointVisionSource.prototype.animateTime.call(this, dt);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user