Skip to content

Commit

Permalink
Merge branch 'release/0.5.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
caewok committed Jun 18, 2023
2 parents 97d682e + c7eada1 commit e56587e
Show file tree
Hide file tree
Showing 9 changed files with 422 additions and 161 deletions.
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 0.5.2
GM can define a minimum and maximum elevation color in settings. The coloration in the elevation layer will be interpolated between the two colors, based on the scene minimum and the current maximum elevation in the scene.

# 0.5.1
Elevation can now handle up to 65,536 distinct values. This is accomplished by utilizing both red and green channels of the elevation image.

Expand Down
7 changes: 7 additions & 0 deletions languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@
"elevatedvision.settings.add-fly-button.name": "Add Token Fly control",
"elevatedvision.settings.add-fly-button.hint": "Add a control to the token toolbar that can be enabled or disabled to tell Elevated Vision when a token should be considered capable of flight. When the control is enabled, automatic token elevation will keep tokens above the ground when moved off a terrain or tile cliff greater than the token height.",

"elevatedvision.settings.color-min.name": "Elevation Minimum Color",
"elevatedvision.settings.color-min.hint": "Set the color used to display the minimum elevation (above the scene minimum) on the elevation layer.",
"elevatedvision.settings.color-max.name": "Elevation Maximum Color",
"elevatedvision.settings.color-max.hint": "Set the color used to display the maximum elevation on the elevation layer. Colors between min and max will be interpolated.",
"elevatedvision.settings.color-min.string_hint": "Set the color used to display the minimum elevation (above the scene minimum) on the elevation layer. Install the Color Picker module to get a color picker here.",
"elevatedvision.settings.color-max.string_hint": "Set the color used to display the maximum elevation on the elevation layer. Colors between min and max will be interpolated. Install the Color Picker module to get a color picker here.",

"elevatedvision.controls.fill-by-grid.name": "Fill by grid",
"elevatedvision.controls.fill-by-los.name": "Fill by line-of-sight",
"elevatedvision.controls.fill-space.name": "Fill space enclosed by walls",
Expand Down
147 changes: 68 additions & 79 deletions scripts/ElevationLayer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* globals
AbstractBaseFilter,
canvas,
CONFIG,
Dialog,
Expand Down Expand Up @@ -36,7 +35,7 @@ import { CoordinateElevationCalculator } from "./CoordinateElevationCalculator.j
import { TokenPointElevationCalculator } from "./TokenPointElevationCalculator.js";
import { TokenAverageElevationCalculator } from "./TokenAverageElevationCalculator.js";
import { TravelElevationCalculator } from "./TravelElevationCalculator.js";
import { ElevationLayerShader } from "./ElevationLayerShader.js";
import { EVQuadMesh, ElevationLayerShader } from "./ElevationLayerShader.js";
import { ElevationTextureManager } from "./ElevationTextureManager.js";


Expand Down Expand Up @@ -71,7 +70,9 @@ On canvas:
*/

// TODO: What should replace this now that FullCanvasContainer is deprecated in v11?
class FullCanvasContainer extends FullCanvasObjectMixin(PIXI.Container) {}
class FullCanvasContainer extends FullCanvasObjectMixin(PIXI.Container) {

}

