-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
Merge branch 'main' into release
Showing
43 changed files
with
596 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
## [0.1.0] | ||
- 首次發布測試版 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,20 @@ | ||
# Maple Character Creator | ||
# MapleSalon2 | ||
Salon Simulator for Maplestory, preview all of hair cut or eyes color and all mix dye recipe. | ||
|
||
Now also able to simulate item dye! and preview all action. | ||
|
||
## Screenshot | ||
![](./doc/preview_app.png) | ||
|
||
## Download | ||
All download avaiable at [Releases page](./releases). | ||
|
||
Installer will only check `Webview` and extract the app exe to desire folder, fell free to move it anywhere. | ||
|
||
## Build it manually | ||
Make sure you have environment below. | ||
- Rust 1.70.0 or higher | ||
- Node.js 16 or higher | ||
|
||
then | ||
> npm run tauri build |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
{ | ||
"productName": "MapleSalon2", | ||
"version": "0.0.0", | ||
"identifier": "com.maplecreator.io", | ||
"version": "0.1.0", | ||
"identifier": "com.maplesalon.io", | ||
"build": { | ||
"beforeDevCommand": "npm run dev", | ||
"devUrl": "http://localhost:1420", | ||
|
@@ -29,6 +29,14 @@ | |
"icons/[email protected]", | ||
"icons/icon.icns", | ||
"icons/icon.ico" | ||
] | ||
], | ||
"windows": { | ||
"nsis": { | ||
"languages": ["English", "TradChinese"] | ||
}, | ||
"wix": { | ||
"language": ["en-US", "zh-TW", "zh-CN"] | ||
} | ||
} | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Show } from 'solid-js'; | ||
import { useStore } from '@nanostores/solid'; | ||
|
||
import { $enableExperimentalUpscale } from '@/store/settingDialog'; | ||
import { $showUpscaledCharacter } from '@/store/trigger'; | ||
|
||
import { Switch, type ChangeDetails } from '@/components/ui/switch'; | ||
|
||
export const ShowUpscaleSwitch = () => { | ||
const isEnable = useStore($enableExperimentalUpscale); | ||
const isShow = useStore($showUpscaledCharacter); | ||
|
||
function handleChange(details: ChangeDetails) { | ||
$showUpscaledCharacter.set(details.checked); | ||
} | ||
|
||
return ( | ||
<Show when={isEnable()}> | ||
<Switch checked={isShow()} onCheckedChange={handleChange}> | ||
顯示高清化 | ||
</Switch> | ||
</Show> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { onMount, onCleanup, createEffect, createSignal } from 'solid-js'; | ||
|
||
import { $upscaleSource } from '@/store/expirement/upscale'; | ||
import { usePureStore } from '@/store'; | ||
|
||
import { | ||
PipelineType, | ||
createGpuDevice, | ||
createRendererWithPipelines, | ||
type GpuResource, | ||
type Anime4KRenderer, | ||
type PipelineOption, | ||
} from '@/renderer/filter/anime4k'; | ||
|
||
import { toaster } from '@/components/GlobalToast'; | ||
|
||
export const UpscaleCharacter = () => { | ||
const source = usePureStore($upscaleSource); | ||
const [isInit, setIsInit] = createSignal<boolean>(false); | ||
let canvasRef!: HTMLCanvasElement; | ||
let requestId: number | null = null; | ||
let gpuResource: GpuResource | null = null; | ||
let renderer: Anime4KRenderer | null = null; | ||
const useType: (PipelineOption | PipelineType)[] = [ | ||
{ | ||
pipeline: PipelineType.BilateralMean, | ||
params: { | ||
strength: 0.2, | ||
strength2: 1, | ||
}, | ||
}, | ||
{ | ||
pipeline: PipelineType.Dog, | ||
params: { | ||
strength: 2, | ||
}, | ||
}, | ||
PipelineType.CNNSoftVL, | ||
]; | ||
|
||
onMount(async () => { | ||
const soruceCanvas = source(); | ||
if (!soruceCanvas) { | ||
return; | ||
} | ||
try { | ||
gpuResource = await createGpuDevice(canvasRef); | ||
|
||
renderer = await createRendererWithPipelines(soruceCanvas, canvasRef, { | ||
...gpuResource, | ||
pipelines: useType, | ||
}); | ||
setIsInit(true); | ||
} catch (e) { | ||
console.error(e); | ||
toaster.error({ | ||
title: '無法初始化 WebGPU', | ||
description: '請確保您的 Webview 版本支援 WebGPU。', | ||
}); | ||
} | ||
}); | ||
|
||
onCleanup(() => { | ||
if (requestId) { | ||
cancelAnimationFrame(requestId); | ||
} | ||
if (gpuResource) { | ||
gpuResource.context.unconfigure(); | ||
} | ||
}); | ||
|
||
createEffect(async () => { | ||
if (!isInit()) { | ||
return; | ||
} | ||
const sourceCanvas = source(); | ||
function frame() { | ||
if (renderer && sourceCanvas) { | ||
renderer.updateFrameTexture(); | ||
renderer.render(); | ||
} | ||
} | ||
function loop() { | ||
frame(); | ||
requestId = requestAnimationFrame(loop); | ||
} | ||
requestId = requestAnimationFrame(loop); | ||
}); | ||
|
||
return <canvas ref={canvasRef} width="300" height="340" />; | ||
}; |
31 changes: 31 additions & 0 deletions
31
src/components/dialog/SettingDialog/RenderSetting/UpscaleSwitch.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { useStore } from '@nanostores/solid'; | ||
|
||
import { | ||
$enableExperimentalUpscale, | ||
setEnableExperimentalUpscale, | ||
} from '@/store/settingDialog'; | ||
|
||
import { HStack } from 'styled-system/jsx/hstack'; | ||
import { Text } from '@/components/ui/text'; | ||
import { Switch, type ChangeDetails } from '@/components/ui/switch'; | ||
import { SettingTooltip } from '@/components/dialog/SettingDialog/SettingTooltip'; | ||
|
||
export const UpscaleSwitch = () => { | ||
const enableExperimentalUpscale = useStore($enableExperimentalUpscale); | ||
|
||
function handleChange(details: ChangeDetails) { | ||
setEnableExperimentalUpscale(details.checked); | ||
} | ||
|
||
return ( | ||
<Switch | ||
checked={enableExperimentalUpscale()} | ||
onCheckedChange={handleChange} | ||
> | ||
<HStack gap="1"> | ||
<Text>實驗性高清預覽</Text> | ||
<SettingTooltip tooltip="新增按鈕顯示高清化的角色預覽,開啟時顯示高清版(Anime4K)的圖片在旁邊,此功能可能造成極大的效能影響,請確認有足夠的電腦資源再使用" /> | ||
</HStack> | ||
</Switch> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
struct VertexOutput { | ||
@builtin(position) Position : vec4<f32>, | ||
@location(0) fragUV : vec2<f32>, | ||
} | ||
|
||
@vertex | ||
fn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput { | ||
const pos = array( | ||
vec2( 1.0, 1.0), | ||
vec2( 1.0, -1.0), | ||
vec2(-1.0, -1.0), | ||
vec2( 1.0, 1.0), | ||
vec2(-1.0, -1.0), | ||
vec2(-1.0, 1.0), | ||
); | ||
|
||
const uv = array( | ||
vec2(1.0, 0.0), | ||
vec2(1.0, 1.0), | ||
vec2(0.0, 1.0), | ||
vec2(1.0, 0.0), | ||
vec2(0.0, 1.0), | ||
vec2(0.0, 0.0), | ||
); | ||
|
||
var output : VertexOutput; | ||
output.Position = vec4(pos[VertexIndex], 0.0, 1.0); | ||
output.fragUV = uv[VertexIndex]; | ||
return output; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,311 @@ | ||
import type { Anime4KPipeline } from 'anime4k-webgpu'; | ||
import fullscreenTexturedQuadVert from './fullscreenTexturedQuad.wgsl'; | ||
import sampleExternalTextureFrag from './sampleExternalTexture.wgsl'; | ||
|
||
type Anime4kPipelineConstructor = new (desc: { | ||
device: GPUDevice; | ||
inputTexture: GPUTexture; | ||
nativeDimensions?: { width: number; height: number }; | ||
targetDimensions?: { width: number; height: number }; | ||
}) => Anime4KPipeline; | ||
|
||
export enum PipelineType { | ||
/** | ||
* deblur, must set param: strength | ||
* | ||
* @param strength Deblur Strength (0.1 - 15.0) | ||
*/ | ||
Dog = 'Dog', | ||
/** | ||
* denoise, must set param: strength, strength2 | ||
* | ||
* @param strength Itensity Sigma (0.1 - 2.0) | ||
* @param strength2 Spatial Sigma (1 - 15) | ||
*/ | ||
BilateralMean = 'BilateralMean', | ||
|
||
/** restore */ | ||
CNNM = 'CNNM', | ||
/** restore */ | ||
CNNSoftM = 'CNNSoftM', | ||
/** restore */ | ||
CNNSoftVL = 'CNNSoftVL', | ||
/** restore */ | ||
CNNVL = 'CNNVL', | ||
/** restore */ | ||
CNNUL = 'CNNUL', | ||
/** restore */ | ||
GANUUL = 'GANUUL', | ||
|
||
/** upscale */ | ||
CNNx2M = 'CNNx2M', | ||
/** upscale */ | ||
CNNx2VL = 'CNNx2VL', | ||
/** upscale */ | ||
DenoiseCNNx2VL = 'DenoiseCNNx2VL', | ||
/** upscale */ | ||
CNNx2UL = 'CNNx2UL', | ||
/** upscale */ | ||
GANx3L = 'GANx3L', | ||
/** upscale */ | ||
GANx4UUL = 'GANx4UUL', | ||
|
||
ClampHighlights = 'ClampHighlights', | ||
DepthToSpace = 'DepthToSpace', | ||
|
||
/* anime4k preset @see https://github.com/bloc97/Anime4K/blob/master/md/GLSL_Instructions_Advanced.md */ | ||
/** Restore -> Upscale -> Upscale */ | ||
ModeA = 'ModeA', | ||
/** Restore_Soft -> Upscale -> Upscale */ | ||
ModeB = 'ModeB', | ||
/** Upscale_Denoise -> Upscale */ | ||
ModeC = 'ModeC', | ||
/** Restore -> Upscale -> Restore -> Upscale */ | ||
ModeAA = 'ModeAA', | ||
/** Restore_Soft -> Upscale -> Restore_Soft -> Upscale */ | ||
ModeBB = 'ModeBB', | ||
/** Upscale_Denoise -> Restore -> Upscale */ | ||
ModeCA = 'ModeCA', | ||
} | ||
|
||
const PipelineMap: Record<PipelineType, () => Promise<unknown>> = { | ||
[PipelineType.Dog]: () => import('anime4k-webgpu').then((m) => m.DoG), | ||
[PipelineType.BilateralMean]: () => | ||
import('anime4k-webgpu').then((m) => m.BilateralMean), | ||
|
||
[PipelineType.CNNM]: () => import('anime4k-webgpu').then((m) => m.CNNM), | ||
[PipelineType.CNNSoftM]: () => | ||
import('anime4k-webgpu').then((m) => m.CNNSoftM), | ||
[PipelineType.CNNSoftVL]: () => | ||
import('anime4k-webgpu').then((m) => m.CNNSoftVL), | ||
[PipelineType.CNNVL]: () => import('anime4k-webgpu').then((m) => m.CNNVL), | ||
[PipelineType.CNNUL]: () => import('anime4k-webgpu').then((m) => m.CNNUL), | ||
[PipelineType.GANUUL]: () => import('anime4k-webgpu').then((m) => m.GANUUL), | ||
|
||
[PipelineType.CNNx2M]: () => import('anime4k-webgpu').then((m) => m.CNNx2M), | ||
[PipelineType.CNNx2VL]: () => import('anime4k-webgpu').then((m) => m.CNNx2VL), | ||
[PipelineType.DenoiseCNNx2VL]: () => | ||
import('anime4k-webgpu').then((m) => m.DenoiseCNNx2VL), | ||
[PipelineType.CNNx2UL]: () => import('anime4k-webgpu').then((m) => m.CNNx2UL), | ||
[PipelineType.GANx3L]: () => import('anime4k-webgpu').then((m) => m.GANx3L), | ||
[PipelineType.GANx4UUL]: () => | ||
import('anime4k-webgpu').then((m) => m.GANx4UUL), | ||
|
||
[PipelineType.ClampHighlights]: () => | ||
import('anime4k-webgpu').then((m) => m.ClampHighlights), | ||
[PipelineType.DepthToSpace]: () => | ||
import('anime4k-webgpu').then((m) => m.DepthToSpace), | ||
|
||
[PipelineType.ModeA]: () => import('anime4k-webgpu').then((m) => m.ModeA), | ||
[PipelineType.ModeB]: () => import('anime4k-webgpu').then((m) => m.ModeB), | ||
[PipelineType.ModeC]: () => import('anime4k-webgpu').then((m) => m.ModeC), | ||
[PipelineType.ModeAA]: () => import('anime4k-webgpu').then((m) => m.ModeAA), | ||
[PipelineType.ModeBB]: () => import('anime4k-webgpu').then((m) => m.ModeBB), | ||
[PipelineType.ModeCA]: () => import('anime4k-webgpu').then((m) => m.ModeCA), | ||
}; | ||
|
||
export type GpuResource = { | ||
device: GPUDevice; | ||
context: GPUCanvasContext; | ||
}; | ||
|
||
export async function createGpuDevice(canvas: HTMLCanvasElement) { | ||
const adapter = await navigator.gpu.requestAdapter(); | ||
if (!adapter) { | ||
throw new Error('WebGPU is not supported'); | ||
} | ||
const device = await adapter.requestDevice(); | ||
const context = canvas.getContext('webgpu') as GPUCanvasContext; | ||
const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); | ||
context.configure({ | ||
device, | ||
format: presentationFormat, | ||
alphaMode: 'premultiplied', | ||
}); | ||
|
||
return { device, context }; | ||
} | ||
|
||
export interface PipelineOption { | ||
pipeline: PipelineType; | ||
params: Record<string, number>; | ||
} | ||
|
||
export interface CreateRendererOptions { | ||
device: GPUDevice; | ||
context: GPUCanvasContext; | ||
pipelines: (PipelineType | PipelineOption)[]; | ||
} | ||
|
||
export type Anime4KRenderer = { | ||
render: () => void; | ||
updateFrameTexture: () => void; | ||
}; | ||
|
||
export async function createRendererWithPipelines( | ||
sourceCanvas: HTMLCanvasElement, | ||
destCanvas: HTMLCanvasElement, | ||
options: CreateRendererOptions, | ||
) { | ||
const { device, context, pipelines } = options; | ||
const { width: WIDTH, height: HEIGHT } = sourceCanvas; | ||
|
||
destCanvas.width = WIDTH; | ||
destCanvas.height = HEIGHT; | ||
|
||
const mainTexture = device.createTexture({ | ||
size: [WIDTH, HEIGHT, 1], | ||
format: 'rgba16float', | ||
usage: | ||
GPUTextureUsage.TEXTURE_BINDING | | ||
GPUTextureUsage.COPY_DST | | ||
GPUTextureUsage.RENDER_ATTACHMENT, | ||
}); | ||
|
||
const loadPipelines = await Promise.all( | ||
pipelines.map((pipeline) => { | ||
if (typeof pipeline === 'string') { | ||
return PipelineMap[pipeline](); | ||
} | ||
return PipelineMap[pipeline.pipeline](); | ||
}), | ||
); | ||
|
||
const pipelineChain: Anime4KPipeline[] = loadPipelines.reduce( | ||
(chain: Anime4KPipeline[], pipeline, index) => { | ||
const inputTexture = | ||
index === 0 ? mainTexture : chain[index - 1].getOutputTexture(); | ||
const pipeClass = pipeline as Anime4kPipelineConstructor; | ||
const pipeOption = pipelines[index]; | ||
const pipe = new pipeClass({ | ||
device, | ||
inputTexture, | ||
nativeDimensions: { width: WIDTH, height: HEIGHT }, | ||
targetDimensions: { width: WIDTH, height: HEIGHT }, | ||
}); | ||
if (typeof pipeOption !== 'string' && pipeOption.params) { | ||
for (const [key, value] of Object.entries(pipeOption.params)) { | ||
pipe.updateParam(key, value); | ||
} | ||
} | ||
chain.push(pipe); | ||
return chain; | ||
}, | ||
[] as Anime4KPipeline[], | ||
); | ||
|
||
const lastPipeline = pipelineChain[pipelineChain.length - 1]; | ||
// const lastTexture = lastPipeline.getOutputTexture(); | ||
// destCanvas.width = lastTexture.width; | ||
// destCanvas.height = lastTexture.height; | ||
|
||
// render pipeline setups | ||
const renderBindGroupLayout = device.createBindGroupLayout({ | ||
label: 'Render Bind Group Layout', | ||
entries: [ | ||
{ | ||
binding: 1, | ||
visibility: GPUShaderStage.FRAGMENT, | ||
sampler: {}, | ||
}, | ||
{ | ||
binding: 2, | ||
visibility: GPUShaderStage.FRAGMENT, | ||
texture: {}, | ||
}, | ||
], | ||
}); | ||
|
||
const renderPipelineLayout = device.createPipelineLayout({ | ||
label: 'Render Pipeline Layout', | ||
bindGroupLayouts: [renderBindGroupLayout], | ||
}); | ||
|
||
const renderPipeline = device.createRenderPipeline({ | ||
layout: renderPipelineLayout, | ||
vertex: { | ||
module: device.createShaderModule({ | ||
code: fullscreenTexturedQuadVert, | ||
}), | ||
entryPoint: 'vert_main', | ||
}, | ||
fragment: { | ||
module: device.createShaderModule({ | ||
code: sampleExternalTextureFrag, | ||
}), | ||
entryPoint: 'main', | ||
targets: [ | ||
{ | ||
format: navigator.gpu.getPreferredCanvasFormat(), | ||
}, | ||
], | ||
}, | ||
primitive: { | ||
topology: 'triangle-list', | ||
}, | ||
}); | ||
|
||
const sampler = device.createSampler({ | ||
magFilter: 'linear', | ||
minFilter: 'linear', | ||
}); | ||
|
||
const renderBindGroup = device.createBindGroup({ | ||
layout: renderBindGroupLayout, | ||
entries: [ | ||
{ | ||
binding: 1, | ||
resource: sampler, | ||
}, | ||
{ | ||
binding: 2, | ||
resource: lastPipeline.getOutputTexture().createView(), | ||
}, | ||
], | ||
}); | ||
|
||
function updateFrameTexture() { | ||
device.queue.copyExternalImageToTexture( | ||
{ source: sourceCanvas }, | ||
{ texture: mainTexture }, | ||
[WIDTH, HEIGHT], | ||
); | ||
} | ||
function render() { | ||
let textureView: GPUTextureView | undefined; | ||
try { | ||
textureView = context.getCurrentTexture().createView(); | ||
} catch (e) { | ||
console.info('render canceled'); | ||
} | ||
if (!textureView) { | ||
return; | ||
} | ||
const commandEncoder = device.createCommandEncoder(); | ||
for (const pipe of pipelineChain) { | ||
pipe.pass(commandEncoder); | ||
} | ||
const passEncoder = commandEncoder.beginRenderPass({ | ||
colorAttachments: [ | ||
{ | ||
view: textureView, | ||
clearValue: { | ||
r: 0.0, | ||
g: 0.0, | ||
b: 0.0, | ||
a: 1.0, | ||
}, | ||
loadOp: 'clear', | ||
storeOp: 'store', | ||
}, | ||
], | ||
}); | ||
passEncoder.setPipeline(renderPipeline); | ||
passEncoder.setBindGroup(0, renderBindGroup); | ||
passEncoder.draw(6); | ||
passEncoder.end(); | ||
device.queue.submit([commandEncoder.finish()]); | ||
} | ||
|
||
return { render, updateFrameTexture }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
@group(0) @binding(1) var mySampler: sampler; | ||
@group(0) @binding(2) var myTexture: texture_2d<f32>; | ||
|
||
@fragment | ||
fn main(@location(0) fragUV : vec2f) -> @location(0) vec4f { | ||
return textureSampleBaseClampToEdge(myTexture, mySampler, fragUV); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { atom } from 'nanostores'; | ||
|
||
export const $upscaleSource = atom<HTMLCanvasElement | null>(null); | ||
|
||
export function setUpscaleSource(canvas: HTMLCanvasElement | null) { | ||
$upscaleSource.set(canvas); | ||
} | ||
export function resetUpscaleSource() { | ||
$upscaleSource.set(null); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters