diff --git a/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts b/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts index e57220a..1fcc988 100644 --- a/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts +++ b/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts @@ -1,33 +1,23 @@ -import { enableExtension } from '../helper/enable-extension'; +import { ColorTexture } from '../texture/color-texture'; +import { DistanceTexture } from '../texture/distance-texture'; +import { Texture } from '../texture/texture'; import { UniversalRenderingContext } from '../universal-rendering-context'; import { FrameBuffer } from './frame-buffer'; /** @internal */ export class IntermediateFrameBuffer extends FrameBuffer { - private frameTexture: WebGLTexture; - private floatEnabled = false; - private floatLinearEnabled = false; + private distanceTexture?: DistanceTexture; + private colorTexture: ColorTexture; constructor(gl: UniversalRenderingContext) { super(gl); - try { - enableExtension(gl, 'EXT_color_buffer_float'); - this.floatEnabled = true; + this.colorTexture = new ColorTexture(gl); - enableExtension(gl, 'OES_texture_float_linear'); - this.floatLinearEnabled = true; - } catch { - // it's okay + if (gl.isWebGL2) { + this.distanceTexture = new DistanceTexture(gl); } - // can only return null on lost context - gl.activeTexture(gl.TEXTURE0); - - this.frameTexture = this.gl.createTexture()!; - this.configureTexture(); - - // can only return null on lost context this.frameBuffer = this.gl.createFramebuffer()!; this.configureFrameBuffer(); @@ -35,74 +25,48 @@ export class IntermediateFrameBuffer extends FrameBuffer { } public destroy(): void { - this.gl.deleteTexture(this.frameTexture); + if (this.distanceTexture) { + this.gl.deleteTexture(this.distanceTexture); + } + this.gl.deleteTexture(this.colorTexture); + this.gl.deleteFramebuffer(this.frameBuffer); } - public get colorTexture(): WebGLTexture { - return this.frameTexture; + public get textures(): Array { + return this.distanceTexture + ? [this.distanceTexture, this.colorTexture] + : [this.colorTexture]; } public setSize(): boolean { const hasChanged = super.setSize(); if (hasChanged) { - this.bind(); - - this.gl.texImage2D( - this.gl.TEXTURE_2D, - 0, - this.floatEnabled ? this.gl.RG16F : this.gl.RGB, - this.size.x, - this.size.y, - 0, - this.floatEnabled ? this.gl.RG : this.gl.RGB, - this.floatEnabled ? this.gl.FLOAT : this.gl.UNSIGNED_BYTE, - null - ); + this.colorTexture.setSize(this.size); + this.distanceTexture?.setSize(this.size); } return hasChanged; } - private bind() { - this.gl.activeTexture(this.gl.TEXTURE0); - this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture); - } - - private configureTexture() { - this.bind(); - - this.gl.texParameteri( - this.gl.TEXTURE_2D, - this.gl.TEXTURE_MAG_FILTER, - this.floatLinearEnabled ? this.gl.LINEAR : this.gl.NEAREST - ); - this.gl.texParameteri( - this.gl.TEXTURE_2D, - this.gl.TEXTURE_MIN_FILTER, - this.floatLinearEnabled ? this.gl.LINEAR : this.gl.NEAREST - ); - this.gl.texParameteri( - this.gl.TEXTURE_2D, - this.gl.TEXTURE_WRAP_S, - this.gl.CLAMP_TO_EDGE - ); - this.gl.texParameteri( - this.gl.TEXTURE_2D, - this.gl.TEXTURE_WRAP_T, - this.gl.CLAMP_TO_EDGE - ); - } - private configureFrameBuffer() { this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.frameBuffer); - const attachmentPoint = this.gl.COLOR_ATTACHMENT0; this.gl.framebufferTexture2D( this.gl.FRAMEBUFFER, - attachmentPoint, + this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, - this.frameTexture, + this.colorTexture.colorTexture, 0 ); + + if (this.gl.isWebGL2) { + this.gl.framebufferTexture2D( + this.gl.FRAMEBUFFER, + this.gl.COLOR_ATTACHMENT1, + this.gl.TEXTURE_2D, + this.distanceTexture!.colorTexture, + 0 + ); + } } } diff --git a/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts b/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts index 77dc6d1..e476941 100644 --- a/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts +++ b/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts @@ -174,9 +174,9 @@ export class UniformArrayAutoScalingProgram implements IProgram { objectMinDistance = ${ descriptors[i].sdf!.distanceFunctionName }(position, objectColor); - + color = mix( - objectColor / {paletteSize}, + objectColor, color, ${ descriptors[i].sdf?.isInverted diff --git a/src/graphics/graphics-library/texture/color-texture.ts b/src/graphics/graphics-library/texture/color-texture.ts new file mode 100644 index 0000000..eaab31b --- /dev/null +++ b/src/graphics/graphics-library/texture/color-texture.ts @@ -0,0 +1,31 @@ +import { vec2 } from 'gl-matrix'; +import { UniversalRenderingContext } from '../universal-rendering-context'; +import { Texture } from './texture'; +import { FilteringOptions } from './texture-options'; + +/** @internal */ +export class ColorTexture extends Texture { + public static readonly textureUnitId = 0; + + constructor(gl: UniversalRenderingContext) { + super(gl, ColorTexture.textureUnitId, { + minFilter: FilteringOptions.LINEAR, + maxFilter: FilteringOptions.LINEAR, + }); + } + + public setSize(size: vec2) { + this.bind(); + this.gl.texImage2D( + this.gl.TEXTURE_2D, + 0, + this.gl.RGBA, + size.x, + size.y, + 0, + this.gl.RGBA, + this.gl.UNSIGNED_BYTE, + null + ); + } +} diff --git a/src/graphics/graphics-library/texture/distance-texture.ts b/src/graphics/graphics-library/texture/distance-texture.ts new file mode 100644 index 0000000..b7ada47 --- /dev/null +++ b/src/graphics/graphics-library/texture/distance-texture.ts @@ -0,0 +1,53 @@ +import { vec2 } from 'gl-matrix'; +import { enableExtension } from '../helper/enable-extension'; +import { Texture } from './texture'; +import { FilteringOptions } from './texture-options'; + +/** @internal */ +export class DistanceTexture extends Texture { + public static readonly textureUnitId = 1; + + private floatEnabled = false; + private floatLinearEnabled = false; + + constructor(gl: WebGL2RenderingContext) { + super(gl, DistanceTexture.textureUnitId, { + minFilter: FilteringOptions.NEAREST, + maxFilter: FilteringOptions.NEAREST, + }); + + try { + enableExtension(gl, 'EXT_color_buffer_float'); + this.floatEnabled = true; + + enableExtension(gl, 'OES_texture_float_linear'); + this.floatLinearEnabled = true; + } catch { + // it's okay + } + + if (this.floatLinearEnabled) { + this.setTextureOptions({ + minFilter: FilteringOptions.LINEAR, + maxFilter: FilteringOptions.LINEAR, + }); + } + } + + public setSize(size: vec2) { + this.bind(); + this.gl.texImage2D( + this.gl.TEXTURE_2D, + 0, + this.floatEnabled ? (this.gl as WebGL2RenderingContext).R16F : this.gl.RGBA, + size.x, + size.y, + 0, + this.floatEnabled ? (this.gl as WebGL2RenderingContext).RED : this.gl.RGBA, + this.floatEnabled + ? (this.gl as WebGL2RenderingContext).FLOAT + : this.gl.UNSIGNED_BYTE, + null + ); + } +} diff --git a/src/graphics/graphics-library/texture/palette-texture.ts b/src/graphics/graphics-library/texture/palette-texture.ts index 4515730..f98dcc5 100644 --- a/src/graphics/graphics-library/texture/palette-texture.ts +++ b/src/graphics/graphics-library/texture/palette-texture.ts @@ -4,8 +4,10 @@ import { Texture } from './texture'; /** @internal */ export class PaletteTexture extends Texture { + public static readonly textureUnitId = 2; + constructor(gl: UniversalRenderingContext, private readonly paletteSize: number) { - super(gl, 1); + super(gl, PaletteTexture.textureUnitId); } public setPalette(colors: Array) { diff --git a/src/graphics/graphics-library/texture/texture.ts b/src/graphics/graphics-library/texture/texture.ts index ff9114e..8897088 100644 --- a/src/graphics/graphics-library/texture/texture.ts +++ b/src/graphics/graphics-library/texture/texture.ts @@ -1,4 +1,3 @@ -import { UniversalRenderingContext } from '../universal-rendering-context'; import { FilteringOptions, TextureOptions, WrapOptions } from './texture-options'; /** @@ -8,10 +7,17 @@ export class Texture { protected texture: WebGLTexture; constructor( - protected readonly gl: UniversalRenderingContext, + protected readonly gl: WebGLRenderingContext | WebGL2RenderingContext, private textureUnitId: number, textureOptionOverrides: Partial = {} ) { + this.texture = gl.createTexture()!; + + this.bind(); + this.setTextureOptions(textureOptionOverrides); + } + + public setTextureOptions(textureOptionOverrides: Partial = {}) { const defaultTextureOptions: TextureOptions = { wrapS: WrapOptions.CLAMP_TO_EDGE, wrapT: WrapOptions.CLAMP_TO_EDGE, @@ -24,14 +30,28 @@ export class Texture { ...textureOptionOverrides, }; - this.texture = gl.createTexture()!; - this.bind(); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl[textureOptions.wrapS]); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl[textureOptions.wrapT]); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl[textureOptions.minFilter]); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl[textureOptions.maxFilter]); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_WRAP_S, + this.gl[textureOptions.wrapS] + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_WRAP_T, + this.gl[textureOptions.wrapT] + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_MIN_FILTER, + this.gl[textureOptions.minFilter] + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_MAG_FILTER, + this.gl[textureOptions.maxFilter] + ); } public get colorTexture(): WebGLTexture { diff --git a/src/graphics/rendering/fps-autoscaler.ts b/src/graphics/rendering/fps-autoscaler.ts index c202c8b..fe85aa4 100644 --- a/src/graphics/rendering/fps-autoscaler.ts +++ b/src/graphics/rendering/fps-autoscaler.ts @@ -23,7 +23,7 @@ const settings = { finalRenderScale: 1.0, }, { - distanceRenderScale: 1.0, + distanceRenderScale: 0.5, finalRenderScale: 1.0, }, ], diff --git a/src/graphics/rendering/render-pass/distance-render-pass.ts b/src/graphics/rendering/render-pass/distance-render-pass.ts index d06f5b4..a4fc961 100644 --- a/src/graphics/rendering/render-pass/distance-render-pass.ts +++ b/src/graphics/rendering/render-pass/distance-render-pass.ts @@ -15,8 +15,11 @@ export class DistanceRenderPass extends RenderPass { this.drawables.push(drawable); } - public render(commonUniforms: any, ...inputTextures: Array) { + public render(commonUniforms: any, inputTextures: Array) { this.frame.bindAndClear(inputTextures); + if (this.gl.isWebGL2) { + this.gl.drawBuffers([this.gl.COLOR_ATTACHMENT0, this.gl.COLOR_ATTACHMENT1]); + } const stepsInUV = 1 / this.tileMultiplier; diff --git a/src/graphics/rendering/render-pass/lights-render-pass.ts b/src/graphics/rendering/render-pass/lights-render-pass.ts index fd7ac9e..cbbd33d 100644 --- a/src/graphics/rendering/render-pass/lights-render-pass.ts +++ b/src/graphics/rendering/render-pass/lights-render-pass.ts @@ -14,14 +14,7 @@ export class LightsRenderPass extends RenderPass { this.drawables.push(drawable); } - public render( - commonUniforms: any, - distanceTexture: WebGLTexture, - inputTextures: Array - ) { - this.gl.activeTexture(this.gl.TEXTURE0); - this.gl.bindTexture(this.gl.TEXTURE_2D, distanceTexture); - + public render(commonUniforms: any, inputTextures: Array) { this.frame.bindAndClear(inputTextures); const tileCenterWorldCoordinates = vec2.transformMat2d( diff --git a/src/graphics/rendering/renderer/renderer-implementation.ts b/src/graphics/rendering/renderer/renderer-implementation.ts index 231fb00..f21e8a0 100644 --- a/src/graphics/rendering/renderer/renderer-implementation.ts +++ b/src/graphics/rendering/renderer/renderer-implementation.ts @@ -2,11 +2,14 @@ import { vec2 } from 'gl-matrix'; import { Drawable } from '../../../drawables/drawable'; import { DrawableDescriptor } from '../../../drawables/drawable-descriptor'; import { LightDrawable } from '../../../drawables/lights/light-drawable'; +import { colorToString } from '../../../helper/color-to-string'; import { msToString } from '../../../helper/ms-to-string'; import { DefaultFrameBuffer } from '../../graphics-library/frame-buffer/default-frame-buffer'; import { IntermediateFrameBuffer } from '../../graphics-library/frame-buffer/intermediate-frame-buffer'; import { WebGlStopwatch } from '../../graphics-library/helper/stopwatch'; import { ParallelCompiler } from '../../graphics-library/parallel-compiler'; +import { ColorTexture } from '../../graphics-library/texture/color-texture'; +import { DistanceTexture } from '../../graphics-library/texture/distance-texture'; import { PaletteTexture } from '../../graphics-library/texture/palette-texture'; import { Texture } from '../../graphics-library/texture/texture'; import { TextureWithOptions } from '../../graphics-library/texture/texture-options'; @@ -56,12 +59,11 @@ export class RendererImplementation implements Renderer { }, tileMultiplier: (v) => (this.distancePass.tileMultiplier = v), isWorldInverted: (v) => (this.distancePass.isWorldInverted = v), - backgroundColor: (v) => (this.uniformsProvider.backgroundColor = v), textures: (v: { [textureName: string]: TexImageSource | TextureWithOptions }) => { this.textures.forEach((t) => t.destroy()); this.textures = []; - let id = 2; + let id = 3; for (const key in v) { this.uniformsProvider.textures[key] = id; let texture: Texture; @@ -113,8 +115,6 @@ export class RendererImplementation implements Renderer { vec2.fromValues(canvas.clientWidth, canvas.clientHeight) ); - this.queryPrecisions(); - this.autoscaler = new FpsAutoscaler({ distanceRenderScale: (v) => (this.distanceFieldFrameBuffer.renderScale = v as number), @@ -143,6 +143,7 @@ export class RendererImplementation implements Renderer { compiler, { paletteSize: settings.paletteSize, + backgroundColor: colorToString(settings.backgroundColor), } ) ); @@ -155,6 +156,7 @@ export class RendererImplementation implements Renderer { compiler, { shadowTraceCount: settings.shadowTraceCount.toString(), + backgroundColor: colorToString(settings.backgroundColor), } ) ); @@ -162,7 +164,7 @@ export class RendererImplementation implements Renderer { await compiler.compilePrograms(); await Promise.all(promises); - if (settings.enableStopwatch) { + if (settings.enableStopwatch && this.gl.isWebGL2) { try { this.stopwatch = new WebGlStopwatch(this.gl); } catch { @@ -179,30 +181,6 @@ export class RendererImplementation implements Renderer { return Object.prototype.hasOwnProperty.call(descriptor, 'sdf'); } - private queryPrecisions() { - const precisionToObject = (shader: GLenum, precision: GLenum) => { - const toExponent = (v: number): string => `2^${v}`; - const p = this.gl.getShaderPrecisionFormat(shader, precision)!; - return { - range: `[${toExponent(p.rangeMin)}, ${toExponent(p.rangeMax)}]`, - precision: toExponent(p.precision), - }; - }; - - Insights.setValue('precisions', { - 'vertex shader': { - 'low float': precisionToObject(this.gl.VERTEX_SHADER, this.gl.LOW_FLOAT), - 'medium float': precisionToObject(this.gl.VERTEX_SHADER, this.gl.MEDIUM_FLOAT), - 'high float': precisionToObject(this.gl.VERTEX_SHADER, this.gl.HIGH_FLOAT), - }, - 'fragment shader': { - 'low float': precisionToObject(this.gl.FRAGMENT_SHADER, this.gl.LOW_FLOAT), - 'medium float': precisionToObject(this.gl.FRAGMENT_SHADER, this.gl.MEDIUM_FLOAT), - 'high float': precisionToObject(this.gl.FRAGMENT_SHADER, this.gl.HIGH_FLOAT), - }, - }); - } - public addDrawable(drawable: Drawable): void { if ( RendererImplementation.hasSdf((drawable.constructor as typeof Drawable).descriptor) @@ -235,20 +213,23 @@ export class RendererImplementation implements Renderer { const common = { // texture units - distanceTexture: 0, - palette: 1, + distanceTexture: DistanceTexture.textureUnitId, + colorTexture: ColorTexture.textureUnitId, + palette: PaletteTexture.textureUnitId, distanceNdcPixelSize: 2 / Math.max(...this.distanceFieldFrameBuffer.getSize()), shadingNdcPixelSize: 2 / Math.max(...this.lightingFrameBuffer.getSize()), }; - this.distancePass.render(this.uniformsProvider.getUniforms(common), ...this.textures); + this.distancePass.render(this.uniformsProvider.getUniforms(common), [ + this.palette, + ...this.textures, + ]); this.gl.enable(this.gl.BLEND); this.lightsPass.render( this.uniformsProvider.getUniforms(common), - this.distanceFieldFrameBuffer.colorTexture, - [this.palette] + this.distanceFieldFrameBuffer.textures ); this.gl.disable(this.gl.BLEND); diff --git a/src/graphics/rendering/settings/default-runtime-settings.ts b/src/graphics/rendering/settings/default-runtime-settings.ts index e65f81f..bf75fa3 100644 --- a/src/graphics/rendering/settings/default-runtime-settings.ts +++ b/src/graphics/rendering/settings/default-runtime-settings.ts @@ -1,4 +1,4 @@ -import { vec3, vec4 } from 'gl-matrix'; +import { vec3 } from 'gl-matrix'; import { RuntimeSettings } from './runtime-settings'; /** @@ -9,7 +9,6 @@ export const defaultRuntimeSettings: RuntimeSettings = { tileMultiplier: 8, isWorldInverted: false, lightCutoffDistance: 400, - backgroundColor: vec4.fromValues(1, 1, 1, 1), colorPalette: [], ambientLight: vec3.fromValues(0.25, 0.15, 0.25), textures: {}, diff --git a/src/graphics/rendering/settings/default-startup-settings.ts b/src/graphics/rendering/settings/default-startup-settings.ts index 1192309..311249b 100644 --- a/src/graphics/rendering/settings/default-startup-settings.ts +++ b/src/graphics/rendering/settings/default-startup-settings.ts @@ -1,3 +1,4 @@ +import { vec4 } from 'gl-matrix'; import { StartupSettings } from './startup-settings'; /** @@ -7,5 +8,6 @@ export const defaultStartupSettings: StartupSettings = { shadowTraceCount: 16, paletteSize: 256, ignoreWebGL2: false, + backgroundColor: vec4.fromValues(1, 1, 1, 1), enableStopwatch: false, }; diff --git a/src/graphics/rendering/settings/runtime-settings.ts b/src/graphics/rendering/settings/runtime-settings.ts index ca0b0d9..f086c16 100644 --- a/src/graphics/rendering/settings/runtime-settings.ts +++ b/src/graphics/rendering/settings/runtime-settings.ts @@ -38,18 +38,13 @@ export interface RuntimeSettings { */ lightCutoffDistance: number; - /** - * The default background color of the scene, can have transparency. - */ - backgroundColor: vec3 | vec4; - /** * Its length should be less than the one specified in [[StartupSettings]].paletteSize. * * The possible colors for the objects. Each color is referenced by its index in the * palette. * - * Can have transparency. + * Can have transparency, but only if WebGL2 support is enabled. */ colorPalette: Array; diff --git a/src/graphics/rendering/settings/startup-settings.ts b/src/graphics/rendering/settings/startup-settings.ts index ca85185..31f6a4c 100644 --- a/src/graphics/rendering/settings/startup-settings.ts +++ b/src/graphics/rendering/settings/startup-settings.ts @@ -1,3 +1,5 @@ +import { vec3, vec4 } from 'gl-matrix'; + /** * Interface for a configuration object containing the settings * that need to be given before shader compilation. @@ -31,6 +33,11 @@ export interface StartupSettings { */ paletteSize: number; + /** + * The default background color of the scene, can have transparency on every platform. + */ + backgroundColor: vec3 | vec4; + /** * When set to `true`, rendering will fall back to WebGL * even when WebGL2 is present. diff --git a/src/graphics/rendering/shaders/distance-fs-100.glsl b/src/graphics/rendering/shaders/distance-fs-100.glsl index 0a6a1b5..f1442cc 100644 --- a/src/graphics/rendering/shaders/distance-fs-100.glsl +++ b/src/graphics/rendering/shaders/distance-fs-100.glsl @@ -6,17 +6,23 @@ uniform float maxMinDistance; uniform float distanceNdcPixelSize; varying vec2 position; +uniform sampler2D palette; + +vec4 readFromPalette(int index) { + return texture2D(palette, vec2((float(index) + 0.5) / {paletteSize}, 0.5)); +} + + {macroDefinitions} {declarations} void main() { - float minDistance = maxMinDistance; - float color = 0.0; - - float objectMinDistance, objectColor; + float minDistance = maxMinDistance, objectMinDistance; + vec4 color = {backgroundColor}; + vec4 objectColor; {functionCalls} - gl_FragColor = vec4(minDistance * 8.0, color, 0.0, 1.0); + gl_FragColor = vec4(color.rgb, minDistance * 8.0); } diff --git a/src/graphics/rendering/shaders/distance-fs.glsl b/src/graphics/rendering/shaders/distance-fs.glsl index 6b1e33a..1b0ad90 100644 --- a/src/graphics/rendering/shaders/distance-fs.glsl +++ b/src/graphics/rendering/shaders/distance-fs.glsl @@ -6,21 +6,28 @@ uniform float maxMinDistance; uniform float distanceNdcPixelSize; in vec2 position; +uniform sampler2D palette; + #define WEBGL2_IS_AVAILABLE +vec4 readFromPalette(int index) { + return texture(palette, vec2((float(index) + 0.5) / {paletteSize}, 0.5)); +} + {macroDefinitions} {declarations} -out vec2 fragmentColor; +layout(location = 0) out vec4 fragmentColor; +layout(location = 1) out float distanceValue; void main() { - float minDistance = maxMinDistance; - float color = 0.0; - - float objectMinDistance, objectColor; + float minDistance = maxMinDistance, objectMinDistance; + vec4 color = {backgroundColor}; + vec4 objectColor; {functionCalls} - fragmentColor = vec2(minDistance, color); + distanceValue = minDistance; + fragmentColor = color; } diff --git a/src/graphics/rendering/shaders/shading-fs-100.glsl b/src/graphics/rendering/shaders/shading-fs-100.glsl index 1b9f502..db05b9f 100644 --- a/src/graphics/rendering/shaders/shading-fs-100.glsl +++ b/src/graphics/rendering/shaders/shading-fs-100.glsl @@ -10,22 +10,20 @@ precision lowp float; uniform float shadingNdcPixelSize; uniform vec2 squareToAspectRatioTimes2; uniform vec3 ambientLight; -uniform vec4 backgroundColor; -uniform sampler2D distanceTexture; -uniform sampler2D palette; +uniform sampler2D colorTexture; varying vec2 position; varying vec2 uvCoordinates; float getDistance(in vec2 target, out vec4 color) { - vec4 values = texture2D(distanceTexture, target); - color = texture2D(palette, vec2(values[1], 0.0)); - return values[0] / 8.0; + vec4 values = texture2D(colorTexture, target); + color = vec4(values.rgb, 1.0); + return values[3] / 8.0; } float getDistance(in vec2 target) { - return texture2D(distanceTexture, target)[0] / 8.0; + return texture2D(colorTexture, target)[3] / 8.0; } float shadowTransparency(float startingDistance, float lightCenterDistance, vec2 direction) { @@ -122,13 +120,13 @@ void main() { #endif #endif - vec3 outsideColor = backgroundColor.rgb * lighting; + vec3 outsideColor = {backgroundColor}.rgb * lighting; vec3 insideColor = colorAtPosition * lightingInside; float edge = clamp(startingDistance / shadingNdcPixelSize, 0.0, 1.0); vec3 antialiasedColor = mix(insideColor, outsideColor, edge); gl_FragColor = vec4( antialiasedColor, - mix(rgbaColorAtPosition.a, backgroundColor.a, step(0.0, startingDistance)) + rgbaColorAtPosition.a ); } diff --git a/src/graphics/rendering/shaders/shading-fs.glsl b/src/graphics/rendering/shaders/shading-fs.glsl index 4798db2..9050a78 100644 --- a/src/graphics/rendering/shaders/shading-fs.glsl +++ b/src/graphics/rendering/shaders/shading-fs.glsl @@ -8,23 +8,21 @@ precision lowp float; {macroDefinitions} uniform float shadingNdcPixelSize; +uniform float distanceNdcPixelSize; uniform vec2 squareToAspectRatioTimes2; uniform vec3 ambientLight; -uniform vec4 backgroundColor; uniform sampler2D distanceTexture; -uniform sampler2D palette; +uniform sampler2D colorTexture; in vec2 position; in vec2 uvCoordinates; -float getDistance(in vec2 target, out vec4 color) { - vec4 values = texture(distanceTexture, target); - color = texture(palette, vec2(values[1], 0.0)); - return values[0]; +vec4 getColor(vec2 target) { + return texture(colorTexture, target); } -float getDistance(in vec2 target) { +float getDistance(vec2 target) { return texture(distanceTexture, target)[0]; } @@ -83,13 +81,14 @@ float shadowTransparency(float startingDistance, float lightCenterDistance, vec2 out vec4 fragmentColor; void main() { - vec4 rgbaColorAtPosition; - float startingDistance = getDistance(uvCoordinates, rgbaColorAtPosition); - + vec4 rgbaColorAtPosition = getColor(uvCoordinates); vec3 colorAtPosition = rgbaColorAtPosition.rgb; + float startingDistance = getDistance(uvCoordinates); + + vec3 lighting = ambientLight; - vec3 lightingInside = lighting; + vec3 lightingInside = ambientLight; #ifdef CIRCLE_LIGHT_COUNT #if CIRCLE_LIGHT_COUNT > 0 @@ -142,13 +141,13 @@ void main() { #endif #endif - vec3 outsideColor = backgroundColor.rgb * lighting; + vec3 outsideColor = {backgroundColor}.rgb * lighting; vec3 insideColor = colorAtPosition * lightingInside * INTENSITY_INSIDE_RATIO; - + float edge = clamp(startingDistance / shadingNdcPixelSize, 0.0, 1.0); vec3 antialiasedColor = mix(insideColor, outsideColor, edge); fragmentColor = vec4( antialiasedColor, - mix(rgbaColorAtPosition.a, backgroundColor.a, step(0.0, startingDistance)) + rgbaColorAtPosition.a ); } diff --git a/src/graphics/rendering/uniforms-provider.ts b/src/graphics/rendering/uniforms-provider.ts index 2281910..c85b308 100644 --- a/src/graphics/rendering/uniforms-provider.ts +++ b/src/graphics/rendering/uniforms-provider.ts @@ -1,10 +1,9 @@ -import { mat2d, vec2, vec3, vec4 } from 'gl-matrix'; +import { mat2d, vec2, vec3 } from 'gl-matrix'; import { UniversalRenderingContext } from '../graphics-library/universal-rendering-context'; /** @internal */ export class UniformsProvider { public ambientLight!: vec3; - public _backgroundColor!: vec4; public textures: { [textureName: string]: number } = {}; private scaleWorldLengthToNDC = 1; @@ -21,7 +20,6 @@ export class UniformsProvider { ...uniforms, ...this.textures, ambientLight: this.ambientLight, - backgroundColor: this._backgroundColor, uvToWorld: this.uvToWorld, worldAreaInView: this.worldAreaInView, squareToAspectRatio: this.squareToAspectRatio, @@ -31,14 +29,6 @@ export class UniformsProvider { }; } - public set backgroundColor(value: vec3 | vec4) { - if (value.length === 3) { - this.backgroundColor = vec4.fromValues(value[0], value[1], value[2], 1); - } else { - this._backgroundColor = value as vec4; - } - } - public getViewArea(): vec2 { return this.worldAreaInView; } diff --git a/src/helper/code-for-color-access.ts b/src/helper/code-for-color-access.ts new file mode 100644 index 0000000..380f3c8 --- /dev/null +++ b/src/helper/code-for-color-access.ts @@ -0,0 +1,13 @@ +import { vec3, vec4 } from 'gl-matrix'; +import { colorToString } from './color-to-string'; + +/** + * @internal + */ +export const codeForColorAccess = (color: vec3 | vec4 | number): string => { + if (color instanceof Array || color instanceof Float32Array) { + return colorToString(color); + } + + return `readFromPalette(${color})`; +}; diff --git a/src/helper/color-to-string.ts b/src/helper/color-to-string.ts new file mode 100644 index 0000000..28ea5dd --- /dev/null +++ b/src/helper/color-to-string.ts @@ -0,0 +1,7 @@ +import { vec3, vec4 } from 'gl-matrix'; + +/** + * @internal + */ +export const colorToString = (v: vec3 | vec4): string => + `vec4(${v[0]}, ${v[1]}, ${v[2]}, ${v.length > 3 ? v[3] : 1})`; diff --git a/src/main.ts b/src/main.ts index d0f61e2..326a043 100644 --- a/src/main.ts +++ b/src/main.ts @@ -40,9 +40,10 @@ applyArrayPlugins(); * Example usage: * * ```js - * import { compile, Circle, CircleLight } from 'sdf-2d'; + * import { compile, hsl, CircleFactory, CircleLight } from 'sdf-2d'; * * const canvas = document.querySelector('canvas'); + * const Circle = CircleFactory(hsl(30, 66, 50)); * const renderer = await compile(canvas, [Circle.descriptor, CircleLight.descriptor]); * ``` * @@ -67,12 +68,19 @@ export * from './drawables/drawable'; export * from './drawables/drawable-descriptor'; export * from './drawables/lights/circle-light'; export * from './drawables/lights/flashlight'; -export * from './drawables/shapes/circle'; -export * from './drawables/shapes/droplet'; +export * from './drawables/shapes/circle-factory'; +export * from './drawables/shapes/droplet-factory'; +export * from './drawables/shapes/inverted-tunnel-factory'; +export * from './drawables/shapes/meta-circle-factory'; +export * from './drawables/shapes/noisy-polygon-factory'; export * from './drawables/shapes/polygon-factory'; -export * from './drawables/shapes/inverted-tunnel'; -export * from './drawables/shapes/meta-circle'; -export * from './drawables/shapes/rotated-rectangle'; +export * from './drawables/shapes/rotated-rectangle-factory'; export * from './graphics/graphics-library/texture/texture-options'; export * from './graphics/rendering/renderer/noise-renderer'; export * from './graphics/rendering/renderer/renderer'; +export * from './helper/colors/hex'; +export * from './helper/colors/hsl'; +export * from './helper/colors/rgb'; +export * from './helper/colors/rgb255'; +export * from './helper/colors/rgba'; +export * from './helper/colors/rgba255';