mirror of
https://github.com/Terncode/pixel.horse.git
synced 2026-09-24 21:55:52 +02:00
Merge branch 'archive' into archive-update-v0.53.2
This commit is contained in:
+15
-12
@@ -15,6 +15,7 @@ export interface Contributors {
|
||||
contributors: Contributor[];
|
||||
}
|
||||
|
||||
// The Team
|
||||
export const CREDITS: Credit[] = [
|
||||
// example:
|
||||
// {
|
||||
@@ -81,28 +82,30 @@ export const CREDITS: Credit[] = [
|
||||
|
||||
export const CONTRIBUTORS: Contributors[] = [
|
||||
{
|
||||
group: 'Musicians',
|
||||
group: 'Music Composers',
|
||||
contributors: [
|
||||
{ name: 'Wandering Artist', links: ['https://wanderingartist.bandcamp.com/', 'https://www.youtube.com/user/WanderingArtistMusic'] }
|
||||
]
|
||||
{ name: 'Wandering Artist', links: ['https://wanderingartist.bandcamp.com/', 'https://www.youtube.com/user/WanderingArtistMusic'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
group: 'Artists & Animators',
|
||||
group: 'Programmers',
|
||||
contributors: [
|
||||
{ name: 'Industrialice' },
|
||||
],
|
||||
},
|
||||
{
|
||||
group: 'Artists',
|
||||
contributors: [
|
||||
{ name: 'Shino', links: ['https://www.deviantart.com/shinodage'] },
|
||||
{ name: 'ChiraChan', links: ['https://www.deviantart.com/chiramii-chan', 'https://chirachan-art.tumblr.com/'] },
|
||||
{ name: 'Goodly', links: ['https://www.deviantart.com/goodlyay'] },
|
||||
{ name: 'TioRafaJP', links: ['https://www.deviantart.com/tiorafajp', 'https://www.youtube.com/user/RafaelJP2'] },
|
||||
{ name: 'ShareMyShipment', links: ['https://www.deviantart.com/sharemyshipment'] },
|
||||
{ name: 'Velenor', links: ['https://www.deviantart.com/velenor'] },
|
||||
{ name: 'Velenor' },
|
||||
{ name: 'Meno', links: ['https://twitter.com/menojar', 'https://www.deviantart.com/menojar'] },
|
||||
{ name: 'OtakuAP', links: ['https://www.deviantart.com/otakuap'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
group: 'Artists',
|
||||
contributors: [
|
||||
{ name: 'Disastral' },
|
||||
{ name: 'Meno', links: ['https://www.deviantart.com/menojar'] },
|
||||
{ name: 'CyberPon3', links: ['https://twitter.com/CyberPon3'] },
|
||||
{ name: 'Paulpeoples', links: ['https://www.deviantart.com/paulpeopless'] },
|
||||
{ name: 'Velvet-Frost', links: ['https://www.deviantart.com/velvet-frost'] },
|
||||
{ name: 'Jet7Wave', links: ['https://www.deviantart.com/jetwave'] },
|
||||
@@ -119,7 +122,7 @@ export const CONTRIBUTORS: Contributors[] = [
|
||||
{ name: 'Towmacow Waffles', links: ['https://www.deviantart.com/towmacowwaffles'] },
|
||||
{ name: 'OrchidPony', links: ['https://www.deviantart.com/orchidpony'] },
|
||||
{ name: 'Cherry Cerise', links: ['https://www.deviantart.com/cherryceriseart'] },
|
||||
{ name: 'Radio' },
|
||||
{ name: 'RADIOstations', links: ['https://twitter.com/stagbeeble'] },
|
||||
{ name: 'Ultimate Fluff' },
|
||||
{ name: 'SC', links: ['https://0somecunt0.tumblr.com/tagged/sfw'] },
|
||||
{ name: 'SailorDolpin', links: ['https://vk.com/id324582699'] },
|
||||
|
||||
+22
-6
@@ -18,9 +18,14 @@ const SELECTED_ENTITY_BOUNDS = withAlphaFloat(ORANGE, 0.5);
|
||||
function drawEntities(batch: PaletteSpriteBatch, entities: Entity[], camera: Camera, options: DrawOptions) {
|
||||
const drawHidden = options.drawHidden;
|
||||
let entitiesDrawn = 0;
|
||||
let depthStep = 1.0 / entities.length;
|
||||
|
||||
for (let entity of entities) {
|
||||
if (isBoundsVisible(camera, entity.bounds, entity.x, entity.y) && (!isHidden(entity) || drawHidden)) {
|
||||
const depth = depthStep * entitiesDrawn;
|
||||
entity.depth = depth;
|
||||
batch.depth = depth;
|
||||
|
||||
for (const entity of entities) {
|
||||
if ((!isHidden(entity) || drawHidden) && isBoundsVisible(camera, entity.bounds, entity.x, entity.y)) {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
drawPonyEntity(batch, entity as Pony, options);
|
||||
entitiesDrawn++;
|
||||
@@ -45,38 +50,47 @@ function drawEntities(batch: PaletteSpriteBatch, entities: Entity[], camera: Cam
|
||||
|
||||
export function drawEntityLights(batch: SpriteBatch, entities: Entity[], camera: Camera, options: DrawOptions) {
|
||||
const drawHidden = options.drawHidden;
|
||||
let drawn = 0;
|
||||
|
||||
for (const entity of entities) {
|
||||
if (DEVELOPMENT && (entity.type !== PONY_TYPE && !entity.drawLight)) {
|
||||
console.error('Cannot draw entity light', entity);
|
||||
}
|
||||
|
||||
if ((!isHidden(entity) || drawHidden) && isBoundsVisible(camera, entity.lightBounds, entity.x, entity.y)) {
|
||||
if (isBoundsVisible(camera, entity.lightBounds, entity.x, entity.y) && (!isHidden(entity) || drawHidden)) {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
drawPonyEntityLight(batch, entity as Pony, options);
|
||||
} else {
|
||||
entity.drawLight!(batch, options);
|
||||
}
|
||||
++drawn;
|
||||
}
|
||||
}
|
||||
|
||||
return drawn;
|
||||
}
|
||||
|
||||
export function drawEntityLightSprites(batch: SpriteBatch, entities: Entity[], camera: Camera, options: DrawOptions) {
|
||||
const drawHidden = options.drawHidden;
|
||||
let drawn = 0;
|
||||
|
||||
for (const entity of entities) {
|
||||
if (DEVELOPMENT && (entity.type !== PONY_TYPE && !entity.drawLightSprite)) {
|
||||
console.error('Cannot draw entity light sprite', entity);
|
||||
}
|
||||
|
||||
if ((!isHidden(entity) || drawHidden) && isBoundsVisible(camera, entity.lightSpriteBounds, entity.x, entity.y)) {
|
||||
if (isBoundsVisible(camera, entity.lightSpriteBounds, entity.x, entity.y) && (!isHidden(entity) || drawHidden)) {
|
||||
batch.depth = entity.depth;
|
||||
if (entity.type === PONY_TYPE) {
|
||||
drawPonyEntityLightSprite(batch, entity as Pony, options);
|
||||
} else {
|
||||
entity.drawLightSprite!(batch, options);
|
||||
}
|
||||
++drawn;
|
||||
}
|
||||
}
|
||||
|
||||
return drawn;
|
||||
}
|
||||
|
||||
export function hasDrawLight(entity: Entity) {
|
||||
@@ -99,10 +113,11 @@ export function hasLightSprite(entity: Entity) {
|
||||
}
|
||||
|
||||
export function drawMap(
|
||||
batch: PaletteSpriteBatch, map: WorldMap, camera: Camera, player: Pony, options: DrawOptions,
|
||||
tileSets: TileSets, selectedEntities: Entity[],
|
||||
batch: PaletteSpriteBatch, map: WorldMap, camera: Camera, player: Pony,
|
||||
options: DrawOptions, tileSets: TileSets, selectedEntities: Entity[],
|
||||
) {
|
||||
TIMING && timeStart('forEachRegion');
|
||||
batch.depth = 1.0;
|
||||
if (BETA && options.engine === Engine.Whiteness) {
|
||||
batch.drawRect(WHITE, 0, 0, toScreenX(map.width), toScreenY(map.height));
|
||||
} else if (BETA && options.engine === Engine.LayeredTiles) {
|
||||
@@ -118,6 +133,7 @@ export function drawMap(
|
||||
|
||||
TIMING && timeStart('drawEntities');
|
||||
const entitiesDrawn = drawEntities(batch, map.entitiesDrawable, camera, options);
|
||||
batch.depth = 1.0;
|
||||
TIMING && timeEnd();
|
||||
|
||||
if (BETA || TOOLS) {
|
||||
|
||||
+218
-166
@@ -5,7 +5,7 @@ import {
|
||||
EntityState, Pony, Notification, TileType, Action, IServerActions, Season, WorldState, Holiday,
|
||||
TileSets, ChatMessage, PartyInfo, Entity, DrawOptions, Engine, defaultDrawOptions, PonyStateFlags,
|
||||
DoAction, ChatType, WorldStateFlags, DebugFlags, MessageType, AccountSettings, Matrix4,
|
||||
FakeEntity, SelectFlags, WorldMap, MapType, MapFlags, EntityFlags, houseTiles, isValidTile
|
||||
FakeEntity, SelectFlags, WorldMap, MapType, MapFlags, EntityFlags, houseTiles, isValidTile, GraphicsQuality
|
||||
} from '../common/interfaces';
|
||||
import {
|
||||
clamp, lengthOfXY, setFlag, hasFlag, boundsIntersect, point, toInt, lerpColor, distanceXY
|
||||
@@ -27,7 +27,7 @@ import { toggleWalls } from '../common/mixins';
|
||||
import { getEntityTypeName, hammer, broom, createAnEntity, saw, placeableEntities, shovel } from '../common/entities';
|
||||
import { hasExtendedInfo, setHeadAnimation, createPony } from '../common/pony';
|
||||
import { PaletteManager } from '../graphics/paletteManager';
|
||||
import { getRenderTargetSize, isWebGL2 } from '../graphics/webgl/webglUtils';
|
||||
import { isWebGL2 } from '../graphics/webgl/webglUtils';
|
||||
import { drawFullScreenMessage, drawNames, drawChat } from '../graphics/graphicsUtils';
|
||||
import { Key } from './input/input';
|
||||
import { loadAndInitSpriteSheets } from './spriteUtils';
|
||||
@@ -62,7 +62,7 @@ import { initializeToys } from './ponyDraw';
|
||||
import { ErrorReporter } from '../components/services/errorReporter';
|
||||
import { mockPaletteManager } from '../common/ponyInfo';
|
||||
import { timeStart, timeEnd, timingCollate, timeReset } from './timing';
|
||||
import { bindFrameBuffer, unbindFrameBuffer, resizeFrameBuffer } from '../graphics/webgl/frameBuffer';
|
||||
import { createFrameBuffer, bindFrameBuffer, unbindFrameBuffer, disposeFrameBuffer } from '../graphics/webgl/frameBuffer';
|
||||
import { WebGL, initWebGL, disposeWebGL, initWebGLResources } from './webgl';
|
||||
import { bindTexture } from '../graphics/webgl/texture2d';
|
||||
import {
|
||||
@@ -208,7 +208,6 @@ export class PonyTownGame implements Game {
|
||||
supporterPony = createPony(0, 0, SUPPORTER_PONY, mockPaletteManager.addArray(defaultPalette), mockPaletteManager);
|
||||
discordPony = createPony(0, 0, DISCORD_PONY, mockPaletteManager.addArray(defaultPalette), mockPaletteManager);
|
||||
scale: number;
|
||||
failedFBO = false;
|
||||
rightOverride?: boolean;
|
||||
headTurnedOverride?: boolean;
|
||||
stateOverride?: EntityState;
|
||||
@@ -248,6 +247,8 @@ export class PonyTownGame implements Game {
|
||||
private deltaMultiplier = 1;
|
||||
private lastDraw = 0;
|
||||
private entitiesDrawn = 0;
|
||||
private lightEntitiesDrawn = 0;
|
||||
private lightSpriteEntitiesDrawn = 0;
|
||||
private lastFps = performance.now();
|
||||
private frames = 0;
|
||||
private drawFps = 0;
|
||||
@@ -274,6 +275,16 @@ export class PonyTownGame implements Game {
|
||||
private errorReporter: ErrorReporter,
|
||||
private zone: NgZone,
|
||||
) {
|
||||
if (settings.browser.lowGraphicsMode !== undefined) {
|
||||
settings.browser.graphicsQuality = (settings.browser.lowGraphicsMode === true ? GraphicsQuality.Low : GraphicsQuality.High);
|
||||
settings.browser.lowGraphicsMode = undefined;
|
||||
settings.saveBrowserSettings();
|
||||
}
|
||||
if (settings.browser.graphicsQuality === undefined) {
|
||||
settings.browser.graphicsQuality = GraphicsQuality.High;
|
||||
settings.saveBrowserSettings();
|
||||
}
|
||||
|
||||
this.scale = this.getScale();
|
||||
this.audio.initTracks(this.season, this.holiday, this.map.type);
|
||||
this.audio.setVolume(this.volume);
|
||||
@@ -290,7 +301,22 @@ export class PonyTownGame implements Game {
|
||||
return this.settings.browser.volume || 0;
|
||||
}
|
||||
get disableLighting() {
|
||||
return !!this.settings.browser.lowGraphicsMode || this.failedFBO;
|
||||
if (this.settings.browser.graphicsQuality === GraphicsQuality.Low) {
|
||||
return true;
|
||||
}
|
||||
if (this.webgl) {
|
||||
return this.webgl.failedFBO;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
get disableLightMasksFixing() {
|
||||
if (this.settings.browser.graphicsQuality !== GraphicsQuality.High) {
|
||||
return true;
|
||||
}
|
||||
if (this.webgl) {
|
||||
return this.webgl.failedDepthBuffer;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
get frameDelay() {
|
||||
return (this.settings.browser.powerSaving || this.editingActions) ? (1000 / 45) : 0;
|
||||
@@ -325,8 +351,16 @@ export class PonyTownGame implements Game {
|
||||
}
|
||||
}
|
||||
private toggleDisableLighting() {
|
||||
if (!this.failedFBO) {
|
||||
this.settings.browser.lowGraphicsMode = !this.settings.browser.lowGraphicsMode;
|
||||
if (!this.webgl) {
|
||||
return;
|
||||
}
|
||||
if (!this.webgl.failedFBO) {
|
||||
if (this.settings.browser.graphicsQuality === GraphicsQuality.Low) {
|
||||
this.settings.browser.graphicsQuality = GraphicsQuality.High;
|
||||
}
|
||||
else {
|
||||
this.settings.browser.graphicsQuality = GraphicsQuality.Low;
|
||||
}
|
||||
this.settings.saveBrowserSettings();
|
||||
}
|
||||
}
|
||||
@@ -1198,10 +1232,8 @@ export class PonyTownGame implements Game {
|
||||
this.lastDraw = now;
|
||||
|
||||
// draw
|
||||
const {
|
||||
gl, frameBuffer, frameBufferSheet, spriteShader, spriteBatch, lightShader, paletteBatch, paletteShader,
|
||||
palettes,
|
||||
} = this.webgl;
|
||||
const { gl, frameBuffer, frameBuffer2, spriteBatch, paletteBatch, palettes, failedFBO,
|
||||
mergeShader, paletteShader, spriteShader, spriteShaderWithColor, lightShader } = this.webgl;
|
||||
|
||||
TIMING && timeStart('draw');
|
||||
|
||||
@@ -1246,7 +1278,7 @@ export class PonyTownGame implements Game {
|
||||
drawOptions.engine = this.engine;
|
||||
}
|
||||
|
||||
ortho(this.fboMatrix, 0, gl.drawingBufferWidth / actualScale, gl.drawingBufferHeight / actualScale, 0, 0, 1000);
|
||||
ortho(this.fboMatrix, 0, gl.drawingBufferWidth / actualScale, gl.drawingBufferHeight / actualScale, 0, 0, 1000, false);
|
||||
TIMING && timeEnd();
|
||||
|
||||
TIMING && timeStart('ensureAllVisiblePon...');
|
||||
@@ -1263,132 +1295,134 @@ export class PonyTownGame implements Game {
|
||||
lerpColor(light, white, 0.3);
|
||||
}
|
||||
|
||||
if (this.engine === Engine.NewLighting) {
|
||||
// ...
|
||||
} else if (this.disableLighting) {
|
||||
ortho(this.viewMatrix, camera.x, camera.x + camera.w, camera.actualY + camera.h, camera.actualY, 0, 1000);
|
||||
lerpColor(light, white, 0.1); // adjust lighting for missing lights
|
||||
// you'd draw directly onto the screen only when there's no framebuffer
|
||||
// or the graphics is low and framebuffer size matches screen size
|
||||
|
||||
// color -> screen
|
||||
gl.clearColor(bg[0], bg[1], bg[2], bg[3]);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
TIMING && timeStart('initializeFrameBuffers');
|
||||
this.initializeFrameBuffers(this.webgl, width, height, this.settings.browser.graphicsQuality === GraphicsQuality.High);
|
||||
TIMING && timeEnd();
|
||||
|
||||
const useDepthBuffer =
|
||||
!failedFBO && (this.settings.browser.graphicsQuality === GraphicsQuality.High) && !!frameBuffer!.depthStencilRenderbuffer;
|
||||
const useLighting = !failedFBO && (this.settings.browser.graphicsQuality !== GraphicsQuality.Low);
|
||||
const drawSceneDirectlyOntoScreen =
|
||||
failedFBO || (useLighting === false);
|
||||
|
||||
drawOptions.useDepthBuffer = useDepthBuffer;
|
||||
|
||||
let matrixTop = camera.actualY;
|
||||
let matrixBottom = camera.actualY + camera.h;
|
||||
if (!drawSceneDirectlyOntoScreen) {
|
||||
[matrixTop, matrixBottom] = [matrixBottom, matrixTop];
|
||||
}
|
||||
|
||||
ortho(this.viewMatrix, camera.x, camera.x + camera.w, matrixBottom, matrixTop, 0, 1000, false);
|
||||
|
||||
let mapDrawingColor = white;
|
||||
if (!useLighting) {
|
||||
mapDrawingColor = light;
|
||||
lerpColor(mapDrawingColor, white, 0.1); // adjust lighting for missing lights
|
||||
}
|
||||
|
||||
gl.clearColor(bg[0], bg[1], bg[2], bg[3]);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.depthFunc(gl.ALWAYS);
|
||||
|
||||
if (drawSceneDirectlyOntoScreen) {
|
||||
TIMING && timeStart('color -> screen');
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
gl.disable(gl.DEPTH_TEST);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
this.drawMap(this.webgl, this.map, this.viewMatrix, light, drawOptions);
|
||||
} else {
|
||||
ortho(this.viewMatrix, camera.x, camera.x + camera.w, camera.actualY, camera.actualY + camera.h, 0, 1000);
|
||||
|
||||
TIMING && timeStart('initializeFrameBuffer');
|
||||
this.initializeFrameBuffer(this.webgl, width, height);
|
||||
this.drawMap(this.webgl, this.map, this.viewMatrix, mapDrawingColor, drawOptions);
|
||||
TIMING && timeEnd();
|
||||
}
|
||||
else {
|
||||
// if (!isWebGL2(gl)) {
|
||||
// gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
// gl.clear(gl.COLOR_BUFFER_BIT); // hack, doing this clear fixes black screen issues for some older devices
|
||||
// }
|
||||
|
||||
if (!frameBuffer) {
|
||||
DEVELOPMENT && console.warn('No frame buffer');
|
||||
return;
|
||||
let clearMask = gl.COLOR_BUFFER_BIT;
|
||||
if (useDepthBuffer) {
|
||||
gl.depthMask(true);
|
||||
clearMask |= gl.DEPTH_BUFFER_BIT;
|
||||
}
|
||||
|
||||
// color -> fbo
|
||||
TIMING && timeStart('color -> fbo');
|
||||
// gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer.handle);
|
||||
bindFrameBuffer(gl, frameBuffer);
|
||||
gl.viewport(0, 0, frameBuffer.width, frameBuffer.height);
|
||||
gl.clearColor(bg[0], bg[1], bg[2], bg[3]);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT); // | gl.DEPTH_BUFFER_BIT);
|
||||
TIMING && timeStart('color -> framebuffer');
|
||||
bindFrameBuffer(gl, frameBuffer!);
|
||||
gl.viewport(0, 0, frameBuffer!.width, frameBuffer!.height); // clearing the whole surface is preferable for most GPUs
|
||||
gl.clear(clearMask);
|
||||
gl.viewport(0, 0, width, height);
|
||||
gl.disable(gl.DEPTH_TEST);
|
||||
//gl.depthFunc(gl.LEQUAL);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||
this.drawMap(this.webgl, this.map, this.viewMatrix, white, drawOptions);
|
||||
this.drawMap(this.webgl, this.map, this.viewMatrix, mapDrawingColor, drawOptions);
|
||||
gl.depthMask(false);
|
||||
TIMING && timeEnd();
|
||||
|
||||
// color -> screen
|
||||
TIMING && timeStart('color -> screen');
|
||||
// gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
unbindFrameBuffer(gl);
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
gl.clearColor(0, 0, 0, 1);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
// gl.disable(gl.DEPTH_TEST);
|
||||
gl.disable(gl.BLEND);
|
||||
if (useLighting) {
|
||||
TIMING && timeStart('light -> fbo');
|
||||
bindFrameBuffer(gl, frameBuffer2!);
|
||||
gl.viewport(0, 0, frameBuffer2!.width, frameBuffer2!.height); // clearing the whole surface is preferable for most GPUs
|
||||
gl.clearColor(light[0], light[1], light[2], light[3]);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
gl.viewport(0, 0, width, height);
|
||||
gl.blendFunc(gl.ONE, gl.ONE);
|
||||
|
||||
gl.useProgram(spriteShader.program);
|
||||
gl.uniformMatrix4fv(spriteShader.uniforms.transform, false, this.fboMatrix);
|
||||
gl.uniform4fv(spriteShader.uniforms.lighting, white);
|
||||
gl.uniform1f(spriteShader.uniforms.textureSize, frameBufferSheet.texture!.width);
|
||||
bindTexture(gl, 0, frameBufferSheet.texture);
|
||||
spriteBatch.begin();
|
||||
spriteBatch.drawImage(WHITE, 0, 0, width, height, 0, 0, width, height);
|
||||
spriteBatch.end();
|
||||
TIMING && timeEnd();
|
||||
gl.useProgram(lightShader.program);
|
||||
gl.uniformMatrix4fv(lightShader.uniforms.transform, false, this.viewMatrix);
|
||||
gl.uniform4fv(lightShader.uniforms.lighting, white);
|
||||
spriteBatch.begin();
|
||||
this.lightEntitiesDrawn = drawEntityLights(spriteBatch, this.map.entitiesLight, this.camera, drawOptions);
|
||||
spriteBatch.end();
|
||||
|
||||
// light -> fbo
|
||||
TIMING && timeStart('light -> fbo');
|
||||
// gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer.handle);
|
||||
bindFrameBuffer(gl, frameBuffer);
|
||||
gl.viewport(0, 0, frameBuffer.width, frameBuffer.height);
|
||||
gl.clearColor(light[0], light[1], light[2], light[3]);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
gl.viewport(0, 0, width, height);
|
||||
//gl.enable(gl.DEPTH_TEST);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFunc(gl.ONE, gl.ONE);
|
||||
TIMING && timeEnd();
|
||||
if (useDepthBuffer) {
|
||||
gl.depthFunc(gl.GEQUAL);
|
||||
}
|
||||
gl.useProgram(spriteShaderWithColor.program);
|
||||
gl.uniformMatrix4fv(spriteShaderWithColor.uniforms.transform, false, this.viewMatrix);
|
||||
gl.uniform4fv(spriteShaderWithColor.uniforms.lighting, white);
|
||||
gl.uniform2f(spriteShaderWithColor.uniforms.textureSize,
|
||||
normalSpriteSheet.texture!.width, normalSpriteSheet.texture!.height);
|
||||
bindTexture(gl, 0, normalSpriteSheet.texture);
|
||||
spriteBatch.begin();
|
||||
this.lightSpriteEntitiesDrawn = drawEntityLightSprites(spriteBatch, this.map.entitiesLightSprite, this.camera, drawOptions);
|
||||
spriteBatch.end();
|
||||
gl.depthFunc(gl.ALWAYS);
|
||||
if (isWebGL2(gl)) {
|
||||
(gl as WebGL2RenderingContext).invalidateFramebuffer(gl.FRAMEBUFFER, [gl.DEPTH_ATTACHMENT]);
|
||||
}
|
||||
TIMING && timeEnd();
|
||||
|
||||
// shadows
|
||||
//for (const e of map.entities) {
|
||||
// if (e.drawShadow && camera.isBoundVisible(e.shadowBounds || e.bounds, e.x, e.y)) {
|
||||
// this.spriteBatch.depth = camera.mapDepth(e.y);
|
||||
// e.drawShadow(this.spriteBatch);
|
||||
// }
|
||||
//}
|
||||
TIMING && timeStart('color + lights -> screen');
|
||||
unbindFrameBuffer(gl);
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
gl.disable(gl.BLEND);
|
||||
|
||||
// soft lights
|
||||
TIMING && timeStart('drawEntityLights');
|
||||
gl.useProgram(lightShader.program);
|
||||
gl.uniformMatrix4fv(lightShader.uniforms.transform, false, this.viewMatrix);
|
||||
gl.uniform4fv(lightShader.uniforms.lighting, white);
|
||||
spriteBatch.begin();
|
||||
drawEntityLights(spriteBatch, this.map.entitiesLight, this.camera, drawOptions);
|
||||
spriteBatch.end();
|
||||
TIMING && timeEnd();
|
||||
gl.useProgram(mergeShader.program);
|
||||
gl.uniformMatrix4fv(mergeShader.uniforms.transform, false, this.fboMatrix);
|
||||
gl.uniform2f(mergeShader.uniforms.textureSize, frameBuffer!.colorTexture.width, frameBuffer!.colorTexture.height);
|
||||
bindTexture(gl, 0, frameBuffer!.colorTexture);
|
||||
bindTexture(gl, 1, frameBuffer2!.colorTexture);
|
||||
spriteBatch.begin();
|
||||
spriteBatch.drawImage(WHITE, 0, 0, width, height, 0, 0, width, height);
|
||||
spriteBatch.end();
|
||||
TIMING && timeEnd();
|
||||
}
|
||||
else {
|
||||
TIMING && timeStart('color framebuffer -> screen');
|
||||
unbindFrameBuffer(gl);
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
gl.disable(gl.BLEND);
|
||||
|
||||
// light sprites
|
||||
TIMING && timeStart('drawEntityLightSprites');
|
||||
gl.useProgram(spriteShader.program);
|
||||
gl.uniformMatrix4fv(spriteShader.uniforms.transform, false, this.viewMatrix);
|
||||
gl.uniform4fv(spriteShader.uniforms.lighting, white);
|
||||
gl.uniform1f(spriteShader.uniforms.textureSize, normalSpriteSheet.texture!.width);
|
||||
bindTexture(gl, 0, normalSpriteSheet.texture);
|
||||
spriteBatch.begin();
|
||||
drawEntityLightSprites(spriteBatch, this.map.entitiesLightSprite, this.camera, drawOptions);
|
||||
spriteBatch.end();
|
||||
TIMING && timeEnd();
|
||||
|
||||
// light -> screen
|
||||
TIMING && timeStart('light -> screen');
|
||||
// gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
unbindFrameBuffer(gl);
|
||||
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFunc(gl.DST_COLOR, gl.ZERO);
|
||||
|
||||
gl.useProgram(spriteShader.program);
|
||||
gl.uniformMatrix4fv(spriteShader.uniforms.transform, false, this.fboMatrix);
|
||||
gl.uniform4fv(spriteShader.uniforms.lighting, white);
|
||||
gl.uniform1f(spriteShader.uniforms.textureSize, frameBufferSheet.texture!.width);
|
||||
bindTexture(gl, 0, frameBufferSheet.texture);
|
||||
spriteBatch.begin();
|
||||
spriteBatch.drawImage(WHITE, 0, 0, width, height, 0, 0, width, height);
|
||||
spriteBatch.end();
|
||||
TIMING && timeEnd();
|
||||
gl.useProgram(spriteShader.program);
|
||||
gl.uniformMatrix4fv(spriteShader.uniforms.transform, false, this.fboMatrix);
|
||||
gl.uniform4fv(spriteShader.uniforms.lighting, white);
|
||||
gl.uniform2f(spriteShader.uniforms.textureSize, frameBuffer!.colorTexture.width, frameBuffer!.colorTexture.height);
|
||||
bindTexture(gl, 0, frameBuffer!.colorTexture);
|
||||
spriteBatch.begin();
|
||||
spriteBatch.drawImage(WHITE, 0, 0, width, height, 0, 0, width, height);
|
||||
spriteBatch.end();
|
||||
TIMING && timeEnd();
|
||||
}
|
||||
}
|
||||
|
||||
// ui -> screen
|
||||
@@ -1401,7 +1435,7 @@ export class PonyTownGame implements Game {
|
||||
gl.uniformMatrix4fv(paletteShader.uniforms.transform, false, this.fboMatrix);
|
||||
gl.uniform4fv(paletteShader.uniforms.lighting, white);
|
||||
gl.uniform1f(paletteShader.uniforms.pixelSize, this.paletteManager.pixelSize);
|
||||
gl.uniform1f(paletteShader.uniforms.textureSize, paletteSpriteSheet.texture!.width);
|
||||
gl.uniform1f(paletteShader.uniforms.textureSize, 1.0 / paletteSpriteSheet.texture!.width);
|
||||
bindTexture(gl, 0, paletteSpriteSheet.texture);
|
||||
bindTexture(gl, 1, this.paletteManager.texture);
|
||||
paletteBatch.begin();
|
||||
@@ -1467,12 +1501,13 @@ export class PonyTownGame implements Game {
|
||||
paletteBatch.end();
|
||||
TIMING && timeEnd();
|
||||
|
||||
gl.useProgram(spriteShader.program);
|
||||
gl.uniformMatrix4fv(spriteShader.uniforms.transform, false, this.fboMatrix);
|
||||
gl.uniform4fv(spriteShader.uniforms.lighting, white);
|
||||
gl.useProgram(spriteShaderWithColor.program);
|
||||
gl.uniformMatrix4fv(spriteShaderWithColor.uniforms.transform, false, this.fboMatrix);
|
||||
gl.uniform4fv(spriteShaderWithColor.uniforms.lighting, white);
|
||||
|
||||
if (BETA && this.showMinimap && this.minimap) {
|
||||
gl.uniform1f(spriteShader.uniforms.textureSize, normalSpriteSheet.texture!.width);
|
||||
gl.uniform2f(spriteShaderWithColor.uniforms.textureSize,
|
||||
normalSpriteSheet.texture!.width, normalSpriteSheet.texture!.height);
|
||||
bindTexture(gl, 0, normalSpriteSheet.texture);
|
||||
spriteBatch.begin();
|
||||
spriteBatch.save();
|
||||
@@ -1500,7 +1535,8 @@ export class PonyTownGame implements Game {
|
||||
}
|
||||
|
||||
if (BETA && this.debug.showRegions && this.player) {
|
||||
gl.uniform1f(spriteShader.uniforms.textureSize, normalSpriteSheet.texture!.width);
|
||||
gl.uniform2f(spriteShaderWithColor.uniforms.textureSize,
|
||||
normalSpriteSheet.texture!.width, normalSpriteSheet.texture!.height);
|
||||
bindTexture(gl, 0, normalSpriteSheet.texture);
|
||||
spriteBatch.begin();
|
||||
drawDebugRegions(spriteBatch, this.map, this.player, this.camera);
|
||||
@@ -1510,22 +1546,23 @@ export class PonyTownGame implements Game {
|
||||
const showFPS = !!this.settings.browser.showFps;
|
||||
const showHelp = BETA && this.input.isPressed(Key.F1);
|
||||
const showPalette = DEVELOPMENT && this.debug.showPalette;
|
||||
const showAdditionalStats = false;
|
||||
|
||||
if (showFPS || showHelp || showPalette) {
|
||||
if (showFPS || showHelp || showPalette || showAdditionalStats) {
|
||||
// 1 to 1 pixel scale drawing
|
||||
TIMING && timeStart('showFps');
|
||||
const scale = 2;
|
||||
// const height = gl.drawingBufferHeight / (ratio * scale);
|
||||
ortho(this.fboMatrix, 0, gl.drawingBufferWidth / ratio, gl.drawingBufferHeight / ratio, 0, 0, 1000);
|
||||
gl.uniformMatrix4fv(spriteShader.uniforms.transform, false, this.fboMatrix);
|
||||
gl.uniform1f(spriteShader.uniforms.textureSize, normalSpriteSheet.texture!.width);
|
||||
ortho(this.fboMatrix, 0, gl.drawingBufferWidth / ratio, gl.drawingBufferHeight / ratio, 0, 0, 1000, false);
|
||||
gl.uniformMatrix4fv(spriteShaderWithColor.uniforms.transform, false, this.fboMatrix);
|
||||
gl.uniform2f(spriteShaderWithColor.uniforms.textureSize,
|
||||
normalSpriteSheet.texture!.width, normalSpriteSheet.texture!.height);
|
||||
bindTexture(gl, 0, normalSpriteSheet.texture);
|
||||
spriteBatch.begin();
|
||||
spriteBatch.save();
|
||||
spriteBatch.scale(scale, scale);
|
||||
|
||||
if (showFPS) {
|
||||
drawText(spriteBatch, this.drawFps.toFixed(), fontSmall, BLACK, 2, 2);
|
||||
drawOutlinedText(spriteBatch, this.drawFps.toFixed(), fontSmall, WHITE, BLACK, 2, 2);
|
||||
|
||||
if (this.timingsText) {
|
||||
const size = measureText(this.timingsText, fontMono);
|
||||
@@ -1543,19 +1580,18 @@ export class PonyTownGame implements Game {
|
||||
}
|
||||
}
|
||||
|
||||
// if (DEVELOPMENT) {
|
||||
// const width = gl.drawingBufferWidth / (ratio * scale);
|
||||
// const { isCollidingCount, isCollidingObjectCount } = getCollisionStats();
|
||||
// const text =
|
||||
// `${isCollidingCount.toString().padStart(7)} calls\n` +
|
||||
// `${isCollidingObjectCount.toString().padStart(7)} total checks\n` +
|
||||
// `${this.markedColliding.toString().padStart(7)} player checks`;
|
||||
// const size = measureText(text, fontMono);
|
||||
// const x = width - 160;
|
||||
// const y = 26;
|
||||
// spriteBatch.drawRect(0x000000aa, x, y, 150, size.h + 10);
|
||||
// drawText(spriteBatch, text, fontMono, WHITE, x + 5, y + 5);
|
||||
// }
|
||||
if (showAdditionalStats) {
|
||||
const width = gl.drawingBufferWidth / (ratio * scale);
|
||||
const text =
|
||||
`entities ${this.entitiesDrawn}/${this.map.entitiesDrawable.length}\n` +
|
||||
`light enitities ${this.lightEntitiesDrawn}/${this.map.entitiesLight.length}\n` +
|
||||
`light sprite entities ${this.lightSpriteEntitiesDrawn}/${this.map.entitiesLightSprite.length}`;
|
||||
const size = measureText(text, fontMono);
|
||||
const x = width - Math.max(160, size.w);
|
||||
const y = 26;
|
||||
spriteBatch.drawRect(0x000000aa, x, y, 150, size.h + 10);
|
||||
drawText(spriteBatch, text, fontMono, WHITE, x + 5, y + 5);
|
||||
}
|
||||
|
||||
spriteBatch.restore();
|
||||
spriteBatch.end();
|
||||
@@ -1564,13 +1600,14 @@ export class PonyTownGame implements Game {
|
||||
const paletteTexture = this.paletteManager.texture!;
|
||||
const { width, height } = paletteTexture;
|
||||
|
||||
gl.uniform1f(spriteShader.uniforms.textureSize, normalSpriteSheet.texture!.width);
|
||||
gl.uniform2f(spriteShaderWithColor.uniforms.textureSize,
|
||||
normalSpriteSheet.texture!.width, normalSpriteSheet.texture!.height);
|
||||
bindTexture(gl, 0, normalSpriteSheet.texture);
|
||||
spriteBatch.begin();
|
||||
spriteBatch.drawRect(0x00000066, 20, 20, width, height);
|
||||
spriteBatch.end();
|
||||
|
||||
gl.uniform1f(spriteShader.uniforms.textureSize, width);
|
||||
gl.uniform2f(spriteShaderWithColor.uniforms.textureSize, width, height);
|
||||
bindTexture(gl, 0, paletteTexture);
|
||||
spriteBatch.begin();
|
||||
spriteBatch.drawImage(WHITE, 0, 0, width, height, 20, 20, width, height);
|
||||
@@ -1601,15 +1638,17 @@ export class PonyTownGame implements Game {
|
||||
drawFullScreenMessage(paletteBatch, this.camera, message, palettes.mainFont.white);
|
||||
}
|
||||
private drawMap(webgl: WebGL, map: WorldMap, viewMatrix: Matrix4, lighting: Float32Array, options: DrawOptions) {
|
||||
const { gl, paletteBatch, paletteShader } = webgl;
|
||||
const { gl, paletteBatch, paletteShader, paletteShaderWithDepth } = webgl;
|
||||
|
||||
const mapPaletteShader = options.useDepthBuffer ? paletteShaderWithDepth : paletteShader;
|
||||
|
||||
TIMING && timeStart('drawMap');
|
||||
if (this.tileSets && this.player) {
|
||||
gl.useProgram(paletteShader.program);
|
||||
gl.uniformMatrix4fv(paletteShader.uniforms.transform, false, viewMatrix);
|
||||
gl.uniform4fv(paletteShader.uniforms.lighting, lighting);
|
||||
gl.uniform1f(paletteShader.uniforms.pixelSize, this.paletteManager.pixelSize);
|
||||
gl.uniform1f(paletteShader.uniforms.textureSize, paletteSpriteSheet.texture!.width);
|
||||
gl.useProgram(mapPaletteShader.program);
|
||||
gl.uniformMatrix4fv(mapPaletteShader.uniforms.transform, false, viewMatrix);
|
||||
gl.uniform4fv(mapPaletteShader.uniforms.lighting, lighting);
|
||||
gl.uniform1f(mapPaletteShader.uniforms.pixelSize, this.paletteManager.pixelSize);
|
||||
gl.uniform1f(mapPaletteShader.uniforms.textureSize, 1.0 / paletteSpriteSheet.texture!.width);
|
||||
bindTexture(gl, 0, paletteSpriteSheet.texture);
|
||||
bindTexture(gl, 1, this.paletteManager.texture);
|
||||
paletteBatch.begin();
|
||||
@@ -1618,7 +1657,7 @@ export class PonyTownGame implements Game {
|
||||
paletteBatch.end();
|
||||
|
||||
if (this.highlightEntity && this.highlightEntity.draw) {
|
||||
gl.uniform4fv(paletteShader.uniforms.lighting, highlightColor);
|
||||
gl.uniform4fv(mapPaletteShader.uniforms.lighting, highlightColor);
|
||||
paletteBatch.begin();
|
||||
this.highlightEntity.draw(paletteBatch, this.drawOptions);
|
||||
paletteBatch.end();
|
||||
@@ -1680,16 +1719,29 @@ export class PonyTownGame implements Game {
|
||||
DEVELOPMENT && log(`scrollY: ${window.scrollY}`);
|
||||
}
|
||||
}
|
||||
private initializeFrameBuffer({ gl, frameBuffer }: WebGL, width: number, height: number) {
|
||||
const targetSize = getRenderTargetSize(width, height);
|
||||
private initializeFrameBuffers(
|
||||
{ gl, frameBuffer, frameBuffer2 }: WebGL, width: number, height: number, useDepthBuffer: boolean
|
||||
) {
|
||||
if (!frameBuffer || !frameBuffer2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (frameBuffer && targetSize !== frameBuffer.width) {
|
||||
const hasDepth = frameBuffer.depthStencilRenderbuffer !== null;
|
||||
const isSizeChanged = width !== frameBuffer.width || height !== frameBuffer.height;
|
||||
const isDepthChanged = hasDepth !== useDepthBuffer;
|
||||
|
||||
if (isSizeChanged || isDepthChanged) {
|
||||
const maxSize = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
|
||||
const isSizeTooBig = maxSize != null && (width > maxSize || height > maxSize);
|
||||
|
||||
if (maxSize != null && targetSize > maxSize) {
|
||||
this.setScale(this.scale + 1);
|
||||
if (isSizeTooBig) {
|
||||
this.setScale(this.scale + 1); // should not happen, useDepthBuffer is also ignored if it does
|
||||
DEVELOPMENT && console.warn('Cannot resize framebuffer');
|
||||
} else {
|
||||
resizeFrameBuffer(gl, frameBuffer, targetSize, targetSize);
|
||||
disposeFrameBuffer(gl, frameBuffer);
|
||||
disposeFrameBuffer(gl, frameBuffer2);
|
||||
createFrameBuffer(gl, frameBuffer, width, height, false, useDepthBuffer, null);
|
||||
createFrameBuffer(gl, frameBuffer2, width, height, false, false, frameBuffer.depthStencilRenderbuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1742,7 +1794,7 @@ export class PonyTownGame implements Game {
|
||||
let value = '';
|
||||
|
||||
if (this.settings.browser.showStats) {
|
||||
const tris = spriteBatch.tris + paletteBatch.tris;
|
||||
const tris = spriteBatch.drawnTrisStats + paletteBatch.drawnTrisStats;
|
||||
const flush = paletteBatch.flushes;
|
||||
const sent = this.sent.toFixed();
|
||||
const recv = this.recv.toFixed();
|
||||
@@ -1772,9 +1824,9 @@ export class PonyTownGame implements Game {
|
||||
|
||||
TIMING && timeReset();
|
||||
|
||||
spriteBatch!.tris = 0;
|
||||
spriteBatch!.drawnTrisStats = 0;
|
||||
spriteBatch!.flushes = 0;
|
||||
paletteBatch!.tris = 0;
|
||||
paletteBatch!.drawnTrisStats = 0;
|
||||
paletteBatch!.flushes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,12 @@ export const excite = createHeadAnimation('excite', 8, false, [
|
||||
...repeat(10, [0, 0, 1, 1, 5]),
|
||||
]);
|
||||
|
||||
export const excite_meno = createHeadAnimation('excite_meno', 8, false, [
|
||||
...repeat(2, [0, 0, 2, 2, 0]),
|
||||
[0, 1, 6, 6, 0],
|
||||
...repeat(10, [0, 0, 1, 1, 5])
|
||||
]);
|
||||
|
||||
export const surpriseSad = createHeadAnimation('surpriseSad', 8, false, [
|
||||
[0, 1, 15, 15, 8],
|
||||
...repeat(8, [0, 0, 15, 15, 8]),
|
||||
@@ -534,6 +540,24 @@ export const sneeze = createHeadAnimation('sneeze', 12, false, [
|
||||
...repeat(4, [0, 0, 18, 18, 7]),
|
||||
]);
|
||||
|
||||
export const happy_tongue = createHeadAnimation('happy_tongue', 12, false, [
|
||||
...repeat(3, [0, 0, 1, 1, 0]),
|
||||
[0, 1, 6, 6, 0],
|
||||
...repeat(8, [0, 0, 14, 14, 4]),
|
||||
]);
|
||||
|
||||
export const happy_tongue_meno = createHeadAnimation('happy_tongue_meno', 12, false, [
|
||||
...repeat(3, [0, 0, 2, 2, 0]),
|
||||
[0, 1, 6, 6, 0],
|
||||
...repeat(8, [0, 0, 12, 12, 4]),
|
||||
]);
|
||||
|
||||
export const happy_tongue_meno_2 = createHeadAnimation('happy_tongue_meno_2', 12, false, [
|
||||
...repeat(3, [0, 0, 2, 2, 0]),
|
||||
[0, 1, 6, 6, 0],
|
||||
...repeat(8, [0, 0, 11, 11, 4]),
|
||||
]);
|
||||
|
||||
export const headAnimations = [
|
||||
smile, nom, laugh, yawn, surprise, surpriseSad, sneeze, excite,
|
||||
];
|
||||
|
||||
@@ -214,13 +214,14 @@ export function initializeToys(paletteManager: PaletteManager) {
|
||||
}
|
||||
}
|
||||
|
||||
const zeroPoint = point(0, 0);
|
||||
// const zeroPoint = point(0, 0);
|
||||
const wakes = [
|
||||
{ ox: 21, oy: 60, behind: sprites.pony_wake_4, front: sprites.pony_wake_3 },
|
||||
{ ox: 24, oy: 60, behind: sprites.pony_wake_6, front: sprites.pony_wake_5 },
|
||||
{ ox: 18, oy: 51, behind: sprites.pony_wake_2, front: sprites.pony_wake_1 },
|
||||
];
|
||||
|
||||
// swimming effects of different size; add value per tail
|
||||
const wakeIndices = [0, 2, 1, 0, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1];
|
||||
|
||||
function getWakeIndex(info: Info) {
|
||||
@@ -292,9 +293,10 @@ export function drawPony(batch: Batch, info: Info, state: State, ponyX: number,
|
||||
let hatOffset = at(HEAD_ACCESSORY_OFFSETS, info.mane ? info.mane.type : 0)!;
|
||||
const noMane = !info.mane || hasNoMane(info.mane.type);
|
||||
|
||||
if (info.headAccessory !== undefined && info.headAccessory.type === 20) {
|
||||
hatOffset = zeroPoint;
|
||||
}
|
||||
// temp front layer hat test
|
||||
// if (info.headAccessory !== undefined && info.headAccessory.type === 20) {
|
||||
// hatOffset = zeroPoint;
|
||||
//}
|
||||
|
||||
if (draw(options, NoDraw.Behind)) {
|
||||
// far wing
|
||||
@@ -639,13 +641,14 @@ export function drawHead(
|
||||
drawSet(batch, sprites.facialHair, info.facialHair, x, y, WHITE);
|
||||
}
|
||||
|
||||
const skipTopAndFrontMane = info.headAccessory !== undefined && info.headAccessory.type === 20;
|
||||
// temp front layer hat test
|
||||
// const skipTopAndFrontMane = info.headAccessory !== undefined && info.headAccessory.type === 20;
|
||||
|
||||
if (draw(options, NoDraw.FrontMane)) {
|
||||
drawSet(batch, sprites.backFrontManes, info.backMane, x, y + maneOffsetY, WHITE);
|
||||
}
|
||||
|
||||
if (draw(options, NoDraw.TopMane) && !skipTopAndFrontMane) {
|
||||
if (draw(options, NoDraw.TopMane) /* && !skipTopAndFrontMane*/ ) {
|
||||
drawSet(batch, sprites.topManes, info.mane, x, y, WHITE);
|
||||
}
|
||||
|
||||
@@ -682,7 +685,7 @@ export function drawHead(
|
||||
drawSet(batch, sprites.earAccessories, info.earAccessory, x + earAccessoryOffset.x, y + earAccessoryOffset.y, WHITE);
|
||||
}
|
||||
|
||||
if (draw(options, NoDraw.FrontMane) && !skipTopAndFrontMane) {
|
||||
if (draw(options, NoDraw.FrontMane) /* && !skipTopAndFrontMane */) {
|
||||
drawSet(batch, sprites.frontManes, info.mane, x, y + maneOffsetY, WHITE);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ export const tails = createCompleteSets(sprites.tails, 3);
|
||||
export const chest = createCompleteSets(sprites.chestAccessories, bodyFrames);
|
||||
export const chestBehind = createCompleteSets(sprites.chestAccessoriesBehind, bodyFrames);
|
||||
export const backAccessories = createCompleteSets(sprites.backAccessories, bodyFrames);
|
||||
sprites.neckAccessories.forEach(f => f && f.pop()); // TEMP: remove headphones
|
||||
export const neckAccessories = createCompleteSets(sprites.neckAccessories, bodyFrames);
|
||||
export const waistAccessories = createCompleteSets(sprites.waistAccessories, bodyFrames + 1);
|
||||
|
||||
@@ -145,10 +144,6 @@ function mergeSpriteSets(...sets: ColorExtraSets[]): ColorExtraSets {
|
||||
export const backLegSleeves: Sets = sprites.backLegSleeves
|
||||
.map(sets => sets && [undefined, undefined, undefined, undefined, undefined, ...sets]);
|
||||
|
||||
// TEMP: remove summer hat
|
||||
sprites.headAccessoriesBehind.pop();
|
||||
sprites.headAccessories.pop();
|
||||
|
||||
export const mergedManes = mergeSpriteSets(sprites.behindManes, sprites.topManes, sprites.frontManes)!;
|
||||
export const mergedBackManes = mergeSpriteSets(sprites.backBehindManes, sprites.backFrontManes)!;
|
||||
export const mergedFacialHair = mergeSpriteSets(sprites.facialHairBehind, sprites.facialHair)!;
|
||||
|
||||
+57
-54
@@ -1,35 +1,41 @@
|
||||
import { spriteShader, paletteLayersShader, lightShader } from '../generated/shaders';
|
||||
import { FrameBuffer, createFrameBuffer, disposeFrameBuffer } from '../graphics/webgl/frameBuffer';
|
||||
import { SpriteSheet, CommonPalettes, PaletteManager, Camera } from '../common/interfaces';
|
||||
import { Shader, createShader, disposeShader } from '../graphics/webgl/shader';
|
||||
import { PaletteSpriteBatch, PALETTE_BATCH_BYTES_PER_VERTEX } from '../graphics/paletteSpriteBatch';
|
||||
import { getWebGLContext, getRenderTargetSize, unbindAllTexturesAndBuffers } from '../graphics/webgl/webglUtils';
|
||||
import { mergeShader, spriteShader, paletteLayersShader, lightShader } from '../generated/shaders';
|
||||
import { FrameBuffer, disposeFrameBuffer, createFrameBuffer } from '../graphics/webgl/frameBuffer';
|
||||
import { CommonPalettes, PaletteManager, Camera } from '../common/interfaces';
|
||||
import { Shader, ShaderProgramData, disposeShaderProgramData } from '../graphics/webgl/shader';
|
||||
import { PaletteSpriteBatch } from '../graphics/paletteSpriteBatch';
|
||||
import { getWebGLContext, unbindAllTexturesAndBuffers } from '../graphics/webgl/webglUtils';
|
||||
import { createCommonPalettes } from '../graphics/graphicsUtils';
|
||||
import { createTexturesForSpriteSheets, disposeTexturesForSpriteSheets } from '../graphics/spriteSheetUtils';
|
||||
import * as sprites from '../generated/sprites';
|
||||
import { SpriteBatch } from '../graphics/spriteBatch';
|
||||
import { BATCH_SIZE_MAX } from '../common/constants';
|
||||
import { BATCH_VERTEX_CAPACITY_MAX } from '../common/constants';
|
||||
|
||||
export interface WebGL {
|
||||
gl: WebGLRenderingContext;
|
||||
frameBuffer: FrameBuffer | undefined;
|
||||
frameBufferSheet: SpriteSheet;
|
||||
spriteShader: Shader;
|
||||
lightShader: Shader;
|
||||
paletteShader: Shader;
|
||||
frameBuffer?: FrameBuffer;
|
||||
frameBuffer2?: FrameBuffer;
|
||||
mergeShader: ShaderProgramData;
|
||||
paletteShader: ShaderProgramData;
|
||||
paletteShaderWithDepth: ShaderProgramData;
|
||||
spriteShader: ShaderProgramData;
|
||||
spriteShaderWithColor: ShaderProgramData;
|
||||
lightShader: ShaderProgramData;
|
||||
spriteBatch: SpriteBatch;
|
||||
paletteBatch: PaletteSpriteBatch;
|
||||
palettes: CommonPalettes;
|
||||
failedFBO: boolean;
|
||||
failedDepthBuffer: boolean;
|
||||
renderer: string;
|
||||
indexBuffer: WebGLBuffer;
|
||||
}
|
||||
|
||||
const mergeShaderSource = mergeShader;
|
||||
const spriteShaderSource = spriteShader;
|
||||
const paletteShaderSource = paletteLayersShader;
|
||||
const lightShaderSource = lightShader;
|
||||
|
||||
function createIndices(capacity: number) {
|
||||
const numIndices = (capacity * 6) | 0;
|
||||
function createIndices(vertexCount: number) {
|
||||
const numIndices = (vertexCount * 6 / 4) | 0;
|
||||
const indices = new Uint16Array(numIndices);
|
||||
|
||||
for (let i = 0, j = 0; i < numIndices; j = (j + 4) | 0) {
|
||||
@@ -52,62 +58,48 @@ export function initWebGL(canvas: HTMLCanvasElement, paletteManager: PaletteMana
|
||||
export function initWebGLResources(gl: WebGLRenderingContext, paletteManager: PaletteManager, camera: Camera): WebGL {
|
||||
let renderer = '';
|
||||
let failedFBO = false;
|
||||
let frameBuffer: FrameBuffer | undefined;
|
||||
let frameBufferSheet: SpriteSheet = { texture: undefined, sprites: [], palette: false };
|
||||
let failedDepthBuffer = false;
|
||||
let frameBuffer = {} as FrameBuffer;
|
||||
let frameBuffer2 = {} as FrameBuffer;
|
||||
|
||||
gl.enable(gl.DEPTH_TEST); // no reason to not have it enabled at all times, depth reads/writes are controlled by other parameters
|
||||
gl.disable(gl.DITHER);
|
||||
|
||||
try {
|
||||
const size = getRenderTargetSize(camera.w, camera.h);
|
||||
frameBuffer = createFrameBuffer(gl, size, size);
|
||||
frameBufferSheet.texture = frameBuffer.texture;
|
||||
createFrameBuffer(gl, frameBuffer, camera.w, camera.h, false, true, null);
|
||||
createFrameBuffer(gl, frameBuffer2, camera.w, camera.h, true, false, frameBuffer.depthStencilRenderbuffer);
|
||||
} catch (e) {
|
||||
DEVELOPMENT && console.warn(e);
|
||||
failedFBO = true;
|
||||
failedDepthBuffer = true;
|
||||
}
|
||||
|
||||
if (!failedFBO) {
|
||||
failedDepthBuffer = frameBuffer!.depthStencilRenderbuffer === null;
|
||||
}
|
||||
|
||||
createTexturesForSpriteSheets(gl, sprites.spriteSheets);
|
||||
const palettes = createCommonPalettes(paletteManager);
|
||||
|
||||
const paletteShader = createShader(gl, paletteShaderSource);
|
||||
const spriteShader = createShader(gl, spriteShaderSource);
|
||||
const lightShader = createShader(gl, lightShaderSource);
|
||||
|
||||
const VERTICES_PER_SPRITE = 4;
|
||||
const buffer = new ArrayBuffer(BATCH_SIZE_MAX * VERTICES_PER_SPRITE * PALETTE_BATCH_BYTES_PER_VERTEX);
|
||||
const vertexBuffer = gl.createBuffer();
|
||||
|
||||
if (!vertexBuffer) {
|
||||
throw new Error(`Failed to allocate vertex buffer`);
|
||||
}
|
||||
const mergeShaderRaw = new Shader(mergeShaderSource);
|
||||
const paletteShaderRaw = new Shader(paletteShaderSource);
|
||||
const spriteShaderRaw = new Shader(spriteShaderSource);
|
||||
const lightShaderRaw = new Shader(lightShaderSource);
|
||||
|
||||
const indexBuffer = gl.createBuffer();
|
||||
|
||||
if (!indexBuffer) {
|
||||
throw new Error(`Failed to allocate index buffer`);
|
||||
}
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
|
||||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, createIndices(BATCH_SIZE_MAX), gl.STATIC_DRAW);
|
||||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, createIndices(BATCH_VERTEX_CAPACITY_MAX), gl.STATIC_DRAW);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
||||
|
||||
const vertexBuffer2 = gl.createBuffer();
|
||||
|
||||
if (!vertexBuffer2) {
|
||||
throw new Error(`Failed to allocate vertex buffer (2)`);
|
||||
}
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer2);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW);
|
||||
|
||||
const spriteBatch = new SpriteBatch(gl, BATCH_SIZE_MAX, buffer, vertexBuffer2, indexBuffer);
|
||||
const paletteBatch = new PaletteSpriteBatch(gl, BATCH_SIZE_MAX, buffer, vertexBuffer, indexBuffer);
|
||||
const spriteBatch = new SpriteBatch(gl, BATCH_VERTEX_CAPACITY_MAX, indexBuffer);
|
||||
const paletteBatch = new PaletteSpriteBatch(gl, BATCH_VERTEX_CAPACITY_MAX, indexBuffer);
|
||||
spriteBatch.rectSprite = sprites.pixel;
|
||||
paletteBatch.rectSprite = sprites.pixel2;
|
||||
paletteBatch.defaultPalette = palettes.defaultPalette;
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
||||
|
||||
paletteManager.init(gl);
|
||||
|
||||
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
|
||||
@@ -116,9 +108,17 @@ export function initWebGLResources(gl: WebGLRenderingContext, paletteManager: Pa
|
||||
renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
|
||||
}
|
||||
|
||||
const mergeShader = mergeShaderRaw.compile(gl, []);
|
||||
const paletteShader = paletteShaderRaw.compile(gl, []);
|
||||
const paletteShaderWithDepth = paletteShaderRaw.compile(gl, ['DEPTH_BUFFERED']);
|
||||
const spriteShader = spriteShaderRaw.compile(gl, []);
|
||||
const spriteShaderWithColor = spriteShaderRaw.compile(gl, ['USE_COLOR']);
|
||||
const lightShader = lightShaderRaw.compile(gl, []);
|
||||
|
||||
return {
|
||||
gl, paletteShader, spriteShader, lightShader, spriteBatch, paletteBatch,
|
||||
frameBuffer, frameBufferSheet, palettes, failedFBO, renderer,
|
||||
gl, mergeShader: mergeShader, paletteShader: paletteShader, paletteShaderWithDepth: paletteShaderWithDepth,
|
||||
spriteShader: spriteShader, spriteShaderWithColor: spriteShaderWithColor, lightShader: lightShader,
|
||||
spriteBatch, paletteBatch, frameBuffer, frameBuffer2, palettes, failedFBO, failedDepthBuffer, renderer, indexBuffer
|
||||
};
|
||||
}
|
||||
|
||||
@@ -128,9 +128,12 @@ export function disposeWebGL(webgl: WebGL) {
|
||||
unbindAllTexturesAndBuffers(gl);
|
||||
disposeTexturesForSpriteSheets(gl, sprites.spriteSheets);
|
||||
disposeFrameBuffer(gl, webgl.frameBuffer);
|
||||
disposeShader(gl, webgl.lightShader);
|
||||
disposeShader(gl, webgl.spriteShader);
|
||||
disposeShader(gl, webgl.paletteShader);
|
||||
disposeShaderProgramData(gl, webgl.paletteShader);
|
||||
disposeShaderProgramData(gl, webgl.paletteShaderWithDepth);
|
||||
disposeShaderProgramData(gl, webgl.spriteShader);
|
||||
disposeShaderProgramData(gl, webgl.spriteShaderWithColor);
|
||||
disposeShaderProgramData(gl, webgl.lightShader);
|
||||
webgl.spriteBatch.dispose();
|
||||
webgl.paletteBatch.dispose();
|
||||
gl.deleteBuffer(webgl.indexBuffer);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user