Skip to content

Commit

Permalink
Merge branch 'master' of github.com:yogstation13/demo-viewer into yog…
Browse files Browse the repository at this point in the history
…station13-master
  • Loading branch information
Bizzonium committed Aug 13, 2024
2 parents c0014f6 + 3ee9920 commit 6774f17
Show file tree
Hide file tree
Showing 12 changed files with 412 additions and 108 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:

jobs:
deploy:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

Expand Down
32 changes: 31 additions & 1 deletion src/main/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DemoPlayerUi } from "./ui";
import classes from "./menu.scss";
import { InspectorPanel } from "./inspector";
import { ChatPanel } from "./chat";
import { SeeInvisibility } from "../misc/constants";

export class Menu extends Panel {
constructor() {
Expand Down Expand Up @@ -74,10 +75,17 @@ export class MainMenu extends Menu {
this.ui.nerdy_stats.style.display = (this.ui.nerdy_stats.style.display == "block") ? "none" : "block";
this.close();
});
let vision_button = this.add_basic_button("Set Vision", null, () => {
new SeeInvisibilityMenu(this.ui).put_to_right(vision_button).open(true);
});
this.add_basic_button("Toggle Darkness", null, () => {
this.ui.player.toggle_darkness();
this.close();
})
});
this.add_basic_button("Dump Textures", null, () => {
this.ui.player.dump_textures();
this.close();
});
}
}

Expand Down Expand Up @@ -237,3 +245,25 @@ export class ChatOptionsMenu extends Menu {
});
}
}

///For setting the see_invisibility value of the demo player
export class SeeInvisibilityMenu extends Menu {
constructor(public ui : DemoPlayerUi) {
super();
this.add_basic_button("Minimum Possible Vision", null, () => {
ui.player.set_see_invisible(SeeInvisibility.SEE_INVISIBLE_MINIMUM);
});
this.add_basic_button("Regular Vision", null, () => {
ui.player.set_see_invisible(SeeInvisibility.SEE_INVISIBLE_LIVING);
});
this.add_basic_button("Ghost vision", null, () => {
ui.player.set_see_invisible(SeeInvisibility.SEE_INVISIBLE_OBSERVER);
});
this.add_basic_button("ALL vision", null, () => {
ui.player.set_see_invisible(SeeInvisibility.INVISIBILITY_MAXIMUM);
});
this.add_basic_button("Debug vision", null, () => {
ui.player.set_see_invisible(SeeInvisibility.INVISIBILITY_ABSTRACT);
});
}
}
76 changes: 56 additions & 20 deletions src/main/rendering/gl_holder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CopyShader, get_copy_shader, get_icon_shader, IconShader, ShaderHolder
import { RenderingCmd } from "../../player/rendering/commands";
import { ViewportElement } from "../viewport";
import { render_maptext } from "./maptext";
import { BlendMode } from "../../misc/constants";

