Skip to content

Commit

Permalink
feat: enhance renderer (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
LuciNyan authored Apr 4, 2024
1 parent 6fb7097 commit cfb5551
Show file tree
Hide file tree
Showing 32 changed files with 100 additions and 34 deletions.
2 changes: 2 additions & 0 deletions packages/pixel-profile/src/cards/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Resvg } from '@resvg/resvg-js'
import { readFile } from 'node:fs/promises'
import { join } from 'node:path'
import satori from 'satori'
// import {glow} from "../shaders/glow";

export type Stats = {
name: string
Expand Down Expand Up @@ -149,6 +150,7 @@ export async function renderStats(stats: Stats, options: Options = {}): Promise<

if (screenEffect) {
pixels = scanline(pixels, width, height)
// pixels = glow(pixels, width, height)
pixels = curve(pixels, width, height)
}

Expand Down
14 changes: 11 additions & 3 deletions packages/pixel-profile/src/renderer/render.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { coordsToIndex, FragShader } from './common'
import { clamp } from '../utils'
import { Coordinates, coordsToIndex, FragShader, RGBA } from './common'
import { TEXTURE_FILTER, textureFilterGeneratorByName, TextureFilterName } from './texture-filter'

type Options = {
Expand All @@ -18,11 +19,18 @@ export function render(
const maxX = width - 1
const maxY = height - 1

const texture2D = textureFilterGeneratorByName[textureFilter](pixels, width, height)
const textureFilterFn = textureFilterGeneratorByName[textureFilter](pixels, width, height)

function texture2D(coords: Coordinates): RGBA {
coords[0] = clamp(coords[0], 0, maxX)
coords[1] = clamp(coords[1], 0, maxY)

return textureFilterFn(coords)
}

for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const rgba = fragShader([x / maxX, y / maxY], texture2D)
const rgba = fragShader([x, y], texture2D)
const index = coordsToIndex(x, y, width)
target[index] = rgba[0]
target[index + 1] = rgba[1]
Expand Down
7 changes: 2 additions & 5 deletions packages/pixel-profile/src/renderer/texture-filter/linear.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@ export function genBiLinearFilter(pixels: Buffer, width: number, height: number)
return tmp1 * (1 - sy) + tmp2 * sy
}
function biLinearFilter(coords: Coordinates): RGBA {
coords[0] = clamp(coords[0], 0, 1)
coords[1] = clamp(coords[1], 0, 1)

const x = coords[0] * maxX
const y = coords[1] * maxY
const x = coords[0]
const y = coords[1]
const x0 = clamp(Math.floor(x), 0, maxX)
const x1 = clamp(x0 + 1, 0, maxX)
const y0 = clamp(Math.floor(y), 0, maxY)
Expand Down
16 changes: 3 additions & 13 deletions packages/pixel-profile/src/renderer/texture-filter/nearest.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import { clamp } from '../../utils'
import { Coordinates, coordsToPixel, RGBA, Texture2D } from '../common'

export function genNearestNeighborFilter(pixels: Buffer, width: number, height: number): Texture2D {
const maxX = width - 1
const maxY = height - 1

export function genNearestNeighborFilter(pixels: Buffer, width: number): Texture2D {
function nearestNeighborFilter(coords: Coordinates): RGBA {
coords[0] = clamp(coords[0], 0, 1)
coords[1] = clamp(coords[1], 0, 1)

const x = coords[0] * maxX
const y = coords[1] * maxY

const nearestX = Math.round(x)
const nearestY = Math.round(y)
const nearestX = Math.round(coords[0])
const nearestY = Math.round(coords[1])

return coordsToPixel(pixels, nearestX, nearestY, width)
}
Expand Down
4 changes: 2 additions & 2 deletions packages/pixel-profile/src/shaders/border.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export function addBorder(
(uv, texture2D) => {
const maxX = width - 1
const maxY = height - 1
const x = uv[0] * maxX
const y = uv[1] * maxY
const x = uv[0]
const y = uv[1]

const frameWidth = frameWidthRatio * width

Expand Down
11 changes: 8 additions & 3 deletions packages/pixel-profile/src/shaders/curve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ const margin = [0, 0]
const screenCurvature = 0.1

export function curve(source: Buffer, width: number, height: number): Buffer {
return render(source, width, height, (uv, texture2D) => {
return render(source, width, height, (xy, texture2D) => {
const uv = [xy[0] / width, xy[1] / height]

const maxX = width - 1
const maxY = height - 1

function distortCoordinates(coords: Coordinates): Vec2 {
const cc = subtract2(coords, [0.5, 0.5])
const dist = dot2(cc, cc) * screenCurvature
Expand All @@ -17,15 +22,15 @@ export function curve(source: Buffer, width: number, height: number): Buffer {
return add2(coords, cc)
}

const coords = distortCoordinates(uv)
const coords = distortCoordinates([uv[0], uv[1]])

coords[0] = coords[0] * (margin[0] * 2 + 1) - margin[0]
coords[1] = coords[1] * (margin[1] * 2 + 1) - margin[1]

const vignetteCoords: Vec2 = [uv[0] * (1 - uv[1]), uv[1] * (1 - uv[0])]
const vignette = Math.pow(prod2(vignetteCoords) * 15, 0.25)

const samplerColor = texture2D(coords)
const samplerColor = texture2D([coords[0] * maxX, coords[1] * maxY])

return [samplerColor[0] * vignette, samplerColor[1] * vignette, samplerColor[2] * vignette, 255]
})
Expand Down
49 changes: 49 additions & 0 deletions packages/pixel-profile/src/shaders/glow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { render } from '../renderer'
import { add2, Vec2 } from '../utils'
import { add3, divide3, dot3, mix3, Vec3 } from '../utils/math'

const radius = 10
const intensity = 1
const threshold = 0.9
const _threshold = threshold * 255

export function glow(source: Buffer, width: number, height: number): Buffer {
return render(
source,
width,
height,
(uv, texture2D) => {
const originalColor = texture2D(uv)

let bloomColor: Vec3 = [0, 0, 0]
let n = 0

for (let i = -radius; i <= radius; i++) {
for (let j = -radius; j <= radius; j++) {
const offset: Vec2 = [i / width, j / height]
const sampledColor = texture2D(add2(uv, offset))
const luminance = dot3(sampledColor, [0.2126, 0.7152, 0.0722])
if (luminance > _threshold) {
bloomColor = add3(bloomColor, sampledColor)
n++
}
}
}

if (n === 0) {
return originalColor
}

bloomColor = divide3(bloomColor, n)

const _bloomIntensity = intensity * (n / Math.pow(radius * 2 + 1, 2))

const finalColor = mix3(originalColor, bloomColor, _bloomIntensity)

return [finalColor[0], finalColor[1], finalColor[2], 255]
},
{
textureFilter: 'NEAREST'
}
)
}
8 changes: 3 additions & 5 deletions packages/pixel-profile/src/shaders/pixelate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ import { render } from '../renderer'

export function pixelate(source: Buffer, width: number, height: number, blockSize: number): Buffer {
return render(source, width, height, (uv, texture2D) => {
const blockW = blockSize / width
const blockH = blockSize / height
const x = Math.floor(uv[0] / blockW)
const y = Math.floor(uv[1] / blockH)
const x = Math.floor(uv[0] / blockSize)
const y = Math.floor(uv[1] / blockSize)

return texture2D([x * blockW + blockW / 2, y * blockH + blockH / 2])
return texture2D([x * blockSize + blockSize / 2, y * blockSize + blockSize / 2])
})
}
4 changes: 1 addition & 3 deletions packages/pixel-profile/src/shaders/scanline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ const scanlineThickness = 3

export function scanline(source: Buffer, width: number, height: number): Buffer {
return render(source, width, height, (uv, texture2D) => {
const scanlinePosition = Math.floor(uv[1] * height)

const onScanline = scanlinePosition % scanlineThickness === 0
const onScanline = uv[1] % scanlineThickness === 0

const samplerColor = texture2D(uv)

Expand Down
19 changes: 19 additions & 0 deletions packages/pixel-profile/src/utils/math.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { RGBA } from '../renderer'

export type Vec2 = [number, number]
export type Vec3 = [number, number, number]

export function clamp(x: number, min: number, max: number): number {
return Math.min(max, Math.max(min, x))
Expand All @@ -25,3 +28,19 @@ export function dot2(a: Vec2, b: Vec2): number {
export function prod2(v: Vec2): number {
return v[0] * v[1]
}

export function add3(a: Vec3 | RGBA, b: Vec3 | RGBA): Vec3 {
return [a[0] + b[0], a[1] + b[1], a[2] + b[2]]
}

export function dot3(v1: Vec3 | RGBA, v2: Vec3 | RGBA): number {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
}

export function divide3(v: Vec3 | RGBA, scalar: number): Vec3 {
return [v[0] / scalar, v[1] / scalar, v[2] / scalar]
}

export function mix3(v1: Vec3 | RGBA, v2: Vec3 | RGBA, t: number): Vec3 {
return [v1[0] * (1 - t) + v2[0] * t, v1[1] * (1 - t) + v2[1] * t, v1[2] * (1 - t) + v2[2] * t]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit cfb5551

Please sign in to comment.