export function _onMouseMoveCanvas(wrapper, event) {
wrapper(event);
Expand Down Expand Up @@ -303,6 +304,38 @@ export class ElevationLayer extends InteractionLayer {
return this._scaleNormalizedElevation(this.#maximumNormalizedElevation);
}

/**
* Current maximum elevation value for the scene.
* @type {number}
*/
#elevationCurrentMax;

get elevationCurrentMax() {
return this.#elevationCurrentMax ?? (this.#elevationCurrentMax = this._calculateElevationCurrentMax());
}

/**
* Calculate the current maximum elevation value in the scene.
* @returns {number}
*/
_calculateElevationCurrentMax() {
// Reduce is slow, so do this the hard way.
let max = Number.NEGATIVE_INFINITY;
const pix = this.elevationPixelCache.pixels;
const ln = pix.length;
for ( let i = 0; i < ln; i += 1 ) max = Math.max(max, pix[i]);
return this._scaleNormalizedElevation(max);
}

/**
* Update the current elevation maximum to a specific value.
* @param {number} e Elevation value
*/
_updateElevationCurrentMax(e) {
this.#elevationCurrentMax = Math.max(this.#elevationCurrentMax, e);
this._elevationColorsMesh.shader.updateMaxCurrentElevation();
}

/* ------------------------ */

/**
Expand Down Expand Up @@ -543,10 +576,13 @@ export class ElevationLayer extends InteractionLayer {
// Add the sprite that holds the default background elevation settings
this._graphicsContainer.addChild(this._backgroundElevation);

// Add the elevation color mesh
this._elevationColorsMesh = new ElevationLayerShader();

await this.loadSceneElevationData();

// Add the elevation color mesh
const shader = ElevationLayerShader.create();
this._elevationColorsMesh = new EVQuadMesh(canvas.dimensions.sceneRect, shader);

this.renderElevation();

this._initialized = true;
Expand Down Expand Up @@ -799,6 +835,9 @@ export class ElevationLayer extends InteractionLayer {
pixels[i + 1] = newPixelChannels.g;
}

// Reset the elevation maximum, b/c we don't know this value anymore.
this.#elevationCurrentMax = undefined;

// This makes vertical lines: newTex = PIXI.Texture.fromBuffer(pixels, width, height)
const br = new PIXI.BufferResource(pixels, {width, height});
const bt = new PIXI.BaseTexture(br);
Expand Down Expand Up @@ -845,6 +884,10 @@ export class ElevationLayer extends InteractionLayer {
}
}

// Update the elevation maximum.
if ( this.#elevationCurrentMax === from ) this.#elevationCurrentMax = undefined;
else this._updateElevationCurrentMax(to);

// Error Makes vertical lines:
// newTex = PIXI.Texture.fromBuffer(pixels, width, height)
const br = new PIXI.BufferResource(pixels, {width, height});
Expand All @@ -853,6 +896,7 @@ export class ElevationLayer extends InteractionLayer {

// Save to the background texture (used by the background sprite, like with saved images)
this.#replaceBackgroundElevationTexture(newTex);

}

/**
Expand All @@ -872,6 +916,7 @@ export class ElevationLayer extends InteractionLayer {
const shape = useHex ? this._hexGridShape(p) : this._squareGridShape(p);
const graphics = this._graphicsContainer.addChild(new PIXI.Graphics());
const color = this.elevationColor(elevation);
this._updateElevationCurrentMax(elevation);

// Set width = 0 to avoid drawing a border line. The border line will use antialiasing
// and that causes a lighter-color border to appear outside the shape.
Expand Down Expand Up @@ -930,8 +975,8 @@ export class ElevationLayer extends InteractionLayer {
* @returns {PIXI.Graphics} The child graphics added to the _graphicsContainer
*/
fillLOS(origin, elevation = 0, { type = "light"} = {}) {
this._updateElevationCurrentMax(elevation);
const los = CONFIG.Canvas.polygonBackends[type].create(origin, { type });

const graphics = this._graphicsContainer.addChild(new PIXI.Graphics());
const draw = new Draw(graphics);
const color = this.elevationColor(elevation);
Expand Down Expand Up @@ -988,6 +1033,8 @@ export class ElevationLayer extends InteractionLayer {
return;
}

this._updateElevationCurrentMax(elevation);

// Create the graphics representing the fill!
const graphics = this._graphicsContainer.addChild(new PIXI.Graphics());
drawPolygonWithHoles(polys, { graphics, fillColor: this.elevationColor(elevation) });
Expand Down Expand Up @@ -1111,6 +1158,7 @@ export class ElevationLayer extends InteractionLayer {
if ( !g ) return;
this._graphicsContainer.removeChild(g);
g.destroy();
this.#elevationCurrentMax = undefined;
this._requiresSave = true;
this.renderElevation();
}
Expand All @@ -1119,9 +1167,16 @@ export class ElevationLayer extends InteractionLayer {
* Remove all elevation data from the scene.
*/
async clearElevationData() {
this.#destroy();
this._clearElevationPixelCache();
this._backgroundElevation.destroy();
this._backgroundElevation = PIXI.Sprite.from(PIXI.Texture.EMPTY);

this._graphicsContainer.destroy({children: true});
this._graphicsContainer = new PIXI.Container();

await canvas.scene.unsetFlag(MODULE_ID, FLAGS.ELEVATION_IMAGE);
this._requiresSave = false;
this.#elevationCurrentMax = 0;
this.renderElevation();
}

Expand All @@ -1136,6 +1191,8 @@ export class ElevationLayer extends InteractionLayer {

this._graphicsContainer.destroy({children: true});
this._graphicsContainer = new PIXI.Container();

this._elevationTexture?.destroy();
}

/* -------------------------------------------- */
Expand Down Expand Up @@ -1167,6 +1224,10 @@ export class ElevationLayer extends InteractionLayer {
this.container.removeChild(this._elevationColorsMesh);
}

_updateMinColor() {
this._elevationColorsMesh.shader.updateMinColor();
}

/**
* Draw wall segments
*/
Expand Down Expand Up @@ -1357,78 +1418,6 @@ export class ElevationLayer extends InteractionLayer {

}

/**
* Filter used to display the elevation layer coloration of elevation data.
* elevationSampler is a texture that stores elevation data in the red channel.
* Elevation data currently displayed as a varying red color with varying alpha.
* Alpha is gamma corrected to ensure only darker alphas and red shades are used, to
* ensure the lower elevation values are perceivable.
*/
class ElevationFilter extends AbstractBaseFilter {
static vertexShader = `
attribute vec2 aVertexPosition;
uniform mat3 projectionMatrix;
uniform mat3 canvasMatrix;
uniform vec4 inputSize;
uniform vec4 outputFrame;
uniform vec2 dimensions;
varying vec2 vTextureCoord;
// varying vec2 vCanvasCoord;
varying vec2 vCanvasCoordNorm;
void main(void)
{
vTextureCoord = aVertexPosition * (outputFrame.zw * inputSize.zw);
vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy;
vec2 canvasCoord = (canvasMatrix * vec3(position, 1.0)).xy;
vCanvasCoordNorm = canvasCoord / dimensions;
gl_Position = vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);
}
`;

static fragmentShader = `
varying vec2 vTextureCoord;
varying vec2 vCanvasCoord;
varying vec2 vCanvasCoordNorm;
uniform sampler2D uSampler;
uniform sampler2D elevationSampler;
void main() {
vec4 tex = texture2D(uSampler, vTextureCoord);
vec4 elevation = texture2D(elevationSampler, vCanvasCoordNorm);
if ( elevation.r == 0.
|| vCanvasCoordNorm.x < 0.
|| vCanvasCoordNorm.y < 0.
|| vCanvasCoordNorm.x > 1.
|| vCanvasCoordNorm.y > 1. ) {
// Outside the scene boundary or no elevation set: use the background texture.
gl_FragColor = tex;
} else {
// Adjust alpha to avoid extremely light alphas
// basically a gamma correction
float alphaAdj = pow(elevation.r, 1. / 2.2);
gl_FragColor = vec4(alphaAdj, 0., 0., alphaAdj);
}
}
`;

/** @override */
// Thanks to https://ptb.discord.com/channels/732325252788387980/734082399453052938/1009287977261879388
apply(filterManager, input, output, clear, currentState) {
const { sceneX, sceneY } = canvas.dimensions;
this.uniforms.canvasMatrix ??= new PIXI.Matrix();
this.uniforms.canvasMatrix.copyFrom(canvas.stage.worldTransform);
this.uniforms.canvasMatrix.invert();
this.uniforms.canvasMatrix.translate(-sceneX, -sceneY);
return super.apply(filterManager, input, output, clear, currentState);
}
}

// NOTE: Testing elevation texture pixels
/*
api = game.modules.get("elevatedvision").api
Expand Down
Loading

0 comments on commit e56587e

Please sign in to comment.