export class DemoPlayerGlHolder {
gl : WebGLRenderingContext;
Expand All @@ -16,6 +17,7 @@ export class DemoPlayerGlHolder {
max_texture_size : number;
copy_framebuffer : WebGLFramebuffer;
white_texture : WebGLTexture;
canvas_copy : WebGLTexture;

shader : IconShader;
shader_matrix : IconShader;
Expand All @@ -27,7 +29,7 @@ export class DemoPlayerGlHolder {
if(this.gl2) {
this.gl = this.gl2;
} else {
let gl = canvas.getContext("webgl", {desynchronized: true});
let gl = canvas.getContext("webgl", {desynchronized: true, alpha: false});
if(!gl) throw new Error("Could not initialize WebGL");
this.gl = gl;
}
Expand All @@ -49,11 +51,15 @@ export class DemoPlayerGlHolder {

this.white_texture = not_null(gl.createTexture());
gl.bindTexture(gl.TEXTURE_2D, this.white_texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255,255,255,255]));
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
gl.bindTexture(gl.TEXTURE_2D, null);
this.copy_framebuffer = not_null(gl.createFramebuffer());
this.max_texture_size = Math.min(gl.getParameter(gl.MAX_TEXTURE_SIZE), 32768);

this.canvas_copy = not_null(gl.createTexture());
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, this.canvas_copy);

this.square_buffer = not_null(gl.createBuffer());
gl.bindBuffer(gl.ARRAY_BUFFER, this.square_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1]), gl.STATIC_DRAW);
Expand Down Expand Up @@ -169,7 +175,7 @@ export class DemoPlayerGlHolder {
}
}
gl.bindTexture(gl.TEXTURE_2D, null);
} else if(cmd.cmd == "atlestexcopywithin") {
} else if(cmd.cmd == "atlastexcopywithin") {
let tex = not_null(this.atlas_textures[cmd.index]);
let shader = this.shader_copy;
this.set_shader(shader);
Expand Down Expand Up @@ -257,6 +263,8 @@ export class DemoPlayerGlHolder {
ia.vertexAttribDivisorANGLE(shader.a_layer, 1);
ia.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, cmd.num_elements);
gl.deleteBuffer(buf);
// gl.activeTexture(gl.TEXTURE0 + 1);
// gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, gl.canvas);
} else if(cmd.cmd == "copytoviewport") {
let this_viewport_pixel = curr_viewport_pixel;
let this_viewport = curr_viewport;
Expand Down Expand Up @@ -338,26 +346,54 @@ export class DemoPlayerGlHolder {
// this one was fun - I made test cases in BYOND and took screenshots and tried to reverse-engineer the blending equations from that.
// fun fact BYOND uses premultiplied alpha. However, when you
set_blend_mode(blend_mode : number) : void{
if(blend_mode == 0) blend_mode = 1;
//if(blend_mode == 0) blend_mode = 1;
if(blend_mode == this.curr_blend_mode) return;
this.curr_blend_mode = blend_mode;
const gl = this.gl;
if(blend_mode == 2) { // BLEND_ADD
gl.blendEquation(gl.FUNC_ADD);
gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
} else if(blend_mode == 3) { // BLEND_SUBTRACT
gl.blendEquation(gl.FUNC_REVERSE_SUBTRACT);
gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ZERO, gl.ONE);
} else if(blend_mode == 4) { // BLEND_MULTIPLY
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA); // fun fact if you do the math everything cancels out so that the destination alpha doesn't change at all.
} else if(blend_mode == 5) { // BLEND_INSET_OVERLAY
// TODO figure out if this is actually right
gl.blendEquation(gl.FUNC_ADD);
gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE)
} else { // BLEND_OVERLAY or BLEND_DEFAULT
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
switch(blend_mode){
case BlendMode.DEFAULT: {
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
break;
}
case BlendMode.ADD: {
gl.blendEquation(gl.FUNC_ADD);
gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
break;
}
case BlendMode.SUBTRACT: {
gl.blendEquation(gl.FUNC_REVERSE_SUBTRACT);
gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ZERO, gl.ONE);
break;
}
case BlendMode.MULTIPLY: {
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA); // fun fact if you do the math everything cancels out so that the destination alpha doesn't change at all.
break;
}
case BlendMode.INSET_OVERLAY: {
// TODO figure out if this is actually right
gl.blendEquation(gl.FUNC_ADD);
gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE)
break;
}
case BlendMode.ALPHA: {
gl.blendEquation(gl.FUNC_ADD);
//gl.blendFuncSeparate(gl.DST_COLOR, gl.ZERO, gl.DST_ALPHA, gl.ZERO)
gl.blendFunc(gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA);
break;
}
case BlendMode.ALPHA_INVERTED: {
gl.blendEquation(gl.FUNC_ADD);
gl.blendFuncSeparate(gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE)
break;
}
//Just in case there's a weird value we'll use the default
default: {
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
break;
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,7 @@ export class DemoPlayerUi {
handle_sounds(sounds : DemoSound[]) : void {
this.sound_player.handle_sounds(sounds);
}
async dump_textures() {
this.gl_holder.dump_textures();
}
}
76 changes: 63 additions & 13 deletions src/misc/appearance.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IconStateDir } from "../player/rendering/icon";
import { RESET_ALPHA, RESET_COLOR, RESET_TRANSFORM } from "./constants";
import { BlendMode, Planes, RESET_ALPHA, RESET_COLOR, RESET_TRANSFORM } from "./constants";
import { Matrix, matrix_invert, matrix_is_identity, matrix_multiply } from "./matrix";

export enum FilterType {
Expand Down Expand Up @@ -175,14 +175,27 @@ export type TransitionalAppearance = BaseAppearance<TransitionalAppearance|Appea

export namespace Appearance {
const empty_arr : [] = [];
export function resolve_plane(plane : number, parent_plane = 0) : number {
if(parent_plane < -10000 || parent_plane > 10000) parent_plane = resolve_plane(parent_plane);
if(plane < -10000 || plane > 10000) {
export function resolve_plane(plane : number, parent_plane = Planes.GAME_PLANE) : number {
if(parent_plane < Planes.LOWEST_EVER_PLANE || parent_plane > Planes.HIGHEST_EVER_PLANE) parent_plane = resolve_plane(parent_plane);
if(plane < Planes.LOWEST_EVER_PLANE || plane > Planes.HIGHEST_EVER_PLANE) {
plane = ((parent_plane + plane + 32767) << 16) >> 16;
}
return plane;
}

/**
* Used to determine if the appearance belongs to a plane that should be invisible when darkness is toggled off. Without darkness there's no reason to see sprites
* that exist to be an alpha mask of the dark.
* @param plane of the appearance as a number
* @returns TRUE if the plane value falls within the range of Byond lighting planes, FALSE if the plane is anything else
*/
export function is_lighting_plane(plane : number): boolean {
if(plane < Planes.LOWEST_EVER_PLANE || plane > Planes.HIGHEST_EVER_PLANE) {
plane = plane % (Planes.HIGHEST_EVER_PLANE - Planes.LOWEST_EVER_PLANE);
}
return (plane >= Planes.LIGHTING_PLANE && plane <= Planes.LIGHT_MASK_PLANE)
}

export function get_appearance_parts(appearance : Appearance) {
if(appearance.sorted_appearances) return appearance.sorted_appearances;
let appearances : Appearance[] = [];
Expand All @@ -195,8 +208,21 @@ export namespace Appearance {
appearances.push(...get_appearance_parts(underlay));
}
}
appearances.push(appearance)
for(let overlay of [...appearance.overlays].sort((a,b) => {
appearances.push(appearance);

/**
This is monster's original sort method which works on some browsers, but not all because it doesn't have all 3 cases required to uphold symmetry.
The cases required for a complete custom sort are
| compareFn(a, b) | return value | sort order
| | > 0 | sort a after b, e.g. [b, a]
| | < 0 | sort a before b, e.g. [a, b]
| | === 0 | keep original order of a and b
So the issue is that monster's only ever returned negatives or 0, so the lacking positive result would break some browser's js engine like firefox.
Whereas chromium based browsers (i.e. Google Chrome, Microsoft Edge) would function as intended.
const appearances_to_sort = [...appearance.overlays].sort((a,b) => {
let a_layer = a.layer < 0 ? appearance.layer : a.layer;
let b_layer = b.layer < 0 ? appearance.layer : b.layer;
if(a_layer < b_layer)
Expand All @@ -206,7 +232,31 @@ export namespace Appearance {
if(a_float_layer < b_float_layer)
return a_float_layer - b_float_layer;
return 0;
})) {
})
*/

//To circumvent the sorting issues, we're going to split the possible layers into 2 arrays.
//1 for regular layers which have positive values and 1 for float layers which have negative values
const regular_layers = appearance.overlays.filter((overlay) => overlay.layer >= 0);
const float_layers = appearance.overlays.filter((overlay) => overlay.layer < 0);

//sort by descending order for regular layers
regular_layers.sort((a,b) => {
return a.layer - b.layer;
});

//sort by ascending order for float layers
float_layers.sort((a,b) => {
return a.layer - b.layer;
});

//now combine the arrays with regular layers first.
const appearances_to_sort = regular_layers.concat(float_layers);

//Resume monster's code

for(let overlay of appearances_to_sort) {
overlay = overlay_inherit(appearance, overlay);
if(resolve_plane(overlay.plane, appearance.plane) != resolve_plane(appearance.plane)) {
float_appearances.push(overlay);
Expand Down Expand Up @@ -257,11 +307,11 @@ export namespace Appearance {
}
overlay.color_alpha = color_alpha;
}
if(overlay.blend_mode == 0 && appearance.blend_mode > 0) {
clone();
overlay.blend_mode = appearance.blend_mode;
}
if(overlay.plane < -10000 || overlay.plane > 10000) {
// if(appearance.blend_mode == BlendMode.DEFAULT && overlay.blend_mode != BlendMode.DEFAULT) {
// clone();

// }
if(overlay.plane < Planes.LOWEST_EVER_PLANE || overlay.plane > Planes.HIGHEST_EVER_PLANE) {
clone();
overlay.plane = resolve_plane(overlay.plane, appearance.plane);
}
Expand Down Expand Up @@ -395,7 +445,7 @@ export namespace ReaderAppearance {
pixel_y: 0,
pixel_z: 0,
pixel_w: 0,
blend_mode: 0,
blend_mode: BlendMode.DEFAULT,
glide_size: 8,
screen_loc: null,
transform: [1,0,0,0,1,0],
Expand Down
Loading

0 comments on commit 6774f17

Please sign in to comment.