Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c71ee21c1 | ||
|
|
75d8651f17 | ||
|
|
165cd2a7f9 | ||
|
|
bc98c5c665 | ||
|
|
ae4edc29e8 | ||
|
|
773a04369e | ||
|
|
45f4c1bc84 | ||
|
|
fb2927c094 | ||
|
|
4814bfb561 | ||
|
|
d8d487c189 | ||
|
|
0669ec0fc2 | ||
|
|
81cac1214d | ||
|
|
d8a0729029 | ||
|
|
aeff087c7d | ||
|
|
beae87b0cc | ||
|
|
e2301aa4ec | ||
|
|
32848aaf71 | ||
|
|
afb4a9e051 |
No files matched your search
@@ -31,3 +31,8 @@ jobs:
|
||||
working-directory: packages/server
|
||||
- run: dart test
|
||||
working-directory: packages/server
|
||||
# Compiling the dedicated server proves it stays Flutter-free.
|
||||
- run: dart compile exe bin/server.dart -o build/watch-together-server
|
||||
working-directory: packages/server
|
||||
- run: build/watch-together-server --help
|
||||
working-directory: packages/server
|
||||
@@ -14,15 +14,17 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Linux build deps
|
||||
# media_kit_video links libmpv + epoxy via pkg-config. Runner images
|
||||
# differ: some run as root without sudo.
|
||||
run: |
|
||||
if command -v apt-get >/dev/null; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev
|
||||
fi
|
||||
SUDO=sudo; [ "$(id -u)" = 0 ] && SUDO=
|
||||
$SUDO apt-get update
|
||||
$SUDO apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev \
|
||||
liblzma-dev g++ libmpv-dev libepoxy-dev xz-utils unzip curl python3
|
||||
|
||||
- name: Setup Flutter (beta)
|
||||
- name: Setup Flutter (stable)
|
||||
run: |
|
||||
git clone https://github.com/flutter/flutter.git -b beta --depth 1 ~/flutter
|
||||
git clone https://github.com/flutter/flutter.git -b stable --depth 1 ~/flutter
|
||||
echo "$HOME/flutter/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Build tarball
|
||||
@@ -34,7 +36,7 @@ jobs:
|
||||
name: linux-tarball
|
||||
path: dist/*.tar.gz
|
||||
|
||||
- name: Publish release + manifest
|
||||
- name: Publish release
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,35 +1,40 @@
|
||||
# AGENTS.md — sync_relay_project
|
||||
# AGENTS.md
|
||||
|
||||
Project conventions for agents. Global interaction rules live in the
|
||||
user-level AGENTS.md; this file holds repo-specific facts only.
|
||||
Source of truth order: codebase > `HANDOFF.md` + `docs/ROADMAP.md` >
|
||||
chat history.
|
||||
Repo-specific rules. Global interaction rules live in the user-level
|
||||
AGENTS.md. Source of truth: the code, then the docs below.
|
||||
|
||||
## Docs
|
||||
|
||||
- [README.md](README.md): users. [docs/HOW-IT-WORKS.md](docs/HOW-IT-WORKS.md):
|
||||
plain tour. [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md): packages, sync,
|
||||
media, updater, decisions. [docs/PROTOCOL.md](docs/PROTOCOL.md): wire format.
|
||||
[docs/DEVELOPMENT.md](docs/DEVELOPMENT.md): build, test, release, gotchas.
|
||||
[docs/ROADMAP.md](docs/ROADMAP.md): backlog and epics.
|
||||
- Docs describe current truth only: no dates, no "fixed" notes, no phase
|
||||
logs (git has history, plans go in ROADMAP).
|
||||
- Each fact lives in exactly one file; others link to it.
|
||||
- Code and its docs change in the same commit. A wire change also bumps
|
||||
`RelayConstants.protoVersion` and edits PROTOCOL.md.
|
||||
- Say "server" (there is only one), never "room", in UI, code and docs.
|
||||
|
||||
## Wishlist drafts
|
||||
|
||||
The user drops raw idea/bug lists as drafts (gitignored, never
|
||||
committed: `docs/Wishlist.md`, `docs/drafts/`). Agent duty on sight:
|
||||
translate each entry into its proper place — `docs/ROADMAP.md`
|
||||
backlog (ordered, one sitting-sized item each) or Epics, real bugs
|
||||
with repro detail preserved — then confirm placement with the user
|
||||
and delete the draft. Drafts must never be committed, even partially.
|
||||
The user drops raw idea/bug lists as drafts (gitignored, never committed:
|
||||
`docs/Wishlist.md`, `docs/drafts/`). On sight, translate each entry into its
|
||||
place in `docs/ROADMAP.md` (ordered backlog item or epic; keep repro detail
|
||||
for real bugs), confirm placement with the user, then delete the draft.
|
||||
Drafts must never be committed, even partially.
|
||||
|
||||
## Commits
|
||||
|
||||
Few commits, one per topic/session — never per fix. Rewriting
|
||||
unpushed history (amend, squash) is expected, not exceptional.
|
||||
Commit code + its docs together. No `flutter analyze` unless asked
|
||||
or diagnosing; scoped `dart analyze` on touched files is the
|
||||
pre-commit check. Tests run only when the code under test changed.
|
||||
Few commits, one per topic/session, never per fix. Rewriting unpushed
|
||||
history (amend, squash) is normal. Commit code + its docs together. No
|
||||
`flutter analyze` unless asked or diagnosing; scoped `dart analyze` on touched
|
||||
files is the pre-commit check. Run tests only when the code under test changed.
|
||||
|
||||
## Releases (user pushes tags, CI does the rest)
|
||||
## Releases
|
||||
|
||||
Release flow: `tool/release.sh [patch|minor|major]` derives the
|
||||
version (no typing), bumps all pubspecs, commits, tags → review →
|
||||
`git push --follow-tags` → `.gitea/workflows/release.yml`
|
||||
builds, publishes the Forgejo release, commits
|
||||
`updates/manifest.json` back. `tool/release_publish.sh` is the same
|
||||
flow by hand. Workflows live in `.gitea/workflows` (this forge reads
|
||||
`.gitea` first, `.github` is ignored when it exists).
|
||||
Never commit secrets: tokens arrive via env (`DISCORD_WEBHOOK_URL`,
|
||||
`RELEASE_TOKEN`) or Actions-provided (`GITHUB_TOKEN/GITEA_TOKEN`).
|
||||
`tool/release.sh [patch|minor|major]` then `git push --follow-tags`; CI
|
||||
publishes. Details: [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md). Never commit
|
||||
secrets: tokens come from env (`DISCORD_WEBHOOK_URL`, `RELEASE_TOKEN`) or
|
||||
Actions (`GITHUB_TOKEN`/`GITEA_TOKEN`).
|
||||
-321
@@ -1,321 +0,0 @@
|
||||
# HANDOFF — sync_relay_project (watch-together app)
|
||||
|
||||
Date: 2026-09-12 (updated late session). Phases 0–4 + presence hardening
|
||||
+ UI redesigns done, all green (core 42, server 41, desktop 24).
|
||||
Phases retired as a tracker 09-12 — `docs/ROADMAP.md` is now a flat
|
||||
backlog (Built / Backlog / Epics / Deferred); phase text lives in
|
||||
git history.
|
||||
Black screen (§8) DIAGNOSED + FIXED (avatar-texture teardown race;
|
||||
Visibility keep-mounted) + VERIFIED, incl. over internet. Bisect
|
||||
screens (legacy/minimal/nosheet) REMOVED 09-12 — app.dart routes
|
||||
session straight to SessionScreen. Internet test PASSED (WAN port
|
||||
6969, 09-12); user reports 2-client LAN soak + 1.4 GB real-file
|
||||
test also done 09-12 (outcomes not yet recorded below). Tonight's
|
||||
fixes: server logging wired into app (`initLogging` + hello logs),
|
||||
Cancel aborts pending connect, first-join failure no longer
|
||||
retry-loops. Git repo INITIALIZED (commit 427d851, root
|
||||
.gitignore). Prior chat may be unreliable; this file plus `docs/`
|
||||
is the full state (`docs/ROADMAP.md` is now the phase tracker).
|
||||
|
||||
## 1. What this is
|
||||
|
||||
Private watch-together desktop app (Windows + Linux). Host serves a file
|
||||
or shared link from their own machine; 4–8 friends watch in sync.
|
||||
One binary, three modes: Client (Join), Server+Client (Host, opens
|
||||
ports, self-plays via loopback), `--headless` (server only, no window).
|
||||
North star: <1.5 s drift, seeks settle ~2 s, cache rides short drops,
|
||||
kick kills sync+video, no relay memory growth.
|
||||
|
||||
## 2. Locked architecture (do not reopen without the user)
|
||||
|
||||
- `packages/core`: protocol, sync engine, media abstractions. ZERO Flutter
|
||||
imports (enforced by test). `packages/server`: Relic-based room + media
|
||||
server, also zero Flutter imports. `apps/desktop`: the ONE Flutter
|
||||
binary embedding both. Direct-serve model: host opens ports, clients
|
||||
open nothing. NO host-upload tunnel (the brief's WSS chunk protocol is
|
||||
obsolete unless a VPS tier ever needs remote-host upload).
|
||||
- Server HTTP+WS: **Relic ^1.2.0**. Client WS: **web_socket_channel**.
|
||||
Server lib also uses **web_socket** for event types.
|
||||
- PACKAGES ARE NOT LOCKED (user decision 09-11, overrides the old brief
|
||||
list): pick on merit, no churn where the stack works. Current desktop
|
||||
additions: media_kit_video + media_kit_libs_video (required),
|
||||
file_picker (avatar/media picking), hive_ce + hive_ce_flutter
|
||||
(connect-form persistence), image (avatar shrink). signals + media_kit
|
||||
+ Relic stay (load-bearing).
|
||||
- Sync: heavily Syncplay-inspired + original readiness design, NOT 1:1.
|
||||
Reference clone (scratch, may be gone — re-clone shallow):
|
||||
`git clone --depth 1 https://github.com/Syncplay/syncplay.git /tmp/opencode/syncplay-ref`
|
||||
Audit already done; conscious deviations: clock never moves from
|
||||
reports (theirs follows slowest watcher), no pause-on-leave,
|
||||
force-for-all instead of operator-only setOthersReadiness, and
|
||||
QUORUM gate (09-12, user found solo-play meaningless): HELD→PLAYING
|
||||
needs in-set size ≥ 2 unless ≤1 member is fresh — lone watcher plays
|
||||
alone, second watcher present ⇒ one Space waits. Late joiners outside
|
||||
the set never block.
|
||||
- Single room password (one secret, persisted in Hive on the user's own
|
||||
box — accepted). No op roles (deferred: op flag + second hello
|
||||
secret). Kick = transient nudge: revoke + close + `kicked` reason,
|
||||
instant rejoin with fresh token.
|
||||
- Deferred, do not build: TLS/Caddy, Jellyfin native, updater
|
||||
expansion (v1 `--upgrade` SHIPPED 09-12 — see §9.12; in-app
|
||||
prompt + Windows helper still deferred), playlist (extension shape reserved in PROTOCOL.md), op roles, sounds
|
||||
(researched, wired, no assets — see §7).
|
||||
- Standing rules: health reporting (every failure displays, nothing
|
||||
stalls silently); proto bump + PROTOCOL.md same-commit on ANY
|
||||
wire change (still v4 — quorum/timeouts are server policy, no bump).
|
||||
|
||||
## 3. Repo map (root: Flutter/sync_relay_project/)
|
||||
|
||||
- `packages/core/lib/src/`: constants.dart (tuning: seek 300 ms,
|
||||
drift 5 s, slow 1.5 s @0.95, min_buffer 4 s, heartbeat 1 s, ping 5 s,
|
||||
avatar 256 KiB (base64 chars; wide headroom over any 128x128 PNG
|
||||
— raised 09-12 from 64 KiB, which rejected normal PNGs), name 32, chat 500; dropAfter lives as RoomEngine ctor
|
||||
default, now 30 s), errors.dart, logging.dart, config.dart,
|
||||
protocol.dart (v4 schemas), media_source.dart, sync_engine.dart
|
||||
(RoomEngine + quorum in evaluate's HELD branch; PLAYING branch
|
||||
unchanged).
|
||||
- `packages/server/lib/src/`: session.dart, media_endpoint.dart,
|
||||
room_hub.dart (forgetSocket, sweepClosedSockets via `isClosed` poll,
|
||||
closeAllSockets, onError→forgetSocket), room_server.dart (1 Hz
|
||||
heartbeat: sweepStale + sweepClosedSockets + dropSilentSockets +
|
||||
broadcast; stop() closes client sockets first). `bin/server.dart`.
|
||||
- `apps/desktop/lib/src/`: sync/ (sync_client.dart: hello/intents/
|
||||
fan-out/match-by-`t`; room_diff.dart: diff + debounce + play gate),
|
||||
playback/ (media_kit Player, 64 MB cache, pin props, 0.5 s seek
|
||||
deadband, stop() on leave, SYNC_RELAY_VO/HWDEC env overrides),
|
||||
session/ (session_coordinator.dart: THE brain — room→player,
|
||||
reports, scrub/nudge→seek intents incl. HELD, seek-land retry,
|
||||
idle 8/10 min, reconnect loop, 5 s silence timeout; health.dart),
|
||||
sfx/ (SfxKind/Cue/Service + NoopSfxService — sounds deferred),
|
||||
state/ (session_state.dart: route/mode/lastForm/prefs/host/join/
|
||||
leave; connect_prefs.dart), screens/ (welcome/connect/session),
|
||||
widgets/ (user_section.dart: ConnectProfileCard; member_avatar.dart:
|
||||
THE avatar — memoized, no bg on images, dark ring+fallback;
|
||||
dialogs.dart: kick confirm; media_input.dart: parseMediaInput).
|
||||
- `apps/desktop/test/`: room_diff_test (9), media_input_test (6),
|
||||
updater_test (7: version/manifest/layout + stub-server flows),
|
||||
sync_playback_e2e_test (quorum: solo Space holds, both ready plays;
|
||||
needs mpv + ~/Videos/chiyo.mp4), coord_presence_test (dead server
|
||||
clears + reconnects; needs mpv).
|
||||
- `tool/`: range_logger, shaper (chaos: KB/s cap, latency,
|
||||
--kill-after), fake_viewer, e2e_check (sim timeline, still ALL PASS
|
||||
post-quorum), package_linux.sh (release tarball + Discord card,
|
||||
stamps APP_VERSION).
|
||||
- `docs/`: PROTOCOL.md (v4 + quorum + 15/30 s timeouts + isClosed note,
|
||||
normative), ARCHITECTURE.md (+health rule), mpv-http-contract.md.
|
||||
- `deploy/`: systemd unit. Git repo initialized 09-12 (`git init`,
|
||||
root `.gitignore`, initial commit 427d851 covering phases 0–4 +
|
||||
tonight's connect/logging fixes). Bisection is possible again.
|
||||
|
||||
## 4. Protocol v4 + policy (see PROTOCOL.md for normative detail)
|
||||
|
||||
hello→welcome(token, memberId, mediaUrl?, room-state); intents:
|
||||
ready{ready,source}/force{target:all|memberId,ready}/seek/seek-swap/
|
||||
report{position,buffered,eventId}/chat/kick{memberId}. Broadcasts:
|
||||
room @1 Hz + on change (diff by eventId), feed{actor,action,…}
|
||||
(toasts/log/sounds), kicked{reason}, err. Media:
|
||||
GET /m/<sid>/<token>/<name> (200/206×3 shapes/416/401/403/410/503).
|
||||
Transport PLAYING/HELD; gate = non-empty set AND all in-set ready +
|
||||
buffered≥4 s + fresh AND quorum (in-set≥2 unless ≤1 fresh).
|
||||
Stale >15 s ⇒ out of gate; silent >30 s ⇒ closed + removed.
|
||||
Closed sockets swept every second; socket errors remove immediately.
|
||||
Client: 5 s room-silence ⇒ dead (clear room, warn, reconnect loop
|
||||
1.5 s polite infinite + manual cancel/retry, prior-flag restore).
|
||||
|
||||
## 5. Phase log (all exits met, all green as stated above)
|
||||
|
||||
- P0 scaffold + CI + Flutter-free tests; binary binds/logs/exits.
|
||||
- P1 Range table byte-exact, real mpv traces, shaper built. 503 tested.
|
||||
- P2 sessions: secret→128-bit token, 401/403/410 gates, kick kills WS+
|
||||
media, byte counters, fake_viewer ALL PASS live, proto→3.
|
||||
- P3 engine + readiness: engine tests (fake clock), e2e 15/15 sim,
|
||||
Syncplay audit. Sanity: NaN guards, caps, stale/leave feeds,
|
||||
1 Hz flush, token redaction.
|
||||
- P4 desktop shell→app: SyncClient framing, RoomDiff (eventId diff,
|
||||
slowdown latch 0.95×/0.1 reset, seek-land check), media_kit wiring
|
||||
(pinned buffer props, buffered from demuxer), Space=ready, avatars,
|
||||
toasts+sheet, health display, reconnect loop. Sounds WIRED ONLY
|
||||
(NoopSfxService) — see §7.
|
||||
- P5 presence+sync hardening (user-reported, all reproduced live
|
||||
first): stop() closes sockets; isClosed sweep (~1 s graceful);
|
||||
onError forget (~2–4 s kill -9, was 56 s ghost); drop 60→30 s;
|
||||
client silence-timeout + stuck-reconnect-flag fix + ready-future
|
||||
leak fix; seek race fixed (2 s same-event debounce both
|
||||
transports, edge-aware detector 1 s guard, 0.5 s apply deadband);
|
||||
HELD seeks send intents (paused frame moves for all); arrows
|
||||
nudge ∓10 s; local play gate (in-set+ready); autoplay off;
|
||||
leave() stops player (was leaking audio); kick confirm; Cancel
|
||||
connect; connect-form memory→Hive persistence; file/media
|
||||
Browse buttons.
|
||||
- P6 UI redesigns (two subagents, disjoint files — repeat this
|
||||
pattern): full-bleed video + overlays, controls never autohide
|
||||
(24 h hover) + Ready/Mark-everyone-ready IN the controls bar
|
||||
(intents only, zero local transport buttons), center avatars-only
|
||||
64 px, slide-in toasts, animated right sheet (users/log/chat/swap/
|
||||
Leave w/ confirm), health pill only-when-unwell, ESC closes/
|
||||
asks-leave, global focus-proof keys (Space/Tab/arrows/ESC/F,
|
||||
350 ms throttle, ignored while typing; Tab traversal disabled on
|
||||
the session screen 09-12 — game-style, Tab toggles the sheet), single media field
|
||||
(parseMediaInput + tests), avatar pipeline (128 px PNG, keeps
|
||||
transparency — JPEG did not; self-check measures encoded base64
|
||||
against RelayConstants, single source of truth), tap to
|
||||
pick, no path fields), Discord-like corner profile (connect only;
|
||||
welcome is title+Host/Join; edits apply next join — no rename
|
||||
intent on the wire), dialogs for terminal states.
|
||||
- UX decisions locked along the way: Space flips self-ready only;
|
||||
free seeks any transport (no flag churn); join catch-up never
|
||||
halts; idle 8-min warn + 10-min auto-unready; reconnect = re-hello
|
||||
with flag restore; kick → dialog + connect screen; fixed 1.5 s
|
||||
reconnect + cancel/retry; GMod toasts (social only) + side sheet;
|
||||
avatar fallback = initial circle; "waiting for X (n/m ready)".
|
||||
- Open user questions for later: warning-tone timing; bar width at
|
||||
minimum window; second-ESC on leave dialog (re-asks vs cancel);
|
||||
cancel-stops-host-server (kept: idle means no bound port).
|
||||
|
||||
## 6. Gotchas (learned the hard way)
|
||||
|
||||
1. Relic gives Range as TYPED RangeHeader — convert via unit+first.
|
||||
2. Relic server-side onDone DOES NOT fire for dead peers (proven
|
||||
live both directions: clean close AND kill -9 both ghosted to
|
||||
timeout). Presence = isClosed heartbeat sweep + socket-onError
|
||||
forget + lastSeen timeouts. NEVER depend on onDone. (Docs pattern
|
||||
confirms CloseReceived is a data event.)
|
||||
3. Welcome races room broadcasts — match WS messages by `t`, never
|
||||
by index.
|
||||
4. web_socket_channel streams are single-subscription — one listener
|
||||
per socket (test double-listens throw "already been listened to").
|
||||
5. `sub.asFuture()` can resolve before `onDone` — poll with
|
||||
deadlines in tests.
|
||||
6. Comma-form mpv reconnect flags work here; colon-form rejected
|
||||
(re-verify via set_property if touched).
|
||||
7. Numeric literals corrupted once by tooling — verify with rg after
|
||||
writes touching ports/consts.
|
||||
8. Tool `bash` `&`-backgrounding is unreliable; use nohup + log file
|
||||
in its OWN call, poll in later calls, kill via `fuser -k
|
||||
PORT/tcp` (never `pkill -f`). Chain small calls, never long
|
||||
`&`-chains (they hang the runner past timeout with zero output).
|
||||
9. Tests must not assume threat model beyond trust-basis.
|
||||
10. web_socket_channel 3.x: `channel.ready` errors unhandled on
|
||||
refused connections — eat it (`unawaited(ch.ready.then(...,
|
||||
onError: ...))`); stream onError is the reporting path.
|
||||
11. MediaKit has NO public Player.setProperty — runtime props go via
|
||||
guarded dynamic call on player.platform; cache size via public
|
||||
PlayerConfiguration(bufferSize:).
|
||||
12. NEVER `flutter test`-pump the session screen: media_kit Video
|
||||
hangs the runner (a hung flutter_tester must be kill -9'd by PID;
|
||||
pgrep carefully). Sync-path coverage lives in room_diff (pure),
|
||||
lifecycle (server, raw WS), coord_presence + e2e (real mpv,
|
||||
no widgets). Deleted session_overlays_test.dart for this reason.
|
||||
13. No `flutter analyze` unless asked (IDE covers it) — except
|
||||
deliberate per-change checks; kept clean throughout.
|
||||
14. New `MediaDesktopVideoControlsThemeData` per build is fine
|
||||
(stock guards subscriptions) but wasteful; leave it.
|
||||
15. Env overrides for mpv experiments (no rebuild to switch):
|
||||
SYNC_RELAY_VO (e.g. xv, gpu, gpu-next), SYNC_RELAY_HWDEC (e.g. no).
|
||||
16. Hidden-but-mounted overlays keep focus: closing the sheet left
|
||||
focus on an offstage button, so Space fell through (350 ms
|
||||
throttle hole) into the hidden control. Fix pattern: ExcludeFocus
|
||||
on the closed subtree + unfocus-on-close effect. Same reason new
|
||||
overlay buttons reuse the shared no-focus node.
|
||||
|
||||
## 7. Sounds (deferred, wiring ready)
|
||||
|
||||
Base: Kenney Interface Sounds (CC0, confirmation_* ladder for
|
||||
ascending-ready). Alt ladder: ObsydianX Pack 1 (CC0, avoid paid
|
||||
packs). Soft layer: akx/Notifications (CC0 branch). Playback pick:
|
||||
flutter_soloud (preload WAV, per-play pitch) — NOT added. Swap-in =
|
||||
replace NoopSfxService; cues already fire with readyIndex. URLs +
|
||||
mapping in 09-11 chat (unreliable — re-derive from sources above).
|
||||
|
||||
## 8. Black window while playing (09-12, FIXED)
|
||||
|
||||
Symptom was: room PLAYING ⇒ entire window black (audio + keys
|
||||
alive, unready restored, zero errors). Cause: the waiting-avatars
|
||||
center overlay unmounted its GPU textures (avatar Images) exactly
|
||||
at the HELD→PLAYING flip; teardown racing mpv's frame uploads on
|
||||
the shared GL context fails silently ⇒ black. Legacy chips never
|
||||
unmounted and minimal never mounted, which is why they survived.
|
||||
Fix: center overlay is Visibility(visible + maintainState +
|
||||
maintainAnimation + maintainSize) — avatars stay mounted, paint
|
||||
skipped when hidden. Verified by user with full tree, and holds
|
||||
over internet (WAN 2-client test, port 6969, late 09-12) — CLOSED.
|
||||
RULE: never unmount GPU-textured widgets on a transport-gated
|
||||
branch; keep mounted + skip paint. Bisect screens
|
||||
(legacy/minimal/nosheet + SYNC_RELAY_UI switch in app.dart)
|
||||
DELETED 09-12 (commit tracks this); no commented bisect lines
|
||||
remain in session_screen.dart.
|
||||
|
||||
## 9. Next (ordered, updated 09-12 late session)
|
||||
|
||||
1. §8 black screen — CLOSED (fix verified incl. over internet).
|
||||
2. Remove bisect flags — DONE 09-12 (files deleted, app.dart
|
||||
routes session directly; tree analyzes clean).
|
||||
3. 2-client LAN soak — user reports DONE 09-12 (details pending).
|
||||
4. 1.4 GB real-file media test — user reports DONE 09-12
|
||||
(details pending; api_key must never land in files).
|
||||
5.–8. MIGRATED 09-12 to `docs/ROADMAP.md` backlog (cache-exhaustion,
|
||||
sounds, file-join wart, /health) — the roadmap is now the single
|
||||
backlog; this section keeps session history + user-owned pendings
|
||||
only.
|
||||
9. FIXED 09-12: auto-unready fired while passively watching —
|
||||
the 10-min check keyed off `_lastInput`, refreshed only by
|
||||
explicit actions. Steady playback now counts as activity:
|
||||
warn + auto-unready are skipped while room transport is
|
||||
PLAYING (`session_coordinator.dart` idle block). HELD-and-idle
|
||||
still unreadies after 10 min.
|
||||
10. FIXED 09-12 (second attempt — first theory was wrong): one chat
|
||||
send rendered as TWO log rows. Root cause is server dual
|
||||
delivery, not double-send: `broadcastChat`
|
||||
(`room_hub.dart:69`) emits both a `ChatMessage` (with text,
|
||||
converted to a feed entry client-side) and a textless `feed`
|
||||
entry, and the client logged both. The blank-guard in
|
||||
`sendChat` was defense against a phantom. Real fix: client
|
||||
drops textless `chat` feed entries (`sync_client.dart` feed
|
||||
case) — one send, one row, one toast, one sfx. No wire
|
||||
change, still v4. Chat field also keeps focus after send
|
||||
(dedicated FocusNode, re-requested on submit/button).
|
||||
11. KNOWN (non-breaking, fix later — roadmap backlog #2): seeks feel
|
||||
jumpy (forward-back-forward) — suspect the seek-land retry
|
||||
(`_checkSeekLanded`, `session_coordinator.dart:429`)
|
||||
re-applying SeekAction against the 0.5 s deadband / 2 s
|
||||
debounce and the 1 Hz room echo. Needs a live repro with a
|
||||
timeline log before touching.
|
||||
12. Updater v1 SHIPPED 09-12: `watch-together --upgrade`
|
||||
(`apps/desktop/lib/src/update/updater.dart`, zero Flutter
|
||||
imports, 7 tests) — manifest check, download, sha256, apply
|
||||
over live install (extract-temp + delete-first move-over;
|
||||
ETXTBSY forbids writing the running exe, delete+rename is
|
||||
fine). Version stamped via `--dart-define=APP_VERSION`
|
||||
(wired in `tool/package_linux.sh`; dev runs report
|
||||
`0.0.0-dev`). Publishing is CI-driven: tag `vX.Y.Z` →
|
||||
`.gitea/workflows/release.yml` builds, creates the Forgejo
|
||||
release, uploads the tarball, commits the manifest back
|
||||
(`tool/release_publish.sh` does the same by hand).
|
||||
Manual trigger only: bump desktop pubspec in a release commit
|
||||
first (script enforces tag == pubspec). No silent
|
||||
proto jumps: updater warns when manifest protocol != local.
|
||||
Environment: dart 3.14 beta, flutter 3.48 beta, mpv+ffmpeg present,
|
||||
~/Videos/chiyo.mp4 sample. Never kill the user's Syncplay mpv
|
||||
instance. Git repo at project root (init 09-12); commit code + docs
|
||||
together; prefer FEW commits (one per topic/session, not per fix)
|
||||
over bisect-granularity — user decision 09-12.
|
||||
|
||||
## 10. Window chrome — frameless, mpv-style (09-12, VERIFIED by user)
|
||||
|
||||
Native title bar gone everywhere (`window_manager ^0.5.2`,
|
||||
`TitleBarStyle.hidden` in main.dart GUI path only, headless
|
||||
untouched). New screens MUST bring their own drag + min/max/close
|
||||
or they ship immovable — reuse `widgets/window_buttons.dart` +
|
||||
`widgets/window_chrome_bar.dart` (welcome/connect pattern).
|
||||
Session: drag is `widgets/window_drag_layer.dart`, topmost raw-
|
||||
pointer observer inside the controls stack (a GestureDetector
|
||||
below media_kit's overlay LOSES the arena — do not revert to
|
||||
that); dead zones: bottom 120 px (seek stays exact), open sheet,
|
||||
leave dialog. `modifyVolumeOnScroll: false` is load-bearing for
|
||||
drag — side effect: volume is speaker-button-only, no scroll-
|
||||
volume. Maximize button = media_kit fullscreen toggle in
|
||||
session (no OS maximize there); NO aspect-ratio lock by user
|
||||
decision (custom UI lives outside the video frame). Close =
|
||||
graceful leave + stopServer, then window close. Min size
|
||||
160x90, no max. Verified on KDE Wayland (Arch): bar-drag,
|
||||
video-drag, fullscreen, free resize all good.
|
||||
@@ -1,28 +1,220 @@
|
||||
# sync_relay_project
|
||||
# watch-together
|
||||
|
||||
Watch-together desktop app (working title). One binary, three modes:
|
||||
Watch a video with friends, in sync, with the quality of a real mpv player.
|
||||
Pick from your Jellyfin library, paste any direct video link, or pick a file on your own disk;
|
||||
everyone's play, pause and seek stay together.
|
||||
|
||||
- **Client** — GUI Join, sync WS + mpv. No server code runs.
|
||||
- **Server+Client (Host)** — GUI Host starts `packages/server` in-process,
|
||||
listens on a port, self-connects via loopback. Host must open ports.
|
||||
Clients never open ports.
|
||||
- **Headless** — `watch.exe --headless`, same server package, no window.
|
||||
Why not Jellyfin SyncPlay: it runs in the browser and its sync is poor.
|
||||
This is a desktop app that drives mpv.
|
||||
|
||||
v1 order: links support (shared http(s) media URL, Syncplay-style sync)
|
||||
first, file relay (server-proxied bytes, whitelist case) after.
|
||||
Jellyfin native + auto-update are deferred as their own undertakings.
|
||||
Name: `watch-together` is a placeholder and the final name is undecided
|
||||
(`sync-relay` is the working name). It appears in file names and the
|
||||
update manifest until that is settled.
|
||||
|
||||
Layout:
|
||||
- Desktop only (Linux now, Windows planned), always mpv. No web clients.
|
||||
- No transcoding. Everyone plays the original file.
|
||||
- Friends trust model: no accounts, no roles. A blank password means an open server.
|
||||
|
||||
How it fits together: [docs/HOW-IT-WORKS.md](docs/HOW-IT-WORKS.md).
|
||||
|
||||
## Install and update
|
||||
|
||||
Download the latest `watch-together-<version>-linux-x64.tar.gz` from the
|
||||
Releases page of this repo, extract it, run `watch_together`.
|
||||
|
||||
Update from the app: when a newer version exists, an update indicator
|
||||
appears in Home's top bar and opens the update card. "Update and restart" downloads,
|
||||
verifies, applies in place and restarts; the install folder must be writable
|
||||
by you. Settings has Check now and an auto-check toggle. From a terminal:
|
||||
`watch_together --upgrade` or `update.sh` (shipped in the tarball). A
|
||||
release with a newer protocol is a required update: everyone on a server
|
||||
must run the same protocol version, and a mismatch is refused with a message
|
||||
telling you to update.
|
||||
|
||||
## Host from the app
|
||||
|
||||
Home, Host tab. Pick what to watch (optional): Jellyfin (browse your linked
|
||||
servers, see below), Link (paste an http(s) URL; Ctrl+V outside a field
|
||||
pastes it in) or File (path or Browse). In the column beside it set a port and an optional password (blank =
|
||||
anyone can join), then Host. Your name and avatar come from your profile
|
||||
(the chip at the top left). The app starts a
|
||||
server inside itself and joins it; you are the host and nobody can kick you.
|
||||
Leaving or closing the app stops the server. Friends need to reach your machine: open
|
||||
the TCP port on your router (or use a LAN or VPN address). Friends open nothing.
|
||||
|
||||
If you pick a local file, the server streams it to everyone from your disk.
|
||||
Nothing is uploaded or stored anywhere.
|
||||
|
||||
## Dedicated server
|
||||
|
||||
For an always-on box (no display needed): the release tarball also contains
|
||||
`watch-together-server`, a small standalone server without the app. Run it,
|
||||
then everyone (you included) uses Join.
|
||||
|
||||
```
|
||||
/packages/core protocol, sync engine, messages (pure Dart, no Flutter)
|
||||
/packages/server room + media HTTP endpoint (pure Dart, no Flutter)
|
||||
/apps/desktop Flutter app embedding packages/server (the ONE binary)
|
||||
/tool spikes + harnesses (range_logger, shaper, fake_viewer, e2e_check)
|
||||
/deploy systemd unit, notes
|
||||
/docs PROTOCOL.md, ARCHITECTURE.md, mpv-http-contract.md, ROADMAP.md
|
||||
./watch-together-server --port 8080 --secret <password>
|
||||
```
|
||||
|
||||
Phases + status: `docs/ROADMAP.md`. Session handoff: `HANDOFF.md` (root).
|
||||
| Flag | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `--port`, `-p` | 8080 | TCP port, all IPv4 interfaces |
|
||||
| `--secret` | empty | password; empty = open server (a warning is printed) |
|
||||
| `--name` | `server` | name reported by `/health` |
|
||||
| `--media` | none | local file to serve as the starting video |
|
||||
| `--advertise-host` | none | host put in file URLs instead of the one each viewer dialled |
|
||||
| `--config` | none | YAML or JSON file with the same settings (`port`, `secret`, `name`, `mediaPath`, `advertiseHost`); replaces the flags |
|
||||
|
||||
Enforcement: `core` and `server` must have zero Flutter imports (tested).
|
||||
It prints `READY port=... name=...` once listening and stops cleanly on
|
||||
Ctrl+C or SIGTERM. A dedicated server has no host: anyone can kick anyone.
|
||||
To run it as a service, unpack the tarball to `/opt/watch-together` and use
|
||||
[deploy/watch-together.service](deploy/watch-together.service) (copy it to
|
||||
`/etc/systemd/system/`, edit the flags, `systemctl enable --now watch-together`).
|
||||
|
||||
## Join
|
||||
|
||||
Home, Join tab. Enter the host's address, port, and the password if there
|
||||
is one, then Enter or Join. Your name and avatar come from your profile (top
|
||||
bar chip or Settings). Servers you got into appear as up to 6 Recent server
|
||||
tiles with live status (online and how many are watching, or offline, plus
|
||||
"needs update" when the server runs another protocol): click one to rejoin,
|
||||
x to forget it. Ctrl+1 / Ctrl+2 switch between Join and Host.
|
||||
|
||||
## Settings
|
||||
|
||||
Profile, hardware decoding (auto, off or custom; the env var
|
||||
`SYNC_RELAY_HWDEC` overrides it; applies on the next join or Reload video),
|
||||
"Experimental: mpv-style controls" (below), updates, playing the next
|
||||
Jellyfin episode automatically, video shaders (see below), and the
|
||||
keyboard shortcuts (read-only).
|
||||
Integrations links Jellyfin servers (below). About shows the version.
|
||||
|
||||
Keys in a session: Space = ready / unready, Tab = side panel (people, log,
|
||||
chat, change video), Left/Right = seek 10 s, Shift+Right = skip 1:30,
|
||||
PgUp/PgDn = previous / next chapter (as in mpv), F = fullscreen, Esc =
|
||||
close panel or ask to leave, Ctrl+R = reload video, `<` / `>` or Shift+P /
|
||||
Shift+N = previous / next Jellyfin episode, Ctrl+1..6 = Anime4K mode A, B,
|
||||
C, A+A, B+B, C+A, Ctrl+0 = shaders off. Every seek, skip and chapter jump
|
||||
moves everyone.
|
||||
|
||||
Controls: the seek bar marks chapter starts with a diamond; hovering it
|
||||
shows the time and the chapter title. The chapters button lists them
|
||||
(current one checked; click to jump). "1:30" skips ahead 1:30. Audio and
|
||||
Subtitles buttons (with the track count) list tracks as "Japanese · E-AC3
|
||||
2.0 · title"; subtitles have Off.
|
||||
|
||||
Experimental mpv-style controls (Settings → Player, off by default,
|
||||
switches right away): video controls modeled on mpv's uosc theme. A thick
|
||||
timeline across the bottom shows the played part, the cached part ahead
|
||||
(hatched), chapter starts as diamonds and the time; hovering it shows the
|
||||
chapter title and the time there. With the controls hidden it stays as a
|
||||
thin line. Above it flat buttons: ≡ menu, Subtitles and Audio (with the
|
||||
track count), the shader badge (the active Anime4K mode, e.g. "A HQ"),
|
||||
ready, chapters, 1:30, previous / next episode, change video, people,
|
||||
volume and fullscreen. Keys and skip buttons work the same.
|
||||
|
||||
Skipping: during the opening a "Skip OP" button floats in the corner (it
|
||||
jumps to the end of the opening), during the ending "Skip ED" (to the end
|
||||
of the ending only; what comes after is yours to skip). The opening and
|
||||
ending come from Jellyfin's intro / outro segments when your Jellyfin has
|
||||
them (needs a segment plugin, e.g. Intro Skipper), else from chapter names
|
||||
(OP, Opening, Intro / ED, Ending, Credits, Outro). Without an opening, on
|
||||
anything longer than 20 minutes, "Skip 1:30" floats there during the first
|
||||
6 minutes.
|
||||
|
||||
## Ports
|
||||
|
||||
| What | Default | Notes |
|
||||
|---|---|---|
|
||||
| Sync WebSocket and `/health` | TCP 8080 | plain `ws://`, no TLS |
|
||||
| Local file streaming | same port | path `/m/...`, needs a session token |
|
||||
|
||||
Only the host needs the port reachable.
|
||||
|
||||
## Jellyfin
|
||||
|
||||
Integrations > Jellyfin > Add server: type the address, then sign in with
|
||||
Quick Connect (the app shows a code; approve it in Jellyfin under Profile >
|
||||
Quick Connect) or your username and password. Several servers can be
|
||||
linked; each shows its status, and a star picks the default. Sign out
|
||||
revokes the app's sign-in on the server. If a sign-in expires the server
|
||||
shows "Reconnect" instead of disappearing.
|
||||
|
||||
The Host tab's Jellyfin source is a library browser: Continue watching (with
|
||||
time left), Next up and the latest per library on the start page; library
|
||||
grids with sort (name, date added, release date, rating, random) and
|
||||
Unwatched / Favorites filters; series pages with seasons, episode progress
|
||||
and a "Next up" button; details with the file's tracks; search. Clicking a
|
||||
movie or episode picks it; the button in the top right enlarges the browser
|
||||
and moves port, password and Host into a bar below it. On wide windows a
|
||||
side pane shows details of whatever is under the mouse.
|
||||
|
||||
Keys in the browser: arrows move, Enter picks or opens, I = details,
|
||||
Esc / Backspace / Alt+Left = back (Esc first clears a search), / or Ctrl+F =
|
||||
search.
|
||||
|
||||
Host from the library: pick a movie or episode and Host. Only the item
|
||||
goes to the server (which Jellyfin server and which item), never a link or
|
||||
your sign-in. Pasting a Jellyfin link (web page or stream link) does the
|
||||
same when the app can reach that Jellyfin; otherwise it is shared as a
|
||||
plain link.
|
||||
|
||||
Watching:
|
||||
- Everyone with their own account on that Jellyfin server plays the file
|
||||
directly with their own sign-in. Jellyfin tracks progress per account:
|
||||
your watched state, Continue watching and resume point follow what you
|
||||
saw (reported on start, every 10 s, on pause, resume, seek and track
|
||||
change, and when it stops).
|
||||
- Friends without an account watch through the host: the server fetches
|
||||
the file with the host's sign-in and passes it on (only the current item,
|
||||
only to people in the session). They show "via host" in the member list.
|
||||
A dedicated server relays when started with `--jellyfin <file>` (see
|
||||
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md), Jellyfin relay).
|
||||
- Without either, the app says "This needs a Jellyfin account on ..." with
|
||||
a button to link one; it plays as soon as you are signed in.
|
||||
|
||||
Episodes: the ⏮ / ⏭ buttons next to the controls (or `<` / `>`,
|
||||
Shift+P / Shift+N) put up the previous or next episode for everyone. From
|
||||
the ending (when it is known, see Skipping above; else in the last two
|
||||
minutes) a "Next episode" button floats in the corner. When an
|
||||
episode ends, a card shows what is next with Play next; with "Play the
|
||||
next episode automatically" (Settings, on by default) it counts down 10 s
|
||||
first, and Cancel stops it on your screen (seeking back stops it for
|
||||
everyone). Anyone with an account can put the next one up; friends
|
||||
watching via the host cannot.
|
||||
|
||||
Audio and subtitles: the Audio and Subtitles buttons in the controls pick tracks.
|
||||
Your choice is remembered per series (and as a default) and the closest
|
||||
match (language, then title, then codec and channels) is selected on the
|
||||
next episode. This is per person; nobody else is affected.
|
||||
|
||||
"Change video" in the session panel (Tab) opens the same picker as the Host
|
||||
tab: the library starts on the series you are watching with the current
|
||||
season, else where you left it. File is offered to the host only.
|
||||
|
||||
## Video quality and shaders
|
||||
|
||||
Each viewer can run mpv GLSL shaders on their own picture; nobody else is
|
||||
affected. The app ships [Anime4K](https://github.com/bloc97/Anime4K) v4.0.1
|
||||
(MIT) with the presets of its mpv guide: Mode A (1080p sources), B (720p),
|
||||
C (480p), A+A, B+B, C+A, each as HQ (strong GPUs, GTX 1080 and up) or Fast
|
||||
(the guide's low-end set). "Custom shaders" runs your own `.glsl` files.
|
||||
|
||||
Pick one with the ✨ button in the player's control bar (also in
|
||||
fullscreen) or Ctrl+0..6; the change applies live and is saved, so the next
|
||||
session starts with it. Settings → Video quality & shaders sets the default,
|
||||
HQ or Fast (used by Ctrl+1..6) and the custom files. Shaders cost GPU time
|
||||
every frame and need hardware video rendering: on media_kit's software
|
||||
fallback they do nothing, and the app says so. A shader that is missing or
|
||||
fails to load shows a toast and switches shaders off.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- "host offline - check address and port": wrong address, or the port is not open.
|
||||
- "wrong server password": password mismatch.
|
||||
- "host runs a different version": update the app on both sides.
|
||||
- Picture frozen but sound fine: Ctrl+R reloads the video; the app also does it automatically.
|
||||
- Everyone waits at "waiting for X": X has not buffered 4 seconds yet or has not pressed Space.
|
||||
- No Windows build yet.
|
||||
|
||||
For contributors: [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md),
|
||||
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md), [docs/PROTOCOL.md](docs/PROTOCOL.md).
|
||||
+5
-16
@@ -1,17 +1,6 @@
|
||||
# watch_together
|
||||
# apps/desktop
|
||||
|
||||
A new Flutter project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
|
||||
- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter)
|
||||
- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||
- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
|
||||
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
The Flutter desktop app (what users run; hosting runs the server from
|
||||
`packages/server` on an isolate). Layout and rules:
|
||||
[../../docs/ARCHITECTURE.md](../../docs/ARCHITECTURE.md). Build and test:
|
||||
[../../docs/DEVELOPMENT.md](../../docs/DEVELOPMENT.md).
|
||||
@@ -0,0 +1,36 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// For more information, please refer to <https://unlicense.org>
|
||||
|
||||
//!DESC Anime4K-v4.0-AutoDownscalePre-x2
|
||||
//!HOOK MAIN
|
||||
//!BIND HOOKED
|
||||
//!BIND NATIVE
|
||||
//!WHEN OUTPUT.w NATIVE.w / 2.0 < OUTPUT.h NATIVE.h / 2.0 < * OUTPUT.w NATIVE.w / 1.2 > OUTPUT.h NATIVE.h / 1.2 > * *
|
||||
//!WIDTH OUTPUT.w
|
||||
//!HEIGHT OUTPUT.h
|
||||
|
||||
vec4 hook() {
|
||||
return HOOKED_tex(HOOKED_pos);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// For more information, please refer to <https://unlicense.org>
|
||||
|
||||
//!DESC Anime4K-v3.2-AutoDownscalePre-x4
|
||||
//!HOOK MAIN
|
||||
//!BIND HOOKED
|
||||
//!BIND NATIVE
|
||||
//!WHEN OUTPUT.w NATIVE.w / 4.0 < OUTPUT.h NATIVE.h / 4.0 < * OUTPUT.w NATIVE.w / 2.4 > OUTPUT.h NATIVE.h / 2.4 > * *
|
||||
//!WIDTH OUTPUT.w 2 /
|
||||
//!HEIGHT OUTPUT.h 2 /
|
||||
|
||||
vec4 hook() {
|
||||
return HOOKED_tex(HOOKED_pos);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v4.0-De-Ring-Compute-Statistics
|
||||
//!HOOK MAIN
|
||||
//!BIND HOOKED
|
||||
//!SAVE STATSMAX
|
||||
//!COMPONENTS 1
|
||||
|
||||
#define KERNELSIZE 5 //Kernel size, must be an positive odd integer.
|
||||
#define KERNELHALFSIZE 2 //Half of the kernel size without remainder. Must be equal to trunc(KERNELSIZE/2).
|
||||
|
||||
float get_luma(vec4 rgba) {
|
||||
return dot(vec4(0.299, 0.587, 0.114, 0.0), rgba);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
|
||||
float gmax = 0.0;
|
||||
|
||||
for (int i=0; i<KERNELSIZE; i++) {
|
||||
float g = get_luma(MAIN_texOff(vec2(i - KERNELHALFSIZE, 0)));
|
||||
|
||||
gmax = max(g, gmax);
|
||||
}
|
||||
|
||||
return vec4(gmax, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
//!DESC Anime4K-v4.0-De-Ring-Compute-Statistics
|
||||
//!HOOK MAIN
|
||||
//!BIND HOOKED
|
||||
//!BIND STATSMAX
|
||||
//!SAVE STATSMAX
|
||||
//!COMPONENTS 1
|
||||
|
||||
#define KERNELSIZE 5 //Kernel size, must be an positive odd integer.
|
||||
#define KERNELHALFSIZE 2 //Half of the kernel size without remainder. Must be equal to trunc(KERNELSIZE/2).
|
||||
|
||||
vec4 hook() {
|
||||
|
||||
float gmax = 0.0;
|
||||
|
||||
for (int i=0; i<KERNELSIZE; i++) {
|
||||
float g = STATSMAX_texOff(vec2(0, i - KERNELHALFSIZE)).x;
|
||||
|
||||
gmax = max(g, gmax);
|
||||
}
|
||||
|
||||
return vec4(gmax, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
//!DESC Anime4K-v4.0-De-Ring-Clamp
|
||||
//!HOOK PREKERNEL
|
||||
//!BIND HOOKED
|
||||
//!BIND STATSMAX
|
||||
|
||||
float get_luma(vec4 rgba) {
|
||||
return dot(vec4(0.299, 0.587, 0.114, 0.0), rgba);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
|
||||
float current_luma = get_luma(HOOKED_tex(HOOKED_pos));
|
||||
float new_luma = min(current_luma, STATSMAX_tex(HOOKED_pos).x);
|
||||
|
||||
//This trick is only possible if the inverse Y->RGB matrix has 1 for every row... (which is the case for BT.709)
|
||||
//Otherwise we would need to convert RGB to YUV, modify Y then convert back to RGB.
|
||||
return HOOKED_tex(HOOKED_pos) - (current_luma - new_luma);
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(M)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.09991986, 0.13782342, -0.031251684, -0.06356843, -0.3437488, 0.05450952, 0.34347802, 0.46335372, 0.08607224, 0.044988394, 0.137179, 0.17976908, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.024212424, -0.09278509, -0.00040907756, 0.34552294, -0.13254678, 0.113105185, 0.005667946, -0.00036919137, -0.06375679, 0.009184115, 0.115518734, -0.115506776, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.14101827, 0.023523493, 0.044094566, -0.019271746, -0.44348842, -0.08818877, -0.4026149, -0.21995795, -0.15880394, -0.013732858, -0.020751135, 0.012719151, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.013001821, -0.34503505, 0.39219138, 0.18792126, 0.24760444, -0.016173402, 0.10154511, 0.15453082, -0.058132876, 0.016784398, -0.05808539, -0.11039915, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(0.37024534, 0.041440863, -0.3374568, -0.44994286, 0.19555596, 0.20855539, -0.27974075, -0.5372628, 0.21228147, -0.0295346, -0.56700057, 0.030042822, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.12940632, 0.057526, 0.090682045, -0.06985033, -0.13704006, -0.047685407, 0.44615674, -0.48056605, -0.06166251, -0.01883519, 0.2032237, -0.113287605, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.010856669, -0.35820737, 0.16757219, 0.082619876, -0.03967303, 0.038705572, 0.32652855, -0.012030017, 0.015120559, -0.15314877, 0.23442009, 0.09767922, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.046272673, -0.17752305, 0.082018286, -0.2512824, 0.58619463, -0.060903464, -0.022793597, 0.077803515, -0.17025311, 0.05136993, 0.029383298, -0.15475409, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.11212024, 0.13378005, -0.2027488, 0.08056421, -0.11176219, -0.048429377, -0.08396386, 0.10507829, 0.13326839, 0.0430627, 0.051362377, 0.06482755, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(-0.061233472, 0.39222646, 0.029704979, 0.02586828);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.16410656, -0.40521824, 0.13121907, -0.02314597, 0.105412476, -0.060401272, -0.043063477, -0.13933973, 0.12558138, -0.020861467, 0.030370515, 0.13178016, -0.14220351, 0.20736893, 0.003321564, -0.29241714) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.18517321, 0.29162985, -0.26783395, 0.039760686, 0.025527012, -0.067319244, 0.055004176, 0.048916563, 0.12750523, -0.091435954, 0.13818842, 0.36704224, 0.0839921, 0.10186618, -0.17237376, 0.13282418) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.1657887, 0.0131325135, -0.17222486, 0.091398895, -0.12756164, -0.08437298, -0.29052997, 0.3269337, 0.15870757, -0.013529402, -0.0581753, 0.11802371, 0.07099966, -0.024063632, 0.31834844, -0.11183859) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.46036887, -0.07654623, 0.22923063, 0.17463821, 0.10555414, -0.117430426, 0.12406777, -0.011399492, 0.028316498, 0.13684341, 0.009664087, 0.2022659, 0.04953974, -0.31342217, -0.6103131, -0.13605757) * go_0(0.0, -1.0);
|
||||
result += mat4(0.03406955, -0.39819366, 0.61176, -0.46809456, -0.029321073, 0.46619493, 0.36700186, 0.02288561, 0.11464085, -0.10931452, -0.09154022, 0.07334147, -0.5609916, 0.31826234, -0.011012659, -0.46719545) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.056855045, 0.27037027, -0.09269696, -0.563572, -0.06816116, -0.22986612, 0.08693167, -0.16246101, 0.09954046, -0.05374176, 0.0071916827, -0.1788692, 0.3825241, -0.1609887, 0.055204768, 0.10213068) * go_0(0.0, 1.0);
|
||||
result += mat4(0.0646626, 0.102358796, -0.45055822, 0.20557903, -0.23337309, 0.12633002, -0.19299199, -0.15085731, -0.13473304, 0.053790465, -0.10061193, -0.13393497, -0.04264752, -0.029740738, -0.07865285, 0.20883279) * go_0(1.0, -1.0);
|
||||
result += mat4(0.010471527, -0.033218473, -0.46157447, 0.004866583, 0.23226471, -0.059343327, -0.1439596, 0.13619648, 0.013839963, 0.15930325, 0.043742355, 0.17467323, 0.33772305, 0.40261495, -0.08351293, 0.18129359) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.12493434, -0.1875134, -0.074943796, -0.0031701606, -0.037142616, 0.1667002, 0.16665547, -0.011248127, 0.0071619414, 0.0034872112, 0.120318964, -0.09625579, 0.14917047, -0.16310586, 0.07231737, 0.30447328) * go_0(1.0, 1.0);
|
||||
result += mat4(0.093798615, 0.17074613, -0.08780678, -0.012520207, 0.118534856, 0.027508778, -0.2778478, -0.19509242, -0.34137097, 0.32000312, -0.22027159, 0.337515, 0.16220862, 0.108993016, 0.14070526, 0.12784284) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.14325632, -0.1467453, -0.27502358, 0.09370837, 0.11821083, -0.012266484, -0.2100548, 0.4707502, -0.06766648, 0.58165014, -0.2512279, -0.33783755, 0.1318925, -0.04346277, 0.15454485, 0.044500057) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.05683207, 0.0051946463, -0.108000524, 0.10133204, -0.50763863, 0.007308442, 0.8542404, 0.28387356, 0.022709515, 0.294523, -0.3822472, 0.66166407, 0.01404485, 0.031282708, -0.26756814, -0.123147786) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.36455178, 0.3470555, -0.045303088, -0.03170764, -0.15802494, -0.0019141496, -0.25939587, -0.23875342, 0.130428, 0.03954273, -0.17985536, 0.105145946, 0.15804817, 0.12551713, 0.28371975, -0.085748516) * go_1(0.0, -1.0);
|
||||
result += mat4(0.0060625463, 0.2443924, -0.017692259, -0.20214005, -0.09584515, -0.012805372, -0.13942227, 0.16143198, 0.12942013, 0.41785547, 0.046071563, 0.7030026, 0.10499644, -0.20566013, -0.031321276, 0.27830327) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.081274964, -0.14562319, 0.27200526, -0.20491314, 0.012910989, 0.024201397, 0.04816258, 0.21297328, -0.22015952, -0.44160756, -0.056035373, 0.33824417, -0.31645304, 0.15469243, 0.053187452, -0.20989445) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.046550367, 0.033185404, 0.33337244, 0.12853645, 0.23520172, -0.05909214, 0.0861368, 0.10706329, -0.07058717, -0.11759937, -0.18594047, 0.080006264, -0.055425353, -0.12506317, 0.15729053, -0.0915004) * go_1(1.0, -1.0);
|
||||
result += mat4(0.042516407, 0.14844789, 0.16533111, 0.13502933, -0.0655417, -0.057256397, 0.076713726, -0.23448966, 0.12855926, 0.014219275, 0.051761385, 0.053433083, -0.2446715, -0.4008074, 0.19603717, -0.1796951) * go_1(1.0, 0.0);
|
||||
result += mat4(0.14777803, 0.15524907, 0.043158617, -0.06996876, 0.19210646, -0.2144364, -0.47020787, -0.4207906, -0.18074386, -0.2163903, 0.0030754965, 0.36799973, -0.3837698, -0.0022661497, -0.37276733, -0.28934997) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.018297346, -0.080951825, -0.062163066, -0.08050014);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.31543177, 0.23095237, -0.06692611, -0.5867763, 0.003622504, 0.17948842, -0.14627707, 0.1745016, -0.052964583, -0.15551159, 0.05644786, -0.012665164, 0.13107763, 0.11369179, -0.09452995, -0.11973403) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.2694661, -0.115382135, 0.3073268, -0.067228466, -0.25511482, -0.13922207, 0.36758214, -0.18821828, -0.022617863, 0.20333402, -0.11125889, 0.3552245, -0.013346653, -0.099095374, -0.25100616, 0.35521755) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.011012409, -0.13675085, 0.25642, -0.34851208, -0.23184675, 0.18012202, 0.57654136, 0.103173524, -0.16461405, 0.038177088, 0.1234096, 0.013202029, -0.19033363, 0.07469178, -0.017948546, 0.15287702) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.05340533, 0.23797482, 0.20351392, -0.05333351, -0.12181174, -0.23363493, -0.20696607, 0.109941036, -0.11519453, 0.13842066, -0.10687832, 0.29040006, 0.022218632, 0.031238724, 0.2685182, 0.15300068) * go_0(0.0, -1.0);
|
||||
result += mat4(0.22985318, -0.3103802, -0.22916415, 0.25238806, -0.11690287, -0.1947488, 0.118020535, 0.07814263, -0.06335474, -0.007870727, 0.076106325, 0.094677486, -0.16776285, -0.006570437, -0.29589584, 0.41413507) * go_0(0.0, 0.0);
|
||||
result += mat4(0.43607962, -0.36456433, -0.123776875, -0.16634953, -0.091190875, 0.13035081, 0.28627968, 0.27249968, 0.12356344, -0.008616177, 0.09599816, -0.006144557, -0.23490307, 0.3013123, 0.14153156, 0.21837278) * go_0(0.0, 1.0);
|
||||
result += mat4(0.060364585, 0.37860224, 0.039182413, -0.22805426, -0.089910224, -0.06817697, -0.2684275, -0.12528503, 0.036934495, -0.07826616, 0.06559976, -0.08253646, 0.13489649, 0.06237663, 0.126376, 0.21194184) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.12534817, 0.21225189, -0.27818045, -0.3070443, -0.006957577, -0.025105853, 0.12100924, -0.06916452, 0.23081483, 0.1802756, -0.18995638, 0.16603014, -0.2904096, -0.25292823, -0.21834068, 0.13719653) * go_0(1.0, 0.0);
|
||||
result += mat4(0.017209655, 0.10757137, 0.21414296, -0.30885983, 0.10467716, -0.2184891, 0.100061476, -0.1527528, 0.2100472, -0.25768545, -0.22329919, -0.29153427, -0.06983842, -0.103854865, -0.051384352, 0.14629121) * go_0(1.0, 1.0);
|
||||
result += mat4(0.0059623295, -0.26060802, 0.32115817, 0.021025505, 0.09783085, -0.15865178, 0.1473021, -0.24977303, -0.033508282, 0.17480391, -0.091310136, 0.09870876, 0.10504043, -0.06105686, 0.013493489, -0.11278855) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.14875248, -0.14859414, 0.19377062, -0.17456068, 0.101288855, -0.1113682, -0.48944646, 0.1018565, -0.037392337, 0.08539691, 0.1751306, -0.15428723, -0.059375558, 0.027663672, 0.051804014, -0.049813222) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.118846565, -0.19869871, -0.037388258, 0.08456728, -0.11662527, -0.43818352, -0.093285345, 0.038507205, -0.051991668, 0.21008292, 0.10792365, 0.2020924, 0.057021596, 0.09460527, 0.0016551288, -0.0015957063) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.11062174, -0.2639232, -0.060295466, -0.3217331, -0.050545212, 0.30989558, 0.30906132, 0.030323273, 0.028986752, 0.037429404, 0.20855664, -0.19848943, 0.034687653, -0.09599135, -0.06250494, -0.13215867) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.010391146, 0.07657845, 0.44491258, 0.0435906, 0.0075931503, 0.42632654, 0.47022533, 0.34737435, -0.15452717, -0.14613411, -0.45231065, 0.12094409, 0.0067911847, 0.057501152, 0.09876979, 0.044946447) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.15607435, 0.2293058, -0.09520331, 0.012836732, -0.15282455, 0.26437718, -0.1685477, -0.13211122, -0.055801593, -0.016778728, -0.34478986, -0.23228309, 0.12300962, -0.13235827, -0.13987203, -0.16550972) * go_1(0.0, 1.0);
|
||||
result += mat4(0.13161735, -0.09039346, -0.033475474, -0.23686698, 0.1514885, 0.20977421, 0.031431954, -0.0049226107, 0.090661936, 0.15288061, -0.03316583, 0.09646573, -0.32651708, 0.18825398, -0.15777239, 0.17572704) * go_1(1.0, -1.0);
|
||||
result += mat4(0.112157226, -0.08712878, 0.23453182, 0.1043877, -0.14686783, 0.28682423, -0.086443506, 0.059457052, -0.31530112, -0.2700583, -0.06028952, -0.070416875, 0.18053482, 0.16653341, 0.25215197, 0.061915852) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.20122242, 0.076313145, -0.0988483, 0.094337784, -0.35436687, 0.3762327, -0.07809558, 0.3055848, 0.10425242, -0.17087407, 0.030301496, -0.13911743, 0.01630275, 0.24247427, -0.006474477, 0.03842641) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.008952847, -0.0058945753, -0.08097229, 0.020968592);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!SAVE conv2d_3_tf
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.2237721, -0.0064096362, -0.31808427, 0.73477733, 0.015353088, 0.23983319, 0.14967978, -0.34920225, -0.07456269, 0.093151815, -0.14331086, -0.24586205, -0.14183366, 0.06401045, -0.22044073, 0.29932275) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.07968509, -0.3349146, 0.16529128, 0.08443499, 0.4095855, -0.17120704, 0.17425705, 0.15298946, 0.2981273, 0.2212369, 0.10392389, -0.28775454, -0.065247655, -0.15255849, 0.13094437, 0.18685219) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.015706737, -0.17755036, 0.2622526, 0.112057306, -0.15876788, -0.38466996, -0.33700845, -0.031711742, -0.023320962, -0.3145249, -0.21223734, -0.1314596, -0.1888095, -0.046370104, 0.09000896, -0.0046378844) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.31127506, 0.31304324, -0.03965752, 0.03649018, -0.029851055, 0.05801377, 0.00040150844, -0.04422069, 0.18019931, 0.14415511, -0.09845236, 0.21895434, -0.013932474, -0.046454947, -0.3403935, -0.006705289) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.34878647, -0.5129283, 0.060250953, -0.16354133, 0.20644619, 0.08732273, -0.24118888, 0.24455065, 0.24449423, 0.44103387, 0.22455928, 0.25738943, -0.26914698, -0.21309987, 0.08386486, 0.021484816) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.057454903, -0.4121922, 0.022661546, 0.37178272, 0.03331408, 0.05044008, 0.04324371, 0.20727943, 0.2432641, 0.076906696, -0.20858039, 0.012439015, -0.19335061, 0.09217451, 0.1968369, -0.19435833) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.16960496, 0.24616167, 0.37977478, 0.14324574, -0.011531225, -0.11312143, -0.18141079, -0.23843932, 0.0086012175, -0.3564491, -0.12639481, 0.009799298, -0.29120612, 0.23756824, 0.18035695, -0.087133996) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.10081239, 0.29191494, 0.10434693, 0.08970636, 0.008997759, 0.104756236, 0.039641086, 0.02323888, -0.11627765, 0.023693223, -0.30801758, -0.120208986, 0.05086147, 0.18498175, 0.15595439, -0.09877306) * go_0(1.0, 0.0);
|
||||
result += mat4(0.101321675, -0.2929976, 0.38810417, 0.5605376, -0.04073937, 0.030110704, -0.18147062, -0.09833952, 0.01927733, 0.15335669, -0.15384074, -0.110595055, -0.054297395, -0.077522054, 0.07918369, -0.068480626) * go_0(1.0, 1.0);
|
||||
result += mat4(0.23263514, -0.11719232, 0.2903209, -0.007503795, -0.020222448, -0.17790157, -0.15600762, -0.08741775, 0.12529704, 0.25548857, -0.04585447, -0.10255033, 0.18350503, -0.29593533, 0.0868933, 0.027004737) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.14958654, -0.006238835, -0.2928948, 0.1988557, -0.17057803, 0.12524141, 0.13978264, -0.019280292, 0.05967142, -0.07790818, -0.5893818, -0.022845713, -0.08596779, 0.07875358, -0.03316667, -0.4369282) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.19195688, -0.060883682, -0.25897828, 0.07063324, 0.090833396, 0.003422883, 0.109534174, 0.031180874, -0.05017118, 0.022862168, -0.270113, -0.057831235, 0.53920543, -0.10252776, -0.091807485, 0.004294343) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.18494242, -0.119284816, 0.3821897, 0.07777979, 0.15568028, -0.2854859, -0.22441281, -0.049155876, -0.15292497, 0.21895619, -0.095677756, 0.15210424, 0.001643022, -0.026176987, 0.048463076, -0.4824009) * go_1(0.0, -1.0);
|
||||
result += mat4(0.007215129, 0.17074333, 0.053930074, -0.027014816, -0.17180431, -0.15163863, -0.0012122132, -0.18934256, -0.08294297, -0.24580221, -0.46552867, -0.27923223, 0.4092668, 0.06288688, -0.1602188, -0.0030876845) * go_1(0.0, 0.0);
|
||||
result += mat4(0.111870885, 0.03317145, 0.14155298, 0.20328505, -0.05104131, 0.13979794, 0.018966835, -0.07238511, 0.05493792, -0.14975783, -0.10293237, -0.21985306, 0.49054706, 0.18288186, -0.26925826, 0.35845932) * go_1(0.0, 1.0);
|
||||
result += mat4(0.3747799, -0.096748486, -0.17139742, 0.25289854, -0.17421168, -0.018461818, 0.09747162, 0.01660535, -0.20580359, 0.56189656, 0.17151354, -0.26347768, 0.28350568, -0.21486014, -0.44330928, -0.008981037) * go_1(1.0, -1.0);
|
||||
result += mat4(0.10169985, -0.18244018, 0.04760736, 0.41017643, -0.09468786, -0.024218475, 0.103733875, -0.22540338, 0.10630112, 0.3677178, -0.104170956, 0.057317447, 0.21764882, 0.0789158, -0.22041337, 0.15065216) * go_1(1.0, 0.0);
|
||||
result += mat4(0.11633995, -0.008195114, -0.14501533, 0.07168025, 0.058413275, 0.055995367, 0.09362145, -0.13827963, 0.13760869, 0.040319785, 0.038895044, 0.2675253, -0.087339684, 0.1412073, -0.17166458, -0.2312994) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.059377354, -0.02055341, 0.07234869, -0.015452986);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!SAVE conv2d_4_tf
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.29012984, -0.13150147, 0.31015614, 0.05992291, -0.050289866, 0.14845313, -0.09608898, 0.27913308, 0.060307387, -0.04160452, 0.035932682, -0.08137563, -0.07999419, 0.11818284, -0.27512288, 0.21948813) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.12916058, -0.21759962, -0.33868533, 0.021636661, 0.053470243, 0.1412425, 0.043395396, -0.26751056, -0.01689101, -0.2623835, 0.010809152, 0.062962815, -0.20692012, -0.1677863, -0.23313859, -0.17402615) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.08204112, -0.23672083, -0.0064437394, -0.13200696, -0.056692924, -0.02708657, 0.12536962, 0.004428919, 0.14137582, 0.15404348, -0.105753876, 0.047957454, 0.15734316, 0.16562423, -0.010160829, -0.06602983) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.025653997, -0.10877775, -0.31258908, 0.18841636, -0.36005193, 0.1816357, -0.34537643, -0.0741087, 0.4663994, 0.0065186517, 0.08109033, 0.2976773, -0.35774228, -0.041366056, -0.37852773, 0.050565656) * go_0(0.0, -1.0);
|
||||
result += mat4(0.04392313, 0.11316681, -0.14421389, 0.17985669, -0.1651274, -0.5656209, -0.124100484, 0.42774054, -0.1153939, 0.16829851, 0.2025612, 0.054007456, -0.06868256, -0.56935954, -0.12227961, 0.17688861) * go_0(0.0, 0.0);
|
||||
result += mat4(0.34041, 0.499, 0.15234196, 0.21353458, -0.2732667, -0.049950935, 0.03550811, -0.21051687, 0.2609023, 0.016438454, -0.29874632, 0.37994128, 0.049288407, -0.31126305, 0.029235512, -0.012256015) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.0046853204, 0.15391374, -0.040689662, 0.20186873, -0.08137621, 0.35905558, 0.23733845, 0.21794793, -0.066420384, 0.029600656, -0.31421044, -0.050773863, -0.06260773, 0.04634221, -0.10948491, -0.045498934) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.082953, -0.025837064, -0.09928303, -0.14300232, 0.275064, 0.07793617, 0.22240888, 0.06637834, -0.4382666, -0.2932182, -0.27243167, -0.14221182, 0.5695728, 0.20719238, 0.5575927, 0.40816882) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.18510929, -0.15052167, 0.25277212, 0.06804461, 0.016387, 0.20310035, 0.2903229, -0.0615877, -0.28987274, -0.11942605, 0.013498961, 0.3184152, 0.29543474, -0.042830903, -0.018111207, -0.13263674) * go_0(1.0, 1.0);
|
||||
result += mat4(0.25749087, 0.0053866603, -0.09391162, -0.06129529, -0.094091184, -0.07419633, 0.0013858611, 0.012000353, -0.062903, -0.0204224, -0.12113313, 0.017942557, -0.073379934, 0.052201986, 0.35864577, 0.023564404) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.100115694, 0.19451359, 0.23252094, 0.19506809, -0.12470779, 0.0027281935, -0.17488572, -0.018721964, -0.15159339, 0.18457152, 0.057712987, -0.08191495, 0.19735703, 0.07326743, -0.28563106, 0.01642815) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.068062514, 0.28356665, 0.07377898, 0.42776972, 0.28725025, -0.13045293, -0.17525704, -0.05885591, -0.16676305, -0.2555945, -0.10078422, -0.053032875, 0.084470876, 0.06460686, 0.13824362, -0.05231353) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.22637829, -0.028969254, 0.1968254, -0.13331996, 0.038017053, -0.008854481, -0.2031639, 0.09237089, -0.3821112, 0.1108527, -0.11029933, -0.24542028, 0.22416145, -0.031492114, -0.19144306, -0.0996271) * go_1(0.0, -1.0);
|
||||
result += mat4(0.10776744, 0.16363445, 0.14656505, -0.3737814, -0.06642015, 0.5616549, -0.008412252, -0.37266847, 0.12506576, -0.15329036, 0.037538245, -0.10810259, 0.01706349, 0.1813702, 0.035651788, -0.012786579) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.4023338, -0.2098614, -0.18285121, -0.02727653, 0.26107362, 0.041306913, -0.036515504, -0.045217298, -0.39958602, -0.21229339, -0.021053292, -0.13427502, 0.36178818, 0.20934913, 0.1500852, 0.2634554) * go_1(0.0, 1.0);
|
||||
result += mat4(0.07794611, -0.25937587, -0.06822529, -0.056336135, 0.094220124, 0.21588847, -0.0455218, -0.10968329, -0.08068449, -0.31366697, 0.07799637, 0.24252681, 0.23963861, 0.13715535, 0.010329345, 0.09094301) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.20975718, -0.12550138, 0.14453574, -0.0020878632, -0.07153068, 0.3249998, -0.056577377, 0.18166828, 0.37204072, 0.17018336, 0.3752895, 0.32178587, 0.2571982, -0.27258632, -0.25971004, -0.40536007) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.3243907, -0.06300621, -0.09398436, -0.19549188, 0.14906861, 0.061537784, -0.055284478, 0.11281728, 0.12964857, 0.09979093, -0.1810159, -0.4104283, 0.05807971, -0.056371246, 0.08072554, 0.18479007) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.048888464, -0.0561434, 0.030690912, -0.030496685);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!SAVE conv2d_5_tf
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.15332128, 0.027258258, 0.14900503, -0.15982795, 0.17021236, -0.51046044, -0.15287271, -0.058167327, 0.51826185, -0.34817994, 0.004513167, 0.05395769, 0.1990321, -0.049979225, 0.11391989, -0.16062729) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.033682905, 0.019728886, 0.19931756, 0.17381927, 0.2585768, -0.2124572, -0.014632459, 0.39779893, -0.1146207, -0.2396625, 0.08960277, 0.38345298, 0.25497693, 0.11692859, -0.14207517, 0.12667973) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.14911255, 0.08910706, 0.16136818, 0.03914566, 0.24204038, -0.03607149, -0.4571109, 0.10802461, -0.0021356856, 0.00885878, 0.22297303, 0.2367231, 0.045177583, 0.11120606, -0.009971904, -0.059262395) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.24565999, -0.2261384, 0.47373205, 0.024613412, -0.10923052, 0.039027315, -0.42707404, -0.3783373, 0.3544573, -0.5468578, -0.27599156, -0.09455918, 0.18760219, -0.19082001, 0.030565469, 0.20589156) * go_0(0.0, -1.0);
|
||||
result += mat4(0.1973198, -0.03433863, 0.059960485, 0.045642868, 0.1819595, -0.14460869, 0.1286175, 0.2067575, -0.042632047, -0.11842967, -0.11224446, -0.18764776, -0.19563004, 0.027425969, 0.24056377, 0.5949649) * go_0(0.0, 0.0);
|
||||
result += mat4(0.055027682, 0.16331595, -0.2608588, 0.12545955, 0.4588985, 0.03642909, 0.22187738, 0.45190734, -0.001210133, -0.057651415, -0.061199043, 0.11935476, -0.049561135, 0.27509886, 0.13778673, -0.124914035) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.02257459, 0.27705106, 0.044165276, -0.26521233, 0.05982374, -0.2824302, 0.3171142, 0.08430561, -0.10155528, 0.16182268, -0.09183147, -0.19447176, 0.3295707, -0.50616395, -0.036964044, 0.23166709) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.0232342, 0.07299799, -0.18038079, -0.13672702, -0.108305976, 0.15024792, -0.19531927, 0.0870979, -0.26488534, 0.19481428, 0.10737945, -0.14573483, -0.33094683, 0.24155116, -0.09850332, 0.2797003) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.24089853, 0.19506595, 0.4799156, -0.058313113, 0.36212957, -0.44844806, 0.23864488, 0.15477742, -0.07795971, -0.0033861927, -0.11216164, 0.033454563, -0.25893036, 0.23793478, -0.15769425, -0.00033481256) * go_0(1.0, 1.0);
|
||||
result += mat4(0.05772507, -0.1640253, -0.13499664, -0.20460358, -0.024399966, 0.14966168, -0.090857334, -0.039677754, 0.00036956606, -0.24236615, -0.053542696, -0.0049544116, 0.026651502, 0.39019194, -0.2742246, -0.061242323) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.016323274, -0.036179908, 0.029965919, 0.11151491, -0.00016685206, -0.29573023, 0.17996423, -0.20145437, 0.1324275, -0.18442132, -0.24618152, 0.061780427, -0.02770517, 0.28452995, 0.39804098, -0.1174389) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.025068847, -0.053328387, -0.27053785, 0.26866457, -0.09866204, 0.057677213, 0.01850112, -0.18014707, -0.13319959, -0.14411181, -0.26355243, -0.022209354, -0.05062645, -0.036771543, 0.13294417, -0.18458557) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.046194963, 0.038230438, -0.08993043, -0.07236354, 0.11031123, -0.16504908, -0.09517036, -0.16459833, -0.5279925, 0.12686682, -0.05726125, 0.055361677, 0.31593755, 0.027328093, 0.001839602, 0.30581662) * go_1(0.0, -1.0);
|
||||
result += mat4(0.08608678, 0.03168437, 0.007713377, -0.26140293, -0.1268983, 0.13395861, -0.069848835, -0.24080403, 0.018839337, -0.049821075, -0.21461345, -0.14168301, -0.0872339, 0.47096667, 0.022512507, 0.14860632) * go_1(0.0, 0.0);
|
||||
result += mat4(0.06293673, 0.22462969, 0.045494985, 0.021673543, 0.18227446, -0.2956555, 0.08010543, -0.01919729, -0.012190269, 0.241983, -0.046537094, -0.40094566, -0.3853647, 0.1081711, -0.16926058, 0.16138376) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.14854589, -0.17625804, -0.10849075, 0.221543, 0.099971965, 0.13901573, 0.29464146, 0.020068526, 0.054358527, -0.10351705, -0.0062914286, 0.24127026, -0.16914125, 0.12729423, -0.18377453, -0.6452375) * go_1(1.0, -1.0);
|
||||
result += mat4(0.12603393, -0.10986093, 0.2314103, 0.16915044, -0.13619255, -0.09349073, 0.20594226, -0.34507084, 0.19077192, 0.052500796, 0.07185645, 0.029082738, -0.015576321, 0.08254907, -0.5501743, -0.38495848) * go_1(1.0, 0.0);
|
||||
result += mat4(0.09300796, -0.079218306, 0.46825135, -0.08735625, 0.06321122, 0.16234867, 0.042932414, -0.013057422, 0.09697148, 0.23457524, 0.19417483, -0.16804664, 0.18379296, 0.17770062, -0.050235, -0.059676602) * go_1(1.0, 1.0);
|
||||
result += vec4(0.011169491, 0.032399546, 0.138099, 0.023857072);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!SAVE conv2d_6_tf
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.22753362, -0.08612073, 0.33140692, 0.08699529, -0.18788953, -0.056579117, -0.12905197, -0.06694621, 0.054559365, 0.15031597, -0.13430363, 0.021646025, 0.14884405, -0.0694291, 0.26149413, 0.11270503) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.17876762, -0.09637848, 0.11285323, 0.2004893, 0.1317187, -0.036162686, 0.17958368, -0.069625, 0.28760737, -0.12505141, 0.12760694, 0.047717955, -0.16811855, -0.16340709, 0.13278298, -0.08403954) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.21917523, 0.079711854, -0.28642535, 0.2822416, 0.03001489, -0.014772918, -0.3487396, 0.10597145, -0.013841082, 0.17034237, 0.10810282, -0.08089695, -0.22184245, -0.59067357, 0.44113398, 0.13045649) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.29906932, 0.013923749, 0.2031124, -0.11846688, -0.13953634, 0.08003455, -0.10164494, -0.21218559, 0.10563715, 0.31033117, -0.075903505, 0.047310907, -0.37824214, -0.14506383, 0.11866701, -0.21384487) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.1353849, 0.19258606, 0.063908584, -0.2043788, 0.27244982, 0.1665306, -0.29357895, -0.22441709, 0.18514316, -0.17840464, 0.20986097, 0.14351055, -0.057732623, 0.42166704, -0.23182064, -0.4957248) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.34830126, 0.109066755, -0.28285867, -0.048280068, -0.12290918, 0.04291651, -0.047484186, -0.03702595, 0.23047262, 0.09398974, 0.022467108, 0.08271034, 0.3066665, -0.54077, 0.057771873, 0.23194093) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.17731948, -0.3175927, 0.1452728, 0.09396786, -0.16433562, -0.01833653, -0.22345604, -0.04161193, -0.14827462, 0.18544114, -0.15544125, -0.06179007, 0.16989979, -0.20985202, 0.16391534, -0.09447268) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.053878862, -0.21034616, 0.023831524, 0.19772215, 0.31647214, 0.0126534775, -0.19130844, -0.049282108, -0.21446131, 0.067189045, 0.09117449, -0.25548774, 0.12109098, 0.22009392, -0.3924665, -0.13340388) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.16096684, -0.18495405, 0.10410178, 0.0015673033, -0.00183498, -0.044303037, -0.062745355, -0.090802394, 0.043269135, 0.06924481, -0.21367405, -0.14619029, 0.11555763, -0.20292862, 0.5799557, 0.14739846) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.21030277, -0.09578802, 0.013482288, -0.21484336, 0.12995781, 0.40431052, -0.3347856, -0.18183486, 0.15550353, -0.04402301, 0.4603779, 0.14874357, -0.07694621, -0.053523075, -0.19607326, -0.10850742) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.2347211, 0.2697403, -0.0634794, -0.17925987, 0.17231455, 0.24999185, -0.5208536, -0.10491828, -0.233575, 0.52950364, 0.0038063182, -0.1380038, 0.022935199, 0.19369157, 0.14586553, 0.1938704) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.10245223, 0.34150192, 0.25862157, -0.20165509, 0.5597771, 0.114510864, -0.122526556, -0.04010975, 0.1704679, -0.23335956, -0.16771887, -0.03783455, -0.056995615, 0.24153493, -0.08082429, -0.24210933) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.103466526, 0.15278348, -0.30526164, -0.080755696, 0.103505425, 0.15862796, 0.14696524, -0.008358076, -0.09180311, -0.12505089, 0.28052542, -0.13551563, 0.07528779, -0.09636086, -0.10369617, 0.23656134) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.25752836, 0.099439755, -0.30716348, 0.035077725, 0.023509016, 0.23106368, 0.05277125, 0.34910464, 0.088015385, 0.26995596, 0.1390645, -0.40671825, 0.18096298, -0.100688554, 0.5492049, 0.2482101) * go_1(0.0, 0.0);
|
||||
result += mat4(0.41411775, -0.107200556, -0.13813478, 0.13768874, 0.27137747, 0.06313619, -0.08522967, 0.03218302, -0.03166121, -0.3415683, -0.52242, -0.1741813, -0.36956537, 0.179129, -0.09742935, -0.11696616) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.07975504, 0.17964838, 0.37122533, 0.16064765, 0.14309953, 0.29473078, 0.0926391, -0.22333665, 0.34612748, -0.3387473, 0.0077308523, -0.07239449, 0.18522519, -0.21297298, 0.11493978, 0.16117814) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.17402779, 0.10023144, 0.11712206, 0.031971734, 0.18713303, 0.08736295, 0.013007052, -0.06943139, -0.20102951, -0.010721135, -0.2562522, 0.34877458, -0.13732676, -0.40258047, 0.25824392, 0.15720639) * go_1(1.0, 0.0);
|
||||
result += mat4(0.044494305, 0.3296108, 0.0017603852, 0.09362289, 0.38839245, 0.40015858, -0.13395199, -0.044521853, -0.56266373, 0.251378, 0.5005789, -0.13106057, -0.18491416, -0.046887, 0.067797676, -0.14694957) * go_1(1.0, 1.0);
|
||||
result += vec4(0.013687534, -0.08185164, -0.04755438, 0.290178);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(M)-Conv-3x1x1x56
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_6_tf
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
#define g_0 (max((conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_1 (max(-(conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_2 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_5 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_6 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_9 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_10 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_13 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.08837163, -0.065234736, -0.034704313, 0.0, 0.021405501, 0.013663729, 0.019249594, 0.0, 0.05328863, 0.03580334, 0.046457592, 0.0, -0.12216048, 0.022547891, 0.016400825, 0.0) * g_0;
|
||||
result += mat4(0.061996464, 0.05631466, 0.06808407, 0.0, -0.005013109, -0.0044589997, -0.032367796, 0.0, 0.016481603, 0.13721058, 0.14924648, 0.0, 0.020035887, -0.07250003, -0.08034037, 0.0) * g_1;
|
||||
result += mat4(0.24078514, 0.081361525, 0.053420708, 0.0, -0.009353794, -0.051077116, -0.058007747, 0.0, -0.14071098, 0.01035966, 0.005308949, 0.0, -0.1489842, -0.06711817, -0.05552926, 0.0) * g_2;
|
||||
result += mat4(-0.13002375, 0.012733757, 0.017821986, 0.0, 0.17767483, 0.20204604, 0.1751779, 0.0, 0.12804912, 0.07381453, 0.05655911, 0.0, 0.17044514, 0.07301451, 0.06523978, 0.0) * g_3;
|
||||
result += mat4(-0.1170986, -0.05130371, -0.027939914, 0.0, -0.16645707, -0.121526904, -0.09471366, 0.0, -0.04143118, 0.026693767, 0.034615446, 0.0, -0.084318705, -0.064990036, -0.054324172, 0.0) * g_4;
|
||||
result += mat4(0.12094524, 0.09518409, 0.07387219, 0.0, 0.062216382, 0.053228356, 0.031372335, 0.0, 0.072797105, 0.026258165, 0.009804673, 0.0, 0.120719045, 0.073281154, 0.056623302, 0.0) * g_5;
|
||||
result += mat4(-0.11141495, -0.11566289, -0.10398725, 0.0, -0.0651895, -0.06820691, -0.054204144, 0.0, -0.032746475, -0.008849683, -0.007610222, 0.0, -0.024655705, -0.048778858, -0.041144755, 0.0) * g_6;
|
||||
result += mat4(0.058090195, 0.07538767, 0.059722915, 0.0, 0.044788487, 0.04212742, 0.027502589, 0.0, 0.04892866, 0.015416752, 0.008312418, 0.0, -0.011864114, -0.0074752793, -0.0060824654, 0.0) * g_7;
|
||||
result += mat4(0.043446552, 0.061971307, 0.05758086, 0.0, -0.06379154, -0.053758245, -0.047204215, 0.0, 0.016307736, 0.03423424, 0.030179083, 0.0, 0.041445345, 0.03843772, 0.033059113, 0.0) * g_8;
|
||||
result += mat4(-0.003803544, 0.0008906116, -0.00059585314, 0.0, 0.102071285, 0.11485224, 0.10007254, 0.0, -0.074306004, -0.08803551, -0.07972321, 0.0, -0.030704215, -0.021514274, -0.009049376, 0.0) * g_9;
|
||||
result += mat4(0.0066058086, 0.0011408008, 0.0016199006, 0.0, -0.03916473, -0.042929266, -0.04018418, 0.0, -0.03153446, -0.039413508, -0.034767237, 0.0, 0.113516055, 0.12577052, 0.113335624, 0.0) * g_10;
|
||||
result += mat4(0.02655948, 0.041905303, 0.03861737, 0.0, 0.048471425, 0.049788587, 0.050447535, 0.0, 0.12092813, 0.13564217, 0.12613249, 0.0, -0.0023508538, 0.0012828974, 0.0028730957, 0.0) * g_11;
|
||||
result += mat4(0.0084758485, 0.008800083, 0.008206044, 0.0, -0.056123603, -0.06610845, -0.060320783, 0.0, -0.081793964, -0.101638645, -0.096699014, 0.0, -0.04402356, -0.04177539, -0.03829645, 0.0) * g_12;
|
||||
result += mat4(0.10676299, 0.118409514, 0.10618478, 0.0, -0.05880252, -0.06488367, -0.06432695, 0.0, 0.019221924, 0.017602798, 0.017413978, 0.0, -0.07512528, -0.080483615, -0.066218294, 0.0) * g_13;
|
||||
result += vec4(-0.010478934, -0.008364784, -0.010246552, 0.0);
|
||||
return result + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(S)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.19288683, -0.21397883, 0.111997396, -0.04791413, -0.26682988, -0.06144587, -0.03601853, -0.16693151, 0.038494494, -0.16651472, 0.147657, -0.083003886, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.14286195, 0.08746566, -0.40107322, 0.12390977, -0.33392772, -0.18703035, -0.21326795, 0.04780781, -0.15155545, -0.0010025925, -0.1554875, -0.10676251, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.28095165, 0.022872915, -0.21342312, -0.29982176, 0.025937587, -0.055012174, -0.33779636, 0.0015666655, 0.076416336, 0.06656033, -0.1557806, 0.1078894, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.31584853, 0.07527119, 0.30713862, -0.34014285, -0.50103146, -0.07217874, 0.512807, -0.09597398, -0.32097813, -0.051580857, -0.022466356, 0.01148551, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.026032459, -0.04193211, 0.37703893, -0.031916667, -0.27421117, 1.0906446, -0.049654085, -0.19814016, 0.07819544, 0.06003738, 0.1405805, -0.0064135445, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(0.041450135, 0.11319654, -0.23237701, 0.08443178, 0.53344345, 0.30857387, -0.057264958, -0.1575803, 0.2325609, -0.027797326, -0.04544767, -0.18720597, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.2531829, -0.074966915, -0.27800754, -0.3146097, 0.20126024, -0.5380133, -0.15082566, -0.19021043, 0.29951036, 0.17123336, -0.01681872, -0.12574998, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(0.25203633, 0.19882993, 0.14906439, 0.13593598, 0.40712556, 0.084902965, 0.42969635, 0.2961132, -0.057267334, -0.030388135, 8.8084314e-05, 0.0210724, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.13459359, -0.12199573, 0.12591946, 0.24736497, 0.2033463, -0.09388599, -0.094370656, 0.1071285, -0.18479438, -0.066625565, 0.08279283, 0.20130983, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(-0.011108127, -0.07481861, 0.07640154, 0.4964964);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(S)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.056432575, 0.0028165397, -0.026325442, -0.14802271, 0.16885762, -0.062179096, -0.2332292, 0.17513658, -0.08011296, 0.02947316, 0.014771492, -0.17946689, 0.026012989, -0.09823925, 0.036625937, -0.06924322) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.13571467, 0.09831142, 0.12911566, 0.06305893, -0.07188695, -0.20161287, 0.3858435, -0.21069056, -0.12294444, -0.1404628, -0.022659872, 0.23008968, 0.10969853, 0.17640765, 0.39796907, 0.20413099) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.0061665224, 0.055102807, -0.0059629944, -0.021429887, 0.061626043, 0.16898955, -0.21215646, 0.16510476, 0.2238265, 0.19429931, 0.09874656, 0.06828208, -0.122404456, -0.00026717107, -0.28203064, -0.29979932) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.22735378, 0.14538136, 0.11549746, 0.194148, -0.09841722, -0.0661309, 0.348576, -0.017375294, -0.044078812, 0.1298332, 0.04793373, -0.30687734, 0.08353025, 0.083519086, 0.10766399, 0.31796935) * go_0(0.0, -1.0);
|
||||
result += mat4(0.048365135, -0.17566709, -0.33212858, -0.052667376, -0.26443407, -0.010216014, 0.1573303, 0.05725314, 0.08140953, -0.09664591, 0.076109104, -0.026773714, 0.07732627, 0.10188082, -0.28266954, -0.16230233) * go_0(0.0, 0.0);
|
||||
result += mat4(0.29931107, 0.117944, -0.10414009, 0.12795551, 0.12576093, 0.17082554, -0.15803693, 0.13430743, -0.025801308, -0.10797019, 0.0721032, 0.2825884, -0.11025257, 0.12798019, 0.081827976, -0.050441865) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.11827391, 0.08306765, -0.3430314, 0.07898041, -0.023839617, -0.019507334, 0.23176382, -0.40992323, 0.09411734, 0.38415068, -0.25845516, -0.29984522, 0.1470966, -0.0684779, -0.07071314, -0.026773235) * go_0(1.0, -1.0);
|
||||
result += mat4(0.19091596, 0.082110435, -0.5266589, -0.1744098, -0.015838385, -0.046316292, 0.023171103, -0.03731331, 0.2642396, 0.31824252, -0.041754793, -0.09525519, -0.14696182, 0.052168854, 0.039857205, -0.027555354) * go_0(1.0, 0.0);
|
||||
result += mat4(0.15207373, 0.09845733, 0.0142631065, 0.096375965, 0.06089903, 0.17902578, -0.42391995, 0.22475442, 0.016356342, -0.06277531, -0.12173141, -0.18635495, -0.0013459618, 0.15725887, 0.019310836, 0.20293565) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.18395247, 0.30672902, 0.09034339, 0.1821889, -0.0419004, -0.2169228, -0.14052129, 0.11006559, 0.1709272, 0.51062274, 0.13758625, -0.2242552, -0.030382963, 0.3357568, -0.26491287, 0.02501938) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.040511727, 0.12523083, -0.27318433, 0.08388512, 0.25354835, 0.3404216, -0.2632471, -0.17784123, 0.2732347, 0.4468553, 0.084667034, -0.1856242, 0.034099877, -0.00954992, -0.32751867, -0.062207516) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.17564747, 0.11645554, -0.16362113, 0.105654195, -0.2762563, -0.1413764, 0.23264363, -0.14000498, 0.095402054, 0.0715738, -0.19346157, -0.028285999, 0.009799127, 0.04059529, 0.19688335, 0.1282381) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.23575781, -0.11446148, -0.20504695, 0.035568226, 0.36890212, -0.85968876, -0.18545328, 0.33796397, -0.30916876, -0.10445518, -0.3046253, 0.33271998, -0.06263589, -0.2160114, -0.16383372, -0.31173357) * go_1(0.0, -1.0);
|
||||
result += mat4(0.20469664, 0.4039374, -0.070057206, 0.030353077, 0.39843914, -0.15490077, -0.24476516, 0.38238233, -0.21809858, 0.23496576, -0.051794037, 0.033664484, -0.14411364, -0.2515329, 0.124655396, -0.05818785) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.09065731, -0.16787091, 0.013269188, 0.23687351, -0.41504318, -0.048163068, 0.31760025, -0.33648986, 0.29752317, 0.2926866, 0.14408836, -0.33382463, -0.15873958, -0.121961035, 0.11797893, 0.09000567) * go_1(0.0, 1.0);
|
||||
result += mat4(0.13356976, 0.013763947, 0.012169505, -0.109594524, 0.03417223, 0.7031121, 0.65146804, 0.5250268, -0.50132495, -0.419648, 0.2940041, 0.83051753, -0.17595838, 0.1633008, -0.018587278, 0.079596795) * go_1(1.0, -1.0);
|
||||
result += mat4(0.07570128, -0.1581438, 0.03904949, 0.14890033, -0.054611947, 0.17469402, -0.44252598, 0.036181703, -0.4981031, -0.37507218, -0.18466389, 0.2645845, 0.25189674, -0.025896115, 0.034307647, -0.020462232) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.11645865, 0.02296537, 0.040909223, 0.015069485, 0.062284566, -0.22526766, 0.09241534, -0.32623053, 0.18208642, 0.3954284, 0.2884468, -0.25137675, -0.037232924, -0.10185309, -0.17956531, 0.018966453) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.16371979, -0.024620198, -0.035754893, 0.04176776);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(S)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.01921286, -0.26684764, -0.12663573, 0.31641877, -0.25313398, 0.12264074, 0.58750325, -0.14084283, 0.5837018, -0.042300556, -0.20435576, -0.009954825, 0.060783498, 0.05540401, 0.2205112, -0.06578902) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.21930243, -0.03774968, 0.22615197, 0.18338196, 0.011201461, -0.271034, 0.00573116, -0.12248194, 0.47990513, 0.2982416, -0.1087603, -0.050099242, -0.07620939, -0.07148229, 0.03691984, -0.16796488) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.14962853, -0.053769328, 0.02387081, 0.22002189, 0.052237745, -0.26160842, -0.08603077, 0.012542448, 0.08119985, 0.075785555, -0.33437458, -0.43373227, -0.13206963, -0.08759176, -0.03288923, -0.09799959) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.1305593, -0.5974288, 0.06058367, 0.08406488, 0.013692483, 0.06646377, 0.16469325, 0.08990975, 0.42217395, -0.11289523, -0.06165009, 0.48556912, -0.15702641, -0.19922857, -0.0035429662, -0.0022089656) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.1964807, 0.038099788, 0.21587034, 0.039734077, -0.07063389, 0.11604167, -0.24558097, -0.08900199, -0.7684516, -0.1037487, -0.09380674, 0.33144563, -0.16653742, 0.0028585843, -0.33774406, -0.0528696) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.27298656, -0.05665099, 0.09661685, 0.19780266, 0.1025106, -0.22055034, -0.21218458, -0.040628925, 0.0095010325, 0.13118382, -0.42582452, -0.22197723, 0.21006055, -0.06189587, -0.15285942, -0.09526762) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.14494462, -0.046788953, 0.065877035, 0.09911713, 0.35096622, 0.16682479, 0.028363144, 0.36037162, 0.29413632, 0.28212717, -0.025364442, -0.3406269, 0.047262143, -0.11892685, -0.008032766, 0.29743317) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.15191558, -0.36980554, 0.14555687, 0.0043930537, -0.012661432, 0.15737776, -0.115250416, 0.10324491, 0.24491951, -0.15575431, -0.27802598, 0.21959937, 0.18063772, 0.4455559, -0.09693302, 0.33382267) * go_0(1.0, 0.0);
|
||||
result += mat4(0.2717801, 0.13452889, 0.14105384, 0.16324317, -0.40111846, 0.1154301, -0.0076733204, -0.09697362, 0.44306824, -0.02831414, -0.2153124, -0.12075326, 0.060776163, 0.30347148, -0.0036976219, -0.12070682) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.39780128, -0.29875937, -0.12952097, 0.080333896, 0.07520163, 0.021689568, -0.23121156, -0.038140096, -0.1593877, 0.017156163, -0.06038025, 0.009244022, -0.13917233, 0.30957314, 0.243109, -0.104947075) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.07965157, 0.06776501, -0.13288979, 0.005851189, -0.08768168, -0.03689969, 0.12034646, 0.22441491, 0.14453568, -0.17648841, -0.3378289, -0.018329712, 0.11722939, -0.34161824, 0.08424494, -0.01400687) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.08153887, 0.07222914, -0.14663404, -0.038526025, -0.07385973, 0.18440577, 0.35890242, 0.17084727, 0.26345527, 0.15280858, -0.007446105, -0.024403179, -0.30336383, -0.22978698, 0.11612946, -0.23614909) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.07447396, 0.09023449, -0.13798, -0.086943336, -0.30787337, 0.15087669, 0.14418626, -0.03371195, 0.048989657, -0.13075387, -0.13458036, -0.059836224, 0.06495196, 0.269715, 0.3674355, 0.38956037) * go_1(0.0, -1.0);
|
||||
result += mat4(0.34981915, -0.048779126, 0.31717536, 0.38080826, -0.20149232, -0.82969636, -0.10167862, 0.6382858, 0.25976858, 0.4370118, -0.04724865, -0.10014156, 0.19380626, -0.080370255, 0.09578106, -0.035166856) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.026443917, 0.4132611, 0.01822534, 0.12742202, -0.26652107, -0.2996705, 0.30905882, 0.07989903, 0.38249823, 0.21486135, 0.025314959, -0.14717339, -0.13344015, -0.32088286, -0.2833883, -0.30973712) * go_1(0.0, 1.0);
|
||||
result += mat4(0.021517841, 0.006556378, 0.2025686, -0.12044382, -0.38583103, -0.0027515136, -0.06556736, -0.097090125, 0.04676486, -0.11954886, -0.051612873, 0.07831412, -0.18823163, -0.16542958, 0.04245155, 0.6437998) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.39475346, -0.2936861, 0.26768062, -0.28151843, 0.21935691, 0.2101108, -0.15455097, 0.19548604, 0.09188909, -0.020147726, 0.103328265, -0.12574542, -0.34167948, 0.07523185, -0.17669058, 0.62446547) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.37661025, -0.29630858, 0.05451026, 0.1611643, 0.14079669, -0.2170294, -0.038716137, 0.13514164, -0.21235192, -0.07860726, -0.005749412, 0.025625167, -0.13297133, 0.33012658, -0.27434957, -0.18416783) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.0036821906, -0.050239526, -0.01355402, 0.00048220603);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(S)-Conv-3x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.15873, 0.17989138, 0.14648493, 0.0, -0.017379675, -0.017363746, -0.019855022, 0.0, 0.009670625, 0.0070157526, 0.0075994316, 0.0, 0.025388412, 0.027231036, 0.024052646, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.048195973, 0.041760173, 0.037366055, 0.0, -0.115950756, -0.12887983, -0.12535639, 0.0, 0.032125086, 0.03397254, 0.032950625, 0.0, 0.01223746, 0.020822672, 0.0161561, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.0890567, 0.094453335, 0.09014035, 0.0, 0.016081346, 0.017434116, 0.020783134, 0.0, -0.011775135, -0.010094134, -0.018522855, 0.0, 0.072103254, 0.07940666, 0.065876864, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.04841196, -0.06963968, -0.056574684, 0.0, 0.10912542, 0.11813441, 0.10643838, 0.0, -0.013013885, -0.01562045, -0.013802797, 0.0, 0.037505716, 0.04352026, 0.04645123, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.3472869, -0.36243078, -0.33530185, 0.0, 0.23654196, 0.2305048, 0.22150646, 0.0, -0.045226905, -0.041799217, -0.042511635, 0.0, -0.10267792, -0.1123385, -0.10845448, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(0.011987401, 0.012285043, 0.007813165, 0.0, -0.15911353, -0.17523928, -0.1535267, 0.0, 0.15675929, 0.16531634, 0.15948962, 0.0, -0.09240023, -0.09513292, -0.084187366, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.069052905, 0.07278333, 0.0756627, 0.0, -0.012180326, -0.018794727, -0.031050753, 0.0, -0.044663202, -0.04362803, -0.038904265, 0.0, -0.008540197, -0.011201734, -0.01556625, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.08261173, -0.09042543, -0.07589266, 0.0, 0.043515377, 0.045066774, 0.04037769, 0.0, -0.06262993, -0.07469342, -0.058593787, 0.0, 0.026696987, 0.028740842, 0.037405368, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(0.07975598, 0.09597654, 0.08997132, 0.0, -0.07844719, -0.07880916, -0.06835411, 0.0, 0.05668995, 0.050163813, 0.053357534, 0.0, -0.020040333, -0.019867316, -0.01907621, 0.0) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.017078733, -0.017393313, -0.008266595, 0.0, -0.0033478448, -0.0027439648, -0.0042334674, 0.0, -0.06354017, -0.062058125, -0.04652064, 0.0, -0.010787706, -0.0062706997, -0.007573461, 0.0) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.019895451, -0.016341688, -0.008712399, 0.0, 0.026231976, 0.023955572, 0.0216376, 0.0, -0.061950512, -0.05481285, -0.05261985, 0.0, -0.018804235, -0.016235247, -0.0131616965, 0.0) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.055628926, -0.063315354, -0.057192408, 0.0, -0.0256364, -0.028660972, -0.02937357, 0.0, -0.017604912, -0.020851422, -0.016070362, 0.0, -0.0870202, -0.0832279, -0.07525406, 0.0) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.062738225, 0.07106593, 0.061644047, 0.0, -0.06068257, -0.06983662, -0.066070385, 0.0, 0.024919355, 0.03227179, 0.028569462, 0.0, -0.07866227, -0.098967604, -0.092128105, 0.0) * go_1(0.0, -1.0);
|
||||
result += mat4(0.040397774, 0.047241107, 0.03962998, 0.0, -0.09112752, -0.10057507, -0.09301817, 0.0, 0.10833967, 0.101835825, 0.10027467, 0.0, 0.27189335, 0.27433604, 0.26781923, 0.0) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.044211388, -0.042373534, -0.03658007, 0.0, 0.113148406, 0.12423258, 0.107804194, 0.0, -0.17081551, -0.18562958, -0.17475435, 0.0, 0.09636739, 0.10763415, 0.093332425, 0.0) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.03798545, -0.047811143, -0.050768293, 0.0, 0.018775463, 0.026812987, 0.03452908, 0.0, 0.0055677597, 0.0039081173, -0.0017878668, 0.0, -0.10728597, -0.12618187, -0.109045394, 0.0) * go_1(1.0, -1.0);
|
||||
result += mat4(0.06359783, 0.064184755, 0.04934199, 0.0, -0.009819327, -0.006616115, -0.007431496, 0.0, 0.025055679, 0.024787048, 0.017360551, 0.0, -0.047140837, -0.061695747, -0.06440822, 0.0) * go_1(1.0, 0.0);
|
||||
result += mat4(0.060199022, 0.06482763, 0.059514645, 0.0, 0.026998974, 0.028776823, 0.024897143, 0.0, 0.17968474, 0.19337215, 0.16760105, 0.0, 0.0075838566, 0.010503482, 0.011993149, 0.0) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.0052927984, -0.0060193934, -0.0048643993, 0.0);
|
||||
return result + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(M)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.073079124, 0.11507942, 0.028201895, -0.021776304, -0.25251916, -0.08662003, 0.38814726, 0.4146095, 0.06326891, 0.01635252, 0.06423356, 0.13488062, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.059791833, -0.03105604, 0.041643705, 0.35197195, -0.17314838, 0.067622855, -0.032012507, 0.09691628, -0.11094062, 0.007625051, 0.094762206, -0.05824145, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.120281175, 0.027440755, -0.026316144, -0.025291128, -0.41698205, -0.05966847, -0.28400028, -0.06946398, -0.10906026, -0.015854035, -0.028724853, -0.06626416, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.068752654, -0.12652585, 0.38200122, 0.17978846, 0.2749825, 0.015504972, 0.21765926, 0.2246602, -0.062151223, 0.07457783, 0.13588274, -0.037328478, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(0.3718559, 0.025637252, -0.4048626, -0.41484925, 0.24768798, 0.09984098, -0.5663632, -0.6659978, 0.212067, -0.08328392, -0.5277322, -0.016879432, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.11072714, -0.010321538, 0.11265787, 0.0055236337, -0.13345073, 0.004847663, 0.3744461, -0.4038564, -0.09893075, 0.031325124, 0.2883957, -0.04268903, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.10444391, -0.60588187, 0.02543334, 0.10911738, -0.10860678, 0.15701362, 0.29235297, 0.045803998, 0.076250754, -0.10799697, 0.08841044, 0.08145623, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.04246739, -0.1225759, 0.11280305, -0.12079673, 0.5289142, -0.011892906, -0.0800465, 0.05915611, -0.126204, 0.08239301, -0.0092391195, -0.07672885, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.11922264, 0.14036109, -0.09491126, 0.05112697, -0.12543046, -0.08662423, -0.041537095, 0.048038274, 0.11672854, -0.006516173, -0.023524825, 0.030505095, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(-0.07697861, 0.41154122, 0.042374082, -0.087270625);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.09419103, -0.1178418, 0.09523275, 0.24648252, 0.03595256, -0.05417468, -0.029167585, -0.012279932, 0.08852021, -0.12534834, 0.0604663, 0.050634373, -0.19536541, 0.21548285, 0.040379744, -0.28046605) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.13783203, 0.17191975, 0.06956328, 0.005270252, -0.029844455, -0.17657366, 0.03439078, 0.048861686, 0.12017991, -0.087307535, 0.11815637, 0.31309614, 0.08440897, 0.09969244, -0.06220224, 0.2633136) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.098606475, -0.05856224, -0.01163882, -0.020945825, -0.08988821, 0.18520717, 0.011407763, 0.20973705, 0.21017794, 0.038311377, -0.018910313, 0.053878684, -0.08751144, -0.0081623215, 0.29060364, 0.14363094) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.13354321, -0.38046083, 0.14157647, 0.10190452, -0.045502663, 0.0053245644, -0.10817685, -0.048371315, 0.16157807, 0.2086147, 0.07632662, 0.24636099, -0.0053555835, -0.19587666, -0.46687222, 0.002362032) * go_0(0.0, -1.0);
|
||||
result += mat4(0.28275147, -0.1468291, 0.24075283, -0.35119128, 0.18727398, 0.3833064, 0.08667899, 0.15021381, -0.092296466, -0.25686404, -0.116076745, 0.2231862, -0.27637103, 0.12317917, -0.0341737, -0.40077657) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.007041629, 0.18089123, -0.21195571, -0.12346183, -0.06088577, -0.30784377, 0.0048495876, 0.06013008, 0.07200418, -0.0076884073, 0.02632822, -0.0011575016, 0.21025613, -0.2573419, -0.06994815, 0.32497165) * go_0(0.0, 1.0);
|
||||
result += mat4(0.0016823286, -0.014366541, -0.5049525, 0.048534572, -0.0057915323, -0.0030526456, -0.028976317, -0.16376147, -0.15560333, -0.053708192, -0.055678204, -0.13087665, 0.0048869387, 0.027514834, 0.017380254, -0.06743363) * go_0(1.0, -1.0);
|
||||
result += mat4(0.044514824, -0.1754644, -0.26664957, 0.1486667, 0.114894986, 0.061640915, -0.13305616, 0.06450565, 0.03552732, 0.2835473, 0.13800526, 0.005875215, 0.15751484, 0.41759813, -0.19406971, 0.071032055) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.18419577, -0.05527526, 0.017057603, -0.1146602, 0.15775396, -0.01188916, 0.09368113, 0.05765405, 0.064170234, -0.017833546, 0.12100514, -0.06250493, 0.2421206, 0.15719843, 0.23718071, 0.023142194) * go_0(1.0, 1.0);
|
||||
result += mat4(0.079226464, 0.07877355, -0.022315226, -0.13507473, 0.14683898, 0.028739132, -0.24479519, -0.280197, -0.13223173, 0.21732429, -0.1546993, 0.045442928, 0.163642, -0.07062695, 0.03805918, 0.060860883) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.095216066, -0.16650215, -0.34863555, -0.025274571, 0.3064775, -0.034196265, -0.25773287, 0.19570488, -0.005434017, 0.26308087, 0.009404902, -0.24736062, 0.05558232, -0.014217521, 0.03667355, -0.15134114) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.074846864, 0.010901994, 0.035149742, 0.12106729, -0.36042807, -0.011231913, 1.4317516, 0.6400351, 0.105860665, -0.11587906, -0.11065066, 0.19126756, 0.14132085, 0.021570992, -0.3618735, -0.081163004) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.06937371, 0.3815214, 0.026842717, -0.04051589, -0.09472515, -0.027198657, -0.16502109, 0.114273794, -0.15207845, -0.15054241, -0.25099036, -0.10871029, 0.14311226, 0.07640166, 0.47051275, 0.0447809) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.25960425, 0.11150338, -0.042022616, -0.006633396, -0.29595324, -0.0149574205, 0.09806478, 0.03635802, 0.26789796, 0.41416678, 0.05145585, 0.61168057, 0.019582301, -0.118703716, 0.13974573, 0.04498941) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.04119621, -0.15503803, 0.33170196, -0.1158483, -0.06258357, 0.2574262, -0.07890287, -0.6929032, 0.004379942, 0.097908296, 0.009286624, 0.27194506, -0.2476702, 0.13828708, 0.05071857, -0.43693772) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.010842703, 0.13108006, 0.30126816, 0.20221521, 0.018797455, 0.0614624, 0.11102966, 0.019204421, 0.09975456, 0.04676902, -0.044540443, 0.118877, -0.04871634, -0.089208096, 0.027455999, 0.029557817) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.10421777, 0.3135469, 0.14557797, 0.0497297, 0.0034963787, -0.20342828, 0.08332032, -0.09004643, 0.06574797, -0.14168271, -0.08754358, 0.30385306, -0.3374016, -0.4360316, 0.15854433, -0.24081887) * go_1(1.0, 0.0);
|
||||
result += mat4(0.1407836, 0.09678823, -0.02240152, -0.013985894, 0.012281648, -0.24124922, -0.46433777, -0.25915003, 0.042200714, -0.21701157, -0.016618999, 0.13135725, -0.34656256, -0.034729004, -0.29246503, -0.13514486) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.08458621, -0.023144595, -0.057707336, -0.081382714);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.27743992, 0.04277345, 0.019331178, -0.7335445, 0.006292013, 0.19800001, -0.0025032016, 0.16098699, -0.03186617, -0.060173523, 0.08878855, -0.10669283, 0.130609, -0.068515256, -0.03571823, -0.13751523) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.2430821, -0.08233978, 0.082374334, 0.04843392, -0.18989052, -0.041925047, 0.40021122, -0.317836, -0.13517766, 0.032255337, -0.0746507, 0.22114721, -0.045706213, -0.12841983, -0.27830583, 0.05763077) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.08436965, -0.04967552, -0.16798134, -0.1539139, -0.17429228, -0.10166739, 0.35864773, 0.12873615, -0.07667423, 0.04985163, 0.13391761, -0.054322604, 0.085659124, -0.078792974, 0.06481059, 0.058667548) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.17568155, 0.56705236, 0.056562193, -0.020951264, 0.005879628, -0.2502103, -0.19619654, 0.019490348, -0.14527243, 0.16983634, 0.049245857, 0.18316677, 0.055053137, 0.10699275, 0.0016993808, 0.20105995) * go_0(0.0, -1.0);
|
||||
result += mat4(0.36284775, -0.05856962, -0.42545465, 0.31931567, -0.15698905, -0.28837132, -0.028697362, -0.024917847, 0.04317283, 0.024557106, -0.052158598, 0.38654143, -0.1782944, 0.43094924, -0.11738149, 0.21554618) * go_0(0.0, 0.0);
|
||||
result += mat4(0.22645079, -0.20319854, 0.20733371, -0.18697177, -0.05167819, -0.12845007, 0.5543688, 0.2453291, 0.08027872, -0.0628224, -0.06593836, -0.05795855, -0.24527508, 0.23632833, -0.043366548, 0.14135826) * go_0(0.0, 1.0);
|
||||
result += mat4(0.08384414, 0.20807321, 0.030559694, -0.13640808, -0.07641805, -0.10919174, -0.19799095, -0.12955745, 0.093737304, -0.17856954, 0.035103753, -0.044699315, -0.07255943, -0.02331535, 0.2059249, 0.3058302) * go_0(1.0, -1.0);
|
||||
result += mat4(0.022345139, 0.16286038, -0.27228013, -0.41105714, -0.0014384583, 0.089546144, -0.08296848, -0.0050463285, 0.07038578, -0.030679917, 0.031246305, 0.36761853, -0.34799108, -0.0405689, -0.19182852, 0.015853593) * go_0(1.0, 0.0);
|
||||
result += mat4(0.1021783, -0.11396049, -0.08733628, -0.017449526, 0.042015605, -0.14808236, 0.10072531, -0.07403295, 0.15276712, -0.07807765, -0.10013386, -0.26110634, -0.04858846, 0.066066965, 0.13598624, 0.21687816) * go_0(1.0, 1.0);
|
||||
result += mat4(0.07041569, -0.17775945, 0.15697548, -0.15425202, -0.06569677, -0.033233996, 0.22596005, -0.026170855, -0.20729817, 0.1316505, -0.058410037, 0.22166035, 0.09107114, -0.13078825, -0.05639485, -0.02716142) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.057966787, -0.15311252, 0.095924966, -0.055951685, 0.082777694, -0.08471956, -0.39918202, 0.10599212, 0.102710955, 0.21808124, 0.12083635, -0.38835892, 0.031709857, 0.13955092, 0.12647778, 0.011549966) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.09810508, -0.119743295, 0.06166254, 0.13595435, 0.036198203, -0.028710455, -0.40789905, -0.034894038, -0.12622337, 0.14379597, 0.039958883, 0.19636424, 0.047094557, -0.07987105, -0.04905092, -0.07875785) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.34118712, -0.2833933, -0.045028314, -0.40670308, -0.01961924, 0.37131935, 0.29099533, -0.19843055, 0.18604252, -0.0037280058, 0.1091072, -0.40579233, 0.11422739, -0.16490164, -0.0022396361, -0.21486944) * go_1(0.0, -1.0);
|
||||
result += mat4(0.0010853866, 0.2223109, 0.2416471, -0.33326814, 0.2549397, 0.6442047, 0.18411863, -0.19081281, -0.43552014, -0.1793875, -0.58699155, -0.01900168, -0.26955804, -0.071371995, 0.07599079, 0.27434483) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.19644544, 0.14383379, -0.2599538, 0.001666124, -0.16369823, 0.009537702, -0.3690974, -0.048157427, -0.2040159, 0.01522431, -0.11007749, -0.07012568, 0.17536888, -0.012183123, -0.17366478, -0.15090804) * go_1(0.0, 1.0);
|
||||
result += mat4(0.0855136, 0.06863859, -0.17249937, -0.12850079, 0.15325847, 0.22742507, 0.22535504, 0.24032994, -0.109522276, 0.24135293, -0.17784368, 0.08172238, -0.16143093, 0.1358853, -0.09399085, 0.012180792) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.04346881, 0.13367178, 0.10387612, 0.04705543, -0.10315795, 0.5816371, -0.090529, -0.017955385, -0.09032907, -0.52505773, 0.10958755, -0.26151448, 0.17246644, 0.011886279, 0.3566306, 0.32170597) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.27853554, 0.1558035, 0.070289604, 0.17052644, -0.31982365, 0.29085326, -0.09494764, 0.2270542, 0.10514691, -0.24606484, -0.02049181, 0.126686, 0.16719124, 0.013080999, -0.08577963, -0.07057233) * go_1(1.0, 1.0);
|
||||
result += vec4(0.0061747693, -0.029145364, -0.026801255, 0.027419873);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!SAVE conv2d_3_tf
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.07447851, -0.07888509, -0.28236163, 0.2479792, -0.065199964, 0.24733023, 0.099619575, -0.26430824, -0.03523585, -0.03547245, -0.10619345, -0.25326422, -0.116270036, -0.065133184, -0.30401528, 0.01563764) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.19106275, -0.26104823, -0.14457102, -0.17298317, 0.24148639, -0.10950928, 0.062851585, 0.042540826, 0.13287601, 0.06975747, 0.15848075, -0.3854902, -0.13132331, -0.16468687, -0.029844414, 0.27754608) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.015378025, -0.14203559, 0.08058816, 0.32896644, -0.074871175, -0.26611313, -0.18830848, 0.091641426, -0.16522385, -0.23424402, -0.12279703, -0.13343342, -0.2509982, -0.0554576, 0.07286022, -0.028823337) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.13543738, 0.049395677, -0.015148539, 0.13301241, -0.12827122, -0.012590744, 0.012936948, 0.008271658, 0.12442749, 0.3497426, -0.16126058, -0.2670464, -0.010479037, 0.07037434, -0.15527055, 0.13205245) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.09535385, -0.3931354, 0.24716614, -0.21284536, 0.14652656, 0.38149378, -0.09607391, 0.06350967, 0.48615915, 0.32634613, 0.146291, 0.2566475, -0.40927815, -0.05268087, -0.04110691, -0.0068722935) * go_0(0.0, 0.0);
|
||||
result += mat4(0.089152284, -0.01860622, 0.016856732, 0.31244752, 0.022529159, -0.0071319416, -0.09786801, -0.13005258, 0.1524636, 0.21627748, -0.07395979, -0.087633945, -0.38435504, -0.08842507, -0.0058702417, -0.32936293) * go_0(0.0, 1.0);
|
||||
result += mat4(0.0816838, 0.0012210817, 0.28217188, 0.36141106, 0.0014665248, -0.0636269, 0.042035818, -0.056671552, -0.032501306, -0.22908778, -0.2067977, -0.004497514, -0.23052917, 0.26728114, 0.15353456, -0.17732324) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.17229734, 0.0818218, -0.10076918, 0.030027041, -0.14819005, -0.085340135, 0.050100215, 0.05683199, -0.12653661, -0.036583595, -0.32319903, -0.15273796, -0.15346588, 0.20005536, 0.23097478, -0.19834782) * go_0(1.0, 0.0);
|
||||
result += mat4(0.055430107, -0.2886931, 0.361814, 0.33160287, -0.084407054, 0.06254009, -0.02332793, -0.018134018, -0.014879812, 0.112346604, -0.20686437, -0.23408228, -0.01091196, -0.062669374, 0.085567676, 0.23738655) * go_0(1.0, 1.0);
|
||||
result += mat4(0.080383554, -0.1172084, 0.19703126, 0.27777427, -0.07559937, -0.25445858, 0.3450109, -0.071967736, 0.2034805, 0.33716002, 0.15314537, -0.22953224, 0.113631405, -0.0058444734, 0.2890972, 0.06557255) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.17646056, -0.025448758, -0.14952567, 0.017148364, -0.15238142, 0.1435677, 0.20273875, 0.22255951, -0.011660059, -0.003515217, -0.17305166, -0.13478355, -0.06558679, -0.032662887, -0.20914736, -0.5397283) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.1679393, -0.109410115, -0.117427185, 0.14982319, -0.06457877, -0.06607065, 0.0018200208, -0.0118605625, 0.046539318, -0.020642165, -0.14413542, -0.09530688, 0.22196163, -0.2187166, -0.10759705, 0.013234591) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.13220267, -0.12540027, 0.26163217, 0.12791659, 0.16204996, -0.4023048, -0.13485721, -0.10187536, 0.059764992, 0.048170995, -0.25281772, 0.2090587, -0.06542371, -0.10791867, -0.21286209, -0.309109) * go_1(0.0, -1.0);
|
||||
result += mat4(0.16233061, 0.120428756, -0.11460241, 0.24531102, -0.2670459, -0.24195078, -0.20964348, -0.12930301, -0.2343609, -0.22543164, -0.28909695, -0.33560297, 0.6009884, 0.39171818, -0.1276308, -0.020736236) * go_1(0.0, 0.0);
|
||||
result += mat4(0.40162864, 0.045881115, 0.032667033, 0.31454235, -0.17351128, -0.009387306, 0.17341217, 0.30810982, -0.025815086, -0.10390133, 0.012544771, 0.036918722, 0.34386298, 0.23177734, -0.046727546, 0.20098232) * go_1(0.0, 1.0);
|
||||
result += mat4(0.11541034, -0.11647824, -0.12874861, 0.004921287, -0.13921295, -0.25733355, -0.1112383, -0.033295818, 0.0035326157, 0.3782048, 0.055785846, -0.1547331, 0.17358719, -0.2789715, -0.13400431, 0.1583795) * go_1(1.0, -1.0);
|
||||
result += mat4(0.4130191, -0.33944547, -0.064674884, 0.39617148, -0.11483455, -0.022601767, 0.1129301, -0.09713594, 0.14681247, 0.34442267, 0.08721343, -0.08309499, 0.088704996, -0.20943391, -0.2891408, 0.1709401) * go_1(1.0, 0.0);
|
||||
result += mat4(0.19503653, 0.17490312, -0.23491044, -0.028934423, 0.04479765, -0.0334551, 0.0602648, 0.0019939998, 0.23314747, 0.21557438, 0.07273092, 0.15467109, -0.11194509, 0.0736583, -0.17628083, -0.3851578) * go_1(1.0, 1.0);
|
||||
result += vec4(0.022887055, 0.01521631, 0.17967467, -0.0131908795);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!SAVE conv2d_4_tf
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.10233342, -0.30233157, 0.24238978, -0.007108631, 0.14248851, 0.08486557, 0.0028373515, 0.122387215, 0.10996857, -0.17286511, 0.19819227, 0.07023527, 0.07579955, -0.16861476, -0.210025, 0.12760942) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.091181986, -0.41497424, -0.27567792, -0.09938067, -0.12210428, 0.20617811, -0.017644284, -0.22552875, 0.049019493, -0.18990634, 0.11057753, -0.043193225, -0.15278774, -0.18331046, -0.1837594, 0.029758787) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.1757096, -0.199691, -0.034743477, -0.15369363, -0.1701244, -0.0459655, 0.10508695, -0.09795581, 0.13464944, 0.37202564, 0.14706515, 0.23416734, 0.08302458, 0.20696343, -0.13935481, 0.03092827) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.49887478, 0.24046332, -0.029459715, 0.17374687, -0.15019977, 0.31086043, -0.28297687, -0.22239804, 0.12314376, 0.11594825, 0.17682782, 0.09753434, -0.26263535, -0.12739435, -0.57744014, 0.087381124) * go_0(0.0, -1.0);
|
||||
result += mat4(0.08101439, -0.16185337, 0.112901986, 0.24439482, -0.44051018, -0.70680356, -0.23015513, 0.63106006, -0.08817581, -0.057614524, 0.15352182, -0.049620207, 0.17742544, -0.49583626, -0.3844133, 0.18385352) * go_0(0.0, 0.0);
|
||||
result += mat4(0.17149475, 0.31255633, 0.19286609, 0.21052869, -0.11856372, -0.032373343, 0.06503625, -0.31664965, 0.040755365, -0.027614031, -0.33330554, 0.40148625, 0.056921627, -0.27068445, 0.047014963, 0.103712596) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.09326643, 0.13677256, 0.06390537, 0.08080093, -0.10685094, 0.124757454, 0.14696303, 0.10871933, -0.10971212, 0.01655797, -0.11052674, -0.17361104, 0.015513338, -0.1917502, -0.26384255, -0.022672707) * go_0(1.0, -1.0);
|
||||
result += mat4(0.032367155, -0.087523445, -0.06951093, -0.08128242, 0.2627859, 0.14933161, 0.3114999, -0.007791172, -0.4146471, -0.2530298, -0.43175155, -0.06878434, 0.5724947, 0.25498095, 0.4838959, 0.15076154) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.13427481, -0.10134261, 0.087439895, 0.015921364, 0.15421022, 0.20205952, 0.22928835, -0.07339068, -0.33318612, -0.17467582, -0.04758165, 0.11858059, 0.17408857, -0.099393494, -0.06389948, -0.06494366) * go_0(1.0, 1.0);
|
||||
result += mat4(0.15349221, 0.08508258, -0.09294437, -0.03204993, -0.22561033, -0.15088828, -0.020105945, 0.10041996, -0.024723593, 0.06610271, -0.24423431, -0.050512858, -0.100530736, 0.16394953, 0.16365045, -0.012055956) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.16342951, 0.23113559, 0.21289586, 0.28391558, 0.052211206, -0.17983536, -0.008415342, 0.08977486, -0.054481823, 0.17506577, -0.14162593, -0.070448756, 0.093877845, 0.05161232, -0.25006327, 0.007014646) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.104965575, 0.20048036, 0.024134496, 0.5442797, 0.19958296, -0.05165447, 0.076928124, 0.030868227, -0.0563495, -0.19757621, 0.10801544, -0.24202053, 0.0067657093, -0.17784451, -0.03134409, -0.06741009) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.33347723, -0.12338564, 0.23495969, -0.23091966, 0.059872203, 0.028045453, -0.06781438, 0.111325614, -0.21861015, -0.030451605, -0.04267672, -0.0039260075, 0.0911101, 0.054191053, -0.08498816, 0.04810343) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.05028896, 0.21515386, 0.16005337, -0.32279232, 0.19178568, 0.779363, -0.12682606, -0.4378189, 0.37980273, 0.063021325, 0.19370794, -0.05618088, -0.00088428083, 0.29736623, 0.24649377, -0.0021625878) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.45007992, -0.16040307, -0.1714593, -0.16251564, 0.070867635, 0.21317895, -0.070962, 0.17147541, -0.27786884, -0.33259448, -0.022767346, -0.17967366, 0.21208113, 0.19740848, 0.16877973, 0.09630738) * go_1(0.0, 1.0);
|
||||
result += mat4(0.09235827, -0.35231477, -0.093315996, -0.035850406, -0.08311695, 0.054329164, 0.17788444, -0.020736141, -0.03739786, -0.1678283, 0.12676615, 0.17182353, 0.17408027, 0.07699043, 0.095501214, 0.0069830767) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.16631392, -0.16925642, -0.17081848, 0.017719474, -0.20530944, 0.19215193, -0.039511178, -0.08296625, 0.2240653, 0.100644305, 0.2901835, 0.32166973, -0.10026419, -0.14864013, -0.19926691, -0.11607018) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.13750182, 0.07445518, -0.033964884, -0.085812084, -0.03903257, -0.054933593, 0.06765632, 0.064338475, 0.27182797, 0.07721309, -0.0334218, -0.19344835, -0.14405386, 0.046106674, 0.16596143, 0.0879945) * go_1(1.0, 1.0);
|
||||
result += vec4(0.049844168, 0.02670437, 0.050967637, -0.10779561);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!SAVE conv2d_5_tf
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.034357008, 0.00082413113, -0.13382089, -0.05066409, 0.26684088, -0.31363875, 0.073608615, 0.20824149, 0.21509308, -0.07118628, 0.11287014, -0.09817389, 0.16107765, 0.17146803, -0.13836654, -0.05962866) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.029981667, 0.08738892, 0.17735903, 0.15817277, 0.041752994, -0.20031185, 0.064203605, 0.48786053, -0.0033609737, -0.42522693, 0.058846988, 0.22180536, 0.17181319, 0.13097888, -0.059532285, 0.062227458) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.13188283, 0.07971828, 0.28278515, 0.038570832, -0.12815465, 0.29860008, -0.2785862, -0.07612298, -0.14369671, 0.12457525, 0.11982623, -0.018675303, 0.14936846, 0.1284789, -0.0042489986, 0.042810377) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.2892425, -0.20834558, 0.07358541, -0.11190968, -0.16300741, 0.15674856, -0.04297203, -0.29218298, -0.036296643, -0.052267153, -0.22889943, -0.21203549, -0.03553075, -0.20343691, -0.07413655, -0.092966415) * go_0(0.0, -1.0);
|
||||
result += mat4(0.2484468, -0.23412868, -0.070199326, 0.2061922, 0.5047224, -0.48216155, -0.5792768, 0.610787, 0.023935676, -0.040435325, -0.1238493, -0.09576053, -0.26183444, 0.14510648, 0.5365255, 0.5499143) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.058255754, 0.08133753, -0.18663554, 0.26190025, 0.26006857, -0.007619795, 0.14585225, 0.073580734, -0.0396066, 0.2821596, 0.31778112, -0.029853562, -0.19703479, 0.17809318, 0.21089044, -0.106730856) * go_0(0.0, 1.0);
|
||||
result += mat4(0.20549655, -0.05962688, 0.1432124, 0.013446325, -0.19064854, 0.061387196, 0.1792527, 0.0010619498, -0.1456842, 0.18950678, -0.13990986, -0.37644413, -0.083257, -0.2937246, 0.032096215, 0.14719158) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.26601696, 0.4242341, -0.073702715, -0.3221337, 0.026037043, -0.0117916465, -0.024286825, 0.23183465, -0.030869482, -0.045915652, -0.040611852, 0.11372697, -0.25404635, 0.21859063, 0.13869432, 0.19651218) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.028276298, -0.11217159, 0.27144867, -0.010531775, 0.11032058, -0.09957206, 0.12570262, 0.14724332, 0.08758557, -0.11042305, 0.025948172, -0.010910802, -0.029466914, -0.041135952, -0.017091949, 0.05501236) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.12688768, -0.19051413, 0.052141912, -0.13618521, -0.16320245, -0.1601866, 0.16207355, -0.023218745, 0.2103894, -0.06212745, -0.07042835, 0.0996637, -0.1763831, 0.13890013, -0.12125462, -0.105104685) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.10485512, -0.49283037, -0.504295, 0.009089699, -0.17389494, -0.12835866, 0.14188384, -0.22946316, 0.006298799, -0.0348454, -0.0852419, 0.17956656, -0.08088888, 0.35675287, 0.16014415, -0.055372503) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.17157564, 0.1557075, -0.17681694, 0.14834762, -0.13708206, 0.101721555, 0.17070566, -0.22522852, 0.08100986, -0.23204406, -0.38926315, -0.13165781, 0.1040296, -0.045591615, 0.15745829, -0.10410621) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.20517144, 0.35896194, -0.0010962893, -0.18043008, -0.016253468, 0.035292216, 0.06781499, 0.015984116, -0.20261237, -0.28905126, 0.007414641, 0.008870292, 0.52166605, -0.0996688, -0.23151648, 0.2811893) * go_1(0.0, -1.0);
|
||||
result += mat4(0.013482173, -0.04891998, -0.06094191, -0.14416319, -0.00087873987, 0.11979091, 0.06457245, -0.2305623, -0.1476981, 0.2634587, -0.058895197, -0.07394766, -0.27173743, 0.7530214, 0.037599873, 0.22086331) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.10357755, 0.23899554, 0.034912035, -0.14336212, -0.019786308, -0.085470654, -0.03096524, 0.108783185, 0.28971127, 0.24527478, -0.19110362, -0.49510127, -0.15574701, 0.10968643, -0.13727877, 0.04502924) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.10808282, -0.079148844, -0.3244773, -0.2210664, -0.0062175165, 0.1303082, 0.012592612, -0.38039228, 0.26899642, -0.16624425, -0.04438198, 0.42067865, -0.13381268, 0.03408099, -0.2999706, -0.3817641) * go_1(1.0, -1.0);
|
||||
result += mat4(0.030872926, -0.26852018, -0.14650428, 0.16869825, -0.19185568, -0.06341456, 0.12261606, -0.26597574, 0.44865233, 0.21416639, 0.40359476, 0.12814924, 0.2542566, -0.23348318, -0.43142912, -0.35113996) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.03364283, 0.11002299, 0.3311268, -0.14580412, -0.10348537, 0.13331696, -0.0793144, -0.04116661, 0.040704627, -0.14875266, -0.09259674, -0.062087066, 0.063962296, 0.18420577, -0.085616685, -0.16555141) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.037546165, -0.015675364, 0.13989694, 0.027605768);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!SAVE conv2d_6_tf
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.35835463, 0.038305778, -0.10198824, -0.021951782, 0.02142098, -0.072417736, -0.2577152, 0.054713376, 0.075116105, -0.21191697, -0.1213158, -0.105036296, 0.12030758, -0.17591658, 0.1726511, 0.17754573) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.32325825, 0.19869742, 0.333873, 0.39670366, 0.20716824, 0.09557955, 0.120742686, -0.2271023, 0.37509173, -0.031341635, 0.10247365, 0.031520665, -0.092765376, -0.13535516, 0.8333728, 0.05886494) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.17573749, 0.16768494, 0.021141645, 0.19668253, 0.21080776, 0.31503728, -0.26834, 0.19103156, 0.21946241, 0.14559007, -0.09761235, -0.23565038, -0.49393657, -0.5332298, 0.09806347, 0.054431103) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.042109374, -0.05564321, 0.27586877, 0.010382545, 0.007322007, 0.13193823, -0.18262729, 0.06399193, 0.14174329, 0.3898842, -0.10398105, 0.01846146, -0.24542394, -0.13020967, -0.16491668, -0.03544872) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.15291597, 0.1566557, 0.14745249, -0.23258151, 0.17843612, 0.15885495, -0.691466, -0.41177312, 0.40330106, -0.07991953, 0.2832403, 0.10656986, -0.19571523, 0.3670614, -0.62296015, -0.5666968) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.17513512, 0.011393021, -0.44352317, -0.059153114, -0.2227142, -0.033094753, 0.09624524, 0.051315393, 0.2632246, 0.09945105, 0.042561427, -0.1234722, 0.23755905, -0.506999, 0.114180565, 0.27887583) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.459564, -0.120326266, 0.17507194, 0.06701153, -0.14124362, -0.36653697, -0.2856802, -0.22955593, -0.08515889, 0.18788262, 0.23427077, 0.021544341, 0.31996533, -0.2668834, 0.08469808, -0.01347926) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.14092083, -0.31244513, -0.044023518, 0.013948701, 0.33119613, -0.011959397, -0.1494438, -0.111066826, -0.11994278, 0.116068155, -0.13032633, -0.037004936, 0.13851176, -0.006655432, -0.39841232, -0.079951204) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.08959123, 0.18297827, -0.0763483, 0.11364159, -0.04361797, -0.029816678, -0.19314721, -0.03484794, 0.044681285, 0.04669291, -0.30017474, -0.07453036, 0.090825416, -0.27414632, 0.36355078, 0.15742934) * go_0(1.0, 1.0);
|
||||
result += mat4(0.18470702, 0.113800436, -0.18546791, 0.044184085, 0.12490399, 0.1826781, -0.01313173, -0.19048993, -0.026458051, -0.1693334, 0.21958382, 0.030458853, -0.059242606, 0.039351143, -0.061676584, -0.06904634) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.114877924, -0.03781683, -0.19207929, 0.007679428, 0.2409049, 0.2965285, -0.38395065, 0.11604976, -0.22588749, 0.48505852, 0.09866521, -0.2585994, -0.011380872, -0.018334057, -0.047188547, 0.3038583) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.2783936, -0.17609318, 0.4904369, -0.31848624, 0.39725313, 0.082951784, -0.15595853, -0.007526218, 0.2355193, -0.30003366, -0.27686292, 0.120900005, -0.1223885, 0.40760317, 0.0013726618, -0.24877374) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.1580051, -0.044973504, 0.00053594523, -0.057797022, 0.18895927, 0.23527777, -0.18095906, -0.076961614, 0.2544444, -0.05932328, 0.13717431, -0.024487074, 0.33157274, -0.09072586, -0.004386734, -0.05180953) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.21685815, 0.061656334, -0.066127226, 0.24831405, 0.26001146, 0.046466008, -0.047196623, 0.13538954, -0.06449239, 0.45951647, -0.13132116, -0.7079741, -0.06683439, -0.47628635, 0.42461708, 0.6475073) * go_1(0.0, 0.0);
|
||||
result += mat4(0.2590011, -0.26020283, 0.0005333198, 0.01555692, 0.37920526, 0.29205114, -0.20281325, -0.1455974, 0.056119893, 0.022032745, -0.30095813, 0.48154855, -0.35761952, 0.07582935, 0.12462687, 0.068093665) * go_1(0.0, 1.0);
|
||||
result += mat4(0.20434918, 0.26690874, 0.028224666, 0.042565826, 0.037406113, 0.5059272, -0.0047208676, 0.0019095197, 0.16626422, -0.23407575, -0.072687164, 0.00063299487, -0.10172441, -0.11645544, 0.008715937, -0.012423992) * go_1(1.0, -1.0);
|
||||
result += mat4(0.08269191, 0.116322584, -0.08155921, -0.04790326, 0.09546776, 0.3632936, -0.08139031, -0.10399187, 0.06618616, -0.26862565, 0.25058737, 0.0410593, -0.07191658, -0.20559746, 0.21857823, 0.12776822) * go_1(1.0, 0.0);
|
||||
result += mat4(0.54989135, 0.38051483, 0.015739547, -0.0068143173, 0.26107135, 0.2585036, -0.12345306, -0.13934542, -0.19018838, 0.2730626, 0.42644337, 0.16693048, -0.15189888, 0.023638237, 0.11272267, 0.039560657) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.20554838, -0.10647836, -0.02824578, 0.08658529);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(M)-Conv-3x1x1x56
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_6_tf
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
#define g_0 (max((conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_1 (max(-(conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_2 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_5 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_6 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_9 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_10 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_13 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.030150581, -0.002168429, 0.014918388, 0.0, 0.020940892, 0.04591048, 0.049137186, 0.0, 0.111167125, 0.05311203, 0.0625381, 0.0, 0.020043287, 0.04785493, 0.040921766, 0.0) * g_0;
|
||||
result += mat4(0.04158565, -0.008488135, 0.0020472286, 0.0, 0.049123142, -0.055042226, -0.06489915, 0.0, 0.09238876, 0.10387972, 0.09576964, 0.0, -0.054776173, -0.098954335, -0.09018853, 0.0) * g_1;
|
||||
result += mat4(0.2081418, 0.08273068, 0.040325668, 0.0, -0.09937802, -0.13162258, -0.13989717, 0.0, -0.13983749, 0.01309777, 0.0023888077, 0.0, -0.18937743, -0.07021057, -0.047152344, 0.0) * g_2;
|
||||
result += mat4(-0.09646629, 0.080605574, 0.10463501, 0.0, 0.22579835, 0.24077554, 0.22600271, 0.0, 0.049726978, 0.015292378, -0.0047161994, 0.0, 0.16281025, 0.048491795, 0.038338162, 0.0) * g_3;
|
||||
result += mat4(-0.09772107, -0.043998875, -0.054745924, 0.0, -0.1257736, -0.13175423, -0.10889618, 0.0, -0.015900036, 0.07074481, 0.08210496, 0.0, -0.11321135, -0.12526917, -0.105605066, 0.0) * g_4;
|
||||
result += mat4(0.14187162, 0.14032297, 0.13016908, 0.0, 0.018954534, 0.016011704, 0.010169183, 0.0, 0.04762765, -0.044460997, -0.06499567, 0.0, 0.11133751, 0.09464176, 0.08865274, 0.0) * g_5;
|
||||
result += mat4(-0.16567162, -0.1744712, -0.1637222, 0.0, -0.02412003, 0.0074480795, 0.007903436, 0.0, -0.06161098, -0.046788957, -0.03971239, 0.0, 0.030736001, 0.036460854, 0.03660504, 0.0) * g_6;
|
||||
result += mat4(0.084027, 0.10024112, 0.08152756, 0.0, 0.005087354, -0.026047802, -0.027264625, 0.0, 0.10519243, 0.08977278, 0.077558964, 0.0, -0.052826345, -0.06602686, -0.055083472, 0.0) * g_7;
|
||||
result += mat4(0.007862721, 0.009936555, 0.012004831, 0.0, -0.042322706, -0.061728776, -0.05359773, 0.0, 0.030532641, 0.045623366, 0.04214089, 0.0, 0.030569768, 0.011892851, 0.0074041556, 0.0) * g_8;
|
||||
result += mat4(0.03948997, 0.043119986, 0.039943404, 0.0, 0.0526772, 0.06820589, 0.058139592, 0.0, -0.062081397, -0.06755701, -0.054816127, 0.0, -0.004076369, 0.0061744447, 0.016273081, 0.0) * g_9;
|
||||
result += mat4(0.0071622543, 0.004829105, -0.002032197, 0.0, -0.048541367, -0.059043564, -0.05662218, 0.0, 0.0015553127, 0.009178359, 0.009577062, 0.0, 0.114169896, 0.1349016, 0.11432262, 0.0) * g_10;
|
||||
result += mat4(0.019324556, 0.028323999, 0.027396113, 0.0, 0.016746879, 0.01608199, 0.026891617, 0.0, 0.12068619, 0.13617857, 0.113496214, 0.0, -0.013930715, -0.014250072, -0.00824306, 0.0) * g_11;
|
||||
result += mat4(-0.0024534757, -0.0064973077, -0.007905654, 0.0, -0.019158727, -0.024820521, -0.020509848, 0.0, -0.09608131, -0.11177871, -0.10503465, 0.0, -0.011210447, -0.010875943, -0.015295865, 0.0) * g_12;
|
||||
result += mat4(0.09681486, 0.113604136, 0.10416855, 0.0, -0.08199983, -0.09013433, -0.08562243, 0.0, 0.041304465, 0.048315883, 0.042945288, 0.0, -0.09863276, -0.117853515, -0.09870226, 0.0) * g_13;
|
||||
result += vec4(-0.0039074384, -0.0085585555, -0.0132283475, 0.0);
|
||||
return result + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(S)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.10922428, -0.16249932, 0.15452726, -0.15669551, 0.053448875, -0.16528402, 0.01697721, -0.049275912, 0.20947173, -0.10576949, 0.19738325, -0.025417482, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.3285196, 0.15909512, -0.5273671, 0.23778777, -0.40508887, -0.0609677, -0.4188177, 0.11137456, -0.24131267, 0.10453423, -0.36216277, 0.053446792, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.23072472, -0.082083695, -0.0041477727, -0.09136237, 0.11958912, -0.312698, -0.15842685, -0.013882424, 0.10933724, 0.017880991, -0.022167003, 0.014662608, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.2789985, 0.054727737, 0.22577816, -0.49625716, -0.48472273, -0.011525487, 0.5354349, -0.08814955, -0.27021924, -0.044563178, 0.008232271, -0.13480483, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.18203105, 0.09277001, 0.27071548, -0.17773713, -0.4335171, 1.2275106, -0.07663438, -0.29020032, 0.011992759, 0.060106967, 0.11002492, -0.046098012, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(0.08363418, 0.063420765, -0.10278259, 0.09357691, 0.38670546, 0.13577081, 0.048631024, -0.024960777, 0.0846784, -0.057097007, 0.06049236, 0.042082917, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.12315548, -0.056513585, -0.09826642, -0.17079762, 0.06479095, -0.36984903, -0.12512982, 0.042867575, 0.08360464, 0.12835538, -0.005067881, 0.02542005, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(0.18997705, 0.086363226, -0.0007131526, 0.19858918, 0.39745626, -0.0090341605, 0.27864447, 0.20052041, 0.010576528, -0.089242525, -0.025109483, -0.030768145, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(0.05427315, -0.060894873, 0.06548642, 0.095537595, 0.29116166, -0.16159569, -0.13293959, -0.112566955, 0.0059667625, 0.016041303, 0.03831561, 0.09869594, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(0.0113532655, -0.06449327, 0.035503868, 0.5683031);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(S)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.027102098, 0.2640691, 0.1169015, 0.030902913, 0.15404584, 0.1361459, -0.38066056, 0.096569136, -0.111836195, -0.0051853824, -0.0996669, -0.23538585, -0.07060754, -0.18889332, -0.10793357, -0.15154232) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.1378689, 0.21024452, 0.010976513, 0.0179521, -0.05993059, -0.28364083, 0.24486947, 0.21347582, -0.12522404, -0.16091396, 0.15499291, 0.08353191, -0.03342411, -0.08964405, 0.25111282, -0.07550899) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.06398718, 0.05763278, 0.021394925, 0.14780094, -0.033050716, 0.03346528, -0.0846797, 0.0125302235, 0.18018652, 0.24586707, 0.050538495, 0.09879243, -0.100035876, 0.043505374, 0.042692907, -0.08768257) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.11572878, 0.0545887, 0.16437739, 0.2775331, 0.10323911, -0.18938646, -0.17097469, -0.188723, 0.085762165, 0.14605838, -0.15568069, -0.16947642, 0.09042493, -0.087587915, -0.041969277, 0.27252352) * go_0(0.0, -1.0);
|
||||
result += mat4(0.21475963, -0.018211678, -0.5711054, -0.09235345, -0.20367791, -0.23041399, 0.16346097, 0.007901888, 0.12542121, 0.16807431, 0.09862575, 0.16968751, 0.28490388, 0.40945014, -0.22364445, 0.14460565) * go_0(0.0, 0.0);
|
||||
result += mat4(0.27512726, 0.14046481, -0.17684339, 0.102218024, -0.10503195, 0.3080809, 0.03681373, 0.2668656, -0.093752496, -0.07476867, 0.19900662, 0.06028286, -0.19815882, -0.0584525, 0.027984729, -0.02143819) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.16829525, -0.06818115, 0.0006509334, 0.01163159, 0.18918815, -0.10731989, -0.008126929, -0.47991323, -0.11022971, 0.19150843, 0.05272113, -0.34417602, 0.022882428, 0.1774031, 0.062597334, -0.09915319) * go_0(1.0, -1.0);
|
||||
result += mat4(0.32131585, 0.05668815, -0.34203658, 0.05542482, -0.008077225, 0.009148517, 0.10953332, -0.050969962, 0.09904077, 0.46938205, -0.5148919, -0.22275375, -0.10536104, -0.23662373, 0.002147416, -0.14256701) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.19335353, -0.103732094, 0.17156832, 0.0059756916, -0.118641876, 0.14529023, -0.18662338, 0.0447326, 0.026719248, 0.042491894, 0.026437795, 0.05601309, 0.08645617, 0.08365193, -0.039582565, 0.16612953) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.014315469, 0.012588422, 0.037587024, 0.08707526, -0.08064868, -0.28149533, 0.27326405, 0.21468583, -0.04278333, 0.29369017, 0.18653142, 0.035729136, 0.079363555, 0.30725953, 0.0147137, 0.08527481) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.06659263, 0.03452449, -0.33752796, 0.0066543026, 0.48697233, 0.019602561, -0.32033685, -0.20538871, 0.3089118, 0.4315903, -0.13524854, -0.10791581, 0.3315688, 0.13135147, -0.26904663, 0.142365) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.13619833, 0.045271892, -0.029841429, 0.010704955, -0.29257727, -0.10563375, 0.35345638, -0.06734038, -0.043791633, -0.0056891907, -0.078411415, 0.075443126, -0.05746597, -0.19959894, -0.12797245, 0.18837726) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.25673476, 0.120482095, -0.23827696, -0.13557845, 0.300447, -0.3008584, -0.13834439, 0.5459493, -0.26155484, 0.06905137, 0.16247983, 0.039960653, -0.023218757, 0.07977591, -0.11354706, -0.25831422) * go_1(0.0, -1.0);
|
||||
result += mat4(0.0842605, 0.282916, 0.14062001, 0.06356874, 0.55912817, 0.1743876, -0.30324093, 0.052068707, -0.20756413, 0.27321506, -0.26560605, -0.27695876, -0.3927334, -0.5439608, 0.39293098, -0.001130203) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.021890296, -0.12703396, 0.06660714, -0.03164527, 0.0018722567, -0.26552317, 0.06978973, -0.24030049, 0.46008193, 0.5595346, 0.081981994, -0.038414747, -0.010446991, -0.56102365, -0.079274766, -0.01851302) * go_1(0.0, 1.0);
|
||||
result += mat4(0.052988984, 0.030581746, -0.06868741, 0.21545182, -0.5706256, -0.0034910638, 0.48361364, 0.9020033, -0.02242781, -0.13256042, 0.08997955, 0.21001706, -0.059571438, -0.040119104, -0.05029196, -0.127414) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.08275339, -0.05999088, 0.11068767, 0.014646892, -0.041986465, 0.1028236, -0.17218924, 0.026559748, -0.17412743, -0.38364175, 0.17410514, 0.13038695, 0.23155633, 0.2655843, 0.045085523, 0.13005458) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.013383197, -0.064526096, 0.049046878, 0.015992291, 0.123987064, 0.0104690585, 0.07065378, -0.009824511, -0.036109775, 0.13384768, 0.29676288, -0.39475223, -0.009368096, -0.05666906, -0.09132696, -0.082638375) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.106538564, -0.065693766, -0.03790106, 0.04776706);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(S)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.024004154, -0.26474997, -0.5256586, 0.051624652, -0.16621786, 0.2964122, 0.6044247, -0.14335106, 0.17002718, -0.2679876, -0.30162668, 0.1273794, -0.17601459, -0.1782376, 0.104725115, -0.16351137) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.121676154, 0.047741555, -0.06738679, -0.056402843, 0.004424971, -0.35099635, -0.073440626, 0.039784692, 0.15204315, -0.1165704, 0.11231046, -0.27369732, 0.33737272, -0.11880767, 0.09637475, -0.14709689) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.017987821, -0.08798823, -0.062515825, -0.046803873, -0.05871703, 0.27013004, 0.19397618, -0.052147817, 0.003271283, -0.0029015478, -0.07390092, -0.09348337, -0.1574738, 0.06750957, -0.07661155, 0.054327156) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.15215784, -0.72508365, -0.3202069, 0.20295432, -0.19125701, 0.021401431, -0.051837035, -0.025939213, 0.25565025, -0.12872623, 0.13169816, 0.27377388, -0.008718429, -0.05864064, 0.028844763, 0.1144993) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.30012092, -0.1322455, -0.11868545, 0.09857058, 0.082795605, -0.075334676, -0.3752773, -0.02918163, -0.67764, -0.38598236, -0.21023573, 0.38274166, -0.07398165, -0.07213789, -0.28427607, 0.1266569) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.37507388, 0.18809201, -0.21982779, 0.27208912, 0.022066567, -0.27627763, 0.12345216, -0.30041683, 0.017002959, -0.091398515, -0.25207692, -0.29253414, -0.08231422, -0.14665812, -0.07868529, -0.24562219) * go_0(0.0, 1.0);
|
||||
result += mat4(0.08686712, 0.080837384, 0.20736577, 0.008233064, 0.14957365, 0.21801959, -0.04870689, 0.42149112, 0.27255878, 0.33320278, -0.08467146, 0.10381615, 0.055278245, 0.085710146, 0.009097151, 0.29092705) * go_0(1.0, -1.0);
|
||||
result += mat4(0.0012207404, -0.023874281, -0.027035477, 0.005157451, 0.19330226, 0.33711615, -0.16495204, 0.549021, 0.44879642, 0.1978837, -0.20492741, 0.28099406, 0.2631811, 0.40786585, -0.055340275, 0.2575511) * go_0(1.0, 0.0);
|
||||
result += mat4(0.29127392, -0.06287165, 0.12715077, 0.14784902, -0.3183704, 0.42057636, -0.11483724, -0.3019506, 0.010730576, 0.29091576, -0.046116166, -0.23528357, -0.0037143505, 0.1191774, -0.06084074, 0.011641706) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.2579205, 0.036545023, 0.11691888, 0.04996418, 0.21318026, 0.21370813, -0.14114271, 0.031217605, -0.06979331, -0.0690704, 0.04618086, 0.025164584, -0.10994228, 0.109930746, 0.103678934, 0.12193115) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.19843774, -0.11237926, 0.007291354, 0.16480611, -0.15669724, 0.46283355, 0.077065215, 0.112273656, 0.17143534, -0.19934891, -0.25481275, 0.034591813, -0.27032652, -0.2702769, 0.04816228, -0.031614583) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.16307239, -0.11295217, 0.05861256, 0.14225823, -0.015648091, 0.11741865, 0.113366075, 0.023935538, 0.19560932, -0.10553561, -0.042583376, -0.048160724, -0.3116519, 0.13957061, -0.0044852323, -0.015472912) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.15629178, 0.06463271, -0.13176678, 0.025518289, -0.021733627, 0.22236359, 0.019508492, -0.11629477, 0.10801276, -0.021957984, -0.11272639, -0.03615053, -0.121420704, 0.2520835, 0.043395765, 0.1699031) * go_1(0.0, -1.0);
|
||||
result += mat4(0.2886654, 0.21755892, 0.21757497, 0.08442575, -0.109903164, -0.67295986, 0.22886126, -0.027185453, 0.3761606, 0.23199768, 0.05908783, -0.1496158, 0.10832971, -0.3530352, 0.20234483, -0.07615918) * go_1(0.0, 0.0);
|
||||
result += mat4(0.11043024, 0.18943349, 0.42394367, 0.029350199, -0.15085667, 0.020204183, -0.081609115, 0.07907012, 0.33805525, 0.0066280114, 0.0018284445, 0.022983696, 0.004984607, 0.0429299, -0.14568979, -0.29143327) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.16376027, -0.20387048, 0.06522074, 0.17484841, -0.13885716, -0.04380927, -0.03535832, -0.16978237, -0.004799155, -0.25407305, -0.039976966, -0.011992087, -0.22535577, -0.09583549, 0.0334331, 0.016292758) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.38688713, -0.20232083, 0.23887886, -0.10438324, -0.24170811, -0.074868314, 0.03977399, -0.22810821, -0.08257971, -0.11902456, 0.106009185, -0.078289054, -0.11932821, 0.024207884, 0.10070917, 0.79348284) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.4018743, 0.050456528, 0.035341598, -0.03788609, 0.12964934, -0.44461823, 0.029031694, 0.29604837, -0.102386944, -0.13805065, 0.0055692918, 0.14659804, -0.22499937, 0.14680648, -0.3443954, -0.06994176) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.0063428865, 0.0057986965, -0.12526293, -0.059240736);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(S)-Conv-3x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.08631539, 0.09499331, 0.065609254, 0.0, -0.023760278, -0.027293118, -0.022839671, 0.0, -0.012447854, -0.008565141, -0.012041815, 0.0, -0.033292875, -0.031266093, -0.02874347, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.08709062, 0.09760889, 0.08988583, 0.0, -0.09099671, -0.102120616, -0.098076016, 0.0, 0.057814583, 0.06999608, 0.05961344, 0.0, 0.12246188, 0.1319784, 0.12254915, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.07694916, 0.0822054, 0.07549296, 0.0, -0.046808865, -0.051509347, -0.035890795, 0.0, 0.01599848, 0.014677793, 0.0086143715, 0.0, 0.033142705, 0.0426565, 0.035911378, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.0008269902, 0.0009082343, 0.014101725, 0.0, 0.0006387551, 0.005079344, -0.013034868, 0.0, 0.013909732, 0.011026747, 0.012485332, 0.0, 0.027028518, 0.022164145, 0.03183532, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.33575395, -0.36700967, -0.34140685, 0.0, 0.35850254, 0.37535715, 0.34613726, 0.0, -0.12680013, -0.1256115, -0.112494245, 0.0, -0.061541136, -0.059120018, -0.06552594, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.047570463, -0.050335366, -0.04665491, 0.0, -0.110970475, -0.12363716, -0.11072252, 0.0, 0.041563414, 0.059771337, 0.045290247, 0.0, -0.17999935, -0.19700716, -0.17459513, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.078488424, 0.07483357, 0.08347933, 0.0, -0.0063715233, 0.00035415235, -0.010886946, 0.0, 0.031237155, 0.02512343, 0.034399323, 0.0, -0.023146842, -0.026732154, -0.027644241, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.05906883, -0.06784104, -0.04506148, 0.0, -0.003939601, -0.0011749315, -0.006256036, 0.0, -0.1662408, -0.16871658, -0.16598499, 0.0, 0.051277652, 0.04837499, 0.05120855, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(0.08158806, 0.08674548, 0.07437206, 0.0, -0.05765347, -0.06196418, -0.057311118, 0.0, 0.26747537, 0.2668808, 0.2389857, 0.0, -0.010376844, -0.01690028, -0.008414153, 0.0) * go_0(1.0, 1.0);
|
||||
result += mat4(0.030539425, 0.02415435, 0.039969034, 0.0, 0.006491679, 0.014436586, 0.005435709, 0.0, -0.0058292216, -0.013982021, -0.011243379, 0.0, 0.025942149, 0.015361476, 0.019134998, 0.0) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.06322247, -0.07146787, -0.06673042, 0.0, 0.028702464, 0.039047733, 0.039646607, 0.0, -0.072553575, -0.08046175, -0.07027197, 0.0, -0.1447189, -0.1539398, -0.1466465, 0.0) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.046430312, -0.054549117, -0.048076343, 0.0, 0.032971155, 0.02980819, 0.029172963, 0.0, -0.017612953, -0.015100736, -0.01202649, 0.0, -0.026717246, -0.028401854, -0.034548033, 0.0) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.0020459262, -0.0008748501, -0.012601956, 0.0, 0.0054226154, 0.008867029, 0.018921215, 0.0, -0.0021330053, -0.0036601655, -0.0022091097, 0.0, -0.08636891, -0.10203159, -0.09741449, 0.0) * go_1(0.0, -1.0);
|
||||
result += mat4(0.07306159, 0.08245483, 0.06548199, 0.0, -0.1933229, -0.20326294, -0.19189309, 0.0, 0.107496604, 0.11584994, 0.10907522, 0.0, 0.30877885, 0.31297725, 0.30890995, 0.0) * go_1(0.0, 0.0);
|
||||
result += mat4(0.03192904, 0.035112645, 0.033732817, 0.0, 0.074100636, 0.08349646, 0.06659352, 0.0, -0.1136165, -0.12470947, -0.11192198, 0.0, 0.14465587, 0.16328491, 0.13984151, 0.0) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.05098033, -0.053096622, -0.05533725, 0.0, 0.0045651463, -0.007682458, 0.0026934785, 0.0, -0.021199327, -0.016210148, -0.030939564, 0.0, -0.031621892, -0.046702545, -0.02647333, 0.0) * go_1(1.0, -1.0);
|
||||
result += mat4(0.055801813, 0.06430485, 0.05052402, 0.0, 0.0241233, 0.013879883, 0.017344628, 0.0, 0.08707151, 0.10031039, 0.095042154, 0.0, -0.109053336, -0.11414017, -0.111838564, 0.0) * go_1(1.0, 0.0);
|
||||
result += mat4(0.030582374, 0.03604719, 0.040417343, 0.0, 0.038665913, 0.036998056, 0.030004544, 0.0, 0.09209076, 0.10010001, 0.08389406, 0.0, -0.014655714, -0.0074866647, -0.012227013, 0.0) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.008303841, -0.008251826, -0.0069884053, 0.0);
|
||||
return result + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,873 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.14361712, -0.16690509, 0.37253398, -0.45202538, -0.21331833, -0.32675815, -0.33971128, 0.20261937, -0.20606318, -0.215143, -0.079716705, 0.15640882, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.17360486, -0.3435545, 0.08199117, 0.56259036, -0.120246716, 0.24312893, -0.021436244, -0.11864853, 0.19452724, 0.106943935, -0.077393375, -0.3503661, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.072465785, 0.2772823, 0.25493625, 0.3098145, -0.115831695, 0.072458096, -0.014782132, -0.15310249, 0.12178311, -0.015555423, -0.2229811, 0.16469522, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.18652022, -0.30702665, -0.59921896, 0.079824045, 0.4426619, 0.049343713, 0.44902903, -0.2711445, 0.20470268, -0.029203767, 0.29092675, 0.15562426, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.21041247, 0.48450592, -0.110547826, 0.3842122, 0.5303875, -0.26512837, 0.19846216, 0.045673862, 0.12773214, -0.05117536, -0.03510946, -0.30123934, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(0.3186735, 0.052702922, -0.12499774, 0.055628903, -0.16476867, 0.12642322, -0.18314636, 0.018323101, -0.3609603, 0.25649396, 0.3185421, -0.0057759956, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.16603558, -0.09259665, -0.28760567, -0.14319661, 0.12511417, -0.12551902, -0.00070228375, 0.20914114, -0.22466865, 0.1064727, 0.32598525, -0.08596318, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.03163653, 0.026722813, -0.4361858, -0.21164834, 0.4176763, 0.08203146, 0.35289326, -0.06128859, 0.20506798, -0.07098943, 0.1807802, 0.2658414, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.09821681, 0.058886815, 0.39192092, -0.06791861, -0.15682612, 0.09503328, -0.23400265, 0.026475023, -0.08800713, -0.043749645, -0.18024494, -0.08045564, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(-0.040999945, 0.075765304, -0.0911532, -0.10705836);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf1
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.16406488, -0.2506693, -0.15592022, -0.05529256, -0.3997277, -0.229681, -0.07762124, 0.1843808, 0.07895815, 0.14437248, 0.219114, -0.048090722, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.2150676, 0.09080163, 0.19598733, -0.40578827, -0.33846557, -0.02518622, 0.037079208, 0.20188439, -0.013777575, -0.2369007, -0.30985412, 0.0411912, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.119948365, 0.23014452, -0.14962277, -0.096262485, 0.09625151, 0.2025487, 0.03933539, 0.12268028, -0.24373281, 0.19730613, 0.11634144, 0.12293635, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.08030697, -0.40114692, 0.21532272, 0.20222071, 0.073098, -0.004463858, 0.02820587, -0.18861918, -0.20994501, -0.12444653, -0.23178193, -0.13965288, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(0.14150894, 0.14563078, 0.697704, 0.20918849, 0.26776335, -0.34291518, 0.06394055, 0.17925078, 0.4165139, -0.042595536, 0.105312675, 0.231854, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(0.024318576, 0.16668217, 0.0729521, -0.7071404, 0.3121693, 0.37295797, -0.015632952, 0.33763757, 0.00706697, 0.10836652, -0.11132417, 0.292844, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.14489831, 0.0027769986, -0.24509215, 0.5557927, -0.1104541, 0.005070684, -0.020032275, -0.5642205, 0.16048644, 0.07248175, 0.20387374, -0.38145426, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(0.33140838, -0.007438425, 0.26074782, 0.15947102, 0.219755, -0.14690271, -0.07412696, -0.24176367, -0.2230114, 0.027256912, -0.11255796, -0.05882673, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.19712369, 0.003842208, -0.10893768, 0.09047115, -0.10260409, 0.18662766, 0.009733428, 0.0039940844, -0.006444674, -0.15196493, 0.06641555, -0.06169452, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(-0.029148052, -0.03215124, -0.6175828, 0.057135154);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.05195995, 0.15220909, -0.24354807, -0.109075695, 0.020483498, -0.14830725, 0.0018816335, -0.0072673927, 0.0649385, 0.046050787, -0.10789607, -0.046609525, -0.11455093, -0.009358115, 0.11280759, 0.18053898) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.08619698, 0.091353096, -0.16379662, 0.07822936, 0.072919995, 0.1482446, 0.17846228, 0.04639898, -0.18998149, 0.1653338, -0.44187957, -0.010017503, -0.069953404, 0.08784785, -0.16391355, 0.35095468) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.088297926, 0.27259287, 0.013088447, 0.023461785, 0.10037149, -0.017414214, 0.08559885, -0.10822335, 0.10591637, 0.17240539, 0.15749931, 0.026641782, 0.11889612, -0.018095117, -0.08736018, 0.09934933) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.21426749, 0.0800268, -0.19816414, 0.07693414, 0.026270509, -0.11724047, 0.026078718, 0.13080709, 0.12207936, 0.056103867, -0.323923, -0.111454345, 0.059245165, 0.07257926, 0.032195322, 0.27225617) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.20130268, 0.026809234, -0.0020803472, -0.04394057, -0.1982125, -0.033678252, -0.12881789, 0.0025656687, 0.14193355, -0.2541802, -0.13239717, -0.05983356, -0.029376393, 0.33187667, 0.14438996, -0.21993925) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.12772562, 0.022498213, 0.24753313, 0.07440761, -0.17564529, 0.09971503, -0.013372, 0.09459552, -0.21597451, -0.40116546, 0.23446435, 0.1515452, 0.050813515, 0.19662157, -0.10604596, -0.24638489) * go_0(0.0, 1.0);
|
||||
result += mat4(0.23866327, -0.2706382, -0.07480157, 0.03789501, 0.117716484, -0.095995456, -0.0435066, 0.013025061, -0.029759895, -0.036287807, 0.08570493, 0.030151363, 0.18863682, -0.27228612, 0.020479294, -0.07058746) * go_0(1.0, -1.0);
|
||||
result += mat4(0.0026758043, -0.20750894, 0.2802277, -0.07761428, -0.012089615, -0.112726666, -0.03867965, -0.085082226, 0.034227375, 0.19662802, 0.26272395, 0.036822405, -0.23040786, -0.20173554, 0.07110236, -0.26939383) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.14012688, -0.067249745, 0.14726773, -0.0070919944, 0.19275497, 0.04460783, 0.18776374, -0.019941995, -0.076159865, 0.002261728, 0.238768, 0.039375026, 0.13200568, -0.023286859, 0.034387972, -0.01827453) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.0107542025, -0.13001555, 0.06596806, -0.03370635, -0.024291076, 0.10367739, -0.03396605, 0.041960735, 0.16230568, 0.024845246, -0.016806586, 0.22547007, -0.025378102, 0.064547986, -0.2113137, 0.042272836) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.2219356, -0.049535394, 0.10289468, 0.14175911, 0.013058568, -0.15909089, -0.02546921, 0.11721571, 0.13020545, 0.39660174, -0.07601573, -0.16366366, -0.023935124, 0.06681424, -0.26143414, -0.07485668) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.1405031, -0.0645044, -0.15865614, 0.1829069, -0.22526503, 0.08991175, 0.041972812, -0.012462953, 0.3022753, 0.19457603, 0.022607598, -0.25460255, 0.028327515, 0.14420614, -0.077984214, 0.09278112) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.13224132, 0.13115089, -0.188987, -0.19428022, -0.080641985, 0.20909777, 0.067079, -0.19832124, 0.13150498, 0.04450851, -0.2770351, -0.010381239, 0.32295567, 0.04445836, 0.030657565, 0.020271502) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.08188993, 0.039709873, 0.16059989, -0.13279189, 0.11389818, -0.071865685, 0.09312801, -0.08816363, -0.65844774, -0.6854379, 0.21431407, 0.597198, -0.3734657, -0.116027676, 0.015932929, -0.0653176) * go_1(0.0, 0.0);
|
||||
result += mat4(0.24136105, 0.21444799, -0.14235207, 0.08445492, 0.017335927, -0.49877876, -0.06224622, 0.1571534, 0.035594277, 0.059829034, 0.087631516, -0.17090686, -0.005452869, 0.13786094, 0.27586326, 0.046760406) * go_1(0.0, 1.0);
|
||||
result += mat4(0.095078, 0.30310658, 0.010268592, 0.18540539, -0.20722823, -0.0005848572, -0.06464327, -0.111019135, -0.07837157, -0.12183798, -0.09187498, -0.3368629, -0.08216629, -0.20095807, 0.009563313, 0.024838416) * go_1(1.0, -1.0);
|
||||
result += mat4(0.28712475, 0.0641969, -0.034764312, 0.13600683, -0.09211094, 0.009699817, -0.001104855, -0.026146285, 0.33425868, -0.16132632, 0.18051304, -0.104004376, 0.20768233, 0.0888418, 0.050057285, -0.020228952) * go_1(1.0, 0.0);
|
||||
result += mat4(0.11642946, -0.021900529, -0.08910504, 0.15492517, -0.19726521, 0.1434987, -0.24708387, 0.006737377, 0.11353539, -0.15897587, -0.029491093, 0.06002862, -0.09640613, -0.11342702, 0.21375169, 0.0062719737) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.15513068, -0.3151456, 0.20799752, -0.07449935, -0.09226967, 0.112302735, -0.16211908, -0.37986508, -0.27418482, -0.10445544, 0.21112369, -0.06780466, -0.062341, 0.07758948, -0.012719117, -0.16481343) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.16382848, 0.14490448, -0.012869055, 0.1804095, -0.05304844, -0.14624795, -0.14816979, -0.17435774, 0.25356865, 0.11435022, 0.19412366, 0.19499794, -0.10189348, 0.023880519, 0.16822465, -0.17454338) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.04854064, 0.11944563, 0.022984248, -0.0852543, -0.0077684796, -0.044182744, -0.02888099, 0.27452356, -0.07887827, -0.15155658, -0.12841311, -0.21202831, -0.18533322, -0.05852455, 0.0761054, -0.22115342) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.21520375, 0.11415518, 0.18909843, -0.16420493, -0.20909967, -0.3257246, 0.29332343, -0.029541709, -0.1679851, 0.14073059, 0.32720464, 0.13311239, -0.0021121972, -0.08773544, -0.045532625, 0.36960867) * go_2(0.0, -1.0);
|
||||
result += mat4(0.58407414, -0.23632582, -0.16739567, 0.264173, 0.09584864, 0.18455075, 0.20051196, -0.04616608, 0.13441175, -0.0055764276, -0.08625195, 0.097847305, 0.19565724, -0.12183587, -0.11488796, 0.2520169) * go_2(0.0, 0.0);
|
||||
result += mat4(0.01584208, -0.31471413, 0.017104283, 0.0682452, 0.18728764, 0.042960413, 0.06437809, -0.14483811, 0.13882554, 0.016576322, -0.029599546, 0.034904055, -0.20939542, -0.10213055, 0.08821727, 0.0030552552) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.2973797, 0.15791039, 0.10811437, -0.07947077, -0.26328024, -0.061920475, 0.12498813, 0.100570425, -0.018922925, 0.002256239, -0.094379805, -0.032315314, 0.48677605, -0.04879864, 0.028028104, -0.14557233) * go_2(1.0, -1.0);
|
||||
result += mat4(0.016148027, 0.13884154, -0.19554809, -0.006344376, -0.013450252, 0.2581758, 0.10643088, 0.23465036, -0.078438915, -0.099644944, -0.1442203, -0.2285087, 0.33528957, -0.17052084, -0.26595074, 0.14794162) * go_2(1.0, 0.0);
|
||||
result += mat4(0.041404825, -0.0813985, -0.19863169, -0.008302881, 0.023570588, -0.043578386, -0.20971186, 0.14654282, 0.048436746, 0.11266723, -0.25812748, -0.03340969, -0.18430679, -0.046258014, -0.007674466, -0.037139155) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.060693484, -0.08285047, 0.06638212, 0.18479855, 0.11099276, -0.14470962, 0.16915078, 0.32247669, -0.10845523, 0.0027510398, -0.014941873, -0.15779859, 0.051481526, -0.14748912, 0.12125527, -0.059839584) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.27571446, 0.01663349, -0.057985745, -0.089736536, -0.09541078, 0.18101417, 0.084854685, 0.11060913, 0.05631825, 0.066835634, -0.02837782, -0.049748126, -0.050051138, -0.05126488, 0.27121767, 0.06331115) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.13630085, -0.03787764, 0.13351586, -0.024081819, 0.10403757, -0.0034796793, -0.04838045, -0.064052396, -0.34672704, -0.06271465, -0.024577484, -0.13450806, -0.013759927, 0.11706738, 0.07913658, -0.016639082) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.023730129, 0.020174952, 0.048988737, -0.013395666, 0.0073305597, 0.059409764, -0.27721968, 0.13349204, -0.022947624, 0.112007216, -0.008175606, -0.14903043, -0.35755506, -0.02145208, -0.021762518, -0.17889674) * go_3(0.0, -1.0);
|
||||
result += mat4(0.19315337, 0.16287236, -0.07667863, -0.020898499, -0.021058874, -0.20849414, -0.3571716, -0.13001479, 0.44977963, 0.016706442, -0.03471178, 0.35189477, 0.3050666, -0.019236205, 0.16278796, 0.3093703) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.1507458, -0.13747548, -0.05822537, 0.16035356, -0.08386089, -0.03476887, -0.0022021863, -0.032772254, 0.17572841, 0.004200287, 0.045312192, 0.27265742, -0.037853006, -0.056344658, -0.3095155, 0.15215549) * go_3(0.0, 1.0);
|
||||
result += mat4(0.11428048, -0.19523771, 0.016499955, -0.03625986, 0.15670861, -0.077859454, -0.059640404, 0.023970904, -0.009806148, 0.0904747, -0.006978744, 0.15938658, 0.030886533, 0.13507655, -0.002613293, -0.1335748) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.20070468, 0.06281564, -0.026250493, -0.042895693, -0.06574456, 0.10412931, 0.12061968, -0.0750467, -0.10865931, -0.05715226, -0.022071969, 0.02608941, -0.21416737, -0.18582128, -0.091236554, -0.044943426) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.057988428, 0.21430638, -0.17991407, -0.051662743, 0.060244065, -0.021494022, -0.018070806, -0.09278776, -0.011404125, 0.064091586, 0.12852973, -0.16610947, 0.08740408, 0.045517463, -0.27932477, 0.11050971) * go_3(1.0, 1.0);
|
||||
result += vec4(0.012687187, -0.11876551, -0.041985378, -0.10110911);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!SAVE conv2d_1_tf1
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.07579397, 0.008718031, 0.03874428, -0.022123579, 0.064964466, -0.27502275, -0.0053009577, 0.11669645, 0.007708085, 0.009340055, -0.13001843, -0.03758108, -0.07045759, -0.08749642, -0.21329811, 0.13205966) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.14087188, -0.12068241, 0.046639618, 0.05115712, 0.108357444, -0.05040456, 0.03280633, 0.09336891, -0.055509757, -0.036777936, 0.043575723, -0.041975956, -0.17782387, -0.12977566, -0.0736514, 0.17304243) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.2638534, 0.0385968, 0.14743716, 0.18057759, -0.036564615, 0.107838504, 0.08324167, 0.13403444, -0.41366392, 0.072824344, -0.013165103, 0.06114856, -0.040475495, -0.14222278, 0.10455181, 0.0021660402) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.30221993, -0.06315301, 0.057081617, -0.020285107, 0.053984016, 0.13086873, -0.30863532, 0.028010197, 0.0070908144, 0.19940577, -0.013766302, -0.039389495, 0.28064504, 0.05970737, 0.074613005, -0.10217121) * go_0(0.0, -1.0);
|
||||
result += mat4(0.042094592, -0.1725651, 0.3514404, 0.008126955, 0.08739713, 0.081543595, -0.12912413, 0.0854203, 0.28885832, 0.107783586, 0.22996111, 0.13907135, 0.071920335, -0.15172984, 0.07151959, 0.1406894) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.1072496, 0.03934067, 0.20014063, 0.051399443, -0.29610988, 0.18659018, -0.17761967, 0.08701774, -0.17493258, -0.08035252, 0.03155133, -0.13986085, 0.023490375, 0.083998375, 0.014006612, 0.03860323) * go_0(0.0, 1.0);
|
||||
result += mat4(0.09324427, 0.10990628, -0.18758917, 0.0054821614, -0.09425237, 0.1192338, -0.063183226, -0.15047066, 0.15664004, 0.037881903, -0.06762073, 0.09622682, 0.028449943, -0.25338468, -0.18897526, -0.18360007) * go_0(1.0, -1.0);
|
||||
result += mat4(0.030310342, 0.2083269, -0.04938559, -0.009608655, 0.019751158, 0.12257741, 0.090964966, -0.09864261, 0.058817703, -0.053385522, 0.15931179, -0.10585003, 0.06986225, 0.3435001, -0.33307528, -0.14035752) * go_0(1.0, 0.0);
|
||||
result += mat4(0.13506691, -0.00015406386, -0.15279713, -0.2290177, 0.019568326, 0.41041428, 0.10566904, -0.08350839, 0.19839814, -0.31052053, -0.04471875, 0.07629561, -0.117245845, 0.19819061, 0.1683647, 0.11896638) * go_0(1.0, 1.0);
|
||||
result += mat4(0.06920538, 0.2656798, -0.06529862, -0.1695985, -0.21614018, 0.17208195, 0.123307765, -0.061470803, 0.07827313, -0.18543327, 0.0937214, 0.098630935, -0.17667519, -0.01978596, -0.09126346, -0.034487445) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.030779282, -0.24423946, -0.08623178, 0.1490136, 0.029337894, 0.17548573, -0.05990294, -0.29123273, -0.10020608, -0.3527181, -0.105286725, 0.27502912, -0.25686985, 0.18521136, -0.110095225, -0.07999611) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.03266192, 0.045139533, -0.03275437, -0.13748369, 0.15633966, 0.089048125, -0.07592367, -0.09013536, -0.18907873, 0.08265683, -0.069233745, 0.27151683, -0.0647864, -0.15308899, 0.021954, 0.05528693) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.10284642, -0.14667438, 0.18669777, 0.053000864, -0.12383836, -0.037600834, 0.29438737, 0.04739594, 0.07846367, -0.11676573, -0.048153553, -0.34298027, 0.028358897, 0.119508564, 0.08012271, -0.019992562) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.22123314, -0.2223458, 0.002969434, -0.07143056, 0.027859585, 0.010600199, 0.056626067, 0.15160584, -0.16350581, -0.044484995, -0.1805076, 0.33351076, 0.073631234, 0.0167081, 0.15704727, 0.107799366) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.006882137, 0.19744347, 0.041128602, 0.17459555, 0.10376277, -0.12519689, 0.0993647, -0.13044195, 0.10485074, 0.1712284, 0.13369127, 0.24649777, -0.038975652, -0.24550107, 0.19567624, -0.09961197) * go_1(0.0, 1.0);
|
||||
result += mat4(0.24763626, -0.0902329, 0.21201743, 0.078442305, 0.013261817, -0.019013328, -0.07576136, 0.14993069, -0.24216306, -0.05666454, -0.064632, -0.38150248, 0.14649945, -0.020437164, -0.13821694, -0.026110074) * go_1(1.0, -1.0);
|
||||
result += mat4(0.21790951, -0.08288076, 0.011415891, -0.1446542, -0.15910968, -0.21221179, -0.06154624, -0.028623452, 0.10872824, 0.17089185, 0.26339474, -0.42544034, 0.095593184, 0.20962211, 0.0034138034, 0.024243662) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.050784085, 0.06333505, 0.041011192, 0.17474842, 0.14517011, -0.4340653, -0.10313813, 0.12524489, 0.18353751, 0.4589042, -0.037463415, 0.07841999, -0.114173576, -0.10669665, 0.029463472, -0.14393249) * go_1(1.0, 1.0);
|
||||
result += mat4(0.12771326, -0.06622126, 0.08327681, -0.15113758, -0.114005744, 0.059280578, 0.04071302, -0.11074485, -0.23312584, -0.032968838, 0.13736604, -0.15776984, 0.067029156, 0.0580463, 0.20655325, -0.2112593) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.16148107, 0.02879793, -0.24918973, 0.009605728, -0.102177374, 0.050518002, -0.00015101423, -0.046602443, 0.5081422, -0.044740383, -0.06243097, 0.076031074, 0.1157983, 0.03965003, 0.109161526, -0.36589798) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.018941574, 0.000912917, -0.2585099, 0.13668273, 0.062664494, -0.09246434, -0.14594543, -0.11160076, 0.015663203, -0.02447256, -0.070794076, 0.11807077, 0.12931514, 0.14109722, -0.07506544, -0.012781477) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.48816162, 0.16294348, 0.011336221, 0.107038386, -0.01978858, 0.039453425, 0.112853855, 0.007536018, -0.005471479, -0.11315905, 0.032013394, 0.11523904, -0.2504089, 0.04803124, -0.09689627, 0.24372064) * go_2(0.0, -1.0);
|
||||
result += mat4(0.61343086, 0.09531598, -0.24803302, 0.23788263, 0.13495958, 0.24733612, 0.1575427, -0.06863399, 0.2341275, -0.15821049, -0.165848, 0.0290172, -0.010136783, 0.04415787, -0.2619951, 0.09987892) * go_2(0.0, 0.0);
|
||||
result += mat4(0.19411229, 0.24528526, -0.250216, -0.33602244, 0.17639299, -0.052413136, 0.122578874, 0.028618507, 0.25713214, 0.22033587, -0.19680484, 0.028938502, -0.083384775, -0.06476429, 0.036840588, -0.14297847) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.2897587, -0.12176407, 0.19259763, -0.106649496, -0.026704982, -0.036201328, -0.06753124, 0.37967134, -0.20092241, 0.006229027, 0.12085137, -0.09810282, -0.1501556, -0.0099991355, 0.25044358, 0.08538966) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.11304407, -0.24147832, 0.21644448, -0.035938095, -0.036439262, -0.042730987, -0.04384442, 0.10325233, -0.32405272, -0.11873838, -0.15075137, -0.036929503, -0.10808143, 0.25799102, 0.13749036, 0.5451476) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.24142508, -0.04895773, 0.09022442, 0.2821465, -0.06298706, -0.1807906, 0.02960867, 0.22310257, -0.1915311, 0.2900501, 0.1670845, -0.080343634, 0.25779882, -0.27144584, -0.23575482, -0.14724477) * go_2(1.0, 1.0);
|
||||
result += mat4(0.020742219, -0.10571064, -0.0010137435, 0.14439318, 0.32805952, -0.027505733, -0.07111945, 0.07043296, -0.09525604, 0.03175366, -0.14633068, -0.15810682, 0.18050082, 0.08191363, 0.07047039, 0.0018573351) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.023874652, 0.14996628, 0.11298528, -0.1508891, -0.052415725, -0.02570088, 0.0055150646, 0.16365297, -0.046594325, 0.18095094, 0.09934885, -0.066233225, 0.2404304, -0.112728044, 0.14004207, 0.11369578) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.14799033, 0.025304591, 0.031008242, 0.03795376, -0.15800071, -0.043169834, 0.10797239, 0.17129694, 0.09674189, -0.11010672, 0.07283912, -0.11063907, 0.108249694, 0.025199141, 0.09162024, -0.1827302) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.08983324, 0.07823903, -0.137839, 0.11909572, 0.11996334, -0.05947995, -0.25459376, -0.18159851, 0.044489045, 0.052461334, 0.13674203, 0.12579007, -0.33665392, -0.07313439, -0.013640538, -0.010538632) * go_3(0.0, -1.0);
|
||||
result += mat4(0.0884388, -0.10034604, 0.047238693, 0.12025125, -0.16648497, -0.20305477, 0.08240087, -0.17453992, 0.19033237, 0.28438845, -0.32885036, 0.14011146, -0.13389368, -0.012868356, -0.15273216, -0.19119217) * go_3(0.0, 0.0);
|
||||
result += mat4(0.09196779, -0.13800567, 0.08842335, -0.18658079, 0.17512907, 0.021311145, -0.06347847, -0.13827331, -0.10689703, -0.1707886, -0.15724367, -0.167876, 0.22493233, 0.3070637, -0.035266686, -0.0068385694) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.2739973, 0.07336105, -0.196827, 0.060224827, 0.05752693, -0.014346674, 0.025412507, -0.27530053, 0.27755278, -0.07631679, -0.053861864, 0.113329165, -0.31025892, -0.012681806, 0.06228483, -0.054306302) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.16827694, 0.16333361, 0.068389125, 0.24560109, 0.11659498, 0.052896734, -0.020310031, -0.17830387, -0.07551057, -0.01822214, -0.037451357, 0.24607496, -0.2033962, -0.11107965, 0.05005381, 0.13685274) * go_3(1.0, 0.0);
|
||||
result += mat4(0.13665263, -0.24541081, 0.0012457973, -0.012630116, -0.09559698, 0.17756529, -0.039300505, -0.044217475, -0.22984356, -0.2294885, 0.104534455, -0.04131095, 0.084843494, 0.038027752, -0.106351435, 0.18853655) * go_3(1.0, 1.0);
|
||||
result += vec4(0.010324113, -0.01262194, 0.0762259, -0.014071781);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.06961854, 0.06914646, 0.120440066, -0.04889646, -0.012870159, 0.01994181, 0.052958567, -0.14740478, -0.0027199117, -0.004924673, 0.10131955, -0.11496505, -0.06742836, 0.08287776, 0.11206167, -0.021625644) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.025003597, 0.05389498, 0.14938618, 0.12255602, 0.050963886, 0.16300994, 0.17633909, 0.03229484, 0.2092038, 0.13367431, -0.09538967, 0.1636076, -0.022082182, 0.10898033, 0.0422286, -0.062253885) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.0018258828, 0.08333001, 0.002765037, -0.022241322, 0.1628206, 0.14671557, 0.3001151, 0.030986495, 0.05225914, -0.04880372, 0.15963705, 0.17972782, 0.055128947, 0.114626616, 0.03460699, -0.07679627) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.08866054, 0.0882386, 0.13833097, -0.079257324, -0.03060485, 0.049487974, 0.092268504, -0.17009564, 0.021603461, 0.20750603, 0.18884364, -0.10977116, 0.31758478, 0.053426504, 0.093257, 0.14912026) * go_0(0.0, -1.0);
|
||||
result += mat4(0.13069148, 0.21368778, -0.4405162, -0.009193694, 0.090230525, -0.15897161, -0.005089127, -0.06011075, -0.27336648, -0.021869129, -0.2084852, -0.0850094, -0.10896211, 0.27229342, -0.044210993, -0.03346366) * go_0(0.0, 0.0);
|
||||
result += mat4(0.05807779, 0.08506817, 0.23984064, 0.12547795, 0.036945213, 0.039088245, -0.10716132, -0.15966031, 0.13548918, 0.07746645, -0.248966, -0.15717135, -0.059498273, 0.0088413125, -0.02828682, -0.021795277) * go_0(0.0, 1.0);
|
||||
result += mat4(0.013289853, 0.007272393, 0.06875863, -0.053158432, -0.03578172, 0.20148727, 0.1961931, -0.16910668, 0.03259818, 0.054221123, -0.0326064, 0.06493197, 0.053533003, -0.11878436, 0.14398894, -0.17543368) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.17906332, 0.1111989, 0.047910325, 0.11560207, 0.09790123, -0.2023765, 0.04265116, 0.0075303926, 0.012974969, -0.0853146, -0.04037416, 0.14489946, -0.0716403, -0.055603035, -0.30376709, -0.011667526) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.053314358, -0.012657763, 0.0077033425, 0.12168191, 0.016371705, 0.11979062, -0.08494259, -0.009617431, 0.1303907, 0.043279216, -0.17285421, 0.15823162, -0.030746695, 0.121796146, 0.13097613, 0.0024783302) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.11677548, -0.06592395, -0.022185773, 0.0031006308, -0.00906918, -0.0006412884, -0.00083743286, 0.083697535, -0.060518038, 0.14058606, 0.122444086, 0.17866874, 0.02376487, -0.06369968, -0.026537767, 0.21466877) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.12340551, -0.015656117, 0.051990572, 0.04361656, -0.05291406, 0.10119005, 0.17603071, 0.10464767, 0.03288951, 0.091776796, -0.17373918, -0.12871055, 0.10205503, -0.17783496, -0.17020486, -0.09781929) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.01845568, -0.008877597, 0.14279746, 0.031775143, 0.041680444, 0.08784194, 0.044564564, -0.0011678484, -0.010219994, 0.10472676, 0.046920944, -0.110975444, -0.1197329, -0.11303071, -0.14893234, -0.091113724) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.03856561, -0.12173735, 0.040876064, 0.13847597, -0.14995924, -0.13332345, 0.18687452, -0.22562599, 0.08920785, -0.0017916666, 0.019448435, 0.2306492, -0.054546747, -0.1465318, -0.10628867, -0.0073827514) * go_1(0.0, -1.0);
|
||||
result += mat4(0.12689775, 0.11765595, 0.13039489, 0.06940679, 0.2672624, -0.03880143, -0.11693099, -0.05516293, -0.09665274, -0.2583138, 0.22954193, -0.19324702, -0.39629623, -0.35457405, 0.10052407, -0.19756024) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.06307673, -0.096393906, -0.0075868783, -0.25133502, 0.03436604, -0.008201423, 0.06386583, 0.106548436, 0.014626536, 0.03485315, -0.043418273, -0.1141408, 0.005102567, -0.11701804, -0.01645601, -0.057083) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.019062268, 0.020416953, -0.08854219, -0.037497565, 0.09449262, -0.09127615, -0.063330196, 0.08736769, -0.12394077, -0.17950213, -0.11101161, 0.16013645, -0.09370585, 0.0047447495, -0.04288296, 0.00314098) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.08263743, -0.14441489, -0.14886282, -0.05694989, 0.4254853, 0.10864832, 0.26322174, -0.042006254, 0.24269578, -0.053833783, -0.11558995, -0.066605136, -0.064816564, -0.25914803, -0.017624624, 0.0402331) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.100058846, -0.030422715, -0.19600148, -0.13322774, 0.1796998, 0.087852575, 0.07324559, -0.0047889417, 0.007248384, 0.08930289, 0.09643387, -0.0060126656, 0.16357517, -0.06628222, 0.030618697, 0.097391844) * go_1(1.0, 1.0);
|
||||
result += mat4(0.09539377, -0.10802722, -0.014952347, 0.1683223, -0.03919409, 0.041155327, -0.012186347, -0.030456683, -0.015024977, 0.061710294, 0.00049987395, 0.27338788, 0.04845922, -0.014114694, -0.06371904, 0.008664) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.063082814, -0.02755945, -0.15663072, -0.053271208, 0.070173115, 0.038125586, -0.11840675, -0.016337764, -0.07963128, -0.06404943, 0.23033784, -0.007848355, -0.04434174, -0.092422634, -0.013985954, -0.038096108) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.037121523, -0.020622304, 0.086708754, 0.045878958, -0.13188364, -0.022858748, -0.22411314, -0.08116162, 0.048863005, 0.039260563, -0.04934298, 0.11015131, 0.028177079, 0.025245499, 0.1067935, 0.15324049) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.068235874, -0.14401375, -0.032677606, 0.02996807, -0.11290208, 0.114133574, -0.09627152, 0.053930115, 0.14560424, -0.15935057, -0.13495773, 0.29710987, -0.23231608, 0.14334352, 0.070753984, -0.08189047) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.22378983, -0.09858718, 0.30114698, -0.0048736916, 0.02198528, 0.21444769, -0.11228022, -0.14812283, 0.092372194, 0.1598949, 0.2534843, 0.4932573, -0.16642319, 0.12972073, -0.04147445, -0.09365905) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.132199, -0.0798279, -0.18289213, -0.15133642, -0.033057958, 0.007495456, 0.070398286, 0.049111973, -0.03361502, 0.032059964, 0.003850814, 0.22922683, 0.20279214, -0.07350396, 0.27681342, 0.11891455) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.095355205, -0.08533997, -0.043466177, 0.03183743, 0.0048090555, -0.07969942, -0.044769235, 0.15350139, 0.06485437, -0.027922742, 0.0850892, 0.00069019396, 0.035737295, 0.20380683, 0.03413393, 0.025630401) * go_2(1.0, -1.0);
|
||||
result += mat4(0.26616514, -0.024066277, 0.09220501, 0.09643391, -0.014585791, 0.22894275, -0.053128377, -0.08719867, -0.08819027, 0.01932318, -0.113633566, -0.15435793, 0.10542983, 0.029819246, 0.33675614, -0.059085276) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.031325538, 0.040770013, -0.049561024, -0.2095101, -0.09537227, -0.075998954, -0.04323478, -0.05470401, -0.110066876, 0.059249427, -0.042351052, -0.047700178, 0.21932366, -0.12850443, 0.035361454, 0.013699006) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.08417607, 0.113477044, 0.03574209, 0.007835156, 0.2021717, 0.030678429, 0.19313626, -0.03506592, 0.04233059, -0.08540689, -0.07128929, -0.13245375, -0.08918939, -0.042622462, 0.19011301, -0.18228586) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.19981891, -0.16255717, 0.042949058, -0.06921157, 0.279451, -0.11536949, -0.13747527, -0.10020231, -0.013784027, -0.06727259, 0.3556115, 0.08460814, -0.15348805, -0.07692103, -0.018658075, 0.0037634284) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.09063814, -0.036312047, 0.13528036, 0.0070792423, 0.11834377, 0.02331524, 0.09386154, 0.07144935, 0.033078104, -0.1397121, 0.09283168, 0.2118868, -0.06313442, 0.032146804, 0.0060367053, 0.005822348) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.035949346, 0.06469895, -0.0051385965, -0.078584194, 0.43195483, 0.0045206803, -0.24012396, 0.21436183, -0.013394304, -0.04198491, 0.06645506, -0.23869638, -0.02311661, 0.06589808, 0.16800866, -0.21120183) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.24937367, -0.042277586, 0.08117994, 0.3105402, -0.26087892, -0.10325264, -0.08689298, 0.0064907144, 0.031937066, 0.09783758, -0.9514562, -0.104631096, 0.27990052, 0.36389935, 0.057687905, 0.14072314) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.19865227, 0.09398578, 0.06911146, 0.13077813, 0.024283953, -0.0036808057, -0.036725305, -0.024085987, 0.061556816, 0.0029027078, 0.24621862, 0.112107046, 0.068239614, 0.052718107, 0.20803368, 0.065064415) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.055511028, -0.08662344, -0.074801624, -0.021917107, 0.18730342, 0.047116343, 0.14872652, 0.10580926, 0.16962165, 0.16628978, 0.17343876, -0.1697205, 0.047853447, -0.22705628, 0.031780355, -0.09273609) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.17306295, -0.067308225, -0.17174196, -0.13221754, -0.24622467, 0.029901514, -0.12799668, -0.04145667, -0.14546, 0.013308366, 0.028113116, 0.1678875, 0.07922657, -0.015584258, 0.17059629, 0.07330948) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.09916512, 0.0623665, -0.022458963, 0.061962493, 0.18569344, -0.06590287, 0.111395456, 0.08477448, -0.03609452, 0.024279302, -0.083497405, 0.06459743, -0.22963138, -0.12262581, 0.006980887, -0.06653474) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.023354841, 0.0019475977, -0.0705355, -0.08216019);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!SAVE conv2d_2_tf1
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.13703531, 0.06135254, -0.05032855, 0.0039429665, -0.05997914, 0.03737832, -0.09703001, -0.08112204, -0.096779875, 0.086732335, 0.03021232, -0.14636067, 0.079296306, 0.006656948, 0.08904937, 0.06196539) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.26374274, 0.16698441, -0.08554561, 0.03734819, -0.08525629, 0.12257442, 0.015473835, 0.13266069, 0.008439022, -0.05002345, 0.03232084, 0.17349075, 0.014541135, -0.10353582, 0.13339484, -0.13474584) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.05637785, -0.049726896, 0.06597188, 0.0058668824, -0.10623723, 0.13441847, 0.015975956, -0.07811197, 0.05975957, -0.062021587, -0.06533749, 0.083735935, 0.02666556, 0.029904561, -0.0102926055, -0.10931666) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.22616413, 0.042830274, -0.116208926, -0.053796053, -0.1112898, 0.20703097, -0.34109348, -0.065111674, -0.17255561, 0.16784647, 0.00193431, -0.043237597, -0.02353095, -0.1302526, 0.05119598, 0.01403269) * go_0(0.0, -1.0);
|
||||
result += mat4(0.086109385, -0.053006437, -0.24992542, 0.007938272, -0.0027849772, 0.09198081, -0.17596659, 0.030577915, -0.31807357, -0.29618275, 0.0056317504, 0.3662508, 0.16753437, -0.12481447, -0.057597708, -0.14973637) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.14585754, 0.027715279, -0.039035518, 0.11505972, 0.0038059987, -0.20368981, -0.014822689, 0.094012834, -0.20693347, -0.37216228, -0.12690443, 0.2727411, -0.15475404, -0.01948714, -0.12414737, 0.10378582) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.11750072, 0.051394574, -0.011073509, -0.1100907, -0.1389209, -0.10706716, 0.0017484069, -0.059556484, -0.20038931, 0.24976069, -0.011129469, -0.080446415, 0.19259459, -0.14515446, -0.07275811, 0.039244935) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.101780266, 0.003889027, 0.010705813, 0.011088775, -0.20406786, -0.009807119, 0.23070864, -0.030722639, -0.012015954, 0.025211284, -0.29246482, 0.04907962, -0.10485314, 0.21213223, 0.15788344, -0.014188987) * go_0(1.0, 0.0);
|
||||
result += mat4(0.1546438, -0.15895118, 0.010730076, 0.034053337, -0.018741185, -0.008467293, 0.13143812, 0.022905342, -0.27543658, 0.3054419, 0.07025048, 0.29454592, -0.0032350307, 0.01671764, 0.081928045, -0.10051137) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.014834404, 0.07487839, -0.16554666, -0.04127725, 0.15239598, -0.017607473, 0.09927426, 0.15027349, -0.2073968, 0.041613225, -0.10290223, -0.12565911, 0.022021815, -0.07609557, -0.16338238, 0.04468512) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.01768976, 0.0637369, 0.006542782, -0.0022799321, -0.14728844, -0.058199093, -0.029928437, 0.079634584, 0.095769696, -0.13526416, 0.20718366, -0.10116214, 0.1688786, -0.08906526, 0.020397741, 0.06541649) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.033067044, 0.10095467, -0.13792777, 0.022673525, -0.012797848, -0.11222105, 0.11443862, 0.04893716, 0.11389547, -0.07337629, 0.21447009, -0.032212257, 0.23070163, -0.18156143, 0.14542435, -0.10207653) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.22985588, 0.012290226, 0.018557416, -0.064000085, 0.012936774, -0.104329854, -0.0719669, 0.24160251, 0.03716294, -0.093069404, -0.12110873, 0.013251573, -0.12731232, -0.1995954, -0.07679729, 0.06823493) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.23359679, -0.052702624, -0.08710696, 0.19826421, 0.12880315, 0.19875911, -0.20581602, 0.32980308, -0.14479029, 0.099422045, 0.44737315, 0.13044962, 0.12935589, -0.13621494, 0.14902137, 0.09162335) * go_1(0.0, 0.0);
|
||||
result += mat4(0.10801082, -0.22644557, 0.035719793, -0.12396268, 0.2906566, 0.119107775, -0.15470679, 0.17997102, -0.12866725, -0.12695445, -0.06832712, 0.017622665, 0.08215481, 0.065239124, -0.1256659, -0.06811625) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.097956754, 0.09383762, -0.19813508, 0.0035260199, -0.14278924, 0.0660843, 0.19110036, 0.11025648, 0.15489757, 0.011157471, -0.16014035, -0.050144047, 0.0032884583, 0.061513808, -0.03385016, -0.08534137) * go_1(1.0, -1.0);
|
||||
result += mat4(0.09499595, 0.04162155, -0.26091605, -0.18066265, -0.21523187, -0.036668014, 0.09586408, 0.059850723, -0.10890033, 0.28857672, -0.32993382, 0.05107536, 0.012024929, -0.27968574, 0.15081042, -0.07215633) * go_1(1.0, 0.0);
|
||||
result += mat4(0.15673614, -0.064684846, -0.13838115, 0.1264376, -0.23772664, 0.11594999, 0.0898036, -0.092647165, 0.26081505, 0.05110054, -0.017965768, 0.06740709, -0.24977967, 0.05645255, -0.08204664, 0.0435078) * go_1(1.0, 1.0);
|
||||
result += mat4(0.02560865, -0.1613835, 0.05876215, 0.101586774, -0.00058163394, 0.0013674656, 0.039857507, -0.002919488, 0.05573127, -0.04311352, 0.05305971, 0.10097247, 0.036392104, -0.025071293, 0.029137935, -0.08593101) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.12406646, -0.21399136, 0.05611706, 0.021867402, -0.037916705, 0.05941278, 0.11277805, -0.12387807, 0.008577062, -0.045022104, 0.16465645, -0.07607619, 0.035939474, 0.07221297, -0.13557361, 0.07806311) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.19589397, 0.011909766, -0.01258029, -0.065313555, 0.07366803, -0.0812486, 0.115863465, 0.019752543, -0.15854625, 0.11246406, 0.007201303, 0.0008530298, -0.0287012, -0.036224626, 0.059641607, 0.09416462) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.20361906, -0.20671111, -0.1126041, 0.049152024, 0.17586707, 0.10047246, 0.13149028, -0.16302691, -0.08559989, -0.17756243, -0.0061752857, 0.124775924, 0.020011704, 0.17147969, -0.0003063916, -0.015890911) * go_2(0.0, -1.0);
|
||||
result += mat4(0.11051906, 0.13774526, 0.29333818, -0.029932505, -0.07021508, 0.046212852, 0.11793092, -0.081830084, -0.18609521, -0.108229816, -0.044969153, -0.041069634, -0.13936938, 0.11356429, 0.19260931, 0.093210496) * go_2(0.0, 0.0);
|
||||
result += mat4(0.010555152, -0.15726428, -0.13187453, -0.12396212, 0.17309372, 0.100884624, 0.11547714, -0.030650318, -0.21877939, -0.0015167049, -0.090150684, 0.029793834, 0.1465573, -0.038805004, -0.033211514, -0.04926991) * go_2(0.0, 1.0);
|
||||
result += mat4(0.10250675, -0.030922988, -0.008545946, 0.024706079, 0.105154864, -0.06838902, -0.12627976, 0.032457255, 0.21747419, -0.12865087, -0.056018118, 0.07152061, -0.11214344, -0.029831404, 0.044855718, -0.04316971) * go_2(1.0, -1.0);
|
||||
result += mat4(0.12806997, 0.12385188, -0.06831653, -0.015933594, 0.08645126, 0.013043054, -0.19599608, -0.060719345, -0.23076192, 0.19181651, 0.1292978, 0.036317572, -0.061692618, -0.25434494, -0.10012762, 0.06366783) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.11098094, 0.034632366, -0.053560194, 0.08499573, 0.20842391, -0.020262053, -0.023394845, 0.048971336, 0.10436084, 0.12614205, 0.035942093, -0.07592917, -0.07455495, -0.012119416, -0.011834865, 0.21032205) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.00055114913, -0.06662242, -0.009248925, -0.0024843027, -0.22993802, -0.04828541, -0.08667693, -0.093717255, 0.14400347, 0.030130679, -0.01590651, 0.10399553, 0.14478837, -0.11228224, -0.039653912, -0.042144097) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.011044514, -0.09870122, -0.24879128, 0.111903004, 0.092567004, 0.06100228, 0.0053522107, 0.065252475, -0.18228072, 0.25602147, -0.2863954, 0.103064165, 0.052214783, -0.017557586, -0.07434391, 0.021111684) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.04537496, -0.024985183, -0.15247425, -0.0009907635, -0.09677889, 0.09858206, -0.030702371, 0.03539458, -0.029408665, 0.24335481, -0.1918429, 0.08056781, 0.1548214, 0.2850923, -0.15131058, -0.052048493) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.055409238, -0.13090813, -0.016612396, -0.019183576, -0.18499215, -0.013184845, 0.038750056, 0.10953814, -0.18437819, 0.19183092, -0.09780726, -0.046532292, -0.10841146, -0.17717329, -0.1731886, -0.06741823) * go_3(0.0, -1.0);
|
||||
result += mat4(0.27919188, -0.14904179, 0.22850563, -0.17785722, -0.32835802, -0.19134615, 0.32093298, 0.24667856, 0.51687604, -0.59745705, 0.23057328, -0.41411245, -0.4234339, -0.03083826, -0.13972719, 0.1729651) * go_3(0.0, 0.0);
|
||||
result += mat4(0.042352367, -0.109207705, -0.31047532, 0.08896513, -0.2187999, -0.117951825, 0.060705405, -0.10287316, 0.013815159, -0.023699438, -0.053614594, 0.09065406, -0.15286967, -0.101803675, 0.019537682, 0.12476822) * go_3(0.0, 1.0);
|
||||
result += mat4(0.0016159728, 0.04094818, 0.012745902, -0.051958837, 0.014557628, 0.00061195926, -0.11669799, 0.08763203, -0.27820277, 0.17871988, 0.10634548, 0.05234229, 0.03827577, -0.3117398, 0.027675012, 0.0655132) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.0025006514, -0.1457415, 0.053443488, -0.0050932285, 0.01582735, 0.18783967, -0.066718, -0.15485887, -0.039741408, -0.21280284, 0.1502977, 0.09507925, 0.17178543, -0.014238171, -0.35757875, 0.026410697) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.19434428, -0.079038315, -0.017264817, -0.04004242, 0.0063378955, 0.027904915, 0.02571677, 0.09895997, -0.036605608, -0.19889063, 0.015920812, -0.014095519, 0.4363826, -0.14143194, 0.015463533, -0.1656284) * go_3(1.0, 1.0);
|
||||
result += vec4(0.08523788, 0.052322272, 0.08955637, -0.06945023);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!SAVE conv2d_3_tf
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.048841953, -0.010713874, 0.09238948, -0.0789676, -0.093295254, 0.063662216, -0.023454266, -0.06739832, 0.027439933, 0.007399632, -0.03550259, -0.013834889, 0.17168441, 0.06177229, 0.023950668, 0.14574073) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.117296845, -0.07858486, -0.02099164, -0.024150673, -0.11662526, -0.26440877, -0.05449493, -0.13366842, -0.06870016, 0.12457937, 0.25052628, 0.013982828, 0.15127566, -0.031653196, -0.13851896, 0.04148151) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.024360385, -0.31051615, 0.012448293, -0.11265428, 0.06123606, -0.0701936, 0.033618104, -0.064061284, -0.06969811, -0.108838804, 0.014163671, 0.02596177, 0.20071186, -0.0028744373, 0.13663651, -0.05592813) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.13492568, -0.0726796, 0.13431883, -0.085713945, 0.056370113, 0.115660414, -0.14475793, 0.0044200714, 0.027387753, 0.045452334, 0.28178552, 0.017371183, 0.17304336, 0.0582999, 0.14465337, 0.046005037) * go_0(0.0, -1.0);
|
||||
result += mat4(0.064034574, 0.041531377, 0.08218889, -0.44529077, -0.010563538, -0.14926371, 0.051012456, 0.08209141, 0.24089444, -0.225398, -0.22259372, -0.26353076, -0.1687418, -0.11501685, -0.016655196, -0.09882357) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.019985389, -0.19189276, -0.104917, -0.11139956, -0.08406414, 0.031484302, -0.082132496, 0.025829919, 0.07512055, 0.31116992, 0.061163265, -0.074850895, -0.091695994, -0.26492774, -0.06617365, 0.06590624) * go_0(0.0, 1.0);
|
||||
result += mat4(0.1326703, 0.13008863, -0.1659525, -0.058325157, -0.047528613, 0.06777741, 0.06953616, 0.010587038, 0.031675722, -0.08119788, -0.11269768, -0.06225964, -0.26593694, 0.03627298, 0.12866129, 0.17876588) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.29016155, -0.12549841, -0.050858997, -0.088932805, 0.002237332, 0.01287246, 0.30138868, -0.071756564, -0.061206467, -0.11114371, -0.25731218, -0.11551616, -0.069513, -0.004583348, -0.10647163, 0.01981785) * go_0(1.0, 0.0);
|
||||
result += mat4(0.16387528, 0.03450354, 0.03422023, -0.014030813, 0.13418834, -0.010909722, -0.00447121, -0.03082622, -0.23983373, -0.020655053, -0.054034587, -0.07133469, 0.21171515, 0.06268651, -0.1738516, -0.15001713) * go_0(1.0, 1.0);
|
||||
result += mat4(0.040721033, -0.037582736, -0.13819644, -0.123978324, 0.1650318, 0.033942625, 0.17534302, 0.06452234, 0.18384823, 0.0048657497, 0.20220642, -0.0025760103, 0.011163899, 0.027265374, -0.051284578, 0.19202651) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.057493486, -0.031516504, 0.10835143, -0.040618125, -0.07762303, -0.06787725, 0.025559613, -0.0055560498, -0.0017830619, 0.020185964, -0.06656476, -0.008523214, 0.32331157, -0.21633361, 0.15338033, -0.104042485) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.18544987, -0.090446, -0.26797467, -0.082941435, -0.15003708, -0.11446041, -0.0394892, 1.1379096e-05, 0.04978554, 0.3350256, 0.032780237, 0.034625802, 0.0596261, 0.045886245, 0.009002243, 0.04746998) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.17104147, 0.0054165213, 0.09161088, -0.0673989, -0.119282715, -0.09094731, 0.47243354, 0.09914267, -0.13958418, -0.0050379517, 0.14352496, 0.18380567, -0.16128838, 0.08766813, 0.013876981, -0.09808636) * go_1(0.0, -1.0);
|
||||
result += mat4(0.09617889, 0.045525175, -0.2550057, -0.02874332, 0.2743444, -0.20102581, 0.008461914, 0.16626629, -0.13309516, -0.19307104, 0.15780488, 0.15518525, -0.2790243, 0.056782067, 0.16836968, 0.17771688) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.10694667, 0.14490083, -0.037976455, 0.013456577, -0.1166783, 0.060722847, 0.07323464, -0.013812333, 0.03234213, 0.50859296, -0.20670377, -0.019631205, -0.022543924, 0.21776745, -0.093769215, 0.12193299) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.15260598, -0.04798592, -0.02370747, -0.005714705, 0.030857049, -0.16643822, 0.23971851, 0.08117996, -0.069645695, -0.06674784, 0.033509918, 0.06333286, 0.14010383, 0.02218942, -0.036704093, 0.043163314) * go_1(1.0, -1.0);
|
||||
result += mat4(0.14653306, 0.002759894, 0.10548246, 0.24976018, 0.3212893, -0.07108953, 0.14068738, 0.29437128, -0.020556152, -0.17813908, 0.1989112, 0.12182122, -0.19231579, 0.06547012, -0.032785345, 0.089717634) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.23632105, -0.027022298, 0.00586518, 0.01836479, -0.2854795, -0.035417695, -0.07586866, 0.0715673, 0.17984483, 0.11210451, 0.032767817, 0.097993985, -0.010899036, 0.15933803, 0.05454052, 0.06768528) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.017289463, -0.058823984, 0.0807603, 0.32464716, 0.2756627, 0.036061637, -0.034578573, -0.08811335, 0.031841308, 0.11359879, 0.07553143, -0.028648997, 0.057192322, 0.07769366, -0.1998847, -0.06258051) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.0422091, 0.046305113, 0.028377453, -0.031071126, 0.06866086, 0.1538135, -0.009288249, -0.25543538, 0.07067607, -0.114061736, -0.024740022, -0.11824987, -0.17426041, 0.0028396242, 0.12849464, 0.057790644) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.057328146, 0.030677445, 0.07496485, 0.07847613, -0.22358766, -0.15659446, -0.18270054, -0.21316889, 0.084770195, 0.013863274, -0.001335942, -0.04027535, -0.15230416, -0.048156176, -0.04614562, 0.089494966) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.117369525, 0.026577681, -0.1941765, 0.14904885, -0.16210394, -0.19549404, 0.19999947, 0.37138188, 0.14809363, -0.05078633, -0.092692114, -0.08533522, 0.12769112, 0.017061725, 0.104464866, -0.026744602) * go_2(0.0, -1.0);
|
||||
result += mat4(0.0880251, -0.005333869, -0.10327546, 0.30419552, 0.107773595, 0.02335926, -0.19014318, 0.19670166, -0.09443473, 0.10621109, 0.36843884, 0.13197622, 0.24537645, 0.4032842, 0.21791221, 0.08400414) * go_2(0.0, 0.0);
|
||||
result += mat4(0.06408587, 0.15366535, 0.042582024, 0.15629277, 0.028716238, -0.013479061, -0.23052843, -0.2992272, -0.050045617, -0.27255702, -0.038093377, 0.0031149297, -0.05625518, 0.52598304, -0.0845234, -0.09116851) * go_2(0.0, 1.0);
|
||||
result += mat4(0.02294159, -0.011902539, 0.00079296535, 0.030631313, 0.02114366, 0.082455896, 0.09450867, -0.08027284, 0.042443607, 0.15427661, 0.11882799, -0.040319934, 0.23706424, -0.107808165, -0.1730313, -0.06340064) * go_2(1.0, -1.0);
|
||||
result += mat4(0.2645207, 0.002157867, -0.095794424, 0.1141035, 0.08255855, -0.06977906, -0.04348005, 0.27864936, -0.1197219, 0.015997604, 0.09500464, -0.0010631803, 0.07198933, -0.053128377, 0.02176274, -0.001298847) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.045475803, 0.03626341, -0.00891833, 0.17907676, -0.2810277, 0.13725498, -0.02413441, -0.08605496, 0.08306595, -0.012227401, -0.0070282067, -0.019027572, -0.13443586, -0.041331865, 0.029120144, -0.00490357) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.13398282, 0.06475972, 0.2528711, 0.02553969, -0.13428321, -0.03931247, 0.11360386, -0.18912545, -0.3725821, -0.018747944, -0.20893294, -0.012743096, 0.07444533, -0.15381604, 0.29776138, 0.10601149) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.21793252, 0.07817356, -0.109576665, 0.19185133, -0.072846025, 0.04960289, -0.07506936, 0.12839878, -0.0061091883, 0.093669325, 0.009295678, 0.03780657, -0.10901407, 0.1375137, -0.0745914, 0.1468883) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.10739044, 0.30611086, 0.1585515, 0.07903283, 0.05612715, -0.0061900485, 0.13646163, 0.15230569, 0.036846787, -0.15846778, -0.18765065, 0.06611226, -0.07209187, 0.056037188, 0.04302953, -0.03887873) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.05618538, -0.072312586, -0.018046018, 0.049542785, -0.033638306, -0.035169322, -0.25882784, -0.036425237, 0.43763217, -0.07049093, 0.08085481, 0.013634128, -0.2701461, -0.13007875, 0.09603447, 0.2479431) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.02283992, -0.24593964, 0.04616348, 0.023422526, -0.20994014, 0.064769074, -0.07680045, -0.30547765, 0.1518723, 0.31953967, -0.12841515, -0.19525428, -0.0076093865, -0.112106465, -0.04573789, -0.04834478) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.008045419, -0.20285496, 0.15290824, 0.036240693, 0.11959966, -0.15712506, 0.096806675, 0.008780234, -0.19716795, -0.3824029, 0.1376541, 0.13325086, -0.103316806, -0.31788048, -0.071698256, -0.25901568) * go_3(0.0, 1.0);
|
||||
result += mat4(0.13714787, 0.020738773, 0.13716534, 0.12359137, -0.038154524, 0.053202964, -0.12023912, 0.09011213, -0.012448548, -0.026505312, -0.11293235, 0.10613704, -0.39916727, 0.041521315, 0.10659441, 0.027749784) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.26475835, 0.044597875, -0.31229413, -0.17121075, -0.21795374, -0.009583571, -0.13428004, -0.30734754, -0.017038794, 0.113667324, -0.1516075, 0.06525228, -0.13789397, -0.05770066, -0.016166758, -0.29457557) * go_3(1.0, 0.0);
|
||||
result += mat4(0.054183286, 0.022085225, 0.086794585, 0.10968018, 0.1276148, 0.05739452, 0.08860957, -0.08131373, -0.081570424, -0.107991874, -0.03724999, 0.000843539, 0.20231429, -0.123543546, -0.19073018, -0.28328305) * go_3(1.0, 1.0);
|
||||
result += vec4(0.013646388, -0.021442367, 0.0045393505, -0.037433166);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!SAVE conv2d_3_tf1
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.13948695, 0.016643738, 0.08168136, 0.02315663, 0.017184775, 0.11487715, 0.05770107, 0.010102888, 0.04955321, -0.045132335, -0.05731744, -0.05798246, 0.2245112, 0.17406365, 0.08979801, -0.10607952) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.2812785, 0.022830509, 0.15164222, 0.13460225, 0.22263442, 0.2558749, -0.122489706, 0.10409658, 0.023308244, -0.19583783, -0.007824269, 0.06256542, 0.11161938, 0.14878923, 0.30865005, 0.08962341) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.20843887, 0.012371968, -0.008279775, -0.042467568, -0.13022369, 0.056743186, -0.018389069, 0.13964763, -0.03361555, -0.053087234, 0.012521351, 0.0209293, 0.015771557, 0.11718523, 0.010176676, 0.021708367) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.14373007, -0.114338934, -0.09077395, -0.11040866, 0.055298284, 0.022516333, 0.18901019, -0.05640152, -0.1413198, -0.08748339, -0.029985962, 0.00712751, -0.071436934, -0.18909407, 0.173448, 0.053675048) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.023129769, 0.42883545, -0.18110612, 0.24296297, -0.02441117, 0.18108079, -0.12298153, -0.19192219, -0.14139178, -0.069563635, 0.1524624, -0.17755614, -0.248875, 0.015161957, -0.16541803, -0.17773613) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.065477535, -0.113195814, -0.08284894, 0.11679537, 0.028445985, -0.026559185, -0.007267581, 0.14052133, 0.14847197, -0.040276285, -0.038166475, -0.030452784, -0.15184602, -0.22223297, 0.113732725, 0.11163395) * go_0(0.0, 1.0);
|
||||
result += mat4(0.04990171, 0.08493333, 0.08668171, 0.14610586, -0.010766879, -0.05690133, 0.10706113, 0.13667485, 0.044783257, 0.029695645, -0.101674624, -0.02023205, 0.031889528, 0.14293797, 0.08712652, 0.08716896) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.21387868, -0.21650635, 0.2743992, -0.048781313, -0.027735803, -0.1543507, 0.11343657, -0.18251626, 0.15225998, 0.13158897, -0.41056108, 0.102582805, -0.09181491, -0.0042975787, 0.056065407, -0.16961528) * go_0(1.0, 0.0);
|
||||
result += mat4(0.08966051, 0.09331515, -0.085415326, -0.022695992, 0.009771476, -0.07143986, 0.0590329, 0.07347928, -0.09033658, -0.06805735, -0.20129825, 0.017873045, 0.16908158, 0.014213783, 0.112663984, 0.10048714) * go_0(1.0, 1.0);
|
||||
result += mat4(0.115590535, 0.08364541, 0.00864431, -0.094349444, -0.11073411, 0.05337711, 0.055587426, 0.12131219, -0.04710173, -0.046455074, 0.110379905, 0.25445566, 0.15154606, 0.04483541, 0.08708686, 0.113456205) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.014296297, 0.24858733, 0.05035193, -0.09225393, 0.034625243, 0.06219943, 0.19825043, 0.04673499, -0.4083363, -0.39954248, -0.08299408, 0.048756655, 0.09862206, 0.01588621, 0.0070629907, 0.04173666) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.17356622, 0.1484559, -0.10054033, 0.013332302, 0.15200937, 0.08985606, -0.031668343, -0.026007611, -0.16339104, 0.054744486, 0.07386605, -0.033910174, -0.0018002358, -0.02968911, 0.054931052, 0.09970459) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.07330346, 0.05938635, 0.01911963, -0.09856661, -0.081916444, -0.046957035, -0.043849826, 0.09572135, -0.13621825, 0.034347896, -0.21189907, 0.10592239, -0.060592845, 0.09957844, 0.050621815, -0.07447668) * go_1(0.0, -1.0);
|
||||
result += mat4(0.044731334, -0.13406886, -0.04138754, -0.06764551, -0.018899845, 0.35320804, -0.10959127, 0.17435175, -0.17941645, -0.30889434, 0.10573405, 0.0319751, -0.15677677, 0.08164649, 0.16559398, -0.08152387) * go_1(0.0, 0.0);
|
||||
result += mat4(0.057760764, -0.12145107, 0.06889264, -0.30627275, 0.011501002, -0.080296256, -0.18067095, 0.10592384, 0.12884894, -0.18973115, 0.18740658, 0.28362688, 0.12934786, -0.010292026, 0.0559999, 0.079962276) * go_1(0.0, 1.0);
|
||||
result += mat4(0.048659086, -0.006250348, -0.041242067, -0.12078197, -0.07152629, 0.05699244, 0.0011704164, -0.023007339, 0.07814492, 0.02546712, -0.08957218, -0.036925297, -0.03383498, 0.12583385, 0.12207602, 0.03910942) * go_1(1.0, -1.0);
|
||||
result += mat4(0.26151723, 0.23277281, -0.021892069, 0.052827276, 0.18268764, 0.28595275, -0.20529993, 0.19892794, 0.0038986763, 0.114547804, -0.020574905, 0.02405073, 0.11713121, 0.04491106, -0.07557327, 0.014374293) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.14276731, -0.06600894, -0.029757235, -0.099975966, 0.023050314, -0.07662015, -0.11542214, 0.087981045, 0.070319094, 0.12462511, 0.008152087, 0.12613884, -0.07071591, 0.0063393894, 0.08699723, -0.0242523) * go_1(1.0, 1.0);
|
||||
result += mat4(0.035586607, -0.26826563, -0.10145326, -0.002177148, 0.022144236, -0.117452875, 0.021346297, 0.051908135, -0.022425706, 0.067299, 0.09406446, 0.078294896, 0.014900606, -0.05468236, 0.07241715, 0.061000507) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.184133, 0.06229474, -0.13819578, -0.025011744, -0.01868356, -0.18940887, 0.092631504, -0.092806384, 0.0035951615, 0.11777577, 0.028149817, 0.0049419673, 0.22230826, 0.06337655, -0.20004818, -0.20937593) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.13852163, -0.094492316, -0.040309057, 0.10771662, 0.18963522, 0.08687606, -0.20030232, -0.082126215, 0.012181411, 0.044306785, -0.036970526, 0.04403363, 0.07911973, 0.0021176056, 0.26944208, -0.06657045) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.027229607, 0.12410596, 0.04348171, 0.0019921176, 0.088246435, -0.02828269, -0.26499373, -0.12566662, 0.025947344, -0.0078000715, 0.058063716, -0.0032702687, 0.0059978673, -0.04860002, 0.027650384, -0.23394564) * go_2(0.0, -1.0);
|
||||
result += mat4(0.07892762, -0.13300626, 0.46678603, -0.033239357, -0.12306804, -0.079602, 0.20534003, 0.23873802, -0.035643574, 0.059950788, -0.26559883, 0.12206408, 0.25408483, 0.029933078, 0.32081822, 0.033947676) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.06847802, -0.017930118, -0.12299636, -0.12987946, 0.09267518, -0.0009083275, -0.035390552, -0.15379669, -0.1132433, -0.036670692, -0.08342377, 0.015636675, 0.022590527, 0.10533322, 0.0389949, -0.059033744) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.041753534, -0.014428097, 0.06999257, -3.546234e-05, -0.033465035, -0.040709455, 0.13118082, -0.21016484, -0.07846085, -0.030885663, 0.06934681, 0.12725256, -0.023784902, -0.13373604, -0.015261479, 0.05234782) * go_2(1.0, -1.0);
|
||||
result += mat4(0.13798563, 0.12757827, -0.26978776, 0.102494285, 0.13285922, 0.35432795, -0.11997128, 0.17108068, -0.12235328, -0.24582328, 0.26962712, -0.086760186, 0.010127441, 0.08048835, 0.047505867, 0.19991067) * go_2(1.0, 0.0);
|
||||
result += mat4(0.03584222, -0.13433793, -0.044629525, -0.0010440781, -0.0033084434, -0.026725832, -0.05386642, -0.13612603, 0.10066015, 0.10499841, 0.031767137, -0.04550841, -0.09391546, 0.1454157, -0.26962402, 0.21015608) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.21956864, -0.13502425, -0.02126954, 0.059263993, -0.13461533, -0.04001395, -0.0924258, -0.069165014, 0.22019973, 0.003270619, 0.022072528, -0.14173602, 0.0028843523, -0.13784003, -0.061057515, -0.0049253837) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.0011410525, -0.16098002, -0.12883134, 0.018262507, 0.001481578, 0.19514659, -0.13703239, 0.096059754, 0.34194204, 0.13983466, 0.14021507, 0.011405113, -0.11303146, -0.17050214, -0.06992079, -0.05566986) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.12307941, -0.02192472, 0.13193923, -0.061640862, -0.16841564, -0.0822524, 0.10141759, 0.02139286, 0.1599039, -0.050632223, 0.16702358, 0.111514546, 0.02397393, 0.037606515, 0.017971672, -0.048641708) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.02697617, -0.08579184, -0.28045088, 0.05262136, -0.059576314, 0.107535526, -0.06188862, 0.0010509328, -0.18178311, -0.17288832, 0.20703638, 0.083048366, 0.03859681, -0.07548898, 0.011605782, -0.021842534) * go_3(0.0, -1.0);
|
||||
result += mat4(0.13198483, 0.37200937, -0.0896539, 0.12450637, 0.037202634, 0.035985112, 0.16579124, -0.08967905, -0.24341385, 0.32482424, -0.3037812, -0.007154969, -0.007152382, -0.017435173, 0.12662841, -0.090513505) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.014726027, 0.08394915, -0.02100581, 0.24882795, -0.023793869, -0.006450114, 0.17093314, -0.06994153, -0.08689907, 0.113542505, -0.053211495, -0.1780173, 0.030043352, 0.2500714, -0.026940798, -0.0069258413) * go_3(0.0, 1.0);
|
||||
result += mat4(0.037078895, -0.03033529, -0.066851325, 0.14718252, 0.066372745, 0.028897487, -0.036055963, 0.035399746, 0.06733992, 0.21021596, -0.18314466, -0.027192699, 0.020213274, -0.17751546, -0.050674338, -0.09382659) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.14761917, -0.22166072, 0.033172436, -0.21982265, -0.09172891, -0.20794454, 0.1738752, -0.13685037, 0.10981111, -0.23169234, 0.053787973, 0.12001196, -0.038242023, -0.047124114, 0.22503005, 0.1015142) * go_3(1.0, 0.0);
|
||||
result += mat4(0.021231879, -0.015423476, 0.058986407, 0.032002006, -0.029305007, 0.008933183, 0.10777483, -0.112574644, -0.023935415, -0.06604598, 0.053859934, -0.08354717, 0.13703763, -0.078382134, 0.12914242, -0.022056468) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.002022359, -0.007333954, -0.038140967, -0.03819673);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!SAVE conv2d_4_tf
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.050738923, 0.15003614, -0.18880141, 0.16791905, 0.16549185, -0.26726744, -0.12813666, -0.021510791, 0.070805945, 0.043350577, 0.0035756908, 0.11776675, -0.01824196, 0.12618026, 0.07424072, 0.032886628) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.11678059, 0.0565686, 0.04392921, -0.27621672, 0.2116695, 0.038044345, -0.015018062, -0.028636303, 0.049744565, -0.12935996, 0.027176194, -0.13208814, -0.21195693, 0.08980974, 0.013893243, -0.018403184) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.3214697, -0.03143518, 0.19927292, 0.12566878, 0.16190828, 0.11784847, 0.09943727, 0.11755882, 0.017959306, -0.064603634, -0.14054321, -0.11917774, 0.0056958874, 0.06461699, 0.104604125, 0.021947173) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.24738057, -0.034892898, -0.03364674, 0.017340986, 0.02933764, -0.08090866, -0.034651175, -0.17391174, 0.08536477, -0.17446008, 0.22706915, -0.10555482, 0.0877744, 0.0681237, -0.035909466, -0.10355238) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.090646185, -0.12971672, -0.14531808, -0.060838025, 0.24902023, 0.1310588, 0.18602785, 0.21283495, -0.32160765, -0.070119165, -0.10350057, 0.19260244, -0.2610542, -0.3030521, 0.08432348, -0.22286619) * go_0(0.0, 0.0);
|
||||
result += mat4(0.28333843, -0.053968847, 0.08344997, 0.19987041, 0.22163449, 0.22161576, 0.0030572868, 0.10848695, -0.20529847, 0.08406883, -0.07130339, 0.09987656, 0.29774663, -0.08768785, 0.15567012, -0.010313759) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.1260916, -0.071901485, -0.30566844, 0.19393384, -0.05133266, 0.07868844, -0.24817581, 0.055521224, 0.23277187, 0.16324161, 0.07110341, -0.042626668, 0.052509766, -0.014292625, -0.019677468, 0.041733738) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.04264262, -0.06528029, 0.0013520801, -0.02140956, 0.27304867, -0.029477939, -0.1859993, 0.01418354, 0.07256604, 0.14302284, 0.03309569, -0.15932149, 0.01500576, -0.053860538, 0.1131707, -0.06272606) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.0400483, -0.030188695, -0.108427785, 0.057873204, 0.42774406, -0.11353873, 0.110134825, 0.052191462, 0.00087113964, 0.040683694, 0.100507155, -0.16746339, -0.26971558, 0.06506685, -0.20950548, 0.040783025) * go_0(1.0, 1.0);
|
||||
result += mat4(0.11394146, -0.10693933, 0.2377026, -0.03783948, -0.16496852, 0.046675198, -0.23396324, 0.05696911, -0.02770668, 0.12922443, -0.093586415, 0.102305606, 0.0040032533, -0.038440734, -0.0035825048, -0.22108772) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.17577791, -0.024538597, -0.19877498, -0.14544973, 0.16614193, -0.3279891, 0.14678721, -0.16355143, -0.012954231, 0.20982395, 0.044255227, 0.087878115, 0.11289659, -0.26981032, -0.10789584, 0.24094439) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.0041394173, -0.0937936, 0.15251775, 0.1026978, -0.01999847, -0.02865502, 0.16765144, -0.17490439, -0.016996933, 0.03891808, -0.01858217, -0.106255606, 0.027496144, -0.14120618, 0.023483312, -0.08291959) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.060642462, -0.2957824, 0.33968493, -0.04501478, -0.14999421, -0.0067213452, -0.018236576, 0.01627547, -0.07771579, 0.0124932695, -0.11797959, -0.090979554, 0.0096479915, 0.021336472, -0.07794724, 0.030138575) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.091704845, -0.20800348, -0.22158638, 0.048748583, 0.15139692, -0.2832814, 0.09610812, 0.41077513, 0.0007106381, -0.14465855, 0.0056652213, 0.031696238, -0.03384328, 0.1940933, 0.19262145, 0.014331562) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.16637586, -0.22008398, 0.102937706, 0.15260033, 0.039856806, -0.21082906, -0.19694057, 0.0712475, 0.015049883, 0.17320138, 0.06505415, -0.020279367, -0.018576574, 0.201407, -0.08108244, 0.04151909) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.12496581, 0.107817784, 0.10645319, 0.035113968, 0.0166165, 0.1316661, -0.045253787, -0.03863719, 0.09126881, 0.07553792, -0.029150097, -0.07629157, -0.17978054, -0.27080613, -0.028408276, -0.15366451) * go_1(1.0, -1.0);
|
||||
result += mat4(0.081859134, -0.11599677, 0.027383117, 0.092724435, 0.059302155, 0.10008954, -0.12217131, 0.07471211, -0.20396213, -0.040741358, 0.118772194, -0.21725504, 0.099645875, 0.09691941, -0.07696025, -0.016445495) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.18712623, -0.14458412, 0.03693652, 0.014525352, -0.09607279, -0.19400409, 0.032149505, 0.07106094, 0.051436905, -0.07765334, 0.017043818, 0.17777587, 0.05274306, 0.0062209824, -0.080005355, 0.026041988) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.090594456, -0.041637532, 0.10346829, -0.09393943, 0.027663473, 0.20729685, -0.011156861, 0.021863503, 0.04781304, -0.039483577, -0.092933334, -0.25187445, 0.033062164, 0.010756357, -0.13035728, -0.008321023) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.07772912, 0.010776647, -0.018709056, 0.25634038, 0.00906326, 0.21411708, 0.122652486, 0.07725616, 0.15266491, 0.1274286, 0.10400329, 0.20354506, 0.013765407, -0.039089683, 0.25870228, -0.08919069) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.14971368, 0.06935879, -0.089983195, 0.01406992, 0.16989979, -0.037809014, 0.07157283, -0.050660506, -0.032826405, 0.033794664, -0.0051332368, 0.089349195, 0.06263488, -0.07048108, 0.07263597, -0.11618368) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.013391823, -0.07888697, -0.13984044, -0.01241464, -0.06475807, 0.06978077, -0.20329754, 0.16602662, 0.013664227, 0.12317301, -0.10240692, -0.0657491, -0.31402445, -0.14472555, 0.1739024, 0.0005437834) * go_2(0.0, -1.0);
|
||||
result += mat4(0.16330495, 0.02644609, 0.23837087, -0.07734767, 0.12377497, -0.18478604, 0.35040903, -0.05262452, 0.049074646, -0.0077528385, 0.15370984, -0.22888668, 0.3603141, 0.29372314, -0.4432887, 0.20702155) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.18785694, 0.21085343, -0.111042105, 0.0478716, -0.08214944, -0.0922987, 0.29570273, 0.025100114, 0.25403878, 0.01271447, 0.21851794, -0.1434596, -0.21153769, 0.023305666, -0.10386609, 0.043919638) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.117247805, 0.013329102, 0.0313911, -0.08055777, -0.0053445757, -0.2886372, 0.07938673, -0.06659165, 0.20798062, 0.030106818, -0.04811631, 0.036332276, -0.057687126, 0.03813657, 0.035860628, -0.11273985) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.0031557097, 0.027456097, -0.14444692, 0.08411739, 0.13466308, -0.13212901, -0.0034804344, 0.1464661, -0.21033211, 0.05913627, 0.10233881, 0.009844489, -0.15369488, -0.018978333, -0.07518442, -0.010549853) * go_2(1.0, 0.0);
|
||||
result += mat4(0.112989105, -0.011166866, -0.08277204, 0.046827227, -0.08067428, 0.13465053, -0.1656419, 0.07280515, 0.037523627, -0.050147127, -0.17731906, 0.1067486, 0.119732924, -0.102017604, 0.31421226, -0.14060387) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.1106223, 0.09229271, -0.09355422, -0.02413533, -0.096457504, -0.13282233, 0.022983741, -0.13534859, -0.0056585902, -0.07214356, 0.14617127, -0.13723095, 0.058078192, -0.1038417, -0.10452195, -0.18855028) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.16357008, 0.080841675, 0.1663936, 0.20815827, 0.03813903, 0.34158087, -0.012987109, 0.39152008, -0.027927356, -0.14332302, -0.012866622, -0.016149148, -0.08733816, 0.1960951, 0.19572765, -0.2710826) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.024827998, 0.24175219, 0.030659903, -0.22227505, 0.026898654, 0.009930298, 0.088392995, 0.32644793, -0.10351868, -0.08717382, 0.22931585, 0.05197704, 0.06534648, 0.13636068, 0.062107667, 0.024806283) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.18550465, 0.062058095, -0.08620093, 0.20158216, -0.1460996, 0.14275469, -0.28057688, -0.11685651, -0.09627509, 0.09029933, 0.03669734, 0.1257313, -0.07974307, 0.020742215, -0.0039170664, 0.11340528) * go_3(0.0, -1.0);
|
||||
result += mat4(0.15225565, 0.171972, 0.13573253, 0.0056740018, -0.1667786, 0.06028638, -0.1255049, -0.23327217, -0.139949, 0.029957669, -0.16713464, 0.046236664, -0.05070503, 0.18714412, -0.20076098, 0.1672637) * go_3(0.0, 0.0);
|
||||
result += mat4(0.18468563, 0.07733334, 0.14463845, -0.10712052, 0.36213547, 0.29404843, 0.2110929, 0.14646721, -0.059985258, -0.2709805, 0.073061034, -0.039072156, 0.015898943, -0.17166951, 0.20194982, -0.04723745) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.26353067, 0.050225407, -0.42643914, 0.06601958, -0.10513071, -0.1654714, 0.0593609, 0.027410276, -0.19465327, -0.13865606, 0.05579213, 0.07982532, -0.20893136, -0.008150932, 0.053529713, -0.0317475) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.012075693, -0.27574313, 0.22184552, -0.117393926, -0.49310133, -0.13997443, -0.079180904, -0.053438634, -0.07552426, -0.045796394, -0.037434675, 0.24076645, -0.04395852, 0.10325762, -0.19867313, -0.070216134) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.026107877, -0.030023552, -0.047810435, 0.20572239, 0.061861858, 0.1776161, -0.306099, 0.16332485, -0.1843373, 0.06758581, -0.23902373, -0.10575018, 0.03990962, -0.046113137, 0.14876197, -0.21280771) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.009669773, 0.036289547, -0.050454646, 0.051479716);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!SAVE conv2d_4_tf1
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.14542116, -0.15827142, -0.20811677, -0.103433, 0.19787271, 0.33990738, 0.17085013, -0.059132278, 0.013047369, -0.1687924, 0.06732661, -0.050968684, 0.09197164, -0.041265316, -0.108277336, -0.014430892) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.022837132, 0.20440012, -0.14266612, 0.019944299, 0.069084294, 0.3171199, -0.1521742, -0.35806596, 0.13581008, -0.13811131, 0.12219503, 0.17329764, -0.15100783, 0.0862648, 0.118227705, 0.18736814) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.013604392, 0.11496102, -0.18734755, -0.047555517, 0.05297245, 0.006461213, 0.06247472, -0.0202791, 0.02329791, 0.11530998, -0.148774, 0.0965498, 0.1487269, 0.061629567, -0.22488646, -0.005393787) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.29286116, 0.11958281, -0.11193505, -0.17139061, -0.035151243, -0.2635945, 0.0002499315, -0.16346519, 0.23779829, 0.04454211, 0.21293561, 0.25617847, 0.12194803, -0.0017443774, -0.009216221, -0.034387548) * go_0(0.0, -1.0);
|
||||
result += mat4(0.28791443, -0.25421545, -0.058626153, -0.1520494, -0.16808414, -0.39723453, -0.13199537, 0.056999452, -0.048155293, 0.38699663, -0.114719056, 0.001293743, -0.0959443, -0.08189709, 0.26921842, 0.061219636) * go_0(0.0, 0.0);
|
||||
result += mat4(0.00781977, -0.07103863, -0.21942843, 0.2419546, 0.20016691, -0.28697264, -0.034715973, -0.03381459, -0.028126812, 0.046806023, -0.14423183, -0.13472253, 0.009225362, -0.086190686, 0.0041205613, 0.08953202) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.04926224, -0.099740155, -0.088695474, 0.09950333, -0.06495916, 0.20126842, -0.0062843356, -0.034764495, -0.10808971, -0.19946553, 0.075991094, 0.14746219, 0.08247818, 0.07382381, -0.056908615, -0.026823666) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.04837408, 0.12605472, -0.23957102, -0.14252385, -0.046534102, -0.07511751, -0.21040416, 0.2064639, -0.006026243, -0.25005546, -0.063780144, 0.076840036, -0.07484346, 0.017368162, 0.04657373, -0.022188455) * go_0(1.0, 0.0);
|
||||
result += mat4(0.04545079, -0.002226373, -0.11695467, 0.12954631, 0.054903183, 0.15162702, -0.19222596, 0.05351421, -0.079599276, -0.036238387, 0.1362261, 0.037431743, -0.0015106505, 0.18739921, 0.122365154, -0.05871144) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.005558987, -0.13553315, -0.006372213, 0.06633917, -0.22141413, -0.15780807, 0.057122614, -0.057320844, -0.06306763, 0.19112623, -0.041758966, 0.03555483, -0.005718873, 0.009167371, 0.050909385, -0.14599234) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.18175003, 0.10442485, 0.052994236, -0.4001252, -0.08328538, 0.06380226, -0.055015627, 0.010929493, -0.22888647, -0.033181675, -0.07570874, 0.07933599, -0.07894686, 0.12202901, 0.13679314, -0.054344065) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.030145945, -0.06121175, -0.08550973, 0.10082535, 0.07198805, 0.21414264, -0.25636044, 0.028803539, 0.043738026, -0.0367658, 0.27998537, -0.06274612, -0.22862338, 0.002624325, 0.28519824, 0.18540645) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.012136538, -0.07059324, 0.018098673, 0.12078888, -0.087637, 0.041642863, 0.034997553, -0.16741107, 0.04701011, -0.004160269, 0.122639626, 0.0043271836, 0.011551197, -0.16421974, -0.102481335, 0.014233497) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.37945676, 0.25232047, -0.03707734, -0.1985225, -0.11536396, 0.22039749, -0.21809638, -0.10596801, -0.17211124, -0.2035486, 0.011822896, 0.27510995, -0.105182275, 0.022503568, -0.0063389307, -0.071560584) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.16101715, -0.034247126, 0.16626042, 0.031131435, 0.03048031, -0.105447404, -0.05728527, -0.14518815, -0.019103229, -0.15152888, -0.119154684, 0.028724093, 0.05836196, -0.35943082, -0.016481897, -0.0437348) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.07719413, -0.33214888, -0.0541927, 0.16506542, -0.032792456, 0.016834807, 0.1724155, 0.073768586, 0.002303886, -0.001382793, -0.0562648, -0.10167158, -0.19101655, 0.052783452, -0.1422853, 0.09653729) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.30030164, 0.11637444, -0.23238538, -0.27238008, -0.077208534, -0.027645003, 0.10369907, 0.20162316, -0.14428844, 0.1766293, 0.024419712, 0.11301171, 0.07772854, 0.18613201, 0.20721672, -0.1751799) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.1026615, -0.12484944, 0.15386428, 0.038676128, -0.119472496, -0.032417197, -0.14208497, -0.05254358, -0.0035079278, -0.011276316, 0.043117497, -0.010022288, 0.031624593, 0.014969992, -0.031410277, 0.15284787) * go_1(1.0, 1.0);
|
||||
result += mat4(0.018149922, -0.05906194, 0.054767277, 0.008161979, -0.076949194, 0.040888708, -0.006419542, -0.12897012, -0.0028229658, 0.20937827, 0.02741711, -0.04013348, -0.12731804, 0.008064522, 0.002870103, 0.027690327) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.023197446, -0.08888926, 0.15531142, 0.13745947, 0.054352283, -0.121785395, 0.16237587, 0.023567237, -0.36160588, 0.30499592, -0.033180915, -0.1515843, 0.04251452, -0.17903805, 0.03235283, -0.08062386) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.0072868476, -0.2010616, 0.13061914, 0.12846659, 0.11725315, 0.14589547, -0.05373261, -0.081606135, -0.07010131, -0.025378224, 0.10265872, 0.18658938, -0.12165338, 0.036297683, 0.03925332, 0.16576236) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.10300252, -0.11548347, -0.08691649, -0.014866044, -0.3213804, 0.47206497, -0.16032113, 0.026284516, 0.046302956, -0.052474245, -0.025335522, -0.10957576, -0.16872157, 0.19049212, -0.023881195, 0.061396897) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.16202278, 0.52128345, -0.2601511, 0.06116799, -0.21123995, 0.39389637, -0.350544, -0.16157438, -0.02823116, -0.39056876, -0.14267299, 0.03262984, 0.342303, -0.20556125, -0.0019219286, -0.1824844) * go_2(0.0, 0.0);
|
||||
result += mat4(0.23399737, -0.0912646, 0.11152403, -0.20945886, -0.053451832, -0.09786892, -0.059099484, 0.18103573, -0.117154315, -0.18342866, 0.12650815, 0.0067340015, -0.037984423, 0.17667364, 0.071636364, -0.011689163) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.099510275, -0.0925438, -0.009136904, -0.03774997, -0.13348748, 0.3605135, -0.078298144, -0.14712195, 0.22566219, 0.18659295, 0.05614545, 0.10792911, -0.12477693, -0.03587624, 0.08050775, -0.054740936) * go_2(1.0, -1.0);
|
||||
result += mat4(0.10312337, -0.063681684, 0.16496794, 0.09038492, -0.08903926, 0.41163155, -0.013669214, -0.21472235, -0.054991595, 0.0033639956, 0.18160143, 0.17240305, -0.039428882, 0.17087695, -0.1729076, 0.09871825) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.13123736, 0.0802573, 0.077981554, -0.101768315, 0.089998, -0.13781744, 0.122858986, 0.054121554, -0.02640825, 0.13577555, -0.037485655, -0.04179625, 0.000106130996, -0.100183845, 0.00046665114, 0.21791616) * go_2(1.0, 1.0);
|
||||
result += mat4(0.011894387, -0.030088445, 0.025817253, 0.08193235, 0.109322436, 0.10855583, -0.19661167, -0.09405307, 0.2073779, -0.33972177, 0.048635002, -0.14883177, 0.056954246, 0.3953476, 0.18765114, -0.014010224) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.22594279, -0.014942035, -0.1519647, 0.25367293, 0.16330296, 0.03317176, -0.32148597, -0.46503916, 0.19944623, -0.26229686, 0.019909514, -0.059794176, 0.12912126, 0.044948537, -0.08649492, 0.08024645) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.022943841, -0.068013534, 0.11032515, 0.011685601, 0.020096298, -0.3285243, 0.08196111, -0.089537136, -0.03976742, -0.1315977, -0.36306036, 0.24678081, 0.22115967, -0.017472323, -0.19451386, -0.035218123) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.020891193, -0.12721714, -0.15030408, 0.026523203, -0.12413139, -0.11235275, -0.21476477, -0.11326953, 0.028815055, -0.18552732, -0.0076828003, -0.14679903, 0.020509586, -0.18695217, 0.06696879, 0.103938386) * go_3(0.0, -1.0);
|
||||
result += mat4(0.057521313, 0.28509304, -0.2525733, 0.16745082, -0.26614547, 0.18545172, -0.27140215, 0.018639714, 0.19730581, 0.1659491, -0.058363054, -0.4048628, 0.024913948, -0.44124457, 0.13872208, -0.0371103) * go_3(0.0, 0.0);
|
||||
result += mat4(0.100904405, 0.06700356, -0.035322092, 0.21781014, 0.018047005, -0.21737386, -0.3734802, 0.13506944, 0.012760691, 0.06620756, -0.0253398, 0.0030280363, -0.044015452, -0.055860534, -0.3547194, -0.04230283) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.19012743, -0.34408915, 0.18940191, 0.13152952, 0.107553795, -0.00694412, -0.07930157, -0.30964044, 0.034710668, -0.031806916, 0.019838978, 0.017044948, 0.110688254, -0.0029772928, 0.09414367, -0.10760175) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.05745392, 0.29022983, 0.014998233, 0.27365527, 0.08169933, 0.0734232, -0.09404464, -0.26870936, 0.21171738, -0.19529793, -0.064401075, -0.18972695, -0.08024953, -0.027122354, -0.11661348, 0.010131282) * go_3(1.0, 0.0);
|
||||
result += mat4(0.07599435, -0.06851123, 0.06258365, 0.10296892, 0.15556085, -0.041609086, -0.11303363, 0.07082365, 0.013949174, -0.087201476, -0.0855705, -0.12979257, 0.04048528, 0.4211556, 0.04118289, -0.22093314) * go_3(1.0, 1.0);
|
||||
result += vec4(0.07789114, 0.0024746545, 0.1891165, -0.0023716448);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!SAVE conv2d_5_tf
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.10883355, -0.14958352, 0.026701333, 0.090302855, 0.033934478, 0.120340124, 0.027125617, -0.16792692, -0.075757094, 0.28692973, 0.013230067, -0.040618937, 0.087148145, -0.05985753, -0.06352023, -0.05775848) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.18206549, -0.10363482, 0.097648725, -0.08801144, 0.31633568, 0.058347676, -0.009121898, 0.02594872, 0.14757825, 0.4730546, -0.008518203, -0.3090668, -0.004052835, -0.14166127, -0.010156037, 0.21191326) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.05735183, 0.039180398, -0.12357178, 0.04830351, 0.120369986, -0.052775342, 0.005902798, 0.07695394, 0.00602021, 0.16758691, 0.10287989, -0.1718468, -0.1319741, 0.16932078, -0.2055026, -0.31820264) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.05427556, -0.28392607, 0.08579091, -0.0015861926, 0.062348455, -0.27778792, -0.07450379, 0.01616914, -0.012357131, -0.056992117, -0.1896176, 0.018156245, 0.06499259, -0.076558664, 0.10341699, -0.08993959) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.05741742, -0.05414434, 0.18006511, 0.09840777, -0.11849741, 0.40419933, 0.21349974, 0.40268886, 0.23218039, -0.0680356, -0.3130592, -0.21271054, 0.13776754, 0.19114101, 0.17373541, 0.43457666) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.060757063, 0.11339545, -0.042958036, -0.06483378, -0.06681766, -0.056395415, 0.037868995, 0.033861663, -0.1041215, 0.0046828864, 0.14360638, 0.087886184, -0.26808187, 0.19876598, -0.05276215, -0.07073776) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.24029991, -0.14217372, -0.011767948, 0.011623913, 0.33820602, -0.24501325, -0.11444902, 0.14536968, 0.16780593, 0.0065867775, -0.074971735, 0.021472024, -0.10853042, 0.09527126, 0.009436061, -0.09688826) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.31893802, -0.0016892607, -0.105592966, -0.116694786, -0.007851739, 0.1429722, 0.0741952, 0.050125953, 0.07185179, 0.1900389, 0.030889044, 0.15422693, 0.12550323, 0.3556344, 0.108276874, -0.099125646) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.33620578, -0.11113713, -0.15881014, 0.028243937, -0.12028756, -0.028566968, -0.002682634, -0.15635195, -0.06869284, -0.03309234, 0.03086361, 0.050773233, -0.08939835, 0.15237434, -0.024076303, -0.13092752) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.31200737, 0.32207087, -0.068700634, -0.39202076, 0.0676771, 0.083766654, -0.05696634, 0.03088338, 0.046761762, 0.09732023, 0.030844063, -0.03369749, -0.12664944, -0.029924957, 0.10551989, 0.086157694) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.1919761, 0.17179352, -0.025805056, -0.05570367, -0.16736336, 0.07430868, -0.13228212, 0.10702857, -0.09723214, 0.1884809, 0.09422538, -0.16902041, -0.1964137, 0.17877853, 0.17453954, -0.11339361) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.11865004, 0.013131073, 0.17317963, -0.2077911, -0.1116894, 0.09672745, -0.023348883, -0.1176519, 0.15893579, 0.22941695, 0.18798698, 0.059098385, 0.09498779, 0.10118143, 0.08737761, -0.016268898) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.025380889, 0.17163627, -0.014800655, 0.12669696, 0.050048903, -0.06513837, 0.020915661, 0.2144372, -0.17799327, 0.0068409992, 0.06751171, -0.16618991, 0.14637277, 0.010591964, -0.15909241, 0.02660789) * go_1(0.0, -1.0);
|
||||
result += mat4(0.3178319, 0.15036377, -0.03386948, 0.13883169, -0.33842105, 0.061425313, -0.04195804, 0.22558802, 0.2250625, 0.060225345, -0.08467863, 0.0014776831, 0.080328, 0.03221249, 0.20838667, 0.11489719) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.0013924981, 0.28233197, -0.17997956, -0.10959627, -0.16253087, 0.016549526, -0.1571556, 0.017017027, -0.14697123, 0.0869202, 0.2104898, -0.15658243, 0.13424201, -0.022636503, -0.09512045, 0.0927298) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.038486905, -0.19215351, -0.2446516, -0.02958912, 0.06899297, 0.028667469, -0.05537665, 0.066711955, -0.0017354499, -0.07466053, 0.028587297, -0.042017035, 0.023596823, 0.0067433366, -0.14685915, 0.13400853) * go_1(1.0, -1.0);
|
||||
result += mat4(0.0573442, 0.1424536, 0.19606829, 0.07141616, -0.032276712, 0.20030099, 0.16644277, 0.10393295, 0.27240822, 0.0071844175, -0.023368603, -0.14067268, -0.20310283, 0.039528254, 0.103837095, 0.08236034) * go_1(1.0, 0.0);
|
||||
result += mat4(0.15616669, 0.3495403, -0.05678421, -0.069600284, -0.07361787, 0.079501756, 0.009530261, -0.032385882, 0.029831208, -0.095407076, 0.010261287, 0.15250465, -0.04868275, 0.058579214, 0.03779718, -0.10810775) * go_1(1.0, 1.0);
|
||||
result += mat4(0.06492073, 0.018667994, -0.004712761, -0.032692235, 0.04027288, -0.114499666, -0.04327484, 0.13778907, -0.09373396, -0.08822919, 0.04796151, -0.057756703, -0.26161298, 0.07182931, 0.12998815, -0.14389744) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.19001032, 0.13091461, -0.2551175, 0.013365716, -0.031779066, 0.002531366, -0.13807543, -0.14165778, -0.2701911, -0.0890182, 0.34704998, -0.008494185, 0.16179956, -0.060182545, 0.060827415, -0.17249492) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.10665868, 0.15999752, -0.042796712, -0.14010513, -0.014244899, 0.017433831, 0.053657144, -0.0965679, 0.23623326, 0.0690172, 0.1290121, -0.025523739, 0.122357905, -0.18172716, 0.02829383, 0.10042929) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.09273112, 0.09466892, -0.009225705, 0.16772579, 0.0813042, -0.16461512, 0.038097944, 0.19834967, -0.033650465, -0.12888893, 0.1414859, -0.021587005, -0.0047441716, 0.08880282, 0.020621201, 0.065779164) * go_2(0.0, -1.0);
|
||||
result += mat4(0.0051817205, 0.20322648, -0.077459775, 0.07461627, 0.1817634, -0.5371515, -0.29336745, -0.57652086, 0.035826538, 0.41058993, 0.21512514, -0.041881148, -0.2490056, -0.07172767, 0.20821427, -0.69866294) * go_2(0.0, 0.0);
|
||||
result += mat4(0.18961228, 0.027452804, -0.0075194626, -0.029665018, 0.28770384, -0.099777386, -0.12160496, 0.07690297, 0.30273837, 0.026466522, 0.18100439, -0.09078488, 0.2035407, -0.062081084, 0.06744994, -0.07512911) * go_2(0.0, 1.0);
|
||||
result += mat4(0.008473044, 0.07501521, -0.11242355, -0.039451122, -0.21818535, -0.07779562, 0.13194147, 0.084983595, 0.0770609, -0.034488454, 0.08823556, -0.07168295, 0.041894365, 0.0789253, 0.06191209, 0.013991105) * go_2(1.0, -1.0);
|
||||
result += mat4(0.10582237, 0.1514222, 0.10751824, 0.08231926, 0.23913008, -0.2673503, 0.036170945, 0.31463087, 0.026397424, -0.26629624, -0.07428361, -0.077513516, 0.0768238, -0.026638538, 0.12589583, -0.11521212) * go_2(1.0, 0.0);
|
||||
result += mat4(0.30389515, 0.18963532, 0.023015842, -0.10240883, 0.045651495, -0.036785256, -0.13346411, 0.16431254, -0.030950911, -0.03381929, 0.09413111, 0.03924852, 0.11044091, -0.10149653, 0.14114548, 0.07801978) * go_2(1.0, 1.0);
|
||||
result += mat4(0.029622428, 0.14528686, -0.034057826, 0.010664312, 0.059213262, -0.29354423, -0.08448559, 0.10569036, -0.02988314, -0.016480735, 0.042203777, -0.028342744, 0.36807576, 0.09301971, 0.123721026, 0.07806503) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.04849538, -0.09201287, 0.10069803, -0.031749677, 0.18774022, -0.27789372, 0.05288653, 0.08097265, 0.006918896, -0.060978457, -0.113319606, 0.008844536, 0.021804892, -0.0011744015, -0.35720357, -0.24996938) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.07147501, -0.09339197, 0.16154395, 0.3372506, -0.0004858638, -0.056553435, -0.12463908, -0.0047342298, -0.009141984, -0.13796125, -0.14035304, -0.104403175, -0.07054226, 0.12142519, -0.24971877, -0.1914648) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.008194284, -0.027617034, 0.004994261, -0.07672895, 0.25697777, -0.18313397, 0.03266311, -0.029157834, 0.010476624, 0.12394092, -0.059660904, 0.08561672, -0.0008583816, -0.044442356, 0.28336492, 0.065344445) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.3570137, -0.06802815, -0.10298613, -0.21256869, 0.3025278, -0.263425, 0.13547331, 0.038517762, 0.14951234, -0.16869017, 0.03293678, 0.21897063, -0.14688788, 0.21619378, -0.27550143, 0.048003722) * go_3(0.0, 0.0);
|
||||
result += mat4(0.15607022, -0.111073844, 0.2733694, 0.05423378, 0.25116092, -0.17350473, 0.13460433, 0.09602139, 0.17372625, -0.0024815476, -0.30154657, 0.0062206364, -0.0051755225, 0.04985103, -0.06310478, -0.30450678) * go_3(0.0, 1.0);
|
||||
result += mat4(0.057571005, -0.019051064, 0.054884393, 0.03993782, 2.6782007e-05, -0.05726912, 0.067192145, -0.08955987, -0.11937056, 0.15837386, -0.011670469, -0.06299701, -0.014917928, 0.23921679, 0.0054613873, -0.23099245) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.035849575, -0.06785954, -0.15053692, 0.011964653, 0.1975448, -0.1633047, -0.024539666, 0.03170174, -0.12585635, -0.021171011, 0.15862562, 0.10296358, 0.3114039, 0.10010659, -0.09519227, -0.12945092) * go_3(1.0, 0.0);
|
||||
result += mat4(0.044433746, -0.058466546, -0.13258536, -0.033972915, 0.0037206819, -0.057343487, 0.13798106, 0.044445634, -0.22623023, 0.2408462, 0.048287082, -0.30717465, -0.13402344, 0.20024839, -0.026932377, -0.034217034) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.05988374, -0.23198523, -0.058251306, -0.038808554);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!SAVE conv2d_5_tf1
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.045249436, -0.040327657, -0.2667367, 0.0913868, 0.14961123, 0.07253207, 0.29162952, -0.11320944, 0.017569833, 0.012350104, 0.22532712, 0.025312115, -0.12193993, 0.037391737, 0.03220835, 0.12102545) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.020587588, -0.07043244, -0.28093454, 0.18336722, 0.08153308, -0.05914772, -0.15255487, 0.079236075, -0.4269835, -0.11470208, -0.19043571, 0.2723162, 0.0066251885, -0.17115718, 0.022036036, 0.07349558) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.09441315, 0.042170826, 0.071251415, -0.13891962, 0.10236482, 0.05356262, 0.0291025, 0.063867815, -0.14530063, -0.08727925, -0.0048300857, 0.06766869, -0.3481536, -0.10943503, 0.014951926, 0.11993114) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.13420522, 0.095721036, -0.1756104, -0.09906728, 0.09808904, -0.27402034, -0.102161326, 0.40162942, 0.13465238, 0.20237032, 0.3192343, -0.061512157, -0.20711629, -0.09659007, 0.06838548, 0.30256763) * go_0(0.0, -1.0);
|
||||
result += mat4(0.025805298, -0.0322599, 0.23653145, -0.2760735, 0.11291006, -0.10836205, 0.20742846, 0.06974535, -0.4191803, -0.10882523, 0.038603242, 0.22662747, -0.08845715, -0.26151156, -0.16670766, 0.008536192) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.085842185, -0.21239999, -0.032774646, 0.088163696, 0.038300447, -0.09510875, 0.10113864, -0.14712982, 0.14264707, -0.10895432, 0.03051617, -0.06791873, -0.35589013, -0.12884575, -0.09460007, -0.0879575) * go_0(0.0, 1.0);
|
||||
result += mat4(0.19235751, -0.109611385, -0.037397474, -0.26632717, 0.07878826, 0.19749992, 0.0035685285, 0.11793927, 0.019899402, 0.085741036, 0.08433813, -0.018344546, -0.0901484, 0.08221562, 0.12735383, 0.12801875) * go_0(1.0, -1.0);
|
||||
result += mat4(0.19123435, 0.007882246, -0.018564796, -0.09904253, 0.28052533, 0.6360808, 0.25001726, -0.30590564, 0.07646281, -0.34298185, -0.33293694, -0.036753535, 0.18719083, 0.22131144, -0.1420962, -0.0014709529) * go_0(1.0, 0.0);
|
||||
result += mat4(0.23060241, -0.14145076, -0.113213465, 0.037221998, 0.22163334, 0.18520229, 0.2961799, -0.063605964, 0.022606356, 0.043340076, -0.3233993, -0.075055614, -0.0038865958, 0.19558622, -0.018503085, -0.22932632) * go_0(1.0, 1.0);
|
||||
result += mat4(0.11712158, -0.03590364, 0.38039652, -0.019910801, 0.13338004, -0.07078425, 0.09404417, -0.27607328, -0.02205519, -0.013522961, 0.2924021, -0.16088538, -0.034280356, -0.063614614, -0.061583273, -0.22479968) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.05624079, 0.32659104, 0.47335497, -0.14091404, 0.14739423, -0.07122778, -0.009384643, -0.058900848, 0.06260307, -0.17574102, 0.3538743, 0.2842822, -0.18150197, 0.26806462, 0.24673693, 0.19710627) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.24837571, -0.01663848, -0.13093965, 0.30109972, -0.09680959, 0.074526474, 0.024111765, -0.012781737, -0.08591349, -0.100348584, 0.02363011, -0.02687084, -0.27630556, 0.14074354, -0.016993485, 0.084373675) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.1543391, -0.2008408, -0.21885285, 0.2320177, 0.06669948, -0.05171086, -0.25833863, -0.14085051, -0.035878573, -0.1632403, 0.09782713, 0.22973235, -0.14022017, -0.018347954, -0.29652777, 0.10912002) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.050962634, -0.040519282, -0.04381614, 0.084133334, 0.21222316, -0.091010064, 0.13157965, -0.21375372, -0.021148674, -0.044127557, -0.11400533, 0.097688414, 0.31571037, -0.05167655, 0.27606225, 0.12169133) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.1329087, 0.14291021, 0.043337896, -0.25970098, -0.11379552, -0.040157612, 0.08379851, -0.24104865, 0.1593102, -0.031879216, -0.004603848, -0.019003935, -0.24769545, -0.17577063, 0.16019398, 0.04640235) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.11615644, 0.12189521, 0.12919527, -0.104224406, -0.10143574, 0.14024515, -0.02759362, -0.1467619, 0.09028311, -0.06510291, 0.061612967, 0.10227729, -0.08785846, 0.06464871, -0.05048917, 0.09055746) * go_1(1.0, -1.0);
|
||||
result += mat4(0.34443164, 0.013906371, -0.0595573, 0.09354196, 0.12184454, -0.02698316, -0.06208632, -0.11266858, 0.004904335, -0.33987018, -0.2494041, 0.127125, 0.040493876, 0.0280356, -0.037431944, 0.05823802) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.1762869, -0.20683959, -0.37788594, -0.1244979, -0.17202286, -0.038234763, 0.015924744, -0.014006752, 0.07097758, -0.25219876, -0.3164728, 0.022413896, -0.41423917, -0.03191542, 0.009464804, 0.0770316) * go_1(1.0, 1.0);
|
||||
result += mat4(0.12442388, 0.031095076, 0.18799834, -0.18449762, -0.11995044, 0.11634828, -0.0055850362, 0.08558657, -0.025694892, -0.2854381, -0.32876188, 0.14690274, -0.1835963, -0.1786755, -0.44678628, 0.1678422) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.031241562, -0.1265462, 0.081369035, -0.1184643, 0.0010021052, -0.10810683, -0.039572187, 0.13850863, -0.010703417, -0.057981443, 0.30309856, 0.13869847, -0.16935349, 0.16969836, 0.045642667, 0.26460654) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.28779998, 0.04767888, -0.011856489, 0.114210494, 0.034624737, 0.19084676, -0.02740287, 0.035041407, -0.049002927, 0.10928203, 0.17362499, -0.1280889, 0.00077811617, -0.17594084, -0.18379052, 0.22303762) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.0008487252, -0.060438234, 0.109334275, -0.18768874, 0.13844973, 0.09226474, 0.18361697, -0.19385563, -0.29241335, -0.1033556, -0.3289991, 0.10027422, -0.09454755, -0.22817631, -0.2964217, -0.19499257) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.057920385, 0.06342629, -0.048577324, 0.15952215, -0.061343953, 0.16471362, 0.1501856, 0.027373426, 0.01837245, -0.0732048, 0.09776471, 0.14817989, -0.112215854, 0.109101914, 0.058316242, 0.29969788) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.12411656, -0.033170763, -0.08715826, 0.110862456, 0.1871076, 0.14550175, 0.23373431, 0.19281025, -0.37016305, -0.11924462, 0.026793748, 0.092801645, 0.04318573, 0.20969667, -0.39267823, 0.1938874) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.15932916, 0.22217506, 0.007901788, -0.04037383, 0.09095982, -0.043115042, 0.098845564, -0.073432215, -0.14535685, 0.11504512, -0.07950504, -0.010718905, -0.050012022, -0.13089752, -0.3323894, -0.005423676) * go_2(1.0, -1.0);
|
||||
result += mat4(0.007320675, 0.21108273, 0.20758918, -0.04005568, -0.13234317, -0.15708306, 0.41804615, -0.09720499, -0.09623786, 0.2441289, 0.33276868, 0.17716111, -0.45670444, -0.026252905, -0.01958701, 0.24028622) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.14936383, -0.023504466, -0.028479185, -0.053541556, -0.060263615, -0.087681144, 0.2435555, 0.08470686, -0.17713271, -0.2303349, 0.09337386, 0.039068084, -0.16263027, 0.034289114, 0.16604292, 0.10550447) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.16556105, 0.12211341, -0.0036831333, 0.13802956, 0.065256506, 0.03395266, -0.2296282, 0.21284704, 0.017770419, -0.1722762, -0.1741687, 0.10708671, 0.331979, 0.11924846, -0.09410989, -0.123036265) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.096586555, -0.30475244, -0.24065268, 0.053860847, 0.19413544, 0.05542323, -0.06327867, 0.012265184, -0.08913778, 0.13779551, -0.099127166, 0.007493773, -0.07125554, -0.0011684593, -0.003005287, -0.094847135) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.21711998, -0.13086027, 0.07825239, -0.21121782, 0.055840425, -0.0019166623, -0.05480048, 0.019817038, 0.007626905, 0.14126389, 0.04515749, -0.029315706, 0.18555732, -0.114861906, -0.21993469, 0.031716693) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.06716353, -0.11964145, 0.09711908, -0.061763637, -0.0948045, 0.14189975, 0.2810092, 0.2505306, 0.08872909, 0.086749084, -0.17528322, -0.048835423, 0.124959685, -0.12602286, 0.065660164, -0.06783225) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.23066516, -0.0068310793, -0.0021060852, 0.09136854, 0.09919007, 0.2259628, -0.026603302, 0.1367709, -0.07940821, 0.14962214, 0.00652088, -0.3114987, -0.18900892, -0.20450105, 0.09329685, -0.19482759) * go_3(0.0, 0.0);
|
||||
result += mat4(0.095197074, 0.06346413, -0.05207484, -0.086378016, 0.19733003, 0.1448027, -0.02410627, 0.024829205, -0.20296144, -0.09551166, 0.022987023, 0.09035918, -0.15824226, 0.1350293, -0.06641893, 0.11739518) * go_3(0.0, 1.0);
|
||||
result += mat4(0.08381447, -0.13171835, -0.030271608, 0.14649504, 0.0007350431, 0.15303299, -0.001797464, 0.30294403, -0.07635094, -0.102541, -0.12176348, 0.053775523, 0.08070882, -0.035387367, -0.09521456, 0.22530125) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.04650126, 0.12029137, 0.009236626, -0.1371486, -0.119391896, 0.20490645, 0.17123316, -0.015455403, 0.05842872, 0.14354227, 0.37586045, 0.054906923, 0.062954046, 0.07285954, 0.12260665, -0.08675996) * go_3(1.0, 0.0);
|
||||
result += mat4(0.22510684, -0.010087092, 0.005660375, 0.05069907, 0.10297958, 0.1411009, 0.09538159, 0.00922383, -0.31313825, -0.06449414, 0.109746836, 0.30148697, 0.35861742, -0.045380104, 0.09908991, -0.1933117) * go_3(1.0, 1.0);
|
||||
result += vec4(0.012253057, 0.13434875, -0.10318777, -0.074252345);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!SAVE conv2d_6_tf
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.04279202, -0.01698567, 0.18318103, -0.18172316, 0.04757184, 0.07232096, -0.054900512, 0.11956132, 0.048900753, 0.0006714882, -0.09200336, 0.16104606, 0.38940707, 0.2754208, -0.12735553, -0.30017206) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.2469705, 0.103162065, 0.10321547, -0.1292231, 0.3013039, -0.018333653, -0.19897339, 0.122247696, 0.14719778, 0.003909129, -0.19585025, 0.03670547, -0.2132921, 0.33642963, 0.17569672, 0.07414473) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.015335451, 0.15161209, 0.0447609, -0.042884503, 0.14257035, 0.07775234, -0.2064044, 0.03842874, -0.1660166, -0.19817057, -0.10740875, -0.123968095, 0.14156081, -0.2197906, -0.08622206, 0.4185408) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.33392438, -0.12483512, -0.062084857, 0.16336447, 0.09862199, 0.1659862, 0.034751434, -0.11968266, -0.017155796, 0.21001562, -0.053017724, 0.10386376, 0.07066254, 0.50014263, 0.31065208, -0.026068505) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.34320992, -0.030056434, -0.24118581, -0.024320357, 0.327435, -0.036838267, -0.19433706, 0.24561343, -0.1489437, 0.225435, 0.18421564, 0.021147838, 0.264245, 0.16846146, -0.51724315, 0.039252095) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.25945047, 0.12058094, 0.2889452, -0.061687145, -0.10309796, -0.19476385, -0.10393912, 0.16837607, -0.05198191, -0.036113493, -0.11847194, 0.16367626, 0.018113747, 0.059499823, 0.0062132217, 0.15846115) * go_0(0.0, 1.0);
|
||||
result += mat4(0.094601326, 0.053219795, 0.027610637, 0.12041253, 0.21425363, 0.15754686, 0.08518286, -0.00661778, -0.021661628, -0.17554528, -0.014842315, 0.22240937, 0.15908821, -0.20964032, 0.21754523, 0.30307937) * go_0(1.0, -1.0);
|
||||
result += mat4(0.13757955, 0.06684095, -0.03616685, -0.014618309, 0.04168136, -0.17148526, -0.16317028, 0.14210777, 0.102521434, -0.19108291, -0.14441934, 0.14435884, 0.24228935, -0.10589834, 0.24029285, 0.27317202) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.16239886, -0.073841535, 0.067964345, -0.11332664, 0.07695667, -0.047180675, -0.08260769, 0.09427637, 0.09471068, 0.012713836, 0.14605078, -0.062490974, -0.11498225, 0.04150893, 0.37402585, 0.21953487) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.07445113, -0.14220217, 0.09271495, -0.014715529, -0.37606132, -0.14938155, -0.024809113, 0.22279873, -0.011379667, -0.04545505, -0.033382278, 0.08971831, 0.016359061, -0.016230864, 0.052939463, -0.07754285) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.10961948, 0.09230085, 0.061259165, 0.0015837378, 0.053883027, -0.22557226, 0.018400123, 0.43234614, 0.08967873, 0.06687854, -0.4389578, -0.01658211, -0.040707946, 0.0048945122, 0.1433802, 0.049759727) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.027641231, 0.026085567, 0.109188825, -0.19011945, 0.19309571, 0.0084956605, 0.05034047, -0.08674781, -0.008124587, 0.031490494, -0.0744263, 0.084508896, -0.007835403, 0.13120581, 0.0021786217, -0.025225073) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.020191731, 0.24703082, -0.36845222, 0.0032569442, -0.1497622, 0.05968502, 0.09595371, 0.008410154, 0.119981945, -0.09983294, -0.19541258, -0.111814305, -0.25664008, 0.31031236, -0.23063917, -0.13823026) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.092747286, 0.23009373, -0.29804415, 0.05036082, 0.031480987, 0.18805481, 0.3676576, 0.06004687, 0.19841099, -0.058367446, -0.44229323, -0.19645047, 0.037667975, 0.12398346, -0.25753063, -0.26919344) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.019061154, 0.03841801, -0.28433323, 0.38128456, -0.059526864, 0.29960185, 0.014484517, -0.10234412, 0.05444907, -0.12615138, 0.14936689, -0.079120934, 0.028092088, 0.096715964, 0.0037780635, -0.12791039) * go_1(0.0, 1.0);
|
||||
result += mat4(0.26949528, 0.015951393, 0.15355164, -0.030336212, -0.100286454, -0.052609976, 0.03197625, -0.092190474, 0.06131517, 0.18291938, -0.15216532, -0.026021928, 0.18581273, -0.10659101, 0.14806952, 0.20509768) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.2205839, 0.11654808, 0.43800604, 0.03188946, 0.13840868, 0.020377772, 0.038510147, 0.03779825, -0.23494276, 0.08624197, 0.036650848, -0.115041405, -0.03776705, -0.32108167, 0.0094707385, 0.37881464) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.031778246, -0.38020673, 0.16956653, 0.33444092, -0.042172886, -0.03465591, -0.17585713, 0.025507452, 0.07595919, -0.06807453, -0.100295454, -0.019174794, 0.07763043, -0.09321411, -0.05212223, 0.112239085) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.048172995, -0.012284629, 0.12846173, -0.13459995, 0.25443402, -0.013064909, 0.15480834, 0.14016332, 0.036635883, -0.049085367, 0.0506487, 0.26623604, -0.023176057, 0.012088936, -0.1844897, 0.040488705) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.2147455, 0.17323543, -0.2943051, -0.053386763, -0.023367947, 0.090753146, -0.011997397, -0.0626111, -0.13558747, -0.035944186, -0.014752113, 0.25506687, 0.055502877, 0.31465453, -0.16283247, -0.08967175) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.033773236, -0.09510872, -0.09313707, 0.046486538, -0.1699796, -0.11685979, 0.22197925, -0.013884658, 0.12514, -0.12129843, -0.09695589, -0.075202964, -0.12321221, 0.18949097, -0.03694664, -0.2306249) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.08668444, -0.22983012, -0.30873656, 0.07371376, 0.082137264, -0.014844924, 0.2283955, 0.24782042, 0.31113505, 0.14810014, 0.32804835, -0.12014127, -0.17742543, -0.15872951, -0.080107674, -0.16898526) * go_2(0.0, -1.0);
|
||||
result += mat4(0.29746926, 0.19479977, 0.13996765, -0.4268552, -0.16478531, 0.0835479, 0.45685142, -0.05510062, -0.1282004, 0.12359051, 0.34026766, -0.26152933, -0.13128015, 0.329812, 0.27172327, -0.06600192) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.06552484, 0.19600633, 0.12407863, -0.13815112, 0.17426166, 0.040930413, 0.06495108, 0.034157254, -0.029772963, 0.015127817, 0.10718436, -0.13752984, -0.0205358, 0.1884735, 0.104591034, -0.020779913) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.053475305, -0.13616458, 0.05487909, 0.13256747, -0.10030239, -0.12376705, 0.062755466, 0.03264356, 0.068466686, 0.05019395, -0.034875803, -0.17806669, -0.21720818, 0.25592342, -0.2685692, -0.27576914) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.04562929, 0.04225299, -0.22311088, -0.09517893, -0.19886662, -0.11944208, 0.11044239, -0.10464355, 0.037634842, 0.124069214, 0.0927385, 0.108838566, -0.088783056, 0.17008123, -0.1007014, -0.23137446) * go_2(1.0, 0.0);
|
||||
result += mat4(0.10306672, 0.027472405, -0.069015354, -0.14412996, 0.24068132, -0.10624665, -0.25597134, 0.05208812, -0.10230778, 0.006520562, -0.11931577, 0.26738268, -0.09168354, 0.13557245, -0.008878644, -0.22292739) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.09403718, 0.11993688, -0.036254726, -0.053109076, 0.18422048, 0.25203657, 0.10025996, -0.11272799, -0.22040273, -0.05758331, -0.07059054, -0.054108664, -0.20009018, -0.22061199, 0.057880517, -0.26669186) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.08534496, 0.0027822452, -0.01112169, -0.13484463, -0.09446875, -0.057457812, -0.03910888, -0.2816038, -0.096015625, -0.03636662, 0.12532772, 0.092033, 0.038156748, -0.101240925, 0.024886698, -0.086328045) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.2349796, 0.19884427, -0.0734711, 0.08422328, -0.07201622, 0.020658491, 0.1331021, 0.039766714, 0.19280422, 0.13086005, -0.11339721, -0.14782044, 0.19341573, 0.16767374, -0.03593828, 0.18139753) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.040663462, -0.15233721, 0.524604, 0.26603413, 0.07202415, 0.053382196, 0.030758869, -0.06144292, -0.010495834, 0.13868876, -0.020688854, -0.15551737, -0.2958513, -0.32805985, -0.25359175, -0.036683984) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.06644081, -0.145321, 0.24945419, 0.031560224, 0.17245345, 0.23418438, 0.20341763, -0.2619872, 0.038787205, 0.16488725, 0.0019107185, 0.03820528, 0.04169643, -0.34155026, -0.11183654, 0.028614044) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.028469078, 0.010781976, 0.05263661, -0.15337946, -0.20491667, -0.13879907, 0.13934538, 0.061196275, 0.056804053, 0.063193604, -0.2389496, 0.037072126, -0.058510017, 0.036215063, 0.3074709, 0.10517675) * go_3(0.0, 1.0);
|
||||
result += mat4(0.028534278, 0.0022668538, 0.04492863, -0.060705435, 0.06349762, -0.016823182, -0.09148226, 0.03930522, -0.083295114, 0.14799853, -0.08089152, -0.21993661, -0.23298621, 0.05106244, -0.013708201, -0.16311577) * go_3(1.0, -1.0);
|
||||
result += mat4(0.05885827, 0.122300275, -0.16086812, -0.21892425, -0.07548077, 0.09286181, -0.027564062, -0.028723463, -0.0056181233, 0.23472206, -0.0049285595, -0.45054138, 0.07592325, -0.044704806, 0.019616256, -0.06956836) * go_3(1.0, 0.0);
|
||||
result += mat4(0.036423888, 0.20839189, -0.16420732, -0.15954947, -0.11311323, -0.24191359, 0.19845375, 0.084540576, -0.20946553, 0.09259613, 0.03234368, -0.056766506, -0.11992363, -0.06882079, -0.020428827, -0.093375795) * go_3(1.0, 1.0);
|
||||
result += vec4(0.013113342, -0.2905848, -0.029724011, 0.1769613);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!SAVE conv2d_6_tf1
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.093678355, -0.08574688, 0.007699401, -0.038818456, -0.10667588, 0.043627866, 0.23127791, 0.061317544, -0.32790044, 0.08618836, 0.009400048, -0.17129329, 0.23541448, -0.015561885, -0.11172365, -0.1190039) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.0052874424, 0.08136584, -0.12633958, -0.016064916, 0.14033778, 0.07755252, -0.26242834, 0.063312635, 0.06861756, 0.14867078, -0.2561066, 0.33325562, -0.106489345, -0.10068009, -0.039633382, -0.016305668) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.27784392, -0.14990395, -0.35981888, -0.2564094, -0.07480205, -0.026457628, 0.1027643, 0.19381845, -0.07160986, -0.15616457, -0.032070953, 0.32998616, 0.15383582, 0.16622585, -0.1435993, -0.02287804) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.09360053, 0.58019537, 0.02028909, 0.413114, 0.025173154, -0.030326266, -0.028177274, -0.12964654, -0.25432733, -0.06556034, 0.023097439, -0.09458851, -0.21772051, -0.10324596, -0.36674342, -0.14803977) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.1227467, 0.20252965, 0.2559927, 0.08719227, 0.030749539, -0.2526622, -0.25694713, -0.2960799, -0.34960067, -0.25393236, -0.28439638, 0.086787805, -0.34202877, 0.21933395, 0.23473133, 0.079260886) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.00147522, -0.16591258, -0.030617915, 0.10052425, -0.1822102, 0.038774874, -0.04285007, 0.07312042, 0.052175622, -0.33510515, 0.027545406, 0.2995306, -0.08535316, 0.11144203, 0.27999434, -0.09770663) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.04394928, -0.26842886, -0.08354109, 0.04077001, -0.009221606, 0.0328837, 0.006459338, 0.08984004, -0.13035133, 0.20004508, 0.21950854, -0.12742348, 0.32386312, 0.085903555, -0.29273173, -0.056370437) * go_0(1.0, -1.0);
|
||||
result += mat4(0.019171638, -0.1824711, -0.10899421, -0.16201603, 0.054712642, -0.020315547, -0.048609916, -0.068621606, -0.055706583, -0.25671515, -0.019494208, 0.08366393, 0.09531471, -0.05988052, -0.024995802, 0.019303525) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.08694609, 0.26762635, 0.10477892, -0.15392998, -0.059596587, -0.047562487, -0.25932398, -0.054960977, -0.00015596532, 0.07196634, -0.017385524, -0.18826845, -0.017969077, -0.27291682, -0.153906, -0.107691295) * go_0(1.0, 1.0);
|
||||
result += mat4(0.17340474, -0.1285696, -0.04484238, 0.15782213, -0.06190358, 0.27896214, 0.28475145, -0.042519942, -0.19862229, -0.1354097, 0.14344497, 0.015599392, 0.18698554, 0.035121564, -0.018465763, 0.0010143917) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.13428356, -0.06612225, 0.19397905, 0.14209093, 0.1526626, 0.2617573, -0.15316434, 0.35452205, 0.05003259, 0.07679617, -0.008399171, -0.0062716682, 0.11833864, 0.1331285, -0.006803729, 0.22615404) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.0020632436, -0.173174, -0.15404437, 0.05430569, 0.21100305, 0.39063898, -0.019479724, 0.17396629, -0.061121427, -0.13424753, -0.008459669, -0.04975768, 0.20599939, -0.11374013, -0.21116278, 0.063624285) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.0073831948, -0.12009769, -0.16402034, 0.054093774, 0.061061747, -0.009054565, -0.02815144, -0.17071937, -0.22791979, 0.073427565, 0.25161973, 0.1011713, -0.23804636, 0.13810354, 0.09063126, -0.23065178) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.31885087, 0.21730177, -0.20516786, 0.04075695, -0.2736768, -0.38779113, -0.19445951, -0.14024325, -0.11824961, -0.102919355, -0.17858729, -0.013441498, 0.16320607, -0.27105078, -0.00019549616, 0.024509901) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.16024838, -0.3132909, -0.15461555, 0.34874174, -0.0051668375, 0.1811257, 0.3384939, 0.16381103, 0.047184363, -0.20424844, -0.1330078, -0.13795874, 0.21890834, -0.08242861, 0.22677775, 0.031102268) * go_1(0.0, 1.0);
|
||||
result += mat4(0.19408257, 0.016361775, -0.202373, 0.2245766, -0.008954751, -0.047279913, -0.09170596, 0.01567793, -0.0019059096, -0.07785436, 0.0756357, 0.09683383, 0.034215495, -0.030802004, -0.077977195, -0.1101297) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.1060503, -0.0044663083, -0.14942732, -0.11696249, -0.04550482, 0.11463188, 0.17801443, 0.07229662, -0.14176941, 0.02773344, -0.10770335, -0.08745911, -0.023052111, -0.17474785, 0.016645849, -0.059080444) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.050500304, -0.14716387, 0.04525464, 0.23543595, 0.08411192, 0.16031684, 0.1659825, -0.03595111, -0.012943453, 0.13354135, -0.051425032, -0.0075654723, 0.11174184, 0.1266808, -0.18799087, 0.10571744) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.15583408, 0.09837484, 0.19239932, -0.03557196, -0.05406335, 0.096456856, -0.13921897, -0.2212671, 0.28973594, 0.04017474, -0.25423512, 0.1522156, -0.10563249, -0.033190794, 0.101713456, -0.08922746) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.0787607, -0.14545321, 0.099762656, -0.2824299, 0.10130184, 0.019948835, -0.1013831, 0.06604923, 0.089561954, 0.28344154, 0.05757009, 0.04981809, -0.15927236, 0.008129835, -0.04280382, 0.10653281) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.28149363, 0.019583186, 0.25983065, 0.30190885, 0.055435803, -0.01970755, 0.04546505, -0.027456624, 0.43886992, -0.032305803, -0.23557569, 0.12753153, -0.18509789, -0.073295385, 0.0083466545, -0.08271229) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.016040009, -0.20475672, -0.015803276, 0.18247975, 0.21178837, -0.041543446, -0.24716362, 0.10105528, 0.19479224, -0.06583694, -0.09192672, -0.037776746, 0.09636229, -0.12086331, 0.13989103, 0.014564729) * go_2(0.0, -1.0);
|
||||
result += mat4(0.19923596, -0.4132588, -0.4254784, -0.33433357, -0.16956097, -0.25086832, 0.23311833, -0.08976422, 0.06432824, -0.0071802614, 0.0033370545, -0.11073493, -0.46609998, -0.09332235, -0.27287352, 0.052513942) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.06954148, -0.06908355, -0.01875471, -0.35067585, 0.038715206, 0.08843527, 0.28899097, -0.024983376, 0.05879495, 0.110363334, 0.055481512, -0.0046147215, -0.035302363, -0.2722019, -0.0829261, 0.21088009) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.101971015, -0.18584369, 0.1469676, 0.025965, 0.07205807, 0.08838771, 0.08537094, 0.023344917, -0.106373414, -0.09254277, -0.25996596, 0.24570447, 0.00590166, -0.20074098, -0.05443169, -0.10562662) * go_2(1.0, -1.0);
|
||||
result += mat4(0.12980327, -0.16834956, -0.1635997, 0.23437372, -0.07374834, 0.0062907683, 0.17292136, 0.0018093853, 0.04122969, -0.025285576, 0.29646805, 0.13402736, -0.040267725, 0.0011441729, -0.18658921, 0.12006417) * go_2(1.0, 0.0);
|
||||
result += mat4(0.13221453, 0.15109141, 0.07707579, 0.05148666, -0.039716493, 0.12869143, -0.012840577, 0.10953536, -0.05721115, -0.120122276, -0.07632444, 0.32949027, 0.00022400127, 0.22217369, 0.2180494, -0.028773604) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.08405412, 0.11332542, 0.120847605, 0.00520135, -0.13689686, -0.1459117, -0.029643068, 0.16147274, 0.21844815, -0.036921967, -0.12862785, -0.15930249, -0.11265427, -0.17471205, 0.0026749703, 0.2048758) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.03768306, -0.07585988, 0.046583172, -0.35557657, 0.012359812, -0.05498573, 0.19581361, -0.08186999, -0.008727976, -0.16623624, -0.03647879, 0.22760212, 0.048297524, -0.12502927, 0.08636729, -0.26437047) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.19518375, 0.17423135, 0.19473018, -0.22721744, -0.25087392, -0.17043075, -0.021999557, -0.27388734, -0.096786864, -0.012226921, 0.16101876, 0.030362492, -0.017619403, -0.2494354, -0.07336028, 0.06842719) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.13816363, 0.14551367, -0.08497621, 0.15563537, -0.01600614, -0.010629245, 0.007773828, 0.2733634, 0.13066974, -0.2223056, -0.12664202, -0.19242655, -0.13211249, 0.065143794, 0.23912583, 0.19819915) * go_3(0.0, -1.0);
|
||||
result += mat4(0.001870705, -0.0028601827, 0.14014813, 0.14659253, -0.037523735, 0.3726274, 0.13139205, 0.0112125, -0.16308945, -0.17571904, 0.12799808, -0.032106552, 0.013872656, 0.432307, -0.14197885, 0.24013121) * go_3(0.0, 0.0);
|
||||
result += mat4(0.117900506, -0.08039036, -0.17504077, -0.08337764, -0.0068703834, -0.07430392, -0.17125578, -0.3470726, -0.20989974, -0.019394008, -0.027336912, 0.18668686, 0.052886557, -0.023217537, 0.004054446, 0.055974416) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.055653654, 0.08726097, 0.01206228, -0.25783783, -0.08736529, 0.19947968, -0.010166337, 0.36168414, 0.20298903, -0.15769973, -0.21389212, -0.19638214, -0.093130395, -0.067289785, 0.10245741, -0.14167903) * go_3(1.0, -1.0);
|
||||
result += mat4(0.04559992, -0.102125205, 0.21949212, -0.07308472, -0.15511832, 0.23785073, 0.04275021, 0.085007004, 0.079402514, 0.10851189, -0.151969, -0.29738536, -0.0776658, 0.1113102, -0.18987878, -0.045522977) * go_3(1.0, 0.0);
|
||||
result += mat4(0.073690206, -0.016468357, 0.122353435, -0.023995928, 0.095143944, 0.23051415, 0.17702249, 0.030164838, -0.09111423, -0.14219609, -0.19734482, -0.24854833, -0.0067356345, -0.1760497, 0.22637916, 0.119141534) * go_3(1.0, 1.0);
|
||||
result += vec4(0.22705397, -0.029518934, -0.026397338, -0.08183741);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!SAVE conv2d_7_tf
|
||||
//!WIDTH conv2d_6_tf.w
|
||||
//!HEIGHT conv2d_6_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_6_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_6_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_6_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_6_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.16737834, 0.35369134, 0.14049083, 0.017871622, 0.0058661173, -0.035960242, -0.039154284, -0.01920433, 0.0729212, -0.03617972, -0.42717552, -0.019914677, -0.30816802, -0.07726792, 0.2088459, -0.09198307) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.0991125, 0.11411345, 0.15300295, -0.09510225, 0.014268626, -0.42914182, -0.13365223, -0.19440699, -0.27214321, 0.085696176, 0.1527733, -0.21056797, -0.062475704, -0.023041902, -0.29080424, -0.54386055) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.30736786, -0.16801229, 0.07400606, -0.31128535, -0.11047924, 0.16556956, -0.33445996, -0.09190697, -0.06132585, -0.11021996, 0.014628762, -0.45183894, 0.08186993, 0.19378273, 0.113438204, 0.038364496) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.24129803, 0.29174972, -0.1250327, 0.14254767, 0.0026774528, 0.1742466, -0.021835174, 0.01668921, 0.13646975, 0.313305, -0.23293279, -0.16737306, -0.059818722, 0.06404477, 0.108172625, 0.22065729) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.3504013, 0.20759478, 0.28683922, 0.2771802, 0.13761812, -0.21180478, -0.17020214, -0.21419087, -0.031916566, -0.040439468, 0.39206958, 0.715565, 0.46198523, 0.05055317, -0.07409331, -0.050633535) * go_0(0.0, 0.0);
|
||||
result += mat4(0.122958206, 0.0071205017, -0.21314384, -0.22197853, 0.016202174, -0.15960938, -0.14601983, -0.023609173, -0.07586023, 0.099936776, -0.0480375, -0.08681468, -0.14976887, -0.38979456, 0.16078879, -0.12263952) * go_0(0.0, 1.0);
|
||||
result += mat4(0.1687149, 0.108331114, 0.10112296, 0.01738403, -0.06773097, -0.19410455, -0.09728116, 0.0013846151, -0.038603816, -0.05495021, 0.2453317, -0.40052003, -0.022453755, 0.045039784, 0.0474246, -0.2665161) * go_0(1.0, -1.0);
|
||||
result += mat4(0.06805519, -0.052276067, 0.052459523, -0.0033053474, 0.13439268, -0.06845637, -0.20462433, -0.09088968, -0.00096404477, -0.35103628, 0.15096465, 0.3285226, 0.018747555, -0.06623108, 0.1754265, 0.3211156) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.04583627, 0.122267574, -0.44002235, -0.20039988, 0.039372742, -0.16505809, -0.26659602, 0.12207268, 0.03337428, 0.23131758, -0.009866899, 0.010381569, 0.29676, -0.020599596, 0.17816995, 0.32852224) * go_0(1.0, 1.0);
|
||||
result += mat4(0.09469788, -0.12531966, -0.11786524, -0.3115985, -0.2213199, -0.012536277, -0.13176842, 0.14986996, 0.12069894, 0.2744789, 0.21674646, 0.46060535, -0.4101697, -0.55295914, 0.29993954, 0.114459395) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.18347421, -0.29010707, 0.29127017, 0.087738656, 0.17509815, 0.03982794, 0.1731455, 0.38041735, 0.110374, -0.25045586, 0.36446962, 0.016104888, -0.012112869, 0.10154983, -0.45384112, -0.11416608) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.033837743, -0.020894403, -0.287127, -0.21196121, -0.03255823, 0.2599821, -0.38386443, 0.30563655, 0.39044768, -0.112917066, -0.021323297, 0.12623324, 0.06885038, -0.20750642, 0.07642818, -0.103580445) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.1723114, -0.3726216, -0.21184283, 0.1761503, -0.24993578, -0.31068864, 0.19998416, -0.23127908, -0.052656204, -0.04243976, 0.4397144, 0.01863219, -0.04796025, -0.11009142, -0.0073631364, 0.2716381) * go_1(0.0, -1.0);
|
||||
result += mat4(0.04202001, 0.27142277, -0.027491128, 0.27428457, -0.11009916, 0.39839938, -0.7223327, -0.124673314, 0.08123618, -0.11884722, -0.20375855, -0.7179687, 0.30648115, -0.28195357, -0.3350774, -0.29778734) * go_1(0.0, 0.0);
|
||||
result += mat4(0.071278594, -0.09155223, 0.06417857, 0.08250104, -0.45117077, -0.023316784, 0.38917172, -0.19110887, -0.09265943, -0.2643835, -0.09707039, -0.33238646, -0.0818088, 0.17623149, -0.28457013, 0.13986786) * go_1(0.0, 1.0);
|
||||
result += mat4(0.019971045, -0.046649583, -0.03036858, 0.07944429, 0.26344573, 0.054998036, 0.07139812, 0.21139374, 0.08021858, -0.025791258, -0.0423707, 0.25174072, -0.021300986, 0.13209766, 0.19120613, 0.3840775) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.11456406, -0.33503455, 0.21409267, -0.056933913, -0.12204284, -0.37379473, 0.33474764, 0.38634798, 0.12618992, 0.1353635, -0.22651522, -0.3160159, 0.18621005, 0.024818055, -0.11935204, 0.014005666) * go_1(1.0, 0.0);
|
||||
result += mat4(0.1501391, 0.0014716414, -0.22049955, -0.10928345, -0.07085164, -0.08778668, 0.19251469, -0.4932493, 0.071784936, -0.06903646, -0.060333923, 0.020552203, -0.33637995, -0.22848415, 0.21518159, 0.23815839) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.04230713, -0.19312756, -0.0613665, 0.058912925, -0.17639293, -0.029920885, -0.027867602, -0.16602923, 0.10262268, -0.0743682, 0.15286638, 0.08042581, -0.042299524, 0.0022034592, 0.15304253, 0.049871147) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.004346093, -0.07895582, 0.02089975, 0.13429636, -0.1020282, 0.5270822, 0.017983409, 0.1531299, -0.02891241, -0.07050933, -0.18729019, 0.13855362, -0.11538968, 0.20733222, 0.1546878, 0.11550679) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.21800312, 0.20944421, -0.1817274, 0.022868395, -0.019241469, 0.038916696, 0.088702604, 0.1467791, 0.0048542274, 0.10344671, -0.0107803065, 0.23302868, 0.049728952, -0.016042534, -0.08694045, -0.0028224774) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.1570157, 0.08688841, 0.03926086, -0.040503077, -0.052700017, -0.1432353, -0.04516745, -0.09649034, -0.053716175, 0.07059194, -0.07360609, 0.26307717, 0.121471435, -0.13640986, -0.1113535, -0.38560814) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.014722592, -0.39773384, 0.28259715, -0.10905738, 0.07889424, 0.1415529, -0.15419348, -0.2064834, -0.15126482, -0.28288555, -0.0014232624, -0.26178944, -0.025823193, 0.008017357, -0.08547297, 0.26373458) * go_2(0.0, 0.0);
|
||||
result += mat4(0.2978961, -0.020236012, -0.101216674, 0.15498216, -0.0069343713, -0.088363856, 0.20511419, 0.23958007, 0.045810107, -0.19189738, -0.14137349, 0.04177724, -0.1394684, 0.0071990825, 0.06991723, -0.21052721) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.05615232, 0.22506002, -0.12479586, -0.0070057763, 0.092545755, 0.096306436, 0.041890718, 0.1226944, -0.07541768, -0.08369033, -0.15144373, 0.09310172, 0.28388003, 0.09935607, 0.11299509, 0.0014283776) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.005848455, 0.117699094, 0.23539856, 0.11006195, 0.10962903, 0.28139547, 0.18785141, -0.11635996, 0.057289902, 0.2370178, -0.29825503, -0.13706475, -0.3869794, 0.024066223, 0.36742347, 0.35919484) * go_2(1.0, 0.0);
|
||||
result += mat4(0.13744523, 0.09239356, 0.01173183, 0.119055405, -0.07841836, 0.0668925, 0.22598477, -0.016510552, 0.07971727, -0.17154713, 0.03333588, -0.13790733, 0.15421963, 0.2895701, -0.28440917, 0.015132756) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.054354303, 0.36663428, 0.02634933, 0.18688667, 0.0607547, 0.17321853, 0.086784445, -0.023283, 0.0027200899, 0.026914112, -0.07438439, 0.27042162, 0.09985293, 0.012430832, -0.20694605, -0.20363812) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.42759168, 0.15540305, -0.18979609, 0.0073875943, 0.034251947, -0.34551802, 0.53327596, 0.17446762, -0.25879666, 0.2780996, 0.11094055, 0.17597, 0.13790102, 0.2615357, 0.09666047, 0.36155468) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.052614138, -0.1880028, 0.361331, 0.07957976, 0.12552904, -0.0042941784, 0.096562445, -0.041199915, 0.07412456, 0.16379668, 0.05464284, 0.050022952, -0.028281605, 0.09332573, 0.21379845, 0.21396561) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.07546953, 0.16393837, -0.3060623, -0.64610606, -0.013715101, 0.18005042, 0.045286633, -0.21057944, -0.12779316, -0.10310629, 0.14360385, 0.011625261, 0.05597252, 0.023864657, -0.00018915108, -0.24224915) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.08550672, 0.2438917, -0.30383766, -0.2463794, 0.13835424, -0.079946786, -0.060197506, 0.051599402, -0.24983203, -0.06691107, -0.0041784844, 0.07539119, -0.030340329, -0.23565106, -0.17968354, -0.10262371) * go_3(0.0, 0.0);
|
||||
result += mat4(0.19315718, -0.045718513, 0.120446794, -0.225136, 0.22922774, -0.046026126, 0.11448238, 0.114267804, -0.22327735, -0.03368635, 0.29763463, 0.03673529, -0.0583939, -0.092253424, 0.045279544, 0.04475646) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.062286656, -0.06241419, -0.23600577, -0.24818502, -0.058666106, 0.17710151, -0.1751668, 0.05758226, 0.18278669, 0.033297777, 0.046349872, 0.09178792, -0.0745512, 0.20019765, 0.037281513, 0.22204825) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.24708512, -0.1318695, -0.24966322, -0.31206796, 0.079176836, 0.11837155, -0.12882641, -0.01013533, -0.009065797, 0.0789075, 0.016151598, 0.00020127615, 0.1450729, 0.10825556, 0.09322918, 0.07283566) * go_3(1.0, 0.0);
|
||||
result += mat4(0.2604332, 0.25550258, 0.07709474, 0.28426003, 0.10387355, 0.09152259, 0.18742633, -0.0073229484, -0.20327723, -0.26013616, 0.055792782, -0.1713302, 0.14862068, 0.06698207, 0.17608787, -0.11622757) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.20551574, 0.073114716, -0.21843387, -0.28057778);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!SAVE conv2d_7_tf1
|
||||
//!WIDTH conv2d_6_tf.w
|
||||
//!HEIGHT conv2d_6_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_6_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_6_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_6_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_6_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.18413043, -0.12355504, 0.2708789, 0.17259507, -0.069752574, 0.12640886, 0.01075919, -0.028221423, -0.020598855, -0.17259665, 0.16907778, -0.10040477, 0.017177016, 0.0176426, 0.23724149, 0.14657862) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.16921899, -0.33950835, 0.37508205, 0.09996622, 0.13377811, -0.036743056, -0.11633877, -0.23046862, -0.009307903, 0.027441062, 0.054166224, 0.011627087, -0.22831611, 0.043198805, -0.12695734, 0.0062862337) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.17216596, -0.15588646, -0.14179194, 0.12487524, 0.10507964, 0.124544986, -0.0046104924, -0.116668865, -0.006100901, -0.022074439, 0.03376759, 0.10498887, 0.109659016, -0.03567928, 0.29972833, -0.045950003) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.29127, 0.21912472, 0.16494286, 0.027708547, 0.043136686, 0.04409876, -0.07686145, -0.13180132, -0.16630307, 0.15650205, -0.005864527, 0.03916553, 0.15750135, 0.1705246, 0.21626697, 0.06906506) * go_0(0.0, -1.0);
|
||||
result += mat4(0.055395894, 0.28228188, 0.114794776, 0.020619212, -0.031812593, 0.11964309, -0.24317431, -0.36277202, 0.54564184, -0.032843567, -0.118973784, -0.40999004, -0.118530475, 0.09256661, 0.06583871, -0.36627474) * go_0(0.0, 0.0);
|
||||
result += mat4(0.17914769, 0.33976436, -0.11220768, 0.1325754, 0.40586957, 0.3064959, -0.19086123, 0.014164092, -0.17376979, -0.0037554938, 0.11771888, 0.44933778, -0.15937245, -0.10635065, 0.084963776, 0.14630255) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.3723194, 0.21509883, 0.020062352, 0.094394304, 0.030794155, -0.11394617, -0.09103134, -0.0042343247, -0.28981096, -0.061873477, -0.17772584, 0.36440176, 0.007828069, -0.012121627, 0.25862312, 0.24646287) * go_0(1.0, -1.0);
|
||||
result += mat4(0.10368119, -0.06185447, -0.022830853, 0.10918094, 0.18888599, -0.09235343, -0.055134308, -0.2210923, 0.15334128, -0.3084707, 0.31606838, 0.39931116, 0.29489174, -0.24794856, -0.4799932, -0.2617589) * go_0(1.0, 0.0);
|
||||
result += mat4(0.32550937, -0.17103608, 0.3257806, -0.23358762, 0.20370598, 0.13325407, -0.020303056, -0.105462655, -0.22264756, -0.034177396, 0.36885822, 0.20504399, 0.36375418, -0.26149705, 0.022433946, 0.15646128) * go_0(1.0, 1.0);
|
||||
result += mat4(0.007481421, 0.005642636, -0.170087, -0.08915849, 0.6329519, 0.06880098, -0.20856442, -0.1801066, -0.1342754, 0.13643123, 0.26994216, -0.27503812, 0.018052012, 0.058687408, -0.19784917, 0.021157453) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.1486918, 0.12212738, -0.03104796, 0.08664756, 0.3464865, 0.27309546, -0.022896903, -0.32080007, -0.28113958, 0.74847424, -0.33735126, -0.04616876, -0.23119605, 0.4214322, -0.16457441, 0.09162191) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.15863913, 0.1303683, -0.06339421, 0.06328312, -0.3100047, -0.33906308, 0.13805804, -0.14923394, 0.4997829, -0.14977637, 0.02265068, -0.04585939, 0.29802153, 0.3767994, -0.031849556, -0.051892217) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.04541847, -0.13645087, 0.14119779, 0.06409465, -0.29877988, -0.0009743694, 0.028256422, 0.14978185, -0.13014801, -0.24171488, -0.10782599, 0.010709664, 0.21880737, -0.34132662, 0.22972895, -0.07159475) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.1510528, 0.115773134, 0.036761034, -0.284284, -0.35684052, 0.16348189, -0.105475456, 0.08259931, -0.6489164, -0.033928663, -0.04243186, 0.25324553, -0.31829014, 0.066608824, -0.11131264, 0.51919967) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.06517726, 0.1933327, 0.044391852, -0.013346896, -0.3033368, 0.106350735, -0.1351003, -0.13414839, 0.11720078, -0.24844061, -0.2900742, -0.047861837, 0.42789885, -0.47915378, -0.09643217, -0.22915216) * go_1(0.0, 1.0);
|
||||
result += mat4(0.109821886, 0.31451595, 0.13300805, -0.08792569, -0.023928089, -0.038061168, 0.17821129, 0.003772247, 0.14684688, -0.12646271, 0.16072205, 0.011095222, 0.09209181, 0.005167038, -0.08823252, 0.079890974) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.20074554, 0.39979288, -0.007316405, -0.047838025, 0.10849111, -0.22469573, -0.059183244, -0.13663793, 0.07881898, 0.105663374, -0.3152222, 0.08104766, -0.22965154, 0.118780024, -0.07886757, 0.073527716) * go_1(1.0, 0.0);
|
||||
result += mat4(0.1304303, 0.023158893, -0.081089824, -0.15955788, 0.42183343, -0.12898655, -0.14028409, 0.011985, 0.3977131, -0.313598, -0.148818, -0.048350018, -0.13534498, -0.12760727, -0.014968193, 0.06646305) * go_1(1.0, 1.0);
|
||||
result += mat4(0.18085147, -0.11859402, 0.117530234, -0.10420847, 0.1848264, -0.12192718, -0.18729533, -0.10098887, 0.011134682, -0.23658146, 0.12963286, 0.117404245, 0.054487415, -0.030003065, -0.32175776, -0.08044254) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.07251758, 0.073430285, -0.22191651, 0.030512359, -0.029650904, -0.15816379, 0.0418705, 0.04776615, -0.014070836, -0.14669086, -0.009874937, -0.015444495, -0.2747725, -0.061624944, -0.11261252, 0.14757589) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.09274913, 0.046194065, 0.05642919, -0.07803342, 0.23578037, 0.01224276, 0.015608659, 0.05847865, -0.091819406, -0.14424564, -0.034869857, 0.019276984, -0.031180726, -0.21905676, 0.100375675, -0.13659117) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.072157644, -0.13294607, 0.24301524, 0.048643183, -0.04338094, -0.0021709928, -0.06530963, -0.22672611, 0.07479903, 0.08388352, -0.07460508, -0.14517406, -0.072923675, -0.26912874, -0.2769797, 0.054033212) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.5648679, -0.28059873, -0.039906785, -0.39112374, -0.3841447, -0.20383365, 0.12607281, 0.16049421, -0.34394273, -0.022326993, 0.16646549, -0.23433913, 0.071224056, 0.048073303, 0.122035526, 0.14941359) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.11803124, 0.114169255, 0.018188128, 0.0053847185, -0.07537228, -0.048262373, 0.073838905, -0.041833423, 0.044405136, -0.03813592, 0.076818384, -0.06015139, -0.085042655, -0.14306667, -0.21477652, 0.31548396) * go_2(0.0, 1.0);
|
||||
result += mat4(0.19307283, -0.014985916, -0.14332882, -0.05549754, 0.14551677, 0.11406769, 0.2744144, -0.031179624, 0.17578745, -0.11309805, 0.010072839, -0.07453384, -0.23163621, 0.19061968, 0.11016298, 0.108093746) * go_2(1.0, -1.0);
|
||||
result += mat4(0.23180474, -0.12522835, -0.03218773, -0.0031955864, -0.14057393, 0.07269213, -0.20883523, 0.09332164, -0.16037942, 0.25845763, -0.002303125, -0.014625506, 0.17063208, -0.11648214, 0.13988028, -0.024688654) * go_2(1.0, 0.0);
|
||||
result += mat4(0.043369994, 0.12473897, 0.108142346, 0.10268199, 0.16159926, -0.17804666, -0.007889351, 0.07232418, 0.26326916, 0.0474316, -0.41637155, -0.11879895, 0.14051722, 0.08747377, 0.1162202, -0.06443569) * go_2(1.0, 1.0);
|
||||
result += mat4(0.0041097966, 0.109841965, 0.097240336, 0.08123332, -0.081065506, 0.12650634, 0.23450434, 0.09631333, 0.21942414, -0.108897425, -0.033703003, 0.047280088, -0.017764917, -0.058596086, -0.15305139, 0.09055131) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.26824722, 0.014116421, 0.11844865, -0.156046, 0.057152968, 0.21287468, -0.3243975, -0.18181354, -0.07131152, -0.17860547, 0.18918999, 0.15399154, 0.20270234, 0.11524436, 0.05146645, -0.18196748) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.2745638, -0.026905773, 0.045458756, 0.22942849, -0.21052304, 0.20649272, -0.03713028, 0.33655703, -0.12467089, -0.015030098, 0.15504798, -0.05647672, 0.18751477, 0.08505986, 0.04756538, -0.058810517) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.1737789, 0.06552432, -0.34797582, -0.05370679, -0.036056817, 0.085242435, -0.12802805, 0.03710984, -0.09883285, 0.08946925, -0.0446528, 0.07734006, -0.10973603, 0.262812, 0.14010249, -0.1543792) * go_3(0.0, -1.0);
|
||||
result += mat4(0.316673, -0.16414417, -0.23147403, -0.3080756, -0.056620106, -0.11389848, 0.0948114, 0.13236332, -0.40048537, -0.090742044, 0.12090404, 0.024549136, -0.19124876, -0.3007761, 0.16159211, -0.28620452) * go_3(0.0, 0.0);
|
||||
result += mat4(0.032962102, -0.05481415, -0.1185786, 0.18153866, -0.2105442, -0.03802839, 0.14060515, 0.072460145, -0.1523761, -0.11426362, 0.02610123, -0.053477813, -0.20768824, 0.04533907, 0.14381588, -0.041578818) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.021694858, -0.028784249, -0.09928565, 0.07335764, 0.1315628, 0.11288982, 0.078681685, -0.1229723, -0.09618894, -0.07387309, 0.04340066, -0.036534667, 0.37295115, -0.08176548, -0.16579813, -0.13485877) * go_3(1.0, -1.0);
|
||||
result += mat4(0.45979, -0.289226, -0.15456465, 0.0117592, 0.22803205, 0.15497394, -0.38995707, 0.005227681, -0.20515667, 0.17184737, -0.069968715, -0.24724679, -0.048521046, 0.013277072, 0.049562644, -0.05522196) * go_3(1.0, 0.0);
|
||||
result += mat4(0.14561136, -0.18995416, 0.18104567, 0.063063085, -0.09728072, 0.018328888, -0.17258182, 0.069259025, 0.15187183, 0.16760696, -0.14086077, 0.013297849, -0.07579904, -0.09294852, -0.24227127, -0.048749007) * go_3(1.0, 1.0);
|
||||
result += vec4(0.31939298, 0.03303962, -0.010749771, 0.084496394);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-Soft-(VL)-Conv-3x1x1x112
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!BIND conv2d_7_tf
|
||||
//!BIND conv2d_7_tf1
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
#define g_0 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_1 (max((conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_2 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_5 (max((conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_6 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_9 (max((conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_10 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_13 (max((conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_14 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_15 (max(-(conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_16 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_17 (max((conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_18 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_19 (max(-(conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_20 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_21 (max((conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
#define g_22 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_23 (max(-(conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
#define g_24 (max((conv2d_7_tf_tex(conv2d_7_tf_pos)), 0.0))
|
||||
#define g_25 (max((conv2d_7_tf1_tex(conv2d_7_tf1_pos)), 0.0))
|
||||
#define g_26 (max(-(conv2d_7_tf_tex(conv2d_7_tf_pos)), 0.0))
|
||||
#define g_27 (max(-(conv2d_7_tf1_tex(conv2d_7_tf1_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.121882804, 0.055417646, 0.037575886, 0.0, 0.040015355, 0.10440659, 0.120197006, 0.0, 0.008896276, 0.07269119, 0.09253319, 0.0, 0.009000448, -0.033739295, -0.059260685, 0.0) * g_0;
|
||||
result += mat4(-0.048027042, 0.09210703, 0.123745404, 0.0, -0.007914943, 0.05483587, 0.054822505, 0.0, -0.005998682, 0.005822986, 0.009868176, 0.0, -0.05866792, -0.04236153, -0.022935968, 0.0) * g_1;
|
||||
result += mat4(-0.091270015, -0.033997003, -0.012321896, 0.0, -0.037983265, -0.078790314, -0.085029654, 0.0, 0.10656225, 0.0008334142, -0.0041227583, 0.0, 0.077364065, 0.033960085, 0.029391684, 0.0) * g_2;
|
||||
result += mat4(0.15057671, -0.037442014, -0.037083894, 0.0, 0.015493511, -0.016119987, -0.027061606, 0.0, -0.012329675, 0.0060544596, -0.019787522, 0.0, 0.12182345, 0.11346318, 0.08640806, 0.0) * g_3;
|
||||
result += mat4(0.19254518, 0.009179287, 0.023821035, 0.0, 0.020269603, 0.025629226, 0.040180814, 0.0, -0.025135614, -0.07785793, -0.099851295, 0.0, -0.122886, 0.03322616, 0.0509256, 0.0) * g_4;
|
||||
result += mat4(0.060054794, 0.053996198, 0.047226787, 0.0, 0.038959846, -0.025839888, -0.030583512, 0.0, -0.034999896, 0.011966571, -0.011057454, 0.0, 0.05765179, -0.041760337, -0.0694113, 0.0) * g_5;
|
||||
result += mat4(-0.20393562, -0.0055942894, -0.02089636, 0.0, 0.14781304, -0.01954523, -0.0746086, 0.0, 0.071556985, 0.07512172, 0.067927115, 0.0, 0.084076844, -0.0561336, -0.06856403, 0.0) * g_6;
|
||||
result += mat4(-0.039552618, -0.04448951, -0.04170605, 0.0, -0.00886809, 0.06708884, 0.07120977, 0.0, 0.04834384, -0.10599933, -0.11024835, 0.0, -0.015948117, 0.084044695, 0.10778199, 0.0) * g_7;
|
||||
result += mat4(0.050153337, 0.012563414, 0.014994658, 0.0, 0.10498867, 0.07151875, 0.06761489, 0.0, 0.061650798, -0.035183728, -0.050987806, 0.0, 0.0017240314, 0.041055307, 0.020366805, 0.0) * g_8;
|
||||
result += mat4(0.110105395, -0.044468552, -0.072567016, 0.0, -0.049364448, -0.015713394, -0.021540897, 0.0, -0.01636263, -0.084110685, -0.08281401, 0.0, -0.08940374, 0.047863875, 0.051104594, 0.0) * g_9;
|
||||
result += mat4(-0.081597924, 0.002422661, 0.01143175, 0.0, -0.07504751, -0.09938017, -0.1063178, 0.0, -0.10390281, 0.0262197, 0.060155805, 0.0, -0.24289346, -0.0054961476, 0.045964316, 0.0) * g_10;
|
||||
result += mat4(-0.1829316, 0.047622137, 0.07963877, 0.0, 0.048703995, -0.0026299425, -0.003712008, 0.0, 0.029338706, 0.096882835, 0.102083966, 0.0, 0.078538164, -0.07247937, -0.06820231, 0.0) * g_11;
|
||||
result += mat4(-0.02302231, -0.035528302, -0.030674051, 0.0, 0.029780716, 0.031591274, 0.045867007, 0.0, 0.01335752, 0.037001595, 0.04351411, 0.0, -0.11126892, 0.038589563, 0.06444906, 0.0) * g_12;
|
||||
result += mat4(0.0047764573, -0.063372664, -0.065609895, 0.0, 0.0478139, 0.025694113, 0.025097322, 0.0, -0.1019169, 0.029989049, 0.050038517, 0.0, 0.07504127, -0.017047737, -0.026222635, 0.0) * g_13;
|
||||
result += mat4(0.0024485083, 0.00640911, 0.008171829, 0.0, -0.014622121, -0.06078096, -0.0800138, 0.0, -0.0062360805, -0.014344496, -0.021332184, 0.0, 0.117842786, -0.103745885, -0.13756834, 0.0) * g_14;
|
||||
result += mat4(-0.01942775, 0.08720701, 0.104858086, 0.0, -0.05545872, -0.041375194, -0.035368554, 0.0, 0.080331706, -0.021207837, -0.043905254, 0.0, -0.12515299, 3.445463e-05, 0.018742712, 0.0) * g_15;
|
||||
result += mat4(0.013106969, 0.010379314, 0.012753471, 0.0, 0.07086715, -0.020893, -0.03968904, 0.0, -0.06114372, 0.029510446, 0.035070244, 0.0, 0.11180839, -0.087067656, -0.124039896, 0.0) * g_16;
|
||||
result += mat4(-0.056521703, -0.001166792, -2.3704073e-05, 0.0, 0.011961608, 0.01848977, 0.019861937, 0.0, 0.012167056, 0.018613879, 0.020505793, 0.0, 0.009734187, -0.0308419, -0.035206888, 0.0) * g_17;
|
||||
result += mat4(0.0048758825, 0.018046578, 0.014597015, 0.0, -0.061724614, 0.040989272, 0.05644141, 0.0, 0.070315465, 0.008318584, 0.0028647361, 0.0, -0.11316492, 0.043919202, 0.07653594, 0.0) * g_18;
|
||||
result += mat4(0.031487904, -0.010548384, -0.009984509, 0.0, -0.0022647562, 0.0043304027, 0.0029451603, 0.0, -0.0063251094, -0.013420807, -0.011919729, 0.0, -0.022760967, 0.019141173, 0.01782793, 0.0) * g_19;
|
||||
result += mat4(0.023055293, 0.028219413, 0.024810018, 0.0, 0.031653803, 0.050207954, 0.04504577, 0.0, 0.03877294, 0.0280465, 0.025589157, 0.0, 0.0019387804, 0.023891818, 0.016049948, 0.0) * g_20;
|
||||
result += mat4(0.006562233, 0.03880659, 0.037682824, 0.0, -0.021441424, -0.011277022, -0.012471097, 0.0, -0.030526241, -0.013880651, -0.014213582, 0.0, 0.0075785257, -0.0017350517, -0.0024610942, 0.0) * g_21;
|
||||
result += mat4(0.015097556, 0.020325955, 0.015611413, 0.0, -0.014755199, -0.034323387, -0.032325987, 0.0, -0.008603291, 0.010346807, 0.011044969, 0.0, -0.004739154, -0.026397636, -0.01995132, 0.0) * g_22;
|
||||
result += mat4(0.0097906375, -0.015094543, -0.016887931, 0.0, -0.0007786067, -0.0069163437, -0.008449091, 0.0, 0.025534432, 0.018064791, 0.017047096, 0.0, 0.00055667467, 0.001493328, 0.003636564, 0.0) * g_23;
|
||||
result += mat4(-0.042251963, -0.042396102, -0.040224236, 0.0, -0.004492444, -0.0069470624, -0.0065821502, 0.0, 0.062203273, 0.06213223, 0.053592753, 0.0, 0.06424337, 0.07964681, 0.07316769, 0.0) * g_24;
|
||||
result += mat4(0.026366957, 0.02789826, 0.027239393, 0.0, -0.006712127, -0.0035723334, -0.0032348586, 0.0, -0.04960562, -0.062758155, -0.058574595, 0.0, -0.02896146, -0.020999067, -0.021301663, 0.0) * g_25;
|
||||
result += mat4(-0.013106142, -0.017057793, -0.014653614, 0.0, -0.04254173, -0.043040022, -0.041918345, 0.0, -0.011146975, -0.0043820064, -0.003768677, 0.0, -0.0027743059, -0.0114479, -0.0082087545, 0.0) * g_26;
|
||||
result += mat4(-0.10087762, -0.10447133, -0.1005168, 0.0, -0.04165659, -0.04558967, -0.040086865, 0.0, 0.0016493691, 0.0055392827, 0.0070476984, 0.0, -0.018665023, -0.035552308, -0.03375731, 0.0) * g_27;
|
||||
result += vec4(0.018580848, -0.022256816, -0.0266178, 0.0);
|
||||
return result + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,873 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.1690102, -0.2560719, 0.39658326, -0.3679659, -0.27616683, -0.35619372, -0.3748396, 0.08430813, -0.29574734, -0.31511316, -0.09773105, 0.13616018, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.1326393, -0.259433, 0.025070239, 0.58914864, -0.036478516, 0.30723435, 0.007458902, 0.012962684, 0.2493056, 0.13007334, -0.08448256, -0.38414413, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.11539356, 0.35253766, 0.26143202, 0.2760807, -0.09371543, -0.028165473, -0.028452158, -0.27050856, 0.06718067, -0.0056619495, -0.17654495, 0.17288211, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.16145481, -0.3204927, -0.54317135, 0.11830119, 0.49315026, 0.12008072, 0.50857407, -0.30382085, 0.25807253, 0.020755528, 0.29388228, 0.106109895, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.22728722, 0.50484747, -0.07904469, 0.33114597, 0.50306976, -0.22760947, 0.14773269, 0.17628263, 0.14788547, -0.08223464, -0.10880935, -0.3151985, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(0.3414351, 0.057279214, -0.14419858, 0.09761111, -0.11794496, 0.021717256, -0.22750235, 0.13986664, -0.38932344, 0.28996095, 0.3773904, 0.13175532, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.1376552, -0.19587159, -0.35147396, -0.097646296, 0.1686707, -0.14385861, 0.031198, 0.12383533, -0.23089902, 0.08707301, 0.3362293, -0.100579016, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.056774966, 0.047585852, -0.36395878, -0.20211312, 0.4077735, 0.12631284, 0.39813092, -0.033365678, 0.2307249, -0.09131807, 0.20823865, 0.31084216, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.12456089, 0.09755632, 0.31490886, -0.06579996, -0.13386595, 0.07564795, -0.26605195, -0.075180635, -0.11182657, 0.06757017, -0.14351276, -0.16828312, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(-0.046043985, 0.055581126, -0.08791638, -0.13022089);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf1
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.15485518, -0.29363206, -0.22610365, -0.14291525, -0.45240572, -0.18319772, -0.12209436, 0.15031648, 0.09878383, 0.06711082, 0.25763842, -0.084633484, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.10204406, 0.16167697, 0.22371867, -0.37947702, -0.24476196, -0.038824454, 0.060157117, 0.15764871, -0.08072927, -0.2210841, -0.31835055, 0.009979876, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.20506924, 0.21132155, -0.0922578, -0.07430473, 0.14529926, 0.20549752, 0.0077948375, 0.13246094, -0.32353187, 0.21074104, 0.092629515, 0.17590871, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.04125819, -0.44050243, 0.23729716, 0.3218237, 0.12943116, -0.011674174, 0.10390632, 0.027775545, -0.20308031, -0.16904089, -0.2121676, -0.022515794, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(0.09664124, 0.20127031, 0.60345304, 0.16697013, 0.23093723, -0.38116834, 0.109695725, 0.0007595324, 0.4092646, 0.009624758, 0.11229678, 0.25326383, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(0.014879592, 0.19204311, 0.07102085, -0.7312604, 0.34860876, 0.3429918, -0.027331594, 0.27636307, 0.1342437, 0.107820466, -0.12645108, 0.21081445, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.12687613, -0.09247973, -0.25973785, 0.4350873, -0.18987224, 0.028678741, -0.0903819, -0.63974863, 0.205591, 0.11308998, 0.18458389, -0.4149041, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(0.34691808, -0.025498383, 0.3428986, 0.21663484, 0.23404741, -0.1725327, -0.0036315925, -0.13299675, -0.1873967, 0.031331502, -0.08785591, -0.0013278709, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.35846514, 0.048703704, -0.104165934, 0.16529736, -0.15378916, 0.26030356, -0.07134151, 0.03692383, -0.15807101, -0.18885155, 0.044707954, -0.11444462, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(-0.0022791293, -0.024132347, -0.57621074, 0.028573977);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.010346764, 0.07230188, -0.24734616, -0.09937907, 0.02228549, -0.19550583, -0.019540425, -0.1037373, 0.033996485, -0.075554, -0.20228972, 0.07090153, -0.09194035, -0.058972966, 0.1768268, 0.27517542) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.020078976, 0.12433655, -0.1620775, 0.036401592, 0.079748705, 0.11660013, 0.17917652, -0.017513236, -0.18936846, 0.24478136, -0.45726213, -0.045004416, -0.08295188, 0.067733586, -0.080548316, 0.2744211) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.024916803, 0.27562472, 0.043771956, -0.012240604, 0.0786355, 0.042651594, 0.16049327, -0.14577515, -0.032735053, 0.17658092, 0.16382934, -0.02337374, 0.11551492, 0.056343183, -0.17930213, 0.14259394) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.20010485, 0.06747722, -0.19026905, 0.11013709, 0.13062745, -0.044626113, -0.0062261797, 0.2189639, 0.1403497, -0.022713251, -0.19452858, -0.010305412, -0.06407589, 0.09836748, 0.025805516, 0.23430973) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.14664203, 0.034910418, 0.024714258, -0.066872925, -0.15717538, -0.14179383, -0.14091893, 0.05859166, 0.18919097, -0.18544437, -0.09068573, -0.08615929, -0.051434122, 0.2170678, 0.18409058, -0.17461225) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.11354446, 0.10745854, 0.2682663, 0.05949201, -0.10695986, 0.1407851, -0.03551388, 0.10691649, -0.17148238, -0.38287184, 0.2074456, 0.11828914, 0.048535194, 0.1464864, -0.18169662, -0.14074169) * go_0(0.0, 1.0);
|
||||
result += mat4(0.22160622, -0.1513045, -0.053284165, 0.033202525, 0.15574448, -0.043640967, -0.0093824165, -0.0019965349, -0.097964935, -0.08289824, 0.08239996, 0.07868361, 0.05731752, -0.20441617, -0.013016076, -0.253108) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.031249097, -0.2272863, 0.23573665, 0.03357689, 0.011395065, -0.10885564, -0.06287508, -0.031719524, 0.10331069, 0.17560169, 0.18303394, 0.022961004, -0.17011635, -0.24371737, 0.10678694, -0.3222825) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.1275465, -0.08844758, 0.10994917, -0.00910273, 0.09393154, 0.03894992, 0.14367905, -0.11811715, -0.09077633, -0.015776094, 0.27427456, -0.13283503, 0.18724327, -0.08139094, 0.04933602, -0.051852766) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.06764611, -0.27426586, 0.12045272, 0.09410856, -0.14258035, 0.11802992, -0.09093882, 0.0022018093, 0.4590643, 0.046258576, -0.07827223, 0.448011, -0.103631735, -0.016930219, -0.15421398, 0.11045997) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.17295076, 0.00151352, 0.14938255, 0.08336512, -0.07496541, -0.07561223, -0.0846474, 0.14979269, -0.09142163, 0.23925088, -0.015199518, -0.37749895, -0.20636298, -0.022585187, -0.20371509, 0.0745308) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.06458832, -0.009722021, -0.123604394, 0.06548835, -0.3039139, -0.022024399, 0.05297587, -0.0626883, 0.23556642, 0.1516464, -0.07004877, -0.1845364, -0.05918428, 0.19158973, -0.14983447, 0.030489758) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.36604697, 0.17516142, -0.10853731, -0.22694224, -0.107650936, 0.23013335, 0.094055794, -0.17047717, -0.3006048, -0.08621717, -0.18815655, -0.03570218, 0.09676118, -0.017718751, 0.059138596, 0.073388465) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.12791575, 0.101956226, 0.13091874, -0.046373338, 0.04955811, -0.04030444, 0.13869923, -0.046699073, -0.42611042, -0.7173929, 0.052184317, 0.6178025, -0.02929954, -0.07638965, -0.15000828, 0.030710017) * go_1(0.0, 0.0);
|
||||
result += mat4(0.057806686, 0.20842272, -0.20148766, 0.006666912, 0.13356528, -0.45265228, -0.07354092, 0.21447696, 0.019552143, -0.13645506, 0.14643854, -0.0071413796, -0.15487236, -0.002250615, 0.30622452, 0.0033902125) * go_1(0.0, 1.0);
|
||||
result += mat4(0.06896002, 0.24397352, -0.06479052, 0.20676947, -0.24259068, 0.055320013, -0.09032122, -0.11222854, -0.08982342, -0.114818625, -0.06399291, -0.3024516, -0.06302166, -0.1925528, 0.03458982, 0.028828239) * go_1(1.0, -1.0);
|
||||
result += mat4(0.09764086, 0.09599894, -0.0073313303, 0.14418933, -0.045712367, 0.12657364, 0.04620374, -0.069778584, 0.30047333, -0.012418192, 0.15516461, -0.18087754, 0.08178273, 0.14262857, -0.01741533, -0.12509112) * go_1(1.0, 0.0);
|
||||
result += mat4(0.04697884, -0.1506804, 0.031823065, 0.13397239, -0.18396698, 0.10681781, -0.29586303, -0.0039136545, 0.17560847, -0.12486726, -0.018646788, -0.20688744, -0.030614454, -0.0527634, 0.23593572, -0.10542146) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.19182229, -0.32615846, 0.26283535, -0.1371942, -0.071202695, 0.12056063, -0.11450658, -0.27711076, -0.42096004, 0.0014352369, 0.1559669, -0.14464542, -0.17973948, 0.079166576, -0.12501791, -0.20623216) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.12469872, 0.32190827, -0.059510354, 0.1393449, -0.12845798, -0.019571869, -0.22630808, -0.14031963, 0.36072046, 0.05858427, 0.19278921, 0.121090546, -0.067538865, -0.018770566, 0.14318037, -0.15561756) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.024663208, 0.21110268, -0.016415706, 0.060093414, -0.03739678, -0.107412934, -0.077527136, 0.30331334, 0.17196326, -0.15512557, -0.09499732, -0.15748607, -0.16680105, -0.015185634, 0.16114107, -0.21288376) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.17739037, -0.1190967, 0.13191372, -0.2527187, -0.14992718, -0.30511454, 0.19145966, 0.002194003, -0.12888977, 0.19152176, 0.27528167, 0.099714965, 0.12865707, -0.12051514, -0.055013947, 0.26231763) * go_2(0.0, -1.0);
|
||||
result += mat4(0.46433613, -0.11708138, -0.20157282, 0.32022122, 0.079468675, 0.029407484, 0.2559102, -0.15651533, 0.08644574, -0.09747344, -0.07528584, 0.17354868, 0.19167562, -0.17698488, -0.09896657, 0.17093097) * go_2(0.0, 0.0);
|
||||
result += mat4(0.20283653, -0.33680332, 0.2282385, 0.18832158, 0.20866042, 0.00076752366, 0.16471444, -0.21548858, 0.16193539, 0.17141372, 0.03140222, 0.03913644, -0.030161971, 0.00014570929, 0.08993654, -0.064823024) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.3075755, 0.19942546, 0.015526995, -0.120868504, -0.254515, -0.07791228, 0.03271691, 0.11794217, 0.11258601, 0.045204375, -0.061196107, -0.115958795, 0.3861869, 0.048215542, 0.07016682, -0.009975758) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.07623697, 0.16094944, -0.02283455, 0.14112763, -0.051149167, 0.20429814, 0.011314802, 0.18914083, -0.24240434, -0.08784008, -0.16763984, -0.08492233, 0.31062725, -0.11925119, -0.33195966, 0.2060798) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.016709225, -0.14472668, -0.3677625, -0.09832719, 0.030297454, -0.05775362, -0.1401375, 0.08119674, -0.01795042, 0.05183797, -0.24320887, 0.066842034, -0.22245285, -0.02740993, 0.06316751, 0.053399116) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.039214406, -0.08876633, 0.045552462, 0.19226661, 0.1355001, -0.13942362, 0.17398876, 0.2914014, -0.191809, 0.037143208, 0.013333581, -0.16632195, 0.113767646, -0.106692605, 0.1589787, 0.030107044) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.21997562, 0.13855208, -0.05783191, -0.033682413, -0.010961168, 0.10524961, 0.02177416, 0.18289444, 0.043692037, 0.07853899, -0.039936125, -0.1004449, 0.04494073, -0.020680292, 0.17578089, -0.106598996) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.026852835, -0.16037546, 0.11278316, 0.12656097, -0.006857894, -0.03400118, -0.051564034, 0.00085412664, -0.37556714, -0.05279987, 0.029383834, -0.14246808, -0.056380164, -0.002399925, 0.16025752, 0.036324855) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.022709966, 0.046350412, 0.03390721, 0.02810572, -0.14394265, 0.04215361, -0.3206118, 0.15034916, -0.0028448137, 0.1682989, -0.042686664, 0.020543462, -0.2786501, -0.007482015, -0.040313292, -0.20745736) * go_3(0.0, -1.0);
|
||||
result += mat4(0.05417556, 0.18728684, -0.046121832, -0.27939513, 0.05907976, -0.09191223, -0.16625418, -0.26038164, 0.39956605, -0.052594025, -0.0596556, 0.29517552, -0.015181923, -0.0763375, 0.25131205, 0.13038464) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.036903054, -0.0066989153, -0.062650286, 0.05614359, -0.0064960583, 0.028512698, -0.10906273, -0.010047654, 0.23030473, 0.049983572, 0.10439064, 0.26643834, 0.05041243, 0.09185424, -0.32352915, 0.11295159) * go_3(0.0, 1.0);
|
||||
result += mat4(0.09724027, -0.34962535, 0.06586686, 0.016635379, 0.13831381, 0.01707076, -0.04690347, 0.022350075, 0.018352794, 0.022000022, 0.070613205, 0.117735535, -0.025971051, 0.18832101, -0.09643588, -0.08512127) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.17324433, 0.06810613, -0.057295907, -0.05115964, -0.101570815, 0.12491774, 0.08762367, -0.005862404, -0.05342927, -0.031942457, -0.039624047, -0.04298937, -0.1303138, -0.11869282, -0.024832053, 0.070463404) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.010514842, 0.1376259, -0.11750346, -0.03786737, 0.03459249, 0.015408171, -0.031430878, -0.060825355, -0.072958425, -0.0037895301, 0.041686177, -0.12352204, -0.06261361, 0.054514423, -0.34072715, 0.13860728) * go_3(1.0, 1.0);
|
||||
result += vec4(0.018166734, -0.11002478, -0.05554318, -0.0988193);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!SAVE conv2d_1_tf1
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.040142782, 0.0288423, 0.07569487, -0.01490842, 0.14402796, -0.13682005, 0.027765118, 0.03907358, 0.07117706, 0.058157545, -0.23862502, -0.057674367, -0.19220531, 0.0147159435, -0.18028538, 0.0963821) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.1676744, -0.11937339, 0.12137117, 0.07119485, 0.14148116, -0.043578617, -0.029261118, -0.0016938087, -0.057269357, -0.080076694, 0.12193026, 0.07326153, -0.056278303, -0.01630716, -0.03792076, 0.1483611) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.3021578, 0.011601693, 0.11266048, 0.19086999, -0.0122412145, 0.08431291, 0.11615175, -0.008039614, -0.39987534, 0.07820729, 0.03509667, 0.1963505, -0.08839513, -0.21571854, 0.059425723, -0.06830175) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.23135209, -0.12452708, 0.0943565, 0.0028859286, -0.09836373, 0.10681712, -0.3535964, 0.08457615, 0.045332734, 0.16579892, -0.03809797, -0.021596594, 0.2937497, -0.028294371, 0.046484597, -0.037604347) * go_0(0.0, -1.0);
|
||||
result += mat4(0.072675414, -0.16431206, 0.28952035, 0.0076831076, -0.020242939, 0.029483542, -0.092415355, 0.08673106, 0.12109694, 0.14307201, 0.23134442, 0.11731775, 0.09981601, -0.16968462, 0.037470713, 0.14948717) * go_0(0.0, 0.0);
|
||||
result += mat4(0.0029752052, 0.06526503, 0.1866458, 0.07451277, -0.31836876, 0.17115082, -0.13969697, 0.23844297, -0.03244903, -0.08832665, 0.023691226, -0.18230624, -0.074933805, -0.00044301842, 0.050572682, 0.081511915) * go_0(0.0, 1.0);
|
||||
result += mat4(0.039502528, 0.051221415, -0.13968123, -0.091212444, -0.016925618, 0.15409444, -0.017455677, -0.11653652, 0.03539446, -0.00087720866, -0.12839639, 0.037198763, 0.03674469, -0.26444665, 0.019721227, -0.13013805) * go_0(1.0, -1.0);
|
||||
result += mat4(0.039229527, 0.25667152, 0.0032586441, -0.00718359, 0.1617932, 0.10409968, 0.07182867, -0.09810605, 0.07789241, -0.02014911, 0.025767172, -0.14604759, 0.07175764, 0.32513744, -0.20473222, -0.16266066) * go_0(1.0, 0.0);
|
||||
result += mat4(0.13418433, 0.061813723, -0.13927278, -0.2498272, 0.03468218, 0.29483125, 0.063289374, -0.04726235, 0.1898295, -0.33132064, 0.032045014, 0.02159535, -0.1148363, 0.31306976, 0.06456038, 0.048988886) * go_0(1.0, 1.0);
|
||||
result += mat4(0.07151646, 0.2799246, -0.107190795, -0.16431166, -0.28007045, 0.07206954, 0.06775463, 0.009758042, 0.07032184, -0.20843789, 0.087045245, 0.1360676, -0.25718534, 0.028249472, -0.12614648, 0.009949602) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.020241471, -0.23390484, -0.0083223935, 0.08344701, 0.08222297, 0.12026539, -0.08652223, -0.08228822, -0.039576706, -0.24677879, -0.1157289, 0.2590508, -0.23809408, 0.19911982, -0.116798095, -0.035870325) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.024991842, 0.050509237, -0.024134455, -0.12659028, 0.24089767, 0.122712664, -0.10482493, -0.19403952, -0.19177693, -0.06538376, -0.041478425, 0.32176673, -0.1534002, -0.18680622, 0.06763643, 0.020806564) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.03437814, -0.28067374, 0.2830681, 0.038812317, -0.021698112, -0.120865285, 0.22695538, -0.045419116, -0.030475847, -0.01977341, -0.1265364, -0.3109814, 0.012255813, 0.053917278, -0.018620957, -0.14599285) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.016204128, -0.04093018, 0.054571863, 0.02679643, 0.01756274, -0.057685968, 0.16148666, 0.17370272, -0.11065411, 0.06378157, -0.09331551, 0.22985275, 0.057905316, 0.12323568, 0.07748665, 0.09878629) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.018112244, 0.063234635, -0.013184602, 0.16241394, 0.08877139, 0.02145378, -0.02490027, -0.038920373, 0.13127136, 0.14391647, 0.020553736, 0.14401346, 0.06685973, -0.25398204, 0.10369067, -0.055949755) * go_1(0.0, 1.0);
|
||||
result += mat4(0.07710333, 0.047412727, 0.13813803, 0.18624061, 0.16907091, -0.039532468, 0.06234584, 0.06408178, -0.054543987, -0.045220226, -0.11093376, -0.37399602, 0.20372874, 0.004580967, -0.07742308, 0.017989937) * go_1(1.0, -1.0);
|
||||
result += mat4(0.003485311, -0.08897399, -0.013108594, -0.19473282, -0.27081844, -0.16812073, 0.0052992934, -0.055331517, 0.09446357, 0.019280333, 0.16560757, -0.3230032, 0.043096773, 0.059222896, -0.064184934, -0.059852477) * go_1(1.0, 0.0);
|
||||
result += mat4(0.06794279, -0.034135245, 0.083064295, 0.13506731, 0.13064219, -0.44978833, -0.03513717, 0.08999715, 0.1124541, 0.42208397, -0.0038724816, -0.014332087, -0.13751853, -0.04929869, 0.09134992, -0.17687531) * go_1(1.0, 1.0);
|
||||
result += mat4(0.100909084, -0.0131197255, 0.082274795, -0.2138443, -0.08515947, -0.021058358, 0.10951775, -0.06349191, -0.29129833, -0.029262653, 0.25235432, -0.11748315, 0.121980384, 0.062347785, 0.10916932, -0.15993518) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.28893283, -0.05677308, -0.2641288, -0.058937225, -0.16187571, 0.006647366, -0.063294955, 0.04766719, 0.60601914, -0.07831864, -0.15710756, -0.011491797, 0.15587467, -0.08105375, 0.07847514, -0.2803333) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.077989794, -0.09871811, -0.3516344, 0.15292728, 0.010889273, 0.0011189661, -0.16118282, -0.018821161, -0.039708678, -0.00060983415, -0.06367813, 0.009148068, 0.03919827, 0.18782744, 0.028040757, -0.10230145) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.4079609, 0.18640275, -0.12475227, 0.13891742, 0.25121725, 0.16942379, 0.14409852, 0.087600805, 0.045335658, -0.12683709, -0.0077387216, 0.06563413, -0.19857128, 0.106910795, -0.048285246, 0.10768945) * go_2(0.0, -1.0);
|
||||
result += mat4(0.5989075, 0.20941062, -0.20086494, 0.13344856, 0.073034994, 0.22358665, 0.101664364, -0.13463663, 0.18816395, -0.061176624, -0.14712185, 0.027320342, -0.09529667, 0.031148786, -0.28744993, 0.18698911) * go_2(0.0, 0.0);
|
||||
result += mat4(0.14799193, 0.39471942, -0.23340325, -0.4031061, 0.18926248, -0.11091216, 0.118981816, -0.09155061, 0.17049436, 0.19803695, -0.1513267, 0.023817873, 0.0090933135, -0.04134864, 0.060486555, 0.03536634) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.39094314, 0.01779997, 0.12710269, 0.0067333193, -0.31255835, -0.08206612, -0.048528638, 0.369439, -0.19351655, -0.03420455, 0.15831526, -0.052294146, -0.08481741, 0.0787108, 0.1312136, -0.108919285) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.16068119, -0.42190582, 0.19383872, -0.018445708, 0.09803051, -0.020769652, -0.022599563, -0.052448895, -0.20645833, -0.031432863, 0.0025441595, 0.03410379, -0.20268854, 0.04481527, 0.05191063, 0.42317194) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.12786235, -0.23936178, 0.116561726, 0.30756372, -0.09420156, -0.044529166, -0.03585749, 0.1829332, -0.23939075, 0.24030831, 0.019878127, -0.015069802, 0.24300557, -0.22558568, -0.104956664, -0.09393648) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.04607054, 0.012677649, -0.027597688, 0.1618836, 0.29210827, 0.014221155, -0.13591036, -0.06895336, -0.09559534, 0.07956421, -0.11112994, -0.13325493, 0.24562472, 0.11046177, 0.057847694, 0.0016315983) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.03365951, 0.027391057, 0.09653403, -0.14718771, -0.049631152, -0.06467214, -0.058545876, 0.1424002, -0.06320376, 0.181183, 0.10249362, -0.16052136, 0.3013475, -0.04156266, 0.08862033, 0.06888033) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.10045977, -0.004198456, -0.025856055, 0.05739418, -0.1328637, -0.025975171, 0.06553717, 0.11301186, 0.0704087, -0.083569765, 0.16066101, -0.24453588, 0.25370175, 0.037184533, 0.062386766, -0.20025635) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.017958941, 0.06417776, -0.1525265, 0.12451173, 0.14567685, -0.0049682115, -0.23973411, -0.0783304, -0.010629432, 0.08055161, 0.2028341, 0.17640644, -0.20445108, -0.055524793, -0.019326134, 0.081288636) * go_3(0.0, -1.0);
|
||||
result += mat4(0.007882519, -0.03722546, 0.053249408, 0.00071846246, -0.07053029, -0.21583866, 0.1415364, -0.19486657, 0.20685542, 0.17660026, -0.32156837, 0.1746825, -0.14957622, -0.09224378, -0.098153435, -0.13054638) * go_3(0.0, 0.0);
|
||||
result += mat4(0.10051427, -0.17398237, 0.09842799, -0.14187703, 0.116901085, -0.1229543, -0.0007776771, -0.20410055, -0.11373484, -0.111150615, -0.1974002, -0.11641459, 0.024105398, 0.24985977, 0.015871854, -0.10724633) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.18081793, 0.1209351, -0.12867971, -0.019415248, 0.062617876, -0.037130393, -0.07803658, -0.22862352, 0.2586428, -0.030090366, -0.11894069, 0.18087515, -0.40921417, 0.070013195, 0.030540073, 0.035120826) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.13185939, 0.12992652, 0.08125049, 0.075331174, 0.064219765, 0.056629725, -0.020012032, -0.0855444, -0.044063166, -0.05396545, -0.028002812, 0.21837157, -0.15206428, -0.12681007, 0.14895032, 0.12339962) * go_3(1.0, 0.0);
|
||||
result += mat4(0.08066341, -0.14773634, -0.0212227, -0.014011867, -0.048505764, 0.075407125, -0.020620076, 0.0003291325, -0.21815202, -0.23136546, 0.10853532, -0.036058456, 0.10952532, -0.052677035, -0.13005799, 0.18398996) * go_3(1.0, 1.0);
|
||||
result += vec4(0.022609137, -0.028548084, 0.024431901, 0.010504478);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.069641694, 0.104958326, 0.14786446, 0.027633663, -0.004279524, -0.020451711, 0.0883571, -0.016224537, 0.13585235, 0.11078269, 0.20198658, -0.042161036, 0.020466218, 0.20994963, 0.20072585, -0.028024657) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.050872434, 0.12874635, 0.1298729, 0.115810685, 0.07087254, 0.09885682, 0.23018982, 0.19187538, 0.10953604, 0.0033836907, -0.13325337, 0.09830315, -0.06528767, 0.05096927, -0.016355392, -0.039334368) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.027010268, 0.018263958, 0.0360758, 0.016791478, 0.2815702, 0.15517488, 0.43415815, 0.044976447, -0.0070842914, -0.12546758, 0.16874593, 0.077622116, 0.02252915, 0.1769774, 0.07181055, -0.15128697) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.057129618, 0.118046716, 0.07237424, -0.07842637, -0.044214778, -0.12886304, 0.08603301, -0.10416606, -0.15852053, 0.3788151, 0.26181692, -0.09092249, 0.31635332, 0.064212754, 0.21923725, 0.07500004) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.16981383, 0.044409662, -0.3717617, -0.031610407, 0.03658662, -0.09459229, -0.09449437, -0.014000666, -0.19656453, 0.03934163, -0.16304104, -0.12761801, -0.06235523, 0.16438273, -0.036933117, -0.095564745) * go_0(0.0, 0.0);
|
||||
result += mat4(0.09725091, 0.034022827, 0.17699842, 0.1079676, -0.13236652, 0.03718181, -0.06968635, -0.23288171, 0.10275666, 0.08464966, -0.37162134, -0.35782215, -0.11023659, 0.2519236, -0.035197742, -0.019324787) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.09968464, 0.01102193, 0.0073735216, 0.011999313, -0.004998707, 0.09518938, 0.045727003, -0.21544908, 0.006879454, -0.06398254, -0.12584935, -0.06759933, -0.0820037, -0.07775104, 0.021957919, -0.122708224) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.08869767, 0.031296413, -0.0034280645, 0.13778855, 0.10073061, -0.08393937, -0.032959275, -0.0500518, 0.010908757, -0.09189417, -0.057760105, 0.17652664, -0.08729078, -0.09639096, -0.25654703, 0.055152636) * go_0(1.0, 0.0);
|
||||
result += mat4(0.0027847723, -0.12885433, 0.038065907, 0.17450769, 0.0864409, 0.04592345, -0.015443841, 0.077010944, 0.08967368, 0.06800111, -0.23636387, 0.35023567, 0.03165923, 0.03132063, 0.17964344, 0.035610788) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.032017227, -0.0022808525, -0.08470573, 0.05332408, -0.14674746, 0.025374275, -0.018281924, 0.041163016, 0.00096549373, 0.014724006, 0.004913065, 0.18494442, 0.034953076, -0.15731992, -0.13792977, 0.08041999) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.08305006, 8.6318905e-05, -0.007895379, 0.02731387, -0.061324496, 0.050034665, 0.22662131, -0.013876427, -0.074468784, -0.008136604, -0.23337875, -0.1742574, 0.011753501, -0.11666686, -0.22541048, -0.14549944) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.028333234, 0.121047184, 0.06720256, -0.058930036, 0.030258363, 0.07292774, 0.06455556, 0.0019076486, 0.0073987027, 0.17144889, 0.06084024, -0.08762086, -0.114422195, -0.16595861, -0.08706028, -0.10736261) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.02519315, -0.14611271, 0.0388848, 0.19481422, -0.05970354, -0.08391417, 0.18982239, -0.10447052, 0.15587378, -0.023997072, 0.0781739, 0.2182389, -0.023886079, -0.1422596, -0.13352804, 0.005008043) * go_1(0.0, -1.0);
|
||||
result += mat4(0.08842712, -0.100292705, 0.18925671, 0.12198875, 0.061771665, -0.04473232, 0.025053164, 0.039047796, -0.1672479, -0.08934517, 0.33099812, -0.20269585, -0.21640155, -0.22029749, 0.16539703, -0.2442679) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.16332205, -0.101898365, 0.02919932, -0.11900455, 0.14442924, 0.0916815, 0.037550304, 0.024123482, 0.02042624, 0.033472955, -0.059437107, -0.18735693, -0.013749093, -0.06199881, -0.08685079, 0.04252364) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.09047013, -0.055188328, -0.09106191, -0.048969727, 0.05114009, -0.12753403, 0.07116141, 0.060749624, -0.074034564, -0.21952136, -0.09479503, 0.2753584, -0.014141759, -0.14883812, -0.0673838, -0.012279045) * go_1(1.0, -1.0);
|
||||
result += mat4(0.013816464, -0.0747162, -0.19202435, -0.064403646, 0.34980014, 0.04375546, 0.20264609, 0.006684355, 0.11523799, 0.024674915, -0.08697566, -0.04662527, -0.12743855, -0.39463726, 0.0057380227, 0.01286557) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.08146522, 0.074080914, -0.16856177, -0.183158, 0.19228102, 0.12373886, 0.017574452, -0.01753772, 0.045071773, 0.07725093, 0.023422163, -0.011545186, 0.20751388, -0.10795588, 0.07606346, 0.10282933) * go_1(1.0, 1.0);
|
||||
result += mat4(0.12512013, -0.102208994, -0.09125398, 0.12043188, -0.066011876, 0.08831903, -0.017038671, -0.005541508, -0.049607087, 0.08654939, -0.02037085, 0.26887566, 0.005012545, 0.01869507, -0.013064982, -0.010649147) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.006824864, -0.05071593, -0.20786697, -0.07327317, 0.011382597, 0.030494886, -0.04754353, -0.018284699, 0.01305972, -0.036589053, 0.26637617, 0.021887446, -0.026669119, -0.037982125, -0.063445956, -0.009104248) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.032602567, 0.07094331, 0.052653246, 0.08342047, -0.085082285, -0.14674088, -0.23073354, -0.07915851, 0.0017120204, 0.032407638, -0.039819505, 0.16942178, 0.023192152, -0.0353237, 0.10930186, 0.22939779) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.0010455973, -0.11821993, -0.12639599, 0.12250084, -0.12756817, 0.11478416, -0.1862587, 0.016819192, 0.02110181, -0.25492984, -0.1766048, 0.22188173, -0.21305011, 0.113442205, 0.04599144, -0.15840286) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.15086032, -0.17428935, 0.39080557, 0.07576757, 0.121703945, 0.17944208, -0.003140103, -0.11231332, 0.12102969, 0.15310267, 0.17578171, 0.40631834, -0.21299168, 0.024928993, 0.030104794, 0.020753227) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.098734386, -0.020072265, -0.14308836, -0.08490801, 0.017175158, 0.02250534, 0.04060829, 0.033022214, 0.0046218676, 0.17923212, 0.0112105915, 0.09574084, 0.14819936, -0.14692923, 0.12634254, 0.060762513) * go_2(0.0, 1.0);
|
||||
result += mat4(0.030521613, -0.097913325, -0.016720278, 0.11273997, 0.013019863, -0.06557118, 0.0405774, 0.0915019, 0.022414956, -0.053254984, 0.18639986, 0.07820968, 0.06498986, 0.058922634, -0.02240318, -0.086019725) * go_2(1.0, -1.0);
|
||||
result += mat4(0.2058775, 0.01502064, 0.05847032, 0.007249146, 0.086483665, 0.19420148, 0.03892261, -0.013546935, -0.07980237, 0.04347281, -0.10376214, -0.1366535, 0.05285337, 0.07213318, 0.3642818, -0.11331124) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.025740806, 0.14551482, -0.037410017, -0.17477523, -0.11853099, -0.060820814, -0.102599286, -0.13267937, -0.103053465, -0.014044828, -0.01888072, -0.06499249, 0.22311528, -0.051850274, -0.034120858, 0.044562567) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.21360217, 0.10093803, -0.0016407765, -0.1473997, 0.26524043, 0.02112132, 0.23173104, -0.013157391, 0.05945182, 0.044635538, 0.06031638, -0.21435826, -0.10147484, 0.069090195, 0.09641844, -0.09581093) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.08576515, -0.122861005, 0.049567085, -0.085854456, 0.23809357, -0.024966082, -0.10294079, 0.046241313, 0.008621132, -0.08323767, 0.20277941, 0.163423, -0.07386535, -0.088738985, 0.05274358, -0.025479877) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.041135542, -0.008365642, 0.17088248, 0.04025207, 0.13809255, -0.056895368, -0.01582834, 0.07361908, -0.00068995473, -0.09300962, 0.19117641, 0.24832036, -0.06572358, -0.026025, -0.019093119, -0.049720034) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.024900286, 0.11525501, 0.025882801, 0.037742402, 0.36976853, 0.052211333, -0.15143296, 0.1802276, -0.059080046, 0.017990451, 0.026395092, -0.12689115, -0.07705386, 0.1232379, 0.13273561, -0.12521964) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.19788785, 0.044887315, 0.07663442, 0.16688696, -0.2842248, -0.15684547, 0.028387763, 0.0063470444, -0.012245601, -0.038382255, -0.8187406, -0.25245667, 0.23014604, 0.22746666, 0.1594356, 0.16469443) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.12663333, 0.014730006, 0.03765697, 0.15704912, -0.106595434, -0.05317512, -0.081759915, -0.08797109, 0.064620756, -0.06341419, 0.16493447, 0.23102313, 0.068325415, -0.088058695, 0.16885915, 0.036382258) * go_3(0.0, 1.0);
|
||||
result += mat4(0.035389822, -0.11811836, -0.035656307, -0.0680554, 0.1338908, 0.065852076, 0.023307983, 0.0675308, 0.09690683, 0.18170924, 0.09862692, -0.20964378, -0.08601271, -0.20016764, -0.01879598, -0.14629345) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.27183273, 0.013525998, -0.14995874, -0.23938845, -0.26218823, -0.0009874097, -0.13385512, -0.10664239, -0.048931994, 0.039898522, 0.047444753, 0.10934722, 0.10969629, 0.123539805, 0.11692802, 0.14172275) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.1656506, 0.019683002, 0.0221048, 0.12596753, 0.20420644, -0.07930122, 0.04653823, 0.11492255, -0.0050175437, -0.03271697, 0.013389486, 0.034583613, -0.2196601, -0.1615663, -0.013763388, -0.056037936) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.022956269, 0.029688787, -0.070148066, -0.07163476);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!SAVE conv2d_2_tf1
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.15104648, 0.05522861, -0.0654341, -0.053517453, -0.08264124, -0.0062249107, -0.20364265, -0.05015117, -0.18837251, 0.030655831, 0.046844713, -0.20673253, -0.14042036, -0.05655449, 0.13994302, 0.011745607) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.16517559, 0.1489214, -0.09149559, 0.025003506, -0.124926426, 0.16974348, -0.020857265, 0.08017403, 0.21836148, 0.0025619378, 0.2331612, 0.085599184, -0.030934382, -0.055194855, 0.09527726, -0.10081552) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.041800212, 0.028859638, 0.09395546, 0.05211183, -0.038541477, 0.021495212, 0.04862346, -0.007864793, 0.038407274, -0.13841268, -0.14963801, 0.26470762, 0.16691841, -0.07262008, 0.034374326, -0.14709206) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.00094978884, -0.028974704, -0.0900548, -0.08401967, -0.08935931, -0.043606587, -0.14497143, -0.05226239, -0.21516493, 0.19410603, -0.089924194, -0.04335071, -0.012618276, -0.2671613, 0.020422975, -0.037739716) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.13403237, -0.02524383, -0.03474901, 0.054432765, 0.11946775, 0.107336655, -0.1431715, -0.13370377, 0.015087512, -0.1917613, 0.073493585, 0.2788855, -0.010510839, 0.06891479, -0.06741307, -0.05271205) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.15432046, 0.04021662, -0.16979513, 0.13660534, -0.10518303, -0.10095502, -0.13092068, 0.022805348, -0.16676381, -0.4273298, 0.020867536, 0.3506733, -0.29459694, -0.055828743, -0.069241956, 0.04106382) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.08890133, 0.07549666, -0.040735144, -0.1506932, -0.22227979, -0.0762723, -0.17766447, -0.05741318, -0.21885683, 0.2379157, -0.15525854, -0.07306285, 0.15580738, -0.04394069, -0.19175608, 0.018283797) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.08503275, -0.105500385, -0.114987396, -0.07166016, -0.2147138, 0.09378708, 0.24550334, -0.0834075, -0.033147786, -0.022304727, -0.31062204, 0.027651973, 0.109098755, 0.18889032, 0.1163026, 0.13863255) * go_0(1.0, 0.0);
|
||||
result += mat4(0.15266588, -0.14901319, 0.033916786, 0.09381096, -0.08196443, -0.16194504, 0.035789456, 0.21234898, -0.48724765, 0.2619442, -0.11215393, 0.25061038, 0.022344576, 0.0116525125, 0.111661114, -0.15242295) * go_0(1.0, 1.0);
|
||||
result += mat4(0.020475458, 0.0797404, -0.13576819, 0.009681671, 0.030504882, 0.049232908, 0.022025917, 0.16912088, -0.23914136, -0.084663324, 0.020925451, -0.1023938, 0.035916872, -0.07538111, -0.11470242, 0.15238516) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.12941381, 0.08509899, -0.029489802, -0.09148447, -0.089406274, -0.116145454, -0.08979843, 0.11908148, 0.15473351, -0.21687616, 0.12607013, -0.08244334, -0.079580925, -0.16613089, -0.09287793, -0.03412643) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.023578499, 0.07394217, -0.13069086, -0.1060499, -0.07559958, -0.21839201, 0.1090753, 0.0787872, 0.07677037, -0.25998843, 0.20039314, 0.046882212, 0.31871012, -0.3048051, 0.15118991, -0.00518087) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.15338503, -0.11057532, 0.075839415, -0.18592294, -0.0155324, 0.038140323, -0.10498194, 0.09070477, 0.05108992, -0.047939524, -0.091004305, 0.09649005, -0.10967152, -0.051909525, -0.05314551, 0.09661584) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.14458802, -0.053263694, -0.0010885567, 0.23342133, 0.01918937, 0.12026143, -0.15691495, 0.30480555, -0.08725869, 0.19082253, 0.3594973, 0.016653897, 0.045152336, -0.088590585, 0.0069655925, 0.1392425) * go_1(0.0, 0.0);
|
||||
result += mat4(0.17944881, -0.17950764, 0.13282645, 0.030974053, 0.32233685, 0.18067117, -0.11472813, 0.097301506, -0.047649745, -0.1053861, -0.081039384, 0.035132434, 0.10204545, 0.085582554, -0.13153993, -0.021741152) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.15573682, 0.16409989, -0.22574787, -0.03877603, -0.18285516, 0.11638645, 0.18321282, -0.017770218, 0.18230622, 0.16433364, -0.12795393, -0.03805153, 0.14386104, -0.0891527, -0.056928284, -0.10961495) * go_1(1.0, -1.0);
|
||||
result += mat4(0.257622, 0.052519716, -0.25421762, -0.1887382, -0.083568096, -0.0064690276, -0.029110614, 0.103327505, -0.17006217, 0.2254096, -0.29366904, 0.04302887, -0.10198446, -0.24423616, 0.16781262, -0.005019004) * go_1(1.0, 0.0);
|
||||
result += mat4(0.103393994, -0.059044626, -0.18192382, 0.0990813, -0.26143607, 0.11036474, 0.04788275, -0.096738026, 0.12825653, 0.13631694, -0.077904984, -0.020790676, -0.25118098, 0.122588515, -0.049440473, -0.10758222) * go_1(1.0, 1.0);
|
||||
result += mat4(0.06693113, -0.13647175, 0.131139, 0.13143918, 0.081720434, 0.117537096, 0.15387627, -0.008771362, 0.08513583, 0.023794742, -0.0661625, 0.115793936, 0.0023350024, 0.02215075, -0.0494433, -0.013404977) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.041419264, -0.17622781, 0.028418267, 0.12114493, -0.23587078, 0.08457395, 0.014364018, -0.103271864, -0.051572207, -0.026424447, 0.16755055, -0.10763651, -0.033440586, 0.068594255, -0.050668504, 0.1941505) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.2780181, 0.037816502, -0.11516711, -0.09822884, 0.13762361, -0.14317706, 0.14350282, 0.000623895, -0.08601606, 0.08118504, 0.15497385, -0.04721711, -0.008936935, -0.014223618, -0.09641698, -0.013884213) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.14349665, -0.03144472, -0.057813704, 0.0667044, 0.09026094, 0.051366236, 0.11139983, -0.015782114, -0.18314016, -0.18774192, 0.0014838242, 0.15759028, 0.062388215, 0.13626057, 0.02576217, -0.06317815) * go_2(0.0, -1.0);
|
||||
result += mat4(0.07151769, 0.14508991, 0.1736844, -0.11487795, -0.07999805, -0.07797908, 0.037923355, -0.059138823, -0.23531209, -0.040207293, -0.068355694, -0.024296658, -0.114820175, 0.19726487, 0.21772414, 0.03659222) * go_2(0.0, 0.0);
|
||||
result += mat4(0.16858695, -0.12135113, 0.009391182, -0.081519485, 0.13340487, 0.07007004, 0.094124354, 0.035519842, -0.3320139, -0.06624027, -0.14716229, -0.09205287, 0.12664132, -0.05655441, 0.0123263765, 0.04641279) * go_2(0.0, 1.0);
|
||||
result += mat4(0.19018422, -0.15428329, -0.009354114, 0.04165953, 0.11024837, -0.107493006, -0.05807292, -0.048029456, 0.24319384, -0.10542357, -0.013699952, 0.06228662, -0.06808749, -0.023227982, 0.16528323, -0.05610251) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.008616222, 0.077674195, -0.08638503, 0.09293109, 0.072474636, 0.05004233, -0.20591061, -0.005301386, -0.15486047, 0.15038474, 0.1262478, 0.021724822, 0.02274613, -0.3088281, -0.08437887, -0.10684698) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.16960032, 0.09365251, -0.030414175, -0.010766254, 0.18181023, 0.12130318, 0.08913089, -0.06070321, 0.05200306, 0.092584535, 0.17694671, 0.033796314, -0.038107123, -0.04335955, -0.049443472, 0.30465958) * go_2(1.0, 1.0);
|
||||
result += mat4(0.07661484, -0.009945252, 0.12866217, -0.07592757, -0.21030053, 0.014371748, -0.072458774, -0.04700072, 0.15534303, 0.2007125, -0.15699059, -0.032897495, 0.08110436, -0.11243608, 0.008632577, -0.10153441) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.034697928, 0.06928288, -0.2796273, 0.14405379, 0.12248569, 0.036539096, 0.06607706, 0.077684596, -0.16473202, 0.1665916, -0.29977503, 0.21047153, 0.13114224, -0.091579035, -0.045458574, 0.03254245) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.053284872, 0.053366095, -0.26152626, -0.03123967, -0.031794485, 0.17670582, -0.07450994, 0.017521491, -0.040290453, 0.38342363, -0.25021288, -0.014660264, 0.1621895, 0.25041878, -0.12124821, 0.068036206) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.11366693, -0.030863572, -0.07411263, 0.12475283, -0.046070684, -0.09033321, 0.013222701, 0.06798592, -0.32814804, 0.057653826, -0.14082801, -0.00217398, -0.22856179, -0.19058353, -0.20992154, -0.03701372) * go_3(0.0, -1.0);
|
||||
result += mat4(0.20345633, -0.1332355, 0.27152926, -0.13477845, -0.25242096, -0.28281286, 0.31289554, 0.14284514, 0.53362453, -0.46766588, 0.4518293, -0.39291728, -0.3573227, -0.014670052, 0.0051881406, 0.16552156) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.15017267, -0.07792945, -0.204405, 0.13964304, -0.13642666, -0.10228306, 0.03238279, -0.08689329, -0.072262034, -0.0258388, 0.05689183, 0.055701543, -0.19800112, 0.012217054, -0.033292748, -0.047611095) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.014704416, -0.12203891, 0.066083655, -0.1409769, 0.0041513643, -0.087383606, -0.17498164, 0.11327789, -0.25947225, -0.0016027623, 0.08202566, 0.042270098, 0.006429511, -0.26576808, -0.08461341, 0.049376782) * go_3(1.0, -1.0);
|
||||
result += mat4(0.0695189, -0.14753938, 0.09578246, -0.16607563, -0.0105561055, 0.17166016, 0.027422488, -0.14175262, -0.009492696, -0.23449713, 0.018270867, 0.14635146, 0.33451268, 0.030959005, -0.46468422, 0.024256868) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.16865666, -0.00015881563, -0.054488145, -0.06222717, -0.032101758, 0.06485387, -0.0028512608, 0.046645947, 0.017593225, -0.19447896, -0.024742266, 0.03970127, 0.29845607, -0.16168733, 0.035172883, 0.07924657) * go_3(1.0, 1.0);
|
||||
result += vec4(0.103826486, 0.045373913, 0.11565896, -0.06568643);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!SAVE conv2d_3_tf
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.1851775, 0.053705044, 0.033816848, -0.018555025, -0.21204336, -0.01706974, 0.088259794, -0.13126148, 0.10729598, -0.043457437, 0.08634712, 0.09220895, 0.062131613, -0.01995871, 0.05181067, 0.18520063) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.1662002, -0.14197104, -0.052809287, 0.025287712, -0.08330898, -0.08998097, -0.15642618, -0.14941245, -0.03481203, 0.061857622, 0.26051775, -0.0005498248, 0.086427025, 0.024108192, -0.12418039, 0.022286376) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.058200672, -0.3073398, 0.17150162, -0.13394679, -0.075118184, -0.14607768, -0.006172172, 0.007731589, -0.21818224, -0.06449433, -0.038958784, 0.037722416, 0.28699976, -0.027563032, 0.23295315, 0.028444216) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.12871371, 0.0064904913, 0.14985761, -0.10923005, 0.17413563, 0.1599109, -0.08457703, 0.108153716, -0.08871187, -0.06661137, 0.2754416, -0.009667768, 0.39819396, 0.12392097, 0.14145902, 0.0019376524) * go_0(0.0, -1.0);
|
||||
result += mat4(0.13893189, 0.12715353, 0.015191678, -0.21003054, -0.030412354, -0.01676613, -0.19799289, -0.006130075, 0.37676954, -0.14475077, -0.2065198, -0.30432892, -0.14944535, -0.09121536, -0.107600585, -0.24462196) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.11653076, -0.0068671284, -0.02249137, -0.17877012, -0.15063138, -0.13514869, 0.107643366, -0.03196477, -0.086422764, 0.3079287, 0.17584166, -0.032449376, -0.06917114, -0.2682637, -0.18978168, -0.037039287) * go_0(0.0, 1.0);
|
||||
result += mat4(0.12014731, -0.030360512, -0.12954475, -0.110275604, -0.077214256, 0.019689744, 0.22149551, -0.002266716, 0.09697784, -0.124532826, -0.16776511, -0.034212478, -0.36935154, 0.016926935, 0.1363609, 0.20415346) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.11199535, -0.001692563, -0.09058429, -0.08437503, 0.092625685, 0.06046257, 0.25509837, -0.011657033, -0.17949764, -0.10718947, -0.1180669, -0.24681842, -0.1747311, 0.0014518246, -0.042863015, 0.06103357) * go_0(1.0, 0.0);
|
||||
result += mat4(0.14979295, -0.037154514, 0.01957725, 0.012282435, 0.09168596, -0.05552286, 0.111671515, 0.0078630615, -0.10319766, -0.06416261, -0.23097566, -0.13931875, 0.2110811, 0.013095802, -0.2306504, -0.025639111) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.10091975, -0.10095426, -0.023449723, -0.022170888, 0.054953706, -0.13049407, 0.08289061, 0.023241632, 0.08735388, -0.0058387457, 0.17897247, 0.011434436, 0.008181139, -0.0034718404, -0.015372735, -0.07657766) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.023442164, 0.07535702, 0.024391165, -0.050532013, 0.044168636, 0.0062343236, -0.019756999, -0.009695123, 0.10102337, 0.0052776975, -0.14944167, -0.060957722, 0.24367364, -0.08069369, 0.12170072, -0.047048368) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.18376935, -0.08407229, -0.12943378, 0.0738419, -0.12404976, -0.13367929, 0.11265896, -0.021353, 0.003783386, 0.50088304, 0.14058582, 0.041053623, 0.038247623, -0.014179976, 0.007905778, -0.042492237) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.046272535, 0.052449115, 0.17190954, -0.004745371, -0.045572635, -0.09292636, 0.36309823, 0.16673928, -0.099154025, -0.109614775, 0.17803112, 0.19907133, -0.14306267, 0.06898593, 0.11493454, 0.06795014) * go_1(0.0, -1.0);
|
||||
result += mat4(0.26181114, -0.044014625, -0.21605036, -0.08646438, 0.21038742, -0.084986, 0.0504626, 0.17514943, -0.25218952, -0.18691514, 0.057650108, 0.08653614, -0.101205684, 0.03176334, 0.18569492, 0.17973189) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.0339215, 0.20112811, -0.12986277, 0.028961731, -0.056813832, 0.04451147, -0.07827432, -0.0860976, 0.096853435, 0.3483546, -0.35758162, -0.11749375, -0.035918653, 0.06140711, -0.08520154, 0.02418808) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.09643022, -0.10491069, 0.0068604187, 0.023679713, 0.096521445, -0.29323488, 0.33353668, 0.112864286, -0.1172182, -0.07233183, 0.06607239, 0.08589609, 0.055790007, 0.14396138, -0.14191268, 0.00034840964) * go_1(1.0, -1.0);
|
||||
result += mat4(0.15357164, -0.038462736, 0.08143956, 0.1744909, 0.40503287, -0.114508316, 0.003937322, 0.2536635, -0.042445306, -0.15622465, 0.09155284, 0.010992155, -0.20646071, 0.022801135, 0.08894491, 0.069300614) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.12663515, 0.023849454, -0.053604446, 0.12082873, -0.247968, -0.020969635, -0.03831894, -0.014617553, 0.22630337, 0.037801865, 0.052950703, 0.04285706, -0.14487264, 0.20786528, -0.08719664, 0.1752347) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.073527604, -0.050752833, 0.051830504, 0.32868716, 0.17474994, 0.016937364, -0.08792601, -0.024481766, -0.022229593, 0.030706186, 0.09213566, -0.076506205, 0.073404044, 0.10368055, -0.175889, -0.08453031) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.06838216, 0.007698341, 0.063972116, -0.015604406, 0.16135305, 0.18044342, 0.024137018, -0.23326185, 0.13235588, -0.009096587, -0.058368143, -0.077040404, 0.0011419816, -0.09246194, 0.061036937, 0.049564146) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.023225296, -0.00060856267, -0.07775185, 0.016958566, -0.2641349, -0.08263046, -0.15350416, -0.30203494, 0.113956556, -0.010813236, -0.017738314, -0.13689043, -0.10318342, 0.025793184, -0.010336172, 0.09733422) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.04462596, 0.052866418, -0.34754288, 0.05540498, -0.24492586, -0.32016864, 0.18145293, 0.24873725, 0.32388234, -0.034801524, -0.1347588, -0.07565546, 0.015183539, 0.05059595, 0.08090056, 0.05930932) * go_2(0.0, -1.0);
|
||||
result += mat4(0.045346696, -0.052527856, 0.052270077, 0.13417454, 0.05200045, 0.028119288, 0.005115497, 0.22952151, -0.2158375, 0.12241308, 0.3507457, 0.08616576, 0.07592416, 0.28470486, 0.3432788, 0.24857087) * go_2(0.0, 0.0);
|
||||
result += mat4(0.21311626, 0.052607164, 0.1248861, 0.20193806, 0.045226507, 0.14512901, -0.15103437, -0.17926466, 0.11657411, -0.32711068, -0.16332194, -0.07793982, -0.21802668, 0.5183869, -0.13567342, 0.07823041) * go_2(0.0, 1.0);
|
||||
result += mat4(0.00796368, 0.048073012, -0.14537893, -0.021708772, 0.036246423, 0.1062395, 0.12605369, 0.007073524, -0.1572743, 0.07439501, 0.089162275, -0.0039608316, 0.332032, -0.05461242, -0.17615359, -0.10240517) * go_2(1.0, -1.0);
|
||||
result += mat4(0.20636982, -0.0024615112, -0.10625786, 0.024270926, 0.061810836, -0.13585201, -0.16581286, 0.23549418, 0.01928842, 0.07404979, -0.054449487, 0.04096373, 0.046939734, 0.003980803, 0.02111498, 0.064925276) * go_2(1.0, 0.0);
|
||||
result += mat4(0.10485388, 0.06850885, -0.11292169, 0.16991565, -0.15282536, 0.124175504, -0.050431166, -0.06689582, -0.00059811946, 0.033696912, 0.11055047, 0.033060126, -0.17472714, 0.0048819613, -0.04478706, -0.1344572) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.20473132, 0.056477875, 0.059559986, 0.115130566, -0.058425788, -0.035971727, 0.08334707, -0.096510135, -0.23206294, 0.10635798, -0.21575621, -0.07063254, 0.03877511, -0.107549034, 0.22248401, 0.21702304) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.02557767, 0.09886609, -0.100499466, 0.16687396, -0.084830604, 0.03150401, -0.049512494, 0.05595696, -0.13193256, -0.08585273, 0.14247662, 0.12290477, -0.07168309, 0.14531752, -0.048359327, 0.27716598) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.13297586, 0.20674329, 0.14469388, 0.08981846, -0.004231366, -0.02819193, 0.15470329, 0.17299837, 0.113062344, -0.22716297, -0.21754944, -0.00083956274, -0.14160508, 0.1808253, 0.11268379, 0.27335623) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.07497518, -0.06799594, -0.018158078, -0.00038999433, -0.15169668, -0.06928238, -0.33672288, -0.105485775, 0.33106267, 0.06698315, 0.019718744, -0.06810211, -0.35186404, -0.29145968, -0.056863394, 0.21498048) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.013215512, -0.24763754, 0.20965266, 0.1068435, -0.13234195, 0.053566497, 0.05061848, -0.28645232, 0.15518288, 0.23247199, 0.017553907, -0.25181335, -0.048030723, -0.06663929, -0.111026704, -0.12663394) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.010501938, -0.17995767, 0.06010859, 0.050185587, 0.108627126, -0.101203434, 0.07558728, 0.060466755, -0.106942676, -0.35854608, 0.16015992, 0.16823332, -0.06543775, -0.37310675, 0.014043972, -0.18328045) * go_3(0.0, 1.0);
|
||||
result += mat4(0.09712849, 0.013983463, 0.07291423, 0.031715546, 0.030862397, 0.045510456, -0.22066842, 0.063464865, 0.11721659, -0.10596602, -0.20611264, 0.052158818, -0.3961766, -0.03781582, 0.17633812, 0.1316111) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.25029674, 0.07153423, -0.35125682, -0.18255402, -0.19569087, 0.00432772, -0.0969035, -0.24648514, -0.0040922165, 0.037500706, -0.038137026, 0.056214277, -0.048258524, 0.03567822, -0.05033007, -0.24696785) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.03465209, -0.012495964, 0.22782089, 0.012034795, 0.2916752, 0.08264436, 0.15387125, -0.1473455, -0.15614432, 0.05536727, -0.027079755, 0.010725311, -0.03325222, -0.089212805, -0.10559839, -0.19647683) * go_3(1.0, 1.0);
|
||||
result += vec4(0.0001705175, -0.031081453, 0.010100773, -0.027214011);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!SAVE conv2d_3_tf1
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.026301445, -0.021575214, 0.22165509, 0.059994068, 0.03341161, 0.1831188, 0.20342293, 0.110160105, 0.03908121, 0.020673111, 0.07239561, 0.038754333, 0.15266368, 0.16526422, 0.062376205, -0.09759537) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.19817191, 0.10267733, 0.17744653, 0.23283184, 0.18810122, 0.2708428, -0.12651879, 0.020756349, 0.039632563, -0.22201295, 0.04873703, 0.09159713, 0.13838065, 0.21169297, 0.30816007, 0.044463675) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.27859214, 0.07277634, 0.0021458792, 0.0089682285, -0.069680706, 0.090415835, -0.057762265, 0.18703683, -0.03514389, -0.102816254, -0.036509827, 0.038066104, -0.0168311, 0.094478935, 0.04079697, -0.049064912) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.20913245, -0.110538535, -0.08584027, -0.1222067, 0.05414807, -0.045247085, 0.07351766, -0.002078549, -0.1270987, -0.10164512, -0.1857815, 0.08845066, -0.03743333, -0.098948084, 0.21244387, 0.10441866) * go_0(0.0, -1.0);
|
||||
result += mat4(0.015990427, 0.36396438, -0.24094687, 0.30236533, -0.13271736, 0.06057376, -0.19678196, -0.28577125, -0.25427434, -0.08400598, 0.07284403, -0.18552442, -0.16425897, 0.097259276, -0.32386774, -0.2190484) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.004581924, -0.13954072, -0.122360416, 0.14132866, -0.08529257, -0.013296556, 0.0848472, 0.09336581, 0.10332182, -0.016313016, 0.07103558, 0.032564916, -0.13478759, -0.20207484, 0.12986964, 0.1219679) * go_0(0.0, 1.0);
|
||||
result += mat4(0.09817874, -0.10573357, 0.100535244, 0.19608764, -0.13303067, 0.024192972, -0.030689823, 0.02574889, 0.051233094, 0.03489235, -0.18465245, -0.06943822, -0.031604882, 0.1519888, 0.09348508, 0.09187296) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.21365458, -0.23696984, 0.13097638, -0.09435498, 0.16467983, -0.066370346, 0.1269104, -0.095128186, 0.09954892, 0.12489504, -0.43418056, 0.106512725, -0.17860703, -0.07114084, -0.07630834, -0.26642478) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.009044342, 0.02711196, -0.14873673, 0.015405045, 0.0071443473, -0.025285944, 0.07409282, 0.06338527, 0.0149676185, 0.011741382, -0.2133069, -0.028912885, 0.19420496, 0.039629057, 0.057636812, 0.15214856) * go_0(1.0, 1.0);
|
||||
result += mat4(0.07629928, 0.25540486, -0.050925937, -0.18136702, 0.02261603, 0.22343902, 0.003270321, 0.10735731, -0.12541203, -0.10208828, 0.012832783, 0.2591262, 0.08122926, -0.009837677, 0.10308358, 0.19236866) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.0896358, 0.27571487, 0.04406029, -0.047453407, -0.08587119, 0.16366854, 0.20622262, 0.08347545, -0.3501584, -0.28434548, -0.07592983, 0.09098784, 0.07605388, 0.09677056, 0.0015295541, 0.05102585) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.18255898, 0.18618028, 0.0017002645, -0.013004655, -0.06436534, 0.13967068, 0.063077755, -0.10632303, -0.20803222, -0.028537111, -0.03144366, -0.08555215, 0.05154303, 0.02431626, 0.15246728, -0.013708507) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.020998938, -0.05026291, 0.03700117, 0.00830308, -0.1949294, 0.0026698054, -0.034649856, 0.19784226, -0.083901435, -0.069783084, -0.1504053, 0.16595264, -0.07480141, 0.16067508, 0.06010996, -0.021359695) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.040828142, -0.20158486, 0.034770954, -0.1894161, 0.11665004, 0.29729164, -0.10584386, 0.13165873, -0.18863006, -0.26719162, -0.047613148, -0.12728356, -0.2033613, 0.10550052, 0.20095508, -0.11275811) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.0785033, -0.1896073, -0.051492307, -0.1694358, 0.1368308, 0.049355216, -0.05707422, 0.079159185, 0.024578957, -0.0923136, 0.089215435, 0.28670043, 0.027932687, 0.06510816, 0.10810999, 0.05990052) * go_1(0.0, 1.0);
|
||||
result += mat4(0.08135192, 0.0001326522, -0.16098668, -0.18663193, -0.10280192, 0.078255914, 0.047648013, 0.08326376, 0.055962667, 0.06302574, -0.080121025, -0.031820554, -0.019117938, 0.12515336, 0.09794088, -0.03276838) * go_1(1.0, -1.0);
|
||||
result += mat4(0.280923, 0.24079335, 0.007883573, 0.06270414, 0.3055441, 0.19291803, -0.16041607, 0.14836526, 0.0013885222, 0.04538063, 0.10742898, -0.064491205, 0.048174977, 4.237692e-05, -0.15194727, 0.024381457) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.0009164131, -0.031949926, 0.0076425644, -0.036870714, -0.0031292974, 0.017726978, -0.20172147, -0.0770472, 0.26379177, 0.108997814, 0.08069395, 0.2126177, 0.012075376, -0.029457828, 0.062730506, -0.15754452) * go_1(1.0, 1.0);
|
||||
result += mat4(0.09167904, -0.2657421, -0.03443356, 0.03315832, -0.015365421, -0.1029612, -0.108251, 0.04261033, -0.097120754, -0.05616668, -0.09275983, 0.024902184, 0.050058514, -0.013761632, 0.07555132, -0.0046676896) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.10743835, -0.0007361781, -0.042085417, -0.08237517, -0.10094376, -0.24007876, 0.13924706, -0.07526801, 0.01158322, 0.15491122, 0.0069442675, -0.004242352, 0.11429785, 0.02994726, -0.11829945, -0.04108612) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.073622055, -0.064717196, -0.0025231615, 0.13256475, 0.20159899, 0.047977835, -0.10289233, -0.18419135, -0.00888952, 0.059428576, -0.053062655, -0.02730631, 0.14545685, -0.08686949, 0.17454128, 0.035443828) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.010146019, 0.06712568, 0.12614638, 0.023590917, 0.025756737, 0.06603747, -0.17108095, -0.06179699, 0.027241204, -0.13196802, 0.043475866, -0.0397495, 0.05306092, 0.035672903, 0.047219284, -0.16680142) * go_2(0.0, -1.0);
|
||||
result += mat4(0.079427816, -0.06716479, 0.19028603, -0.19694683, -0.061598092, -0.07471188, 0.21170339, 0.30140215, -0.0023369973, 0.04688297, -0.14154115, 0.19283508, 0.1339858, -0.09116279, 0.15305163, 0.029108394) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.14902157, -0.03339153, -0.08532003, -0.10736339, 0.08702709, 0.07607574, -0.09955836, -0.016585784, -0.030078214, -0.060374748, -0.2854279, 0.02441719, 0.034877967, 0.2099041, 0.11125731, -0.059071556) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.08436325, 0.06893047, -0.045362443, -0.02237741, -0.07583875, -0.034830183, -0.024008518, -0.2882329, -0.011109783, 0.101859994, 0.091137715, 0.0020565533, -0.044729806, -0.18168025, 0.069466636, 0.04994174) * go_2(1.0, -1.0);
|
||||
result += mat4(0.11915174, 0.089596465, -0.18965814, 0.015218237, 0.13500094, 0.19921367, -0.008298205, 0.29650384, -0.049439427, -0.27590424, 0.36169067, -0.030582754, 0.02151196, 0.019915426, 0.04543398, 0.16126189) * go_2(1.0, 0.0);
|
||||
result += mat4(0.1620274, -0.08264547, 0.082442135, -0.0034478644, 0.09888509, -0.0034957859, -0.107241705, -0.17729597, -0.05138647, 0.02052103, -0.019507123, 0.037574988, -0.1694345, 0.17871588, -0.22510391, 0.019049853) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.10962245, -0.1329873, -0.060855392, 0.025941676, -0.19536193, -0.120365486, -0.04313703, -0.052912965, 0.20854498, 0.08341353, 0.008687068, -0.20432276, 0.15677948, -0.19000018, 0.01821201, -0.041512605) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.012287526, -0.14180368, -0.098788455, 0.025949089, 0.09442778, 0.2247651, -0.12453263, 0.10435483, 0.274603, 0.06133054, 0.10506106, 0.14727746, -0.048299775, -0.082819685, 0.07319359, -0.047460355) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.070726536, -0.034744017, 0.07521428, 0.070649154, -0.05958955, -0.100232825, -0.010651838, 0.045392875, 0.2930271, -0.04952355, 0.3112155, 0.117203265, 0.025166962, 0.11176862, 0.06716659, 0.07175864) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.011560962, -0.14032063, -0.17424704, 0.07652749, -0.04220116, 0.052874275, -0.00225693, -0.031843517, -0.07520102, -0.13775803, 0.2449317, 0.069658786, 0.052280303, -0.105218224, 0.03574522, -0.020500354) * go_3(0.0, -1.0);
|
||||
result += mat4(0.08793712, 0.26712346, 0.08315631, 0.23813692, -0.04439029, 0.031587064, 0.09561177, -0.13380238, -0.24982157, 0.31701845, -0.3875432, 0.10487225, 0.09201869, -0.037252493, -0.006935219, -0.14650282) * go_3(0.0, 0.0);
|
||||
result += mat4(0.077635325, 0.13732299, -0.071563005, 0.096517466, -0.15051986, -0.111744404, 0.03996857, -0.052670125, -0.1819665, 0.054554947, -0.13774712, -0.20061246, -0.0023742192, 0.15647805, -0.024121126, 0.075497724) * go_3(0.0, 1.0);
|
||||
result += mat4(0.0073632775, -0.06535298, 0.039895996, 0.20666869, 0.13625242, 0.04823007, -0.07135618, 0.04787906, 0.01383074, 0.15382123, -0.15519714, 0.056721795, 0.061946746, -0.0586851, 0.028934354, -0.02264129) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.19791882, -0.111910924, -0.010451344, -0.30566537, -0.1416239, -0.14523096, 0.116883226, -0.18241516, 0.2680614, -0.18487626, 0.17472346, 0.08346682, -0.14510359, -0.029229192, -0.005879142, 0.050247498) * go_3(1.0, 0.0);
|
||||
result += mat4(0.030153519, -0.092469186, -0.022912916, 0.10200855, -0.04237032, -0.05917764, 0.10479645, -0.05619482, -0.18949397, -0.019547248, 0.013868889, -0.1524476, 0.14048979, -0.032521486, 0.1322921, 0.070972025) * go_3(1.0, 1.0);
|
||||
result += vec4(0.012053958, -4.6962363e-05, 0.0020099226, -0.033494607);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!SAVE conv2d_4_tf
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.06738501, 0.034009207, -0.21538448, 0.14296548, 0.12896985, -0.23526315, -0.08848608, 0.019602662, 0.14937137, 0.11353096, 0.11884168, -0.016765572, 0.030985225, 0.046430565, 0.06614828, -0.19202724) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.10326068, 0.11014975, 0.17069744, -0.21474148, 0.16761585, 0.13434832, -0.101021074, 0.006307025, 0.07478008, -0.1060066, 0.035315692, 0.033488914, -0.24906659, 0.06269967, 0.11120735, -0.040928528) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.09334615, 0.057705753, 0.12213245, -0.06402275, 0.30694544, 0.034585163, 0.20345578, 0.07489286, 0.07483618, -0.14240396, 0.034846418, -0.03811241, 0.010882573, 0.13204294, 0.017563924, -0.047203008) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.21673942, -0.024010994, -0.10238504, -0.041160326, 0.06838163, -0.20950818, 0.06526309, -0.079094924, 0.02208821, -0.28130978, 0.086275116, -0.089067616, 0.12133826, -0.062600106, -0.020521903, -0.07654401) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.03055029, -0.15683146, -0.20331301, -0.06252028, 0.13350682, 0.20338707, 0.038425338, 0.1581342, -0.27322498, -0.14999662, -0.16681097, 0.0971585, -0.20014858, -0.081635274, -0.0781877, -0.20625232) * go_0(0.0, 0.0);
|
||||
result += mat4(0.38375977, -0.019825654, 0.1886721, 0.22616312, 0.3402173, 0.1825304, -0.05531195, 0.30973226, -0.2676023, 0.14413352, 0.021706983, 0.01732799, 0.23466855, -0.13805965, 0.22570935, 0.018103868) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.15169825, 0.0270689, -0.2503316, 0.17289825, -0.16437647, 0.039233048, -0.35572487, -0.048393793, 0.19270042, 0.24260359, 0.12041881, -0.0009793913, 0.11656858, 0.11007414, -0.0757491, 0.047933612) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.18657999, -0.11252566, -0.05237504, -0.07368097, 0.13882741, -0.13710637, -0.006996468, -0.062354874, 0.23452504, 0.15333645, -0.0022776406, -0.17910439, 0.03629509, -0.16264829, -0.010011833, -0.15313338) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.060544558, -0.04913478, -0.061717357, 0.02323648, 0.28739056, -0.07434013, 0.19110644, 0.100050166, 0.0073363045, 0.08185653, -0.024797903, -0.14424153, -0.20838726, 0.16154376, -0.048517212, -0.025453888) * go_0(1.0, 1.0);
|
||||
result += mat4(0.14975396, -0.13142908, 0.36210674, -0.054021083, -0.10632155, 0.045697935, -0.18946633, 0.02228141, -0.08919603, 0.09800842, -0.17634438, 0.09512711, -0.03425503, -0.12298555, -0.05354435, -0.17112055) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.09958265, -0.057276618, -0.16262266, -0.06415915, 0.14579074, -0.36784375, 0.08034197, -0.04537706, 0.005460582, 0.22313322, 0.07382161, 0.014990379, 0.044636846, -0.2811128, -0.22621547, -0.06044004) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.10569276, -0.03738662, 0.16100396, 0.058593616, -0.048862137, -0.08796426, 0.20101094, -0.11039573, 0.17196764, -0.04601554, 0.008571281, -0.073729075, 0.051433694, -0.051276565, 0.087334655, -0.0360379) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.011119538, -0.28781965, 0.28637868, -0.1742508, -0.07121849, 0.10379717, 0.012615981, -0.029563965, -0.18678424, 0.05291095, 0.039143506, -0.028248642, -0.014103922, 0.029155696, 0.10433492, 0.16305852) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.2231037, -0.13697462, -0.29124337, 0.08519773, 0.15893684, -0.17763218, 0.06950923, 0.34361118, -0.024844287, 0.044008408, -0.033844844, -0.086971916, -0.07884748, 0.2543499, 0.056884114, 0.10068364) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.07710048, -0.23218372, 0.04346047, 0.21769643, 0.06473219, -0.18066105, -0.2511205, 0.15309611, 0.04535977, 0.16450433, 0.10846344, 0.0016952346, -0.010874939, 0.28966382, -0.121990964, 0.12956186) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.007910202, 0.17766511, 0.14364475, 0.1016258, 0.0051045395, 0.18691733, 0.005813767, -0.0070582186, 0.019418601, -0.1604435, 0.016088275, -0.18265302, -0.15719391, -0.17369832, -0.036745597, -0.19647408) * go_1(1.0, -1.0);
|
||||
result += mat4(0.08938396, -0.0073808245, 0.11225727, -0.012303106, 0.096785046, 0.030483445, 0.027719889, -0.052584838, -0.14887555, -0.03422243, 0.12646855, -0.1722482, 0.010239037, 0.06406088, -0.20053658, 0.01964698) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.120734036, -0.12450362, -0.06582111, 0.1639675, -0.19787048, -0.08049789, -0.014257596, 0.058436662, -0.0009387449, -0.08698089, -0.017400503, 0.06295286, 0.09890349, -0.057190523, -0.103520766, -0.04207548) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.0118413875, -0.031288836, 0.09749554, -0.012266401, -0.07998591, 0.22615653, -0.06207416, 0.03257896, -0.076378696, -0.079426095, -0.13968349, -0.15423697, -0.1091681, -0.02893125, -0.032659534, -0.063735925) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.119372696, 0.013176554, -0.029381052, 0.21919228, 0.045041792, 0.24844484, 0.26363325, 0.08480674, 0.087083444, 0.11984778, -0.088715754, 0.06421046, 0.05225977, -0.05140334, -0.055052705, -0.049854077) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.0035781674, 0.0861361, -0.07675145, -0.056479637, 0.16973391, -0.12113791, 0.10729832, -0.03773517, 0.058618728, 0.12148276, 0.17260705, -0.06968724, 0.076358154, -0.15307103, 0.17700425, -0.13467014) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.02752418, -0.06366472, -0.025610954, 0.0013539721, -0.06465272, 0.0806373, -0.07336035, 0.10114861, 0.0041146413, 0.15878421, -0.044668555, -0.12150811, -0.1071482, -0.05086587, 0.18589285, 0.05065092) * go_2(0.0, -1.0);
|
||||
result += mat4(0.07200056, 0.021739854, 0.29476613, -0.08475931, 0.15018553, -0.07886365, 0.36336347, -0.020576432, 0.25866082, -0.059272554, 0.054249667, -0.17822553, 0.1755872, 0.3244387, -0.39173844, 0.33894604) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.11570926, 0.1342677, -0.19511898, 0.0075454637, -0.01890476, -0.14239742, 0.18921931, 0.033990458, 0.31306365, -0.006998358, 0.029190077, -0.005679954, -0.15341778, 0.07766778, -0.25691047, -0.0964161) * go_2(0.0, 1.0);
|
||||
result += mat4(0.019746238, 0.0021332854, -0.00879096, -0.1338671, -0.0001600663, -0.29465106, 0.0867611, -0.114963025, 0.07874301, -0.012734178, -0.11124061, -0.010926616, -0.04941506, -0.07516841, 0.116663, -0.29018974) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.01651721, 0.05955898, 0.023618208, 0.098695934, 0.018553663, -0.054378513, 0.1436929, 0.1693743, -0.27483663, 0.029127488, 0.09619316, -0.06109113, -0.08619361, 0.09315214, -0.02478657, 0.18544984) * go_2(1.0, 0.0);
|
||||
result += mat4(0.09570196, -0.016528936, -0.1559397, 0.14312246, 0.04029428, 0.08773151, -0.043646842, 0.17894371, -0.082413055, 0.0027082344, -0.100171275, 0.01547501, 0.18122818, -0.11933676, 0.26404107, -0.3169703) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.12073344, 0.08683522, -0.09249099, 0.058786053, -0.14480567, -0.121013954, 0.033335857, 0.009353379, -0.055087596, -0.13002734, 0.08890566, 0.05508963, -0.0075715426, -0.15936922, -0.03968994, -0.1690259) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.2011206, 0.23898427, 0.23656492, 0.1287573, 0.14850396, 0.40532517, -0.107408255, 0.40119782, 0.099813245, -0.03830304, 0.101520434, -0.026478073, -0.048469637, 0.106440455, 0.056632314, -0.17825997) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.076735444, 0.05965795, -0.0052469415, -0.21785147, 0.11887833, 0.067560315, 0.051149055, 0.23626682, -0.1297049, -0.035512198, 0.20352256, -0.025064934, 0.04958706, 0.0454198, 0.0113334535, 0.0417486) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.09055751, 0.033915352, -0.21836667, 0.22006813, -0.099022895, 0.11720966, -0.15686816, -0.13586599, -0.094427735, -0.08831514, -0.06182928, 0.09213704, -0.03642064, 0.18129414, -0.012926811, 0.12179882) * go_3(0.0, -1.0);
|
||||
result += mat4(0.19389409, 0.09512252, 0.14768016, -0.16623649, -0.031052284, -0.026814984, 0.106168024, -0.2026781, -0.04581419, -0.0016849053, -0.04101923, 0.038959503, -0.011938445, 0.20096186, -0.26666564, 0.4824324) * go_3(0.0, 0.0);
|
||||
result += mat4(0.17727576, 0.07309147, 0.12131863, -0.163096, 0.17225246, 0.26256254, 0.27685758, 0.09094053, 0.029605515, -0.20217367, 0.047564875, 0.043115832, 0.15089568, -0.09670934, 0.24131384, 0.03337442) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.34192136, 0.12063195, -0.31159517, 0.04170889, -0.30147067, -0.21330686, -0.1514457, -0.121126845, 0.04409098, 9.2206596e-05, 0.027680017, 0.03230512, -0.27993527, -0.093485355, 0.07568645, -0.23585452) * go_3(1.0, -1.0);
|
||||
result += mat4(0.0537712, -0.20847629, 0.1740093, -0.013894753, -0.32719997, -0.059484575, -0.006098233, -0.10336451, -0.14706188, -0.07424865, -0.07045905, 0.17093194, -0.22147557, 0.09086218, -0.11033544, -0.05306482) * go_3(1.0, 0.0);
|
||||
result += mat4(0.00489003, -0.11509064, -0.021005848, 0.16637677, -0.089347586, 0.17545725, -0.17313693, 0.13742085, -0.14577347, 0.07951095, -0.092139855, 0.017118992, -0.053472433, 0.079414465, 0.0330263, -0.11189824) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.034743138, 0.012946433, -0.082333155, 0.07721756);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!SAVE conv2d_4_tf1
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.25835788, 0.050451655, -0.1845038, -0.07232528, 0.1323318, 0.26276684, 0.10842882, -0.083056524, 0.17426784, -0.3594826, 0.2728965, 0.08388844, -0.004007842, 0.020535901, -0.051425606, 0.07750436) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.11410436, 0.014572361, -0.27057216, -0.023974562, 0.05234827, 0.15328228, -0.17502303, -0.3199359, 0.12188045, -0.095813684, 0.024145132, 0.0856916, -0.027453909, -0.043129764, 0.16971985, 0.021623038) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.06611095, 0.038625732, -0.13717118, -0.04497733, 0.15213469, 0.04770935, 0.0729271, -0.062052976, 0.004571303, 0.035141192, -0.059409596, 0.044652313, 0.17520894, 0.09665589, -0.1479193, 0.06528058) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.1845968, 0.091479465, -0.09394898, -0.13545018, -0.029501775, -0.21426639, 0.09255898, 0.1257644, 0.20256902, 0.06267267, 0.10378081, 0.13494423, 0.058310498, 0.03642236, -0.16268995, -0.048100803) * go_0(0.0, -1.0);
|
||||
result += mat4(0.2155119, -0.3683131, 0.049449228, -0.20559964, -0.11761922, -0.2518804, -0.020712897, 0.12895772, -0.07543782, 0.5805017, -0.11301444, -0.038493153, -0.06710986, -0.09321189, 0.108671665, -0.03259695) * go_0(0.0, 0.0);
|
||||
result += mat4(0.035307787, 0.108389005, -0.27493554, 0.27029404, 0.25523573, -0.28636125, -0.20766719, -0.008661457, -0.004480811, -0.046390545, -0.16221444, 0.008979624, -0.061375532, 0.035076566, -0.018924266, 0.01380219) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.051922515, -0.12463486, -0.10383422, 0.02220095, -0.1573033, 0.13980615, 0.13248625, -0.16803266, -0.0692132, -0.21552645, 0.13744529, 0.23034313, 0.0052666534, 0.028977966, 0.07720251, -0.06477756) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.14097473, 0.2770271, -0.172289, -0.03000696, -0.028684044, 0.040578447, -0.2290285, 0.082329154, -0.042402364, -0.20926563, 0.08233207, 0.11862443, -0.07038536, -0.02273004, 0.091550544, -0.065856494) * go_0(1.0, 0.0);
|
||||
result += mat4(0.14879914, -0.023923844, -0.23569296, 0.20306346, 0.17502785, 0.28776234, -0.2788995, 0.10012439, -0.05635638, -0.025840463, 0.09222198, 0.118032, 0.08057015, 0.1286071, 0.060189806, -0.052669708) * go_0(1.0, 1.0);
|
||||
result += mat4(0.07076086, -0.15111323, -0.07427972, 0.008372168, -0.17791592, -0.16254742, 0.013961132, -0.0944912, -0.23380096, 0.17377278, -0.09683394, 0.019931393, -0.12042098, 0.0016406325, 0.09393333, -0.06882231) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.21465093, 0.04142968, 0.06840044, -0.37831602, -0.05549571, 0.044905066, -0.07873589, -0.026804, -0.34764197, 0.022487951, -0.077293746, 0.089457795, -0.110094436, 0.24233972, 0.06285107, -0.10851744) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.093270175, 0.084138945, 0.03938272, 0.063565865, -0.010733802, 0.13554469, -0.06650261, 0.033002816, 0.011187271, -0.12821455, 0.20785914, -0.030438649, -0.124710515, -0.022294303, 0.09732408, 0.057609864) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.12833868, 0.021577539, -0.02700365, 0.11799592, -0.03655647, -0.04225167, 0.11049353, -0.16036157, 0.049277548, -0.033842396, 0.10020137, 0.095509745, 0.08060231, -0.09237418, -0.035598125, -0.035926737) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.32829186, 0.3492363, 0.030671779, -0.12606762, 0.010437313, 0.2757115, -0.21517593, -0.15800527, -0.12592544, -0.20578934, 0.10444053, 0.12993255, -0.046079267, 0.03834173, -0.19277227, -0.22124454) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.052546192, 0.026082167, 0.13831234, 0.10982424, 0.012946818, -0.12439852, 0.10134106, -0.10050398, -0.04472338, -0.14325236, -0.20579574, 0.0044005127, 0.22013672, -0.32955512, 0.12404084, -0.008160738) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.10774314, -0.31650826, -0.06601711, 0.19635755, -0.12622592, -0.06396423, 0.13856032, 0.16540553, 0.021387719, 0.23377723, -0.053738154, -0.1000186, -0.08338395, -0.052813534, 0.008122962, 0.13732094) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.18270823, 0.06966014, -0.17788303, -0.27303055, -0.077971615, 0.013978423, -0.02039098, 0.12715338, -0.11924171, 0.18900296, -0.085199654, 0.215198, 0.18587974, -0.009749325, 0.0173584, -0.12018259) * go_1(1.0, 0.0);
|
||||
result += mat4(0.052129295, -0.107416354, 0.12711766, 0.03708665, -0.14369462, -0.055359814, -0.16639823, -0.045143317, -0.06925672, -0.040696755, 0.01999809, -0.016040625, -0.02484878, 0.07417094, 0.050875198, 0.2145528) * go_1(1.0, 1.0);
|
||||
result += mat4(0.055696912, -0.16680926, -0.021987487, 0.024941636, -0.0927883, 0.022136632, 0.033782948, -0.10646058, -0.14944647, 0.25457275, 0.046682496, -0.022462368, -0.07886781, 0.08165927, 0.06848105, 0.0063734027) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.037053242, 0.033215813, 0.18291366, 0.12340375, 0.08491059, -0.28442004, -0.0127422465, -0.039834313, -0.23321372, 0.26676926, -0.05636355, -0.15672484, -0.12891728, -0.15486577, -0.032004442, -0.092745155) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.015779478, -0.18457565, 0.24996394, 0.036197674, 0.15694007, 0.15863103, -0.07332398, 0.0016235278, -0.15536517, -0.056062788, 0.14102836, 0.16915025, -0.08001087, 0.07073164, 0.13796777, 0.123867124) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.045792986, -0.15135059, -0.1354885, -0.043678258, -0.35655212, 0.51232076, -0.12816145, -0.046569496, -0.014127674, -0.06282611, -0.098873, -0.06359104, -0.0919222, 0.11822437, 0.079254694, 0.00579688) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.15683417, 0.61610246, -0.3024612, 0.12917964, -0.09303367, 0.23612969, -0.40842506, -0.12374661, -0.07572449, -0.2613284, -0.09970177, -0.015227848, 0.106239066, -0.21411185, 0.051998455, -0.1364518) * go_2(0.0, 0.0);
|
||||
result += mat4(0.23850034, -0.14394449, -0.0031468747, -0.2380617, -0.027200876, -0.041352056, -0.01864445, 0.033848196, -0.12064239, -0.110480845, 0.08450956, -0.22328654, 0.17664163, 0.22268307, 0.050886698, -0.17475672) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.17808256, 0.010803805, 0.03315186, 0.033143792, -0.14205995, 0.25039625, -0.08784382, -0.13454252, 0.19576813, 0.10755282, 0.22821628, 0.019456752, -0.0422955, -0.016182603, -0.12066697, 0.0548465) * go_2(1.0, -1.0);
|
||||
result += mat4(0.11563777, -0.257929, 0.0010403778, 0.080267854, -0.0025255163, 0.2855168, -0.060352214, -0.07816255, -0.00090574916, 0.049510725, 0.03720483, 0.059250016, -0.08674136, 0.20522198, -0.28694284, 0.1299507) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.14638457, 0.04063328, 0.03139636, -0.007934521, 0.07689684, -0.09467145, 0.10607347, 0.054510128, 0.003306194, 0.05347124, 0.062762424, -0.041480847, -0.07677865, -0.139573, 0.010972524, 0.21957156) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.026845628, -0.043439507, 0.034738723, 0.07281683, 0.14474197, 0.031586993, -0.22767854, -0.0707655, 0.105201736, -0.28805482, 0.008668302, -0.16329518, 0.06157049, 0.3803886, 0.26345953, -0.011096537) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.23328833, 0.085731484, -0.07755016, 0.33559516, 0.07704345, 0.115106605, -0.24114038, -0.44630137, 0.2726737, -0.32170138, -0.009236524, -0.11666051, 0.0457048, 0.07876708, 0.13134004, -0.035318643) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.05140272, 0.011605703, 0.13899171, -0.05071015, 0.18413687, -0.31413674, -0.13043414, -0.15118152, -0.15326938, -0.10720126, -0.23738635, 0.13481396, 0.25115076, -0.009316611, -0.2584441, -0.14389823) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.039723795, -0.14869407, -0.1692942, 0.026501274, -0.10685166, -0.121267825, -0.08584318, -0.09580693, -0.10626739, -0.068417974, 0.11321909, -0.13664317, 0.061380867, -0.2587898, 0.14850819, 0.008178645) * go_3(0.0, -1.0);
|
||||
result += mat4(0.06912782, 0.24230564, -0.048150286, 0.2203717, -0.17417085, 0.105546735, -0.16648416, -0.0045053074, 0.09764028, 0.37122592, -0.1939995, -0.27899942, -0.088152565, -0.53869057, 0.21676709, -0.08056594) * go_3(0.0, 0.0);
|
||||
result += mat4(0.07651754, 0.03704878, -0.0197015, 0.1660726, 0.07002748, -0.11820414, -0.23360898, 0.1481592, 0.029847002, 0.054057185, 0.013176299, 0.06552942, -0.13865773, -0.20105527, -0.37550658, 0.005769631) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.22697811, -0.17426412, 0.10148018, 0.008134666, 0.10771455, 0.16943407, -0.016319012, -0.40176705, -0.06854668, -0.049045276, 0.20919096, 0.13240765, -0.050125647, 0.14902508, 0.052697595, -0.13817468) * go_3(1.0, -1.0);
|
||||
result += mat4(0.04301619, 0.23184754, -0.023551717, 0.3768405, 0.028999053, 0.06709736, -0.05993663, -0.059861984, 0.15499207, -0.22217415, 0.111131504, -0.09082529, -0.19389243, 0.024621522, -0.15305442, 0.010799284) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.035496738, 0.010802548, -0.028718363, 0.19263634, 0.16900502, -0.16661702, -0.027631328, 0.18309957, -0.015860107, -0.03309961, -0.091390446, 0.14000848, -0.0036591904, 0.47659522, -0.09373507, -0.29020965) * go_3(1.0, 1.0);
|
||||
result += vec4(0.08895955, -0.027667087, 0.20500831, 0.00037762933);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!SAVE conv2d_5_tf
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.018134737, -0.2296755, -0.07276725, -0.029795367, 0.05382051, 0.092847414, -0.024469728, -0.1674685, 0.0017946451, 0.30074653, 0.0034195695, -0.04892261, 0.18229689, -0.20116119, -0.12702174, -0.08259108) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.1357695, -0.08149211, 0.09314453, -0.21966846, 0.34740716, 0.043606415, 0.04225903, 0.034449834, 0.17248215, 0.39148283, -0.13868807, -0.010550686, 0.044238456, -0.09693464, -0.005044985, 0.24383289) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.19959371, 0.098685324, 0.058746945, 0.010580748, 0.08051514, 0.031898864, 0.017556064, 0.13004355, -0.01727653, 0.11044019, 0.040673427, -0.20064595, -0.23321067, 0.06398686, -0.19126236, -0.2430858) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.12870286, -0.113455534, 0.23722827, 0.070718594, 0.19049989, -0.1927299, -0.06343845, 0.113127775, 0.082530305, -0.10972526, -0.090779535, 0.05731582, 0.11018802, -0.18049154, 0.09269507, -0.10304576) * go_0(0.0, -1.0);
|
||||
result += mat4(0.15513484, 0.06659583, 0.08125296, -0.012350324, -0.09492788, 0.5048303, 0.13206847, 0.39554298, 0.28953737, -0.20913891, -0.26781562, -0.17539899, 0.023778774, 0.29716817, 0.15768486, 0.37702608) * go_0(0.0, 0.0);
|
||||
result += mat4(0.0724462, 0.015571356, -0.032217246, 0.0050658924, -0.22708446, 0.03968809, 0.016753826, 0.0025668752, -0.055932112, 0.113931604, 0.19766758, -0.030027265, -0.17384295, 0.15013468, -0.0070017707, -0.09469028) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.078361556, -0.0954201, -0.006358101, 0.040500037, 0.4190454, -0.17622913, -0.07234791, 0.05462559, 0.18641087, 0.058313597, -0.0180785, 0.13818781, -0.14640772, 0.0699486, 0.0073663946, -0.076789856) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.21421191, 0.08736062, 0.09041226, 0.03608585, 0.02769972, 0.09641289, 0.11824623, 0.05653645, 0.16464607, 0.19839554, -0.13379547, 0.054417104, 0.067530684, 0.18971571, 0.13785432, -0.097639814) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.32658005, -0.14606023, -0.069448665, 0.032998275, -0.28331423, 0.0011900732, -0.020304207, -0.13535896, 0.08298347, 0.045509677, -0.030503955, -0.037504148, 0.049955815, 0.0925771, 0.00058534974, -0.12398032) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.2955836, 0.29059318, -0.018196672, -0.35866606, -0.01309431, 0.03540315, 0.010609202, 0.11956812, 0.10296229, 0.22536302, 0.015201129, -0.23797737, -0.16960852, -0.11414787, -0.034440614, 0.112644605) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.14952518, 0.07024436, -0.083184876, -0.0814617, -0.13303639, 0.016159372, -0.13521518, 0.2221334, -0.056617837, 0.12958299, 0.064461656, -0.20146395, -0.16023181, 0.2640758, 0.27528805, -0.1426518) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.04382363, 0.09856003, -0.08561442, -0.15699928, -0.121069774, 0.04685383, -0.009170197, -0.031489655, 0.18730178, 0.238442, 0.22497098, 0.032015145, -0.03709115, 0.1535079, 0.21674158, 0.10678019) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.12200952, 0.24224263, 0.034097504, -0.028179523, -0.011962496, -0.04489487, -0.05198827, 0.22194928, -0.045400873, -0.049828544, 0.111477956, -0.098361604, 0.12788995, -0.016093334, -0.19886433, -0.011161484) * go_1(0.0, -1.0);
|
||||
result += mat4(0.30563712, 0.013071727, -0.004799883, 0.12888052, -0.259498, -0.041566677, 0.07311124, 0.162324, 0.28371668, -0.004693743, -0.0019395344, 0.029358242, 0.08730285, 0.12184509, 0.05508437, 0.048439097) * go_1(0.0, 0.0);
|
||||
result += mat4(0.12760857, 0.115813166, -0.217695, -0.10629871, -0.227366, 0.09030426, -0.15313712, 0.020528946, -0.20743734, 0.088583544, 0.04594053, -0.22891994, 0.18949282, -0.042186577, -0.17330512, -0.010711361) * go_1(0.0, 1.0);
|
||||
result += mat4(0.029503195, 0.0063797613, -0.17004286, -0.096844055, 0.010218098, 0.04247233, 0.02362808, 0.14700809, -0.08082364, 0.11159672, -0.018505255, -0.15228583, 0.15693732, -0.025359154, 0.024829186, 0.1943192) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.03912932, -0.21989027, 0.12203028, 0.18702275, -0.118537985, 0.21039696, 0.09102061, 0.012288879, 0.031666897, 0.1318455, -0.04901404, -0.07516063, -0.44782668, 0.04884501, 0.047070876, 0.008728358) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.08669101, 0.3053463, -0.08963947, 0.0034188698, -0.070004664, 0.064788476, 0.093737036, 0.070050925, 0.12728429, -0.13179256, -0.014913502, 0.09308136, -0.027638942, 0.008638711, 0.08794172, -0.05531093) * go_1(1.0, 1.0);
|
||||
result += mat4(0.0728421, 0.07872358, 0.11454748, 0.08497922, 0.071820416, -0.11789207, -0.08184197, 0.1359588, -0.2143346, -0.05876081, 0.023172129, -0.08430511, -0.19276723, 0.14283359, 0.15604696, -0.055187486) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.068641685, 0.2732106, -0.2809107, 0.12736696, -0.08642367, 0.023898933, -0.17859498, -0.18299665, -0.06684587, -0.12204666, 0.45898953, -0.24240111, 0.25182098, -0.04395751, 0.10637211, -0.22135144) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.0852072, 0.051133018, 0.03333165, -0.0008938216, 0.10251267, 0.0550774, 0.041769378, -0.21259712, 0.286912, 0.123342015, 0.282759, -0.0730124, 0.14275575, -0.15580742, -0.15224406, 0.045376908) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.03328225, 0.11563978, -0.07451964, 0.030546209, -0.04698351, -0.18544962, 0.037350416, 0.13969816, 0.0556746, -0.06359919, 0.06478219, -0.031694926, 0.13396506, 0.09443612, -0.01922686, -0.06290365) * go_2(0.0, -1.0);
|
||||
result += mat4(0.07495407, 0.063429266, -0.106221214, -0.085107304, 0.2497817, -0.46598253, -0.18833177, -0.2731128, -0.13024822, 0.56053543, 0.055704467, -0.12331414, -0.031199086, 0.05061188, 0.22097112, -0.6611177) * go_2(0.0, 0.0);
|
||||
result += mat4(0.08276988, -0.044184342, -0.03562185, -0.06159881, 0.27694225, -0.07192965, -0.08663714, 0.020221777, 0.14095962, -0.06229397, 0.051374253, -0.038158998, 0.10664802, -0.041305423, 0.051260717, -0.054698635) * go_2(0.0, 1.0);
|
||||
result += mat4(0.12800686, 0.03485072, 0.039914366, 0.034041498, -0.08305794, -0.046292894, 0.22765331, 0.10904922, 0.0013937047, -0.08750301, 0.009126207, -0.065589435, 0.2837707, 0.08884436, -0.07234862, -0.093502745) * go_2(1.0, -1.0);
|
||||
result += mat4(0.113439895, 0.06081726, 0.1122302, -0.022936966, 0.10329637, -0.31816107, -0.051597945, 0.23846027, -0.083913095, -0.29872265, -0.040147282, -0.08981918, -0.04329814, -0.12339693, -0.034489952, 0.013393211) * go_2(1.0, 0.0);
|
||||
result += mat4(0.33091688, 0.1726297, 0.034332044, -0.091396205, 0.15434311, -0.0022870845, -0.15506189, 0.08710491, -0.16063525, 0.042252056, 0.017086457, 0.08134797, 0.08631321, 0.037843138, 0.088296555, 0.0064518084) * go_2(1.0, 1.0);
|
||||
result += mat4(0.09161051, 0.114355795, -0.15304486, -0.030537153, 0.1835368, -0.3287635, 0.031197926, 0.09717476, 0.04276852, 0.113250345, 0.05949038, -0.10599563, 0.43574792, -0.060788117, 0.18409383, 0.12678055) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.018356865, -0.0072578182, 0.12020777, -0.013127592, 0.20136636, -0.22984362, 0.06896224, 0.00044982752, 0.008428429, -0.123316936, -0.09989286, 0.078248784, -0.16313677, -0.003020313, -0.46285018, -0.08967125) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.03451497, -0.10864502, 0.13207638, 0.17194521, 0.0037514758, -0.20222199, -0.12535086, 0.001511977, 0.056294486, -0.2112898, 0.078261316, 0.10118746, -0.044742294, 0.21793383, -0.19927903, -0.21338293) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.034903776, -0.10167085, 0.031066334, 0.0379958, 0.20532596, -0.17457838, 0.16556816, -0.0021619152, 0.02682665, 0.03396325, -0.059273884, 0.1922813, -0.072151475, -0.010240544, 0.2302027, 0.12385962) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.20170145, -0.08203941, -0.028107846, -0.18003726, 0.44744352, -0.13190243, 0.13233365, 0.03626546, 0.085763134, -0.25613126, -0.11213388, 0.15529087, -0.271649, 0.050587676, -0.062583975, 0.057289865) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.040649455, -0.17949733, 0.35847965, -0.040587306, 0.24314344, -0.23811667, 0.13958354, 0.04961874, 0.09858903, -0.04202913, -0.21850993, 0.0700419, -0.09130745, -0.096835814, 0.0022782686, -0.25416258) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.08215545, -0.019647893, 0.055263475, 0.053733055, 0.098485716, -0.1041945, -0.06541415, -0.08868577, -0.07262986, 0.03513784, -0.110529095, -0.03369232, 0.056786604, 0.2569229, -0.05931065, -0.22081214) * go_3(1.0, -1.0);
|
||||
result += mat4(0.066926084, 0.029664058, -0.10779271, 0.11026963, 0.23927264, -0.16914488, 0.022947345, 0.12303853, -0.07066212, -0.013205378, 0.15348643, 0.035568032, 0.20966691, 0.010149819, -0.08814468, -0.064854674) * go_3(1.0, 0.0);
|
||||
result += mat4(0.11493852, -0.074924305, -0.14840698, -0.16956823, 0.056806292, -0.06387947, -0.06880271, -0.04637334, -0.1929893, 0.18226422, 0.064644486, -0.1594863, 0.027403917, 0.13951495, -0.06569123, -0.07700207) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.043347504, -0.20504741, -0.037821215, -0.014486937);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!SAVE conv2d_5_tf1
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.047881734, -0.09396414, -0.2839081, 0.3140853, 0.052613556, 0.09940423, 0.23960467, -0.022228222, -0.12065009, 0.07898222, 0.08657881, 0.010852739, -0.050450284, 0.01683982, 0.031813968, 0.053060856) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.10252411, -0.03116448, -0.30114275, -0.0316799, -0.017501019, -0.03006003, -0.2095696, 0.10134927, -0.3901916, -0.15335023, -0.11955071, 0.1337449, 0.101239376, -0.25044814, 0.2128469, 0.018979514) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.13392173, 0.052036732, 0.1682114, -0.026263753, 0.027221246, -0.15121374, 0.13723798, 0.08950682, -0.1182108, -0.07294226, 0.023392374, 0.052329235, -0.05632852, -0.07036173, 0.06872573, 0.05238042) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.18112028, 0.18242362, -0.06812871, 0.032463413, 0.124638766, -0.26765212, -0.07678663, 0.33806562, 0.09674393, 0.15574542, 0.23634006, -0.02873782, -0.1626769, -0.14760062, -0.007274849, 0.09866139) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.10726673, -0.10925056, 0.19967109, -0.19936769, 0.15942842, -0.14870064, 0.15493345, -0.08489036, -0.49053356, -0.17321263, 0.28426084, 0.18721215, -0.09898434, -0.2751838, -0.11833524, 0.028445128) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.11788817, -0.23724948, -0.046072144, 0.035621114, 0.04527003, -0.0073492974, 0.11097195, 0.06806836, 0.04814677, -0.1408476, -0.1325629, 0.00929532, -0.16699041, -0.03034791, 0.08320368, -0.15429299) * go_0(0.0, 1.0);
|
||||
result += mat4(0.2729515, 0.008244692, -0.17441982, -0.39026466, 0.17381759, 0.31194404, 0.055934936, 0.20744409, 0.20119062, 0.0734271, 0.0796807, 0.0031037466, -0.0016392237, 0.033733975, 0.07149338, 0.042083208) * go_0(1.0, -1.0);
|
||||
result += mat4(0.07985744, 0.10945015, 0.018472541, 0.1397503, 0.2005682, 0.42641, 0.23022486, -0.2916921, 0.028285174, -0.31885162, -0.27070364, -0.10390779, 0.0751492, 0.12752363, -0.2279459, 0.08998453) * go_0(1.0, 0.0);
|
||||
result += mat4(0.18450491, -0.140783, -0.008006845, 0.09029298, 0.12536179, 0.26949662, 0.09491545, 0.063907005, 0.11212244, 0.09778506, -0.1835966, -0.053119674, 0.0072294096, 0.25018227, 0.010868525, -0.22721334) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.028011927, -0.20073172, 0.5976166, -0.19494139, 0.17958745, -0.03838646, 0.058325976, -0.29409218, -0.12793432, 0.03245129, 0.35662368, -0.05048354, -0.13368197, -0.06151968, -0.012714591, -0.1763054) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.18468465, 0.31682113, 0.12818255, -0.117110476, 0.13709468, -0.10034022, -0.07994527, -0.1259309, 0.04067299, -0.1147398, 0.28361055, 0.27916273, 0.03696692, 0.16829546, 0.27819383, 0.08305029) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.28920117, -0.033877946, 0.01586206, 0.04681198, 0.024248574, -0.045777842, -0.03342128, 0.07525412, -0.063377544, -0.016737273, 0.11235511, -0.04325238, -0.24170023, -0.09993599, -0.03205371, 0.14339828) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.008357902, -0.11038377, 0.03709221, 0.26775306, 0.07963845, -0.25377446, -0.17630441, -0.10966474, 0.057311732, -0.083327, 0.044497233, 0.06903858, -0.26531395, -0.103399664, -0.14806591, 0.269314) * go_1(0.0, -1.0);
|
||||
result += mat4(0.05450808, -0.041993964, -0.07217651, 0.034468375, 0.2117634, 0.0075620585, 0.05825411, -0.2252478, -0.0527787, 0.049732126, -0.032040413, -0.09361454, 0.29585132, 0.018413153, 0.18384546, -0.024226356) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.031109914, 0.19351351, 0.07405522, -0.06313074, -0.09983541, -0.011495182, 0.11749038, -0.16775608, 0.2790974, -0.09338754, 0.07913264, 0.103792936, -0.18679164, -0.15639925, 0.112943865, 0.07930375) * go_1(0.0, 1.0);
|
||||
result += mat4(0.004106195, -0.036833283, 0.12908752, 0.12869535, -0.02472107, 0.17561707, -0.025890926, -0.18789047, 0.096218705, -0.16306408, -0.02198454, -0.010134957, -0.09710009, 0.002062143, -0.046785697, 0.0029441968) * go_1(1.0, -1.0);
|
||||
result += mat4(0.19648251, -0.015663045, -0.0730215, 0.028611008, 0.13529862, -0.015256192, -0.04119306, -0.24628192, 0.02601027, -0.21184283, -0.1962902, 0.09109358, -0.06792383, 0.092336476, 0.12215351, -0.08596062) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.17530201, -0.0351919, -0.31872514, -0.13933206, -0.07000922, -0.049807087, 0.0010997375, -0.033573963, 0.07442056, -0.33290103, -0.40381998, 0.09435, -0.3280128, -0.09953127, -0.11283648, 0.20685865) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.052573867, -0.035328753, -0.11132943, -0.17515652, 0.05021051, 0.058642425, -0.046640664, 0.0799107, -0.027398815, -0.33619994, -0.22135767, 0.07894002, -0.14941697, -0.0940996, -0.11655085, 0.049795926) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.039301276, 0.041062318, 0.20312686, -0.009338705, 0.013706282, -0.0245852, 0.03458311, 0.09601228, -0.18203016, -0.012260314, 0.17984508, -0.056576703, -0.102844186, 0.24047872, 0.05307189, 0.16066082) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.1478775, 0.0046362123, 0.05459521, 0.07162838, -0.01896149, 0.23700175, -0.14174299, 0.06988599, -0.32545477, -0.08065096, -0.061227743, -0.0010796773, 0.094327345, -0.20760082, -0.19523263, 0.19859222) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.049676366, -0.10381536, 0.02546116, -0.13127093, 0.10954914, 0.0048147943, 0.06962328, -0.30456528, -0.11956627, 0.0150488885, -0.10711722, 0.1684613, -0.1939089, -0.10577047, -0.11980919, -0.036988296) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.054795764, 0.09491116, -0.08494948, 0.059765853, 0.0131597435, 0.20786162, 0.11999637, 0.024381055, 0.22830428, 0.027053319, -0.011646274, -0.12145409, -0.07899559, -0.012688263, 0.10684157, 0.3824219) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.23994572, -0.0031532666, -0.0050638164, 0.14236279, 0.05690383, -0.06259682, 0.052624144, 0.20461404, -0.19230312, -0.11072268, 0.013023965, 0.08931543, -0.21997221, 0.11760443, -0.40943825, 0.28656834) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.06606179, 0.26007771, 0.033754125, 0.119690455, 0.024669139, -0.06752839, 0.12688096, -0.0063201943, -0.17123021, 0.07548857, -0.14213699, 0.034093797, -0.15632647, -0.123243414, -0.42634043, 0.1715022) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.046503466, 0.13876389, 0.17973013, -0.25938338, -0.18824704, -0.11876702, 0.31065792, -0.041042212, -0.061369427, 0.2057992, 0.17295738, 0.3836555, -0.21109799, -0.10167118, 0.16577047, 0.113483034) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.24534856, -0.014482421, 0.22515748, -0.12773542, 0.12794174, -0.02528619, 0.41710484, 0.09154934, -0.17805946, -0.25428918, 0.07294183, 0.047079418, -0.30949152, -0.08919157, 0.17888431, 0.17706038) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.1741826, 0.046225294, -0.10761791, 0.2619953, 0.007373745, 0.05104337, -0.22309966, 0.34529984, -0.034363825, -0.022187237, -0.08609555, 0.16842419, 0.28136057, 0.17843607, -0.11307746, -0.05668021) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.12310616, -0.29661375, -0.10581025, -0.049584012, 0.19651765, 0.08436489, -0.14533581, -0.029874112, -0.15422897, -0.062741704, -0.22694711, -0.15547274, -0.15181333, 0.0286061, 0.022438493, -0.062447168) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.3497046, -0.09455009, 0.060618952, -0.2134236, 0.054515295, 0.07451165, -0.09267233, -0.010513333, 0.13842636, 0.11563433, -0.054750167, 0.050432, 0.1514256, 0.04284002, -0.2095581, 0.07907657) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.11745651, -0.04717057, 0.085377194, -0.065956995, 0.07280491, 0.2730059, 0.11088276, 0.2437957, 0.14018989, 0.1164107, -0.09516929, 0.0022427947, 0.111544006, -0.0680495, 0.09324579, -0.12482022) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.07995795, -0.03387884, 0.019846136, 0.10231208, -0.07017192, 0.18659039, 0.035161644, 0.101182766, -0.14901665, 0.21307294, 0.063894205, -0.27546507, -0.24792959, -0.067731075, 0.13146006, -0.19333683) * go_3(0.0, 0.0);
|
||||
result += mat4(0.034206454, 0.1472648, -0.07406727, 0.014654025, 0.18703444, 0.1319857, -0.10610886, 0.08427947, -0.017536618, -0.06487879, -0.12095286, -0.050414838, 0.03260879, 0.1558894, -0.031887084, 0.11840288) * go_3(0.0, 1.0);
|
||||
result += mat4(0.114811294, -0.14574333, -0.09392587, 0.042283528, 0.08919092, 0.18259068, 0.0980717, 0.21024778, -0.1280008, -0.027260462, -0.1129027, 0.18722472, 0.13733985, 0.047153983, 0.030871978, 0.1998385) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.06783575, 0.004612595, 0.1153467, -0.11531557, -0.048889533, 0.07673577, -0.02041786, 0.22744459, -0.13092506, 0.13484807, 0.40003043, -0.053706612, -0.16985156, -0.04791236, -0.052443005, -0.08363625) * go_3(1.0, 0.0);
|
||||
result += mat4(0.18187882, 0.017893985, 0.17856054, 0.005413129, 0.014147176, 0.15102178, 0.12436294, -0.02176765, -0.16727823, -0.0364111, 0.17074408, 0.12899421, 0.31984514, -0.0072070034, 0.031895883, -0.1991405) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.011865144, 0.11717201, -0.13823777, -0.059450272);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!SAVE conv2d_6_tf
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.082203194, 0.021720003, 0.03725474, -0.08048348, 0.2063248, -0.033020593, -0.17585336, 0.06476272, 0.012244563, 0.026554609, 0.014708393, 0.26606125, 0.14248778, 0.12817341, -0.039826933, -0.12751861) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.24573852, 0.19695967, -0.06257417, -0.04782871, 0.3511875, -0.018083302, -0.077342674, 0.15247667, 0.20321761, -0.07479984, -0.09548503, 0.08109568, -0.23808748, 0.07246303, -0.004242619, 0.16162953) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.13296306, 0.19495387, 0.009222276, 0.033592198, 0.20443891, 0.16063854, -0.2581601, -0.016132578, -0.2296461, -0.23647323, -0.15407176, -0.18265317, 0.2343241, -0.049697313, -0.09398783, 0.41931856) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.10866088, -0.40605694, -0.0042648134, 0.07943803, 0.26914695, 0.14816476, 0.037706107, -0.123223364, -0.19962949, -0.053534556, -0.08397409, -0.04244924, -0.075791344, 0.29629225, 0.2311928, 0.099177904) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.1748319, -0.2003186, -0.32659066, -0.21007413, 0.20122464, 0.032196607, -0.026299698, 0.33395135, 0.11411664, 0.05971959, 0.09001304, -0.15936212, 0.012322024, 0.19936106, -0.411186, -0.08319479) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.07349218, 0.006184436, 0.096199185, -0.050186496, 0.064047046, -0.03813128, -0.057007037, -0.025550695, -0.2863145, -0.008512981, -0.20615962, 0.18009211, 0.008298396, 0.22452813, 0.010843521, 0.20169461) * go_0(0.0, 1.0);
|
||||
result += mat4(0.2691149, 0.059546687, 0.08922005, 0.2252196, 0.30341956, -0.024489028, 0.087045394, -0.03856442, -0.14083561, -0.17683443, 0.14137806, 0.15520614, 0.2073925, -0.19525874, 0.23661858, 0.3098405) * go_0(1.0, -1.0);
|
||||
result += mat4(0.006530723, 0.04180736, -0.04762067, -0.064395495, 0.02396811, -0.13332283, 0.0037775645, 0.026309434, 0.0033065109, -0.08315753, 0.02917419, 0.12330464, 0.22819455, -0.07489677, 0.12829056, -0.097994626) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.09983759, 0.032783493, 0.11085758, 0.08993078, -0.057110567, -0.018973934, -0.14946178, -0.03921629, 0.039757587, 0.015860094, 0.04989561, -0.19634786, 0.04351146, 0.019315343, 0.25972188, 0.17989321) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.04111906, -0.165601, 0.0003682197, -0.056232415, -0.32716644, -0.24015541, -0.057547837, 0.05966729, 0.06854747, 0.03599213, -0.18798864, 0.1183447, 0.014268468, -0.1310834, 0.06415977, -0.19414157) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.00070661673, 0.17671427, 0.10584568, -0.060910843, -0.104282066, -0.22676118, -0.01907062, 0.24882245, -0.043454725, 0.07691623, -0.48371696, 0.013537671, -0.025488405, 0.061228953, 0.18548754, 0.028671112) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.0121596735, 0.09595702, -0.08244918, -0.1176173, 0.26773354, -0.021729136, 0.075465776, -0.0928876, 0.12461298, 0.16830076, -0.15302569, 0.113850676, 0.09811088, 0.13006307, 0.24999009, 0.10261325) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.032246377, 0.038265374, -0.26476422, -0.1442876, -0.19866082, 0.08649541, 0.041478764, 0.11155026, 0.21576422, -0.09572912, -0.11174068, -0.19722937, -0.15801935, 0.29604745, -0.08606268, -0.15532136) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.06315591, 0.16151646, -0.009230362, -0.04341246, 0.09085519, 0.21924476, 0.38044852, 0.193819, 0.16622902, 0.0025134624, -0.22688466, -0.025276015, 0.07714917, 0.16302192, -0.11767101, -0.11086476) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.04170153, 0.001859292, -0.26352355, 0.10982333, -0.031867817, 0.15773517, -0.060263418, 0.11117763, -0.017359972, 0.0127261225, 0.0782802, -0.16908924, 0.080516845, -0.05691526, -0.07530135, -0.14553802) * go_1(0.0, 1.0);
|
||||
result += mat4(0.06112685, -0.032287434, 0.17445667, -0.044935808, -0.11449107, -0.051394563, -0.029589338, -0.14555557, 0.03440661, 0.11035615, -0.17175, -0.14851089, 0.037362, -0.18740481, 0.17278154, 0.18073405) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.27670652, 0.19484822, 0.2609349, 0.1455016, 0.04438468, 0.1449185, 0.11185832, -0.18598269, -0.019846648, 0.11886126, -0.098498635, 0.15737785, 0.011406795, -0.18860829, -0.13705735, 0.17535745) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.30244905, -0.28695273, 0.1146976, 0.21144345, -0.037980128, -0.027679864, -0.13992494, -0.04884521, -0.032023884, -0.07921183, -0.16042095, -0.06935386, -0.06570237, -0.1107404, -0.018163798, 0.22625941) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.07292955, -0.07321777, -0.045146503, -0.33291966, -0.096732594, -0.07203495, 0.33692798, 0.2870733, 0.122160144, -0.076574564, 0.042844944, 0.26448342, 0.07672146, -0.028775277, -0.12088313, 0.15583947) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.21589327, 0.05258274, 0.09705794, -0.024653846, -0.039402515, 0.28485695, 0.14711736, -0.10556087, -0.15140481, 0.09039498, 0.017308712, 0.11862922, 0.08230978, 0.21678248, -0.043815188, -0.226433) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.029258793, 0.26618922, 0.02564014, -0.23189862, -0.24074338, -0.18556763, 0.25973624, 0.04746873, 0.0137007125, -0.22239363, -0.12414957, 0.048228756, -0.22406264, 0.282667, -0.021001073, -0.17465611) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.32401654, -0.1495363, -0.20869227, 0.04271639, -0.0087802755, 0.031325378, 0.23834595, 0.039336167, 0.17265107, 0.20947595, 0.28737286, 0.0028783784, -0.057340365, -0.050347418, -0.11915604, -0.1831807) * go_2(0.0, -1.0);
|
||||
result += mat4(0.1811338, 0.07732653, 0.20975596, -0.47129005, 0.07121942, 0.08410583, 0.44170937, -0.19524159, -0.17807977, 0.12837476, 0.20816846, -0.1741958, -0.04411918, 0.06024972, 0.18159702, -0.052485272) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.15229738, 0.27513, 0.28150418, -0.19543962, -0.02045864, -0.07207227, 0.09589587, 0.09110817, 0.061413247, 0.0046052113, 0.11619411, -0.2988938, 0.065739445, 0.10205611, 0.12847126, -0.028355654) * go_2(0.0, 1.0);
|
||||
result += mat4(0.0657154, -0.047568597, -0.16148911, 0.16392621, -0.25281775, -0.061153214, 0.017480455, -0.026288848, 0.20319715, 0.04763355, 0.010444491, -0.26671803, -0.25821987, 0.32863674, -0.30734694, -0.18190521) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.042703815, 0.06633036, -0.048434302, -0.17176376, -0.12699759, -0.1124558, 0.083266065, 0.03354623, -0.13468939, 0.12706263, 0.053659134, -0.06930602, 0.008196115, 0.2034998, -0.06351442, -0.039730288) * go_2(1.0, 0.0);
|
||||
result += mat4(0.09614661, 0.22500272, 0.088511504, -0.16960482, 0.15364788, -0.18854137, -0.13163191, -0.07503735, -0.23177068, -0.0053305267, -0.041978605, 0.0971947, -0.049034655, 0.04486706, 0.09076307, -0.02310868) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.1304683, 0.17743458, -0.09817326, -0.0646786, 0.07886976, 0.20109388, -0.034114968, -0.2029261, -0.03348398, 0.029337432, -0.07302782, -0.02240758, 0.030242773, -0.30032325, 0.02085572, -0.027314361) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.037377544, 0.026350772, -0.07430488, -0.114671774, -0.126935, -0.046512567, -0.033628833, -0.19018382, -0.041053895, -0.031206857, 0.08562848, -0.01875709, 0.21099389, -0.092511, 0.0073047103, -0.009811013) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.11358029, 0.17468451, -0.12739041, -0.14332245, -0.22230148, 0.16862972, -0.04462456, 0.2469604, -0.008622369, 0.0081848325, -0.17032363, -0.16024362, 0.21178265, 0.037127133, 0.08559072, 0.11584694) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.008993893, -0.08037705, 0.4426555, 0.15593371, 0.15273719, -0.03249998, 0.055109, -0.1512612, -0.037183985, 0.20825677, -0.08516227, -0.06664223, -0.10011001, -0.3505215, -0.17941694, 0.052089088) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.109703645, -0.13505603, 0.1336451, 0.13118869, 0.010915504, 0.12748592, 0.21201555, -0.40841985, -0.11059143, 0.033772044, -0.039282143, 0.03095394, 0.10394723, -0.21343367, -0.10699851, -0.028351074) * go_3(0.0, 0.0);
|
||||
result += mat4(0.019704714, 0.06243651, 0.09896519, -0.17492259, 0.012675787, -0.004239029, 0.21319824, 0.069183126, -0.0071114586, 0.123431124, -0.24479835, 0.00723795, -0.045293927, 0.014101029, 0.15746681, 0.042405806) * go_3(0.0, 1.0);
|
||||
result += mat4(0.023828225, -0.0015190929, 0.1194638, 0.082163885, 0.10532113, 0.042044062, 0.02528007, 0.015175004, 0.026613194, 0.33525538, -0.1627064, -0.29887968, -0.197707, 0.038967777, -0.15811683, -0.106895216) * go_3(1.0, -1.0);
|
||||
result += mat4(0.044362027, -0.04946742, -0.14815849, -0.17660522, -0.034201477, -0.012243106, -0.050183997, 0.06407372, 0.039822515, 0.15880872, -0.0672721, -0.4081093, 0.019489579, -0.060278706, -0.015096743, -0.07799167) * go_3(1.0, 0.0);
|
||||
result += mat4(0.11861756, 0.27113584, -0.14107186, -0.10246008, -0.124051, -0.1627854, 0.10698585, 0.2846401, -0.061731786, 0.1724438, -0.12428688, -0.09986041, -0.034171514, -0.07100923, 0.041739646, -0.11308375) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.02981662, -0.26338395, -0.011632586, 0.15063232);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!SAVE conv2d_6_tf1
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.17082009, 0.031344634, -0.06131912, 0.00887183, -0.01528174, 0.12943709, 0.24537678, 0.008178781, -0.312396, -0.023583878, 0.07827866, -0.1231261, 0.15081584, -0.18161978, -0.25179705, -0.036934935) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.05768411, 0.16785417, -0.1788644, -0.0067257965, 0.021445744, 0.10066516, -0.23864186, 0.1450302, 0.12892793, 0.19856106, -0.24444748, 0.16531628, -0.044425935, -0.02775357, 0.009059946, -0.12958384) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.025798557, -0.17238182, -0.34056288, -0.20921059, -0.03576266, 0.1476854, -0.06264234, 0.14452787, -0.04130045, -0.07275762, 0.034578666, 0.2914669, 0.20879944, 0.21359251, -0.048695553, 0.2638088) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.022791177, 0.4204545, 0.116855636, 0.20241925, -0.010444933, -0.14462502, 0.022550104, -0.24423064, -0.09417524, 0.045358784, -0.11405829, 0.035979558, -0.2283092, -0.06670842, -0.23852053, -0.22417003) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.14526704, 0.040880535, 0.14076385, 0.07795045, -0.059177604, -0.13056375, -0.3373641, -0.19344307, -0.29891858, -0.32578763, -0.29061425, 0.1562214, -0.13578376, 0.36586633, 0.24936736, 0.054629393) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.025790233, -0.13020341, -0.10084969, 0.15767297, -0.09738769, 0.04034404, 0.0038675873, 0.043515608, 0.16899958, -0.29117966, 0.03420067, 0.14432564, -0.10473084, 0.21014084, 0.07775908, -0.09303797) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.07443987, -0.16225167, 0.036251917, 0.028432872, 0.03759333, 0.004027401, -0.033941846, 0.0019474924, 0.02357054, 0.30748722, 0.1652115, -0.17361522, 0.16905582, 0.08048018, -0.23639561, -0.029408466) * go_0(1.0, -1.0);
|
||||
result += mat4(0.0461233, -0.09346199, -0.07063276, -0.19447634, -0.049339604, -0.0032855074, -0.22661209, -0.0543389, 0.11924857, -0.21691081, -0.1645725, -0.0075736847, 0.018572787, -0.06552861, -0.01777661, -0.11651732) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.06425901, 0.123392984, -0.16395192, -0.093448035, -0.029316641, 0.0986573, -0.23135012, 0.011170849, 0.00023920486, 0.15296175, 0.35453254, -0.05189021, 0.20708887, -0.103900835, 0.081992395, -0.21829562) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.019074136, -0.1572586, 0.27919227, 0.09119617, 0.035954695, 0.2941489, 0.18262725, -0.055522963, -0.21364328, -0.1573611, 0.104966134, 0.08228523, 0.19945285, -0.0039229114, -0.1565048, 0.028975379) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.18501253, 0.006473006, 0.06637501, 0.04295065, 0.06411007, 0.1166344, -0.10060226, 0.46296063, -0.08600344, -0.03560105, 0.012215349, 0.017885283, 0.061346993, 0.17336361, 0.01935021, 0.20198092) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.04451627, -0.10372061, -0.13968691, 0.14479733, 0.1660607, 0.19334625, 0.0085214665, 0.28863636, -0.07600901, -0.014777084, 0.13209191, -0.09045013, 0.104893915, -0.04776884, -0.007936376, 0.104568765) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.023751335, -0.108048, -0.050531313, 0.15916029, 0.13246661, 0.04644228, -0.09586482, -0.17222965, -0.22898191, -0.033484615, 0.078883134, -0.052609313, -0.2721741, 0.045986425, 0.13972299, -0.28923607) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.23364568, -0.008875902, -0.40894926, 0.060443908, -0.2839635, -0.5270991, -0.2500865, 0.002020195, -0.24488612, -0.04982319, -0.009110353, -0.018023955, 0.06647274, -0.25225738, 0.26154432, -0.033934146) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.1535129, -0.21257545, -0.16553773, 0.17471452, -0.06203719, 0.15238857, 0.18702018, 0.18572305, 0.07740396, -0.074217625, -0.072156586, -0.2183728, 0.00403749, 0.13750519, 0.30362993, 0.06550286) * go_1(0.0, 1.0);
|
||||
result += mat4(0.37164542, -0.1980723, -0.15659203, 0.19498909, 0.01748114, 0.011807152, -0.05424202, 0.11926474, 0.050406165, -0.12925303, -0.020280985, 0.08429331, 0.14769496, -0.077555746, -0.15216178, -0.27070466) * go_1(1.0, -1.0);
|
||||
result += mat4(0.35804263, 0.08539285, -0.14785156, -0.13532467, 0.058254432, 0.20448379, -0.006173341, 0.058168225, -0.21714899, -0.13472849, -0.09392532, -0.12753737, -0.097461835, -0.11419082, 0.09384189, 0.06414768) * go_1(1.0, 0.0);
|
||||
result += mat4(0.023494452, -0.22187226, -0.16694295, 0.0204334, -0.26720086, 0.15916729, 0.3098874, -0.10292057, 0.008854983, 0.13375004, -0.04409455, 0.09286524, 0.095829524, 0.12427317, -0.048659876, 0.18300754) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.119153984, 0.10163183, 0.025017537, -0.40096784, 0.026778705, 0.15821172, -0.19947284, -0.33337715, 0.2952563, 0.16820388, -0.057061996, -0.029319009, -0.12184868, 0.09031512, 0.12028806, 0.021044692) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.086744264, -0.046958666, 0.2130253, -0.46672252, 0.07135636, 0.0100029735, -0.13828261, -0.012365689, -0.11374441, 0.21084632, -0.059631422, -0.013799735, -0.037889663, -0.10701892, -0.09493782, 0.15516634) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.031181194, -0.01535001, 0.029270316, 0.13128386, 0.11838377, -0.17051528, 0.12228499, -0.04841128, 0.33350074, -0.006144013, -0.09055018, 0.27470216, -0.26665646, -0.08703671, -0.01719071, -0.23449609) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.12856458, 0.005562174, -0.19517267, 0.13270985, 0.2776414, 0.032003902, -0.15778573, 0.15344355, 0.26930434, -0.13459459, 0.035019353, 0.08896612, 0.12847935, -0.122637205, 0.001815178, 0.08290523) * go_2(0.0, -1.0);
|
||||
result += mat4(0.33805037, -0.15318587, -0.20955376, -0.26121393, -0.026022578, -0.1617741, 0.1336867, 0.026223289, 0.012059392, -0.17295446, -0.060811974, 0.14027825, -0.21134059, -0.08408573, -0.23773228, 0.110836074) * go_2(0.0, 0.0);
|
||||
result += mat4(0.16176093, 0.15307428, -0.07711325, -0.3458805, 0.061291527, 0.023916256, 0.21370678, 0.0015756418, 0.10642374, 0.24807373, 0.11164451, 0.10780487, 0.087194376, -0.2718231, -0.008457387, 0.054078236) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.03259038, -0.20923306, 0.165477, 0.098864526, -0.02734457, 0.08871225, -0.01552188, 0.047712058, 0.055032052, -0.13044262, -0.2899521, 0.22230095, -0.029343741, -0.16427459, -0.005436118, -0.05111821) * go_2(1.0, -1.0);
|
||||
result += mat4(0.20065974, -0.1556366, -0.12620135, 0.44572976, -0.020925352, 0.12025185, 0.20588058, 0.06391864, 0.046870507, 0.16942503, -0.049370963, 0.008779016, 0.04954915, 0.090298936, -0.16466027, 0.011152038) * go_2(1.0, 0.0);
|
||||
result += mat4(0.13587528, 0.047841422, 0.19804007, -0.1672396, -0.072491, 0.04543739, 0.25287256, 0.015226213, 0.02007356, -0.049578942, -0.08796175, 0.1714897, -0.07819061, 0.1509537, 0.093094915, 0.031139288) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.013774682, 0.118201815, -0.009592314, -0.10837201, -0.0686881, -0.083380274, 0.107689425, 0.046642892, 0.119898744, -0.05502989, -0.19719897, 0.0005697584, -0.0921928, 0.032281205, 0.2568853, 0.2325449) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.02991112, -0.09898633, 0.06076172, -0.20906185, 0.0026118348, 0.06130956, 0.06760944, -0.16662054, 0.065741204, -0.13144116, 0.011419801, 0.22552124, 0.1465757, -0.07417319, -0.10788749, -0.24952699) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.19238451, -0.024058497, 0.19580396, -0.067399554, -0.18832864, -0.11752747, -0.078949094, -0.23762032, -0.04141864, 0.022530237, -0.02222157, 0.0054874527, 0.057746816, -0.34854797, 0.028730657, -0.08976777) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.16888975, 0.19949849, -0.08456147, -0.03619044, -0.019596824, 0.11214634, 0.13971676, 0.22926724, 0.03219445, -0.04566354, -0.14948955, -0.22817011, -0.08714846, -0.19684613, 0.15479128, 0.2433362) * go_3(0.0, -1.0);
|
||||
result += mat4(0.16050309, -0.102841675, 0.20855242, -0.011171905, -0.10309409, 0.22455123, 0.15892951, -0.06582373, 0.010079549, -0.2055006, -0.09385158, 0.006519388, 0.11838815, 0.37134558, -0.165772, 0.12704434) * go_3(0.0, 0.0);
|
||||
result += mat4(0.11643292, 0.03294274, -0.09800525, -0.13601723, -0.081318736, -0.059975546, -0.039105035, -0.2893635, -0.13024913, -0.058016162, -0.09961072, 0.10532414, 0.24250132, -0.35546342, -0.092634924, 0.093994915) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.18799333, 0.25611782, 0.014645917, -0.063751906, 0.06498416, 0.16619027, -0.14411639, 0.3914421, -0.07343631, -0.116468735, -0.10941946, -0.2553544, -0.37774643, -0.0018441634, 0.06827239, -0.0122299045) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.11884597, -0.2477297, 0.048488285, -0.06438257, -0.124703035, 0.25932777, 0.0650111, -0.0930877, 0.06463341, -0.000544085, 0.0147504965, -0.170097, -0.13241997, 0.20983136, -0.15956205, 0.03424298) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.034574904, 0.06755256, 0.09508443, -0.17162292, 0.046379335, 0.2178781, 0.08699012, -0.055380464, -0.2237568, -0.07427848, -0.028395249, -0.3225617, -0.084454566, -0.24776657, 0.254169, 0.13229847) * go_3(1.0, 1.0);
|
||||
result += vec4(0.18765923, -0.07697714, 0.028134674, -0.060966115);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!SAVE conv2d_7_tf
|
||||
//!WIDTH conv2d_6_tf.w
|
||||
//!HEIGHT conv2d_6_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_6_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_6_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_6_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_6_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.21919365, 0.36627784, 0.12603314, 0.24306288, 0.06447028, 0.06472204, -0.05997039, -0.15651788, 0.017059859, -0.006497198, -0.4189735, 0.021636713, -0.23887977, -0.014220949, 0.031113686, -0.17342716) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.10818789, -0.03273837, 0.33918005, -0.19290088, 0.0955361, -0.34107623, -0.054906327, -0.18083344, -0.060723677, 0.24395694, 0.112975016, -0.07254578, -0.14389384, 0.13235968, -0.15054801, -0.26216486) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.23442148, -0.07857079, 0.022283873, -0.2656417, 0.037092753, -0.037313666, -0.5057047, 0.042533103, -0.120424, 0.00021930189, -0.0044566668, -0.45536995, 0.00040759926, 0.14597592, -0.094990164, -0.036161344) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.15024352, 0.19903262, -0.0734784, 0.092836305, -0.025753846, 0.024750374, -0.07550193, 0.035420835, 0.11084378, 0.26119822, -0.08443512, -0.0047807065, -0.042685136, 0.24889739, 0.098650105, 0.2088369) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.25551823, 0.14455976, 0.19886157, -0.23465924, 0.20711218, -0.20875362, -0.11320392, -0.30852005, -0.06795657, 0.008670962, 0.30601278, 0.6929064, 0.17079145, 0.15744895, 0.06441601, 0.06514001) * go_0(0.0, 0.0);
|
||||
result += mat4(0.03142604, -0.006410137, -0.023654792, -0.05708553, 0.062985405, -0.077010594, 0.078804865, 0.050882503, 0.010274228, -0.15558401, 0.09490256, 0.14964707, -0.11966925, -0.36176664, 0.27809814, -0.18862294) * go_0(0.0, 1.0);
|
||||
result += mat4(0.05609992, 0.0041612233, -0.08498908, 0.04479823, -0.080117956, -0.17423204, -0.22858045, 0.054569032, -0.050866384, -0.020000307, 0.027000953, -0.67724514, 0.16240878, -0.04641204, 0.0648367, -0.20613132) * go_0(1.0, -1.0);
|
||||
result += mat4(0.08542306, -0.08254248, -0.11090553, -0.14140448, -0.10788511, -0.13011602, -0.29319742, -0.26007155, 0.11033401, -0.31966573, 0.32668245, 0.19542319, 0.06329418, 0.20904626, 0.2724067, -0.009155685) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.007403411, 0.0012836396, -0.23446666, -0.03017208, 0.062420018, -0.13611084, -0.2975928, 0.13173148, -0.03679939, 0.13743873, -0.10121899, 0.074514665, 0.1497629, -0.09523838, 0.39018926, 0.37807035) * go_0(1.0, 1.0);
|
||||
result += mat4(0.11441487, -0.19565523, -0.25757137, -0.16148767, 0.15575317, -0.12657928, 0.10479676, 0.062919036, 0.010544159, 0.22931573, 0.20360178, 0.4637635, -0.3395036, -0.52467215, 0.08759308, 0.028030418) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.2699195, -0.34218305, 0.15259695, 0.03139074, -0.024053533, -0.029567484, 0.28480124, 0.20525953, 0.15452823, -0.217713, 0.15861876, -0.012275699, 0.21408023, 0.097508304, -0.57126766, -0.14679857) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.0755847, -0.09751562, -0.29480466, -0.22285318, 0.14196442, 0.114573136, -0.22294767, 0.12463806, 0.3322209, -0.04631724, -0.11097061, -0.27986854, -0.16099304, -0.060079545, 0.00299308, 0.120776065) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.050933484, -0.13776319, -0.18809728, 0.24035202, -0.32528606, -0.41684148, -0.029342847, 0.28642926, -0.07963454, -0.12905268, 0.07606093, 0.24670005, -0.08815598, -0.23320907, -0.008099349, 0.21512873) * go_1(0.0, -1.0);
|
||||
result += mat4(0.19247563, 0.18083979, -0.09719762, 0.15314941, -0.22350982, 0.46515045, -0.3571128, 0.35953265, 0.06921985, -0.4482386, -0.18732521, -0.5043983, 0.35159567, -0.33315298, -0.21884166, -0.16283798) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.021124054, -0.007966742, 0.0052493825, 0.022550896, 0.030403977, 0.3377868, -0.47602004, -0.077664234, -0.07222509, -0.07486097, -0.37971064, -0.5107857, -0.06299477, 0.04930232, -0.3330487, 0.29845512) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.063705474, -0.07917637, -0.02026607, -0.05142568, 0.021577014, -0.07379867, 0.033937998, 0.08148773, -0.02717838, -0.03233838, 0.098000035, 0.036476444, -0.13366953, 0.014477577, 0.24064232, 0.39313284) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.16046515, -0.094624564, 0.35435164, 0.09942324, -0.07137174, -0.27999225, 0.124644354, -0.0062176553, 0.015016751, -0.05500243, -0.23249559, -0.4508382, 0.1860433, 0.10671491, -0.033345353, -0.06611453) * go_1(1.0, 0.0);
|
||||
result += mat4(0.21614046, -0.01307525, -0.18941112, -0.20533535, -0.14481686, -0.47801897, 0.22605121, -0.20298961, -0.06744227, -0.20377496, -0.11926173, 0.15645133, -0.31570885, -0.3495616, -0.024666889, 0.040965475) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.11748018, -0.039976366, -0.00084064255, -0.028653437, -0.16216733, -0.036768105, 0.018064514, -0.0928936, 0.14008482, -0.064511225, 0.24329947, -0.0268608, 0.050330248, 0.08540601, -0.07272679, -0.01187671) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.09459936, -0.011723822, -0.06952858, -0.07808506, -0.065588176, 0.332501, -0.0120042395, 0.07668016, 0.14735217, -0.14856043, -0.06702449, -0.020953184, -0.023006834, 0.06135422, 0.1491448, -0.028061569) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.25136968, 0.25146323, -0.108277924, -0.20407207, -0.0013780294, 0.16108194, 0.25143847, 0.06672421, -0.033905584, -0.021144686, -0.019152718, 0.34619498, 0.14560962, 0.034437314, 0.024790365, -0.049976267) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.24928351, 0.12637813, 0.23609994, 0.12722939, -0.036997862, -0.16554876, 0.11144095, -0.10040036, -0.020359103, -0.080701865, -0.3142192, 0.27257237, 0.13546956, -0.14416885, 0.028196262, -0.2886465) * go_2(0.0, -1.0);
|
||||
result += mat4(0.28524777, -0.4236231, 0.27420738, -0.21095508, 0.23475651, 0.115876295, -0.18837357, -0.0260708, 0.030670704, -0.11516913, -0.11365572, -0.2203149, -0.018612983, -0.10719593, -0.031727783, 0.1403327) * go_2(0.0, 0.0);
|
||||
result += mat4(0.07240512, 0.03139215, 0.12328737, -0.021201206, -0.13971715, 0.072742075, -0.0011289873, 0.0053133667, 0.035639685, -0.04322272, -0.19288473, -0.15812221, -0.19126481, 0.0698514, 0.17619178, -0.035605464) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.18552057, 0.07259671, 0.011667668, -0.15630563, 0.11414356, 0.14482655, -0.04021029, 0.18495587, -0.11386139, -0.09058561, -0.011265998, 0.23358451, 0.0521358, 0.12495261, 0.021644838, -0.048094347) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.09222373, 0.0533347, 0.055820454, 0.22382596, 0.18713981, 0.2668916, -0.019384036, 0.012698582, 0.13325234, 0.20361474, -0.33106443, -0.08571572, -0.21243028, -0.10996386, 0.123459645, 0.1534967) * go_2(1.0, 0.0);
|
||||
result += mat4(0.18133277, 0.18108074, -0.05638664, 0.29533157, -0.2108019, -0.033636626, 0.5015888, -0.15116066, -0.041320793, -0.14764231, 0.07314567, -0.18865979, 0.10276937, 0.094240844, -0.1364283, 0.27812913) * go_2(1.0, 1.0);
|
||||
result += mat4(0.06040915, 0.23753685, 0.19019844, 0.23948252, -0.07535012, 0.11848904, 0.14389765, 0.050067905, 0.16150077, -0.030053454, 0.12478255, 0.26020208, 0.111198805, 0.06787492, -0.12771018, 0.006687384) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.5421617, 0.10414128, -0.21526064, -0.08883624, 0.13145073, -0.29695904, 0.57386386, 0.073361695, -0.09538372, 0.27593842, 0.070922814, 0.21769938, 0.06214975, 0.11847816, 0.10033405, 0.29360098) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.16294672, -0.014815565, 0.22046989, 0.16858687, 0.058917344, 0.21384977, 0.18803519, 0.105688855, 0.0355118, 0.20571202, -0.07341922, 0.26624045, -0.0415102, 0.050942056, 0.19727907, 0.20122413) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.020470422, 0.15815964, -0.13437317, -0.1967045, 0.074902646, 0.08356444, 0.055913117, -0.12837863, -0.18647918, 0.07002247, 0.038864706, -0.07288784, 0.04135125, -0.016055549, -0.1340297, -0.15578008) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.07685624, 0.00079105416, -0.068755336, 0.110282525, -0.014170752, 0.041282844, -0.17035173, 0.19439398, -0.3036256, 0.024148455, -0.19566648, -0.06736254, 0.14203559, -0.13016985, -0.32845357, -0.14266774) * go_3(0.0, 0.0);
|
||||
result += mat4(0.0087252045, 0.098839566, -0.08770506, -0.08499465, 0.015245115, -0.110854514, 0.054458305, -0.018121868, -0.09666134, -0.08316006, 0.24617113, -0.17195955, 0.2574254, 0.06734342, -0.13792352, -0.07306126) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.0073954533, -0.20126835, -0.22545357, -0.29462856, 0.057408337, 0.11939119, -0.01846476, 0.12534486, 0.15751605, -0.14282645, -0.14219986, 0.14283386, 0.14090413, 0.10500912, 0.03039335, 0.17448832) * go_3(1.0, -1.0);
|
||||
result += mat4(0.043910783, -0.09140025, -0.21666165, 0.07616939, 0.104454786, 0.309926, -0.12906921, 0.1140117, 0.09372434, 0.049547072, -0.086615674, -0.034449168, 0.096705064, 0.26001686, 0.027063297, 0.12422948) * go_3(1.0, 0.0);
|
||||
result += mat4(0.1365422, 0.2679611, 0.12037257, 0.43346113, 0.08223084, -0.016788265, 0.13570398, -0.017974345, -0.17922844, -0.09475725, 0.073539585, -0.106947675, 0.08998511, 0.04133868, 0.16586913, -0.26291734) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.19233678, 0.016725872, -0.008011114, -0.1977463);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!SAVE conv2d_7_tf1
|
||||
//!WIDTH conv2d_6_tf.w
|
||||
//!HEIGHT conv2d_6_tf.h
|
||||
//!COMPONENTS 4
|
||||
#define go_0(x_off, y_off) (max((conv2d_6_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_6_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_6_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_6_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.36016628, 0.019064043, 0.3073228, 0.16891135, 0.026739368, 0.31136194, 0.11260383, -0.26918694, 0.0419928, -0.3365078, 0.20189743, -0.04136312, 0.039564647, 0.033199426, 0.18768296, -0.017119858) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.28663483, -0.41716507, 0.059281543, 0.043736435, 0.0028875466, 0.13817391, -0.12543318, -0.2794053, -0.023528943, 0.10610115, 0.09100278, 0.040132936, -0.21949205, -0.027810011, -0.0301218, 0.084047124) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.39674807, -0.0040878756, -0.038235947, 0.11880838, 0.009898328, 0.19107847, -0.009313831, -0.1554276, -0.047341663, 0.18049581, -0.029317195, 0.0708909, 0.0708316, -0.110617444, 0.14584038, -0.022261223) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.20400241, 0.0896492, -0.010386381, -0.052133385, 0.005023956, -0.06628705, -0.16436209, -0.25345984, -0.05285192, 0.09706557, -0.03778914, -0.152546, 0.17023252, 0.063713826, 0.00743037, 0.056634087) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.080793336, 0.4204207, 0.19098237, 0.20028038, -0.054076545, 0.22064368, -0.25853387, -0.3643562, 0.2085573, -0.023731, -0.06727709, -0.18683033, -0.18032159, -0.06388348, 0.304463, -0.2517781) * go_0(0.0, 0.0);
|
||||
result += mat4(0.11940941, 0.10624008, 0.16120581, 0.2369602, 0.3321827, 0.4272075, -0.10403669, -0.31388018, -0.006372124, -0.00653671, 0.109810196, 0.2277172, 0.005771998, 0.086026914, -0.08934813, -0.094941735) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.13233568, 0.24112508, -0.0068006413, 0.12466225, 0.11396591, -0.07249253, -0.29090378, -0.12828146, -0.22001141, -0.08532405, -0.11932601, 0.29452974, 0.09572195, 0.017603843, 0.12454017, 0.16321751) * go_0(1.0, -1.0);
|
||||
result += mat4(0.042107448, -0.00807216, 0.06580674, -0.1289527, 0.13977426, -0.037159685, -0.21001346, -0.08698161, 0.22370502, -0.29170328, 0.2179206, 0.36621302, 0.0825477, -0.016513655, -0.11157249, 0.12861598) * go_0(1.0, 0.0);
|
||||
result += mat4(0.2246826, -0.13262233, 0.12131653, -0.15522355, 0.38104856, 0.030237729, 0.1286289, -0.19770473, -0.16175011, -0.13688888, 0.23505463, 0.21333031, 0.76352316, -0.17949077, -0.13124311, 0.1613879) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.050607495, 0.0846705, -0.06136092, -0.033436477, 0.41138348, 0.037043408, -0.02676336, -0.37771952, 0.22147503, 0.06490757, -0.04266158, -0.22606373, 0.045775007, -0.054498192, -0.21495876, -0.036050417) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.06242522, 0.2700824, -0.05602621, -0.12361551, 0.14477442, 0.19403581, 0.23505251, -0.072234035, -0.15831544, 0.4640447, -0.104754634, -0.004539681, -0.20246096, 0.23216484, -0.35886365, 0.11360777) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.14777757, 0.18951412, 0.027219458, 0.11216015, 0.02997997, -0.13466355, -0.0010830094, 0.021302953, 0.23441231, -0.14529245, 0.08068729, 0.10044398, 0.3972878, 0.26570204, 0.0046810666, -0.2863261) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.10385485, 0.1053724, 0.16961229, 0.20727012, -0.025148917, -0.011365095, 0.03899919, -0.030950211, 0.079080455, -0.32767853, 0.064670205, -0.035771385, 0.16833797, -0.21567492, 0.30871257, -0.19965471) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.23420888, -0.004894698, -0.18162623, -0.31107524, 0.11976508, 0.14924951, -0.08723316, 0.21401922, -0.58200324, -0.01177345, -0.049033508, 0.19593577, -0.21139073, 0.13016601, 0.08734843, 0.4158892) * go_1(0.0, 0.0);
|
||||
result += mat4(0.0009789813, 0.33274913, 0.017405733, -0.042906318, -0.26410276, -0.09291333, 0.019387102, 0.105381854, -0.009176527, 0.09483514, -0.28462934, -0.03644404, 0.285194, -0.4260311, 0.14902237, -0.115670316) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.09344311, 0.4463103, 0.19984834, -0.09733857, -0.118717775, -0.0708026, 0.24919955, -0.11234634, 0.1246395, -0.052909933, 0.1525815, 0.07724016, 0.0070534665, -0.06404165, -0.18149726, -0.014058336) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.17353044, 0.15376104, 0.004588994, -0.13554202, -0.19920237, -0.18918681, 0.11327512, -0.117296435, -0.0785251, 0.013677155, -0.2103214, 0.06843426, -0.27790928, 0.09837545, -0.00019213746, 0.09132539) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.01586651, 0.014929441, 0.2426186, -0.1889374, -0.0865462, -0.07454513, -0.20797268, -0.22366855, 0.19704159, 0.0048206006, -0.16707218, -0.14162683, 0.036798395, -0.1663155, -0.12009389, 0.09603803) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.041532192, 0.05753804, 0.17927068, -0.042112097, 0.12080969, -0.15052572, -0.34855765, -0.07356988, -0.28199884, -0.18958664, 0.15879883, 0.08511588, 0.0034213227, -0.05338495, -0.37285298, 0.06626709) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.20219134, 0.22150375, -0.29405454, 0.06597703, -0.018885285, -0.010551704, -0.010774283, 0.08758955, -0.2015349, -0.17006227, -0.24321876, -0.06864207, -0.118437864, -0.043977212, -0.029736811, 0.14040919) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.18709077, -0.09723938, 0.12783436, -0.15167634, 0.29039705, -0.11009911, 0.018371418, -0.060096707, -0.07256923, -0.25799567, -0.06276934, -0.035992302, -0.06729111, -0.059956793, -0.024079734, 0.011838878) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.010449175, -0.08212451, 0.1409803, 0.11861122, -0.18035835, 0.051930565, 0.01049551, -0.09447962, 0.12029649, 0.040604513, -0.059971705, -0.0044667358, -0.22080486, -0.11187681, 0.124374695, -0.004155485) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.28584236, -0.38480133, -0.13987814, -0.4463469, -0.3890419, -0.022498172, 0.17334452, 0.21895568, -0.15450422, -0.10905497, 0.15111905, -0.22554915, 0.106121585, -0.029144369, 0.36059046, 0.22140682) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.23780307, -0.023033705, 0.068205886, -0.110635854, -0.26720005, -0.1608183, 0.19523881, 0.07972837, -0.018495852, -0.2793956, 0.17668398, -0.12020479, -0.079556085, -0.02284952, 0.031480275, 0.31818348) * go_2(0.0, 1.0);
|
||||
result += mat4(0.22501226, -0.00829407, 0.059581667, 0.16512989, 0.18711442, 0.1200968, 0.11812652, -0.16091056, 0.15733972, 0.045156084, 0.20640492, -0.16852027, -0.11217177, 0.06746273, -0.050218176, 0.08643783) * go_2(1.0, -1.0);
|
||||
result += mat4(0.20715691, -0.1082907, 0.027892975, 0.19515261, -0.17838904, 0.1532257, -0.108409844, -0.06632365, -0.13805026, 0.23020233, 0.12416581, -0.14861803, 0.16650471, 0.08158386, -0.09051303, -0.06981649) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.04617126, 0.06579221, 0.25964734, 0.28500968, 0.07641255, -0.090885855, -0.0972522, 0.18298368, -0.06393334, 0.103463, -0.23062052, -0.15270731, 0.13633437, 0.074707486, 0.15065335, -0.024602572) * go_2(1.0, 1.0);
|
||||
result += mat4(0.118319295, 0.010410938, 0.044655934, -0.104725905, 0.030477569, 0.12867387, 0.039075315, 0.18922117, 0.13301082, -0.1601557, 0.038168408, -0.07372259, -0.09522213, -0.095107146, -0.16679631, 0.044673234) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.46229, -0.30780822, -0.09081465, 0.1433387, -0.0315039, 0.059409115, -0.24948491, -0.17146957, 0.060843736, -0.041989822, 0.054005735, 0.22835566, 0.12036598, -0.0070898845, 0.17276852, -0.17754094) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.35119572, 0.020034311, 0.08751943, 0.08193488, 0.041884877, 0.22649358, -0.07447533, 0.20845473, -0.04859846, -0.16206735, 0.06819576, -0.053000778, 0.18146423, 0.04694148, 0.045293212, 0.06783575) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.280914, -0.14998704, -0.23485807, -0.015608296, 0.1549556, -0.11992663, -0.094974115, 0.05887284, 0.053392075, 0.10322464, -0.075066686, 0.068358354, -0.18663338, 0.009901499, -0.123370335, -0.12502703) * go_3(0.0, -1.0);
|
||||
result += mat4(0.7748568, -0.17870626, -0.20770052, 0.024692526, -0.056430295, -0.06324113, -0.03660047, 0.29629672, -0.51896983, -0.027231261, 0.05903762, 0.077677645, -0.061675485, -0.20277846, 0.10352223, -0.08198446) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.06347568, 0.21643166, -0.09718546, 0.0372257, -0.029537952, -0.0357135, -0.09548363, 0.18225233, -0.29609334, -0.3496132, 0.18245913, -0.10162589, -0.18189451, -0.09077887, 0.117313184, -0.06863874) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.047373574, -0.020289376, -0.25748715, -0.13568166, 0.15656634, -0.06841899, 0.012100781, -0.13611819, 0.0016357322, -0.23870537, 0.14035743, -0.14700134, 0.2535575, -0.13697346, -0.13693139, -0.10365287) * go_3(1.0, -1.0);
|
||||
result += mat4(0.4283934, -0.316192, -0.012617617, 0.018468965, 0.21436644, 0.18408814, -0.42651537, 0.12504087, -0.13894933, 0.091662176, -0.20096369, -0.080727175, -0.005487846, 0.17046383, 0.1383948, -0.0054956395) * go_3(1.0, 0.0);
|
||||
result += mat4(0.20014295, -0.027282396, -0.06317007, 0.04452042, 0.064600386, 0.072222926, -0.33409226, 0.08063831, -0.022607977, 0.1308856, -0.39691743, -0.094889864, -0.1810531, 0.011367248, -0.2531222, -0.22468317) * go_3(1.0, 1.0);
|
||||
result += vec4(0.26886886, 0.05874665, 0.10268232, 0.05833081);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v4.0-Restore-CNN-(VL)-Conv-3x1x1x112
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!BIND conv2d_7_tf
|
||||
//!BIND conv2d_7_tf1
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
#define g_0 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_1 (max((conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_2 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_5 (max((conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_6 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_9 (max((conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_10 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_13 (max((conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_14 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_15 (max(-(conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_16 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_17 (max((conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_18 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_19 (max(-(conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_20 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_21 (max((conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
#define g_22 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_23 (max(-(conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
#define g_24 (max((conv2d_7_tf_tex(conv2d_7_tf_pos)), 0.0))
|
||||
#define g_25 (max((conv2d_7_tf1_tex(conv2d_7_tf1_pos)), 0.0))
|
||||
#define g_26 (max(-(conv2d_7_tf_tex(conv2d_7_tf_pos)), 0.0))
|
||||
#define g_27 (max(-(conv2d_7_tf1_tex(conv2d_7_tf1_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.09689336, 0.06046458, 0.072598994, 0.0, 0.11994565, 0.104477674, 0.09302802, 0.0, -0.05718302, 0.050438102, 0.08814741, 0.0, 0.0308889, 0.0033925986, -0.01715605, 0.0) * g_0;
|
||||
result += mat4(-0.028314235, 0.06597744, 0.0966897, 0.0, 0.035656154, 0.07770106, 0.075551905, 0.0, 0.0001793458, -0.000479495, -0.00297406, 0.0, -0.053916585, -0.016807461, -0.0057141334, 0.0) * g_1;
|
||||
result += mat4(-0.047189303, -0.0207, -0.020910334, 0.0, -0.07933196, -0.06961211, -0.086069845, 0.0, 0.0943727, 0.008463375, 0.010755166, 0.0, 0.062410597, 0.022625161, 0.04068433, 0.0) * g_2;
|
||||
result += mat4(0.10270994, -0.019080428, 0.0050091282, 0.0, -0.004672948, -0.013966742, -0.0063746064, 0.0, -2.5856789e-05, 0.03151499, -0.0023983798, 0.0, 0.113539025, 0.12381699, 0.100360274, 0.0) * g_3;
|
||||
result += mat4(0.07868885, -0.030913834, -0.009213676, 0.0, 0.04870991, 0.021467991, 0.038739506, 0.0, -0.042969644, -0.07122453, -0.08798675, 0.0, -0.09784122, 0.021434791, 0.02510374, 0.0) * g_4;
|
||||
result += mat4(0.050420716, 0.0729716, 0.076532185, 0.0, -0.019112485, -0.01037939, -0.026948035, 0.0, -0.02591423, 0.008927897, -0.00042541025, 0.0, 0.1043701, -0.0071186824, -0.041817162, 0.0) * g_5;
|
||||
result += mat4(-0.16143242, -0.0009298223, -0.01228508, 0.0, 0.07744052, -0.018313263, -0.0488145, 0.0, 0.09241393, 0.07128674, 0.055164956, 0.0, 0.054884013, -0.04834418, -0.06281626, 0.0) * g_6;
|
||||
result += mat4(-0.049036566, -0.05979936, -0.05594288, 0.0, -0.014564307, 0.031926468, 0.037857566, 0.0, 0.015474487, -0.11385003, -0.11527764, 0.0, -0.07076006, 0.057038613, 0.095983796, 0.0) * g_7;
|
||||
result += mat4(0.03094887, -0.008734403, 0.00042712069, 0.0, 0.053891554, 0.05837673, 0.06200635, 0.0, 0.09071558, -0.04202184, -0.046172567, 0.0, -0.0425916, 0.04905093, 0.020835675, 0.0) * g_8;
|
||||
result += mat4(0.096628904, -0.037792254, -0.043241944, 0.0, -0.011923947, -0.025950424, -0.031381752, 0.0, -0.060941868, -0.07859433, -0.07535451, 0.0, -0.026777223, 0.08604982, 0.07829908, 0.0) * g_9;
|
||||
result += mat4(-0.06435972, 0.0036599538, 0.00786578, 0.0, -0.061972067, -0.05681472, -0.06667608, 0.0, -0.106890626, 0.007406496, 0.029977169, 0.0, -0.20519382, -0.044860814, 0.0021225857, 0.0) * g_10;
|
||||
result += mat4(-0.16876474, 0.012789643, 0.026692612, 0.0, 0.017817136, 0.026935097, 0.02227043, 0.0, 0.01690181, 0.07716103, 0.086527, 0.0, 0.07923805, -0.10443151, -0.10859543, 0.0) * g_11;
|
||||
result += mat4(0.003730466, -0.024648283, -0.022169832, 0.0, -0.0062762927, 0.022062732, 0.032966793, 0.0, 0.016349113, 0.017197203, 0.020952817, 0.0, -0.1763789, 0.035497356, 0.053835396, 0.0) * g_12;
|
||||
result += mat4(0.020886675, -0.07054202, -0.079142675, 0.0, 0.06664387, 0.044960167, 0.042230908, 0.0, -0.095019594, 0.012421141, 0.0142890485, 0.0, 0.056814816, -0.012751135, -0.014684506, 0.0) * g_13;
|
||||
result += mat4(0.011765893, 0.0008920681, -0.0018258415, 0.0, -0.010473814, -0.023085753, -0.028783914, 0.0, -0.023034256, -0.0024786016, -0.0052162083, 0.0, 0.1643386, -0.06132718, -0.09289065, 0.0) * g_14;
|
||||
result += mat4(0.016597198, 0.09389637, 0.10833379, 0.0, -0.043163072, -0.04714812, -0.035274632, 0.0, 0.09634976, -0.009292612, -0.022424143, 0.0, -0.08765172, 0.0051558353, 0.010900356, 0.0) * g_15;
|
||||
result += mat4(0.030815786, 0.021069322, 0.01812191, 0.0, 0.084839165, -0.0080813095, -0.029270556, 0.0, -0.10456346, 0.062386703, 0.0665605, 0.0, 0.11926609, -0.1104228, -0.13291118, 0.0) * g_16;
|
||||
result += mat4(-0.07159541, -0.007267032, -0.010134558, 0.0, 0.008234213, 0.045609634, 0.040295456, 0.0, 0.018416971, 0.01308482, 0.014649557, 0.0, 0.035107512, -0.02140815, -0.030279048, 0.0) * g_17;
|
||||
result += mat4(0.01918586, 0.03875863, 0.03229402, 0.0, -0.07917104, 0.041135103, 0.057182517, 0.0, 0.08609541, 0.0079662455, 0.004327576, 0.0, -0.14332893, 0.03120354, 0.056732506, 0.0) * g_18;
|
||||
result += mat4(0.03200192, -0.0035752193, -0.0031064528, 0.0, -0.010902813, 0.014607456, 0.019431474, 0.0, -0.016461229, -0.004938204, -0.004655488, 0.0, -0.033470232, 0.0026075812, 0.005896968, 0.0) * g_19;
|
||||
result += mat4(0.037410006, 0.048742272, 0.04348088, 0.0, 0.037719514, 0.030768529, 0.03127472, 0.0, 0.056426726, 0.03066893, 0.016440205, 0.0, -0.010599352, 0.022832409, 0.023211194, 0.0) * g_20;
|
||||
result += mat4(-0.005733291, 0.06365659, 0.06663611, 0.0, -0.041917093, -0.016493445, -0.020438088, 0.0, -0.0014357592, -0.0022506563, -0.0045095007, 0.0, 0.029893145, -0.009129354, -0.015173116, 0.0) * g_21;
|
||||
result += mat4(0.013052085, 0.005108175, 0.0025906067, 0.0, -0.021950055, -0.036447693, -0.036141638, 0.0, -0.036296472, 0.0068928464, 0.013102313, 0.0, 0.0060471976, -0.024798103, -0.023548538, 0.0) * g_22;
|
||||
result += mat4(0.0067743887, -0.06191211, -0.062355213, 0.0, 0.0016080744, -0.020445071, -0.016840393, 0.0, 0.028264903, 0.01852915, 0.015891539, 0.0, -0.023877412, -0.013271666, -0.008158679, 0.0) * g_23;
|
||||
result += mat4(-0.04317466, -0.018953001, -0.020452993, 0.0, -0.009322576, -0.03022352, -0.030970376, 0.0, 0.05653658, 0.05430553, 0.046692245, 0.0, 0.05615359, 0.059338935, 0.056018773, 0.0) * g_24;
|
||||
result += mat4(0.022878079, 0.03392234, 0.033057988, 0.0, -0.017554542, -0.0141542535, -0.014122613, 0.0, -0.048634093, -0.05316463, -0.047988772, 0.0, -0.058002178, -0.040221967, -0.034025013, 0.0) * g_25;
|
||||
result += mat4(-0.018253656, -0.04197674, -0.040467236, 0.0, -0.04358929, -0.028309818, -0.025425073, 0.0, -0.008488672, -0.001727991, 0.00035808363, 0.0, -0.0011709273, 0.0052514165, 0.0059479307, 0.0) * g_26;
|
||||
result += mat4(-0.08333935, -0.09818201, -0.09476284, 0.0, -0.033692095, -0.046259012, -0.045797516, 0.0, -0.007577072, 0.0022402718, 0.0016200038, 0.0, 0.0029786075, -0.020728534, -0.018938033, 0.0) * g_27;
|
||||
result += vec4(0.047567394, -0.02504617, -0.028163986, 0.0);
|
||||
return result + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(M)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.010995803, 0.077095956, -0.043992598, 0.06048717, 0.1164834, -0.11689607, 0.072985925, -0.078805886, 0.01182932, 0.054985743, -0.09018186, 0.044907484, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.1813623, -0.14752422, 0.025720436, -0.17639883, 0.15697388, 0.10445984, -0.1843076, 0.5264643, 0.047516696, -0.097305484, 0.09740847, -0.29619336, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.014534763, 0.09486465, 0.046173926, 0.039391946, 0.09609376, -0.060574662, 0.042200956, -0.3269777, 0.051006425, 0.059818447, 0.04366627, 0.17699827, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.04268535, -0.08152529, 0.10577459, -0.036936995, -0.051562306, 0.054872766, 0.09194519, 0.0025066638, -0.01073954, 0.00064474024, 0.10038221, 0.02131141, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.51751363, -0.40028602, 0.3469574, 0.5933738, -0.91357684, -0.67692596, 0.57815677, 0.39809322, -0.16341521, -0.27169713, 0.12232366, 0.4318641, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(0.12601124, -0.06263236, -0.45907676, -0.41514075, 0.3330334, -0.1929565, -0.6333532, -0.6552794, -0.045809917, 0.046351526, -0.26173338, -0.30252662, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.0030332592, 0.012103107, 0.010537323, -0.02038607, 0.095558085, 0.097704545, 0.083433494, 0.026790185, 0.01943357, -0.061712462, -0.00015703632, -0.032268334, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(0.016870102, 0.5215812, -0.11525501, 0.027527615, -0.09045733, 0.61310345, -0.1575268, 0.1905386, 0.020172214, 0.3503187, -0.08209157, -0.051328037, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(0.005494087, -0.010656317, 0.07682753, -0.08116042, -0.03934524, 0.16589017, 0.101483546, -0.066603065, 0.03494657, -0.07885597, 0.074227594, 0.0016264897, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(0.014463938, -0.0031906287, 0.007015422, -0.003888468);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.08532478, -0.14302494, -0.017921071, -0.0032664281, -0.09841952, 0.024187077, 0.10701477, 0.14110753, -0.05714981, -0.10897174, 0.073803626, 0.103992954, 0.07914382, 0.032193683, -0.18346278, -0.09723936) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.034482613, -0.10742312, -0.047286414, -0.08641124, -0.33896688, -0.036533825, -0.48337597, 0.034040943, -0.13598205, -0.080917805, 0.08540263, -0.012667689, -0.009171425, -0.120026454, -0.20536867, -0.032149274) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.18687321, 0.066278316, 0.024327392, 0.08816582, -0.08017908, 0.09488853, 0.26018232, -0.101504356, 0.17487666, 0.31057635, 0.14785016, -0.09622089, -0.07537452, -0.13844088, -0.05810814, 0.09907489) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.04183032, 0.15207712, 0.005002397, 0.32277516, -0.16169126, -0.119836345, -0.04068436, -0.096728764, 0.11943901, 0.1789597, -0.20412198, 0.19009817, 0.36630696, 0.06946421, -0.5254373, -0.11896399) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.31916487, -0.98911583, 1.0728644, -0.39280394, 0.33458877, -0.17325239, -0.645045, -0.28524077, -0.14512783, 0.24996442, -0.09837877, 0.05468934, 0.31559715, -0.020504637, -0.026724018, 0.24507573) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.23759829, -0.08530173, -0.16665787, -0.22463752, 0.109896734, 0.13446991, -0.049552456, -0.02385489, -0.01245375, 0.3833208, 0.05758832, 0.1528937, 0.0501858, -0.19651426, 0.0076587177, -0.03297025) * go_0(0.0, 1.0);
|
||||
result += mat4(0.14554465, -0.01826686, 0.10284085, -0.19152659, -0.017585073, -0.05511482, 0.06362406, 0.023924058, -0.0018977845, -0.103172876, 0.03287086, -0.20085956, 0.36062446, 0.10749464, -0.20984372, 0.018256644) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.005534592, 0.3709197, -0.18287498, 0.1720451, 0.030155553, -0.023265475, 0.0058617783, -0.031765483, 0.037328955, -0.2730994, 0.35090837, -0.3269043, -0.028477207, 0.32756507, -0.15989502, 0.12158258) * go_0(1.0, 0.0);
|
||||
result += mat4(0.10873739, 0.19583772, 0.060394943, 0.09410379, -0.04739245, 0.026561242, 0.022990001, 0.1093272, -0.01071349, -0.022938967, -0.046423864, 0.2385325, -0.0319821, 0.046962265, 0.09081178, -0.11001857) * go_0(1.0, 1.0);
|
||||
result += mat4(0.13012704, 0.112289295, 0.030790284, -0.050499484, 0.11784853, 0.08107028, -0.07556717, -0.15643, 0.015249331, 0.015299608, 0.07748125, 0.054485757, 0.044857923, 0.12161275, -0.048292994, -0.033995003) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.12931514, 0.15114146, 0.070513315, 0.11246343, 0.4142387, 0.213479, -0.5439916, 0.07776645, 0.13109331, 0.2021147, 0.25932786, -0.22157331, 0.02377734, -0.014970623, -0.1943276, 0.18440372) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.22365458, -0.19829084, -0.06881161, -0.06468993, 0.17202774, 0.0048758537, -0.09235021, 0.18941896, 0.064125344, -0.09067088, 0.09748182, 0.13561936, -0.05876288, -0.0122420965, -0.054380875, -0.17743628) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.18582906, -0.09263032, -0.08210888, -0.20515606, 0.11484005, 0.08557595, 0.0009253741, -0.051202174, -0.18535301, -0.1529345, -0.13092944, 0.03770747, -0.020947013, 0.19187425, -0.15494856, -0.048979875) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.38131633, 0.4278787, 0.19763695, 0.27655518, -0.08711912, 0.07374453, -0.064803004, 0.5983854, 0.2361923, -0.057221692, -0.37138999, -0.24259573, 0.13890724, 0.25706333, -0.54021406, 0.08095518) * go_1(0.0, 0.0);
|
||||
result += mat4(0.0991328, -0.022651536, -0.029148921, -0.009812537, -0.09523686, -0.15704902, 0.052389514, 0.21561539, 0.1950314, -0.08572602, 0.0016523858, 0.14125621, -0.030999828, 0.12009709, 0.0373512, -0.105043754) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.11251988, 0.12106985, 0.011923068, 0.3662747, 0.004800994, 0.017972551, 0.004761366, -0.07934206, -0.13755941, -0.022852683, 0.1502225, 0.009758547, -0.16964264, 0.00984782, 0.07855833, 0.035730787) * go_1(1.0, -1.0);
|
||||
result += mat4(0.01964957, -0.27226487, 0.033933397, -0.117632054, -0.009058229, 0.047830686, -0.01125145, 0.136628, 0.0056388285, 0.3028781, -0.12286517, 0.23498532, -0.009319075, -0.444048, 0.16174883, -0.06367683) * go_1(1.0, 0.0);
|
||||
result += mat4(0.02343933, -0.010915871, -0.058680378, -0.21886891, -0.010750894, -0.06671997, 0.0602906, -0.07903071, 0.066891186, 0.06650588, 0.14362891, -0.101870626, 0.02264628, -0.06940821, -0.077616625, 0.110911585) * go_1(1.0, 1.0);
|
||||
result += vec4(0.032014452, -0.020821465, 0.0826416, -0.002838458);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.06963679, -0.07560548, -0.069522075, 0.0038078027, -0.08002613, 0.13671301, 0.084461786, -0.039376218, 0.19136548, -0.123174496, 0.26566333, -0.16583005, -0.18664864, -0.023539122, -0.21928434, -0.026818147) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.16660932, -0.18558703, 0.37230486, 0.118128106, -0.14098641, 0.14659132, -0.22217897, 0.12952235, -0.4139033, -0.04308319, 0.12885277, -0.17986743, -0.23556231, -0.08351981, -0.43240538, 0.019033253) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.18008037, -0.04448665, 0.011906908, -0.023056917, 0.18136618, -0.04723555, -0.0050158803, -0.14823224, -0.2105281, 0.023047728, -0.14040631, -0.03178526, -0.13477588, -0.01820428, 0.058358394, 0.23792502) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.07363309, -0.061728477, 0.03573137, -0.0050971056, -0.012813505, -0.17236637, 0.1697835, 0.055788577, -0.22263195, 0.10324512, 0.58971673, -0.4872246, -0.1555681, 0.032747746, -0.096495196, 0.070196226) * go_0(0.0, -1.0);
|
||||
result += mat4(0.14174286, 0.099460006, -0.088765986, 0.58350676, -0.025177564, -0.46004987, 0.37007022, -0.11437029, -0.5164534, -0.60465246, 0.38859612, -0.32846406, 0.050266482, -0.20334712, 0.18316261, -0.19327633) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.09377763, -0.0012762006, -0.028991895, -0.26523829, 0.20173682, 0.037923716, -0.03174243, 0.07103378, -0.10764164, -0.30752546, 0.20556998, -0.1892279, 0.08115748, -0.023550175, -0.07627362, 0.11746628) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.06998859, -0.017997518, 0.069938794, -0.14943017, -0.14179112, 0.16643842, -0.110231474, 0.08895815, -0.24074875, 0.3277253, -0.07435203, -0.23452802, 0.039962552, -0.07145652, -0.022511544, -0.04571222) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.059785757, -0.23771374, -0.030571314, 0.25222278, 0.106601834, 0.34398326, 0.14511436, -0.03867526, -0.38982397, -0.11944689, 0.12997924, -0.13079585, 0.005729482, 0.012653905, -0.063693404, 0.09632285) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.04933823, 0.0547175, 0.050636575, -0.10060694, 0.1344485, 0.19752938, -0.100068115, -0.028829506, -0.14096203, -0.079092234, 0.092109434, 0.011606209, -0.04052607, -0.008347507, 0.06956573, -0.028109524) * go_0(1.0, 1.0);
|
||||
result += mat4(0.21918017, -0.11115073, 0.2262453, -0.06889667, -0.11256312, -0.07438075, -0.088454485, 0.13672407, -0.06905764, 0.08128395, 0.016103368, 0.050190717, 0.09691516, 0.05845721, 0.4886816, 0.041121427) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.3449472, 0.09711974, -0.13881907, -0.018265123, 0.27855873, -0.07030004, 0.29545054, 0.37216932, 0.08657718, 0.099066615, -0.10574013, -0.17667885, -0.14855732, -0.11351448, 0.66945946, 0.11312157) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.2526151, -0.04594331, -0.06606611, 0.09104881, 0.06857995, -0.075284235, -0.17664689, 0.21578754, 0.0696524, 0.09142951, 0.080997564, -0.0682772, -0.0011445724, -0.11736295, 0.2519232, -0.101926275) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.12913518, 0.058357026, 0.195421, -0.15651494, 0.2877076, 0.0033844314, -0.07831594, 0.052855384, -0.031295884, 0.03301088, -0.18408822, 0.06732994, 0.23742151, -0.12568143, 0.22810535, -0.11545694) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.49203303, -0.22656603, 0.1723193, -0.51250046, -0.09742038, 0.758559, -0.3387505, -0.6193586, 0.14136684, 0.27679884, -0.050113205, 0.31041816, -0.36475047, -0.48746544, 0.3233227, 0.4579754) * go_1(0.0, 0.0);
|
||||
result += mat4(0.46636763, 0.1507748, -0.2581362, 0.15413165, -0.17160143, 0.14256273, -0.074575804, -0.099299066, -0.0017214464, 0.13778336, -0.07378213, -0.15489665, -0.10533715, -0.0011083825, 0.39584312, 0.0023906573) * go_1(0.0, 1.0);
|
||||
result += mat4(0.026959421, -0.06391859, 0.0034752619, 0.14521928, -0.0010877338, -0.032619733, 0.005375293, -0.018952755, 0.03381545, -0.007652831, 0.034141563, 0.046016496, 0.11219674, 0.030913852, 0.077403754, 0.17192438) * go_1(1.0, -1.0);
|
||||
result += mat4(0.040326044, 0.17290725, -0.1220239, -0.09594783, -0.025229257, 0.17913155, -0.26623353, -0.033396784, -0.03075146, 0.009143897, -0.0136083895, -0.13886899, 0.075683735, -0.11584183, 0.22182357, 0.19350322) * go_1(1.0, 0.0);
|
||||
result += mat4(0.15726025, -0.10215694, -0.060057458, 0.26487043, -0.04075552, -0.016496127, 0.0015382086, 0.108562306, 0.026795091, 0.0441233, -0.08754318, -0.0460157, 0.048422016, 0.14107347, 0.07986661, 0.1047697) * go_1(1.0, 1.0);
|
||||
result += vec4(0.0766796, 0.08115133, -0.05703058, 0.14025708);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!SAVE conv2d_3_tf
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.18038331, 0.21830973, -0.10019419, -0.022745568, -0.14944611, -0.15669158, 0.46361133, -0.07289843, 0.02976627, -0.09000817, 0.113060996, 0.05635241, 0.012762965, -0.022688959, 0.01629751, 0.061114635) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.024338024, -0.10004009, -0.13709056, -0.0851965, 0.23927099, -0.024349794, -0.16574804, 0.084686354, -0.047885604, 0.09688507, -0.12733915, 0.06980246, 0.11480734, 0.014669346, -0.07505829, 0.04676309) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.054203495, 0.011881634, -0.036115017, -0.0686298, -0.13682245, -0.15678032, 0.057050128, -0.03368558, 0.13011025, 0.033391044, -0.09841339, -0.027057761, -0.18701133, 0.20852546, -0.13660902, 0.0005817616) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.08077834, 0.35952288, -0.07647382, -0.0033230998, 0.13929126, -0.09155619, 0.14128102, 0.16005981, 0.18161216, -0.09485738, 0.0029118075, 0.052682754, 0.03242074, 0.08299826, 0.073796146, -0.06446532) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.36655015, 0.4606936, 0.19073649, 0.31655258, -0.006838053, -0.579939, 0.089126326, -0.14021218, -0.3437716, 0.16714323, 0.17705944, -0.22418492, -0.3883696, -0.2302651, 0.2581861, 0.21983066) * go_0(0.0, 0.0);
|
||||
result += mat4(0.0992383, -0.014257871, -0.023896435, 0.19868234, 0.0408007, 0.07995299, 0.16102871, -0.11668251, 0.22458278, -0.05587917, 0.19373615, -0.016202094, -0.25106144, 0.15634494, 0.11624891, -0.2930768) * go_0(0.0, 1.0);
|
||||
result += mat4(0.024616942, 0.36248252, -0.14779098, -0.019894283, -0.007111256, 0.010641561, -0.09541178, 0.21236233, 0.009501827, 0.08132797, -0.13983901, 0.027207611, 0.038444366, -0.013995817, -0.16242191, 0.03294123) * go_0(1.0, -1.0);
|
||||
result += mat4(0.0131698875, -0.18124102, -0.13503514, -0.06099072, 0.07422735, -0.20906176, -0.049005672, 0.08739405, -0.031758767, -0.1978915, 0.23094437, 0.54512614, 0.21338555, -0.011205669, -0.23727885, -0.29533875) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.0010255767, -0.07168225, -0.033568826, 0.22161655, -0.087293416, 0.11350447, 0.13653576, 0.061226424, -0.13074352, 0.058425818, 0.038460605, 0.2749964, -0.012814839, 0.085885845, -0.038151987, -0.17960808) * go_0(1.0, 1.0);
|
||||
result += mat4(0.19728905, -0.040724937, -0.18270236, 0.046735186, 0.03507326, 0.119867206, -0.12691991, 0.18119748, -0.052895024, 0.11348764, -0.043787055, 0.004703516, 0.006752757, -0.06939761, -0.009801806, -0.075640485) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.051735226, 0.1732299, -0.10672899, 0.0320877, -0.4913656, 0.2102274, 0.43920282, 0.059108034, 0.08349019, -0.16517872, 0.15436842, -0.1075667, 0.022741623, -0.26693836, 0.3645307, 0.017874828) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.034464058, 0.014929155, 0.054227423, 0.14167373, -0.0023630706, -0.08904212, 0.11918041, -0.034539603, 0.06048089, -0.06807333, 0.14447778, 0.035260547, 0.09979546, -0.1924939, 0.14596114, -0.12069667) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.04427228, -0.23673469, 0.010357103, -0.2907043, -0.06845721, -0.078984015, 0.06867713, -0.058163825, -0.12154615, 0.08430951, 0.1922373, 0.030108064, -0.43081748, -0.38715646, -0.022240646, -0.15403675) * go_1(0.0, -1.0);
|
||||
result += mat4(0.46885306, -0.33421394, -0.6695223, -0.41841158, 0.30317923, 0.24244753, -0.1047785, -0.18656285, 0.06261881, -0.4405616, 0.24233986, 0.40070608, 0.81440526, 0.11305212, -0.8826317, -0.023478031) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.07879348, -0.024378026, -0.041883785, -0.17030984, 0.23229122, -0.011237109, 0.12058088, 0.20766267, -0.36519575, 0.09599417, -0.1271098, 0.06990154, 0.21161246, 0.041002538, -0.36046275, 0.007304667) * go_1(0.0, 1.0);
|
||||
result += mat4(0.10873893, 0.003872542, -0.13476561, -0.036068805, -0.054637462, 0.02304618, 0.04707738, -0.2856381, 0.07124422, 0.010866545, 0.20484549, -0.008342406, -0.43660247, -0.041055538, 0.33536008, -0.060022205) * go_1(1.0, -1.0);
|
||||
result += mat4(0.1966458, 0.0016302796, -0.25712642, -0.09639119, -0.006955351, 0.10882133, 0.1107341, 0.062697805, -0.1074494, 0.17361663, 0.6429869, -0.39846307, -0.26302996, 0.048710946, 0.40387508, 0.4299715) * go_1(1.0, 0.0);
|
||||
result += mat4(0.18948616, 0.24086732, -0.064474985, -0.11069709, 0.1279659, -0.13438123, -0.028438117, 0.125883, 0.018153818, -0.21942288, 0.020390838, -0.22797634, -0.10821287, -0.17175092, 0.122016855, 0.20699544) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.05101961, -0.060740646, -0.024465766, 0.058471628);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!SAVE conv2d_4_tf
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.14533128, 0.07266841, 0.13238011, -0.23328504, 0.031516243, 0.058471266, -0.06394412, 0.090752736, -0.0042359144, 0.12357294, -0.04377495, 0.0011743477, 0.05412243, -0.08146249, 0.04002749, -0.032876283) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.036972385, -0.15238069, -0.3453321, -0.36025128, 0.07597202, -0.02368151, -0.3889606, 0.34607083, 0.3133179, -0.21712309, -0.4210954, 0.21450534, 0.15226828, 0.25326282, 0.45327064, -0.3350824) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.019018406, -0.33060563, -0.092601225, 0.14970545, 0.1441509, -0.19228427, -0.032771986, 0.26331595, 0.052981265, -0.06627376, -0.08634131, 0.038706224, 0.13403937, -4.4842476e-05, 0.049002815, -0.12719193) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.17527401, -0.0035254909, -0.047959115, -0.4526988, -0.07510284, 0.0013256798, -0.07539148, 0.24220634, -0.08708839, -0.14494033, -0.17085724, -0.099797316, 0.0068515535, -0.08918779, 0.27164719, -0.1702649) * go_0(0.0, -1.0);
|
||||
result += mat4(0.31848368, 0.48983255, -0.44140294, -0.65174145, -0.004199057, 0.19494705, 0.5196497, -0.027118586, 0.032509074, -0.23900363, -0.14489244, 0.36314297, -0.23168536, -0.20960593, 0.61471456, 0.12401275) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.24317405, 0.21560913, 0.15564032, 0.11606844, -0.15039803, -0.59578896, 0.14100945, -0.026194477, 0.37237462, -0.49472088, -0.15215331, -0.38820064, -0.25089455, -0.29643852, -0.09513793, 0.019779462) * go_0(0.0, 1.0);
|
||||
result += mat4(0.12498539, 0.0710632, -0.25012368, -0.2272255, -0.08647026, 0.12277892, 0.011025097, -0.12168395, -0.13489573, 0.016708186, -0.15583871, -0.057124946, 0.1216943, 0.019803725, 0.06952334, -0.032985855) * go_0(1.0, -1.0);
|
||||
result += mat4(0.28794885, 0.33783793, -0.14469545, -0.081780486, -0.50320613, -0.067601606, -0.06847453, -0.021648854, -0.34295765, 0.15071863, -0.06619896, -0.084465064, 0.31909832, 0.015414661, 0.14930317, -0.11295768) * go_0(1.0, 0.0);
|
||||
result += mat4(0.24530606, 0.25526014, 0.09971985, -0.07749641, -0.2361951, -0.07997673, 0.03617294, 0.02959561, -0.4498983, -0.014073485, -0.20587012, 0.06396779, 0.1262825, 0.027433183, 0.14469334, 0.011538011) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.038572453, -0.023108613, -0.039481267, -0.012160024, -0.004521989, -0.028665857, 0.04295255, 0.10580258, 0.05439479, -0.072261885, 0.11030243, 0.08934696, 0.09133867, 0.017547369, 0.097613186, 0.05491059) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.09972817, 0.057730395, 0.12665828, 0.32861367, -0.16186063, 0.0745509, 0.2394045, -0.08687853, -0.034404907, -0.05843572, 0.0684561, -0.1355754, 0.19248672, -0.60372186, 0.12583947, 0.4388962) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.10341107, 0.061113223, 0.08773817, -0.082504354, -0.16612078, 0.2681751, 0.019737698, -0.17122322, -0.135949, 0.3048101, 0.087803006, 0.11373851, 0.013192192, -0.27022064, 0.35529897, -0.15321451) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.032835662, 0.11123062, -0.11322452, -0.17300649, 0.04680824, 0.12849288, 0.17269878, -0.048671383, 0.05189037, -0.009078046, 0.22105052, 0.013008137, -0.009738674, 0.15391739, 0.20969556, 0.14189166) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.47377753, 0.3038031, 0.18604809, 0.1931698, -0.2964668, -0.12287907, -0.7107761, 0.26619422, -0.33923018, 0.19200724, 0.013786281, -0.17496964, 0.079325035, -0.3694445, 0.0054486147, -0.33018264) * go_1(0.0, 0.0);
|
||||
result += mat4(0.14903802, -0.028043179, 1.5238678e-05, 0.021232028, 0.16025065, 0.14746875, -0.22831628, -0.12177345, 0.038778774, 0.32188168, -0.042017702, 0.27155936, 0.17920609, 0.04099755, 0.28527525, 0.074623376) * go_1(0.0, 1.0);
|
||||
result += mat4(0.057019282, -0.112741895, 0.030361209, 0.14567861, 0.056265317, -0.01573537, -0.06707608, 0.016657263, 0.09829025, -0.026795063, 0.023042196, 0.09438241, -0.025483066, -0.052787006, 0.19730279, 0.021218104) * go_1(1.0, -1.0);
|
||||
result += mat4(0.19868211, -0.01531125, 0.108596824, -0.035456363, 0.0033609823, 0.057961613, -0.013726211, 0.101742364, 0.33357215, 0.14468077, 0.29711527, -0.24662566, -0.119014986, -0.1899639, 0.11246697, -0.0035374009) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.05602109, -0.15539522, 0.010730943, 0.057116497, -0.02037749, 0.084210664, -0.028235348, 0.10574697, 0.056925274, 0.07922333, -0.090088, 0.1615985, -0.0044301567, -0.089945644, 0.024176618, -0.041844133) * go_1(1.0, 1.0);
|
||||
result += vec4(0.0015292584, -0.043625206, -0.09429898, -0.06280405);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!SAVE conv2d_5_tf
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.06051604, -0.028152643, -0.21418124, 0.13032125, 0.42565975, -0.09571944, -0.34494513, 0.30004, -0.073245734, -0.028659137, 0.0032105136, -0.05009555, -0.048971225, 0.04814533, 0.002843805, -0.046224426) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.07495975, 0.018714864, 0.21229684, -0.13614887, 0.79988647, -0.0697328, 0.38232988, 0.24165109, 0.25947478, -0.0009418982, -0.17369923, 0.10007766, 0.024117598, 0.028611807, 0.15090801, -0.06344829) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.07982219, 0.0900347, 0.007609254, -0.0034791247, 0.013611781, -0.13560618, 0.09685799, 0.06276075, 0.134693, -0.14370437, -0.25175703, -0.0016138123, -0.0075672898, -0.13325731, -0.061100446, 0.0059743375) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.039018434, -0.19668463, -0.43018532, 0.31886247, 0.4965479, 0.114569925, 0.19110382, 0.27343535, 0.0707728, -0.11877004, -0.25827697, 0.37012872, 0.1474777, 0.07056952, -0.14965728, 0.061595406) * go_0(0.0, -1.0);
|
||||
result += mat4(0.506543, -0.16268773, 0.455319, -0.0702646, 0.70102173, -0.14041683, 0.70184857, 0.4817842, -0.3389246, -0.14463086, 0.13763213, -1.1259074, 0.47722015, 0.38352612, -0.04293366, -0.5604627) * go_0(0.0, 0.0);
|
||||
result += mat4(0.17606944, 0.15897374, 0.13499324, 0.29241478, -0.032824475, 0.11128662, -0.22204424, -0.051803727, 0.013195331, -0.42040786, -0.3950585, 0.70745844, 0.38646924, -0.19080774, -0.15171832, -0.10742828) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.039278325, 0.18421806, -0.044948544, 0.07902063, -0.2149251, 0.09913459, -0.09743655, -0.26899317, -0.002695496, -0.07554527, -0.22373366, 0.17830558, -0.047994815, -0.06789183, -0.06755918, -0.104452066) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.0493473, -0.30411786, -0.056439694, -0.06582185, -0.21309847, 0.100670904, -0.22966193, -0.045954112, 0.12728062, -0.25081897, -0.094699375, -0.4036555, 0.060854495, -0.64373237, -0.21522263, -0.6683476) * go_0(1.0, 0.0);
|
||||
result += mat4(0.063481025, 0.11744312, -0.043330096, 0.33817932, -0.06679828, -0.23207302, -0.10188898, -0.10590511, 0.058780864, 0.047292337, -0.11834696, 0.10076128, -0.036641665, 0.30200714, -0.0002892557, -0.10303763) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.10842604, 0.042055763, 0.29702973, -0.07409644, -0.030164458, -0.012098744, -0.06396587, -0.08787527, 0.051854923, 0.12997511, 0.11468497, 0.15022379, 0.007814715, 0.014517445, 0.025484756, 0.01078619) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.29229385, 0.040265664, -0.15376821, 0.075579196, -0.05593569, -0.045405343, 0.12099204, 0.1571252, 0.17841713, 0.04673325, 0.14550509, 0.08603346, -0.049786013, 0.06121843, -0.16273825, -0.13857752) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.06903744, 0.2628764, -0.13582836, -0.35678583, -0.13821034, -0.019381443, -0.19570538, -0.09298511, 0.08965436, 0.09745909, 0.20055099, 0.024967568, 0.08144204, 0.004633625, 0.12809834, -0.009431525) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.09784006, 0.010729353, 0.046643205, -0.110926524, -0.21556224, 0.00016300633, 0.122175336, 0.15004392, 0.013864355, 0.24767809, 0.13865592, 0.0155424485, -0.1450483, -0.15688781, -0.06195043, -0.13745981) * go_1(0.0, -1.0);
|
||||
result += mat4(0.018991318, 0.55401963, 0.11709872, -0.028442185, -0.46035343, -0.10215539, -0.60193926, 0.47882316, -0.23346989, 0.037200127, 0.22814943, -0.08231696, -0.36430013, -0.011152757, 0.48752213, 0.29796222) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.07258066, -0.023222538, 0.23230423, -0.30317304, 0.03942911, -0.06899803, 0.23778579, 0.07418621, -0.17443737, 0.33387753, 0.007354842, -0.123447575, -0.1745315, 0.11071779, -0.11949625, -0.22832453) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.024909232, -0.0308135, 0.12170621, -0.13298757, 0.045828197, -0.1532345, -0.06633672, 0.23591088, 0.04964077, 0.14091493, 0.038343724, -0.029780807, 0.05762822, -0.048930667, -0.02434709, 0.07109019) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.16039175, 0.3004474, -0.17278233, 0.13677922, 0.18838613, 0.15054552, 0.32901475, -0.1288333, 0.26378244, -0.05119892, 0.34533516, 0.25180495, 0.19452183, 0.0843233, -0.08029368, 0.39877903) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.07097129, -0.26492423, -0.055032317, -0.093516104, -0.11795062, 0.04086253, -0.07989471, 0.059686553, 0.09378249, 0.45851848, 0.2510942, 0.19599153, 0.019765077, -0.02920918, -0.04125142, -0.13859107) * go_1(1.0, 1.0);
|
||||
result += vec4(0.04400571, -0.04015565, 0.0140529545, 0.05474095);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!SAVE conv2d_6_tf
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.014236042, -0.0031431736, -0.1551387, 0.12515116, -0.28528872, 0.36161992, 0.15750743, -0.17111474, 0.13792591, -0.0657419, -0.17471549, 0.14650472, 0.034169197, -0.019157575, 0.23520657, -0.20358163) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.02015035, 0.12993371, 0.11199667, -0.09854378, 0.5001741, 0.03462961, 0.24919736, 0.08505297, -0.20902094, -0.24141377, -0.15360375, 0.049974803, -0.037157424, -0.048510186, 0.20106035, -0.118480384) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.086798504, -0.009607818, 0.034812123, -0.005187592, 0.0351509, 0.021755, -0.04996161, -0.041231696, 0.0020545553, 0.015730752, -0.07507172, 0.018597523, -0.02393343, 0.07624775, 0.03892451, -0.0025574185) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.035725456, 0.06809103, 0.51926994, -0.39983147, -0.16402833, -0.1243394, -0.25922915, 0.28285915, 0.15959994, -0.2351732, 0.2650535, -0.30193794, -0.11468332, 0.050777763, -0.51894253, 0.4408367) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.27042082, 0.22243942, 0.14902467, 0.38428563, 0.46612173, 0.5169912, -0.22330502, -0.11300288, -0.36141354, 0.0668681, 0.2984152, 0.1275798, -0.24121419, 0.2952039, -0.45109174, -0.3822957) * go_0(0.0, 0.0);
|
||||
result += mat4(0.26543504, -0.05742226, -0.052103903, -0.013124308, -0.14358385, -0.04024543, 0.07665455, -0.012301872, -0.18752757, -0.03913891, 0.038205814, -0.006583095, -0.25550908, -0.25725332, -0.12454206, -0.0058936924) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.0018946569, 0.019746022, -0.13080788, 0.11450627, -0.013743845, -0.027179785, -0.14425103, 0.07109661, 0.023703793, 0.086905524, 0.03151253, 0.0132474145, 0.041018624, 0.04548913, 0.2718715, -0.20008296) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.076830454, 0.11652955, 0.5068201, -0.3082819, 0.058615055, -0.006765798, -0.057522714, 0.049981344, -0.006897243, -0.21763432, 0.16896053, -0.21176189, -0.061227098, 0.03566485, 0.08901554, -0.050980624) * go_0(1.0, 0.0);
|
||||
result += mat4(0.02327798, 0.07662976, 0.034811985, -0.03238033, -0.0021881019, -0.030997375, -0.069672935, 0.04040273, -0.1217442, 0.104173124, 0.09862539, 0.020557549, -0.022286594, 0.10287763, -0.021694934, 0.07542515) * go_0(1.0, 1.0);
|
||||
result += mat4(0.124069154, -0.08579466, -0.07816314, 0.11332851, -0.034682628, -0.11038275, 0.04750615, -0.096100725, 0.039588403, -0.15149672, -0.05529172, 0.034304325, -0.022520235, -0.05023852, -0.2674731, 0.21886522) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.1948599, -0.14946899, -0.39548838, 0.18042913, -0.007919619, 0.19826505, 0.23789087, 0.009140256, 0.11857748, 0.18215668, 0.13606293, -0.09209675, -0.080678545, -0.020431137, -0.07728839, -0.051353537) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.07616472, -0.0032800382, -0.045657665, -0.039144326, -0.37786487, -0.08877774, 0.053579114, -0.070886396, 0.011311804, 0.107276045, 0.013236154, 0.009832061, 0.08292063, 0.12258811, 0.0005569043, -0.009806432) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.28062925, 0.15946878, -0.1021801, -0.06471589, -0.26999477, 0.21230288, -0.14243907, 0.2555922, -0.09608517, 0.26339412, 0.20891234, -0.23538485, 0.33958244, -0.12569186, 0.43289876, -0.33462036) * go_1(0.0, -1.0);
|
||||
result += mat4(0.16265294, 0.2625464, -0.34452894, 0.2233622, 0.13850005, -0.42999864, -0.5385177, -0.11035979, 0.51662, -0.78238726, -0.09422375, 0.83759475, 0.44468537, 0.14301361, 0.108906105, 1.1596143) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.73757625, -0.12369605, 0.23523071, 0.006587637, -0.15445381, 0.22757277, 0.052819528, 0.10183905, -0.07912228, -0.16998893, -0.13360223, 0.014348178, -0.17778571, -0.41047302, 0.10241381, -0.08526306) * go_1(0.0, 1.0);
|
||||
result += mat4(0.14712952, 0.048995696, 0.05299946, -0.06817572, 0.1498064, -0.079825334, 0.40354064, -0.31789717, -0.1998377, 0.00955295, -0.32318407, 0.30898204, -0.039571725, -0.026203401, -0.16292085, 0.08574385) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.6353329, -0.56000775, -0.17279743, 0.18198174, -0.19555812, 0.056538377, 0.34365895, -0.07799055, 0.19011354, -0.13952748, 0.029196098, -0.19596763, -0.069196045, -0.17402656, 0.07948411, -0.016226962) * go_1(1.0, 0.0);
|
||||
result += mat4(0.25592864, 0.083498634, -0.28515807, 0.10789751, 0.0043962947, 0.07085363, 0.048724182, -0.025131436, -0.0049440865, -0.033094388, -0.032935806, 0.04266025, 0.20026933, 0.0927841, -0.006839351, -0.013012285) * go_1(1.0, 1.0);
|
||||
result += vec4(0.02021373, 0.0014037411, 0.0012718709, 0.017278494);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(M)-Conv-4x1x1x56
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_6_tf
|
||||
//!SAVE conv2d_last_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define g_0 (max((conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_1 (max(-(conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_2 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_5 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_6 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_9 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_10 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_13 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.0067711817, 0.08160003, 0.0247279, 0.03084815, -0.026977416, -0.02120602, -0.025078611, -0.029852165, -0.011627478, -0.012742972, 0.022736797, -0.0028815821, -0.007515677, 0.0172887, -0.023259213, 0.009608947) * g_0;
|
||||
result += mat4(-0.028660107, -0.014015208, -0.027838672, -0.013171922, 0.0029435428, 0.027047642, -0.017478354, 0.022834882, -0.037572853, -0.0034044068, -0.0149029335, -0.013362301, 0.009827443, -0.015742151, -0.0074795415, -0.0022266617) * g_1;
|
||||
result += mat4(-0.07579662, -0.039754186, -0.066026606, -0.046816852, 0.1099032, 0.043956704, 0.073109835, 0.04680284, -0.06896613, -0.008838632, -0.044584926, -0.01319039, -0.0021152915, -0.04503326, 0.027061926, -0.028334105) * g_2;
|
||||
result += mat4(0.15458213, 0.059769996, 0.09327123, -0.028782733, 0.023459995, -0.15390377, -0.13432898, -0.1127775, 0.072764635, -0.0020463336, 0.034736466, -0.0012086042, -0.05847183, -0.029952323, 0.052969377, 0.09590908) * g_3;
|
||||
result += mat4(-0.07476772, -0.016574614, 0.04131183, 0.017335678, 0.009654406, 0.072183535, -0.002266456, 0.086873695, 9.310129e-05, 0.0056416965, -0.004188391, 0.023132093, -0.05183336, -0.025825873, -0.03684392, -0.0075729224) * g_4;
|
||||
result += mat4(0.00878842, 0.03869637, -0.035759524, 0.003345386, -0.064184256, -0.034568302, -0.06672922, -0.0686381, -0.06794392, -0.10685906, 0.04679947, -0.012535639, 0.006932529, -0.007783515, 0.109123886, 0.13804391) * g_5;
|
||||
result += mat4(-0.03160699, 0.050473, -0.09030729, 0.0649397, 0.11466501, 0.17912874, -0.0081851315, 0.052244574, 0.051632743, 0.061941486, 0.06546816, 0.12174249, -0.05104755, -0.018193979, -0.032196652, -0.035292786) * g_6;
|
||||
result += mat4(0.013612735, -0.0024100312, -0.068611205, -0.07369285, -0.019647537, -0.066944756, -0.010012875, -0.06785739, -0.062246565, -0.087313406, -0.044278186, -0.09368995, 0.052555013, 0.13604961, 0.05645059, 0.08763303) * g_7;
|
||||
result += mat4(0.04218486, -0.05028401, 0.059086576, -0.03545452, 0.027737848, 0.0043074046, 0.0011001764, -0.073026665, -0.04094988, 0.044061556, -0.009812515, 0.06841999, -0.06612581, 0.037223976, -0.07759491, -0.04356598) * g_8;
|
||||
result += mat4(-0.027558247, 0.014248466, -0.019813016, -0.058107473, -0.016717663, -0.020424338, 0.0053625097, -0.009917319, 0.013678771, 0.0113340765, 0.0061787106, -0.036083996, -0.020179711, -0.011310535, 0.054827053, -0.0008278952) * g_9;
|
||||
result += mat4(0.028690035, -0.012079616, 0.11931408, -0.048533775, 0.069336995, 0.0049852817, 0.013774468, 0.035233382, -0.07384821, 0.0003354423, -0.0059171803, -0.04503906, 0.08727279, 0.005138857, -0.17724465, 0.055782065) * g_10;
|
||||
result += mat4(-0.20744391, 0.24348328, -0.3145766, 0.17026486, -0.022870807, -0.01648648, -0.05912279, -0.012555373, -0.066004686, 0.03182394, 0.16285324, -0.1221846, -0.31816196, 0.007928748, 0.43180224, -0.015949022) * g_11;
|
||||
result += mat4(0.16363169, 0.14781676, -0.2377973, -0.1571377, -0.09038187, 0.0046504294, 0.033955004, -0.051421452, 0.046735536, 0.006827522, -0.121338, 0.12671822, 0.15833299, -0.1858712, -0.1942371, 0.17336044) * g_12;
|
||||
result += mat4(-0.018145572, -0.015550516, 0.044410378, 0.046016492, 0.084021375, 0.05327457, -0.008270992, -0.045435544, 0.07185879, -0.131923, 0.26721445, -0.26745328, -0.07093472, 0.042701527, 0.13793674, -0.095621444) * g_13;
|
||||
result += vec4(0.016836504, 0.010161949, 0.021351453, 0.01278978);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(M)-Depth-to-Space
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_last_tf
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_last_tf.w 2 *
|
||||
//!HEIGHT conv2d_last_tf.h 2 *
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
vec4 hook() {
|
||||
vec2 f0 = fract(conv2d_last_tf_pos * conv2d_last_tf_size);
|
||||
ivec2 i0 = ivec2(f0 * vec2(2.0));
|
||||
float c0 = conv2d_last_tf_tex((vec2(0.5) - f0) * conv2d_last_tf_pt + conv2d_last_tf_pos)[i0.y * 2 + i0.x];
|
||||
float c1 = c0;
|
||||
float c2 = c1;
|
||||
float c3 = c2;
|
||||
return vec4(c0, c1, c2, c3) + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(S)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.0057322932, 0.12928207, -0.056848746, 0.18680117, -0.0306273, 0.25602463, 0.053723164, 0.20419341, 0.0018709862, 0.022848232, -0.04105527, 0.10169034, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.009471417, -0.12957802, 0.096014425, 0.21836184, 0.00021601951, -0.22997683, 0.23666254, 0.41192335, 0.021762101, 0.0047863554, 0.008233427, 0.108514786, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.01156376, -0.18988979, 0.04614705, -0.044767227, 0.01050636, -0.26426336, 0.23741047, 0.0027636609, -0.027718676, -0.14202335, -0.016650287, -0.06637125, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.057809234, -0.11033858, 0.056533534, -0.06292466, 0.13880666, -0.18710336, 0.2441031, -0.25326246, 0.0032683122, -0.026437074, 0.0023248852, 7.640766e-05, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.49110603, 0.4429004, -0.44015464, -0.41174838, -0.87738293, 0.7808468, -1.0929365, -0.59699076, -0.18409836, 0.185138, -0.11773224, -0.17097276, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(0.10580959, -0.055947904, -0.03431237, -0.080236495, 0.14862584, -0.15393938, -0.18872876, -0.3170681, 0.03559387, -0.003990826, 0.021298569, 0.012844483, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.040715586, -0.25781113, 0.08896714, -0.1225879, -0.15790503, -0.54010904, 0.29588607, 0.10401059, 0.003413123, -0.108357325, 0.0112870345, -0.11888622, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(0.0049315444, 0.02376202, -0.08224771, 0.121118225, -0.041512914, -0.027994309, -0.585988, -0.069672115, -0.017247835, 0.0056576864, 0.04319012, 0.055003505, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(0.37521392, 0.15916082, 0.059708964, 0.19046007, 0.8120325, 0.38343868, 0.3436578, 0.5287958, 0.16570656, 0.06957687, 0.014022592, 0.074799836, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(-0.01050964, -0.00939481, 0.17684458, 0.027366742);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(S)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.011029496, 0.05866063, -0.09460646, -0.017664742, -0.022488879, 0.18384217, -0.00397663, -0.064733066, 0.08466802, 0.10667488, 8.0212536e-05, 0.0908869, 0.13580276, 0.00097438256, 0.12176522, -0.08218466) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.16062798, -0.10190268, 0.03280682, 0.05621916, -0.009684231, -0.08464307, 0.17058301, -0.096469186, 0.1967505, -0.1450099, 0.093607284, -0.28240147, -0.21377413, 0.10079291, -0.1741522, 0.17330575) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.060160473, 0.06316997, 0.0046929033, -0.049405966, 0.13851729, 0.06830702, -0.0586872, -0.040827133, 0.007052838, -0.03576886, -0.111261636, 0.039155316, -0.07380389, -0.09369825, 0.04471156, 0.09678487) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.36683616, -0.035950605, -0.24414362, -0.009159744, 0.19335322, -0.099253505, 0.075083904, -0.00076695543, 0.65291303, -0.25599423, 0.19827642, 0.065899536, -0.07423247, -0.068967685, 0.0050554527, -0.060272824) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.020688485, -0.83178276, 0.11104878, 0.26454413, 0.13655476, 0.37675047, -0.22219229, -0.01751935, 0.44552696, 0.92510307, 0.16063261, -0.62011045, 0.19366647, -0.06996067, -0.2504841, 0.00803723) * go_0(0.0, 0.0);
|
||||
result += mat4(0.0051537007, -0.057168536, -0.16110587, 0.25232598, -0.04447099, 0.11997351, 0.14808103, -0.34443566, -0.26212573, -0.21970181, 0.2724405, 0.21050811, -0.07949061, -0.064808235, -0.21208277, -0.0042361654) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.0888952, -0.20169449, 0.19144905, -0.016882861, -0.013283103, 0.07552998, -0.24686803, 0.012453213, -0.065454446, -0.016123284, -0.47316182, 0.070926026, 0.09219782, 0.13118166, 0.074736096, 0.0077910526) * go_0(1.0, -1.0);
|
||||
result += mat4(0.5832154, 0.1138069, -0.039765622, 0.3182784, -0.25497997, 0.0013993139, 0.39285088, -0.48511526, -0.39891505, -0.19094779, -0.082146175, -0.20826934, 0.020590555, -0.0012490178, -0.4398621, 0.14377014) * go_0(1.0, 0.0);
|
||||
result += mat4(0.21917395, 3.4314657e-05, 0.25734863, -0.3433305, 0.015720673, 0.2676127, -0.06807297, 0.15040149, -0.23638041, -0.0050233034, -0.13666134, 0.4542111, -0.033572577, -0.08450588, -0.23341487, 0.053490847) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.17482175, 0.057647135, 0.33135444, 0.0850751, -0.1718849, -0.0854123, 0.036795795, -0.13874969, -0.10903869, -0.19007301, -0.06064334, -0.03786032, -0.036696054, 0.07844446, 0.012523185, -0.01562906) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.04411997, -0.10331819, 0.10050193, 0.12406485, 0.07431592, 0.30109692, -0.17511666, -0.13263564, -0.10192587, 0.07821255, -0.22415096, 0.25552443, 0.17881326, -0.13914281, 0.109979235, -0.0016463579) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.01911644, -0.15412527, 0.028903123, 0.20831817, 0.00375175, 0.08110953, 0.074919395, -0.17581624, -0.015677985, 0.06504228, 0.08817818, -0.12518327, -0.09537373, 0.028905088, -0.051288474, 0.054334078) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.2852779, -0.28924024, 0.36805123, 0.21079305, -0.28336474, 0.1679663, -0.08641141, -0.10699407, -0.16090055, 0.1287612, -0.15910125, 0.05734755, 0.15883245, 0.0053026294, 0.080674745, 0.0505137) * go_1(0.0, -1.0);
|
||||
result += mat4(0.17639062, 0.3790122, -0.19588692, -0.020314282, 0.26197383, 0.09014768, 0.19696823, -0.41025418, -0.08308115, -0.33279485, -0.22528782, 0.06172439, -0.1365661, -0.13094363, -0.005086559, 0.089024484) * go_1(0.0, 0.0);
|
||||
result += mat4(0.05262993, 0.0006296959, 0.1657725, -0.32591924, 0.12126701, 0.061543245, -0.10526848, 0.041583937, 0.094976954, 0.09416157, -0.22019257, -0.058390073, -0.2073888, 0.057273377, 0.19558284, 0.004208022) * go_1(0.0, 1.0);
|
||||
result += mat4(0.30005738, 0.18478931, -0.23342943, 0.22455733, -0.016488122, 0.099634305, 0.31620836, -0.15731157, 0.09595808, 0.0013774688, 0.48273298, -0.07027936, -0.18764344, -0.26194447, -0.11794225, -0.012173601) * go_1(1.0, -1.0);
|
||||
result += mat4(0.117986746, -0.13846518, -0.019614812, -0.3011192, 0.5501164, 0.3408611, -0.40090847, 0.15706886, 0.13050972, 0.051776595, 0.20792943, 0.23389706, -0.22965533, -0.053367328, 0.3911586, -0.032988597) * go_1(1.0, 0.0);
|
||||
result += mat4(0.054753624, -0.008485731, -0.2451672, 0.17528129, 0.13657846, 0.010480436, 0.07651423, -0.43316832, 0.12736236, 0.13804524, 0.12529011, -0.30946237, -0.14423579, 0.08403089, 0.24335162, 0.057288036) * go_1(1.0, 1.0);
|
||||
result += vec4(0.012077211, 0.013045883, 0.0380778, -0.02908858);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(S)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.036115196, -0.06971895, -0.07508942, 0.016036168, 0.12120111, 0.24536026, 0.044755507, -0.20663576, 0.029635755, -0.15427187, 0.027148994, -0.20795093, 0.10170582, 0.077919215, 0.66063017, -0.4632968) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.0052889925, -0.019060908, -0.08660142, -0.022095207, -0.08097976, -0.015142803, -0.18552722, -0.078493506, -0.16293915, -0.20099808, -0.08370822, 0.3701389, 0.09094984, 0.2487225, 0.24338846, 0.044003833) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.061406493, -0.017232792, -0.10917424, 0.11203319, 0.040699825, -0.019294346, 0.084953666, -0.018133596, 0.07209552, 0.016069936, 0.17805555, -0.089537814, 0.15809004, 0.1027023, 0.15044671, -0.15530108) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.0948676, -0.040305693, -0.005591629, -0.048048403, -0.07547777, 0.056606572, 0.021390207, 0.32600567, -0.20805131, -0.099587254, 0.029613169, 0.0092129605, -0.29429698, -0.09898621, 0.44470885, -0.89487344) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.122259885, 0.11445877, 0.06666907, 0.1869428, -0.1553992, -0.1658741, 0.2988138, -0.57746625, -0.34609964, 0.11169158, -0.41877756, 0.38075635, 0.21293911, 0.09640372, -0.12754214, -0.08026104) * go_0(0.0, 0.0);
|
||||
result += mat4(0.15128808, 0.050087795, 0.09219755, -0.18080945, 0.0044571217, -0.046019405, -0.1289922, 0.20305426, 0.19601224, 0.04667917, 0.17465587, 0.027672665, 0.18441725, 0.06845396, 0.11288585, -0.23283863) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.072962, -0.06639447, 0.049347494, -0.1386401, 0.10396071, 0.08187777, -0.04280746, 0.07390891, 0.06628344, 0.037797406, 0.021885803, -0.013147403, 0.22376558, 0.36243078, 0.12874891, -0.0023783944) * go_0(1.0, -1.0);
|
||||
result += mat4(0.074945286, 0.16045591, -0.11798349, 0.12910712, 0.054760084, -0.095626175, -0.047832094, 0.03493912, 0.11817307, 0.037452437, -0.14301221, -0.027356789, -0.052390423, 0.11373512, 0.07686775, 0.010008694) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.023999173, -0.091900624, 0.02388157, 0.03173873, 0.0065633506, -0.033716757, -0.1198324, 0.12057766, 0.026465805, -0.07517131, -0.07760598, 0.060463097, 0.07345541, 0.046037503, 0.21101558, -0.26785463) * go_0(1.0, 1.0);
|
||||
result += mat4(0.15544604, -0.03902825, 0.04630384, -0.25173616, -0.0691359, 0.07476507, 0.009071253, 0.089964196, -0.26539803, -0.3958477, -0.22155671, 0.20735882, -0.105860494, -0.003996804, -0.044815883, 0.39544627) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.6169709, 0.23717614, -0.37884676, -0.7484867, 0.020169826, -0.30718836, 1.0965588, -0.20711036, -0.39149985, -0.06843563, -0.06522909, 0.103805855, 0.03265825, -0.15137726, 0.12837899, -0.01294922) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.23638196, -0.4560866, -0.11948684, -0.1464144, 0.10690008, 0.007835961, 0.11864342, -0.13101323, -0.16509797, 0.075027354, 0.08122998, 0.13451207, 0.0011890623, 0.052157886, 0.08372405, -0.07085038) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.21997726, -0.16488647, -0.0291317, 0.17997476, 0.1493211, 0.027494298, 0.0034613227, -0.3207727, 0.18699001, 0.14728633, -0.042895135, -0.07612043, 0.125076, -0.14714554, -0.03480009, -0.22753975) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.5342686, -0.7426105, -0.38294584, 0.42549992, 0.46053204, 0.7867879, 0.106234804, -0.041163098, 0.5198579, -0.5219404, 0.14809476, -0.41802374, 0.06810794, -0.15122683, -0.047409, 0.13178343) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.50428164, 0.18220626, 0.35510704, -0.081787474, 0.03155813, 0.019284263, 0.0032388573, -0.20513348, -0.05385551, 0.17803182, -0.26206362, 0.2870375, 0.008557827, 0.08401449, -0.027598893, -0.010791235) * go_1(0.0, 1.0);
|
||||
result += mat4(0.16657415, 0.067647465, 0.093076974, -0.14438486, -0.10017002, 0.0022367141, 0.03250936, -0.052794546, -0.009178676, -0.019673595, -0.0016697067, -0.15424626, -0.112123474, -0.11079971, 0.011987111, -0.11747758) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.023021797, -0.058703423, -0.037978355, -0.062433913, -0.13130441, 0.048656322, 0.056839373, 0.109036915, -0.07823158, 0.14785293, 0.058555078, -0.11679035, -0.14002073, 0.07395252, 0.098268874, -0.06710464) * go_1(1.0, 0.0);
|
||||
result += mat4(0.14906375, 0.030001195, -0.10338215, 0.0662968, -0.161953, -0.13682815, 0.09563142, 0.009514228, -0.009491218, 0.06737101, -0.1393389, 0.15231515, -0.073147796, 0.00767062, 0.028675212, 0.014213088) * go_1(1.0, 1.0);
|
||||
result += vec4(0.018736731, -0.0026039074, 0.050130025, -0.055364225);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(S)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!SAVE conv2d_last_tf
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.019100675, -0.014241565, 0.004667036, -0.03865062, 0.106731094, 0.026099661, 0.014594411, -0.011881356, 0.0040967264, -0.004626336, 0.006469508, 0.010875305, -0.033909045, -0.085905954, 0.07861378, 0.019452631) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.20777655, -0.060354974, 0.0023840065, -0.064121604, -0.17397617, 0.019293457, -0.09707183, 0.080641985, 0.01025124, -0.017382381, 0.008661793, -0.010995665, 0.21943407, -0.115574986, 0.14471593, -0.068836235) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.057942886, -0.06311754, 0.2253396, -0.04159292, -0.020731755, 0.007877151, 0.041525815, 0.025278691, 0.03041967, -0.025137542, 0.024364179, -0.024543528, 0.029438615, -0.015506873, 0.081686, -0.07812221) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.054237515, 0.0676094, -0.0047708177, 0.0043467237, -0.10032304, -0.020498628, 0.04240586, 0.07272254, 0.0784221, 0.017945962, -0.022310399, -0.013134622, 0.015638694, -0.10001543, 0.1043031, 0.05898838) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.021652509, 0.35796642, 0.059497777, 0.23948468, 0.15454951, -0.10017235, -0.19072174, -0.44812536, -0.03974552, 0.04529369, 0.22207436, 0.026222564, -0.09705454, 0.5623026, -0.3354105, -0.017278556) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.053682446, -0.03411237, -0.09399936, 0.15128824, -0.07463, -0.042020727, 0.0031783928, 0.13481957, -0.07731454, 0.044114403, -0.23085599, 0.060444202, -0.15015422, 0.0018040676, -0.18684982, 0.2812511) * go_0(0.0, 1.0);
|
||||
result += mat4(0.0029329916, 0.001596018, 0.0007512241, 0.016544111, -0.04876942, -0.05272409, 0.037884697, 0.049948208, 0.015518177, 0.11368592, -0.03815777, -0.013149978, -0.027638039, 0.107719295, -0.04115787, 0.02745414) * go_0(1.0, -1.0);
|
||||
result += mat4(0.016691081, 0.010204119, 0.04078854, 0.01613337, 0.03325829, 0.0114824055, -0.017286912, -0.07284126, -0.110984206, -0.21041764, 0.0089543555, 0.18986733, 0.01537506, -0.2059135, 0.029074017, 0.013117443) * go_0(1.0, 0.0);
|
||||
result += mat4(0.013965926, 0.029871881, 0.0034499036, -0.011343668, 0.022120327, -0.0068748263, 0.009324342, -0.039081004, 0.08032371, 0.050809264, 0.035050742, -0.2032847, 0.06305391, -0.021958945, 0.038569167, -0.22465245) * go_0(1.0, 1.0);
|
||||
result += mat4(0.046307724, -0.012419472, 0.007673863, -0.042344846, 0.011042414, 0.016994251, -0.018166406, -0.016955731, -0.13240299, 0.01768431, -0.027607648, 0.0699927, -0.02840628, 0.004414203, 0.0049618417, 0.011084679) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.119954154, -0.007455482, -0.031108133, -0.009946449, 0.0077065965, 0.01660345, 0.032943666, 0.016376585, 0.10273124, 0.1556573, -0.24643841, 0.107307844, -0.068235755, 0.0561896, -0.0104672015, 0.042693343) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.01634601, 0.04195375, -0.10401894, 0.047641944, -0.034602515, -0.0034419263, -0.010457858, 0.015194475, -0.03962551, -0.030031368, 0.16036317, 0.019283568, -0.05877721, 0.016504882, -0.15523468, 0.018161612) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.08083991, 0.0024665035, -0.049373373, 0.030371357, 0.0113322195, -0.014676956, 0.011646689, -0.01142667, 0.124930486, 0.06625774, -0.045840867, -0.009693036, -0.012649251, -0.07388084, 0.008790075, 0.0013844534) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.33941835, -0.2763476, -0.118311435, -0.063535266, 0.20936015, 0.13731301, 0.13443594, 0.07464433, 0.059650812, -0.36973104, 0.16444235, -0.37082872, 0.06432777, -0.18283032, -0.044489607, -0.13895285) * go_1(0.0, 0.0);
|
||||
result += mat4(0.13533665, 0.08268915, -0.03675727, -0.14348659, 0.0186255, -0.05051692, 0.056702953, 0.0061717895, 0.047663026, -0.088188455, 0.23254345, -0.014015464, 0.08400204, -0.0073777726, 0.2202068, -0.12366078) * go_1(0.0, 1.0);
|
||||
result += mat4(0.04361004, 0.046543695, 0.0064863074, -0.03358146, -0.022602187, 0.018138997, -0.011071864, 0.010244091, -0.019814799, -0.17250171, 0.040823266, -0.040131986, 0.010125854, 0.020660749, 0.0020435036, -0.010819304) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.004810193, -0.11286074, 0.051985834, 0.04788631, -0.023950428, 0.036145125, -0.038203828, 0.052401308, 0.022986965, 0.26420745, -0.06076917, -0.09252999, 0.03164547, 0.15652153, -0.037934, -0.0035418556) * go_1(1.0, 0.0);
|
||||
result += mat4(0.03358366, -0.005219482, 0.007060882, -0.06569114, -0.02941682, 0.00966056, -0.0153679885, 0.019905418, -0.107232265, -0.03405676, -0.044340115, 0.26892832, -0.04723829, -0.02589829, 0.004563232, 0.19318114) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.00346731, -0.0046263863, -0.004627155, -0.0057769152);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(S)-Depth-to-Space
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_last_tf
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_last_tf.w 2 *
|
||||
//!HEIGHT conv2d_last_tf.h 2 *
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
vec4 hook() {
|
||||
vec2 f0 = fract(conv2d_last_tf_pos * conv2d_last_tf_size);
|
||||
ivec2 i0 = ivec2(f0 * vec2(2.0));
|
||||
float c0 = conv2d_last_tf_tex((vec2(0.5) - f0) * conv2d_last_tf_pt + conv2d_last_tf_pos)[i0.y * 2 + i0.x];
|
||||
float c1 = c0;
|
||||
float c2 = c1;
|
||||
float c3 = c2;
|
||||
return vec4(c0, c1, c2, c3) + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,969 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.3053028, -0.037464816, 0.113983095, 0.12537485, -0.18630321, 0.084269725, -0.01351514, -0.20190673, -0.12298384, -0.037622184, -0.070214555, -0.19367279, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.41849324, 0.099702746, -0.04276645, -0.047299717, 0.20074473, 0.14217933, 0.15571699, 0.19553481, 0.21868695, -0.053848714, 0.016413521, 0.14117444, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.030540446, -0.052293833, 0.0715466, -0.31160545, 0.07808315, -0.16860045, 0.032828577, -0.2955024, -0.110374965, 0.04043687, -0.014024628, 0.058699366, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.10727635, 0.054200135, 0.20853694, 0.21086875, 0.122690216, -0.091823794, 0.310609, -0.01738923, -0.0013488946, 0.10835534, -0.077265196, 0.086751856, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.77150255, 0.40530515, -0.41257596, -0.14367618, 0.46888494, 0.2650122, -0.934199, 0.40476102, 0.32293493, 0.20251967, 0.19891106, -0.29698747, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.12505147, -0.41904053, -0.065798186, 0.34075752, 0.026240354, -0.2977496, 0.032647505, -0.003566783, 0.10290523, -0.23417123, -0.06014203, 0.094735645, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.11207838, -0.04062474, 0.023897955, 0.08605987, -0.020888371, 0.045541205, -0.07231824, -0.25884083, -0.11796847, -0.002691391, 0.0050435597, 0.02756291, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(0.4615728, 0.041790638, 0.08971143, 0.20213957, -0.38537467, 0.19938901, 0.08594364, -0.08621994, -0.08163473, -0.133266, -0.09561729, -0.014209637, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(0.0787417, -0.0483673, 0.07621572, -0.060169693, -0.013465177, -0.17152289, 0.02515561, 0.17675288, -0.05173998, 0.10768042, -0.029858522, -0.013957215, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(0.0072128535, -0.05658625, 0.052939568, -0.1760861);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf1
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.112743355, 0.0422517, 0.21350034, -0.0967133, 0.16265953, 0.0022497, 0.015078242, 0.08204187, 0.035236806, -0.0468228, -0.09464228, -0.001864949, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.25631642, -0.41485596, -0.16662048, 0.13201024, 0.057921384, 0.2240005, -0.30038536, -0.08305622, 0.2228756, 0.32263795, 0.10608189, -0.18616734, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.08997524, 0.11516871, 0.19212262, -0.035154644, 0.11612274, -0.04056247, 0.14974374, 0.029173585, -0.07629641, -0.14353512, 0.041081246, 0.20230265, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.2262286, 0.055954933, -0.14499907, 0.17314723, 0.16590612, -0.06688698, -0.11118816, -0.012938116, -0.043101817, 0.026133137, 0.2958395, 0.06543993, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.07311521, -0.3041244, -0.47978505, -0.6350967, -0.17432262, 0.34965977, 0.25399777, -0.16590433, -0.49957857, 0.0549526, -0.40869385, -0.08780993, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.3014447, -0.00021343959, -0.14953177, 0.028001398, -0.14931908, -0.14910097, -0.13287953, -0.45026535, 0.17378895, 0.024704922, -0.027308129, -0.10292025, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.06732655, -0.13119644, 0.066014715, 0.081011154, -0.15154321, 0.2407805, 0.07733481, 0.12312706, 0.1741804, 0.008495716, -0.14125362, -0.043644864, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(0.11465958, 0.42001364, 0.011069392, 0.3203028, -0.058801666, -0.37830314, -0.030540617, 0.2245139, -0.11310525, -0.14845212, 0.19957744, 0.25789997, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.16037206, 0.21326372, 0.020099448, 0.018666709, 0.122083254, -0.16033986, -0.10725163, 0.2556128, 0.1650688, -0.10475823, 0.048623525, -0.103755645, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(0.007717166, -0.027800834, 0.0795002, 0.0053199283);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.0056740534, -0.21186607, -0.18014967, 0.118979976, -0.0015611284, -0.07708486, 0.060131397, 0.11653345, 0.027150517, 0.10837246, 0.08583816, -0.14032431, 0.017552888, 0.0035846964, 0.03980114, 0.064649396) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.03289318, -0.12004539, 0.26514888, -0.15079662, 0.04214227, -0.027273783, -0.027950313, 0.19614808, 0.18510003, -0.10346252, -0.029836183, 0.09174428, -0.0088710375, -0.18273513, 0.06601674, 0.009983851) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.08476211, 0.043996535, 0.056711517, 0.009976895, 0.07039107, -0.024862664, -0.059921104, 0.046850603, 0.04983447, 0.04863198, 0.21777405, -0.0576961, 0.045321796, -0.0060038245, 0.096396215, -0.10842004) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.15746164, 0.041757874, 0.035169285, -0.1734288, -0.24219254, -0.13318908, 0.2272079, -0.02902605, 0.07750601, -0.1467191, -0.12296749, -0.07533314, -0.07073083, 0.17909113, 0.04789308, 0.17245363) * go_0(0.0, -1.0);
|
||||
result += mat4(0.057547905, 0.1464685, -0.33115456, -0.26956198, -0.26298407, -0.059824817, 0.022509675, -0.09251868, 0.36277944, -0.2072429, 0.21095088, -0.45492023, 0.07428653, 0.1593302, -0.2945834, 0.12825087) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.1318458, 0.27804148, 0.037600737, 0.12047866, 0.0065036337, 0.0017241207, 0.060497303, -0.14786585, -0.15149063, 0.02731698, 0.048886403, -0.0025970868, -0.026979815, 0.07348884, 0.015636757, -0.107966796) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.079988025, -0.01626299, 0.06517438, 0.086406484, -0.1484504, 0.070595, 0.20620634, 0.09713373, -0.13620836, 0.012067949, -0.00068703433, -0.038030174, 0.22300471, -0.0012400965, -0.014827909, -0.08927486) * go_0(1.0, -1.0);
|
||||
result += mat4(0.15634936, 0.052028038, 0.038081627, 0.12720168, 0.07342066, -0.04318368, -0.0065998454, 0.12109317, -0.45398173, 0.03666754, -0.17773737, 0.038516667, -0.13009632, -0.007457001, -0.013938809, 0.09776142) * go_0(1.0, 0.0);
|
||||
result += mat4(0.029636936, 0.12864171, 0.11347291, -0.11812842, -0.0870342, 0.035678383, 0.050338242, 0.045754932, -0.07072752, 0.010447726, 0.039642975, -0.08795004, -0.1191525, 0.00967509, 0.13485421, -0.053204738) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.011072695, -0.09613245, -0.09094804, 0.028029291, -0.04031162, 0.15690295, 0.25094184, -0.21776834, 0.06524669, 0.06412185, -0.052852992, -0.08097702, -0.039127756, 0.036357917, 0.104585476, 0.25095442) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.08328618, -0.006246033, 0.099708706, -0.014916097, 0.17727195, 0.4369228, 0.14760216, 0.06707674, 0.025167737, -0.022487842, -0.038962565, 0.15380669, 0.08125089, 0.09844594, 0.33538374, -0.003161368) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.0128195705, -0.05475118, -0.037705053, -0.0012077648, -0.17425515, 0.091487505, -0.12909423, 0.0074876705, 0.13438368, 5.778033e-05, 0.04563314, -0.12185897, -0.053612474, -0.049824294, -0.12851205, 0.12856449) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.025741795, 0.01867236, -0.00027440622, 0.10502768, 0.27042285, -0.14947751, 0.11143123, 0.2575913, -0.07414089, -0.33919522, -0.13194235, -0.20088726, 0.23121537, -0.08197353, 0.06693911, 0.015411386) * go_1(0.0, -1.0);
|
||||
result += mat4(0.09143717, 0.22842278, 0.06501074, -0.20009698, -0.042117566, -0.23452093, -0.074082755, -0.10612558, 0.077631965, 0.08343657, -0.07657599, -0.43297377, 0.7092466, -0.16272525, 0.17222248, -0.056038965) * go_1(0.0, 0.0);
|
||||
result += mat4(0.081200436, 0.046752565, 0.028254949, 0.18820632, 0.096592255, 0.05896745, 0.14845169, 0.034777895, 0.07195204, -0.1908046, -0.015341971, 0.02606145, -0.010377239, 0.0755547, -0.15285216, 0.047916733) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.06825636, -0.049540907, -0.024328846, 0.03506251, 0.2060094, 0.054119263, -0.06671269, 0.052428722, 0.055792283, -0.14336903, -0.03180757, 0.013760968, -0.037398104, -0.06880077, -0.023608573, 0.0360965) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.16937497, -0.30156836, 0.0021435453, 0.025772978, -0.17990975, 0.046133514, -0.32447076, -0.083382785, -0.081322014, -0.022132374, -0.05319431, 0.11794733, 0.08943906, 0.12927428, 0.105764806, -0.051034793) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.011012306, 0.047636557, 0.050260928, 0.051847618, 0.010985655, -0.13752967, 0.023869954, 0.07011459, -0.18244945, 0.07239806, -0.013638856, -0.026982805, 0.11395993, -0.031304818, -0.08714153, 0.077115685) * go_1(1.0, 1.0);
|
||||
result += mat4(0.08707592, 0.2265186, 0.13363098, -0.039588258, -0.029561255, 0.019238092, 0.024606103, -0.0019022018, -0.062285982, -0.0629511, -0.03753033, 0.109805316, 0.016018672, -0.08284564, -0.04092752, -0.030386891) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.0016500859, 0.01616536, -0.099148355, 0.24161765, 0.028064307, -0.028680569, 0.054400917, -0.1978921, -0.08584302, -0.096797146, -0.06546965, -0.09342837, 0.030265866, 0.07057579, -0.02080932, 0.053178705) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.030304352, 0.047440585, -0.04248429, 0.08568772, -0.051317703, 0.036739342, 0.00865767, -0.018183297, -0.07335176, 0.025001721, -0.068509035, 0.1814819, -0.09756565, -0.024179723, -0.05959287, 0.0352454) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.023015196, -0.022870664, -0.12028372, -0.111095205, 0.11065281, -0.19900022, -0.24012049, -0.017028643, -0.13484617, 0.050107025, 0.10741765, 0.037951697, 0.013090438, -0.0010045726, -0.029447839, -0.1859787) * go_2(0.0, -1.0);
|
||||
result += mat4(0.17922719, -0.24138594, -0.44595388, -0.032014426, 0.06897096, 0.07125395, 0.1944457, -0.035794795, -0.24022278, -0.13230884, -0.1277025, 0.21229011, -0.12249393, 0.06141907, 0.2687936, -0.26896995) * go_2(0.0, 0.0);
|
||||
result += mat4(0.0397242, -0.30710965, 0.28815824, -0.06642567, -0.07588877, -0.019552408, 0.0057806037, 0.11465521, 0.03560534, -0.10640553, 0.023589289, -0.16667193, 0.02066607, -0.01026633, -0.02655378, 0.082493655) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.007902949, -0.08501038, -0.029395591, -0.07072227, -0.01800967, -0.14564751, -0.08372804, -0.049974415, 0.1756957, -0.02042449, -0.04413007, -0.016873527, -0.2385717, -0.001741017, 0.08298281, -0.019873247) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.01803727, 0.0642893, 0.21513617, 0.066888265, -0.042107955, -0.123470366, 0.045296013, -0.11958806, 0.48208967, -0.027188249, 0.12136116, 0.05246265, 0.13522038, -0.016297493, 0.028486907, -0.059840377) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.1373251, -0.11281026, -0.06418318, 0.08444032, 0.062874556, -0.009133875, -0.049571835, -0.042995855, 0.12483249, -0.025967957, -0.11202483, 0.09862257, 0.099986054, 0.009230306, -0.09042664, 0.046612263) * go_2(1.0, 1.0);
|
||||
result += mat4(0.03203309, 0.106030256, 0.045741174, -0.020529225, -0.028610658, -0.055219248, -0.21404657, 0.07746393, -0.059359375, 0.0033258004, -0.0054513607, 0.06856653, 0.18043655, -0.119936846, -0.05639265, -0.10240379) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.0004331875, 0.10426754, -0.008130048, 0.012795991, -0.14372933, -0.40797862, 0.105197415, -0.0041354536, -0.079792455, 0.0914027, 0.012418237, -0.11449173, 0.020261409, -0.14681602, -0.13355242, 0.18290488) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.052306626, 0.010864275, -0.072627716, -0.009773121, 0.09484167, -0.09631301, 0.14896165, -0.21220942, -0.11994051, -0.002957136, -0.118194886, 0.08661347, 0.10005298, -0.029620873, 0.101668894, 0.0242806) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.055188183, -0.06322889, 0.12994595, 0.03140751, -0.092755616, 0.04239107, 0.18460171, 0.08471877, 0.014203371, 0.13608724, 0.035351243, -0.07883493, -0.10067456, 0.14417742, 0.0054235114, 0.100745104) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.043811034, -0.16055201, -0.11927185, 0.20517266, 0.16734722, 0.27720267, 0.1205665, 0.045803893, -0.07874647, 0.06764307, -0.11157022, 0.080770165, -0.044105835, -0.03276538, -0.10945451, 0.100562036) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.044731796, -0.12854387, -0.061937924, -0.21604767, -0.036132332, -0.024353411, -0.16718283, 0.14903957, -0.11620588, 0.14563644, 0.23363836, 0.08400659, 0.15248756, -0.1424437, 0.112882614, -0.04096889) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.0486021, -0.05714939, 0.042517707, -0.06106919, -0.12970918, -0.071898215, -0.044727243, -0.026308542, 0.05687118, -0.0394057, -0.109454155, -0.0021216893, 0.018588595, 0.08061093, 0.0500373, -0.0034918839) * go_3(1.0, -1.0);
|
||||
result += mat4(0.11269324, -0.17924047, -0.12965205, -0.07287767, -0.015830642, -0.044497102, 0.20014328, -0.14054494, 0.1232692, 0.2395109, 0.14093149, 0.03518561, -0.14088139, -0.09045081, -0.07283352, 0.053434785) * go_3(1.0, 0.0);
|
||||
result += mat4(0.020512339, 0.026349569, -0.06666101, 0.05554806, -0.03044066, 0.26656216, 0.019155584, -0.12118906, 0.087923005, -0.1716557, 0.050843164, 0.037432503, -0.030232614, 0.030457936, 0.04232163, -0.066400655) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.0216415, 0.09015036, -0.030761974, -0.26541537);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!SAVE conv2d_1_tf1
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.04688368, 0.13853125, 0.1714716, -0.03034447, -0.08090605, 0.1225867, 0.17535992, 0.012508419, -0.0010665918, -0.07481546, -0.15541986, 0.0671128, -0.029307734, -0.076674186, 0.03925896, -0.07140553) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.13273083, 0.062933214, 0.04200143, -0.0080243945, -0.120439716, -0.090192355, -0.022639645, 0.00020024918, -0.11211478, -0.12949537, 0.025783822, 0.009155746, 0.01004339, -0.0661901, 0.10630156, 0.053137038) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.07113487, -0.16011865, -0.10838903, -0.0034704183, 0.110606894, -0.14915739, 0.036511585, -0.003103608, -0.0551775, -0.13140677, 0.05270299, 0.12139221, 0.02226174, 0.008415268, -0.06647426, 0.118130066) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.045172617, -0.0020388453, -0.27287582, 0.002428232, -0.2833772, 0.13788106, 0.073339015, 0.10666715, 0.08455194, 0.16499293, 0.089058325, 0.008815447, 0.034657538, -0.109856166, -0.11499077, -0.02918854) * go_0(0.0, -1.0);
|
||||
result += mat4(0.07910854, -0.26334837, -0.3246593, -0.08246522, 0.09211476, 0.40793833, -0.09658794, -0.14430091, -0.50632644, 0.087234974, 0.26298127, 0.3687086, 0.06492316, 0.23082961, 0.18233871, -0.09283792) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.022744032, 0.21690565, 0.2694824, -0.12230013, -0.07969618, 0.21595429, -0.034979805, 0.008938489, 0.21289209, -0.446482, -0.042927746, -0.13587558, -0.032581557, -0.07182814, -0.054092336, -0.009542036) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.0034912943, -0.080354184, -0.08577375, -0.1521193, 0.09809233, 0.034529503, -0.100664355, 0.008191219, -0.014303411, -0.02862216, -0.18669915, -0.12384598, 0.046499267, 0.093707144, 0.10661308, 0.15079576) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.031025652, -0.0384342, 0.14258307, 0.25531343, 0.0075049917, -0.03966595, 0.062381975, 0.19593526, -0.2868182, 0.03162008, -0.4391041, -0.524017, -0.034463473, -0.0066741486, -0.24586639, 0.10521736) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.07452321, -0.0227877, -0.025402244, 0.115727395, -0.039511252, -0.07785703, -0.013689458, 0.0066024344, -0.052957747, 0.011206241, -0.0021671024, 0.077190824, -0.11709912, 0.046635598, 0.123751156, -0.03712064) * go_0(1.0, 1.0);
|
||||
result += mat4(0.055411004, -0.0020031065, 0.06685547, -0.018829947, -0.06378933, -0.18389674, -0.0023551763, 0.0670314, 0.13038594, 0.0601923, -0.03035789, -0.019537423, -0.014483204, -0.056800704, 0.08663347, -0.106859975) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.06603686, 0.07360526, -0.0072026253, -0.06778907, -0.039178446, 0.012397263, -0.13482279, 0.05745685, -0.055182382, -0.10545766, 0.003857615, 0.041947857, -0.15239377, 0.041826613, 0.058879383, -0.0042669442) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.0697229, -0.010702144, -0.032265816, 0.013317131, 0.105028264, 0.21032134, 0.06845646, -0.018358687, 0.064568676, 0.08437135, -0.000723181, 0.1324007, 0.05527932, -0.049871888, -0.10125047, -0.005040889) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.006467578, -0.05120533, -0.011780779, -0.011742203, -0.34242442, -0.020819988, 0.17381702, -0.059836414, -0.028882682, 0.23210457, 0.16579404, -0.03708216, -0.23541835, -0.03290251, 0.029319672, 0.26189178) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.30955994, -0.06408282, -0.16872866, 0.10767772, -0.041430887, 0.051697977, 0.12523535, -0.060389146, 0.026289431, 0.06359533, 0.13526368, 0.2479901, -0.3263977, 0.10216362, -0.0030894123, 0.046437826) * go_1(0.0, 0.0);
|
||||
result += mat4(0.10061438, -0.17047118, -0.21593021, -0.023389054, -0.17507865, -0.30822313, -0.22044766, 0.16078933, 0.07099252, -0.11573018, 0.24712858, -0.0659458, -0.037504572, -0.12297423, 0.03342632, -0.058119852) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.020957774, -0.0224927, 0.04069268, -0.07911167, 0.074009344, 0.065916434, 0.008222278, 0.11625076, -0.25299504, 0.03357169, -0.021988, 0.015821831, -0.0021187372, -0.030700417, -0.004374924, 0.027358979) * go_1(1.0, -1.0);
|
||||
result += mat4(0.06549052, -0.048067164, 0.05489091, -0.28851983, 0.13378961, 0.026875904, -0.09877994, -0.19947459, -0.1274035, -0.022928834, -0.26344195, -0.025870804, 0.022505255, 0.0070861108, 0.121051334, -0.025964163) * go_1(1.0, 0.0);
|
||||
result += mat4(0.059426542, -0.0327433, 0.2313695, -0.07046268, 0.20479666, 0.027021704, 0.2564928, -0.11689885, -0.07407976, -0.019611249, 0.093463086, -0.121553615, 0.035009407, -0.008135333, -0.075931996, 0.047803063) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.059434246, -0.1652242, -0.124611154, 0.04743711, 0.10530296, -0.13869187, -0.036534663, -0.035206333, 0.06067593, 0.06126907, 0.120151915, -0.06722673, 0.008103894, 0.037225723, -0.007520425, 0.065720856) * go_2(-1.0, -1.0);
|
||||
result += mat4(-3.6759695e-05, -0.036789574, 0.013370567, -0.037871476, -0.013454664, 0.15086569, 0.10164699, 0.057703357, -0.12871023, 0.12827681, -0.055057358, -0.040753044, -0.0142621, 0.08563361, -0.04615499, -0.03130452) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.117965914, 0.09056485, 0.07272314, 0.009695964, -0.11331058, 0.07467256, -0.08291521, 0.00937355, -0.04097737, 0.07752905, -0.017335521, -0.12539999, 0.039462104, -0.0007037007, 0.06034812, -0.09497377) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.20828065, 0.0400099, 0.047638226, -0.046423353, -0.026133502, 0.098207295, 0.056742374, 0.017029466, -0.058164768, -0.046973787, -0.17328712, -0.0012984811, 0.050085854, 0.11296557, 0.12639083, 0.058543045) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.098907426, 0.22031747, 0.101559944, 0.06616554, 0.026110496, 0.56487054, 0.23754556, -0.07540935, 0.31768414, -0.47653618, 0.015073956, -0.33731326, 0.087285936, -0.24593173, -0.26141426, 0.15003823) * go_2(0.0, 0.0);
|
||||
result += mat4(0.046026446, -0.13767281, 0.064847544, 0.07717139, 0.08544123, -0.11092969, 0.072325274, 0.010849038, -0.3055905, 0.66436774, 0.1434729, 0.0494463, 0.07115603, 0.083811216, 0.020431712, 0.06537088) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.15532711, 0.030139687, 0.040853374, 0.11089222, -0.08150315, -0.015851755, -0.06787692, 0.096075505, -0.011956207, -0.0017758606, 0.1277494, 0.16156575, -0.038588695, -0.0626418, -0.041797023, -0.19467135) * go_2(1.0, -1.0);
|
||||
result += mat4(0.12917455, 0.017410474, -0.20125067, -0.08040003, -0.13494664, 0.17789102, -0.19909395, 0.08441434, 0.078570575, -0.06330619, 0.23767303, 0.5442659, -0.009227878, -0.021818208, 0.14318731, -0.09042824) * go_2(1.0, 0.0);
|
||||
result += mat4(0.097801, 0.09345441, 0.17846581, -0.14773296, 0.06536365, 0.07642184, -0.011880635, 0.02086135, 0.013336972, -0.053295113, -0.13410404, 0.027241753, 0.087728985, -0.044033397, -0.13098569, 0.009423933) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.02488427, 0.0134966355, -0.0075000813, 0.07272353, 0.015842725, 0.13765687, 0.028079558, -0.08384948, -0.06666623, -0.023220664, 0.025091043, -0.055167805, -0.18826278, 0.04423603, 0.13499942, 0.059128854) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.01935146, -0.030980906, -0.031569187, -0.0036869382, 0.036753897, 0.118464164, 0.15871695, -0.09842428, 0.023324292, 0.071796335, -0.07869346, -0.10751301, -0.2588698, 0.064011686, 0.17386378, -0.039197855) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.08590827, 0.005497696, -0.026512025, 0.015661815, 0.1102415, -0.08268483, -0.0032903247, 0.10049029, -0.008157236, -0.035823178, -0.017570151, -0.081716835, -0.3531045, 0.010005245, 0.017141227, -0.016376914) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.16617337, -0.007689783, 0.00954665, 0.07117733, -0.001669262, -0.012331606, 0.051613946, 0.062780835, 0.06123557, -0.20243123, -0.19181818, 0.032895602, 0.19760677, 0.004464939, 0.12754539, -0.27360034) * go_3(0.0, -1.0);
|
||||
result += mat4(0.15006685, -0.083587274, -0.03215495, -0.16992462, -0.011944293, 0.058361508, -0.088097006, 0.023880545, -0.04168166, -0.06960282, -0.092672385, -0.057278465, 0.23540072, -0.1721208, -0.018213503, -0.23494521) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.124885194, 0.1905868, 0.11108704, 0.03163991, 0.11383064, 0.101223364, 0.069428995, -0.14298953, -0.07609092, 0.13704266, -0.07749446, -0.0005389336, -0.04617235, 0.18011934, 0.08350316, 0.09416366) * go_3(0.0, 1.0);
|
||||
result += mat4(0.073356606, 0.067966126, -0.21285574, 0.0782625, -0.0034364646, -0.032581426, -0.05538558, -0.1317288, 0.14552782, -0.1132393, 0.13063973, -0.00833602, 0.0026844777, 0.028135289, -0.02536825, -0.028372496) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.318728, 0.07862527, -0.12176221, 0.35010242, -0.029198067, 0.016302662, 0.17667587, 0.12605923, 0.1556697, -0.06061443, 0.05843511, 0.10891248, 0.01267106, -0.018492714, -0.15945031, -0.050723754) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.21555941, -0.016813517, -0.084676236, -0.07545412, -0.14518794, -0.014592766, -0.2446481, 0.0530632, 0.0847341, 0.12342537, -0.028644923, 0.083479315, -0.04179012, 0.0025225023, 0.16006976, -0.026940256) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.060742114, -0.037577342, 0.055704296, 0.03134311);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.13129333, -0.022117995, -0.009753253, 0.020439912, 0.044090994, -0.0916335, 0.0036765633, -0.11719207, -0.06413809, 0.04079378, -0.00085516454, -0.06306388, -0.12660664, -0.054126263, -0.005513979, 0.06364538) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.028422508, 0.23270117, -0.28674677, -0.10820166, 0.024321957, -0.0811145, -0.07290707, -0.02125165, -0.064260505, 0.052076746, -0.009654081, 0.08363882, -0.02037171, 0.15006389, 0.121593125, -0.011237004) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.14672333, 0.015381624, 0.1028172, -0.041823238, 0.0072677187, -0.042953942, 0.06426537, -0.0938381, -0.05990813, -0.04599802, -0.11264726, -0.027826328, -0.058160868, 0.10747306, -0.07327458, 0.07998872) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.08702181, -0.03750975, -0.045659006, 0.04488332, 0.09102003, 0.066556975, -0.04353586, 0.08994567, -0.13561495, -0.10653702, 0.006989605, 0.028230097, 0.07177144, 0.2938447, -0.00943923, 0.022120917) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.1801194, -0.11119162, 0.1977298, -0.247902, -0.16654298, -0.07423158, 0.114130594, 0.0014401592, 0.006954727, -0.09810646, -0.051310766, 0.19487657, 0.2545855, -0.06328558, -0.04617056, 0.09444692) * go_0(0.0, 0.0);
|
||||
result += mat4(0.011378825, 0.16044368, 0.017211074, 0.14472178, 0.032992378, -0.008925819, 0.035120245, -0.012409223, 0.074333005, 0.1178002, -0.128956, -0.13624239, -0.2791275, 0.21457297, -0.1476131, 0.04874687) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.03491764, -0.061763793, 0.05779039, 0.0054837577, -0.023937583, 0.08281698, 0.032306053, -0.014566218, 0.12738499, -0.0132100545, -0.051833414, 0.0057818824, 0.012158851, -0.20231532, -0.0043795826, 0.10285843) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.22269921, -0.15135509, -0.039143335, 0.033390045, 0.06770212, -0.14538582, -0.08011057, 0.03796648, -0.025913516, 0.13925864, 0.18309896, 0.012709204, -0.24912506, 0.3217706, 0.0394195, 0.017977878) * go_0(1.0, 0.0);
|
||||
result += mat4(0.00080196525, 0.059145816, 0.05720508, 0.0056548906, 0.005168018, 0.09938438, 0.0200503, -0.05516137, 0.061309986, -0.019621318, -0.1541441, 0.019540716, 0.030571707, -0.09054893, 0.032851614, -0.27210873) * go_0(1.0, 1.0);
|
||||
result += mat4(0.27061436, -0.114008114, -0.0020118617, -0.1656827, 0.09770587, 0.029897455, -0.03307522, -0.04661818, 0.033011347, 0.18498488, -0.05162084, 0.087471776, -0.24665618, -0.12538423, -0.08123797, -0.010210389) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.075188264, 0.0020608555, 0.18558815, 0.041179713, 0.11232638, 0.05507779, -0.19599183, 0.027942855, 0.06199144, 0.22141005, -0.06121163, 0.014993597, 0.24105869, -0.019737717, -0.112485714, 0.0157406) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.09425698, 0.0207658, 0.12074599, 0.009430481, 0.11889248, -0.025782838, 0.0034711843, 0.05113582, 0.012531833, -0.0018606635, -0.09137569, 0.018120576, 0.4051155, 0.02222076, -0.16001017, 0.10981527) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.03582557, 0.014994796, -6.4688604e-05, 0.24618183, -0.11697727, 0.24388117, 0.038502026, -0.3511993, 0.101741396, -0.10748137, 0.035059888, -0.017535849, 0.09450039, 0.06541661, 0.12149035, 0.28798738) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.27143848, 0.017990451, -0.69144464, 0.037944376, -0.04551905, 0.09263134, 0.4259611, -0.14107811, -0.10641847, 0.23065196, 0.040813655, -0.07789163, 0.3087666, 0.08190437, 0.16409059, -0.06455426) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.08290655, -0.35286915, -0.18082355, -0.32229406, 0.1608227, 0.030915622, 0.09207708, 0.02655054, 0.039464593, 0.026095424, 0.052584656, 0.033881903, -0.01751319, -0.0011676399, 0.04002607, 0.1630013) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.012021132, 0.12163766, -0.07410629, -0.06879096, 0.017859738, -0.039261997, -0.028677614, -0.23610398, -0.15963873, -0.0006119958, 0.11275506, 0.0082659265, 0.05677582, 0.08676638, -0.08669759, -0.10475464) * go_1(1.0, -1.0);
|
||||
result += mat4(0.12792721, 0.06888765, 0.31803077, 0.26002547, -0.067599155, -0.011822328, -0.2589909, -0.30024147, 0.11076704, 0.15200609, -0.018180368, -0.19146141, 0.22298847, 0.059484895, 0.034478076, 0.15610938) * go_1(1.0, 0.0);
|
||||
result += mat4(0.0870121, -0.016420847, -0.011579898, 0.097182855, -0.120095566, -0.06843338, -0.043460473, -0.060684606, -0.027540063, -0.008499213, 0.033570655, -0.06866259, 0.01429712, -0.07424434, 0.0009466247, 0.09142678) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.03781424, 0.04587032, 0.03744051, 0.02712279, -0.051038064, 0.0669144, -0.02640278, 0.12384894, -0.0022533627, -0.010022036, 0.07536463, -0.030489929, 0.09418577, 0.155089, -0.011290433, -0.02102941) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.0053278613, -0.07160643, 0.039028414, 0.04123311, -0.10693177, -0.1170874, 0.07230816, -0.033255517, -0.119176835, 0.0786526, -0.11880206, -0.11354601, -0.037539184, 0.14404313, 0.069760695, 0.024738638) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.03413808, -0.006487654, 0.10006853, 0.22228058, -0.13796462, -0.14042488, 0.04017443, -0.031790894, -0.06673143, 0.009888688, 0.08831443, -0.0045771743, -0.028375361, -0.04704813, 0.07128581, -0.07012518) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.06954315, -0.23728988, -0.14192343, -0.08236467, -0.2552115, 0.04102959, -0.06355397, -0.08340241, 0.17617856, 0.20281969, -0.16249381, 0.10843737, -0.04392261, -0.08587206, 0.053069845, -0.15482199) * go_2(0.0, -1.0);
|
||||
result += mat4(0.124981806, 0.12828638, -0.061472785, -0.20108232, -0.14905351, -0.40766275, -0.35427195, -0.13183996, 0.09307428, -0.07697028, 0.06702549, -0.22656697, 0.019868268, -0.19361132, 0.08784669, 0.20249842) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.004661343, -0.09333453, -0.24876262, -0.07906779, 0.110697776, -0.37069768, -0.042212646, -0.0046135853, -0.2254257, -0.023392014, 0.031476703, -0.045574382, -0.12675518, -0.076056994, -0.08228006, -0.040303517) * go_2(0.0, 1.0);
|
||||
result += mat4(0.16182694, 0.0512523, 0.051189836, 0.048962783, -0.05156489, -0.17987493, -0.012037288, 0.06953726, -0.09458492, 0.1610021, -0.004063283, -0.032922342, 0.08995396, 0.1939926, -0.018710036, -0.08153231) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.064830944, 0.06121252, -0.18886387, -0.12976822, -0.031117212, 0.12219633, 0.19070715, 0.12495262, -0.11994464, -0.24687837, -0.08425294, -0.016920334, -0.13286817, -0.3260188, -0.11776061, 0.1651019) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.17652592, 0.002499805, -0.030541016, -0.01393431, 0.031418208, 0.08209422, 0.12430871, 0.4387016, -0.108871914, -0.09041422, 0.031226631, -0.1638517, 0.20756467, 0.014476537, -0.012701195, -0.03440563) * go_2(1.0, 1.0);
|
||||
result += mat4(0.005320072, -0.0032291536, -0.017209187, 0.031944863, -0.2479921, -0.24433962, -0.13832912, 0.07835928, -0.17707248, 0.028202811, -0.19121435, 0.164587, 0.123152815, 0.0050288937, 0.084104605, -0.0380019) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.16008669, -0.018608516, -0.013778938, 0.033447385, -0.01242472, -0.070916265, 0.026909694, -0.07318777, 0.15158044, 0.12047607, -0.1709358, 0.2031767, 0.0025611701, -0.21457459, 0.2791286, 0.10159932) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.14320926, 0.020023825, -0.0484187, 0.011563084, -0.2640472, -0.013056275, 0.004234292, -0.095376395, 0.28363484, -0.0058227647, -0.0777649, 0.05238444, 0.41757923, -0.07081097, 0.012567031, -0.13029522) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.07266207, 0.042793367, -0.08212271, -0.23401663, -0.19457819, 0.4191269, -0.03095442, 0.15339781, -0.28451788, 0.09316364, 0.10231693, -0.22844811, 0.111623526, 0.120017685, 0.18777381, 0.014420896) * go_3(0.0, -1.0);
|
||||
result += mat4(0.15037206, -0.29763284, 0.2601235, 0.0193363, 0.13686465, 0.009907918, -0.37781665, 0.04916627, 0.14114739, 0.5043813, 0.0447959, -0.029427614, 0.041768756, 0.27211213, 0.14163221, 0.086162075) * go_3(0.0, 0.0);
|
||||
result += mat4(0.19159287, 0.21363218, 0.15053211, 0.08992885, 0.100828275, 0.09379921, 0.030783929, 0.11664482, -0.059145752, -0.19400764, -0.09351283, -0.016430443, -0.12910964, -0.067078374, 0.11760082, 0.121194765) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.055059325, 0.09299572, 0.06848913, 0.06334532, -0.1476285, 0.111801244, -0.033960916, 0.06474366, -0.04952303, 0.27885208, -0.052447475, 0.09226763, -0.15024844, -0.0033919013, 0.013498364, 0.09135676) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.017010042, -0.122343406, -0.19097193, -0.27957183, -0.18206005, 0.102321096, 0.22794476, 0.0439245, -0.23710132, -0.08070259, 0.17377135, 0.23811814, 0.17799385, 0.049567625, 0.1470908, 0.07329385) * go_3(1.0, 0.0);
|
||||
result += mat4(0.0038071256, 0.19454515, -0.01222965, -0.07390379, -0.0532754, 0.03942833, 0.123840906, 0.023459576, -0.0658742, -0.023957543, -0.14682837, 0.1221027, -0.010986398, -0.066184506, 0.03026491, -0.0638446) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.06427697, -0.00039365015, 0.011889719, 0.060232002);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!SAVE conv2d_2_tf1
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.012110923, 0.07818654, 0.07964548, 0.11885079, -0.07694473, -0.01378252, 0.006632789, -0.12876098, 0.0069211307, 0.022278586, 0.069553085, 0.16569804, -0.11123615, 0.06125189, -0.11232848, 0.1559266) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.3261174, -0.25586754, 0.21129315, 0.3135101, 0.1509055, 0.0044283345, 0.024674175, -0.08000473, 0.01213029, 0.09093019, 0.04942677, 0.09806723, -0.16454464, -0.14433062, -0.058094524, -0.060819894) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.023174008, 0.02858724, 0.07685972, 0.036857616, -0.10415571, 0.10241035, -0.01893166, 0.02065923, 0.058356714, 0.096426114, -0.03772327, -0.1529002, 0.13740575, -0.048291504, -0.06152548, -0.15199897) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.029300174, -0.13222043, 0.0139825605, -0.02274408, 0.062944874, 0.028447356, 0.05960515, 0.034447193, 0.03133432, -0.019283533, -0.024591971, -0.0043914663, 0.15245225, 0.006851478, -0.051783554, 0.17453748) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.09125915, 0.081739366, 0.01196335, 0.23130219, -0.22557035, -0.13537665, 0.0022028848, -0.043430023, 0.22759882, 0.07920754, -0.027986467, -0.14051494, -0.19557038, -0.03585936, -0.4258294, -0.03856216) * go_0(0.0, 0.0);
|
||||
result += mat4(0.18511422, -0.09368415, 0.1551229, 0.04322566, -0.023400841, -0.02261204, 0.15129441, -0.007954805, -0.10739125, 0.019459398, 0.013128325, 0.018073296, 0.20886365, -0.20662378, -0.03814699, -0.09272838) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.027352437, -0.039882626, 0.12598103, -0.093930446, 0.030846786, -0.09325075, -0.009084744, -0.024584265, 0.07159868, 0.14162529, 0.19019091, 0.058855128, -0.09880401, -0.01843218, 0.14753596, -0.2449532) * go_0(1.0, -1.0);
|
||||
result += mat4(0.06565521, 0.09150168, -0.08654865, 0.0829788, -0.07596146, -0.01815166, -0.08786775, -0.03477514, 0.20538878, -0.012766377, 0.020719538, 0.088188395, -0.034300096, 0.29972988, -0.20005241, 0.018425167) * go_0(1.0, 0.0);
|
||||
result += mat4(0.11713916, 0.024167519, 0.05167596, -0.0027117804, -0.016994188, 0.048177514, -0.012556207, 0.010979094, 0.09098878, 0.028514355, 0.06063336, -0.06624107, 0.012754856, 0.013208708, -0.061374772, -0.0025992664) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.09053513, 0.03183455, 0.017340872, 0.12934409, -0.022161964, -0.0015361432, -0.049972344, -0.12763855, 0.12779881, -0.04697911, 0.018968226, -0.119873665, 0.05462772, -0.13919477, -0.10226718, -0.2540179) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.29912186, -0.09291771, 0.050926663, 0.49361777, 0.21372582, 0.076717265, -0.058968987, -0.1572678, 0.3194591, -0.120582424, 0.03942037, 0.023128232, 0.24321598, 0.07046334, -0.21204855, -0.648296) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.05366883, -0.020366706, 0.020979457, -0.06893884, 0.04837168, 0.017253762, 0.008874203, -0.020785445, -0.20425391, 0.060179923, 0.046167206, 0.09863377, -0.14381303, 0.038928367, -0.06590863, -0.18408588) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.07099762, 0.2029403, -0.033945918, 0.15202214, 0.0901113, -0.27336198, -0.17693861, -0.16206753, -0.17642029, 0.09400492, -0.11165698, -0.07863893, -0.16306102, -0.056210615, 0.22173557, 0.013508989) * go_1(0.0, -1.0);
|
||||
result += mat4(0.08541511, -0.27093616, -0.35273993, -0.48919773, 0.038383547, -0.16013749, 0.012996215, -0.03434873, 0.07024113, -0.28971404, 0.10623425, -0.0019642068, -0.062374946, 0.3291145, 0.22468035, -0.42971882) * go_1(0.0, 0.0);
|
||||
result += mat4(0.020427933, 0.15062793, 0.08308975, -0.025095072, 0.030093266, -0.09649862, -0.03382388, -0.0016017791, 0.105402954, 0.020693144, -0.051065, 0.07704679, 0.02864139, -0.00135146, 0.03762216, 0.029277142) * go_1(0.0, 1.0);
|
||||
result += mat4(0.01700994, 0.12214317, 0.06749582, 0.07354159, -0.093085855, -0.065021954, 0.010773045, -0.00095128635, -0.045384295, -0.072611265, -0.043900184, 0.049471326, 0.029131187, 0.03180158, -0.13313527, 0.05280797) * go_1(1.0, -1.0);
|
||||
result += mat4(0.14751251, -0.15087761, 0.09932281, -0.099232934, -0.062390897, 0.112391844, -0.09159478, 0.15856399, 0.034708973, 0.01819943, -0.02730164, -0.13562973, -0.05687333, -0.0114601655, 0.07025971, 0.02496533) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.0117268525, -0.026162883, 0.07481553, 0.13420302, 0.029870516, 0.07405776, -0.06379041, 0.09631234, -0.07754842, 0.035888605, 0.0034764851, -0.040771756, -0.092022054, -0.034230903, -0.02281844, -0.0028173258) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.059846643, 0.016772347, -0.02287152, 0.07036337, -0.024946844, 0.09826078, -0.068491876, 0.20852126, 0.073890835, -0.058288682, 0.013093785, -0.05776076, 0.0516503, 0.052794468, 0.10837015, 0.038539834) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.16391893, -0.008062687, -0.35022175, 0.2510062, -0.15820411, 0.048403125, 0.024878092, 0.037888516, -0.035924178, -0.068953894, -0.025386479, 0.24405715, -0.018495679, -0.051277515, 0.14754932, -0.031538483) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.038429607, -0.047140498, -0.018157095, -0.029318782, -0.04094171, -0.11870087, 0.11214255, 0.07142628, 0.021007229, -0.005681072, 0.1662777, 0.10829575, 0.112268396, 0.03567479, -0.06738845, 0.0032037434) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.032217573, 0.2102397, -0.20617546, -0.07920811, 0.12918773, 0.054486286, -0.13656865, 0.05806265, 0.01963165, 0.049910642, 0.15538268, 0.10724465, -0.09697837, -0.03070673, -0.0071386313, -0.11899626) * go_2(0.0, -1.0);
|
||||
result += mat4(0.130827, 0.0051715383, -0.07212691, 0.45726067, 0.2773031, 0.2973666, 0.3951691, 0.01333662, -0.14561643, 0.04508669, 0.121690124, 0.13326228, -0.22579186, 0.058161184, 0.09281702, -0.00079749606) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.00771113, 0.09912341, -0.41895548, -0.06705759, 0.029148718, 0.052991726, 0.18665347, -0.031787418, 0.23053595, 0.09444956, 0.10691037, -0.06325714, -0.05335701, 0.1917427, -0.0065284846, 0.032622546) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.056801565, -0.019131258, -0.0939022, -0.08130343, -0.11051993, 0.0035269214, -0.047361933, -0.0543875, 0.10854369, 0.06445185, 0.016828364, -0.022595318, 0.1450623, 0.033027507, -0.020425137, 0.16169788) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.08747717, 0.07770065, 0.018155783, 0.07160794, 0.09860347, -0.04329888, -0.0043579484, -0.2014418, -0.060260013, 0.0036374568, -0.17566042, -0.2268221, 0.001273691, -0.2609373, -0.19417606, -0.04102927) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.086845055, -0.114253804, -0.13433142, -0.025941795, -0.0155711295, -0.13578776, 0.12059696, -0.08760523, -0.0057348222, 0.12164273, 0.07270617, -0.06352636, 0.08894258, 0.04140841, 0.1230304, -0.030357126) * go_2(1.0, 1.0);
|
||||
result += mat4(0.03320213, 0.015911903, -0.06288296, -0.121976145, 0.2713457, 0.13913193, -0.092420585, 0.105714336, 0.10294281, -0.04591945, -0.11767934, 0.032249406, -0.06506192, -0.04639334, 0.08137017, -0.031746846) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.13717805, 0.0071242675, -0.077256985, -0.14974317, -0.08467893, -0.20126395, -0.06240603, 0.09554399, -0.075844854, 0.28380412, 0.046030026, 0.053188596, 0.50943077, 0.1179795, 0.32203588, -0.06712207) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.18528835, 0.0016975187, -0.0041140947, 0.11234392, -0.34049067, -0.056880493, -0.04325441, 0.09905571, 0.10978758, 0.009608353, -0.10801905, -0.04071131, -0.09096832, -0.12350487, 0.011801418, 0.22521795) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.040283076, -0.034117915, -0.026142653, -0.06058959, 0.12511659, 0.4131219, 0.59190845, 0.39758852, 0.16032091, -0.5975032, -0.14516282, 0.115154505, 0.03874097, 0.18462797, 0.22934213, 0.05285643) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.17804009, 0.33769128, -0.14572927, -0.029545018, 0.3897, -0.055615567, 0.15232995, 0.48788264, -0.21422523, 0.03397293, 0.0337794, -0.19830915, -0.022457365, -0.35096076, 0.42616987, -0.19268763) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.13191561, -0.18337126, 0.017879983, -0.070472844, -0.09409196, -0.025770849, -0.060219247, 0.10869267, -0.17341033, -0.09199785, -0.0667796, -0.093538545, -0.21300837, 0.030474098, -0.04540468, 0.041321553) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.0998177, -0.08669185, -0.0090886615, 0.0021083376, 0.08900095, 0.5062186, 0.45537788, 0.029077586, -0.1001008, -0.0077697043, -0.0096318, 0.11706454, 0.07401959, -0.00650215, 0.06092762, 0.037442297) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.18500404, 0.0024998419, -0.11761331, -0.026825588, 0.27255726, 0.093010515, 0.3281413, -0.051473666, -0.050259475, -0.17258662, -0.23394547, 0.104795866, 0.035074063, -0.061560635, 0.05975411, -0.094255395) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.023440497, -0.021479638, 0.0036277648, 0.004972212, 0.02416659, -0.09856867, -0.03971455, -0.27094853, 0.026615402, -0.0047890246, -0.13755885, 0.16591635, -0.0016293586, 0.133207, 0.047790572, 0.029041538) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.0063728676, -0.029053684, -0.052831043, 0.006475641);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!SAVE conv2d_3_tf
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.0431447, 0.047972627, 0.09522898, 0.19048582, 0.0015511789, 0.1182684, -0.065335006, 0.061233886, -0.02451869, 0.065670215, -0.015341636, 0.06836347, 0.10215459, 0.17516296, 0.0857072, 0.072732896) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.10117189, 0.049022958, -0.016017418, -0.12119866, 0.089112304, 0.016286526, -0.025251161, 0.03239003, -0.0783818, -0.086096615, -0.13673106, -0.15934734, -0.51308054, -0.061430074, -0.16208844, 0.2227776) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.011567444, 0.025550444, -0.018439503, -0.015003767, 0.11606929, -0.11613111, -0.040906087, -0.015202219, 0.03932618, -0.1106059, 0.03703376, 0.018548314, -0.12761284, -0.038109995, -0.23577367, 0.20272344) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.025444161, -0.075270735, 0.10999789, 0.16305386, 0.016178958, -0.074034974, 0.1177035, -0.077481024, -0.047774278, -0.029782977, 0.23137823, -0.2389453, 0.033015423, -0.10381626, -0.16437943, 0.20906886) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.098473966, 0.11013442, -0.18486807, 0.1907086, -0.17564997, -0.08509439, -0.42472756, -0.17446618, 0.3440862, 0.12719585, -0.12213955, -0.02246555, 0.18982963, 0.20809166, -0.36067408, 0.51116616) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.019805575, 0.07812505, 0.061653323, -0.08379226, 0.026396899, 0.009063019, -0.10845824, 0.0827647, 0.045301896, -0.07748021, -0.07435832, 0.14860612, -0.077515624, 0.010588131, -0.22704287, 0.26849246) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.02884339, -0.09512523, -0.038564682, 0.08862835, 0.041666254, -0.10532901, 0.040582962, -0.10063983, -0.15736029, -0.03644334, -0.005061672, 0.04302295, -0.046482194, -0.05262547, 0.05110866, 0.03204655) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.005932702, 0.033263832, 0.0044865874, -0.02328917, 0.056534443, -0.14084046, 0.022353357, 0.015087431, -0.2734596, -0.026544483, 0.06297078, 0.11277746, 0.06127936, 0.02466357, -0.04970561, 0.02098484) * go_0(1.0, 0.0);
|
||||
result += mat4(0.013603583, 0.036264602, 0.10985147, 0.01532773, -0.09012781, 0.1132652, -0.17016481, 0.025332611, -0.077462606, 0.02990799, -0.10627784, -0.006231141, -0.089164406, -0.051507175, -0.043900985, 0.09049239) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.15391691, 0.1915742, 0.014101639, -0.022153432, 0.06291936, -0.017871676, -0.016763045, -0.14741553, -0.011252563, -0.20720159, -0.030648025, -0.0142307645, 0.010291614, -0.09243969, -0.052940153, 0.0061574522) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.032283742, 0.030768922, 0.1070225, -0.027818602, 0.10032608, 0.0061178426, -0.03561339, -0.26687133, 0.14369439, -0.11362691, -0.08980895, 0.066520914, 0.33414948, 0.006998835, 0.09193012, -0.2857383) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.059588976, -0.02046844, -0.042585023, 0.031939838, 0.12796514, -0.06155685, 0.03540324, 0.009929082, -0.0039611827, 0.10790477, 0.049435645, -0.083034374, 0.23874004, -0.07460337, -0.020173345, -0.2006587) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.13217632, 0.052319963, -0.026713084, -0.0051368694, -0.10380872, -0.28659084, 0.0044393227, 0.005174543, -0.05092618, -0.07092548, -0.027397033, -0.01609789, 0.13699281, -0.14706929, 0.17737861, -0.23746766) * go_1(0.0, -1.0);
|
||||
result += mat4(0.19268502, 0.14133929, -0.1305119, -0.4034132, 0.057504695, -0.24550998, -0.081932545, 0.45489246, -0.29331785, 0.19625074, 0.063166246, 0.15158689, 0.6715147, -0.4610189, 0.08921431, 0.17761138) * go_1(0.0, 0.0);
|
||||
result += mat4(0.044718128, -0.011809122, 0.024131307, -0.30093196, -0.05607289, 0.047759805, 0.004210022, 0.098192796, 0.030430846, 0.008207501, 0.12266905, -0.10549182, 0.11584339, -0.091016166, -0.08635591, -0.13889709) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.19226642, 0.07147627, -0.14759602, 0.4041079, 0.0744628, -0.19612685, 0.1498252, -0.06273549, 0.017959936, 0.10858338, -0.14985329, 0.062042814, -0.13240446, -0.24362786, 0.113626175, -0.15332204) * go_1(1.0, -1.0);
|
||||
result += mat4(0.08383099, -0.13935047, -0.25981048, 0.16491203, 0.07513876, -0.28346774, 0.19722275, -0.044425573, 0.020889329, -0.22140723, 0.025403097, -0.09183192, 0.014202567, -0.18666178, 0.062913105, -0.047674105) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.1862771, 0.25878942, -0.043018065, 0.22144824, 0.016088247, 0.12113542, -0.11965952, -0.01587184, 0.07830932, -0.16069177, 0.13421321, 0.018718706, 0.09548377, 0.018543294, 0.013614677, -0.1054485) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.2121733, -0.015635416, 0.027564054, -0.085904464, 0.064805664, -0.070543915, 0.08966146, -0.06359783, 0.01131311, 0.046913184, -0.09809833, -0.092063695, -0.087217696, 0.012411829, 0.0045399712, 0.027389864) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.19307798, 0.09449126, 0.084036835, 0.30262446, 0.011706106, 0.029800637, 0.04612629, 0.006186647, 0.11228541, 0.055147965, 0.17659879, -0.023410015, 0.19965266, -0.06684007, -0.081968054, -0.052410994) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.058564443, 0.08252549, 0.058217794, 0.0864448, -0.25663558, 0.080260284, -0.0010294432, 0.05830051, -0.07684524, 0.1820709, 0.04438993, 0.019178499, -0.12425012, -0.04596089, -0.010032888, -0.0012803525) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.43352658, 0.15262963, 0.25620222, 0.22428556, 0.09667152, 0.0037820593, -0.07951691, -0.11553085, 0.12982155, 0.17988266, -0.14283511, 0.074744284, 0.03604327, 0.00452661, -0.12865154, -0.020020623) * go_2(0.0, -1.0);
|
||||
result += mat4(0.06850602, -0.18057181, 0.2093389, -0.07333886, 0.28406742, -0.048766967, 0.18114483, 0.47292945, -0.2340266, -0.06862712, 0.28263155, 0.3150323, -0.054724697, -0.16958356, 0.27928987, -0.19666018) * go_2(0.0, 0.0);
|
||||
result += mat4(0.03281329, 0.0038649621, -0.07108877, 0.10791149, 0.15235375, -0.3083721, 0.168294, 0.10379698, 0.029038485, 0.16282903, 0.04483725, -0.018684763, 0.108186625, 0.027885616, -0.019351846, 0.1623065) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.110499054, 0.31347123, 0.030852, 0.01631416, -0.1466389, 0.080429435, -0.18689284, 0.10667815, 0.20645237, -0.18004708, -0.10570413, -0.15435064, -0.019000605, -3.126077e-06, 0.037761535, -0.015040956) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.023364332, -0.023399066, 0.2712722, 0.049637552, -0.10222765, -0.2698945, 0.20991959, 0.04921932, 0.21510898, -0.0751939, -0.19781734, -0.28162366, -0.041881047, 0.0065111094, -0.04102195, 0.0982682) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.032176614, 0.019144032, -0.08985387, 0.091637276, 0.1012352, 0.0003583357, 0.07897295, -0.09531175, -0.001155058, 0.074372366, -0.026186578, 0.07283374, 0.06052053, 0.009307753, -0.03874333, -0.06228009) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.022224072, -0.15717922, -0.1406057, -0.05941157, -0.028769474, -0.21226564, -0.036570027, 0.22266355, 0.14120889, 0.014577123, 0.10216447, 0.018429281, 0.056729726, -0.055834044, 0.058146577, -0.11999068) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.009995364, -0.020045493, -0.0057422677, 0.0643022, 0.016475432, -0.030856136, 0.042140726, 0.15077904, -0.32955253, 0.0694449, 0.17931722, 0.3439302, -0.12484157, -0.10958869, -0.15755124, -0.09755644) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.008314924, 0.07704758, 0.043228816, -0.08110893, 0.099286236, -0.053224478, 0.22877018, -0.189486, -0.00798416, 0.018341504, 0.10734141, 0.0752633, -0.042524844, -0.086395286, 0.14299925, 0.026488977) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.052531082, 0.19139186, 0.12205995, -0.2573172, 0.15157184, 0.0073150825, 0.089774385, 0.06604469, -0.16528498, -0.002511137, 0.14287429, -0.07819732, 0.025014274, 0.15338829, 0.0761692, -0.02803716) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.21000335, 0.15277153, 0.08546171, 0.2816124, -0.16559112, -0.11068559, 0.47053605, -0.009787771, -0.0013089112, -0.06985127, 0.44743782, 0.25142467, -0.32670796, 0.044035822, -0.12545367, -0.2996084) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.11526387, 0.15654811, 0.099616654, 0.15473685, 0.21278231, 0.046207245, 0.117993094, -0.26825273, -0.12539764, 0.14013724, 0.17357737, -0.05387817, 0.076738276, -0.13339446, 0.15005626, -0.2108176) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.0008846504, -0.05998622, -0.028892396, 0.04784136, 0.0104263965, 0.10899508, -0.073364735, 0.077516064, -0.074248806, -0.21749993, -0.26203, 0.041161157, 0.09366407, -0.026498007, 0.0122177545, 0.03892727) * go_3(1.0, -1.0);
|
||||
result += mat4(0.04349908, 0.13671173, 0.2242545, -0.028021423, -0.03802222, 0.0052366396, -0.010709643, 0.031290106, 0.06291333, -0.024909683, -0.15439379, -0.04502091, 0.2062182, -0.5983536, -0.09670497, -0.38446042) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.008962513, 0.13044207, 0.04964221, 0.012250417, 0.012129821, 0.019985713, -0.06421885, 0.009168735, -0.044516414, 0.071368866, -0.006634213, 0.06497366, 0.08578495, -0.10586125, 0.06628038, -0.14006054) * go_3(1.0, 1.0);
|
||||
result += vec4(0.056541316, 0.041788545, -0.036094554, -0.021763096);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!SAVE conv2d_3_tf1
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.0647927, 0.053666476, -0.14723225, 0.027874574, -0.0003166473, 0.07337155, -0.061972085, -0.012667777, -0.17071614, 0.091927536, -0.051160213, 0.21336353, 0.13854574, 0.09582817, 0.032316446, 0.13838023) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.0398984, 0.108049214, 0.093780346, -0.022015186, -0.15188989, -0.1381083, 0.2998843, 0.21623154, -0.08862326, 0.025862623, 0.06895634, 0.13529755, 0.06957801, -0.0011681129, 0.105972745, -0.04722446) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.026321493, -0.04828038, -0.012545767, -0.005490858, -0.054038163, 0.075943105, -0.11526662, 0.022242405, -0.03543104, -0.12451852, -0.14911178, 0.013503498, 0.08773292, 0.09695139, -0.013498657, -0.27424073) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.018575635, -0.11321618, -0.07853153, 0.04104883, 0.0018416744, 0.11579002, 0.03685964, -0.031546146, -0.1755398, 0.23517849, -0.08095411, 0.031999595, -0.18542038, -0.26171613, -0.20567231, -0.05683613) * go_0(0.0, -1.0);
|
||||
result += mat4(0.1538556, 0.21723682, 0.12131733, -0.15308167, 0.103326, -0.006956118, 0.043583486, -0.23811384, -0.103285454, 0.05543916, -0.37894246, 0.32072112, 0.22651967, 0.03516268, 0.34612176, 0.23688535) * go_0(0.0, 0.0);
|
||||
result += mat4(0.040021293, 0.0029912095, 0.04885362, 0.061496444, 0.016926387, -0.118446946, 0.038948335, -0.0934512, -0.25194243, -0.054018084, -0.07149527, 0.017903058, 0.0845516, 0.33802906, 0.11953944, -0.081294954) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.09558082, -0.36974236, -0.07524102, 0.11131445, 0.047626104, 0.12854609, -0.10264962, -0.044669047, -0.05572307, 0.34475142, -0.16806377, -0.0037204176, 0.03400533, -0.04047774, 0.024379745, 0.09056291) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.039392482, 0.2553437, 0.11705501, 0.03219211, 0.073977776, -0.16610906, -0.032796364, -0.054669864, -0.07123178, 0.00079619256, -0.36920992, -0.029054813, 0.12830003, 0.004987549, 0.08724278, -0.029499404) * go_0(1.0, 0.0);
|
||||
result += mat4(0.021272454, -0.063295126, 0.011779576, 0.103093, -0.011095461, 0.027948728, -0.014605259, -0.04723974, -0.05334346, -0.044831257, -0.07296399, -0.03314197, -0.01687865, -0.09261895, -0.06128567, 0.092708185) * go_0(1.0, 1.0);
|
||||
result += mat4(0.0077418387, 0.00871427, 0.060824487, 0.1093608, -0.021077013, -0.057341542, -0.04769576, -0.08144089, 0.0212823, -0.06731425, -0.04134463, -0.0016761447, -0.03402026, 0.036424547, 0.11689576, -0.14946719) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.18536687, 0.020073935, 0.17041959, 0.024790209, 0.08397728, -0.13884324, 0.013950321, -0.055075396, -0.09317963, -0.05723721, -0.060491834, 0.0017911601, -0.109154835, 0.010338362, -0.1982491, -0.21752335) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.031852514, 0.031424347, 0.07817056, 0.07770759, 0.019805199, -0.091223724, 0.11914662, 0.1673029, -0.018734453, 0.16275099, 0.23245652, 0.36139074, -0.1396047, -0.14774057, 0.13756078, -0.123794965) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.034937833, 0.20777488, 0.10104809, -0.035140667, 0.2536575, 0.010970045, 0.16896339, -0.081219964, -0.062478427, -0.0010431948, -0.027980985, 0.11446318, -0.127309, 0.21002083, 0.044436257, -0.16986957) * go_1(0.0, -1.0);
|
||||
result += mat4(0.06309646, -0.042341243, 0.36642808, 0.18653205, 0.06973023, 0.06315932, -0.323688, 0.25672218, 0.042820994, 0.13792914, -0.12892757, -0.09220378, -0.18939693, 0.03862022, -0.17376114, -0.24673308) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.02130602, -0.35428852, -0.011634983, -3.9823462e-05, 0.110818714, -0.2981158, 0.060209107, 0.012538829, -0.0744833, -0.050204318, -0.12676497, -0.031484153, -0.28799182, 0.22338839, -0.070876874, -0.02102363) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.07929991, 0.014598492, 0.23034762, 0.024872296, 0.07480494, -0.17139243, -0.014421178, 0.056448363, -0.028626937, -0.022152562, 0.044871796, -0.048653606, 0.009350802, 0.019022083, -0.08554845, -0.0922645) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.027405115, 0.1831188, 0.28516722, 0.19882526, 0.27299204, -0.06910511, 0.03244419, -0.0031333128, 0.061055277, -0.114398144, 0.03729459, -0.07840815, -0.37776002, -0.24129418, -0.54815483, -0.2702045) * go_1(1.0, 0.0);
|
||||
result += mat4(0.053723935, 0.13472083, 0.09563273, 0.19009806, -0.18722993, -0.25939655, -0.016197463, -0.067061596, 0.1647598, 0.061905228, 0.06191816, -0.018582113, -0.07218153, 0.11278394, 0.05478068, -0.104871586) * go_1(1.0, 1.0);
|
||||
result += mat4(0.0036616288, -0.045782693, -0.226954, -0.05043515, -0.078096785, -0.036197383, 0.09269631, 0.016823346, -0.0060579977, -0.041455746, 0.09032774, -0.09217121, 0.058089796, 0.060311552, 0.033079024, 0.022586476) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.0436363, -0.079482526, 0.0027447809, 0.039558932, 0.13275702, 6.898711e-05, -0.21961488, -0.11315821, 0.0076181027, -0.025279062, -0.15829584, -0.063141204, 0.062049046, 0.13117202, -0.02435016, 0.109555416) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.010148116, 0.056620967, -0.015910713, -0.07370375, 0.1529919, 0.005792597, 0.02771225, -0.17027487, 0.096740395, 0.063347995, 0.17823112, 0.054105148, 0.04995114, -0.28613812, 0.06369567, 0.15978208) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.13688345, 0.16967694, -0.061759472, 0.013682004, -0.1290496, 0.07167547, -0.065592445, -0.17897636, 0.057080988, 0.035630587, 0.09140394, -0.08695068, 0.16807681, 0.014749346, 0.07875138, 0.034913708) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.098915346, -0.31459075, -0.10892429, 0.1557498, -0.19764107, -0.26881596, -0.03589311, 0.45288458, -0.34171388, 0.12675741, 0.18415868, -0.19770056, 0.29025507, -0.15812592, 0.09685835, 0.0027761247) * go_2(0.0, 0.0);
|
||||
result += mat4(0.06425249, -0.01169722, 0.06379363, 0.053835012, -0.07356561, -0.06367294, 0.108630784, -0.14137438, 0.08536725, -0.03209748, 0.07250959, -0.014214082, 0.07170588, -0.25647813, 0.1092683, 0.18791042) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.023783233, 0.14261739, 0.102011986, -0.03633555, -0.05032627, 0.09378387, 0.11764051, 0.1353335, 0.032817088, -0.1352964, -0.00667997, -0.13388929, 0.022861317, 0.0037358075, 0.018605746, -0.0009892831) * go_2(1.0, -1.0);
|
||||
result += mat4(0.22419162, -0.23105696, -0.09900454, -0.15831396, 0.12398773, 0.097933106, -0.13189293, 0.1330756, -0.19673057, -0.037342317, -0.13462654, -0.08974021, 0.030326528, -0.0815862, -0.118352115, 0.009187904) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.012130391, -0.06408448, 0.13710785, -0.06678414, -0.09970725, -0.14895032, -0.02366641, 0.029581001, -0.07101809, 0.09414698, 0.018300869, 0.009139046, -0.0027311493, -0.2359952, -0.011602826, -0.007582444) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.15473361, -0.06868751, -0.030721204, -0.08650113, 0.071349874, -0.08177769, 0.1611948, 0.18305337, -0.0144878505, 0.10975452, -0.026968453, -0.04909913, -0.059665974, 0.056036238, -0.11623168, -0.10584912) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.096973225, 0.054132458, -0.010600018, 0.089397885, -0.0031138035, 0.037452973, 0.041115325, 0.1924831, 0.14759748, 0.032560788, -0.082884625, 0.0324635, -0.083511285, -0.050381303, 0.025589975, -0.0981257) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.09183111, 0.034952193, -0.048511654, 0.020719057, 0.1863456, 0.01902738, 0.14455654, -0.008500172, 0.16385981, -0.07806569, -0.031216217, -0.17002788, -0.08882952, 0.07335293, -0.2223089, 0.01706056) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.08361569, 0.046698716, -0.016646344, 0.09351987, 0.0054158634, -0.13641126, -0.12396605, 0.011380122, 0.040951792, -0.11222528, -0.0031548145, -0.0022303525, 0.0350846, -0.03280425, -0.09972476, -0.113325305) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.19961461, -0.27561286, -0.12783135, -0.062596925, 0.005870981, -0.24796526, 0.18717633, -0.16945636, -0.076396205, -0.08411448, 0.13751988, 0.21014418, -0.008655945, -0.09848541, -0.14536901, -0.2132181) * go_3(0.0, 0.0);
|
||||
result += mat4(0.14118621, 0.20831147, -0.020545695, 0.008340737, 0.016840864, -0.16912372, -0.121718146, 0.15108089, -0.19803092, -0.07827729, -0.047639225, -0.12277847, 0.04974115, -0.09349339, -0.2756667, -0.19581003) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.0036992705, 0.16539848, 0.022026122, 0.07740234, -0.035687633, -0.004568715, 0.017408118, -0.09757294, -0.094941914, -0.3381112, -0.12724453, 0.025583982, -0.18571027, 0.047607586, -0.0704089, -0.055323426) * go_3(1.0, -1.0);
|
||||
result += mat4(0.13821335, 0.028168043, 0.09990671, -0.032266147, -0.067236245, 0.11512147, -0.112986445, -0.10818019, -0.10062181, 0.21276556, 0.01681818, 0.069806606, 0.09628121, 0.06456379, 0.10394843, -0.02343886) * go_3(1.0, 0.0);
|
||||
result += mat4(0.041937463, 0.072631165, 0.045366894, -0.0046993676, 0.03946691, 0.121010706, -0.030089365, -0.007266469, 0.0092267515, 0.14853416, -0.033248078, -0.027284347, -0.10031526, 0.15864117, -0.16782752, -0.18466589) * go_3(1.0, 1.0);
|
||||
result += vec4(0.07722432, -0.025165567, 0.034291282, -0.09902708);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!SAVE conv2d_4_tf
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.004729794, -0.0124398535, -0.08538641, -0.058604605, 0.008671952, 0.25604513, 0.020800482, 0.24144122, -0.028920606, -0.04705229, 0.030192787, 0.0010597534, 0.017666103, 0.0041322373, 0.20027764, 0.08919112) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.0001626656, 0.05816014, -0.0060765734, 0.08811165, 0.35835367, -0.016291425, -0.56892496, 0.083845764, 0.15026698, -0.15916558, 0.08069463, -0.3931291, -0.0123534845, -0.111639686, -0.14637001, -0.08171439) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.114976816, 0.023376396, 0.13855027, 0.07438716, -0.069991484, 0.20377779, 0.23929878, -0.040769435, 0.018832395, 0.005638609, -0.091848075, 0.027843866, 0.023744943, -0.06620523, -0.11678267, 0.0844119) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.0035854098, -0.08432094, -0.17799544, -0.10041983, 0.25605857, 0.021009786, 0.030499447, -0.09928291, 0.052178737, -0.08286175, -0.057888374, 0.024606042, 0.046342995, 0.13875343, 0.11279266, 0.19826262) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.016232021, -0.21539623, 0.0936961, 0.021143785, 0.094262615, 0.049040064, 0.40978724, 0.15347758, 0.08884813, -0.24887115, -0.14756748, -0.5020875, 0.112477, 0.1466549, -0.33418837, 0.5769466) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.16832942, -0.07354198, -0.12081261, -0.055348314, 0.39716053, 0.25583258, 0.09870877, 0.2151021, -0.025700683, -0.1801462, -0.04616654, -0.02782245, -0.054461803, -0.00042802413, -0.00163228, -0.004240747) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.05193433, -0.0018198475, -0.17647028, -0.19462106, 0.1538165, 0.054894235, 0.12183955, 0.07340974, -0.0019901982, 0.0357373, -0.07597063, -0.06681543, -0.00090057997, -0.053894397, -0.010301875, -0.16553953) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.30873474, -0.2836045, 0.057037193, -0.5016378, 0.11952749, 0.102353275, 0.2351629, -0.14635189, -0.019398788, -0.08776502, 0.021669978, -0.089918956, -0.2187901, -0.1180891, -0.049789533, -0.16109149) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.078335494, -0.08867304, 0.03349591, -0.1000293, -0.20235832, 0.22917585, -0.09905303, 0.08381748, 0.014350217, -0.14478815, -0.027479894, -0.026432173, -0.10309177, -0.09860884, -0.019177807, -0.06963025) * go_0(1.0, 1.0);
|
||||
result += mat4(0.008169383, 0.12532842, -0.23369955, 0.077973194, 0.09076616, -0.021277165, 0.1721421, -0.26914293, -0.014729218, -0.023279984, -0.057670787, 0.003598546, -0.015225789, -0.0115396585, -0.26196182, -0.10724508) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.16542235, 0.06589374, 0.07410237, 0.26753154, -0.3356288, 0.3096256, 0.07112498, -0.0992165, 0.15020338, -0.11021673, 0.18803611, 0.12918204, 0.109007336, -0.031968266, 0.057093572, 0.035949256) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.065006174, 0.031055925, 0.0390232, -0.01678507, -0.21553491, 0.14171642, -0.19541772, -0.033691674, -0.06241631, 0.07497651, 0.024557155, 0.056778047, -0.060191352, -0.0261998, 0.07493729, -0.0699132) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.008541382, 0.020270415, -0.027760057, -0.040962905, -0.26732433, 0.34379438, -0.23012447, 0.0051356517, -0.04059567, 0.0972959, 0.039965224, -0.14796777, -0.0016924662, -0.116963714, -0.026353523, -0.29799464) * go_1(0.0, -1.0);
|
||||
result += mat4(0.03329303, -0.12663862, -0.0004959157, -0.11162377, 0.26238343, 0.43260252, -0.16504994, 0.10727678, -0.22505566, 0.43474057, 0.43304008, 0.05143919, 0.40494493, 0.08689636, -0.035733614, 0.25727916) * go_1(0.0, 0.0);
|
||||
result += mat4(0.12175736, -0.014467151, -0.17461288, -0.18480565, -0.26439998, 0.307935, -0.058916792, -0.014292711, -0.0569471, 0.10751278, -0.04134206, 0.1847734, -0.07519831, -0.033909313, -0.05001451, -0.136606) * go_1(0.0, 1.0);
|
||||
result += mat4(0.1424893, -0.026820501, 0.19645774, -0.0011315406, -0.14680974, 0.07662838, 0.21108222, 0.13260938, 0.17923595, -0.085527614, 0.08217639, 0.06579479, 0.05985784, -0.09016323, 0.11172888, 0.111903176) * go_1(1.0, -1.0);
|
||||
result += mat4(0.19842595, 0.0093640275, 0.10433465, 0.13341904, -0.082806975, 0.22555825, -0.1315717, 0.11907785, 0.24012424, 0.47776055, 0.1835734, 0.17483878, 0.079803735, 0.01155073, -0.21146573, -0.16484722) * go_1(1.0, 0.0);
|
||||
result += mat4(0.15064004, 0.021381427, 0.18301587, 0.21225913, 0.054995645, 0.03212186, 0.052798916, -0.048424408, 0.03609021, 0.0964704, -0.059469886, -0.05133066, -0.08157349, 0.051145166, -0.09107608, -0.1362262) * go_1(1.0, 1.0);
|
||||
result += mat4(0.090521574, -0.014747857, -0.081675015, -0.118686825, 0.04848682, -0.033071827, 0.008534588, 0.023765508, 0.16849907, -0.21797262, -0.17049783, -0.07824179, -0.033794608, 0.052612655, 0.095820345, -0.07262317) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.22816367, -0.13772108, -0.036353834, -0.47638395, -0.0530902, 0.14089061, 0.076203234, 0.18006112, 0.121814854, -0.20750527, 0.08266107, -0.28634354, 0.14301859, -0.13458411, 0.00501663, -0.039783802) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.103384845, -0.14389835, 0.08275834, -0.068423435, 0.22643796, -0.02966374, -0.2847584, 0.037081387, 0.02349005, -0.19353923, -0.00095957273, -0.13623689, -0.073120415, 0.03941467, 0.21864155, -0.014019576) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.082576886, 0.17085212, 0.08971252, -0.04213377, -0.032548156, 0.022137715, 0.08399252, -0.0011743539, -0.09410863, -0.41728264, -0.20709297, -0.18933547, 0.027059928, 0.09743364, 0.2504647, -0.041173562) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.20924084, 0.291118, 0.029851688, 0.16953468, 0.02936709, 0.12213576, 0.22944322, 0.108747594, 0.0001881129, -0.27398208, -0.009702691, 0.15449248, -0.9472944, -0.26114875, -0.28161275, -0.3495961) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.12994622, -0.2758638, -0.1091727, -0.0968308, -0.14323105, 0.035175014, -0.08023811, 0.006023802, -0.031529594, -0.1486306, -0.3398172, -0.23240276, -0.29163983, 0.173475, 0.18809283, 0.22197202) * go_2(0.0, 1.0);
|
||||
result += mat4(0.048254848, -0.083444916, -0.014334202, 0.060992356, -0.023099286, -0.09492961, 0.05592045, 0.0026059286, 0.08998117, -0.108810075, -0.053304546, 0.045926623, 0.068255246, 0.099023566, 0.01595483, 0.1336309) * go_2(1.0, -1.0);
|
||||
result += mat4(0.21916585, 0.2837387, 0.14624594, 0.18843961, -0.06747584, 0.054924384, -0.082568415, 0.05011459, 0.014297759, -0.3884833, -0.054417178, -0.18970548, 0.088336475, -0.030646667, -0.2980552, -0.030035203) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.02748568, -0.011897529, -0.2370837, -0.016740574, -0.0282112, 0.050353892, -0.10761107, -0.00036999505, 0.037646662, -0.17742962, 0.06489219, -0.158852, -0.08016933, 0.07808515, -0.105895035, 0.079869986) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.0058994526, -0.037170693, 0.2574696, 0.06199102, -0.04497728, -0.10667442, -0.15183865, 0.0212881, -0.030842574, 0.073473394, 0.010764398, -0.00084518327, -0.03893014, -0.009649613, 0.07443129, 0.15108284) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.11325495, -0.096435815, -0.097331434, -0.049700152, -0.17231967, 0.047090057, -0.019111065, 0.104790315, -0.15004838, 0.13950798, 0.055996202, -0.070548095, 0.047154237, -0.007650949, -0.053611025, -0.012242293) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.12787002, -0.04958212, 0.053988468, 0.0017896162, 0.049493514, -0.009475431, -0.0022641935, 0.03933694, -0.005174597, 0.043754533, -0.1432976, 0.037084177, -0.04601288, -0.032077815, -0.059897035, 0.12584484) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.019409029, 0.10492923, 0.268368, 0.12597778, -0.17733063, -0.0085961, -0.27136415, -0.049664587, 0.012515404, -0.21444482, -0.39275557, -0.12297177, 0.06800057, 0.19228315, 0.06245887, 0.35772634) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.16317715, 0.2288402, -0.23235172, 0.22230752, -0.1646375, 0.13366091, 0.16681044, -0.17399235, 0.33997267, -0.3179832, -0.34756508, 0.39843196, -0.10748536, 0.322923, 0.23339489, 0.08684083) * go_3(0.0, 0.0);
|
||||
result += mat4(0.02835275, 0.12314228, 0.24030593, 0.30856124, 0.055735108, -0.044914473, 0.0031432225, 0.07469899, 0.1778018, 0.107083894, -0.023706734, -0.15501897, 0.0943098, -0.034707237, -0.18622099, 0.05257965) * go_3(0.0, 1.0);
|
||||
result += mat4(0.042839274, 0.12597966, 0.08979042, -0.0647561, -0.050434645, 0.049438696, -0.20008127, -0.05572608, 0.046238814, 0.12622325, -0.019017145, -0.13960391, -0.040050175, 0.14298008, -0.20270552, 0.13391526) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.0073277587, 0.10606624, -0.08940439, -0.09656414, 0.12387374, -0.0013147948, 0.23607181, -0.00037969893, 0.050353236, -0.17266603, 0.27796733, -0.09877832, 0.02711225, 0.096394345, 0.07457944, 0.21541388) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.18612787, -0.00027517386, -0.17136407, -0.06413671, 0.025629476, -0.04570916, 0.0008431566, -0.03419168, 0.08123608, 0.09465922, 0.11975521, 0.1269741, 0.08413221, 0.12125001, 0.04727287, 0.072378494) * go_3(1.0, 1.0);
|
||||
result += vec4(0.04244928, -0.014280219, 0.017129054, -0.08807801);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!SAVE conv2d_4_tf1
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.01973856, -0.05053795, 0.015545361, 0.10867395, 0.33441806, 0.14731607, 0.6793983, -0.21394718, -0.00846322, 0.09146322, -0.07427475, -0.078477465, -0.090998545, 0.133366, 0.105515696, -0.13784988) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.05404873, 0.09784018, -0.1337389, -0.18082313, 0.13461179, -0.3816801, 0.12209786, 0.08176651, 0.10461896, -0.43315184, 0.017470734, 0.20423968, -0.03941875, -0.101959296, -0.09440259, 0.09154717) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.17229515, -0.06907825, -0.008382803, -0.16671611, -0.01576541, 0.03985307, 0.08209482, -0.11707446, -0.11793074, 0.13702396, -0.02013158, 0.07302033, -0.022301994, -0.11464677, 0.036753565, -0.093276784) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.017650167, 0.009475923, -0.17856382, 0.15925962, 0.06434641, -0.15568036, 0.038135886, 0.18855911, -0.04427734, 0.1878215, 0.10856261, 0.0041275816, -0.12046199, 0.13610138, 0.3741596, -0.12934728) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.24631616, 0.0169485, -0.035534818, 0.37795424, -0.08546174, 0.07817259, 0.42897213, -0.47965595, -0.0146556785, -0.20510523, -0.18889453, 0.06476019, 0.1021008, -0.35398817, -0.031071864, -0.21416448) * go_0(0.0, 0.0);
|
||||
result += mat4(0.32810766, 0.050585747, -0.17658374, -0.13881154, 0.16417882, -0.21286008, -0.106835455, -0.1722344, -0.14151084, 0.08962986, 0.057395387, -0.01623662, 0.02570415, 0.15626897, -0.12687978, 0.080729105) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.050597478, -0.018753758, -0.036346875, -0.017908493, 0.058593344, 0.008303028, 0.05254987, -0.06635018, -0.022532012, 0.029511122, 0.026682215, -0.054647952, 0.069466785, -0.08892492, 0.025351115, -0.023130694) * go_0(1.0, -1.0);
|
||||
result += mat4(0.2412473, -0.16138165, -0.15117447, 0.11851003, -0.096868426, 0.082690425, 0.27923304, 0.11590443, 0.19363573, -0.15770023, -0.066793665, 0.011681678, 0.14037277, -0.112065665, -0.048159517, 0.009453693) * go_0(1.0, 0.0);
|
||||
result += mat4(0.1580054, -0.0060506654, 0.05267837, -0.09178131, -0.09107123, 0.23191126, 0.21108283, -0.070422985, 0.024321035, 0.06131459, 0.066626504, 0.032481454, 0.044402298, 0.1390604, -0.14432502, 0.040869843) * go_0(1.0, 1.0);
|
||||
result += mat4(0.10264861, 0.013504324, 0.012482852, -0.1781206, -0.12799414, -0.27026084, -0.123830505, 0.098105, -0.039127555, 0.09367889, 0.122323096, 0.1416734, 0.044763107, -0.21801683, -0.14018978, 0.17646866) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.017453065, 0.11498537, -0.10998983, -0.3116098, -0.3099762, 0.5024706, 0.051817298, 0.03170681, -0.18937826, 0.07946567, -0.11978771, -0.09523745, -0.0033551592, -0.11768945, 0.08932359, -0.06689581) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.1507582, -0.013266159, -0.073085934, -0.07252967, -0.06301927, -0.13218755, 0.12984878, -0.13678701, 0.023422396, 0.082123175, 0.006906731, -0.004018426, -0.15813835, 0.13711788, 0.016018609, 0.13443229) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.06960673, 0.16156524, -0.1374069, -0.05803206, -0.077960715, -0.10676749, 0.26282015, 0.03521529, 0.058099385, -0.014738148, 0.0011174522, 0.24279532, -0.023991548, -0.108812414, -0.08886019, 0.20584475) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.08043308, 0.063343, 0.055290066, -0.15991378, -0.08096304, -0.23888679, 0.019161629, 0.38381267, 0.3672934, -0.119608454, -0.43623593, -0.46014485, -0.5323366, 0.1318621, 0.087373205, -0.05535459) * go_1(0.0, 0.0);
|
||||
result += mat4(0.20640239, -0.1369444, -0.21677823, 0.08202178, 0.10515278, 0.06810837, 0.073207974, 0.23623931, 0.102422275, -0.05016664, -0.0039228587, -0.1810343, -0.2235563, -0.1246854, 0.1428113, -0.10609135) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.031941894, -0.08905056, 0.21501167, 0.11244667, -0.011811734, 0.21630247, 0.07589472, -0.040489636, -0.11824066, -0.11520391, -0.10075633, -0.035642453, 0.062144946, 0.0073282206, 0.14119269, -0.060479023) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.29382935, -0.056808118, 0.051812876, -0.061358813, -0.08344258, 0.124203674, 0.037964176, -0.01961274, -0.000951725, 0.50005037, -0.24176972, 0.06487161, -0.15469861, 0.04336187, 0.17826353, 0.040010225) * go_1(1.0, 0.0);
|
||||
result += mat4(0.02044482, -0.0879271, -0.01053958, -0.31148303, 0.07497373, -0.11548258, -0.1666126, 0.02369657, -0.058044076, 0.010801491, -0.005933901, -0.08910467, 0.007953008, 0.03761974, -0.029501524, 0.16816042) * go_1(1.0, 1.0);
|
||||
result += mat4(0.1779597, -0.10213089, 0.29942423, -0.016642543, -0.015537001, -0.04676146, 0.09585872, -0.0055750017, -0.014361908, -0.20667697, -0.11348746, 0.13081487, -0.10437329, 0.14328459, 0.11648822, -0.09163837) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.019033967, -0.12420627, -0.07748253, 0.43203858, -0.109799065, 0.07605535, 0.060791396, -0.24517195, -0.15674245, 0.21267459, 0.10665515, -0.073150024, -0.1358355, 0.0054066703, -0.16434059, -0.06031853) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.18834068, 0.26840356, -0.12937617, 0.16103932, -0.0062331813, -0.13630053, -0.013911821, 0.022389365, -0.044232946, -0.056454606, 0.022426741, 0.18010215, 0.041900013, 0.03375041, -0.11376866, -0.010313381) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.12497669, -0.31161824, 0.097568035, 0.19443443, -0.05056519, -0.0031457904, 0.1055554, -0.083650924, 0.07630523, -0.34177595, -0.093093194, 0.20701368, -0.030962149, -0.054470222, -0.23853977, 0.004326528) * go_2(0.0, -1.0);
|
||||
result += mat4(0.34370202, 0.085750066, -0.16071722, -0.54335934, -0.35595295, -0.050744478, -0.17405547, 0.008628697, -0.007086256, 0.23164117, 0.340156, 0.5475976, -0.15292351, 0.28019544, 0.038059216, 0.0044727) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.08231968, -0.0052294536, 0.07451547, 0.22278999, -0.3305531, 0.0017458396, 0.10818422, -0.21325395, -0.08807993, -0.110342845, 0.10082142, -0.051594347, 0.24192205, -0.18042035, -0.0095462985, -0.08757798) * go_2(0.0, 1.0);
|
||||
result += mat4(0.096379586, 0.021887815, -0.05097233, -0.06797989, -0.026171045, 0.022944937, -0.015915364, 0.037667938, 0.17216732, -0.014889412, 0.07343887, 0.028236505, 0.0015047621, 0.1355103, -0.09918284, -0.07673695) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.25385055, 0.15163356, 0.0030003798, 0.18464413, 0.05611221, 0.099498056, -0.07128191, 0.042955168, 0.027493173, 0.07440157, 0.07814497, 0.096160784, 0.13571084, 0.056412842, -0.031997006, -0.16073681) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.21634746, 0.025153082, -0.064477116, 0.0005679147, -0.0029436245, 0.12794618, 0.024849026, 0.03018052, 0.11723976, 0.059955597, -0.013594654, 0.09091745, 0.04775348, 0.21260159, -0.07463213, -0.06727042) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.12166018, 0.024545137, 0.08611618, -0.17627168, 0.09042604, -0.14157623, -0.22147785, 0.09100581, 0.11078359, 0.031410985, -0.17170976, 0.09532806, -0.059569277, 0.09392676, 0.11784347, -0.21471368) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.1483187, -0.2217563, 0.12032977, 0.14932398, 0.27428308, -0.04568031, 0.12670338, 0.09586169, 0.06700745, 0.005126449, 0.0027694793, -0.033667028, 0.06447861, -0.08585174, -0.05509812, -0.11358761) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.22750492, 0.032906335, -0.029479047, 0.11580199, -0.05812372, -0.032269973, 0.05219915, 0.041658226, 0.010897959, 0.065550454, 0.0076911976, -0.045743827, 0.11614996, -0.10393113, -0.0012606392, -0.034367524) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.09350742, 0.09561609, 0.3735968, 0.031685118, -0.042026598, 0.17006761, -0.3910107, 0.16984761, 0.25679177, 0.036610503, -0.13772772, 0.11101589, -0.1137049, 0.07211461, 0.18065079, -0.12324793) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.020749722, 0.14413361, -0.061903823, -0.21550268, 0.31306142, -0.11532895, 0.029482557, 0.03282164, -0.09800627, -0.20765196, 0.33030233, 0.075725295, 0.49252015, 0.042455837, -0.07264194, -0.10401895) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.22697076, -0.15738785, 0.09740376, -0.072098814, -0.06638972, 0.12336611, 0.0073687397, 0.048267826, 0.06717852, -0.027047804, -0.123397194, 0.17829034, 0.04215185, 0.066311836, -0.061742183, -0.046373066) * go_3(0.0, 1.0);
|
||||
result += mat4(0.041311592, 0.2813485, 0.055084586, -0.01823069, 0.08105147, -0.087944716, -0.10135052, -0.02653456, 0.063169874, -0.1351186, 0.06722432, -0.016406318, 0.08666922, 0.0555909, 0.12086502, -0.17224412) * go_3(1.0, -1.0);
|
||||
result += mat4(0.26026788, -0.18303715, 0.029279215, -0.12858874, 0.027197823, 0.0919464, 0.00849638, 0.10547888, -0.12952055, -0.14414985, 0.1903315, 0.05004528, -0.12657289, 0.038008716, -0.036606666, -0.054025438) * go_3(1.0, 0.0);
|
||||
result += mat4(0.069167465, 0.2699947, -0.11137602, -0.05888806, -0.107324794, -0.07598601, 0.06042177, 0.0064530694, -0.039780665, -0.076666445, -0.00846108, -0.06165907, -0.06978219, -0.19108103, -0.040026028, -0.120319635) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.14375664, -0.0056876075, 0.052177623, 0.07152566);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!SAVE conv2d_5_tf
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.15667982, -0.31441393, 0.29112124, -0.15737213, 0.022372838, 0.10690639, -0.12019085, -0.051941186, -0.30367845, 0.02612279, 0.2372532, 0.2021648, -0.20481086, -0.003770439, 0.14981231, 0.066780254) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.03270688, -0.42270073, 0.044317324, 0.15907793, 0.14681059, -0.2934784, 0.24933252, -0.067273855, 0.07752533, -0.23194817, 0.0686707, 0.08999225, 0.121678345, -0.12916678, 0.012397381, 0.012315053) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.10090412, -0.20792678, 0.11076032, -0.02938975, -0.1944187, -0.2003259, 0.04438032, 0.36946484, -0.019868722, -0.15830222, 0.042811528, 0.015641417, 0.113098525, 0.080257006, 0.011135628, -0.2877629) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.15482685, 0.06579119, 0.28301102, 0.23729764, 0.15990537, 0.4529694, 0.107880585, 0.10668121, -0.42430598, -0.2631025, 0.10513542, -0.036242936, -0.09827965, -0.0069260495, -0.11689201, -0.041436482) * go_0(0.0, -1.0);
|
||||
result += mat4(0.08472191, -0.13051608, 0.047930017, 0.36831668, 0.1164478, 0.21384816, 0.22062506, 0.2094167, 0.48668453, 0.32302913, 0.36268055, -0.091801375, -0.079141125, -0.26613805, -0.16608004, 0.03810683) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.13474251, -0.04824603, 0.23303726, -0.116136365, 0.0056330245, 0.15829784, 0.0012259148, 0.12648389, 0.038680512, 0.05131116, 0.024099711, 0.4555406, 0.0035716395, 0.11633299, 0.094744846, -0.2457627) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.0576871, -0.04037522, 0.16857862, 0.0031084458, -0.027274646, -0.18154246, 0.13337846, 0.035422433, -0.0030749738, -0.17288287, 0.019983152, -0.31871706, -0.03280405, 0.06825421, -0.1563798, 0.05031885) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.066631876, 0.012560506, 0.1690693, -0.018248236, 0.0450104, 0.016296914, -0.14910112, -0.16191053, 0.5078224, -0.017615631, 0.15226597, -0.13373777, 0.20148668, 0.060258996, 0.13215344, 0.18430072) * go_0(1.0, 0.0);
|
||||
result += mat4(0.12976126, -0.072738245, 0.053067926, 0.09752956, -0.04716214, 0.04136464, 0.014162617, -0.06621296, -0.09617736, 0.057469178, 0.01280261, -0.042976785, -0.12570308, 0.006027807, 0.031038594, 0.06569918) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.12655424, -0.41563693, -0.030971345, -0.06357555, -0.14121394, -0.15667427, 0.14398985, 0.05995984, 0.0821605, 0.12462943, 0.007492498, -0.0030187522, -0.22804567, -0.10487421, 0.13180672, -0.13978589) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.075991526, 0.12352044, -0.17844258, 0.010614991, -0.18293494, 0.25009897, -0.080779895, 0.21548378, 0.22215544, 0.048670914, -0.057372037, 0.078176, 0.17490411, 0.004919551, 0.059619516, 0.12660357) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.06282951, 0.10929357, 0.026720649, -0.15939257, 0.17107709, -0.04334904, -0.03047162, -0.101681694, 0.03118431, 0.19994627, 0.025729552, 0.035035726, -0.0012207883, -0.08618888, 0.061205562, 0.009940555) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.23581573, 0.08002133, -0.15170844, 0.08872338, -0.25767094, -0.09273545, 0.18153891, 0.2544269, -0.084598936, -0.089766875, -0.14610913, 0.002247754, 0.1802837, -0.019625561, 0.30239686, -0.032793984) * go_1(0.0, -1.0);
|
||||
result += mat4(0.5223286, 0.10347663, 0.4000593, 0.25440502, -0.07646958, -0.31940606, 0.053407036, -0.09356492, 0.2738851, 0.23945184, -0.2907089, -0.45822915, 0.13415676, 0.17187089, 0.08731114, -0.27670014) * go_1(0.0, 0.0);
|
||||
result += mat4(0.059273496, -0.107137166, 0.12087539, 0.179237, -0.021209063, -0.02548005, 0.061256204, 0.033822674, 0.54491127, -0.2475085, 0.08055858, -0.4071213, -0.045093834, 0.07161349, 0.08219979, -0.31735933) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.29527053, 0.021469543, 0.07202354, -0.07103959, 0.03990857, 0.2490762, -0.19419849, -0.13916986, -0.05325315, 0.12922864, -0.041463424, -0.031249814, 0.073991664, -0.09723187, 0.35132217, 0.024760868) * go_1(1.0, -1.0);
|
||||
result += mat4(0.09606787, -0.0951808, -0.0059865676, -0.052033573, -0.3118038, 0.4432636, -0.12943317, 0.09484738, 0.10621756, -0.10550469, 0.11264014, 0.1402276, -0.012679125, -0.08809835, 0.029994955, -0.15121669) * go_1(1.0, 0.0);
|
||||
result += mat4(0.123397775, 0.048338536, -0.00975707, -0.103767075, -0.041053303, -0.07228534, 0.046792876, 0.0668788, 0.29554394, 0.012451002, 0.19568972, 0.112091154, 0.10882395, -0.0995439, 0.051324263, 0.24967718) * go_1(1.0, 1.0);
|
||||
result += mat4(0.2699648, 0.17300771, -0.16056584, 0.1099392, 0.11674778, -0.19811755, 0.111880325, -0.06075038, -0.095849104, -0.04510651, -0.04180761, -0.0052786698, 0.11037549, -0.24115366, 0.018509468, -0.07819484) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.10981622, 0.044488225, 0.050722387, -0.3146652, -0.0013019707, -0.24084032, -0.10475088, 0.026944289, 0.1592903, 0.33087498, 0.061839584, -0.043863457, -0.06904603, -0.08635262, 0.088630445, -0.15485142) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.06810522, 0.19927117, -0.08130387, 0.11612667, -0.015104349, -7.738651e-05, -0.06419643, -0.14813533, 0.026650215, 0.015038833, 0.08161237, 0.058321163, 0.015005185, -0.16189656, 0.024501886, 0.1927279) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.31858218, 0.11962043, -0.20560326, -0.13190113, 0.02138715, -0.057066392, -0.085771754, -0.124566585, 0.044749223, 0.13687828, 0.1195792, 0.14021616, 0.26204133, 0.05119197, -0.13980037, 0.050747477) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.21238558, -0.0734057, -0.2036023, -0.34308743, -0.29370925, 0.2393742, -0.37877437, 0.036869828, -0.17053255, -0.26900926, -0.23330869, 0.32902205, -0.4882585, 0.27430108, -0.033711653, 0.15501487) * go_2(0.0, 0.0);
|
||||
result += mat4(0.23487025, 0.085289046, -0.14281847, 0.12543266, 0.15871634, -0.13858907, 0.14810285, -0.0239261, 0.1286852, 0.07754033, 0.01072327, -0.14313328, 0.05480442, -0.12195059, 0.11341822, 0.08224607) * go_2(0.0, 1.0);
|
||||
result += mat4(0.19490337, 0.023521842, -0.24548791, 0.0035114093, -0.07937166, -0.07674376, 0.08365873, -0.003286068, 0.023862893, 0.009626835, 0.032829892, 0.0078141205, 0.053484406, -0.08297165, 0.09303188, 0.004273738) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.0032906602, 0.13636959, 0.027821168, 0.06270053, 0.024775786, -0.077529594, 0.03799126, 0.030000908, 0.031749167, 0.04360487, 0.004448846, -0.17835903, -0.30834544, 0.013150946, -0.13758293, -0.03296242) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.14166978, 0.034131095, 0.049779188, 0.09453289, -0.011406557, -0.07020709, -0.0031981543, -0.03443845, -0.00010218944, 0.0855161, -0.10951453, 0.042758763, 0.1718446, -0.1577923, 0.0410027, -0.04992991) * go_2(1.0, 1.0);
|
||||
result += mat4(0.1219178, 0.105126485, -0.041097324, -0.08110963, -0.04857337, -0.11544925, -0.14572923, 0.092435546, 0.091857366, 0.15425235, -0.020324683, -0.05764375, -0.020458939, -0.10527823, -0.085554086, 0.16358297) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.12372687, -0.009976829, 0.14252265, -0.1321053, -0.05965866, -0.1393898, -0.017603246, -0.02714342, -0.16824952, -0.23083204, -0.012299022, -0.06689838, -0.015830487, 0.21299921, -0.11637202, 0.0074968333) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.01979935, -0.182785, -0.015397454, 0.14175794, -0.011465284, 0.11285164, -0.036115747, 0.07150463, -0.083641894, -0.10221778, -0.13871445, 0.099696055, 0.04603662, -0.06463785, -0.007984529, -0.0032940735) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.072830334, -0.057334073, 0.09086239, 0.13039105, 0.06350303, 0.17130788, -0.2181585, -0.09137403, -0.31397742, -0.019071499, -0.017274613, 0.13762084, 0.10195637, -0.021455176, 0.04011394, -0.08029658) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.26982597, -0.40265098, -0.4151411, 0.038557775, -0.095602125, 0.3503172, -0.029988842, -0.03484708, 0.095536314, -0.0030311556, 0.31589827, 0.52763534, -0.12629713, -0.24356791, 0.0059487303, 0.42298427) * go_3(0.0, 0.0);
|
||||
result += mat4(0.054166105, 0.18827972, -0.081673265, -0.06720384, 0.09375001, 0.22173035, -0.14050071, 0.108400136, -0.15553835, -0.08716729, -0.037366748, 0.10971073, -0.02560103, -0.26702073, -0.05201882, 0.2432563) * go_3(0.0, 1.0);
|
||||
result += mat4(0.16196893, 0.0889265, -0.09887943, -0.042956755, -0.054403376, -0.123823255, 0.045847844, 0.017027669, 0.00539936, -0.112265736, 0.050549984, -0.104931094, -0.06883012, -0.25745714, 0.11155538, -0.15363649) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.22157209, 0.18200903, -0.13290548, 0.026721261, -0.06066069, -0.18150693, 0.08768983, 0.037362453, -0.1073367, -0.070236765, -0.41223463, -0.168915, -0.15517351, -0.13949952, -0.13307643, -0.15935421) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.026589906, 0.0930502, 0.05195435, 0.06301585, -0.01107014, -0.019382332, 0.027223695, -0.004045145, -0.15238355, -0.0345132, 0.06355168, 0.0011230056, 0.16690113, 0.0017829507, -0.0023939044, -0.09471834) * go_3(1.0, 1.0);
|
||||
result += vec4(0.024455175, 0.01669877, -0.066231176, 0.036848705);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!SAVE conv2d_5_tf1
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.01763509, -0.17156707, -0.06841296, -0.026132878, -0.10600523, 0.11245994, 0.121395074, -0.09331501, 0.12764473, 0.0428028, -0.11837395, 0.2092563, -0.04357652, -0.0490096, 0.024701532, 0.10518723) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.17130826, -0.31987694, -0.07639005, 0.21362033, 0.058639023, 0.066175915, -0.25344703, -0.07923442, -0.14766373, 0.040518284, -0.031103026, -0.040075514, -0.051108997, -0.28214613, -0.18504949, 0.27544948) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.030991005, -0.011353306, 0.15237464, 0.15458584, 0.1250524, 0.19959912, 0.14049476, 0.38410887, 0.07378578, -0.017728366, 0.0963528, -0.043756213, -0.039577194, -0.11800575, -0.08392266, -0.07599512) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.022089608, -0.027317125, 0.051330008, -0.0075439885, 0.021650828, -0.0009390209, -0.12043464, 0.049332134, -0.055557396, -0.053297505, -0.0918705, -0.13089466, -0.10994107, 0.072746456, 0.11496739, -0.05225977) * go_0(0.0, -1.0);
|
||||
result += mat4(0.29730305, 0.26317745, 0.052159555, -0.32006654, 0.48288685, -0.049926184, -0.08091092, -0.13825637, -0.1485706, -0.288657, -0.41443697, 0.06856032, -0.23809211, -0.12953928, 0.4783034, -0.47557938) * go_0(0.0, 0.0);
|
||||
result += mat4(0.026139118, -0.23031352, 0.04861487, 0.033556074, 0.2702056, 0.22802536, -0.15385233, 0.1664119, 0.18749923, 0.36927548, -0.011473684, -0.11771165, -0.16859052, -0.4513202, 0.12863952, 0.02482837) * go_0(0.0, 1.0);
|
||||
result += mat4(0.0073229345, -0.061915245, 0.06710329, 0.0062416573, -0.00555983, 0.14592186, 0.11201052, -0.123630054, 0.32611257, -0.11279885, -0.059449438, 0.2891043, -0.10519016, 0.040108994, -0.012468261, 0.02083298) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.057483062, 0.08454755, -0.15529329, -0.12572923, 0.2600099, -0.02319978, -0.04037675, 0.11496361, 0.07728194, -0.12908956, -0.025529336, 0.112581626, 0.02971823, 0.11659056, -0.01298622, 0.017061908) * go_0(1.0, 0.0);
|
||||
result += mat4(0.22417091, -0.00222947, 0.04980858, 0.12260437, -0.025507605, 0.042577885, 0.120813504, -0.048522256, -0.038494784, -0.0072195013, -0.23012944, -0.020850847, -0.078296244, -0.014830018, 0.19759563, -0.10000253) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.032090195, 0.023757193, -0.08989734, 0.14419042, 0.0112194475, -0.093776144, -0.020197887, 0.29295877, 0.06872183, 0.09511462, -0.03245769, -0.06504889, 0.05132126, 0.00399527, 0.075911656, 0.250893) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.3418496, 0.25525784, 0.0018161442, 0.028484365, -0.17573346, -0.12457501, 0.18466166, 0.20209278, 0.10282706, 0.16353399, 0.025052028, -0.059714165, -0.055806916, -0.28651386, 0.112798095, 0.11624314) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.018793896, 0.07500149, -0.01728254, -0.1726998, -0.13333, 0.09590344, -0.036537904, -0.11522523, 0.19445558, 0.22680458, 0.12061006, -0.06225618, 0.1127748, 0.28380096, -0.07099846, -0.007440302) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.43887648, -0.10018577, -0.29267642, 0.12149727, -0.14333835, 0.04161915, 0.19442867, 0.16506511, 0.09655387, -0.0014398015, 0.13189743, -0.14068556, 0.049408, 0.0829072, 0.2950336, 0.36965907) * go_1(0.0, -1.0);
|
||||
result += mat4(0.41486958, -0.023498302, -0.37900022, -0.31752598, 0.13758768, -0.18782206, -0.31358528, 0.3330786, -0.4039293, -0.06539036, 0.032599606, 0.10663507, -0.26369813, -0.17365438, 0.20723309, 0.1801556) * go_1(0.0, 0.0);
|
||||
result += mat4(0.004117444, -0.14894462, 0.14915143, -0.047375835, -0.2609916, -0.10172324, -0.14925237, -0.33830285, 0.12131607, -0.18156646, -0.42382464, -0.052582145, 0.2329045, -0.4576963, 0.13756892, 0.055571318) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.31689477, 0.017058033, -0.01904924, -0.016893756, -0.011479519, 0.07316262, -0.07086077, 0.08923511, -0.08190091, -0.025866933, -0.06909204, -0.028601022, 0.023224542, 0.03082087, 0.2230426, -0.16713654) * go_1(1.0, -1.0);
|
||||
result += mat4(0.13457374, 0.110913865, -0.1130815, -0.031438913, -0.55201167, 0.04831016, 0.25107765, -0.014003224, 0.19532952, 0.02062346, 0.04839241, 0.088673405, 0.30325848, -0.20222804, -0.085780576, 0.22512968) * go_1(1.0, 0.0);
|
||||
result += mat4(0.076354, 0.021940092, -0.16170324, 0.0025543426, -0.0032400405, -0.0046705627, 0.06241069, -0.031247333, 0.098353796, 0.03723474, 0.22971998, -0.017877292, 0.119858086, 0.008041448, 0.2140585, 0.10343376) * go_1(1.0, 1.0);
|
||||
result += mat4(0.08627595, 0.04532834, 0.027579082, -0.16222088, 0.15583228, -0.14371829, -0.07243855, -0.111895435, -0.14438897, -0.10250594, 0.0034202964, -0.066547595, -0.034390844, -0.021545287, 0.014540157, -0.10215731) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.19720152, 0.21534947, 0.1130938, -0.011730973, 0.013247983, -0.10344174, -0.1906514, -0.015767017, -0.020093633, -0.26487067, -0.005960781, -0.057149183, 0.030110173, 0.047692046, -0.19308545, -0.25292158) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.039498243, 0.053682897, -0.01844695, -0.017540915, 0.039454967, -0.27696076, 0.09503274, -0.038958035, 0.17321438, -0.036311295, 0.03123055, 0.02310311, 0.040591653, 0.0054627894, -0.03520426, -0.026101988) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.055991564, 0.06512919, -0.12532505, 0.024075158, -0.04926237, -0.11701171, 0.026792146, 0.013033238, -0.052847516, -0.01550091, -0.008442071, -0.077945165, -0.033220004, -0.13678443, -0.07040586, 0.121846326) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.19537796, -0.016634773, 0.10707109, -0.024361614, -0.16002733, -0.44066608, 0.16488662, 0.013152995, 0.22407806, 0.12854017, 0.19028598, -0.08379244, -0.05594235, -0.15909895, 0.511962, 0.39027596) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.032652248, 0.06004893, 0.011166194, 0.102761306, -0.035113614, -0.29961765, -0.013817978, 0.20938557, 0.08488225, -0.1118558, -0.0375328, -0.035511103, 0.0046933405, 0.20203683, -0.13552529, -0.12685429) * go_2(0.0, 1.0);
|
||||
result += mat4(0.03054923, 0.08224908, -0.059128158, -0.02583655, -0.02133876, 0.0048713544, 0.10848829, 0.06324404, 0.028332822, -0.011002306, -0.027557913, -0.06072362, 0.1019048, -0.02587316, 0.08563405, -0.08119947) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.10568117, 0.1075248, 0.19379964, -0.14337265, 0.019374132, -0.0907804, -0.13827625, -0.03628561, 0.014735499, -0.026882607, -0.25948793, 0.034926686, -0.05988073, -0.22735636, 0.053511668, 0.04765336) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.029848114, 0.09183966, 0.084713496, 0.09422864, 0.069713995, -0.10584984, -0.020899031, 0.059645247, -0.075805016, -0.01828552, 0.06689195, -0.13804196, -0.023465823, -0.034038994, -0.12946706, 0.058709413) * go_2(1.0, 1.0);
|
||||
result += mat4(0.061918218, 0.038984764, 0.013660938, -0.19340219, -0.014949839, 0.12946278, 0.12725051, 0.13429146, 0.05993008, -0.015394284, 0.011232483, 0.0344157, 0.022161875, -0.023923954, 0.061736204, 0.025963215) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.048136763, 0.03162042, -0.01967249, 0.06374493, 0.034645267, 0.22403605, 0.036197048, -0.06903216, -0.1024706, -0.0005459356, 0.049185563, 0.16309108, 0.07394778, 0.10351343, 0.28430694, -0.13531347) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.14705071, -0.09458433, 0.03063114, 0.07901115, -0.11911086, -0.06428132, -0.013549552, -0.041342866, -0.20770676, -0.15104479, 0.054365363, -0.11652907, 0.05639815, 0.070518605, 0.0017846811, -0.00056205114) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.27148908, 0.07358356, 0.13644488, -0.13824654, 0.0112991175, -0.021521023, -0.10197379, 0.007816017, -0.13314332, 0.12318473, -0.043214846, -0.15759036, -0.19744353, -0.10267182, -0.28249928, 0.11233295) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.096474804, 0.17893109, 0.014679829, -0.21218887, -0.24170275, 0.10603527, 0.05375366, -0.059315052, 0.17087384, 0.13633691, -0.37958893, 0.43264794, 0.17829923, 0.06485103, -0.37551817, -0.22082718) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.30536333, -0.033212308, -0.25232, 0.11730442, -0.11176368, 0.26223183, -0.049025323, -0.01375941, -0.29028055, 0.16842811, -0.035684332, -0.4180911, -0.1611732, 0.07683385, -0.14263596, 0.17508087) * go_3(0.0, 1.0);
|
||||
result += mat4(0.23580009, 0.025621435, -0.15757325, 0.008123166, -0.021905439, -0.02162503, -0.059497356, -0.01636353, 0.047654126, -0.084423855, -0.033733923, 0.0127116265, -0.059593942, -0.053935718, -0.050729543, 0.013887048) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.19232626, 0.07915767, -0.05909752, 0.007695347, 0.058876406, 0.057521783, -0.080253534, 0.2011056, -0.27965516, -0.08033169, -0.13025513, 0.12854645, 0.053400308, -0.18445957, -0.18463044, 0.27920377) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.061806213, -0.020037206, 0.003183183, -0.029844081, -0.039553937, 0.028905323, -0.11367984, -0.097321615, -0.10112643, 0.0039709485, -0.06020118, -0.23871279, -0.077974856, 0.05806996, -0.21440302, 0.11898043) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.023832673, 0.03702965, -0.04749135, -0.10982549);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!SAVE conv2d_6_tf
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.030931145, 0.013683292, -0.0650242, -0.028732346, 0.120067924, -0.029404473, 0.0038229884, -0.14631765, 0.041900825, -0.076596744, -0.11096378, -0.27100095, 0.0052598766, -0.05929686, -0.06816563, -0.086864315) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.043620087, -0.16360405, 0.006527374, 0.15706524, 0.08338088, -0.19027525, 0.22595987, -0.054963548, 0.01825031, -0.03149212, 0.025471251, 0.06429379, -0.011633275, -0.079389006, -0.0030728737, 0.17345747) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.011275288, -0.10668036, 0.05718997, 0.010336089, 0.33393976, -0.2029354, 0.075444475, -0.092244044, 0.07605498, 0.20125951, 0.10493973, -0.12306946, 0.03658231, 0.08233366, -0.12205888, -0.116969004) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.0070305974, 0.105127215, 0.006041873, 0.26743913, 0.028119443, 0.14823505, -0.28344348, 0.12362866, -0.1215781, 0.08104382, 0.102011785, 0.085380934, 0.061244503, -0.06230063, -0.05353345, 0.1166729) * go_0(0.0, -1.0);
|
||||
result += mat4(0.08945733, 0.4101902, -0.06404005, 0.040728435, 0.13076581, -0.20805469, -0.10897316, -0.14924604, 0.10090762, 0.015475414, 0.26346552, 0.12096677, -0.20199244, 0.2780031, 0.18515368, 0.35105625) * go_0(0.0, 0.0);
|
||||
result += mat4(0.07463155, 0.26932517, -0.06768551, 0.10470878, -0.1423996, 0.013550665, -0.06167201, -0.1022994, -0.3107166, -0.15609552, 0.1695213, -0.1277181, 0.12582655, -0.1596128, 0.015612055, -0.19826376) * go_0(0.0, 1.0);
|
||||
result += mat4(0.011745468, 0.006471601, 0.008110513, 0.025831396, 0.1272883, -0.221959, 0.11993834, -0.007903633, 0.009993582, -0.10170755, 0.026594637, -0.027883623, 0.030666083, -0.036415886, 0.007469573, 0.0674783) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.022760388, -0.10911659, -0.012589904, -0.046462692, 0.36987287, 0.71668935, -0.04466556, 0.12082762, 0.0026539841, 0.07070946, -0.00020439121, -0.13925348, 0.08672072, 0.20075354, -0.066352285, 0.14655356) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.081081845, -0.21956222, 0.06781787, -0.106362104, -0.03016425, -0.010460211, -0.009725996, -0.009805538, 0.07037355, 0.19254607, 0.038890257, 0.29580075, -0.10355764, 0.12613009, 0.02485986, -0.031927988) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.13882205, 0.21770848, 0.015392157, 0.010310204, 0.008225721, 0.07457836, 0.09984027, -0.25452816, 0.2193511, -0.22262146, -0.12950355, 0.026151875, 0.022114651, -0.030566849, 0.034688126, 0.03047327) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.0363441, 0.19290726, -0.1143055, 0.30871987, -0.05780708, 0.082128406, -0.115280904, 0.07636388, 0.48947453, -0.29715258, 0.146737, -0.3275992, -0.055972476, -0.09991753, 0.17435446, 0.10917291) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.026389305, 0.054523308, -0.028950177, 0.06913328, -0.18626037, 0.08829993, 0.10407121, 0.001246911, 0.103938825, -0.3117343, -0.045564886, 0.07316613, 0.0027089121, 0.099437356, -0.046500806, -0.0927284) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.051037624, -0.2068234, 0.061572235, -0.3345198, 0.16960172, -0.30289862, -0.002583443, 0.39312238, 0.08246557, 0.16374862, -0.31902805, -0.13205275, -0.032050006, 0.01670186, 0.13852347, 0.120012194) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.67096996, -0.06274476, 0.18575665, 0.80282855, 0.23201196, -0.0054729837, 0.050396994, -0.42014772, 0.34904522, 0.26281372, 0.24697208, 0.55475426, 0.49850988, -0.06581312, -0.0068906257, -0.15741143) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.04252036, -0.28224963, 0.009723064, 0.116357096, 0.2992567, -0.26702902, -0.05648925, 0.12729199, -0.37574205, 0.54211813, -0.25248805, -0.13023548, 0.18903324, -0.5182459, 0.0141203115, -0.19444294) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.0017735233, -0.010132458, -0.040924776, -0.13767008, 0.20757031, -0.06509882, -0.09756446, 0.018974079, 0.090851985, -0.010158765, -0.03999607, -0.12055641, 0.03629025, -0.018645551, -0.05506811, -0.014202848) * go_1(1.0, -1.0);
|
||||
result += mat4(0.16203491, 0.011118734, -0.18486023, -0.024290733, -0.3673846, -0.20295864, 0.23055002, -0.1555852, -0.02706522, 0.03262891, 0.008724611, -0.03760652, -0.20946771, -0.01951837, 0.16955496, 0.11690098) * go_1(1.0, 0.0);
|
||||
result += mat4(0.0783421, 0.22656651, -0.15715368, -0.024174158, 0.020260733, 0.032390315, -0.029133298, 0.086601086, 0.13871798, -0.12525433, 0.16097449, 0.058946393, 0.029865682, 0.08508385, 0.040569812, -0.09402932) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.05063873, 0.11269313, -0.057484943, -0.13579641, 0.047973365, -0.07103839, -0.07838756, -0.0028928046, -0.019466015, 0.018428024, 0.010016324, -0.057396665, -0.19495595, 0.034307264, -0.022888038, 0.08112259) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.09790086, 0.10613111, 0.06611674, 0.19356097, -0.00073371036, -0.019078335, 0.076719105, -0.016212497, -0.3283475, -0.07547389, -0.08140701, 0.3185625, -0.25060275, 0.16820994, -0.123497784, 0.43272668) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.06365342, 0.11186735, -0.17493224, -0.04207358, 0.0003117533, 0.034089327, -3.067692e-05, -0.03422754, 0.16267666, 0.054771993, 0.048384454, -0.041866794, 0.0036008756, 0.0021496525, 0.20258942, -0.06297619) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.03578836, 0.08763908, -0.22370125, -0.32465744, 0.019142643, 0.011316954, 0.17920344, 0.031633645, 0.03766343, -0.116487674, -0.05281752, -0.018965483, 0.049297336, -0.34511214, 0.42598158, 0.051361635) * go_2(0.0, -1.0);
|
||||
result += mat4(0.26638633, -0.33628765, 0.04437907, 0.09616201, -0.020049393, 0.2560829, -0.027108455, 0.255752, 0.3666511, 0.052277412, -0.46667686, 0.48482272, 0.51302284, -0.06941614, -0.17967525, -0.07889891) * go_2(0.0, 0.0);
|
||||
result += mat4(0.18503937, 0.088710256, 0.2083147, -0.20758459, -0.036416974, 0.018303726, 0.03729963, -0.035969947, -0.2685231, -0.42169708, -0.039593916, -0.02642618, 0.29050872, -0.25723743, -0.111259766, 0.15001127) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.026473878, -0.07241443, 0.022400148, -0.03214132, 0.0859297, -0.0036677981, -0.07039137, 0.03703108, 0.042322673, -0.01222808, -0.08151938, 0.033109214, -0.048737407, 0.25929528, -0.40535828, -0.123594694) * go_2(1.0, -1.0);
|
||||
result += mat4(0.10233285, 0.22455986, -0.13368733, 0.033236265, -0.052114893, -0.11709317, 0.009709581, 0.19201641, -0.02973698, 0.032114245, -0.09771862, 0.085680574, 0.15827927, -0.15042172, 0.21833214, -0.13262676) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.08460587, -0.09473209, 0.019323658, -0.057233352, 0.0019434267, -0.14437936, 0.034232683, 0.0030602294, -0.023598112, 0.10692026, -0.09960999, 0.005887181, 0.014738836, -0.32473162, -0.10886747, -0.08365826) * go_2(1.0, 1.0);
|
||||
result += mat4(0.10900178, 0.00080280803, -0.14009437, -0.053074867, -0.07811151, -0.03456029, -0.104943685, 0.016918905, -0.11335709, 0.079421654, 0.13481963, 0.037818357, -0.027339859, 0.05856774, -0.044562265, 0.03908084) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.07628258, -0.23815769, 0.2840278, -0.3541637, -0.044292126, -0.09310441, -0.1335055, -0.031899665, -0.11981227, 0.24012394, -0.041896038, -0.10168982, 0.20248915, -0.10036763, -0.044115108, 0.08520525) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.07234102, -0.119480744, -0.01401321, -0.025182616, -0.031284854, -0.050089385, 0.014808948, 0.038662236, -0.18539418, 0.017342187, 0.023812262, 0.13428104, 0.020824855, -0.07433546, 0.054307282, 0.08511016) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.11046813, -0.04663274, 0.33497185, 0.023273284, -0.24681108, 0.116665915, 0.12045893, 0.13306482, -0.039098527, 0.04747061, 0.042796664, 0.053514794, 0.011861975, -0.048702, 0.008408589, -0.09497112) * go_3(0.0, -1.0);
|
||||
result += mat4(0.34634927, 0.37973458, -0.79267627, -0.7362719, 0.35489878, -0.07635863, 0.24082923, -0.27480397, -0.3236968, -0.25523046, 0.05118527, -0.040529836, -0.6000509, 0.39020586, 0.27632973, 0.5141453) * go_3(0.0, 0.0);
|
||||
result += mat4(0.16761221, -0.033125393, 0.00561569, 0.083019435, -0.101278506, 0.07810264, 0.12060661, 0.16048536, 0.14257826, -0.15996903, 0.018831912, -0.094429865, -0.22227801, 0.426937, -0.054677445, 0.05067348) * go_3(0.0, 1.0);
|
||||
result += mat4(0.02233958, 0.02608942, -0.045318656, 0.06509929, 0.035911568, 0.025316885, 0.0840986, 0.08326237, 0.048455603, -0.13630742, 0.07230253, -0.047261715, -0.092630014, 0.04786565, 0.10354939, -0.07094341) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.1463382, -0.14900577, 0.2835977, -0.106733374, -0.11554754, -0.168429, -0.1411373, -0.20654152, -0.06388508, 0.039648015, 0.08543832, -0.13253337, 0.017264463, -0.06346233, -0.10823598, 0.067361064) * go_3(1.0, 0.0);
|
||||
result += mat4(0.04419582, 0.039152585, 0.06222691, 0.05757103, 0.012084537, 0.051425997, -0.061130576, 0.16752882, 0.07497411, 0.13495837, -0.15585983, -0.02050144, -0.08555421, -0.09147339, 0.025115604, 0.05948922) * go_3(1.0, 1.0);
|
||||
result += vec4(0.00590038, 0.03082865, 0.002111702, -0.03330112);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!SAVE conv2d_6_tf1
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.009029573, 0.029218858, 0.029705316, -0.019268971, -0.0023235187, -0.072589695, 0.1424836, 0.09049359, 0.04342995, 0.18134294, 0.018145641, 0.14789368, 0.050923645, 0.06524081, 0.036812488, 0.11108108) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.026506428, 0.016968496, 0.015961196, 0.010030791, -0.3141888, -0.06769598, -0.23920257, -0.031002127, -0.07351358, -0.19290134, -0.24282931, -0.18831016, -0.0928966, 0.075177215, -0.19699521, -0.05810917) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.017991852, -0.079427645, 0.035970494, -0.017095685, -0.27197137, -0.20046075, 0.2616644, 0.021876303, -0.077394076, -0.04978692, 0.20363241, -0.013741705, -0.032103598, 0.14403099, 0.01442474, 0.048115995) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.16939245, -0.001777, 0.026244136, -0.14122388, -0.056853324, 0.54357284, -0.19769607, -0.03187079, 0.04559263, -0.16048127, 0.12830622, 0.1442168, 0.006611398, -0.01618195, 0.012860053, -0.16539487) * go_0(0.0, -1.0);
|
||||
result += mat4(0.13116026, -0.006161343, 0.7209969, 0.18338475, 0.3099777, 0.6500026, 0.3883795, -0.021434233, 0.31667513, 0.008917659, 0.14124091, -0.22335114, 0.12198921, -0.16449445, 0.08773425, 0.30054978) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.10413989, -0.10316161, 0.04342709, -0.021252686, 0.120892406, 0.37798002, -0.35963747, 0.021069285, 0.37587845, -0.08159587, 0.011139747, 0.2501104, -0.094568014, 0.037900843, -0.025109999, -0.030106556) * go_0(0.0, 1.0);
|
||||
result += mat4(0.09680291, -0.040868275, 0.051731605, 0.089064725, -0.56098557, -0.38148618, -0.017037416, 0.08508287, -0.019247344, 0.019857002, -0.03512887, 0.031057188, -0.09648583, -0.04474188, 0.028748507, -0.11880965) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.010236943, 0.04257042, -0.08202597, -0.004203426, -0.26801527, -0.11716526, -0.017402772, -0.05819106, -0.13394608, 0.0234606, -0.15404865, -0.06801164, -0.0047627664, -0.1975249, 0.09420144, 0.23249897) * go_0(1.0, 0.0);
|
||||
result += mat4(0.107361935, 0.07373787, 0.06242962, 0.05236332, -0.028867323, 0.025924044, -0.042526353, -0.0015729597, -0.1323144, -0.4040712, 0.023919407, -0.09535502, 0.049100045, 0.081110805, 0.08946112, 0.058505684) * go_0(1.0, 1.0);
|
||||
result += mat4(0.13236825, -0.04468476, -0.04426802, 0.031087106, -0.09093992, -0.07470971, -0.01591504, 0.05924266, -0.21910913, 0.065537, -0.18358919, -0.02533145, -0.1512009, -0.04953928, 0.015540006, -0.0043442883) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.14016777, -0.1086958, 0.16316028, 0.050777458, 0.23148167, 0.04944809, -0.10599886, -0.10447021, -0.40729257, -0.10926556, 0.069055155, 0.110635415, 0.108922414, -0.1716362, 0.10743909, -0.102534756) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.017795928, -0.066930935, 0.09396082, 0.092585504, 0.14223933, 0.059458215, 0.072033696, -0.04507726, -0.19956456, 0.1251282, -0.31733638, -0.10465904, 0.08546377, 0.048638333, 0.031372465, -0.08720661) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.108719654, -0.092161916, -0.014724377, 0.20068261, -0.24350016, 0.2113636, -0.07483714, -0.45665312, -0.25134233, 0.2753893, -0.11324696, -0.04472, 0.1576102, -0.045395147, 0.06013951, -0.12507361) * go_1(0.0, -1.0);
|
||||
result += mat4(0.546225, -0.281897, 0.19477816, -0.116612464, -0.3145171, -0.41660902, 0.333625, 0.35902345, 0.48333502, 0.4662005, 0.10222491, -0.15314859, -0.3036888, 0.22849742, 0.20740797, 0.41399437) * go_1(0.0, 0.0);
|
||||
result += mat4(0.007284074, 0.0393942, -0.31192186, -0.15687793, -0.289214, -0.015956698, -0.24718472, -0.1637855, -0.00765037, 0.26677555, 0.20215511, 0.37790874, -0.22096673, 0.25287116, -0.2446764, -0.13610223) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.16734968, 0.16721225, -0.053508647, -0.041097626, 0.062356673, 0.07812319, -0.263546, -0.39739034, 0.003389846, 0.12676363, -0.13175991, -0.19019242, -0.011847587, -0.007580052, -0.023946386, 0.046034034) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.17047611, 0.13298693, -0.07506747, -0.045542978, 0.33571973, 0.20192616, 0.30674616, 0.25668672, -0.24134545, 0.031693842, -0.009647641, 0.040534843, 0.03159419, -0.1100516, 0.11371316, 0.06098735) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.05518961, 0.19402988, -0.09646874, -0.059196774, -0.0073436056, -0.1381309, 0.06868669, 0.061328378, -0.1480867, -0.15774113, -0.022572191, 0.122521356, -0.04067007, -0.10145177, 0.13006335, -0.099452734) * go_1(1.0, 1.0);
|
||||
result += mat4(0.06962972, 0.07768411, 0.021085173, 0.108355984, -0.03132525, 0.10220273, -0.11626593, -0.14104277, 0.018778645, -0.024237925, 0.048783034, 0.09074447, 0.4120426, -0.01948466, 0.073218934, 0.055681944) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.22553118, -0.12923603, -0.22068842, -0.35037905, 0.005709937, -0.09528472, 0.08718399, 0.13200706, 0.17220478, 0.096844435, -0.30439013, -0.14122063, 0.15733318, -0.1014675, 0.33836862, 0.042193163) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.15826897, -0.034870047, 0.09295099, -0.17674965, -0.042326324, 0.06680338, -0.074267656, -0.0631393, -0.11267909, -0.19795708, 0.22005288, 0.35703793, 0.033995766, -0.12663686, -0.02449896, -0.123250045) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.021434195, 0.058398597, 0.04828315, -0.0016824572, -0.04291545, -0.0744907, -0.07698706, -0.15937585, -0.18852457, -0.17966963, 0.023800725, 0.025979731, -0.51412296, -0.018316887, -0.23076254, -0.12298674) * go_2(0.0, -1.0);
|
||||
result += mat4(0.16054317, -0.0002730893, -0.54173076, -0.62443435, 0.04300197, -0.08529622, 0.15392275, 0.15742144, 0.025834514, -0.2800517, -0.17600477, 0.0020806703, -0.3010582, 0.45233512, 0.25595665, 0.103661336) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.024034392, -0.43800178, 0.28606912, -0.20908915, 0.078471914, -0.030501373, -0.059055753, 0.050494444, 0.063274644, -0.025071034, 0.17561312, -0.100698635, -0.25631955, 0.039981876, -0.18506624, 0.08366402) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.1413656, 0.03589635, -0.020917566, 0.017598262, 0.020156413, -0.018854238, 0.027228508, -0.03806087, -0.021715842, 0.071974196, -0.040065665, 0.08459291, -0.23530225, 0.16599682, -0.2772327, 0.10041177) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.055056706, 0.1286236, -0.11890451, -0.1790546, 0.16517544, -0.040448934, 0.12548013, 0.017075695, 0.07185459, -0.13236302, 0.19354409, 0.12767012, 0.31120765, 0.16378082, -0.036915366, -0.19724306) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.02225051, 0.033263147, 0.003279449, 0.08826271, -0.047833472, 6.574577e-05, 0.13721916, 0.04801998, -0.014958419, 0.08791209, -0.08076282, 0.024002168, -0.18028922, 0.23835851, -0.23309888, -0.119310364) * go_2(1.0, 1.0);
|
||||
result += mat4(0.044960875, 0.18821983, 0.027640678, 0.013462449, 0.19011214, 0.21559924, -0.03329638, 0.07234414, 0.030880248, -0.11273214, 0.102028474, 0.12203351, 0.035855662, 0.008828778, 0.007218363, -0.012421797) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.09450626, 0.025191775, -0.10738468, 0.16237053, 0.073676676, 0.12488881, -0.048748355, 0.007877263, 0.3572506, -0.07911043, 0.14684045, 0.0015310893, -0.33411503, -0.1151223, 0.004201752, 0.017775744) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.10607509, -0.008143826, -0.08448629, -0.27557802, 0.0046665915, 0.008158659, 0.030826218, 0.020516023, 0.2333065, -0.017463414, -0.041772116, -0.03027809, -0.028166672, -0.080471426, 0.048199337, 0.08341059) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.14640257, -0.18334304, -0.061674733, 0.0008892598, -0.2374775, -0.2721524, -0.040371176, 0.26362613, 0.19872928, -0.11246391, 0.0842288, 0.11188515, 0.0045209546, -0.04250933, -0.0738212, -0.069005966) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.08760266, 0.4816288, -0.21241407, 0.22734411, -0.1783721, -0.26842996, 0.099888, -0.2867675, 0.085521065, -0.3780281, -0.018543908, -0.039699722, 0.75688565, -0.5333645, 0.47567275, 0.09518891) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.04072665, 0.05998423, -0.48314768, -0.29495844, 0.10358383, -0.09816629, 0.028586809, -0.047708735, 0.008320228, 0.04089551, -0.18359782, -0.27615002, 0.12414414, -0.072417594, 0.25932562, 0.30268723) * go_3(0.0, 1.0);
|
||||
result += mat4(0.14481631, 0.06484443, -0.09898657, -0.06553556, 0.25750044, -0.07265585, 0.12903488, -0.022347894, -0.04693863, -0.000107379274, 0.030295763, -0.0325354, 0.086214684, -0.021326948, 0.039682828, -0.034843277) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.031971477, -0.25145087, 0.03931631, 0.14262606, -0.06044626, 0.22820354, -0.10506207, 0.18064679, 0.0069641788, 0.01477993, -0.003626875, 0.118767865, 0.109416224, -0.002998205, 0.035680585, 0.07843882) * go_3(1.0, 0.0);
|
||||
result += mat4(0.03375426, -0.059815384, 0.11632834, -0.12411481, 0.022583738, 0.02544465, -0.054889992, -0.07031964, -0.10140042, 0.16750422, -0.1448294, -0.09316004, 0.035582513, -0.026138382, -0.031955894, 0.040148776) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.03573331, 0.032919675, 0.011109369, 0.008329268);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x1x1x112
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!SAVE conv2d_last_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define g_0 (max((conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_1 (max((conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_2 (max(-(conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_5 (max((conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_6 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_9 (max((conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_10 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_13 (max((conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_14 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_15 (max(-(conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_16 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_17 (max((conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_18 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_19 (max(-(conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_20 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_21 (max((conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_22 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_23 (max(-(conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_24 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_25 (max((conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
#define g_26 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_27 (max(-(conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.11498094, -0.053904895, -0.11520678, -0.05479549, 0.028396055, 0.032767884, 0.052479446, 0.05257866, -0.25706592, -0.3454966, -0.24713765, -0.2854201, -0.10287636, 0.0023146886, -0.09190338, -0.011193905) * g_0;
|
||||
result += mat4(-0.05461422, 0.008780496, -0.07738697, -0.032230727, -0.047554165, -0.025061952, -0.051897213, -0.009545297, -0.14548294, -0.15184018, -0.01313442, -0.015299784, -0.0007883845, -0.12866738, -0.15260352, -0.27081275) * g_1;
|
||||
result += mat4(0.11007706, 0.035344437, 0.11020841, 0.0425353, 0.1613199, 0.18417408, 0.09274313, 0.11943135, 0.106862, 0.079875536, 0.0937752, 0.068030775, 0.029093558, -0.06441164, 0.06467169, -0.021989612) * g_2;
|
||||
result += mat4(0.049548414, -0.012455486, 0.07185561, 0.021865537, 0.020969186, -0.03374196, -0.024260623, -0.07739141, 0.07164591, 0.12741035, 0.0379913, 0.076403245, 0.07049977, 0.0744538, 0.0062989634, 0.01818882) * g_3;
|
||||
result += mat4(-0.12511204, -0.010836819, 0.13709816, 0.22472954, 0.21280868, -0.006484726, 0.17554289, -0.009977173, 0.078398876, 0.20698707, 0.13432744, 0.29740283, -0.24750128, -0.32757792, -0.19807857, -0.2537023) * g_4;
|
||||
result += mat4(-0.27207088, -0.1385644, -0.2166476, -0.07687419, -0.20300622, -0.29678395, -0.13135734, -0.20851587, 0.0361364, 0.011243289, -0.06845459, -0.11796941, 0.11575868, 0.070215136, -0.10295678, -0.12281369) * g_5;
|
||||
result += mat4(0.13619795, -0.0019436983, -0.12701888, -0.25933513, -0.20134166, 0.00062823144, -0.076756015, 0.11002947, 0.0059049693, -0.18756741, -0.0718802, -0.2589954, 0.23413423, 0.30107784, 0.14445266, 0.18920745) * g_6;
|
||||
result += mat4(0.1494216, 0.0587532, 0.05478662, -0.039123338, 0.23322394, 0.29950607, 0.24384268, 0.27843767, -0.16094431, -0.04705998, -0.016345032, 0.028868208, -0.102872886, -0.04659664, 0.104105346, 0.14305067) * g_7;
|
||||
result += mat4(-0.001037014, 0.010001526, -0.0052278573, 0.024779709, 0.06857274, 0.067640975, 0.085439384, 0.09242789, -0.066597246, -0.055928994, 0.0015658981, 0.016131008, -0.03524695, -0.018364554, -0.047754433, -0.014295886) * g_8;
|
||||
result += mat4(-0.042207, 0.02835915, -0.1404656, -0.08563323, -0.030979915, -0.0673764, 0.10733943, 0.057902794, 0.00022424995, -0.0023634837, -0.10778953, -0.10202357, -0.020368295, -0.019088887, -0.06875738, -0.08504131) * g_9;
|
||||
result += mat4(-0.00043458896, 0.00045652856, -0.02016843, -0.020062413, -0.08740103, -0.042085808, -0.10644177, -0.09226477, 0.11212161, -0.00048174805, 0.021872435, -0.05868698, 0.0333954, 0.058184672, 0.05532576, 0.07621587) * g_10;
|
||||
result += mat4(0.054245148, 0.001020329, 0.09106849, 0.05303779, 0.009889632, 0.01309413, -0.09187347, -0.08618193, -0.011621187, 0.016222361, 0.061095525, 0.060885344, 0.078050986, 0.0111776795, 0.08829944, 0.032022282) * g_11;
|
||||
result += mat4(0.01643529, 0.02285545, -0.03498564, 0.00769657, -0.0042474116, 0.015836312, -0.025771018, -0.0016368, -0.008897948, -0.012588166, -0.01416411, -0.003578984, 0.025991246, 0.021237152, 0.017450012, 0.025172485) * g_12;
|
||||
result += mat4(0.014568868, 0.017796224, -0.036679734, -0.03138748, 0.019457601, -0.027607411, -0.004529679, -0.038048342, -0.054055385, -0.03876025, 0.041948095, 0.005869784, 0.02439633, 0.05177997, 0.016000897, 0.0057169925) * g_13;
|
||||
result += mat4(-0.03021866, 0.017678728, -0.01371109, 0.013548159, -0.0038099394, -0.014066414, 0.028093752, 0.0027308422, -0.010615999, 0.012673458, -0.03028171, -0.016818244, -0.06530097, -0.018845048, -0.0072947564, -0.0038243714) * g_14;
|
||||
result += mat4(-0.019006258, -0.007847591, 0.03690709, 0.06714211, 0.0073993434, -0.009766907, -0.0021441753, -0.01308625, 0.06658726, 0.06701995, -0.027305668, -0.016032105, -0.028976806, -0.0036668575, -0.0027825525, 0.0105632655) * g_15;
|
||||
result += mat4(0.028945107, -0.0014701135, 0.048950657, -0.01923516, -0.0014054152, 0.002650635, -0.005300331, 0.004860559, 0.011158468, 0.005940625, -0.012095051, 0.0041518128, -0.020433836, -0.025870577, -0.0007547932, -0.026509356) * g_16;
|
||||
result += mat4(-0.004545374, 0.04264545, 0.021741537, 0.029115127, 0.04225599, -0.0055392785, 0.026570829, -0.031795148, -0.008307126, 0.020176455, 0.010904648, 0.017765503, -0.10806103, -0.01776947, 0.00070428237, -0.06356262) * g_17;
|
||||
result += mat4(-0.05663172, 0.05908046, -0.03837452, 0.06636983, -0.007960516, -0.06384041, 0.023125881, -0.030108837, 0.0038054318, -0.023263922, 0.020264054, -0.0062937695, 0.031630237, 0.020909082, 0.03594235, 0.035879835) * g_18;
|
||||
result += mat4(-0.0050448794, 0.033650696, -0.002830413, 0.035174295, -0.024521282, 0.013054315, -0.020833842, 0.037953895, 0.08249671, 0.024239466, -0.012758333, -0.027316988, 0.051040914, 0.0005025873, 0.039778862, 0.0024668393) * g_19;
|
||||
result += mat4(0.017232442, 0.022482058, 0.020233413, 0.024337437, 0.07986929, 0.06234036, 0.12662584, -0.05271183, -0.009718745, -0.0046989853, -0.0030333172, -0.04034237, -0.0113442, 0.022746231, -0.035293855, -0.009433693) * g_20;
|
||||
result += mat4(0.015766997, 0.013647276, -0.029327558, 0.039106004, -0.010398323, -0.032851525, 0.02908329, -0.003789618, 0.12963496, 0.010851003, 0.1126276, -0.049255487, 0.06867432, 0.07970792, 0.017840397, -0.026481882) * g_21;
|
||||
result += mat4(-0.058729574, -0.07886952, 0.033267397, 0.02755372, -0.0172006, 0.012404398, -0.0230168, -0.015059758, -0.09239916, -0.029533267, -0.043251917, 0.0035152994, 0.022931995, 0.101714484, -0.044946067, 0.094993) * g_22;
|
||||
result += mat4(-0.04708704, -0.032475296, -0.03228093, -0.08810475, 0.013745045, 0.027828002, -0.031922746, 0.022986397, -0.061620213, -0.03694645, -0.055026993, 0.0031291894, -0.028799903, -0.0025357977, -0.03441407, 0.0028600092) * g_23;
|
||||
result += mat4(0.058981724, -0.10447273, -0.088705614, 0.16546178, -0.023549391, -0.008831522, -0.018411588, 0.029640056, -0.068086684, -0.05414636, -0.029401174, 0.036180343, -0.031988926, -0.047249753, 0.008162177, 0.00548062) * g_24;
|
||||
result += mat4(0.05287462, -0.030657746, 0.02821435, 0.037005343, 0.03534311, -0.15614955, 0.07085459, -0.11997641, -0.009156166, -0.021968868, -0.054147746, -0.07307657, -0.006428544, -0.017528288, 0.012614676, 0.037840024) * g_25;
|
||||
result += mat4(-0.021977803, 0.047799855, 0.02660416, -0.07292106, 0.045195807, -0.0056674764, 0.10824326, -0.112114795, 0.1447127, -0.0119616175, 0.0011661504, -0.04553905, 0.13048342, 0.14574122, -0.105522245, -0.102792375) * g_26;
|
||||
result += mat4(-0.16397473, 0.15785863, -0.06666504, -0.01682913, 0.06070918, 0.070222184, 0.037701584, 0.026657054, -0.0835267, -0.009457008, 0.13232987, 0.13508691, -0.056414206, -0.06818828, 0.079076104, 0.032249212) * g_27;
|
||||
result += vec4(-0.10795144, -0.09953324, -0.055413827, -0.03875493);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x1x1x112
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!SAVE conv2d_last_tf1
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define g_0 (max((conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_1 (max((conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_2 (max(-(conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_5 (max((conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_6 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_9 (max((conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_10 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_13 (max((conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_14 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_15 (max(-(conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_16 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_17 (max((conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_18 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_19 (max(-(conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_20 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_21 (max((conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_22 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_23 (max(-(conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_24 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_25 (max((conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
#define g_26 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_27 (max(-(conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.024905335, -0.0020974763, 0.02695263, 0.00016802056, -0.024053082, -0.02133723, -0.031614035, -0.031826317, 0.120421864, 0.10555479, 0.08609448, 0.116875134, 0.046175968, 0.04224941, 0.059216674, 0.035143953) * g_0;
|
||||
result += mat4(0.059397914, 0.016519934, 0.07189327, 0.047407165, 0.04808963, 0.02792908, 0.057017103, 0.034324065, 0.14228246, 0.11275426, 0.088058695, 0.059600517, 0.02063494, 0.052596953, 0.047207687, 0.08789091) * g_1;
|
||||
result += mat4(-0.013453174, 0.008474715, -0.017593835, 0.009218917, 0.070580654, 0.040542338, 0.08812338, 0.074653216, -0.016356857, 0.015809007, -0.008739107, 0.0097674895, -0.018381525, -0.007775341, -0.040571664, -0.011188163) * g_2;
|
||||
result += mat4(-0.026196122, -0.034825727, -0.042998232, -0.033436514, -0.01678153, -0.004592797, -0.010311677, 0.0008815291, -0.08899181, -0.10274026, -0.066960976, -0.082430154, -0.057137426, -0.07554528, -0.030993424, -0.050372377) * g_3;
|
||||
result += mat4(0.022921838, -0.010479244, -0.050794605, -0.073633075, -0.053708922, 0.009594084, -0.071259, -0.01054356, 0.005165821, -0.08024963, -0.049251772, -0.09581235, 0.17995799, 0.09743011, 0.13533138, 0.11643848) * g_4;
|
||||
result += mat4(0.09727046, 0.07292666, 0.06820908, 0.041535784, -0.0049705, 0.0048759184, -0.035702795, -0.015944308, -0.010730028, 0.018847652, 0.06466244, 0.086318985, -0.05661574, -0.040698618, 0.010839972, 0.0027009705) * g_5;
|
||||
result += mat4(-0.04628466, 0.010060396, 0.02609333, 0.08664702, 0.057045907, 0.033591177, 0.02186063, -0.024303377, 0.006569828, 0.08025825, 0.016128821, 0.10180713, -0.12228169, -0.112990454, -0.078443415, -0.09126021) * g_6;
|
||||
result += mat4(-0.12733299, -0.087755, -0.07374111, -0.044979006, -0.025347412, -0.004083168, 0.023782173, 0.02900392, -0.017815407, -0.041119996, -0.057978686, -0.13521095, 0.08364004, 0.06950181, 0.023554614, 0.008043734) * g_7;
|
||||
result += mat4(0.009062775, -0.003570175, -0.007378757, -0.0018487388, 0.01145638, 0.05217187, -0.008250244, 0.008433307, -0.056756936, -0.044681005, -0.08096105, -0.08033185, -0.023784965, -0.01859799, 0.013042476, 0.021188647) * g_8;
|
||||
result += mat4(-0.0071619656, -0.012498299, -0.05144986, -0.078112476, -0.034992415, -0.017038302, -0.04464615, -0.044504963, 0.024249, -0.004297534, 0.03674578, 0.03090718, 0.04698553, 0.008344952, 0.057619847, -0.0338724) * g_9;
|
||||
result += mat4(-0.011845145, -0.0045043705, -1.6646482e-06, -0.0038495932, -0.01992515, 0.004827126, 0.019493148, 0.00862289, 0.10151322, 0.0021909082, 0.09940764, 0.03728846, 0.027824005, 0.04358071, 0.014909185, 0.036326095) * g_10;
|
||||
result += mat4(0.022513246, 0.028257169, 0.0102195935, 0.03301329, 0.052253865, -0.0021944977, 0.08247392, 0.03256867, -0.040685873, -0.0052207555, -0.0451257, -0.054165114, 0.01647699, 0.0028809097, -0.015233776, -0.0008741886) * g_11;
|
||||
result += mat4(0.017371105, 0.01597189, -0.052552313, -0.008554715, -0.0023150423, 0.006076517, -0.012868931, 0.0039361073, -0.007524978, -0.004284313, -0.021520883, -0.010327569, 0.02543678, 0.008725823, -0.0073885336, 0.005528395) * g_12;
|
||||
result += mat4(0.019192757, 0.016561812, 0.0027538154, 0.0013078215, 0.007916496, -0.042525183, -0.013173432, -0.05265476, -0.062195376, -0.011255499, 0.020898128, 0.021532273, -0.001524097, 0.034835674, -0.004051403, -0.0292426) * g_13;
|
||||
result += mat4(-0.049191684, -9.43322e-06, -0.009106849, 0.012845289, -0.019482708, -0.011163468, 0.0034011535, -0.007062845, -0.006469714, 0.03177786, -0.033006195, -0.0006813464, -0.053963087, 0.00085209147, 0.02734121, 0.034086403) * g_14;
|
||||
result += mat4(-0.03232248, -0.004037002, -0.010319106, 0.030889064, 0.019604538, 0.0020888883, 0.010277864, 0.000661223, 0.057915937, 0.030683514, 0.00042533095, -0.013019287, -0.015896408, 0.0038484468, -0.0042103594, 0.02174542) * g_15;
|
||||
result += mat4(0.032975145, 0.0011456647, 0.04913679, -0.017063798, 0.0117176045, 0.007440557, 0.0020480808, 0.009415731, 0.027573857, 0.015140836, -0.01679426, -0.006124731, -0.03206279, -0.029842237, -0.010428016, -0.028513178) * g_16;
|
||||
result += mat4(-0.00506859, 0.055869613, 0.010164368, 0.027031485, 0.042289548, -0.0054258504, 0.032214936, -0.029970925, -0.0058315448, 0.022889478, 0.01681123, 0.02985076, -0.111186065, -0.02202099, 0.0030994313, -0.062343158) * g_17;
|
||||
result += mat4(-0.060951103, 0.06079555, -0.0396464, 0.070911355, -0.011480358, -0.06803282, 0.01637355, -0.043100975, -0.00423709, -0.028337711, 0.021635853, 0.0014857082, 0.030084312, 0.018155476, 0.043694943, 0.038795974) * g_18;
|
||||
result += mat4(-0.0060662925, 0.029721662, -0.008117774, 0.034551267, -0.024477571, 0.018841071, -0.027095588, 0.034495078, 0.082398005, 0.008998768, -0.016399248, -0.043801688, 0.05936684, 0.006066549, 0.045399766, 3.5319943e-05) * g_19;
|
||||
result += mat4(0.019259382, 0.02494012, 0.029301709, 0.028329274, 0.09122267, 0.06900443, 0.1412115, -0.043169618, -0.01627418, -0.004989528, -0.0042651827, -0.04556752, -0.023623291, 0.013007996, -0.04483056, -0.015727345) * g_20;
|
||||
result += mat4(0.016332543, 0.016384754, -0.030676385, 0.045312885, -0.0100853555, -0.032632045, 0.031514473, -0.0070776115, 0.13642761, 0.0023589598, 0.12214136, -0.062155515, 0.08240989, 0.08894205, 0.03325406, -0.016589595) * g_21;
|
||||
result += mat4(-0.06494277, -0.08158925, 0.030425413, 0.019835634, -0.012624623, 0.013942616, -0.030527417, -0.021668324, -0.09444672, -0.033064254, -0.044167448, 0.0011024752, 0.03210801, 0.12662941, -0.03912534, 0.1112649) * g_22;
|
||||
result += mat4(-0.04716062, -0.03751481, -0.031030515, -0.09067383, 0.0077815712, 0.02169541, -0.035285182, 0.02290573, -0.0704085, -0.03916127, -0.058103334, 0.004915147, -0.0333844, -0.011548617, -0.031151932, -0.00043817286) * g_23;
|
||||
result += mat4(0.05976319, -0.107285, -0.097245865, 0.17706421, -0.021453341, -0.0047738464, -0.017621001, 0.033400454, -0.07225561, -0.05599672, -0.027600193, 0.038664024, -0.03762786, -0.052429967, 0.0104017975, 0.007116869) * g_24;
|
||||
result += mat4(0.06014114, -0.029824806, 0.03209269, 0.04392036, 0.031300627, -0.16249833, 0.06878509, -0.12658615, -0.012383169, -0.025043553, -0.06527381, -0.08149099, -0.014006842, -0.018669648, 0.014510818, 0.042045828) * g_25;
|
||||
result += mat4(-0.023342922, 0.047104675, 0.029629575, -0.082307704, 0.04035797, -0.0013049254, 0.11085582, -0.11031226, 0.14778149, -0.016699014, -0.00634342, -0.055320874, 0.14306462, 0.15896587, -0.110229075, -0.1069649) * g_26;
|
||||
result += mat4(-0.17449625, 0.15787153, -0.06711028, -0.023110518, 0.06862914, 0.074063435, 0.042682912, 0.029800726, -0.08768606, -0.009814701, 0.14180017, 0.14780663, -0.05672417, -0.074305914, 0.07873489, 0.028458012) * g_27;
|
||||
result += vec4(0.06026231, 0.040204916, 0.037672628, 0.023496555);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Conv-4x1x1x112
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!SAVE conv2d_last_tf2
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define g_0 (max((conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_1 (max((conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_2 (max(-(conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_5 (max((conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_6 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_9 (max((conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_10 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_13 (max((conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_14 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_15 (max(-(conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_16 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_17 (max((conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_18 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_19 (max(-(conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_20 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_21 (max((conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_22 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_23 (max(-(conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_24 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_25 (max((conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
#define g_26 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_27 (max(-(conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.1765669, 0.14268716, 0.19186598, 0.15799578, 0.016374417, 0.018578433, 0.0039475, 0.0046772263, 0.39840183, 0.36909792, 0.35409746, 0.37422222, -0.108508386, -0.1331279, -0.10336035, -0.14776541) * g_0;
|
||||
result += mat4(-0.057757027, -0.14071062, -0.025283009, -0.09397916, -0.09031894, -0.14219165, -0.08299535, -0.13970287, -0.12259208, -0.14382727, -0.22002274, -0.25016093, -0.048906635, 0.06620249, 0.016965045, 0.1295978) * g_1;
|
||||
result += mat4(-0.16748372, -0.13718611, -0.18565705, -0.15029612, -0.080749065, -0.09955825, 0.032431383, 0.023855643, -0.2748885, -0.23232168, -0.29121292, -0.26405892, 0.16556135, 0.18657646, 0.1424068, 0.18855052) * g_2;
|
||||
result += mat4(0.10960496, 0.10851629, 0.095003806, 0.11053746, 0.09885307, 0.14437789, 0.13191165, 0.17365928, 0.16558935, 0.15473324, 0.21136154, 0.19976667, -0.07267957, -0.11469687, -0.029134216, -0.06817615) * g_3;
|
||||
result += mat4(0.10202856, 0.04216857, -0.03959349, -0.09849683, -0.1576996, -0.049997438, -0.1579918, -0.058789205, 0.029792828, -0.07311781, -0.045432188, -0.11312683, 0.24257647, 0.16204113, 0.17869382, 0.16024388) * g_4;
|
||||
result += mat4(0.17193612, 0.12692013, 0.13177487, 0.0796725, 0.0797928, 0.08952722, -0.012468046, 0.011071511, -0.068559825, -0.024852324, 0.0526428, 0.07917346, -0.085534215, -0.09591339, 0.04615827, 0.024577664) * g_5;
|
||||
result += mat4(-0.14653449, -0.067267366, -0.002524394, 0.086243175, 0.13660401, 0.08039592, 0.09179008, 0.022573143, -0.024744196, 0.09120211, 0.017654825, 0.14114714, -0.16093308, -0.14538004, -0.09950235, -0.111152865) * g_6;
|
||||
result += mat4(-0.188637, -0.12968326, -0.1200479, -0.06537649, -0.12589337, -0.106242515, -0.02788782, -0.025949068, 0.04948153, 0.02222735, -0.025291357, -0.12379292, 0.11074645, 0.11902375, -0.00056989543, -0.0024386419) * g_7;
|
||||
result += mat4(0.018286629, 0.0072215167, 0.00037828335, 0.0047001047, 0.011478272, 0.041745186, -0.015742473, -0.002282524, -0.03440817, -0.02196847, -0.07838253, -0.07993771, -0.010155526, -0.017590692, 0.027141469, 0.029741213) * g_8;
|
||||
result += mat4(0.016512005, 0.004950637, -0.0238836, -0.05587327, -0.03164328, -0.009499985, -0.059880238, -0.061794154, 0.023154303, -0.013266373, 0.04701534, 0.0415862, 0.06357814, 0.033057794, 0.08389772, 0.00035060212) * g_9;
|
||||
result += mat4(-0.016403968, -0.012538788, -0.0015746636, -0.004771009, -0.021361275, -0.009695242, 0.020548422, -0.0024130535, 0.07796766, -0.01516671, 0.09961382, 0.042754963, 0.017363647, 0.03729065, -0.004795824, 0.01550197) * g_10;
|
||||
result += mat4(-0.0028093113, 0.011869523, -0.02216933, 0.011177349, 0.033342455, -0.021146454, 0.07830085, 0.032490104, -0.03281833, 0.0060484232, -0.04081057, -0.04945058, -0.0056189033, -0.010636801, -0.041949317, -0.025739705) * g_11;
|
||||
result += mat4(0.012979897, 0.016758928, -0.049062215, -0.0035748442, 0.0085972, 0.0036381132, -0.0055621094, 0.0041307937, -0.0008907763, -0.0034079372, -0.025680453, -0.015531803, 0.012816766, 0.009977763, -0.016416566, 0.0034859509) * g_12;
|
||||
result += mat4(0.021753248, 0.016452711, 0.009833835, 0.0065052663, 0.0014061348, -0.046160888, -0.0132271005, -0.05051269, -0.05746351, -0.0012690664, 0.017191738, 0.018192926, -0.008879476, 0.026354216, -0.012801991, -0.029587373) * g_13;
|
||||
result += mat4(-0.04220692, -0.0015560482, -0.0019648245, 0.013402305, -0.018259782, -0.0036008905, 0.0035650074, -0.0019178417, 0.00051580026, 0.027355857, -0.017914988, 0.004937948, -0.046335887, 0.00013612259, 0.030293299, 0.030688645) * g_14;
|
||||
result += mat4(-0.036683388, -0.0031274238, -0.026074665, 0.021684237, 0.022639066, 0.0022493738, 0.011508554, -0.0006385944, 0.04890418, 0.020119468, 0.004167364, -0.008356099, -0.008598796, 0.0089028, -0.0029575853, 0.016687104) * g_15;
|
||||
result += mat4(0.027207986, 0.0011099194, 0.042383645, -0.015179333, 0.014744431, 0.006148344, 0.005165422, 0.0070196544, 0.030286826, 0.016620956, -0.01611366, -0.00667594, -0.029524863, -0.024751091, -0.013321004, -0.025199674) * g_16;
|
||||
result += mat4(0.0027477827, 0.054622147, 0.010154094, 0.025437292, 0.031773083, -0.01055473, 0.022864206, -0.029010754, -0.0029999653, 0.025018329, 0.015316208, 0.027188798, -0.10096525, -0.017268656, 0.0012529213, -0.062078856) * g_17;
|
||||
result += mat4(-0.053670805, 0.057336535, -0.037418038, 0.06443577, -0.016027879, -0.058168363, 0.007034215, -0.03390141, -0.0019346164, -0.027947908, 0.021723913, -0.0018286633, 0.030507812, 0.018293543, 0.042917266, 0.033528328) * g_18;
|
||||
result += mat4(-0.004559579, 0.029667616, -0.001870353, 0.0378995, -0.017147437, 0.020192018, -0.021574946, 0.031568103, 0.07487145, 0.0032376775, -0.018893708, -0.041981626, 0.054478757, 0.0061423797, 0.041280247, 0.000878061) * g_19;
|
||||
result += mat4(0.017076394, 0.023647636, 0.029403262, 0.029923365, 0.08866472, 0.060613394, 0.1314274, -0.04490231, -0.016304834, -0.0062647443, -0.0031828512, -0.03989252, -0.024330825, 0.00741213, -0.04075287, -0.01615817) * g_20;
|
||||
result += mat4(0.017866978, 0.017720113, -0.02846163, 0.040761847, -0.0063438355, -0.02347501, 0.029564403, -0.0029562064, 0.12505588, -0.0073986333, 0.11250363, -0.06179967, 0.07854423, 0.08546533, 0.034743227, -0.010757377) * g_21;
|
||||
result += mat4(-0.06416677, -0.08344284, 0.030138884, 0.017635904, -0.012087523, 0.014205202, -0.03221233, -0.023834767, -0.091186255, -0.028958676, -0.04724334, 0.00013161585, 0.027391518, 0.1249978, -0.045047652, 0.10737729) * g_22;
|
||||
result += mat4(-0.04326348, -0.03543181, -0.029558217, -0.08582413, 0.007812453, 0.014296562, -0.028779754, 0.018517692, -0.063755795, -0.036619596, -0.050809663, 0.005431336, -0.029205568, -0.011827915, -0.031110523, -0.005648626) * g_23;
|
||||
result += mat4(0.05499293, -0.10000709, -0.0943537, 0.16143042, -0.019952895, -0.0039807972, -0.014841254, 0.0320363, -0.065173544, -0.049425576, -0.023904482, 0.03759679, -0.03207411, -0.047782745, 0.01352581, 0.008140566) * g_24;
|
||||
result += mat4(0.055923894, -0.025134467, 0.029583648, 0.04096879, 0.027551858, -0.14995384, 0.06467113, -0.11633077, -0.01563784, -0.026909819, -0.06292879, -0.078409635, -0.009081105, -0.015533088, 0.019585673, 0.04334208) * g_25;
|
||||
result += mat4(-0.021717606, 0.042464726, 0.02743202, -0.07388838, 0.03460472, 0.0038285658, 0.099842004, -0.098247, 0.13276267, -0.020793032, -0.008603039, -0.051913783, 0.12959045, 0.14735717, -0.10888226, -0.10263746) * g_26;
|
||||
result += mat4(-0.16819532, 0.141579, -0.062480718, -0.021918943, 0.06348125, 0.06849444, 0.03888676, 0.027375204, -0.08194279, -0.012574497, 0.13523251, 0.13739482, -0.047547445, -0.058767617, 0.07009549, 0.028136581) * g_27;
|
||||
result += vec4(0.069033325, 0.040207114, 0.027286075, 0.0065334598);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-CNN-x2-(VL)-Depth-to-Space
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_last_tf
|
||||
//!BIND conv2d_last_tf1
|
||||
//!BIND conv2d_last_tf2
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_last_tf.w 2 *
|
||||
//!HEIGHT conv2d_last_tf.h 2 *
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
vec4 hook() {
|
||||
vec2 f0 = fract(conv2d_last_tf_pos * conv2d_last_tf_size);
|
||||
ivec2 i0 = ivec2(f0 * vec2(2.0));
|
||||
float c0 = conv2d_last_tf_tex((vec2(0.5) - f0) * conv2d_last_tf_pt + conv2d_last_tf_pos)[i0.y * 2 + i0.x];
|
||||
vec2 f1 = fract(conv2d_last_tf1_pos * conv2d_last_tf1_size);
|
||||
ivec2 i1 = ivec2(f1 * vec2(2.0));
|
||||
float c1 = conv2d_last_tf1_tex((vec2(0.5) - f1) * conv2d_last_tf1_pt + conv2d_last_tf1_pos)[i1.y * 2 + i1.x];
|
||||
vec2 f2 = fract(conv2d_last_tf2_pos * conv2d_last_tf2_size);
|
||||
ivec2 i2 = ivec2(f2 * vec2(2.0));
|
||||
float c2 = conv2d_last_tf2_tex((vec2(0.5) - f2) * conv2d_last_tf2_pt + conv2d_last_tf2_pos)[i2.y * 2 + i2.x];
|
||||
float c3 = c2;
|
||||
return vec4(c0, c1, c2, c3) + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(M)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.029052526, 0.059789784, -0.024398074, 0.06907132, 0.18920785, -0.12923062, 0.0766382, -0.12048348, -0.017786544, 0.06251133, -0.068393864, 0.056690093, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.14032267, -0.077691495, -0.009036259, -0.13049065, 0.20954624, 0.023231741, -0.2759354, 0.49927905, 0.039609738, -0.092625424, 0.09426452, -0.2246486, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.023119625, 0.046549924, 0.073033765, 0.03727065, 0.04498207, 0.024455868, 0.17602317, -0.3150503, 0.019985953, 0.03670126, 0.0071220254, 0.107966185, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.111121014, -0.084099665, 0.12595509, -0.048271902, -0.007799661, 0.04831373, 0.11868961, 0.11607051, 0.05169621, -0.050569464, 0.120362274, 0.034607537, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.41167754, -0.44940078, 0.35485214, 0.58048695, -1.0151424, -0.70137614, 0.38405335, 0.37337455, -0.096364655, -0.14538667, 0.17917591, 0.32259464, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(0.06378494, -0.040756933, -0.4773648, -0.47702238, 0.1803328, -0.21388084, -0.5509359, -0.6491179, -0.048081584, -0.0025129975, -0.28561604, -0.22229671, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.037024107, 0.016497454, -0.05315267, -0.023392007, 0.1840294, 0.12675077, 0.037417043, -0.022394283, -0.028192522, -0.016344562, -0.07269005, -0.04747136, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(0.039480202, 0.5577544, -0.117326505, 0.06622856, -0.038784727, 0.65673745, -0.109742545, 0.22294083, 0.00038519394, 0.24552485, -0.07008514, 0.00029412706, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.009279719, -0.031882852, 0.14124188, -0.0759899, -0.024016602, 0.15252088, 0.13614258, -0.09961189, 0.05446014, -0.03827061, 0.11210173, -0.028823104, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(0.012836382, -0.0062823873, -0.03165346, -0.0017501811);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.06215308, -0.054471835, 0.1285146, 0.037585296, -0.14467795, 0.0057610427, 0.006528968, 0.18607244, 0.03762581, -0.121003255, 0.0827445, 0.076479666, 0.07540097, 0.16371846, -0.18786757, -0.12048073) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.11520603, -0.22384967, 0.0970881, 0.045122143, -0.40358877, 0.12487416, -0.4489702, 0.04854906, -0.08240888, -0.0058777514, 0.19108902, 0.042189106, -0.07843178, 0.0012592699, -0.11303816, -0.1118517) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.29387334, 0.08150406, -0.06009834, 0.07054583, -0.146034, 0.04053809, 0.23284695, -0.08233496, 0.0957811, 0.20221621, 0.13570721, -0.081069246, -0.031743366, -0.038912926, -0.059060514, 0.05190416) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.18404631, -0.034244366, -0.13406059, 0.2242061, -0.23668705, -0.10359684, -0.09689738, -0.04932347, -0.0020525968, 0.15236467, -0.2634303, -0.029878438, 0.3283669, 0.09891668, -0.46656898, -0.03271751) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.1824976, -1.0545974, 0.93027455, -0.13887188, 0.3128633, -0.2734884, -0.831517, -0.18065166, -0.2119423, 0.19241124, -0.13313763, -0.10523897, 0.2675327, -0.06853148, 0.007885104, 0.26000848) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.18109167, -0.019768981, -0.14131357, -0.3181756, 0.22158594, 0.1431138, -0.12970252, -0.011459096, -0.03742945, 0.2316056, -0.054623842, -0.09360549, 0.10176328, -0.108150974, 0.122787155, 0.07614884) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.02370754, -0.10264054, 0.030659392, 0.056694325, 0.034085, -0.0538203, 0.09111551, 0.0063995267, 0.0835243, -0.06623529, 0.20924146, 0.09457414, 0.27925664, 0.049511474, -0.22062886, 0.03312504) * go_0(1.0, -1.0);
|
||||
result += mat4(0.17009354, 0.34391564, -0.1680695, -0.051450633, -0.044037253, -0.1412577, 0.01097572, -0.049040757, 0.104024716, -0.34571946, 0.5213214, -0.17010914, -0.016452854, 0.3303069, -0.22249438, 0.23866816) * go_0(1.0, 0.0);
|
||||
result += mat4(0.20491506, 0.20098424, 0.015425732, -0.033999693, -0.0111842435, 0.09945295, -0.025766203, 0.17068656, 0.049262784, 0.0077788536, 0.068585835, 0.19229786, -0.013048818, 0.04877973, 0.024053875, -0.06846659) * go_0(1.0, 1.0);
|
||||
result += mat4(0.14208305, 0.09790381, -0.008420949, -0.016165754, 0.02445528, 0.08700781, 0.046639573, -0.22105917, -0.08529265, 0.06606378, 0.0947481, 0.08149193, -0.0959293, -0.037756894, -0.008136973, 0.046241503) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.2577669, 0.13766493, 0.021107635, 0.018978242, 0.452542, 0.25566816, -0.68909633, 0.03804329, 0.06771752, 0.07894156, 0.22501312, -0.047511246, 0.00040517355, -0.0202232, -0.27541754, -0.040150844) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.30176973, -0.15739526, -0.038548045, -0.07003333, 0.32053417, 0.025467036, -0.044913124, 0.20454903, 0.12475206, -0.03966162, 0.07139637, 0.12101497, -0.10777517, -0.062379625, 0.06598757, -0.14795317) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.12068516, 0.0026514034, -0.055378057, -0.0976728, 0.15887645, 0.15590422, 0.076294206, -0.15417404, -0.16548084, -0.18422292, -0.1670212, 0.041155312, -0.11765263, 0.16991171, -0.21535093, 0.01542368) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.37845853, 0.5732961, 0.114283465, 0.14638355, -0.109194644, 0.087304994, -0.15938401, 0.58242995, -0.025850652, 0.02730721, -0.48582682, -0.2547883, 0.1899583, 0.24296008, -0.8162976, 0.018036429) * go_1(0.0, 0.0);
|
||||
result += mat4(0.1633212, -0.117295206, 0.021892091, 0.07762347, -0.09726402, -0.1364192, 0.10752197, 0.42020246, 0.06665656, -0.10822656, 0.1337331, 0.0552859, 0.04700212, 0.108017646, -0.2009353, -0.0435288) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.045603696, 0.05774526, -0.0071174325, 0.24119262, -0.06899063, 0.016012343, 0.009982042, -0.19038968, -0.17796072, -0.12510185, 0.22739507, -0.1805478, -0.100294635, 0.017557602, 0.039842658, 0.13116726) * go_1(1.0, -1.0);
|
||||
result += mat4(0.0131523665, -0.20472725, 0.121814765, -0.17769355, 0.097669855, 0.09648846, -0.072887406, 0.22992326, -0.019087939, 0.35375193, -0.057155706, 0.17699116, 0.030690158, -0.423475, 0.03703492, -0.03429164) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.12143413, -0.018402342, 0.04536776, -0.12743106, 0.03355068, -0.09694192, 0.09913357, -0.036602203, 0.11038047, 0.13236065, 0.12966877, -0.10163848, 0.0030612876, -0.116145626, 0.045318183, 0.11492169) * go_1(1.0, 1.0);
|
||||
result += vec4(0.05657016, -0.04848861, 0.10297782, -0.0076417355);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.088122115, -0.009916053, -0.124469265, -0.032139737, -0.13709281, 0.09177288, -0.06794775, -0.03962873, 0.17613642, -0.11064388, 0.2531882, -0.3817648, -0.1172188, -0.042132895, -0.098772734, -0.114560865) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.18876404, -0.14613804, 0.23869626, 0.06580185, -0.13533239, 0.25754455, -0.29734856, 0.028218834, -0.39304733, -0.14716247, 0.19408274, -0.18518063, -0.31482637, -0.1508887, -0.3841371, 0.021975968) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.22316615, -0.0923483, 0.16932568, -0.13138154, 0.139829, 0.010975908, -0.0587337, -0.054484393, -0.13758336, -0.030077504, -0.050642505, -0.14933856, -0.040563874, -0.030220931, 0.2867556, 0.17022403) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.12611523, -0.07087836, 0.08281469, 0.024588918, -0.023549056, -0.13102995, 0.17571726, 0.0740372, -0.3167631, 0.17491543, 0.4459055, -0.4687942, -0.19755729, 0.03723031, -0.06757113, 0.03502462) * go_0(0.0, -1.0);
|
||||
result += mat4(0.12098187, 0.12341856, -0.061940372, 0.7251308, 0.055730965, -0.5169302, 0.37959704, -0.08753306, -0.45700142, -0.4960699, 0.1690022, -0.40233734, 0.0262836, -0.13345262, 0.11002605, -0.16773209) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.20428565, 0.117523015, -0.044863444, -0.1770644, 0.22925, 0.029694336, -0.23891294, 0.039587863, -0.11235541, -0.23890465, 0.037618574, -0.039127905, 0.14058869, 0.020599412, -0.074353516, 0.12343045) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.04680316, -0.049870726, 0.06975308, -0.21486782, -0.08177838, 0.09760846, -0.031408366, 0.13881667, -0.14650045, 0.29182404, -0.080848776, -0.25525567, 0.018876432, -0.015662232, -0.016014043, -0.08435915) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.100864016, -0.24647528, -0.007994345, 0.13047779, 0.14746517, 0.25517163, 0.054900885, -0.07251866, -0.29500577, -0.03758923, 0.05514366, -0.058372885, -0.03055354, -0.062586576, 0.017739896, 0.08644674) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.029502464, -0.08905223, 0.0047584837, -0.09646073, 0.044714086, 0.15522493, -0.070930906, -0.026954453, 0.057949875, -0.017211404, -0.00566463, -0.0050975676, 0.0050182147, -0.010722001, 0.011812942, -0.04698445) * go_0(1.0, 1.0);
|
||||
result += mat4(0.18863353, -0.11575336, 0.26541254, -0.15280409, 0.14376, -0.05783716, 0.08554402, 0.27605456, 0.004611954, 0.074173525, -0.07963756, 0.082979314, 0.099553905, -0.06539344, 0.4330784, 0.07996894) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.31001288, 0.035875235, 0.049856357, -0.09614268, 0.23397788, -0.12425775, 0.45108303, 0.27973723, 0.0753222, 0.11388394, -0.043821793, -0.05610102, -0.06536777, 0.009822641, 0.7956708, -0.05798737) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.19827974, 0.010130333, -0.13153136, 0.11593003, -0.15762039, -0.0040722084, 0.20404483, 0.28999883, 0.08152756, 0.07773477, 0.019730574, 0.0123460535, -0.034676805, -0.19133334, 0.01860159, -0.12945038) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.1861255, 0.039945368, 0.28345293, -0.17425321, 0.36748698, 0.03729066, -0.35957313, 0.11234573, -0.07122196, 0.012845119, -0.09049443, 0.10106711, 0.07425845, -0.14626606, 0.46169114, -0.2652126) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.6222811, -0.08538015, 0.023319554, -0.7206892, -0.33495513, 0.2960924, -0.033479776, -0.29255456, 0.29802337, 0.47570458, 0.012769826, 0.19874385, -0.25652033, -0.4018595, 0.3055839, 0.1881051) * go_1(0.0, 0.0);
|
||||
result += mat4(0.32152474, 0.0024920676, -0.113435976, 0.14440896, -0.287736, 0.0251382, 0.28160754, 0.02769615, 0.067614004, 0.0832741, -0.095353454, -0.19792004, -0.40394694, -0.24224225, 0.3224996, 0.030300485) * go_1(0.0, 1.0);
|
||||
result += mat4(0.0045148246, -0.04621849, -0.026470715, 0.0588576, 0.14559188, 0.037437905, -0.13778603, 0.08173416, 0.033548757, -0.015654223, 0.15016593, 0.07761835, -0.016546778, 0.02640291, 0.112717085, 0.020371364) * go_1(1.0, -1.0);
|
||||
result += mat4(0.114227325, -0.0405595, -0.11662477, 0.014747093, 0.11170598, 0.58740836, -0.27560827, -0.1848705, -0.02491223, -0.15605451, 0.0028677192, -0.11290364, -0.12331832, -0.3191161, 0.3505101, 0.15236251) * go_1(1.0, 0.0);
|
||||
result += mat4(0.21131381, 0.13965495, -0.103683874, 0.26049778, -0.010777816, 0.015093082, 0.13207617, 0.14064828, -0.007847294, 0.025702007, -0.082993574, -0.04923462, -0.052900862, -0.006775377, 0.1432969, 0.09598549) * go_1(1.0, 1.0);
|
||||
result += vec4(0.08015534, 0.10264796, -0.031173404, 0.21282151);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!SAVE conv2d_3_tf
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.13262276, 0.18682314, -0.1433667, -0.0061677806, -0.15057871, -0.15389217, 0.40721065, -0.082456455, 0.028175479, -0.06136406, 0.13517159, -0.0066659097, -0.03311807, -0.056219388, 0.066265404, -0.017012158) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.0652481, -0.02717338, -0.17586891, -0.1458622, 0.37166637, -0.13651049, -0.095090784, 0.1450258, -0.08856753, -0.029000161, -0.11024598, 0.14231622, 0.027118085, 0.060637098, -0.028174674, 0.020973917) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.17137158, 0.015818363, -0.1761587, -0.07798954, -0.22039492, -0.08250406, 0.15350278, 0.05466543, 0.07231244, 0.124937475, -0.14530692, -0.036220204, -0.20202135, 0.16154502, -0.1472417, 0.045183204) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.06751513, 0.3630837, -0.23374555, -0.17641832, 0.23866339, -0.12625019, 0.14955078, 0.3757683, 0.25546572, -0.0009440543, -0.029705383, 0.12500505, 0.039303612, 0.02745342, 0.06280759, -0.027673393) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.40253955, 0.5532656, 0.15580782, 0.23305601, 0.04307387, -0.37548792, 0.021682428, -0.14554474, -0.44655007, 0.12335231, 0.22693188, -0.19185324, -0.39905196, -0.36661598, 0.34626722, 0.3220371) * go_0(0.0, 0.0);
|
||||
result += mat4(0.13051705, -0.051269528, 0.027860573, 0.12866034, 0.095374286, 0.0072371624, 0.06641015, -0.040609945, 0.14411138, 0.03813084, 0.024812538, -0.069997884, -0.2398024, 0.16384888, 0.004522481, -0.2734798) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.048976544, 0.36923414, -0.23769425, -0.02964149, 0.13426293, -0.070416726, -0.036279447, 0.21007125, -0.0062456504, 0.12307804, -0.18920022, 0.016429992, 0.091225415, -0.00714184, -0.079064, 0.050525308) * go_0(1.0, -1.0);
|
||||
result += mat4(0.007005748, -0.1929285, -0.27960134, -0.014070343, -0.012031938, -0.21320626, 0.22591045, 0.06750757, 0.038049847, -0.08933499, 0.15640227, 0.36653376, 0.11274315, 0.0015512784, -0.14319079, -0.41117874) * go_0(1.0, 0.0);
|
||||
result += mat4(0.039254356, 0.04123307, -0.14476523, 0.19676228, -0.1746638, 0.068685316, 0.19318552, -0.007086376, -0.08810745, 0.041937724, 0.1393943, 0.27539206, -0.08331265, 0.043064818, -0.02783017, -0.13006629) * go_0(1.0, 1.0);
|
||||
result += mat4(0.18761271, -0.009960496, -0.18572417, 0.010640895, 0.10240658, 0.036137953, -0.109363064, 0.05820501, -0.04092678, 0.11809751, -0.11843415, 0.11893309, -0.06356792, 0.1509876, -0.12252014, -0.0070098704) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.0012312894, 0.038436964, -0.046054237, 0.04859312, -0.4190657, 0.2529927, 0.23133701, -0.00065297337, -0.039581586, 0.00905735, 0.16532114, -0.12568031, 0.17818217, -0.28053075, 0.38509414, -0.03763847) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.0897875, 0.063593514, 0.07660054, 0.12268424, 0.21554653, -0.1025501, 0.2557211, 0.04492533, 0.10992355, -0.035215836, -0.009733763, -0.02165148, 0.08618596, -0.19276536, 0.18174514, -0.18021213) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.002999377, -0.12630916, -0.030010369, -0.2676409, -0.20229307, 0.15253967, -0.12200155, -0.1552754, -0.16193017, 0.10819683, 0.10696224, -0.1920264, -0.29354608, -0.32021165, 0.08644405, -0.16153689) * go_1(0.0, -1.0);
|
||||
result += mat4(0.49931613, -0.3669461, -0.49107462, -0.3654748, 0.32047966, 0.03246311, -0.06424334, 0.009108802, 0.2367612, -0.46587244, 0.16957493, 0.3237888, 0.93676794, 0.01834384, -0.9349752, -0.04654371) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.112562165, 0.006074484, -0.12288025, -0.08560263, 0.25336134, 0.025205871, 0.25063732, 0.12370882, -0.40429187, 0.12992847, -0.2816234, 0.08179623, 0.27197668, 0.066299304, -0.12988937, 0.16257611) * go_1(0.0, 1.0);
|
||||
result += mat4(0.047864527, -0.05821779, -0.06311128, -0.0065775234, -0.065763995, 0.014864688, 0.09148591, -0.25059348, 0.008846306, -0.22123712, 0.4062609, -0.100248575, -0.50293785, -0.13373566, 0.21480446, -0.0841981) * go_1(1.0, -1.0);
|
||||
result += mat4(0.19313097, -0.061253734, -0.1801314, -0.20178059, -0.039574936, 0.08167749, 0.010974997, 0.069656976, -0.13193963, 0.35555324, 0.62686867, -0.28656846, -0.27831817, -0.0040086447, 0.4031064, 0.47767937) * go_1(1.0, 0.0);
|
||||
result += mat4(0.15396428, 0.069321476, -0.15190981, -0.24133344, 0.106151104, -0.11271092, 0.06878746, 0.14279713, -0.02006402, -0.36284852, -0.00926688, -0.39887694, -0.20926239, -0.021860912, 0.07588468, 0.2620174) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.0073282495, -0.040352557, -0.063710704, 0.07255652);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!SAVE conv2d_4_tf
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.17903937, -0.0014294779, 0.1824805, -0.19555633, -0.0052551827, -0.013796094, 0.06358042, 0.13301018, 0.008874768, 0.06605332, 0.06117636, 0.012946474, 0.048656575, 0.0060409275, -0.0671362, -0.06897735) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.16098012, 0.10772552, -0.13175552, -0.5299018, 0.068713695, -0.048258893, -0.49698257, 0.36581638, 0.21755004, -0.12125899, -0.27382872, -0.12268086, 0.014334542, 0.20573758, 0.45879167, -0.29648975) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.06860283, -0.18047708, 0.024707617, 0.11900479, 0.09474589, -0.16559775, -0.054095846, -0.011377782, -0.008733984, 0.105020404, -0.040116277, -0.0022003972, 0.1453799, -0.032110006, -0.018741792, -0.12511599) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.20024729, -0.01969923, -0.026999667, -0.39064395, -0.14559332, -0.11634086, -0.13226044, 0.11779975, -0.08838282, -0.0882447, -0.23166943, -0.15760234, 0.030928904, -0.032423917, 0.20324136, -0.19692755) * go_0(0.0, -1.0);
|
||||
result += mat4(0.49499384, 0.7327846, -0.6173799, -0.53821295, -0.15000962, 0.11169762, 0.6942423, 0.07956513, 0.06913002, -0.19037646, -0.19826908, 0.68080276, -0.2747096, -0.15832238, 0.47366706, 0.090432756) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.18274948, 0.09204629, 0.16644076, 0.05641037, 0.03328184, -0.6218293, 0.26432592, -0.093742386, 0.33038342, -0.24853565, -0.23683667, -0.37430722, -0.20684583, -0.32283148, -0.07633969, -0.08765815) * go_0(0.0, 1.0);
|
||||
result += mat4(0.06821987, 0.06395764, -0.14685121, -0.15894371, -0.093540885, 0.057568345, -0.048376244, -0.009256543, -0.26325077, -0.03193119, -0.16857445, -0.02404981, 0.110593356, 0.042911418, 0.06626762, -0.0312436) * go_0(1.0, -1.0);
|
||||
result += mat4(0.3108626, 0.37123847, -0.082249805, -0.21339422, -0.3756041, -0.08518717, -0.16853802, 0.011641729, -0.30096757, 0.26942274, -0.08990497, -0.19451031, 0.21974437, -0.04231723, 0.26160353, -0.040834647) * go_0(1.0, 0.0);
|
||||
result += mat4(0.11795158, 0.24436565, 0.043223023, -0.0159957, -0.19689156, 0.13223267, -0.013983249, 0.09437164, -0.47648698, -0.00082660443, -0.085406005, 0.10885898, 0.104696035, -0.053257108, 0.024389362, 0.0282572) * go_0(1.0, 1.0);
|
||||
result += mat4(0.032890156, 0.0115719065, -0.01898909, -0.03034875, -0.041037276, -0.1026382, 0.03337663, 0.20108728, -0.00023235095, -0.018033072, -0.028535927, 0.07359915, 0.075182244, 0.02959868, 0.15107772, -0.09815672) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.004040557, 0.06707476, 0.039022792, 0.52437925, -0.08027356, 0.040488366, 0.035332825, 0.07683081, -0.03521227, -0.081861034, 0.090804815, 0.10580108, 0.20452882, -0.58755285, 0.04303056, 0.41562977) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.09290062, 0.03495193, 0.02347216, -0.012873525, -0.076936446, 0.1453216, -0.03742271, -0.14174925, -0.058219753, 0.19095406, 0.055627216, 0.09437343, -0.010424211, -0.314692, 0.3314579, -0.053285643) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.053961687, 0.1483992, 0.042458896, -0.1966439, 0.13864957, 0.07587672, -0.06519269, 0.09530391, 0.04215073, 0.039545458, 0.21056756, 0.09972659, 0.02987125, -0.08102741, 0.07075036, 0.21867757) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.5512795, 0.03104814, 0.27901977, 0.122875504, -0.2656715, 0.007895486, -0.6735937, 0.20810314, -0.31432617, 0.07420857, 0.2573659, -0.35361463, 0.19826569, -0.47774056, 0.15816487, -0.29203883) * go_1(0.0, 0.0);
|
||||
result += mat4(0.35078493, -0.07371588, -0.026663188, -0.20976657, -0.009644347, 0.037428845, -0.33933878, -0.010807704, 0.088060796, 0.16753472, -0.12296045, 0.17563403, 0.1501952, 0.07353703, 0.32531765, 0.11667607) * go_1(0.0, 1.0);
|
||||
result += mat4(0.096126616, -0.058021486, -0.03439203, 0.06868024, 0.047914367, 0.026945053, 0.04207778, 0.046023168, 0.16024022, 0.07846185, 0.004195093, 0.07272046, -0.10458233, -0.0904536, 0.16049337, 0.015941419) * go_1(1.0, -1.0);
|
||||
result += mat4(0.032256138, -0.055398785, 0.079738356, 0.113359064, 0.11975066, -0.074372105, 0.102006756, -0.011490042, 0.15155345, 0.0025528704, 0.23328577, -0.059241068, -0.067783386, -0.18220833, 0.0057692174, 0.039900843) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.06173998, -0.07121991, -0.01118306, -0.063749574, -0.032665797, 0.0014987896, 0.03113169, 0.06916617, 0.0066490914, -0.052818965, -0.050131317, 0.10337558, -0.030870482, -0.14671221, 0.12152145, -0.05003445) * go_1(1.0, 1.0);
|
||||
result += vec4(-0.010524109, -0.008519857, -0.08958723, -0.07917139);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!SAVE conv2d_5_tf
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.11029161, 0.027180295, -0.115622066, 0.16493714, 0.29633296, -0.11739625, -0.36390316, 0.15221693, -0.009233659, -0.062213745, -0.07184558, 0.07418268, -0.05182182, 0.0066014086, -0.006811494, -0.010030367) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.18361749, 0.08565693, 0.24127418, -0.20478591, 0.6198113, -0.17994536, -0.011840256, 0.120292775, 0.2873902, -0.019704796, -0.062267166, 0.0104749305, -0.048370067, -0.028105626, 0.11494511, -0.15941763) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.08084502, 0.10195475, -0.03200553, 0.032734055, 0.030348243, -0.028927604, 0.045914374, 0.029237835, 0.07756032, -0.06346545, -0.290196, 0.057043966, 0.13982558, -0.12195619, -0.15895663, -0.10097537) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.12018707, -0.320156, -0.4089669, 0.26015735, 0.59622765, -0.05654362, 0.28581724, 0.32069868, -0.0013007161, -0.060870633, -0.2732852, 0.2357145, 0.2137239, 0.0110256495, -0.069258444, 0.113870576) * go_0(0.0, -1.0);
|
||||
result += mat4(0.54700065, -0.072552234, 0.27267826, -0.26660076, 0.7043544, 0.18192886, 0.80024594, 0.2447395, -0.3289639, -0.2681839, 0.063631415, -1.0118654, 0.45691678, 0.42904988, -0.2301862, -0.6652257) * go_0(0.0, 0.0);
|
||||
result += mat4(0.19215634, 0.030154131, 0.07679603, 0.50318545, 0.056434657, 0.028623195, -0.14471184, -0.13905096, -0.03254216, -0.1191584, -0.18907212, 0.49208716, 0.5069476, -0.1490824, -0.104480386, -0.06595394) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.08893682, 0.13113782, 0.023672188, 0.013086517, -0.25986442, 0.038162243, -0.10951209, -0.2027832, -0.013547809, -0.029482972, -0.17670235, 0.13529542, -0.0621569, -0.0979757, -0.10714689, -0.08474307) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.032828752, 0.00037559783, 0.023968933, -0.047482926, -0.20302027, 0.08830911, -0.20885307, -0.11137413, 0.16585048, -0.076796696, -0.030462325, -0.2020944, 0.048723634, -0.45607433, -0.29950324, -0.5867916) * go_0(1.0, 0.0);
|
||||
result += mat4(0.008863689, 0.061761267, -0.039097138, 0.24465923, -0.05917457, -0.21383028, -0.085846715, -0.14150433, 0.0988731, -0.0160538, -0.045119412, 0.095252946, -0.057551738, 0.21348421, -0.03480491, -0.26071647) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.21351442, 0.10038809, 0.34001955, -0.100911774, 0.0208522, -0.028755441, 0.025793588, 0.013080005, 0.03849989, 0.13662058, 0.04311886, 0.17398632, -0.01397261, -0.016415505, -0.0070752064, 0.007656161) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.280189, 0.09252764, -0.077729605, 0.12662902, -0.10433321, 0.03644144, -0.06625324, 0.05696802, 0.15468478, 0.08328583, 0.069849946, 0.061947342, -0.05560477, -0.0074776993, -0.15365681, -0.03526299) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.05886785, 0.15303846, 0.0066637015, -0.19983207, -0.07803175, -0.10772685, -0.12690999, -0.08275092, 0.033436153, 0.08424011, 0.17092863, 0.0043526487, 0.014620474, 0.044702258, 0.1686881, -0.016890949) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.1833738, 0.14381635, -0.025888365, -0.14182197, -0.25804865, 0.07216123, 0.025790794, 0.14096753, 0.023591481, 0.15610993, 0.026975863, 0.008755717, -0.13039349, -0.063048325, -0.121329494, -0.12331732) * go_1(0.0, -1.0);
|
||||
result += mat4(0.0005065098, 0.44017914, 0.18493074, 0.13099027, -0.36087477, -0.37567857, -0.48981526, 0.5590752, -0.23918836, 0.19170256, 0.16816153, -0.29986876, -0.44738817, 0.018545123, 0.66217834, 0.31810755) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.16725904, 0.05753713, 0.058880586, -0.336765, 0.013667228, 0.056172702, 0.13465533, -0.07573556, -0.06313958, 0.06746643, 0.18878669, 0.09404202, -0.21780397, 0.12862128, -0.09476746, -0.34096682) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.07169524, 0.072302215, 0.052789338, -0.14035568, 0.078670934, -0.22246763, -0.0098074945, 0.024950746, 0.10949147, 0.06182366, 0.021721192, 0.12129548, 0.094007075, 0.06076156, 0.016474832, 0.08092115) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.10960447, 0.1878152, -0.029822018, 0.10598909, 0.1582181, 0.086522795, 0.093725055, 0.12908185, 0.23202112, -0.28859115, 0.26614165, 0.124523655, 0.19427507, 0.059677128, 0.003624697, 0.44220912) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.03620583, -0.102766834, 0.025527107, -0.11316131, -0.1507822, 0.0543862, -0.08225627, -0.06438472, 0.04580623, 0.6329729, 0.23854075, 0.35752076, 0.04363613, -0.12580468, -0.0006126687, -0.04995386) * go_1(1.0, 1.0);
|
||||
result += vec4(0.060475674, -0.042036578, 0.06406282, 0.05569301);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(M)-Conv-4x3x3x8
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!SAVE conv2d_6_tf
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.008187961, -0.08433309, -0.17281345, 0.1306418, -0.2925821, 0.20668334, 0.14854355, -0.15960559, 0.08599311, -0.096088655, -0.10121403, 0.067429096, 0.049158614, 0.036637552, 0.22137405, -0.17016457) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.024813082, 0.028489944, 0.06814137, -0.1245949, 0.54239255, 0.08648708, 0.28979865, 0.110916786, -0.1927179, -0.17756873, -0.1878214, 0.05795718, -0.080397904, 0.22125137, 0.1907366, -0.016493658) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.027259264, 0.01494357, 0.04852894, 0.037580628, 0.031005561, 0.003570554, -0.072993, -0.053475574, 0.031119492, -0.14140029, -0.10386501, -0.015266508, 0.01153506, 0.16006693, 0.088294305, 0.04201491) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.13026185, 0.097255, 0.49145448, -0.33619553, -0.21144676, 0.019042643, -0.27274492, 0.3033865, 0.14040698, -0.13656893, 0.28211337, -0.26930946, -0.1626638, 0.105105706, -0.50837296, 0.39536825) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.42495522, 0.14972518, 0.0007564128, 0.37367433, 0.44553527, 0.3338494, -0.26058698, 0.087256804, -0.4324135, 0.20706014, 0.33552194, -0.13375738, -0.13469471, 0.22374928, -0.36969653, -0.34171587) * go_0(0.0, 0.0);
|
||||
result += mat4(0.26543954, -0.004381978, 0.10609993, -0.09718426, -0.15620759, -0.03287476, 0.093032375, 0.00028344034, -0.11699793, -0.016492033, 0.023340177, 0.0062737763, -0.14305823, -0.2721832, -0.160177, -0.06915171) * go_0(0.0, 1.0);
|
||||
result += mat4(0.03334679, 0.12436332, -0.13226178, 0.13868971, 0.017779246, -0.012697869, -0.11553709, 0.08638636, 0.0955215, -0.0309646, 0.040856246, -0.03978358, 0.023490254, -0.07178907, 0.23794931, -0.1714287) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.11820261, 0.116130814, 0.58924234, -0.37785482, 0.016644944, -0.071019046, 0.0076222476, -0.024118654, -0.076183304, -0.14971451, 0.06356606, -0.07225465, -0.17400762, 0.030856986, 0.03957665, -0.0070553776) * go_0(1.0, 0.0);
|
||||
result += mat4(0.10954708, 0.063694, -0.058218896, 0.0010372304, 0.032423936, 0.006164447, -0.031383317, 0.012955956, -0.17115591, 0.16328962, 0.07279567, 0.06571465, 0.005532307, 0.13575353, 0.04082173, 0.041579492) * go_0(1.0, 1.0);
|
||||
result += mat4(0.03146011, -0.08227295, -0.03498218, 0.04772092, 0.12055223, -0.12383867, 0.05448358, -0.07948453, -0.019064998, -0.0964146, -0.024651276, 0.041473705, -0.06493721, -0.054806646, -0.21607941, 0.20078054) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.25740683, -0.33160943, -0.37422308, 0.12679969, -0.032204475, 0.41485202, 0.4538808, -0.082535125, 0.11784846, 0.10195789, 0.064491615, -0.10170162, -0.09500746, -0.15640756, -0.079364255, -0.12576963) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.02532797, -0.014487023, -0.09441118, -0.060885422, -0.41196415, -0.1359501, 0.07101173, -0.053279232, 0.010979353, 0.1914526, 0.054606825, 0.015926225, 0.10410896, 0.010272597, -0.048138764, -0.02698072) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.35856235, 0.099759184, -0.11972965, -0.03850837, -0.5143867, 0.3721666, -0.100802526, 0.21814734, -0.11864143, 0.15086797, 0.047075786, -0.14188164, 0.48882273, -0.12767795, 0.4937544, -0.41288656) * go_1(0.0, -1.0);
|
||||
result += mat4(0.21679138, 0.023770422, -0.5454043, 0.18567741, 0.15965948, -0.84900963, -0.4684333, -0.21884751, 0.5876668, -0.9346244, -0.30144307, 0.97177315, 0.24103107, 0.35953388, 0.2032729, 1.2934744) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.5121466, -0.123357795, 0.1833694, 0.048652876, -0.20895603, 0.0619325, 0.064119816, 0.072841786, -0.21813762, -0.126957, -0.23441431, -0.009071302, -0.09766064, -0.12546945, 0.086008705, -0.0072638122) * go_1(0.0, 1.0);
|
||||
result += mat4(0.15312338, -0.051029235, 0.07638347, -0.14028431, 0.10694411, -0.14639509, 0.3193828, -0.22767228, -0.19987194, 0.18207504, -0.19648756, 0.24752761, -0.03402804, -0.04186147, -0.20177092, 0.09467012) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.3587345, -0.20358992, -0.11016057, 0.21079709, -0.26201126, 0.040362626, 0.3186598, -0.059521858, 0.27564716, -0.041431133, 0.19315968, -0.30228892, 0.01191173, -0.10380854, 0.03030344, 0.026699625) * go_1(1.0, 0.0);
|
||||
result += mat4(0.13373446, -0.011457521, -0.24851708, 0.06563771, -0.051668253, 0.09096929, -0.013976447, 0.041433394, -0.046981215, -0.00015144625, 0.05696515, 0.024501698, 0.2714476, -0.017434085, 0.025333954, -0.054034695) * go_1(1.0, 1.0);
|
||||
result += vec4(0.06757453, -0.021112159, -0.015639946, 0.05520713);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(M)-Conv-4x1x1x56
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_6_tf
|
||||
//!SAVE conv2d_last_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define g_0 (max((conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_1 (max(-(conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_2 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_5 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_6 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_9 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_10 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_13 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.03795613, 0.09572901, 0.019826923, 0.10568741, -0.0030050736, -0.018890928, 0.0095737, 0.00807826, -0.022741016, 0.0046556294, -0.017018225, -0.010523109, -0.017621946, -0.0006488902, -0.009405731, -0.0027796263) * g_0;
|
||||
result += mat4(-0.046617493, -0.018167915, -0.039274286, -0.027566826, -0.015821747, 0.003789104, -0.0020801623, 0.004032968, -0.05708595, -0.018440764, -0.032891296, 0.004184342, 0.047413353, 0.0034510887, 0.019148773, -0.0035636695) * g_1;
|
||||
result += mat4(-0.046619494, -0.017274255, -0.03372405, -0.011152855, 0.10981248, 0.036214054, 0.07969624, 0.05590572, -0.031791378, -0.00307391, -0.0032425344, 0.0025762853, 0.0053703627, -0.02076939, -0.00058634114, -0.012593452) * g_2;
|
||||
result += mat4(0.110471316, 0.031102506, 0.07860556, -0.018570926, -0.05038586, -0.07667239, -0.0819002, -0.08958284, 0.03846167, -0.007570915, 0.008598097, -0.0082979705, -0.03610172, -0.022735123, 0.02343143, 0.030037913) * g_3;
|
||||
result += mat4(-0.075562544, -0.020187575, -0.020969959, 0.0062222136, 0.019780673, 0.059694994, 0.019240001, 0.05951303, 0.004168261, 0.00041100322, -0.0013793377, 0.002048099, -0.040564027, -0.031818517, -0.015498987, -0.02695407) * g_4;
|
||||
result += mat4(-0.0016428401, 0.018965026, -0.013192817, -0.008289604, -0.044686675, -0.009061507, -0.049217258, -0.043777503, -0.07308355, -0.063734084, 0.019393511, -0.028853234, 0.057311818, 0.04126226, 0.086301416, 0.11784249) * g_5;
|
||||
result += mat4(-0.06087458, 0.046508487, -0.10723279, 0.017619802, 0.13637137, 0.2054238, 0.013641375, 0.091581754, 0.03556439, 0.0500333, 0.0696777, 0.0922045, -0.020914901, -0.025425691, -0.050319638, -0.049094327) * g_6;
|
||||
result += mat4(0.0030941095, -0.008679898, -0.05815756, -0.038728733, -0.062450465, -0.073838525, -0.030359933, -0.08355475, -0.039032117, -0.0689333, -0.04834296, -0.079471886, 0.09694701, 0.17491414, 0.093450785, 0.16742545) * g_7;
|
||||
result += mat4(0.035618782, -0.027659958, 0.055540156, 0.013073733, 0.12144545, 0.05981087, -0.015131131, -0.0476281, -0.090847984, 0.005347584, 0.015588529, 0.024184622, -0.10743599, -0.01785147, -0.08566232, -0.14611128) * g_8;
|
||||
result += mat4(-0.03812077, 0.018126076, -0.016625525, -0.06906415, -0.06267368, -0.058914356, 0.0009385371, -0.026746314, 0.048242237, 0.028906677, -0.028120263, -0.004209134, 0.009636235, 0.013206963, 0.07449269, 0.038961377) * g_9;
|
||||
result += mat4(-0.014510558, -0.021065345, 0.09356215, -0.005815953, 0.08807958, 0.067895725, 0.08723713, 0.057831496, -0.10227873, -0.07699344, -0.06321843, -0.07448854, 0.09820774, 0.007563063, -0.14045772, -0.014161681) * g_10;
|
||||
result += mat4(-0.18385889, 0.2255883, -0.29741547, 0.14618248, -0.08100661, -0.06860545, -0.112705804, -0.122642964, -0.06736901, 0.06971933, 0.12909706, -0.0418256, -0.32786265, 0.032497127, 0.4390302, 0.032726523) * g_11;
|
||||
result += mat4(0.10560793, 0.083280005, -0.20369564, -0.14290833, -0.119196005, -0.028741803, 0.020456403, -0.06509816, 0.073811695, 0.02724128, -0.08691891, 0.10240907, 0.16827166, -0.17502932, -0.18295282, 0.15154512) * g_12;
|
||||
result += mat4(0.0036247042, -0.002368346, 0.049646147, 0.058079436, 0.14403848, 0.07125248, 0.040327612, -0.013934329, 0.03871744, -0.1717596, 0.20666012, -0.24093682, -0.09846371, 0.011563227, 0.11973811, -0.0574434) * g_13;
|
||||
result += vec4(0.022095086, 0.021079032, 0.030224537, 0.02154015);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(M)-Depth-to-Space
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_last_tf
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_last_tf.w 2 *
|
||||
//!HEIGHT conv2d_last_tf.h 2 *
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
vec4 hook() {
|
||||
vec2 f0 = fract(conv2d_last_tf_pos * conv2d_last_tf_size);
|
||||
ivec2 i0 = ivec2(f0 * vec2(2.0));
|
||||
float c0 = conv2d_last_tf_tex((vec2(0.5) - f0) * conv2d_last_tf_pt + conv2d_last_tf_pos)[i0.y * 2 + i0.x];
|
||||
float c1 = c0;
|
||||
float c2 = c1;
|
||||
float c3 = c2;
|
||||
return vec4(c0, c1, c2, c3) + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,969 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2021 bloc97
|
||||
// All rights reserved.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.28296316, -0.020139743, 0.1038232, 0.09352482, -0.16964972, 0.07910997, -0.049914766, -0.10661066, -0.121037185, -0.029087039, -0.02511847, -0.078911744, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.3927183, 0.01805193, -0.031168332, -0.13300525, 0.20814548, 0.118818566, 0.1655351, 0.095023684, 0.17600809, -0.03928444, -0.014350658, 0.08458312, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.079089314, -0.0421829, 0.05452305, -0.22055493, 0.013279097, -0.12875281, 0.02452735, -0.101503745, -0.085946664, 0.05539176, 0.022408713, 0.14837204, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.102643915, -0.011254746, 0.1478563, 0.1030208, 0.12396588, 0.0016621432, 0.2551224, -0.10399001, -0.01068436, 0.07155532, -0.104522154, 0.026937222, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.8789423, 0.35707328, -0.29964274, -0.064913996, 0.4962815, 0.26001287, -0.9511284, 0.49574667, 0.39539725, 0.16308042, 0.119878456, -0.30259115, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.08852938, -0.32612664, -0.006712046, 0.28693515, 0.06320871, -0.3322611, 0.04651086, -0.11020996, 0.01821082, -0.22851005, -0.07803438, 0.021527015, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(0.12295851, -0.011285535, 0.015859747, 0.04005441, -0.018136669, 0.03171969, -0.0406123, -0.10731229, -0.12117574, 0.005033036, 0.047838476, 0.026843475, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(0.4655988, 0.05519082, 0.039515793, 0.28410903, -0.36144528, 0.13039446, 0.11338478, -0.2141387, -0.10026682, -0.07903024, -0.09410254, 0.043833878, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(0.110124744, -0.024725702, 0.028102143, -0.09493807, -0.06455328, -0.15164614, 0.04425987, 0.15483347, -0.045039337, 0.07210396, -0.005390788, -0.03832707, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(0.007907974, -0.035503313, 0.057224784, -0.19763541);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x3
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!SAVE conv2d_tf1
|
||||
//!WIDTH MAIN.w
|
||||
//!HEIGHT MAIN.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (MAIN_texOff(vec2(x_off, y_off)))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.012326053, 0.050769784, 0.1278702, -0.100782245, 0.14329414, -0.054558773, 0.023473471, 0.056829426, 0.048292916, 0.0046510273, -0.11478287, 0.0011030561, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.29542983, -0.55061895, -0.068554066, 0.1433222, -0.072878316, 0.30201668, -0.2223378, -0.06704077, 0.16955832, 0.3279914, 0.17619601, -0.1276919, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.09623417, 0.30559412, 0.094622105, -0.076706685, 0.07943858, -0.084815115, 0.12472551, 0.079850115, -0.13044213, -0.21300878, -0.095747225, 0.13412355, 0.0, 0.0, 0.0, 0.0) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.21291664, 0.17195296, -0.20080926, 0.1064855, 0.10228669, -0.09580175, -0.11217631, -0.09740562, -0.0033135475, -0.053094357, 0.2983595, 0.035281878, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.08955812, -0.45707774, -0.4606922, -0.5754473, -0.11395895, 0.33530128, 0.29705846, -0.18877256, -0.43502945, 0.114171304, -0.3750776, -0.081597246, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.26109028, 0.02662961, -0.10441071, 0.11199392, -0.12038989, -0.09642296, -0.061320662, -0.33058178, 0.20212512, 0.00840794, 0.14357455, -0.038080238, 0.0, 0.0, 0.0, 0.0) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.09533881, -0.13644339, 0.068756215, 0.079305276, -0.053370547, 0.19572955, 0.0682981, 0.14469264, 0.15582883, -0.057183057, -0.13919263, -0.016394936, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.041189935, 0.39878023, 0.028704925, 0.30194348, -0.04486593, -0.33899093, -0.103968106, 0.21802065, -0.077099144, -0.07389541, 0.18069103, 0.18894517, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.12399862, 0.19246885, 0.034825478, -0.0044787163, 0.13121822, -0.13573012, -0.030162754, 0.1899518, 0.102326415, -0.061512686, -0.005647928, -0.0937634, 0.0, 0.0, 0.0, 0.0) * go_0(1.0, 1.0);
|
||||
result += vec4(0.019286277, -0.033644073, 0.08196311, 0.0054393094);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!SAVE conv2d_1_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.04088509, -0.06585775, -0.3094732, 0.12059048, 0.041417453, -0.06144871, -0.06655134, 0.03308842, 0.09287731, 0.010969216, 0.10343026, -0.11185897, 0.05685865, -0.09490512, 0.040908635, 0.03501189) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.04854754, -0.098667145, 0.67147833, -0.11299351, -0.022114437, -0.029202767, 0.014179382, 0.26027945, 0.22076549, -0.16490546, -0.0010764733, 0.08405975, 0.11849154, -0.19072372, -0.35719597, -0.059621073) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.079224996, 0.0669873, -0.1718969, -0.05002573, 0.044926763, -0.02904369, 0.017489236, 0.01144465, 0.059109706, 0.064998455, 0.14725484, -0.23879208, 0.039234288, -0.027365638, 0.26172164, -0.094598554) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.07159218, -0.03181544, 0.113837324, -0.053089984, -0.098298974, -0.29500297, 0.1608509, -0.044355504, 0.050882854, -0.19417204, -0.080487266, -0.00879743, 0.0007914453, 0.16640955, 0.21786706, 0.16398212) * go_0(0.0, -1.0);
|
||||
result += mat4(0.16324541, 0.19753313, -0.46597233, -0.2593132, -0.2781038, -0.21973547, -0.024623038, -0.16348499, 0.3628299, 0.044888914, 0.04054647, -0.63605887, 0.02099492, 0.060544077, -0.49359834, 0.36336297) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.16885692, 0.31907207, 0.020906802, 0.13290039, -0.037330728, -0.022859452, -0.020451576, -0.113437995, -0.085683934, 0.054102756, -0.044824492, 0.061346747, -0.038684413, 0.098444365, -0.06734984, -0.17084897) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.015821548, -0.119599186, 0.1614827, 0.08383641, -0.07933593, 0.12528986, -0.06300182, 0.09286327, -0.10199266, 0.02419403, 0.0028411683, -0.09028338, 0.07962534, -0.08676035, -0.19237737, -0.115502626) * go_0(1.0, -1.0);
|
||||
result += mat4(0.09471972, 0.21153462, -0.14393018, 0.055180002, 0.1817461, 0.016607309, -0.0771979, 0.11181317, -0.5491086, -0.102757886, -0.20952754, 0.022466583, -0.075119644, -0.14725658, 0.38451517, 0.12920731) * go_0(1.0, 0.0);
|
||||
result += mat4(0.0867803, 0.114654355, 0.21199988, -0.15367955, -0.01803536, 0.056378633, 0.0018388306, 0.024613786, -0.13306658, 0.017211098, 0.073351346, -0.12064064, -0.10484361, -0.067748636, 0.033206712, -0.13061953) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.002236411, -0.022144757, -0.04586377, 0.101181075, -0.03511624, 0.08440529, 0.18544284, -0.22786349, -0.042184375, 0.015734851, -0.038622506, 0.038529944, -0.09170703, 0.034527462, -0.07817406, 0.10547265) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.12135524, -0.07412039, -0.04979351, -0.082267545, 0.13343571, 0.29196215, -0.4364121, -0.10226428, 0.060835477, -0.23307934, -0.018231759, 0.15550235, 0.09095689, 0.18164484, 0.1322021, -0.022567045) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.0054531163, -0.039762255, -0.030490747, 0.04779882, -0.15290286, 0.056712102, -0.0776974, 0.04114215, 0.15946816, -0.03882117, 0.16770308, -0.026126247, -0.027203865, -0.064107865, -0.13670811, 0.1556276) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.092548385, -0.027285473, 0.084179096, 0.014961629, 0.2564254, 0.07626849, 0.28534448, 0.2588713, -0.018600503, -0.2433456, 0.041392803, -0.045712482, 0.26388907, -0.053502295, 0.14522223, 0.032808404) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.0013780193, 0.3482449, 0.071003586, -0.30707207, -0.05122194, -0.2833618, 0.07910779, 0.051078696, 0.021535402, 0.13021478, 0.022049015, -0.533547, 0.57265025, -0.12843914, -0.14913581, -0.1433724) * go_1(0.0, 0.0);
|
||||
result += mat4(0.07382619, -0.12152924, 0.13364957, 0.181974, 0.15804219, -0.10126773, 0.3029618, -0.12874149, 0.13743348, -0.23245592, -0.20119278, 0.029547188, 0.042436857, 0.04213892, -0.07975374, 0.023821082) * go_1(0.0, 1.0);
|
||||
result += mat4(0.022782229, -0.08359311, -0.060623147, 0.06565042, 0.09828792, 0.044808697, -0.28872305, -0.00092168007, 0.021737702, -0.08698349, 0.1950025, 0.07931995, 0.040952396, -0.07443172, -0.021157127, 0.0056698937) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.09995892, -0.2047294, 0.1414849, 0.062335726, -0.22492298, 0.05269799, -0.029233055, -0.050517935, -0.12534393, -0.12194023, -0.07035469, -0.070764475, 0.18903446, 0.07691209, 0.06153371, 0.011280912) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.036189888, -0.07586571, -0.05888163, 0.010425367, -0.028375402, -0.18870986, -0.19146784, 0.19274063, -0.18856238, 0.0064240266, -0.14537223, -0.06971656, 0.0852742, -0.04866623, -0.031686075, 0.031702038) * go_1(1.0, 1.0);
|
||||
result += mat4(0.0618941, 0.100858234, 0.2628019, -0.048507668, -0.051001363, -0.03195978, 0.035452217, -0.001991919, -0.09649028, -0.047445696, -0.09221298, 0.07602656, -0.02382384, -0.119645916, 0.085616075, -0.07076033) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.019222878, -0.0491929, -0.4902266, 0.18501294, 0.014529614, -0.077125326, 0.011563931, -0.20236616, -0.101982154, -0.021150962, -0.07537948, -0.1540349, 0.028949164, -0.06827332, 0.0067634755, 0.09582376) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.05995539, -0.031138182, 0.01334257, 0.06827176, -0.030762246, 0.006615233, -0.03562788, 0.016249394, -0.14797118, 0.014671043, -0.09325859, 0.25653747, -0.11474991, 0.05436232, 0.031051394, 0.04179694) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.032279838, -0.030521005, 0.0029688699, 0.005165139, 0.15907808, -0.20421815, -0.07713175, 0.067530625, -0.08619395, 0.026114263, 0.08821273, 0.011591694, 0.018677557, 0.057708874, -0.25859246, -0.18693781) * go_2(0.0, -1.0);
|
||||
result += mat4(0.10823143, -0.31875235, -0.24394153, -0.0025489891, 0.016761065, -0.19857498, -0.07858479, -0.07811158, -0.38551694, -0.049090322, -0.050053325, 0.23398961, 0.014974165, 0.17498055, 0.29105362, -0.353647) * go_2(0.0, 0.0);
|
||||
result += mat4(0.05621677, -0.19492444, 0.460332, 0.055917628, -0.06404381, -0.06684098, 0.053624872, 0.057300456, -0.019248677, -0.15110065, 0.032379635, -0.12673225, 0.0068658157, -0.13001235, -0.017716292, 0.064182095) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.06764552, 0.004707433, -0.13827331, -0.21957871, -0.03789028, -0.04962028, 0.022955444, -0.058468018, 0.13735814, -0.031270552, -0.018490225, 0.0063876202, -0.052979283, -0.030049473, -0.004811771, -0.0044099926) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.028652798, -0.027029367, 0.62600744, 0.0900562, 0.03869923, -0.20111556, 0.095930666, -0.13164565, 0.5562579, 0.011937122, 0.22882107, 0.030288015, 0.09856272, 0.04736032, -0.077492185, -0.10207275) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.10581002, -0.16504957, -0.5688921, 0.0414545, 0.04749444, -0.052849945, -0.011017121, -0.025284614, 0.14316759, -0.08547362, -0.09654446, 0.08682504, 0.050776027, 0.0678741, -0.04913651, 0.07527552) * go_2(1.0, 1.0);
|
||||
result += mat4(0.04126091, 0.0048704315, 0.041699376, -0.05820725, -0.09664279, 0.07648305, -0.17979898, 0.11698985, -0.025436765, 0.023232851, 0.010656572, 0.08157569, 0.19584864, -0.022928072, 0.053339157, 0.0039929505) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.040733483, 0.12260473, 0.08071146, 0.07257762, -0.016945919, -0.31637576, -0.24281953, -0.0038469466, -0.10203634, 0.13631973, 0.06505259, -0.13119389, -0.09723076, -0.139551, -0.07504509, 0.08645985) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.017005404, 0.049066268, -0.007544932, -0.04884536, 0.09984347, -0.04447364, 0.4902235, -0.062780835, -0.18389583, 0.07305648, -0.22014385, 0.08004685, 0.0992568, -0.08569604, 0.093966395, -0.07047139) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.0017705248, 0.020553982, -0.09167042, 0.0036356782, -0.11867446, -0.07055574, 0.40252638, 0.09657129, 0.0888632, 0.1031708, -0.022127641, -0.023769693, -0.0861388, 0.13420185, -0.11774454, 0.038774434) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.15173717, -0.13590458, -0.0891863, 0.12289548, 0.13942605, 0.22152588, -0.19292432, 0.14169839, 0.010543665, 0.07648361, -0.057333756, 0.09535759, -0.053601623, -0.026824495, 0.09365424, 0.17476946) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.070416056, -0.061970036, -0.039723337, -0.18874651, -0.07098426, -0.019835865, -0.5612458, 0.060437083, -0.03774378, 0.18536821, 0.28587544, 0.035555754, 0.15771326, -0.13527197, 0.13342534, -0.06564073) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.10967661, 0.025388904, 0.09003177, -0.04087592, 0.09531671, -0.11809294, -0.41613623, 0.038198076, 0.01019813, -0.018864965, -0.18400626, -0.038704176, 0.0105671035, 0.024449013, -0.008989595, -0.027171193) * go_3(1.0, -1.0);
|
||||
result += mat4(0.16193569, -0.21445285, -0.20130903, -0.13498883, -0.008031679, 0.050757203, 0.78938776, -0.03749514, 0.11998137, 0.19368882, 0.12328945, 0.0058578993, -0.13852382, -0.033867255, -0.018267661, 0.036348555) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.06254118, 0.087295115, 0.031116437, 0.0416281, 0.061828617, 0.34479564, -0.15537797, -0.17144552, 0.13989387, -0.13792284, 0.056215156, 0.12714528, -0.0198865, 0.04927947, 0.013614583, -0.041810013) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.044073943, 0.12072677, -0.0022342638, -0.24414532);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!SAVE conv2d_1_tf1
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.07115729, 0.01065505, 0.19167988, -0.02504489, -0.15064801, 0.079008736, 0.05437936, 0.027479589, -0.021383656, 0.032731537, -0.06657876, 0.022649521, -0.06501893, -0.02335689, 0.010445489, -0.05430297) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.1178601, 0.07425715, 0.063272275, -0.18308601, -0.13955134, 0.005166404, -0.022591779, -0.016827974, -0.024990188, -0.13372071, -0.056342285, 0.12489847, 0.081861794, -0.07083351, 0.021897513, 0.0629395) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.051357627, -0.13874975, -0.09887168, -0.011908862, 0.03639772, -0.13195883, -0.05321156, 0.03913229, -0.08160194, -0.07128151, 0.043625016, 0.11966009, 0.03162217, 0.018834392, -0.0625129, 0.10726711) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.15922394, -0.043482754, -0.22571066, 0.009280428, -0.3882705, 0.08418719, 0.15329506, -0.028419001, -0.011272379, 0.15897545, 0.041217074, -0.0143014155, 0.09451862, -0.056342427, -0.14568482, 0.05556279) * go_0(0.0, -1.0);
|
||||
result += mat4(0.13879324, -0.23339099, -0.24573983, -0.09575104, 0.03823306, 0.4752516, -0.1696623, -0.18472373, -0.1510259, 0.23040254, 0.4196143, 0.3462817, 0.035172507, 0.18228662, 0.22475636, -0.19945027) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.08876766, 0.19567333, 0.25174314, -0.09637879, -0.007957943, 0.13510521, 0.030193076, -0.0018362573, -0.006884444, -0.41804117, -0.1026309, -0.053339038, -0.1283198, -0.03033918, 0.055674326, 0.094377995) * go_0(0.0, 1.0);
|
||||
result += mat4(0.06780768, -0.07774435, -0.0616546, -0.046531744, -0.11723141, 0.10792474, 0.013314576, -0.031451598, -0.009870351, 0.10215877, -0.13101454, -0.19878799, -0.09712651, 0.10423937, 0.14170039, -0.03359521) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.020114673, -0.015194169, 0.03657608, 0.17162928, 0.070458665, -0.08041664, 0.14067306, 0.19699603, -0.28763783, -0.033556152, -0.6588468, -0.48221052, -0.123711474, -0.080758795, -0.3187303, 0.121004865) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.074900605, 0.09297913, -0.08621144, 0.116730206, -0.034766622, -0.10381484, 0.060793545, -0.014790814, -0.123858415, -0.0010626495, 0.20547503, -0.07206306, -0.17324795, 0.023932874, 0.017495958, -0.09924652) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.015568068, 0.005394868, 0.15463537, 0.06416607, -0.045670815, -0.013540727, -0.12960619, 0.0006581649, 0.09432853, 0.05575682, -0.022219105, 0.022416297, 0.0148129435, -0.067619696, 0.022989385, -0.09695771) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.107209, 0.07072438, -0.10235772, -0.12078849, -0.02751833, -0.043195058, -0.17197154, 0.120612316, -0.17310137, -0.09429793, 0.06511165, 0.18072544, -0.21168593, 0.16383737, 0.25012484, -0.089589044) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.005439779, 0.0028433986, -0.09885586, -0.06572956, -0.0061691296, 0.15485546, -0.23724958, 0.004232802, 0.07794742, -0.012552598, 0.07554404, 0.10843201, -0.013223918, -0.08705092, -0.23228747, 0.03599732) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.043396916, -0.10680695, -0.019935586, -0.06703658, -0.30075943, -0.010179525, 0.30197874, 0.04888297, 0.00779067, 0.22583807, 0.2039884, -0.0074303118, -0.19240093, -0.024718538, 0.057117213, 0.19431825) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.37633005, 0.043971814, -0.21423087, 0.118503235, -0.15058799, 0.115756795, -0.13719647, 0.020510519, 0.1123193, 0.14797291, 0.05467349, 0.2039607, -0.31973588, 0.1667847, -0.017739004, -0.11280262) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.0084394775, -0.1281101, -0.20841378, 0.01986435, -0.04122467, -0.21089631, -0.08062371, 0.11315133, 0.05693114, -0.23773515, 0.03792205, -0.008872407, 0.04554895, -0.10683658, 0.10683206, 0.06875721) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.103948504, -0.007483217, -0.12571928, 0.054868475, -0.030646881, -0.010098222, 0.019018777, -0.07072212, -0.10689893, 0.16498323, 0.048089568, -0.10912806, -0.027318537, -0.025491163, 0.012588013, 0.072701246) * go_1(1.0, -1.0);
|
||||
result += mat4(0.14094622, -0.028118243, 0.016804086, -0.18000692, 0.33351874, 0.14980756, -0.07135749, -0.16573106, -0.17243773, 0.054617904, -0.2933543, -0.12602285, 0.08480712, -0.05704333, 0.22336398, 0.026583148) * go_1(1.0, 0.0);
|
||||
result += mat4(0.046759557, -0.03100408, 0.40000245, -0.08521555, 0.19592628, -0.15150753, 0.25288078, -0.061794683, -0.047818147, -0.12249124, 0.020410215, -0.11503924, 0.046108168, 0.030459814, -0.14096366, 0.09120256) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.087491795, -0.024289595, -0.09060237, 0.020922959, 0.09557061, -0.08556962, -0.0503455, -0.010846053, 0.0030694185, -0.008256591, 0.08290225, -0.034981687, 0.07342003, -0.021816112, -0.13905519, -0.06265962) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.08126147, -0.05866924, -0.015698025, 0.093630895, -0.02379264, 0.115918085, 0.19431724, 0.041815966, -0.051647816, 0.15277039, -0.03721037, -0.085520886, 0.041766718, 0.104392216, 0.0559556, 0.0049254233) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.11176419, 0.112272635, 0.1367475, -0.010482275, -0.06719008, 0.064003386, -0.08132314, 0.015465676, 0.052741583, 0.06779717, 0.038533892, -0.16428822, 0.040990274, 0.002559234, 0.097567044, -0.058192518) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.17228632, 0.008296625, 0.009418271, 0.037103783, -0.0601486, 0.04531715, 0.19613501, 0.112170085, -0.02256726, -0.093685195, -0.1341531, -0.038480807, 0.109840475, 0.062418167, 0.15140085, 0.050787117) * go_2(0.0, -1.0);
|
||||
result += mat4(0.15433665, 0.2104034, 0.12395812, 0.13799714, 0.14945604, 0.67457545, 0.27575177, -0.047493283, 0.24992993, -0.5305435, 0.0131732905, -0.36911693, 0.14442082, -0.18583177, -0.2861722, 0.19419897) * go_2(0.0, 0.0);
|
||||
result += mat4(0.040242445, -0.13234852, 0.10056324, 0.055854917, 0.07447713, -0.023067042, 0.00021051937, -0.0495407, -0.22037992, 0.68047297, 0.05774606, -0.012461005, 0.104557075, 0.04832623, 0.010292581, -0.050617047) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.060079176, 0.086553656, 0.0060872175, -0.012576339, 0.025149338, -0.07379716, -0.18048704, -0.007130346, 0.007826557, -0.095655076, -0.0032888134, 0.21027069, -0.09868755, -0.1180311, 0.0081250835, -0.05078016) * go_2(1.0, -1.0);
|
||||
result += mat4(0.19124818, -0.05949092, -0.36762074, -0.08203597, -0.10276991, 0.111005515, -0.2845309, 0.113985784, 0.07206471, -0.026585411, 0.20032002, 0.5691625, -0.0460136, 0.03874166, 0.09858682, -0.15913802) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.00397842, -0.014763085, 0.080231026, -0.09142265, 0.03637215, 0.064106315, -0.030963007, 0.0557953, 0.04173885, -0.024534896, -0.2092259, 0.06913638, 0.08103145, -0.0033994897, -0.10903093, 0.062850125) * go_2(1.0, 1.0);
|
||||
result += mat4(0.01206918, 0.024855271, -0.051995132, 0.013999821, -0.021517826, 0.06216198, -0.050853133, -0.064136736, -0.047408275, -0.07858566, 0.074464396, -0.038218755, -0.13216262, 0.008905726, 0.10333, 0.03049554) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.027152343, -0.069046065, -0.013017797, 0.0763, -0.08611993, -0.020867927, 0.012807627, -0.11971997, 0.025972975, 0.095127404, -0.070044935, -0.21399231, -0.22536097, -0.028828809, 0.123399965, -0.15967365) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.038314234, -0.014114242, 0.012115026, 0.05505015, 0.11785298, -0.08772618, 0.034408223, 0.09134674, -0.04727011, 0.020709611, -0.01780165, -0.14374214, -0.30412516, -0.011123043, -0.024216317, -0.007538433) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.17673545, 0.077738725, 0.056153737, 0.028693894, 0.05688375, 0.021928595, 0.014585902, 0.019364892, 0.029056642, -0.2072201, -0.17548367, 0.085471265, 0.16439342, -0.0052957633, 0.22321554, -0.19246858) * go_3(0.0, -1.0);
|
||||
result += mat4(0.1914782, -0.15620962, -0.16686897, -0.04141303, 0.07696967, -0.013115313, -0.057627093, -0.13849305, 0.08699377, -0.07339016, -0.053074118, -0.059418138, 0.19988623, -0.23852244, -0.12574267, -0.29139704) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.017691063, 0.18901291, 0.16250716, -0.11039392, 0.056900974, 0.036662772, -0.13399602, -0.11378214, -0.10924602, 0.2130181, -0.042094063, -0.012445028, 0.013168919, 0.119448364, -0.014406005, 0.0054324497) * go_3(0.0, 1.0);
|
||||
result += mat4(0.11552786, 0.090796515, -0.11559005, -0.035706047, -0.044022456, -0.027642358, 0.08824298, 0.035067793, 0.18125483, -0.15502097, 0.094219126, 0.07493505, 0.022493582, 0.038250685, -0.076567575, -0.059311453) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.08612596, 0.016376335, -0.0023271537, 0.32511148, 0.03789289, 0.13106889, 0.22370385, 0.21145949, 0.1844514, -0.0766592, 0.093758754, 0.13821359, -0.062405586, 0.0028724174, -0.13588348, 0.00024406122) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.08991004, 0.074423954, -0.020964831, -0.070288494, -0.1192369, -0.015506713, -0.28136373, 0.042911243, 0.08215164, 0.11065419, -0.006201638, 0.057742044, 0.0014476188, -0.01443158, 0.22631277, -0.06787264) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.07235962, -0.019149294, 0.05072898, 0.03962245);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!SAVE conv2d_2_tf
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.14315613, -0.031299837, -0.011195234, 0.0073360316, 0.07264984, -0.110979274, 0.06560588, -0.040463638, 0.28964168, -0.05644335, -0.060729366, -0.15811591, 0.028339373, 0.027486937, 0.0360574, 0.05856459) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.16211128, 0.20672597, -0.30374205, -0.056202736, -0.10893948, 0.053066984, -0.18297112, 0.028844962, 0.22754766, -0.07141921, 0.07142953, -0.1357581, 0.008053467, 0.04668908, 0.17258649, 0.22506891) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.07014762, 0.032112304, 0.028849715, 0.09427007, 0.008323501, -0.085777245, 0.083501115, -0.16150802, 0.24127382, -0.1305689, -0.027557204, -0.15057805, 0.09748757, 0.08182083, -0.107643455, 0.020552907) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.04630706, -0.056070503, 0.058440026, -0.005662525, 0.08736355, 0.08821088, -0.049539115, 0.08171937, 0.28466523, -0.025859421, -0.0026971614, -0.15181617, -0.022231927, 0.3566104, -0.024887348, 0.12051598) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.20976813, -0.23778942, 0.28854275, -0.27583683, -0.27604774, -0.15861328, 0.09581984, 0.06572128, 0.092306405, -0.06962751, -0.042226445, 0.035234913, 0.084891975, -0.03846841, -0.1473667, 0.2810354) * go_0(0.0, 0.0);
|
||||
result += mat4(0.028011162, 0.08945262, 0.15859836, 0.18426442, 0.10649845, -0.0918649, -0.12257575, -0.00914911, 0.23701023, -0.030067213, -0.01938559, -0.11026175, -0.5953985, 0.28875506, -0.035278864, -0.05043055) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.14445779, -0.06907616, 0.13078876, -0.0089114, -0.110637166, -0.123719245, -0.094949, 0.046267383, 0.4727523, 0.0073195575, -0.014788787, -0.14922102, -0.021974785, -0.10706751, 0.00049029186, 0.09215345) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.20936993, -0.22377276, -0.07697398, 0.039161056, 0.044213686, 0.037542075, -0.06600642, 0.017124292, 0.3406197, 0.011907687, 0.019732054, -0.22745137, -0.22178015, 0.49051985, -0.03707166, 0.14849792) * go_0(1.0, 0.0);
|
||||
result += mat4(0.07833466, 0.10888627, 0.16015877, -0.049263358, 0.29002127, -0.010949114, 0.013081097, -0.071674205, 0.3532135, 0.013165473, -0.05282189, -0.16688257, 0.009552089, -0.2740816, 0.04927233, -0.37047002) * go_0(1.0, 1.0);
|
||||
result += mat4(0.23682123, -0.027914839, 0.02372468, -0.07127212, 0.053436097, 0.057737537, -0.008556659, -0.025973454, 0.06468388, 0.18805866, -0.08180048, 0.058999106, -0.3058321, -0.06642967, -0.092997625, 0.10527466) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.1353085, -0.016593851, 0.21518163, -0.10272456, 0.14382689, 0.05056661, -0.27799338, 0.11351653, 0.05838342, 0.28104934, -0.03777824, 0.003435516, 0.057915565, -0.17574134, -0.24437475, 0.13420977) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.13400255, -0.056437124, 0.11310834, 0.040429913, 0.098928474, -0.020769242, -0.079605736, 0.0494632, 0.0660877, 0.098982334, -0.055884495, -0.046533633, 0.17815505, 0.027310565, -0.24176653, -0.025550256) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.03637618, -0.012618673, 0.11865397, 0.19804053, -0.03522831, 0.24310908, -0.056454524, -0.44885796, 0.02212509, -0.20253624, 0.038810212, -0.17396528, 0.08970355, 0.005103078, 0.061075203, 0.44292897) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.25074747, -0.0015575301, -0.685015, 0.07345307, -0.08419402, 0.06640714, 0.43799296, -0.17571151, 0.0049855476, 0.09024738, 0.055744022, 0.018739637, 0.34734032, 0.114896655, 0.0404696, -0.11327049) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.12284062, -0.31131, -0.14712588, -0.18645866, 0.17581487, 0.1357234, 0.09913364, 0.005298711, -0.056155153, 0.042429443, 0.039454732, -0.04111384, 0.2623163, 0.09701166, 0.022825675, 0.050480727) * go_1(0.0, 1.0);
|
||||
result += mat4(0.058734808, 0.038528245, -0.042670116, -0.15190329, -0.028179986, -0.05362995, 0.017090468, -0.24449602, -0.08240927, -0.033122182, 0.009938243, -0.0052937623, 0.2171439, 0.06879817, -0.10361997, 0.018995138) * go_1(1.0, -1.0);
|
||||
result += mat4(0.027555468, 0.016337285, 0.19074728, 0.26690376, -0.088713005, -0.0021182299, -0.23062791, -0.32101163, -0.0040022335, 0.16835448, 0.05424022, -0.02156396, 0.24163729, 0.10243619, -0.04331782, -0.014350939) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.13836963, 0.053369813, 0.036432605, 0.062288612, -0.06264361, -0.049093347, -0.0315955, -0.11237456, -0.064744405, -0.0151798045, 0.044210885, 0.010166375, -0.038355727, -0.05203739, -0.075036794, 0.1664177) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.08583114, 0.08268218, -0.05771351, 0.10195048, -0.10128163, 0.10874855, -0.02580701, 0.028834302, 0.1950179, -0.0130183315, 0.0092119705, -0.060479227, 0.117747106, 0.061403573, -0.0028475628, -0.032362986) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.05310153, -0.061091065, 0.19438389, -0.10475873, 0.00045120303, -0.24876194, 0.017168125, -0.050173752, 0.012073283, 0.035660096, -0.017562328, -0.110271364, -0.015546384, 0.17965329, 0.10068208, -0.014481325) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.085558474, -0.0007109211, 0.20868625, 0.150163, -0.19283043, 0.025976779, 0.08384698, 0.031011146, 0.17268184, 0.008871077, -0.04097794, -0.12868725, 0.01336166, -0.038823843, 0.1703644, -0.067780636) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.06480841, -0.44256654, -0.19949587, -0.030677497, -0.27930573, -0.041867044, -0.15648738, 0.11573067, 0.28664824, 0.009770385, -0.058617204, -0.06607673, -0.038160402, 0.009497089, 0.03303058, -0.079379834) * go_2(0.0, -1.0);
|
||||
result += mat4(0.17752203, 0.10979527, -0.058749028, -0.30194217, 0.30484176, -0.20980492, -0.05234784, -0.2590473, 0.23003183, 0.21903595, -0.024891363, -0.14337292, -0.02971356, -0.29613075, -0.045642294, 0.23826689) * go_2(0.0, 0.0);
|
||||
result += mat4(0.018211683, -0.005840598, -0.19021381, -0.096696235, 0.39998052, -0.34746838, -0.039627917, 0.087701194, 0.15526368, -0.008095372, -0.044220537, -0.08634815, -0.121496454, -0.06792033, -0.14959472, 0.078917444) * go_2(0.0, 1.0);
|
||||
result += mat4(0.33109078, 0.012287281, -0.034155898, -0.04840956, 0.068748444, 0.006142039, 0.06598935, 0.024775596, 0.22379673, 0.056089353, -0.006119644, -0.018509025, 0.10084137, 0.15556572, -0.041211523, -0.21550669) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.058160853, 0.08899222, -0.17401625, -0.1449813, -0.015872562, -0.03780256, 0.15702572, 0.34013954, 0.1580772, 0.074823864, 0.035488904, -0.01627819, -0.15551315, -0.3638866, -0.09833458, 0.15037175) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.12707977, -0.19947061, -0.11524648, 0.09216174, -0.07161296, 0.05675567, 0.06843247, 0.2803306, 0.25222927, -0.044076066, 0.053775772, -0.09939824, 0.16903089, 0.11475717, -0.07015584, -0.036021322) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.12290332, -0.05469477, 0.02696626, 0.051133692, -0.05541504, -0.2811521, -0.13008943, 0.031793896, -0.32529324, -0.01663752, -0.0658181, 0.17300756, 0.22281154, -0.11001508, 0.09578194, -0.055437982) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.083753526, -0.048933715, -0.13912897, 0.10929772, -0.1789828, -0.1586524, -0.10964165, -0.08210391, -0.11568187, -0.04813496, -0.2417861, 0.24446528, 0.13570863, -0.26869404, 0.3013413, 0.11678686) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.21105368, 0.15749952, -0.18983693, -0.023642758, -0.1633653, 0.10107988, 0.052329395, -0.080253236, 0.15375629, -0.045091413, 0.05070866, 0.12416106, 0.16600485, -0.10412354, 0.061849747, -0.084013924) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.03863923, 0.03690167, -0.053106382, -0.07523278, -0.04214836, 0.53898096, 0.15308584, 0.22835171, -0.24771535, 0.1402687, 0.1000896, -0.08719167, 0.0886567, 0.15255097, 0.14695966, -0.06659865) * go_3(0.0, -1.0);
|
||||
result += mat4(0.110334344, -0.12696493, 0.24256139, 0.02536166, 0.08322421, 0.022147777, -0.35030407, 0.13734557, 0.053133942, 0.43650532, -0.30170345, 0.08751837, 0.012917502, 0.27496436, 0.11422729, 0.15508565) * go_3(0.0, 0.0);
|
||||
result += mat4(0.16684863, 0.26743406, 0.15951683, 0.033597723, -0.044719726, 0.1127182, 0.007923161, 0.06415458, -0.07269362, -0.07828715, 0.09216738, 0.11528897, -0.13371283, -0.124177165, 0.14804523, 0.14156726) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.041141883, 0.023617791, 0.11484465, 0.13131519, -0.14753738, 0.17067687, -0.017538434, 0.24042644, -0.058103643, 0.3143255, 0.02476919, -0.0024666793, -0.26759955, -0.06099211, 0.006415725, 0.10394301) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.04198037, 0.03277123, -0.25069895, -0.21043587, -0.27417016, 0.08047665, 0.29731026, 0.07629813, -0.15695353, -0.14299184, 0.026618432, 0.13265325, 0.07727133, 0.12872085, 0.13887435, 0.1347057) * go_3(1.0, 0.0);
|
||||
result += mat4(0.039232086, 0.117847264, -0.071643315, -0.040677182, -0.029160816, -0.06968689, 0.12880929, 0.037579957, -0.036671028, -0.022678757, -0.069731854, 0.10590314, 0.028034678, -0.015759282, 0.047180142, -0.16366881) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.079253934, 0.001511763, 0.100159355, 0.01585197);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!SAVE conv2d_2_tf1
|
||||
//!WIDTH conv2d_1_tf.w
|
||||
//!HEIGHT conv2d_1_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_1_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_1_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.024126908, 0.01737047, 0.04563732, 0.08303721, -0.21339902, 0.00025652428, -0.09666459, -0.07654246, -0.01201168, 0.14373912, 0.22268519, 0.049181588, -0.0751725, 0.006847365, -0.025867194, 0.19233267) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.25251204, -0.34213448, -0.0022676045, 0.29270738, 0.08876456, 0.067294724, 0.2865476, -0.009144941, -0.074606106, 0.14566834, 0.14162645, 0.10980335, -0.7958991, -0.15410729, 0.038512416, -0.17033637) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.115404196, -0.11004134, 0.13174473, -0.0006875606, 0.0051814034, 0.058522645, -0.0795437, 0.0011465811, -0.019500278, 0.12752724, 0.16985136, -0.054932587, 0.16734739, -0.04686017, -0.072241016, 0.054562975) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.07528159, -0.113516726, 0.2081102, 0.009942251, 0.08256535, 0.050133914, 0.012745932, 0.13902397, 0.009369715, 0.083261885, 0.17366019, 0.069754004, 0.030654406, -0.045856245, -0.055254143, 0.16265897) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.14366727, 0.24948351, 0.12160293, 0.10929859, -0.116071545, -0.11725494, -0.13926856, -0.026759636, 0.12723772, 0.1938045, -0.02745115, -0.0644584, -0.23854719, 0.059308372, -0.446269, -0.06978486) * go_0(0.0, 0.0);
|
||||
result += mat4(0.21108554, -0.1717225, 0.066633105, 0.15418948, -0.08902029, 0.047925282, 0.15817304, -0.080941506, 0.007364865, 0.10506626, 0.20205018, -0.078695655, 0.14004812, -0.3195092, 0.19157887, -0.12697977) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.08145032, -0.14292753, 0.066565305, -0.061348185, -0.08738346, 0.011608093, -0.0024047727, -0.024741996, -0.11547277, 0.10013328, 0.21730538, 0.05598899, -0.17741105, 0.075944185, 0.027434295, -0.2550598) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.026223006, 0.11214396, -0.133987, 0.1303522, 9.32011e-05, -0.14755996, -0.14002979, -0.039624512, 0.045111652, 0.17618611, 0.17764348, 0.104528464, 0.20592515, 0.07240335, -0.27604735, 0.038880046) * go_0(1.0, 0.0);
|
||||
result += mat4(0.17734227, -0.002935363, 0.07505682, -0.029969893, -0.024536638, 0.11236127, 0.119374484, 0.08002781, -0.003541722, 0.1428466, 0.1729824, 0.055412393, -0.04790376, 0.18020035, 0.05376964, -0.1520942) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.11352182, -0.019249126, 0.10782615, 0.03079928, 0.020381734, -0.08998433, -0.09211494, -0.054406203, 0.1828849, -0.07692097, 0.004733955, -0.026685018, -0.08044814, -0.071961075, 0.029184176, -0.22562811) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.34489468, -0.07447471, 0.026422959, 0.33550653, 0.22130035, 0.059709545, -0.07646962, -0.18386386, 0.33911958, -0.07534871, 0.040870134, 0.051136248, 0.32681262, 0.20612194, -0.1609581, -0.70460784) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.27617922, 0.09758603, 0.05103887, -0.09281693, -0.007143339, 0.006635712, -0.055270564, -0.022629099, -0.13023081, -0.013819027, -0.038695697, 0.047280338, -0.13964762, 0.09852924, -0.10056262, -0.084967695) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.1370323, 0.030904075, -0.033860117, 0.08926374, -0.14616281, -0.29926816, -0.23738252, -0.21374625, -0.14039646, 0.11503669, 0.082101606, -0.061717354, 0.021357644, -0.10676707, 0.03214661, 0.029967157) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.29881296, -0.22195289, -0.3512607, -0.2277441, 0.033705913, -0.23267402, -0.119738854, -0.18925253, 0.068823405, -0.15160555, 0.2585695, 0.10484223, -0.012574211, 0.38808516, 0.2599094, -0.4991424) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.07474731, 0.22742131, 0.014462262, 0.08409484, 0.09579643, -0.0519534, 0.0007793075, -0.044820115, -0.010144471, -0.040506937, 0.0056340825, 0.057767954, -0.14988829, -0.05099549, 0.007204364, -0.07094934) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.05736621, 0.12072876, -0.02037183, 0.05012334, -0.1173538, -0.10062993, -0.0033958228, 0.0142556345, -0.011005385, -0.0066177617, -0.058390465, 0.048240293, 0.09835053, 0.17917523, -0.06466951, 0.017518612) * go_1(1.0, -1.0);
|
||||
result += mat4(0.1413101, -0.30268928, -0.17851736, -0.10797371, -0.01964573, 0.14356858, -0.06759965, 0.17416531, 0.13905385, -0.017476829, 0.06541924, -0.044690568, -0.080723755, -0.08610206, 0.095347285, -0.09233214) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.07254187, -0.091158785, 0.018472971, 0.03514051, 0.018888336, 0.107934274, -0.018830854, 0.10007211, -0.053966418, -0.035646267, -0.031214178, -0.05980228, -0.13045661, -0.011743741, -0.03325275, 0.071065165) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.037697386, 0.054388218, -0.010934479, 0.2266702, 0.049999133, 0.017648092, -0.044225454, 0.21611899, -0.03805845, 0.054236397, -0.018563407, -0.060588073, -0.031215845, 0.075081706, 0.07333242, -0.09651128) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.32236508, -0.0026381002, -0.30787975, 0.2963127, -0.13276175, 0.1058753, -0.12744896, 0.09749292, -0.02683677, -0.0041124597, 0.006103888, -0.09997201, 0.092101686, -0.08375288, 0.09641652, 0.053333007) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.027999232, -0.060004722, -0.009207874, -0.0952888, -0.038418446, -0.13316345, 0.099323496, 0.048450433, 0.0443969, 0.056023613, 0.1156147, 0.018980766, 0.040020484, 0.07555044, 0.0039174426, -0.044098593) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.101029314, 0.33333415, -0.22052327, -0.035329416, 0.17229559, 0.12564908, -0.07879576, -0.09248896, -0.03239869, 0.022611454, 0.05610472, -0.02181683, -0.06347532, -0.077292696, 0.02005389, -0.078899406) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.028139396, -0.04349171, -0.019393284, 0.42110333, 0.37065667, 0.5282552, 0.43816927, 0.19155908, 0.051832534, 0.02050813, 0.030795977, 0.023960136, -0.27617985, 0.19165507, -0.005492024, -0.13349663) * go_2(0.0, 0.0);
|
||||
result += mat4(5.0700226e-05, 0.21293098, -0.39902148, -0.058406413, -0.06766975, 0.1129277, -0.012398328, 0.025031524, 0.03519656, 0.06486415, 0.15710293, 0.014098051, 0.057754945, 0.116186336, -0.14429826, 0.051864166) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.012280755, 0.043744788, -0.06420968, 0.012739398, 0.043073926, 0.031230433, 0.00036492705, -0.039208546, -0.09329152, 0.06928111, 0.11622664, -0.009106846, 0.111528054, -0.020315262, 0.036427997, 0.15881014) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.066635534, 0.13901882, 0.0885122, 0.1030835, 0.08539728, -0.015466482, 0.0706688, -0.1611047, 0.02179479, -0.00048529037, 0.08708685, -0.00894464, -0.13046473, -0.21456988, -0.20666413, 0.049039323) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.100800075, -0.03772198, -0.095183305, -0.15150243, -0.08743059, -0.24299338, -0.019315414, -0.1574107, -0.013610722, 0.064871654, 0.058439128, 0.008972897, 0.10339555, -0.027356634, 0.07666196, 0.048524544) * go_2(1.0, 1.0);
|
||||
result += mat4(0.046309173, -0.03858991, -0.13260359, 0.0017626585, 0.1453724, 0.1402359, -0.079240486, 0.13017912, 0.0629575, -0.15448172, -0.1856442, -0.044694453, -0.17226808, -0.08065212, -0.008038736, -0.15994963) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.18369722, 0.03849556, -0.035185467, -0.20205377, 0.03879293, 0.02712859, -0.051278092, 0.14862835, 0.10261192, 0.18085574, -0.025982017, -0.029160796, 0.5301373, 0.09614058, 0.35518438, -0.014906588) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.31154996, -0.06868871, -0.012681131, 0.028093819, -0.37321633, -0.14738804, 0.06060776, 0.050054748, 0.013779029, -0.020390315, -0.12487434, -0.0029474346, -0.274524, -0.09142805, 0.0132142445, 0.1577639) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.02177336, -0.020817943, -0.0111796055, -0.0046033757, 0.45033064, 0.3573757, 0.55279994, 0.602122, -0.05536106, -0.33642644, -0.1851379, -0.052192084, 0.03683446, 0.13613251, 0.20098919, -0.090587094) * go_3(0.0, -1.0);
|
||||
result += mat4(0.1520822, 0.37173554, -0.061298244, 0.0019386727, 0.44656134, 0.13406622, 0.39018136, 0.5722051, -0.13074401, 0.012778576, -0.2837446, 0.16098566, 0.100189455, -0.40386122, 0.17464107, -0.17862785) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.01217905, -0.24295084, 0.08192982, -0.14160301, -0.05936872, -0.003312342, -0.07542139, 0.13488367, -0.21560493, -0.14342502, -0.19195864, -0.09448305, -0.1038431, -0.075766176, 0.03226791, 0.06455397) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.076916575, -0.10891301, 0.032635316, 0.03848802, 0.15750243, 0.48169684, 0.5410635, 0.017279895, 0.012730932, -0.0059071835, 0.030766146, -0.0225503, -0.030178519, -0.05866621, 0.033593398, -0.00033098995) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.10757409, 0.2644168, -0.025696747, -0.0077012815, 0.31728277, 0.29771668, 0.2443613, -0.047722775, -0.083712585, -0.12742844, -0.3138776, -0.059888497, 0.12291351, -0.14435866, 0.051414594, -0.11889901) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.063888945, 0.002844068, -0.06129518, 0.03381495, 0.10176077, -0.11625004, -0.10745763, -0.20636752, -0.03820934, 0.01926402, -0.20310643, 0.09767577, -0.00776684, 0.13453315, -0.036967937, 0.09780335) * go_3(1.0, 1.0);
|
||||
result += vec4(0.019374544, -0.050425697, -0.005817216, -0.0059976326);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!SAVE conv2d_3_tf
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.028328063, 0.038015317, 0.14893384, 0.10103896, 0.028176744, -0.02067147, -0.10970998, 0.015726602, -0.07402682, -0.075281784, -0.012586929, 0.053476278, 0.14823362, 0.20312984, 0.24213, 0.039118115) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.009731573, -0.019011121, 0.016360838, -0.0073153526, 0.14594506, -0.0427664, -0.094225354, -0.013891855, -0.037061375, 0.024959227, -0.12289382, -0.21792257, -0.33579424, 0.052678566, 0.04346115, 0.07943186) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.0022269129, 0.013298362, -0.045071404, -0.007918287, 0.010860651, -0.073057, -0.0042394064, 0.03340809, 0.04938919, -0.024218693, -0.008147567, 0.08848061, -0.06840333, 0.10077341, -0.272586, -0.06542769) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.15929016, -0.1415167, 0.057084452, 0.06830724, 0.0046992986, 0.068573505, 0.22142749, -0.18493174, -0.1006019, -0.11373546, 0.17520057, -0.12888812, 0.05176946, -0.14703397, -0.20610721, 0.16611591) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.0069309813, 0.22358349, -0.18569049, 0.13456121, -0.21528137, 0.04618922, -0.47261322, -0.09682613, 0.5402922, 0.15818685, 0.05288464, -0.09949312, 0.21833964, 0.06652228, -0.2694682, 0.58216536) * go_0(0.0, 0.0);
|
||||
result += mat4(0.040808782, 0.023110595, 0.12678777, -0.09057271, 0.03159572, 0.044006016, -0.10090222, 0.09940838, -0.08454473, -0.118349984, -0.053009644, 0.24352531, -0.103818566, 0.12536442, -0.17832974, 0.25161982) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.026323501, -0.14911288, -0.0073903934, 0.06902844, 0.07188603, -0.05006621, 0.06539817, -0.048083752, -0.08032579, -0.07449341, -0.015944218, 0.032426495, 0.069349505, -0.07441237, 0.055614363, 0.065174624) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.046432327, -0.051616143, 0.017791865, -0.047294978, 0.025944458, -0.0020909954, 0.083794415, -0.055740435, -0.3720184, 0.06654654, 0.1944378, 0.07806658, 0.00870193, 0.005404396, -0.059417505, -0.06270168) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.011699918, -0.03260685, 0.016413182, -0.02199741, -0.042898953, -0.018734168, -0.12387174, 0.06405199, -0.050764065, 0.07050078, 0.006969675, 0.05508108, -0.079687595, 0.12154926, 0.071177684, 0.046873443) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.2158498, 0.03612371, -0.05268691, -0.065594874, 0.06997431, -0.07327132, -0.03323361, -0.23306306, -0.00011140713, -0.1891967, -0.017328357, 0.15796778, -0.061359044, 0.008202449, -0.031317197, -0.020873578) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.022816254, -0.014594548, 0.0064240466, 0.07976367, -0.0070318123, -0.07651652, -0.111756384, -0.2788498, 0.16634429, -0.1583179, -0.10245271, 0.10480152, 0.345051, -0.07809675, 0.046080578, -0.32139245) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.020630263, 0.032152038, 0.0019161701, 0.05435833, 0.078139454, -0.10090956, 0.14244889, 0.017286595, 0.0039871824, -0.026395446, 0.14158171, 0.0010112645, 0.17055373, -0.08093189, -0.049234428, -0.33473247) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.10982378, 0.029386539, -0.15483, -0.04345961, -0.16869037, -0.30862433, 0.060743757, -0.032285906, 0.017884266, -0.09846199, -0.090971105, -0.1693697, -0.063690096, -0.08489718, 0.18247683, -0.19921213) * go_1(0.0, -1.0);
|
||||
result += mat4(0.1898742, 0.22187345, -0.28495324, -0.42578775, 0.12833633, -0.2251503, -0.025917793, 0.6011678, -0.36586264, 0.23302059, -0.072634645, 0.0064221635, 0.56792957, -0.4684677, 0.05015159, 0.30121225) * go_1(0.0, 0.0);
|
||||
result += mat4(0.10837159, 0.14743729, -0.03639783, -0.34797576, -0.18306817, -0.07957882, -0.111433275, 0.30104128, -0.102763996, -0.01020151, 0.016333267, -0.012390819, 0.11835027, -0.12597388, -0.006298998, 0.0513052) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.23662986, 0.23325302, -0.046104953, 0.36488137, 0.06990537, -0.06887873, -0.012611426, -0.02618366, -0.05296669, 0.195254, 0.016366778, 0.01693462, -0.08488424, -0.24656284, -0.035283253, -0.15318634) * go_1(1.0, -1.0);
|
||||
result += mat4(0.061704446, -0.26930714, -0.24598889, 0.27657726, 0.05046488, -0.341884, 0.10704377, -0.15971762, 0.072999336, -0.2005826, -0.05874223, -0.053938035, -0.08284583, -0.22792995, 0.1027033, -0.012932447) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.029079054, 0.14774945, 0.026151389, 0.12380946, 0.08926635, -0.08387116, -0.17018612, -0.09304499, 0.086990625, -0.27579373, 0.003823722, -0.024723161, 0.08762848, -0.10080674, -0.012214886, -0.30239874) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.25756493, 0.2537789, 0.21723714, 0.0017929028, -0.014724892, 0.086692676, 0.11934202, -0.025869334, 0.008618976, -0.0046638376, -0.06863114, -0.07598151, -0.17309345, 0.009138105, -0.099874064, 0.07377463) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.39971545, 0.16774859, 0.13102596, 0.30735064, -0.060374007, -0.036933452, 0.14408773, 0.06479284, 0.03806265, 0.045560133, 0.043136165, -0.019244662, 0.17573427, -0.11398941, -0.0751098, 0.041702736) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.074492976, 0.18349282, -0.009050458, 0.0869807, -0.23123743, -0.015426683, -0.14346392, 0.005445149, -0.05322614, 0.10287576, 0.16083732, -0.09557319, -0.13891783, -0.13752605, -0.023572346, 0.13608918) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.31140685, 0.40130782, 0.07704675, 0.27509958, 0.09711739, -0.18293281, -0.14500841, -0.15334702, 0.098314695, 0.22749798, 0.006017282, -0.013669673, 0.07147038, 0.022289474, -0.036797456, -0.0013958871) * go_2(0.0, -1.0);
|
||||
result += mat4(0.0547557, -0.03036202, 0.65113044, 0.10668893, 0.304707, -0.1456157, 0.27668485, 0.2279428, -0.42439902, -0.0073047588, 0.045635667, 0.271637, -0.19595222, -0.28107607, 0.3905438, -0.29898256) * go_2(0.0, 0.0);
|
||||
result += mat4(0.076843366, 0.037181348, 0.08652873, 0.1756985, 0.03728033, -0.22783624, 0.16810594, -0.022009399, 0.16058537, 0.24559903, 0.05266939, -0.13929726, 0.15964857, 0.0013167082, 0.015017631, 0.101646364) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.3022452, 0.20052882, 0.13433233, 0.04250016, -0.15248592, 0.014216527, -0.23489903, 0.13919333, 0.22891816, -0.0053335144, -0.05567782, -0.12769286, -0.05337762, -0.11429989, -0.00882089, -0.030790573) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.11763547, 0.1073185, 0.15810886, 0.013149736, -0.028268294, -0.24712053, 0.08592036, 0.075742744, 0.19626461, -0.10880887, -0.22599675, -0.37207767, -0.032548983, -0.011045266, -0.035218395, 0.099996395) * go_2(1.0, 0.0);
|
||||
result += mat4(0.05631665, 0.029538663, 0.043909863, 0.13720988, 0.10980592, -0.047748722, 0.080308706, -0.06828442, 0.1144396, -0.12510885, -0.067976676, 0.030742755, 0.07134681, -0.06652312, -0.0642328, -0.034490924) * go_2(1.0, 1.0);
|
||||
result += mat4(0.019588284, -0.15197967, -0.16797094, -0.026324488, 0.014429439, -0.028491383, 0.059453625, 0.23443304, 0.02504347, 0.08872467, 0.032782357, -0.085310735, 0.013040259, -0.09837991, 0.073533125, -0.03544458) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.02198588, -0.09614766, 0.024655875, 0.025384603, 0.012162857, 0.065071434, 0.018112874, 0.19828922, -0.33289856, 0.011323505, 0.13696423, 0.31772846, -0.06587399, -0.05569957, -0.16469179, -0.22545892) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.009093827, 0.086783886, 0.060070645, 0.049957857, 0.041628215, 0.082412794, 0.117729135, -0.178277, 0.08326062, -0.07120824, 0.1788718, 0.050748438, -0.08952197, -0.14609487, 0.05515471, 0.14784457) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.10823147, -0.05108019, 0.092807196, -0.13899301, 0.19123949, -0.044189975, 0.0030145745, 0.08935499, -0.10338727, 0.01996205, 0.15671325, -0.08229972, 0.05603653, 0.043324884, 0.13562247, -0.11487494) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.18872134, -0.07302765, 0.030137405, 0.30928415, -0.07689583, 0.045998566, 0.45554903, -0.1653404, 0.14705873, -0.10649596, 0.46833125, 0.17608039, -0.43967086, 0.056812476, -0.17908083, -0.40455228) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.08093384, 0.032636635, 0.124594346, 0.13655491, 0.16780408, -1.4671803e-05, 0.13044862, -0.397665, -0.013273644, 0.08253894, 0.16302188, -0.052874118, 0.04073075, -0.18063635, -0.00838661, -0.31084144) * go_3(0.0, 1.0);
|
||||
result += mat4(0.06804371, -0.14755388, -0.12055216, -0.00437858, -0.044694718, 0.22744909, 0.012434794, 0.06245207, 0.00560859, -0.15815294, -0.19711316, 0.07711764, 0.03078979, -0.09560189, 0.10509056, 0.010651465) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.026342146, 0.13919179, -0.0030414977, 0.06607403, 0.071292974, 0.065464914, -0.027091878, 0.10620255, -0.052090824, 0.06840278, -0.08457357, 0.08867469, 0.2976581, -0.6702739, -0.15472057, -0.3066263) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.00072869845, 0.046573937, -0.08363707, 0.07867379, 0.038065, 0.01228845, 0.031746328, -0.024448024, -0.065555945, 0.1220454, 0.032151606, -0.022336006, -0.0010816467, -0.026455112, 0.112422734, -0.10285581) * go_3(1.0, 1.0);
|
||||
result += vec4(0.052450567, 0.10404023, -0.059578225, 0.009724121);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!SAVE conv2d_3_tf1
|
||||
//!WIDTH conv2d_2_tf.w
|
||||
//!HEIGHT conv2d_2_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_2_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_2_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.037506457, -0.06573841, -0.087879084, -0.06359248, -0.0017873603, -0.009097742, 0.010108622, 0.026364084, 0.012306545, 0.12607974, -0.088268295, 0.14034338, 0.24951904, 0.0983314, 0.03635719, -0.047059253) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.05570699, 0.11044774, 0.04827364, -0.03185735, -0.032498132, -0.062959515, 0.2933071, 0.22244357, 0.061075654, 0.0064111133, 0.011452209, 0.11576761, 0.13969804, 0.20502032, 0.1114938, 0.022496287) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.054194342, 0.000389916, -0.039589155, -0.018707246, -0.036095835, -0.06873059, -0.077109694, 0.028726012, -0.08820959, -0.109247595, -0.05745309, 0.043230128, 0.033671502, 0.16398554, 0.030398889, -0.17000203) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.09218165, -0.12813722, -0.040984686, -0.016605416, 0.054269493, 0.12971285, -0.013961638, -0.17803082, -0.014683587, 0.2502267, -0.14249405, -0.025687713, -0.097426265, -0.30111355, -0.21776466, 0.008809217) * go_0(0.0, -1.0);
|
||||
result += mat4(0.21033873, 0.15221386, 0.18138756, -0.08248389, -0.10091519, -0.06940753, -0.014009188, -0.3009861, -0.02452202, -0.08800422, -0.36376888, 0.18485394, 0.35076657, -0.13293292, 0.24624826, 0.39373755) * go_0(0.0, 0.0);
|
||||
result += mat4(0.014170062, -0.029623963, 0.057001226, 0.09269898, -0.14630881, -0.16557585, 0.06735037, -0.015008042, -0.27238864, 0.081130914, -0.07869508, 0.098087415, 0.11217335, 0.48223323, 0.18613088, -0.035602476) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.21623239, -0.1125095, -0.09964635, 0.101452544, 0.11877652, 0.13471957, -0.10402355, 0.0077938605, 0.030518647, 0.22309083, -0.2115206, 0.017967062, -0.042780407, 0.099759325, -0.10465051, -0.033807248) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.059608232, 0.06684556, 0.00039066386, 0.08542961, 0.097183906, -0.1868667, 0.07778909, -0.06172202, 0.0021662437, -0.05387577, -0.4077133, -0.028940776, 0.110816136, -0.04154161, 0.030078325, 0.072834246) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.01881586, -0.06384429, -0.054874837, -0.016731417, -0.06570834, -0.13579571, 0.0033891131, -0.059161015, -0.11559389, 0.02149361, -0.08791608, -0.008113861, 0.08313892, -0.07327947, -0.013473171, 0.13254371) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.11458958, -0.08827364, -0.025030116, 0.12626298, 0.0070429775, 0.0337767, 0.051719055, -0.09654129, -0.04867615, -0.03609001, -0.06522421, -0.044131942, -0.048825134, 0.10652733, -0.015310965, -0.07341175) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.05782829, 0.014247012, 0.12126171, 0.100055166, 0.24079333, -0.20155986, 0.1640186, -0.12158374, -0.153708, -0.24445893, -0.10536192, 0.12758626, -0.19430119, -0.019024884, -0.080120996, -0.29866305) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.017357074, 0.04390695, 0.12889594, 0.11451521, 0.03333342, -0.16417275, 0.10196121, 0.13059081, 0.09948873, 0.15007107, 0.22664218, 0.35449567, -0.089776486, 0.025239054, 0.12463201, -0.13109131) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.064875744, 0.40551752, 0.11903257, 0.14822967, 0.14993542, -0.12758526, 0.23159283, -0.06080246, -0.084577255, 0.14307548, -0.02186462, 0.05793564, -0.050965074, 0.23895216, -0.07796932, -0.1624384) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.15942748, 0.07191155, 0.42204422, 0.35219797, 0.23286703, -0.283381, -0.2749432, 0.25922084, 0.10494953, 0.14575887, -0.19649154, -0.14563714, -0.03709703, 0.023375817, -0.05610175, -0.32548484) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.04872624, -0.3592348, -0.027413938, 0.0836858, 0.046842758, -0.35193914, 0.06154142, 0.05559191, -0.22538327, -0.097689696, -0.21317257, -0.033945527, -0.23628096, -0.016477302, 0.027297588, -0.04105733) * go_1(0.0, 1.0);
|
||||
result += mat4(0.11543502, -0.043297376, 0.118703, 0.15013209, 0.03191795, 0.014122794, 0.05156918, 0.023102578, 0.0808462, -0.06445798, 0.15860644, -0.062393136, -0.018691704, -0.00032888897, 0.01196705, -0.025045555) * go_1(1.0, -1.0);
|
||||
result += mat4(0.08301664, 0.12298539, 0.20151077, 0.2993159, 0.16968682, -0.18196446, -0.13322797, -0.13693243, -0.0048389523, -0.057406515, 0.21409932, -0.060822334, -0.08554752, -0.19363636, -0.35241908, -0.32256603) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.0523748, 0.17082025, 0.08556144, 0.19181536, -0.2445756, -0.3616732, -0.01641404, -0.078599006, 0.23907976, 0.025989126, 0.07574993, -0.06859337, -0.06667767, -0.022847861, -0.037942342, -0.21112117) * go_1(1.0, 1.0);
|
||||
result += mat4(0.15098672, 0.024212115, -0.19068481, -0.22606348, -0.15221487, -0.032165635, -0.06244531, -0.043535717, -0.07398802, -0.06088507, -0.013834592, -0.10145823, 0.06901983, -0.0862135, -0.05545454, 0.15514566) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.044767097, -0.07583697, -0.17739761, -0.25538698, 0.0966659, -0.0013492911, -0.23315248, -0.21652249, -0.14381947, 0.017784966, -0.15960035, -0.13297895, 0.009810349, -0.041348267, 0.05443229, 0.17781278) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.0052824756, 0.087268956, -0.022167318, -0.09450279, 0.1254372, 0.075806946, 0.028893303, -0.09019378, 0.03488572, 0.046265777, 0.026162563, 0.003914548, -0.0632334, -0.19494742, -0.03602023, 0.113897055) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.11311528, 0.2616239, 0.12303548, 0.13427438, -0.26537886, 0.015112677, -0.03641703, -0.014114427, -0.023280613, 0.03626403, 0.12833157, 0.19168468, 0.2119137, -0.02374797, 0.117919676, 0.07794395) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.13746078, 0.25739196, 0.008431936, -0.053867325, -0.13228695, -0.20661803, 0.026474724, 0.3205188, -0.41819036, 0.42812085, 0.17249924, -0.15810613, 0.39602605, -0.10873597, 0.1457145, -0.060503867) * go_2(0.0, 0.0);
|
||||
result += mat4(0.03706167, -0.036211733, 0.06519942, -0.2123978, 0.019934088, 0.17494182, -0.017252771, -0.067341134, -0.15416612, -0.114118524, -0.00028491023, -0.08172238, -0.11722721, -0.2647645, 0.13316637, 0.13562322) * go_2(0.0, 1.0);
|
||||
result += mat4(0.11832847, 0.22822993, 0.020318847, 0.0734738, -0.025950216, -0.072782144, 0.11133989, 0.18845533, -0.004584898, -0.10486471, 0.054522812, -0.14136603, 0.01940983, -0.039433163, 0.008390286, 0.013686628) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.042335663, 0.0035399816, -0.1813205, -0.25639042, 0.1042524, 0.07707001, -0.04922454, 0.18140413, -0.22322963, 0.030809738, -0.11041754, -0.040288754, 0.09431559, -0.08017892, -0.18317147, -0.019331435) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.061776266, 0.0069793356, 0.019964112, -0.14504445, -0.00070097746, -0.027107855, 0.030182542, -0.05625612, -0.04958449, 0.123165295, 0.0013953283, 0.017912487, 0.031161329, -0.31798717, 0.018331604, 0.030411277) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.0530594, -0.07933117, 0.024755973, 0.004785411, 0.045512546, 0.12833083, 0.023195961, -0.018028054, 0.014223835, 0.102213494, 0.052169293, -0.020509718, 0.017905682, 0.021354724, -0.0410789, -0.066523656) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.017061293, -0.08770806, -0.04889939, 0.01825556, -0.03228951, -0.06838898, -0.09249373, 0.18103507, 0.087000825, 0.04175679, -0.09305919, -0.2792485, 0.03405797, 0.062147446, -0.04757652, -0.021603985) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.04115162, 0.02547615, 0.07033616, 0.09814065, 0.2597489, -0.0335038, 0.14097647, 0.047022782, 0.1374654, -0.27390274, 0.02080897, -0.15251215, -0.025431091, 0.08871465, -0.22243279, -0.07792812) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.061674852, -0.051326606, -0.04885301, 0.08548189, -0.07100394, 0.044875987, -0.19810183, -0.09841128, -0.06628199, -0.041564234, 0.1111919, -0.044448826, 0.06980301, 0.00046094303, -0.045978926, -0.20736355) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.18405268, -0.28115878, -0.33536536, 0.0753763, 0.028309148, 0.0014874876, 0.28369543, -0.2133985, 0.16520546, 0.29562506, 0.109781906, 0.028433772, -0.02691105, -0.39038795, -0.12942268, -0.080103286) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.05387814, -0.04672615, 0.046064686, 0.2791977, 0.11359623, -0.204098, -0.018091407, 0.13550591, 0.04216003, -0.1631328, -0.043013666, -0.045698896, 0.032403514, 0.010206319, -0.25789943, -0.36328712) * go_3(0.0, 1.0);
|
||||
result += mat4(0.11280466, 0.11671405, -0.02122692, 0.021664057, -0.07836575, 0.014747725, 0.030007286, -0.10128616, -0.13695373, -0.10353946, -0.043571353, 0.05922437, -0.11293257, 0.0828006, -0.07322761, -0.08197273) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.0010509897, -0.1674067, 0.08191839, 0.056608744, 0.061343428, 0.19574693, 0.05302967, -0.006813754, -0.016064182, 0.22949885, -0.06631832, 0.034382205, 0.12674272, 0.06583508, 0.19319807, 0.011400221) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.032175347, -0.021227444, -0.027698517, 0.067299634, 0.23929007, 0.20669897, 0.004856941, 0.0009404045, 0.04919408, 0.020296812, 0.012571405, -0.16185577, -0.012276781, 0.16609742, -0.15718406, -0.20344186) * go_3(1.0, 1.0);
|
||||
result += vec4(0.022815697, 0.012251767, 0.045309987, -0.0879881);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!SAVE conv2d_4_tf
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.010501252, -0.046741538, -0.0017120431, -0.04840009, 0.20547974, 0.3366821, -0.10182207, 0.17451541, -0.03404171, -0.15138055, 0.16771653, -0.07168161, 0.102572344, 0.08266354, 0.20205829, 0.13429944) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.05584234, 0.06844309, 0.025430907, 0.124140054, 0.36385667, 0.12099467, -0.41671994, 0.085477844, 0.19748127, -0.21473993, 0.005037813, -0.3973761, 0.04669592, -0.100342326, -0.09403772, -0.034248166) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.17654696, 0.009085064, 0.028360577, 0.033909567, 0.09377573, 0.27896938, 0.103994116, 0.0008595595, 0.064523555, 0.040994007, -0.06337235, 0.05662917, 0.0037455747, 0.017608117, -0.14610702, 1.2175746e-05) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.04631749, -0.14251712, -0.16420849, -0.16259338, 0.46187812, 0.17576592, 0.00049142196, 0.029193122, -0.003925961, -0.11218227, 0.007026237, -0.20583045, -0.0010964901, 0.19355829, 0.2221649, 0.1187224) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.041567978, -0.31510913, 0.01618704, 0.04979329, 0.101294376, 0.16356954, 0.21361789, 0.20735294, 0.1900854, -0.4151726, -0.30471593, -0.59483325, 0.033624128, 0.11495109, -0.15194787, 0.4920959) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.18910064, -0.06516878, -0.20508374, -0.063928686, 0.7289614, 0.26674315, 0.2929481, 0.4026098, -0.033123735, -0.090371035, -0.029094126, -0.15197921, -0.08723726, -0.060160585, -0.07908409, -0.08826931) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.08321312, -0.09749648, -0.08783197, -0.23072585, 0.24343425, 0.10888949, 0.17419606, 0.04136083, 0.0066000987, -0.06112787, -0.12176007, -0.20907228, -0.0008522778, -0.054704696, -0.07197735, -0.0877179) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.40559706, -0.3801705, 0.05970925, -0.6157092, 0.28944594, 0.1252121, 0.403247, -0.122819394, -0.096336536, -0.2324694, 0.05980106, -0.19970767, -0.16646989, -0.10164633, -0.09282806, -0.08897996) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.14336498, -0.12967408, -0.016268672, -0.021431219, -0.0850116, 0.37105832, -0.04093888, 0.08540873, 0.035717323, -0.07282701, -0.009123291, -0.0036565473, -0.02508944, -0.087611906, 0.03604423, -0.00089080486) * go_0(1.0, 1.0);
|
||||
result += mat4(0.1373875, 0.05283984, -0.11992707, 0.102294855, 0.3305128, 0.044920854, 0.31622922, -0.04711731, 0.001336024, 0.022799017, -0.062343203, 0.017140022, -0.07556853, -0.12864219, -0.25721326, -0.20741239) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.22062224, 0.09266222, 0.22466063, 0.18527372, -0.06940306, 0.1317168, 0.019784274, -0.07422301, 0.04061616, 0.0022494853, 0.21723995, 0.24732308, 0.14088804, 0.0116154915, 0.102064446, 0.020701224) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.025154127, 0.045180723, -0.05877639, -0.099235624, 0.13630918, 0.24653725, -0.05723323, -0.022995364, -0.10826078, 0.049667366, 0.12618053, 0.1557369, 0.037487056, -0.22215757, 0.005912914, -0.20549043) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.09641055, 0.098845296, -0.08192096, -0.03691394, -0.18450394, 0.29955688, -0.082493715, -0.06268039, -0.0754319, 0.21018648, -0.016580105, -0.1810546, 0.13857666, -0.0327626, 0.03161804, -0.32589525) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.18272439, -0.17595461, 0.047229152, 0.14596708, 0.40453747, 0.5658558, -0.17969102, 0.21557859, -0.34232348, 0.40355968, 0.53874254, 0.0012561383, 0.28154096, -0.06745097, -0.13049632, 0.42997465) * go_1(0.0, 0.0);
|
||||
result += mat4(0.081179485, -0.0041369614, -0.12001932, -0.102107175, -0.050293338, 0.29165673, 0.08062538, 0.22925815, 0.19389379, 0.28463286, -0.057207666, 0.23133168, -0.07545728, 0.06729763, -0.103593476, 0.014468794) * go_1(0.0, 1.0);
|
||||
result += mat4(0.069821335, -0.010299579, 0.069458775, 0.03894593, -0.054688405, 0.32758355, 0.13935772, 0.37506017, 0.24083133, -0.06105339, 0.25636867, 0.09627044, 0.08939188, 0.006728639, 0.10629504, 0.07887502) * go_1(1.0, -1.0);
|
||||
result += mat4(0.10563019, 0.077379815, 0.045456886, 0.09303406, 0.11326298, 0.28762257, -0.35142374, 0.10285745, 0.28762287, 0.3592446, 0.23816557, 0.22676824, 0.030372012, -0.028023086, -0.30956736, -0.27588373) * go_1(1.0, 0.0);
|
||||
result += mat4(0.110499, 0.009828844, 0.086689755, 0.1839749, 0.16656482, 0.083707325, 0.19506347, -0.01547141, 0.13804145, 0.2206598, -0.16484791, -0.0021595939, -0.06844408, -0.07861768, 0.040771082, -0.13347322) * go_1(1.0, 1.0);
|
||||
result += mat4(0.02667995, 0.019265587, -0.18211095, -0.102116466, -0.042541366, -0.07700912, -0.020587347, -0.03532171, 0.14816427, -0.1672272, -0.17522137, -0.04657808, 0.013430233, -0.0021270285, 0.109880306, 0.004838907) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.14285165, -0.1364756, 0.017568532, -0.27690783, -0.015461915, 0.045437083, 0.018187419, 0.12473493, 0.17991658, -0.15642665, 0.10009151, -0.19040193, 0.1734127, -0.13817501, 0.0710856, -0.12921426) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.14114712, -0.18893671, 0.16121174, 0.035988737, 0.17872387, -0.106395856, -0.23183517, 0.012380416, 0.043066982, -0.28539032, -0.049011275, -0.21125022, -0.11976977, -0.015564958, 0.18880925, -0.0034812456) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.05894521, 0.17266215, -0.0458901, 0.08049924, 0.0156061025, -0.0047465423, 0.09714626, 0.045990974, -0.08786066, -0.37803304, -0.19629405, -0.08546443, 0.014874948, 0.16931784, 0.24799919, 0.06316819) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.28352743, 0.29973608, -0.014540065, 0.2865005, 0.048086923, 0.18976144, 0.22969759, 0.1643124, -0.11259408, -0.107592925, 0.184308, 0.30998367, -1.0860825, -0.29118305, -0.51242536, -0.38492215) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.17199941, -0.14274743, -0.14213641, -0.1691383, -0.17294803, -0.013992068, -0.12135059, 0.082377024, -0.11255549, -0.124990575, -0.32526177, -0.08199375, -0.25591666, 0.1882329, 0.07895415, 0.22012262) * go_2(0.0, 1.0);
|
||||
result += mat4(0.026025832, -0.07267515, 0.09738688, 0.074536435, -0.060470507, -0.037861936, 0.0507819, -0.054857653, 0.0043173633, -0.18107842, -0.02996759, 0.04072402, -0.012617744, 0.061665237, 0.0013981885, 0.08679919) * go_2(1.0, -1.0);
|
||||
result += mat4(0.27913737, 0.39656082, 0.1579819, 0.2774727, -0.007996453, 0.08704765, -0.016933938, 0.07066135, 0.12361742, -0.20802726, -0.13705719, -0.18794124, 0.037409827, -0.03351758, -0.2970392, -0.11001984) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.027419567, 0.043236237, -0.19843115, -0.056489736, -0.017010912, 0.070949584, -0.14881176, -0.0780235, 0.0039477753, -0.16772608, -0.009547604, -0.14060417, 0.0103197545, 0.07129672, 0.034949142, 0.014112084) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.06467971, 0.084101565, 0.26296136, 0.08878442, -0.11232121, -0.054373942, -0.17263442, 0.046408508, 0.032239515, 0.042490713, 0.036938053, -0.034339923, -0.07139367, 0.032505415, 0.0045828503, 0.24428385) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.053585388, -0.08175568, -0.04787236, 0.06061965, -0.0740297, 0.11113596, -0.12467945, 0.08229154, -0.01941305, 0.12903687, 0.09095716, -0.13062255, -0.0102068605, 0.107291475, 0.030279635, 0.07464777) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.11041978, -0.0123585425, 0.11147018, 0.07380536, 0.06632908, 0.011784447, 0.029638765, -0.01566135, 0.009105331, 0.05252663, -0.17972581, 0.01210126, -0.10749957, -0.028144639, -0.105761215, 0.083784826) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.058018316, 0.15083058, 0.2725673, 0.024263225, -0.067711554, 0.051117413, -0.31144425, -0.15761986, 0.017503206, -0.14361219, -0.38261738, -0.20354146, -0.04211545, 0.12921454, -0.01319619, 0.35809723) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.107978396, 0.3230084, -0.13806303, 0.12903036, 0.039864987, -0.006241628, 0.18701774, -0.10785807, 0.30056882, -0.3092082, -0.4273322, 0.3784662, -0.026107281, 0.23165871, 0.35258314, -0.06654702) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.15840323, 0.15210885, 0.04086692, 0.19169305, 0.11847602, 0.0009038581, 0.095951624, 0.043941673, 0.1512248, 0.0749449, -0.027045414, -0.19729601, 0.08265063, -0.045218006, -0.10732461, 0.05197371) * go_3(0.0, 1.0);
|
||||
result += mat4(0.13637526, 0.28841978, 0.10298119, -0.005948496, 0.020897362, -0.02186902, -0.16207378, -0.021084815, 0.029192554, 0.07076991, -0.07210881, -0.06752328, 0.0006557475, 0.08986717, -0.29430988, 0.21411087) * go_3(1.0, -1.0);
|
||||
result += mat4(0.18667863, 0.3117322, -0.0859705, -0.038189936, 0.10214859, -0.11244034, 0.2680223, -0.072901204, -0.07434324, -0.17855306, 0.23134363, -0.055360887, -0.020968167, 0.0858459, 0.078975916, 0.13254759) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.15676941, 0.03476677, -0.09922334, -0.15847856, -0.0033982224, 0.020932984, 0.12874377, 0.048792202, 0.06521213, 0.12456798, 0.15958112, 0.15981804, 0.07657683, 0.1759313, 0.012727211, 0.120304115) * go_3(1.0, 1.0);
|
||||
result += vec4(0.08911729, -0.027969634, -0.010653148, -0.08001697);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!SAVE conv2d_4_tf1
|
||||
//!WIDTH conv2d_3_tf.w
|
||||
//!HEIGHT conv2d_3_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_3_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_3_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.003206617, 0.04896987, 0.049652386, 0.10869342, 0.36313584, -0.070666805, 0.93581825, -0.52484274, -0.14278883, 0.064016834, -0.05534331, 0.02961736, -0.1319316, 0.05740655, 0.2405951, -0.12313382) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.014092832, 0.07058761, -0.07887866, -0.27478936, -0.31456405, -0.31036922, -0.18380909, -0.11277979, -0.034889866, -0.37914017, -0.056245584, 0.24008954, -0.03414483, -0.023189066, -0.010568316, -0.004604883) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.15443979, -0.050161768, -0.012300917, -0.08834887, 0.082193285, 0.06878423, 0.1478042, -0.3774468, -0.18659878, 0.14238152, 0.033605397, 0.13560006, -0.032682173, -0.024561955, 0.05656941, -0.034246165) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.04691462, 0.064624496, -0.15950382, 0.16081297, -0.1417951, -0.109690994, -0.021205869, 0.19361454, -0.006306647, 0.3401972, -0.00014070333, 0.11619607, -0.13437814, 0.05464789, 0.37712076, -0.12470751) * go_0(0.0, -1.0);
|
||||
result += mat4(-0.40016884, 0.010666597, -0.005395378, 0.51084363, -0.009875391, 0.3969395, 0.47768033, -0.3392299, -0.1509509, -0.057620626, -0.1834601, -0.09998148, 0.10095897, -0.2213528, 0.02546703, -0.28506726) * go_0(0.0, 0.0);
|
||||
result += mat4(0.26652217, -0.106772706, -0.12609608, -0.0949661, -0.10869194, -0.55331933, -0.011515521, -0.27978876, -0.2124893, 0.03954004, 0.1691768, 0.05590268, 0.1539662, 0.10703386, -0.027286088, 0.2168544) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.04862511, 0.06919758, -0.12962708, 0.016036907, -0.030030789, -0.20159967, 0.0013158675, -0.07799172, -0.032236706, -0.0035921712, -0.085437834, -0.025374755, -0.06251374, -0.009269627, -0.07519051, -0.01884611) * go_0(1.0, -1.0);
|
||||
result += mat4(0.23940067, -0.19496065, -0.05494683, 0.11601073, -0.074225076, 0.24976431, 0.41665986, 0.12029472, 0.16815041, -0.115868434, 0.06333614, 0.032145746, 0.15990137, -0.14886795, 0.034102913, -0.07727595) * go_0(1.0, 0.0);
|
||||
result += mat4(0.14702639, -0.013711502, 0.011437429, -0.11201445, -0.2582659, 0.34539905, 0.058082145, -0.18346462, 0.0027891365, 0.072565466, 0.12716974, 0.050636146, 0.092657596, 0.08541754, -0.1266164, 0.027881607) * go_0(1.0, 1.0);
|
||||
result += mat4(0.043362036, 0.020758621, 0.09906072, -0.22401148, -0.19104514, -0.25774476, 0.074128486, 0.08558291, -0.075419895, 0.20380639, 0.06398196, 0.015925938, 0.089786015, -0.100721814, -0.1374862, 0.26110905) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.12547149, 0.08151811, -0.15953775, -0.33995447, -0.50784314, 0.46155545, 0.24986996, 0.03404644, -0.047789436, -0.12438347, -0.14143273, -0.17951359, -0.08057819, 0.023863006, -0.008539273, -0.06775414) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.1430169, 0.056971863, -0.021576611, -0.045342956, -0.22356391, -0.15344621, -0.0467977, -0.22970036, -0.0125351725, 0.16957329, -0.0069183917, -0.013949834, -0.048609708, 0.05261722, 0.023262242, 0.2123519) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.019523792, 0.008228363, -0.04616012, -0.14341992, -0.19307113, 0.005937241, 0.24048887, -0.04279845, 0.022574252, 0.15558265, -0.035000063, 0.18318397, -0.05392528, -0.26044658, -0.13493988, 0.056433514) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.28926027, -0.17381874, 0.07685766, -0.0061521684, -0.47455552, -0.49213487, 0.36924496, 0.29042044, 0.201094, -0.14280887, -0.4531411, -0.52902204, -0.28123, 0.1401882, 0.32054895, -0.11357518) * go_1(0.0, 0.0);
|
||||
result += mat4(0.14173324, -0.12069898, -0.07242415, 0.105665006, 0.017373435, -0.056042343, 0.07270201, 0.022111928, -0.01106541, 0.01666006, 0.013564169, -0.36628693, -0.25450787, -0.28179473, -0.04721874, -0.21912882) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.09464695, -0.027919646, 0.13088459, 0.17504032, -0.101641014, 0.29687008, 0.08832321, 0.020538324, -0.15108941, -0.21930224, -0.026915176, -0.07078217, 0.10723033, 0.034364715, 0.18183397, -0.119012214) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.21713468, -0.0846604, 0.046551514, -0.14989382, 0.08672032, -0.07933831, 0.08093595, -0.064147756, -0.15980323, 0.50000644, -0.091568656, 0.03201994, -0.1848647, -0.0646309, 0.03288009, 0.046442386) * go_1(1.0, 0.0);
|
||||
result += mat4(0.053532355, -0.054523747, -0.040242642, -0.31438905, 0.06452703, -0.18785381, -0.14987698, -0.067642935, -0.19892459, -0.057256676, 0.05943023, -0.17331842, 0.02588534, 0.13134238, -0.07121775, 0.23446162) * go_1(1.0, 1.0);
|
||||
result += mat4(0.20633182, 0.01686198, 0.17934167, -0.02063493, 0.042606052, -0.05289458, 0.031508356, 0.00082803797, 0.0756423, -0.047548845, 0.01456339, 0.15910533, -0.20119642, 0.029213727, 0.111036316, -0.047010012) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.09258436, -0.27904224, -0.086695746, 0.33095327, -0.20126075, -0.050745636, -0.048944805, -0.10536587, -0.012995092, 0.07926994, 0.15071853, -0.13644052, -0.05188447, -0.06750699, -0.14227037, 0.028751127) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.18562223, 0.10250865, -0.17573993, 0.20434102, -0.05187468, -0.06441594, -0.052127104, -0.01925564, 0.02927959, -0.12711872, 0.059629507, 0.15696885, -0.010168965, 0.09971862, -0.03177664, -0.022744441) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.21474063, -0.15679085, 0.09609374, 0.109079376, -0.049934637, -0.07393633, 0.16688468, -0.018888129, 0.04240162, -0.31895876, -0.106516436, 0.20008606, -0.054410245, 0.028970616, -0.18008347, -0.013362003) * go_2(0.0, -1.0);
|
||||
result += mat4(0.37891293, 0.042730846, -0.24735828, -0.5234527, -0.3681344, -0.06609157, -0.14993733, -0.020316398, 0.123008475, 0.29632482, 0.32149333, 0.35999274, -0.18967044, 0.46154186, -0.016041815, 0.097378336) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.14873263, 0.07600569, -0.051758345, 0.1803135, -0.23121934, 0.13574593, 0.043973465, -0.13992754, -0.061972607, -0.124083005, -0.049196843, -0.07700431, 0.21572952, -0.25241727, 0.1218322, -0.07773728) * go_2(0.0, 1.0);
|
||||
result += mat4(0.040287063, 0.024240922, 0.021917762, -0.050616946, -0.023174169, 0.05977014, 0.018892275, 0.04014965, 0.11715485, 0.062129, 0.024620812, 0.013617107, 0.075699426, 0.1858111, -0.11769179, -0.08085602) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.3194255, 0.08695645, -0.09453595, 0.2564516, 0.02192303, 0.08167247, -0.06257352, 0.043801844, 0.04392246, 0.2020571, 0.045180902, 0.18857521, 0.1835961, -0.043788187, -0.08768916, -0.14755538) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.22074097, 0.13768476, -0.16183749, 0.059949517, -0.011375954, 0.08581876, 0.004800447, 0.019403988, 0.014646056, 0.07363176, -0.058036458, 0.0706421, 0.08082624, 0.17740329, -0.05484784, 0.050796065) * go_2(1.0, 1.0);
|
||||
result += mat4(-0.032330472, -0.067666024, 0.18980837, -0.19077848, 0.1111905, 0.03855666, -0.11272314, -0.00577739, 0.17697452, -0.053044144, -0.07510145, 0.061853852, -0.024240626, 0.14846492, 0.14804313, -0.20275854) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.17133904, -0.16356844, 0.1978664, 0.13877816, 0.28208038, 0.031539194, 0.11313891, -0.0014802719, 0.0033749861, 0.046372313, 0.054808807, -0.0024151779, 0.0068782056, -0.16414621, -0.07545907, -0.2521294) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.1746992, -0.037628956, -0.0044012754, -0.004390821, 0.0050341445, -0.112742625, 0.051241755, 0.01984483, 0.0003531837, 0.043500375, 0.030881992, 0.003503799, 0.13611782, -0.02509031, -0.007503557, -0.009321301) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.087250136, 0.12374122, 0.2959519, 0.11314702, 0.22080182, 0.106726184, -0.29768205, 0.14931595, 0.23356548, -0.008709153, -0.0797829, 0.046940215, -0.07027616, 0.20533602, 0.0723021, -0.1963585) * go_3(0.0, -1.0);
|
||||
result += mat4(0.00609982, 0.35277408, -0.22781096, -0.28912535, 0.42393112, -0.07654207, 0.12636793, 0.049337976, -0.0967726, -0.19349189, 0.36800626, 0.09745645, 0.47663373, 0.03876107, -0.042987954, 0.016161885) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.047490966, -0.05823166, 0.036158644, 0.025337253, -0.046618905, 0.108276576, -0.024148034, 0.0026794411, 0.1497962, -0.09328474, -0.03160641, 0.24351281, -0.05198027, 0.030720685, 0.00014528916, -0.2224931) * go_3(0.0, 1.0);
|
||||
result += mat4(-0.007338369, 0.18710312, 0.14617369, -0.0070655346, 0.10464997, -0.029674934, -0.11842202, -0.09114357, 0.08524458, -0.08082762, 0.06479597, -0.023760766, 0.07523641, 0.0067315935, 0.101266846, -0.2780903) * go_3(1.0, -1.0);
|
||||
result += mat4(0.14181875, -0.19523518, 0.1068169, -0.10284853, 0.11634046, -0.117397435, 0.09113022, 0.009371062, -0.022120507, -0.1127032, 0.092574745, -0.021989716, -0.088107705, -0.13541982, 0.08130504, -0.0678927) * go_3(1.0, 0.0);
|
||||
result += mat4(0.09948295, 0.23699793, -0.042369924, 0.16744529, -0.10045506, -0.045623623, 0.04871897, -0.0023967526, 0.02602692, -0.089873284, -0.050681606, -0.09332558, -0.09596149, -0.06988313, 0.0007193808, -0.11936899) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.04928105, -0.003357327, -0.03886671, 0.076106146);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!SAVE conv2d_5_tf
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.13425097, -0.23487093, 0.2480183, -0.2806276, -0.041303713, 0.100773126, -0.110890545, 0.036205858, -0.331331, -0.12929262, 0.16300063, 0.3776673, -0.20316373, -0.011239426, 0.10650887, -0.027857736) * go_0(-1.0, -1.0);
|
||||
result += mat4(0.09517376, -0.3004956, 0.05033304, -0.07464521, 0.009204248, -0.23034886, 0.30492118, -0.1215848, 0.15728685, -0.10430078, 0.04038878, 0.08034804, 0.04320418, -0.2929594, -0.018968396, 0.02542387) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.10651935, -0.2736715, 0.19267319, -0.033337504, -0.06697293, 0.028424729, 0.047814637, 0.44929537, 0.02565344, -0.253426, -0.040931404, -0.05018104, 0.032979824, -0.035349697, -0.039578713, -0.3116414) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.09176126, 0.031713437, 0.24861507, 0.31351718, 0.36284143, 0.3622709, 0.16165464, 0.07319267, -0.6303202, -0.21209712, -0.02169929, 0.037275597, -0.1295319, 0.033090707, -0.029330662, 0.054679472) * go_0(0.0, -1.0);
|
||||
result += mat4(0.15021572, -0.15177831, 0.1318225, 0.46864823, 0.059443284, 0.07404233, 0.22612074, 0.21105285, 0.319694, 0.09397257, 0.14277866, -0.0235649, -0.037205156, -0.40715128, -0.18572816, 0.058741573) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.122751735, -0.20926422, 0.2099333, -0.11627138, 0.04171681, 0.0669586, -0.03831368, 0.27334675, 0.0492008, 0.12854317, 0.03308622, 0.45236585, 0.03122829, 0.13853219, 0.05084764, -0.3965012) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.0019293908, -0.15562099, 0.12418126, 0.0045440597, 0.05442391, -0.15613738, 0.14828286, -0.17687118, -0.053517755, -0.33350968, -0.062314924, -0.31358472, -0.09670371, 0.043190923, 0.008150662, 0.09928506) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.06698031, -0.099411525, 0.24259582, -0.1073659, 0.06762824, 0.059605874, -0.20944163, -0.1598055, 0.32746908, -0.17759447, 0.2859796, -0.1274256, 0.30796206, -0.00791448, 0.114059694, 0.14775705) * go_0(1.0, 0.0);
|
||||
result += mat4(0.16291203, -0.14958477, 0.14716864, 0.2056065, -0.019337546, 0.032286238, 0.0030445335, -0.08208513, -0.14208078, 0.13601872, -0.23367858, -0.19092909, -0.20207883, -0.016950991, 0.009309007, 0.1376546) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.11093091, -0.32362202, -0.041845415, 0.029758021, -0.07261404, -0.048653398, 0.19167832, 0.09343212, 0.030472826, -0.15078579, -0.0056376588, 0.0045257527, -0.24521805, -0.10473077, 0.11163019, -0.1724187) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.08601668, 0.16612485, -0.07751539, 0.07261594, -0.19028407, 0.23896623, -0.10416726, 0.23500614, 0.1955228, 0.08699591, -0.049277775, 0.13447775, 0.19434914, -0.11481196, 0.088043146, 0.13352895) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.013221233, 0.07521129, 0.042819552, -0.11163175, 0.066080205, -0.25043094, -0.010348969, -0.013258202, 0.09444396, 0.29623637, 0.025016114, 0.050744686, -0.12219596, -0.0735393, -0.024817836, -0.06897588) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.25720942, 0.19861753, -0.18535058, 0.12190362, -0.33756095, -0.0038898317, 0.09739055, 0.41227046, -0.10030796, 0.025445882, -0.23542109, 0.08677691, 0.08140194, -0.22716106, 0.14016968, -0.0927231) * go_1(0.0, -1.0);
|
||||
result += mat4(0.58745646, -0.12533307, 0.30129984, 0.08898194, -0.07972344, -0.37581098, 0.06863413, -0.13185541, 0.21801205, 0.31779078, -0.3804784, -0.3200699, 0.14534226, 0.05912262, 0.07938948, -0.34869507) * go_1(0.0, 0.0);
|
||||
result += mat4(0.024675166, -0.067802526, 0.030065436, 0.06509131, 0.14367498, 0.022554757, 0.014991865, -0.029914752, 0.5123549, -0.012557206, -0.13014166, -0.34184244, -0.09080884, 0.13782553, -0.018931886, -0.35642785) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.37336427, -0.02705006, 0.14392053, 0.024049882, -0.024705589, 0.14556128, -0.12120506, -0.06275598, -0.1284325, 0.11409197, -0.08397436, -0.075944416, 0.056465942, 0.04016099, 0.096723564, -0.08359723) * go_1(1.0, -1.0);
|
||||
result += mat4(0.20243345, -0.09287934, -0.11676041, 0.005206654, -0.2879361, 0.41677123, -0.16924824, 0.22429213, 0.082279116, -0.1780833, 0.20209241, 0.12970525, -0.030272234, -0.19200714, 0.0015769673, -0.1389732) * go_1(1.0, 0.0);
|
||||
result += mat4(0.04211243, 0.07331798, -0.055724114, 0.04086206, -0.04635456, 0.027212424, 0.021861525, 0.12424812, 0.43009162, 0.021664696, 0.20828371, 0.11859106, 0.07390811, -0.1861182, 0.034559406, 0.18561925) * go_1(1.0, 1.0);
|
||||
result += mat4(0.22596797, 0.025346763, -0.056839246, 0.09137385, 0.07363095, -0.12382036, 0.08911783, -0.012355983, -0.07869761, 0.051298574, 0.00816572, -0.044984274, 0.07962154, -0.2254524, -0.007821531, -0.04936664) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.06265961, -0.17783198, 0.11678783, -0.12965304, 0.014506855, -0.17513473, -0.23593299, 0.14054537, 0.1580306, 0.31872272, -0.0042505316, -0.070422255, -0.01316396, 0.0058355615, 0.062464185, -0.06086727) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.079526044, 0.23932967, -0.1139716, 0.15888569, 0.06526993, -0.06958436, -0.04070066, -0.12081254, 0.026716579, 0.014887845, 0.0061467467, 0.127956, 0.040913627, -0.0032820841, 0.086145625, 0.22520025) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.25577608, 0.02553098, -0.14822578, -0.11907723, -0.09787419, -0.03544863, -0.08098151, -0.01305555, 0.20404844, 0.11294246, 0.10096346, 0.15795162, 0.2554626, 0.09361069, 0.001985862, -0.0051444587) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.24454486, -0.014714279, -0.2954907, -0.39995646, -0.15907967, 0.30107877, -0.34781745, 0.095281735, -0.12492393, -0.28375402, -0.16872306, 0.2531788, -0.52085644, 0.35986066, 0.07716912, 0.09565738) * go_2(0.0, 0.0);
|
||||
result += mat4(0.2493129, 0.06395661, -0.09491958, 0.19702488, 0.109871864, -0.051376317, 0.15404263, -0.21282886, 0.1188967, 0.07824094, -0.016752928, -0.14027214, 0.10949832, -0.27629098, 0.081909016, 0.1354018) * go_2(0.0, 1.0);
|
||||
result += mat4(0.18950915, -0.034574565, -0.10378051, -0.15800652, -0.06835184, -0.06987467, 0.035007782, 0.04686656, 0.054061133, 0.014833506, -0.0035361175, 0.016156103, 0.120767444, -0.10196722, 0.10668838, -0.09058739) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.032248627, 0.056413256, 0.042716432, 0.06681831, 0.047605485, -0.07629479, 0.14311917, -0.06909803, 0.10640394, 0.10701861, -0.0051839007, -0.15133362, -0.32146424, -0.039978918, -0.12280021, 0.0048507582) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.1954503, -0.09257865, 0.11023244, -0.01817947, -0.0035485283, -0.015536726, 0.0071826433, 0.042538714, -0.015454641, 0.079593316, -0.07242554, 0.031178504, 0.2319168, -0.10519467, 0.013837495, -0.040088437) * go_2(1.0, 1.0);
|
||||
result += mat4(0.12625901, 0.04531166, 0.038758352, -0.05790713, -0.10029771, -0.118265375, -0.23944628, 0.11955388, 0.070732996, 0.19404806, -0.019913414, 0.04609079, 0.06262817, 0.022330387, -0.029681094, 0.03719176) * go_3(-1.0, -1.0);
|
||||
result += mat4(-0.07737922, 0.0024623116, -0.037666153, -0.19271135, -0.015002153, -0.0059966356, 0.0024538909, -0.0401021, -0.18540399, -0.11140236, -0.11102473, -0.06390247, 0.016754225, 0.35000673, -0.19139731, 0.07363001) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.02150171, -0.2311761, -0.025124706, 0.16819553, -0.0013348719, 0.32091036, -0.061826598, 0.12579474, -0.036611024, -0.018266583, -0.11280143, 0.11073158, 0.050171874, -0.14706045, 0.029553955, 0.0052631944) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.19249865, -0.22854832, 0.09472751, 0.014705341, 0.059496958, 0.13427268, -0.06309558, -0.07153743, -0.31890163, -0.0657967, -0.040345218, 0.09544393, 0.07359761, 0.11245483, 0.00033233972, 0.031550154) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.24668917, -0.37181908, -0.50614715, -0.101197146, -0.1569055, 0.27734125, 0.17144768, -0.04336267, 0.03658949, 0.06747124, 0.30720958, 0.56301194, -0.11314631, -0.29258573, 0.16256689, 0.5221001) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.022761503, 0.13063031, 0.002526217, -0.03466151, -0.15225072, 0.40217137, -0.089131154, 0.19195192, -0.1379853, -0.04640692, 0.104670234, 0.12268618, -0.012009209, -0.20534724, 0.028777445, 0.22195113) * go_3(0.0, 1.0);
|
||||
result += mat4(0.23697586, 0.08793654, -0.10565018, 0.013993297, -0.025932996, -0.13859354, 0.14333159, -0.099132575, -0.049601994, -0.0917448, -0.0021633878, -0.009032609, -0.034750953, -0.30761167, 0.058994945, -0.19427797) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.26944515, 0.30523893, -0.17787015, 0.10827742, 0.06457236, -0.12202401, 0.15371302, 0.011699893, -0.06253491, -0.10976804, -0.37283847, -0.23996784, -0.2750512, -0.024101513, -0.094127975, -0.17462716) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.026286924, 0.06250577, 0.095423855, -0.02849258, -0.12916361, -0.10954709, -0.05825132, -0.102924265, -0.19550376, -0.11730307, 0.032346163, -0.17682706, 0.16651174, 0.031927045, -0.004800601, -0.06323844) * go_3(1.0, 1.0);
|
||||
result += vec4(0.0095873345, 0.04959374, -0.15246227, 0.0044831373);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!SAVE conv2d_5_tf1
|
||||
//!WIDTH conv2d_4_tf.w
|
||||
//!HEIGHT conv2d_4_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_4_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_4_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.021453971, -0.108874515, 0.0005208881, -0.09774453, -0.0053757126, 0.20114918, 0.24454592, 0.04932251, -0.0037210248, -0.0240578, -0.07736935, 0.27604944, -0.12430849, -0.13093218, -0.014840212, 0.13450128) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.19143668, -0.23023333, -0.10232715, 0.24396868, 0.056112397, 0.14535592, -0.25882182, -0.26274678, -0.23119931, 0.07735849, -0.14785223, -0.21026523, -0.2064457, -0.34512606, -0.17808662, 0.30146623) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.0072161015, -0.013303738, 0.07591899, 0.027883789, 0.210858, 0.1422139, -0.027882019, 0.2618474, -0.048504543, 0.07377317, -0.05427271, -0.10014041, -0.12974857, -0.13140713, -0.02249253, 0.08203184) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.07855138, -0.13984342, 0.10037151, -0.056781758, 0.24686107, -0.0048190085, -0.2693424, 0.31722167, -0.28716075, -0.06422215, -0.06738793, -0.06723655, -0.08194382, -0.007975044, 0.20108353, -0.13338897) * go_0(0.0, -1.0);
|
||||
result += mat4(0.35129568, 0.27930936, 0.024239251, -0.10712293, 0.48684034, -0.04380574, -0.0064479653, 0.03754327, -0.13139078, -0.44939983, -1.0460628, -0.016004754, -0.14476573, -0.07113434, 0.515311, -0.400374) * go_0(0.0, 0.0);
|
||||
result += mat4(0.13104302, -0.23410062, 0.091530964, -0.003652217, 0.16696814, 0.16406855, -0.08138474, 0.047526445, 0.25358474, 0.37850454, 0.0362802, -0.046476766, -0.093869686, -0.4143772, 0.08641024, 0.115896136) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.04416574, -0.052188106, 0.05141859, -0.008132604, -0.013658864, 0.1021097, 0.19391364, -0.09257973, 0.15225394, -0.16920799, -0.16172324, 0.41466942, -0.07087308, 0.08632938, -0.07496043, -0.023530172) * go_0(1.0, -1.0);
|
||||
result += mat4(0.09337352, 0.062108494, -0.219173, -0.046151914, 0.22507025, -0.08966131, -0.123690315, 0.08666376, -0.10731867, -0.08518657, 0.024199447, 0.17898631, 0.120247275, 0.089923285, -0.08756211, 0.1775775) * go_0(1.0, 0.0);
|
||||
result += mat4(0.20326594, -0.060535498, -0.061659336, 0.113954924, -0.073462196, 0.15917051, 0.11728326, -0.072256014, -0.0752342, 0.06265616, -0.19494365, -0.25413772, -0.06641352, -0.015642308, 0.16825356, 0.0027654327) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.17029639, -0.05388927, -0.13159063, 0.0795609, 0.00501164, -0.0703107, -0.08229201, 0.07546247, 0.092942156, 0.059050936, -0.07987315, 0.010874322, 0.037708692, -0.0017377702, -0.030414931, 0.28946167) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.2692667, 0.2258295, 0.062060453, 0.1934921, -0.023051793, -0.038611185, 0.21473692, 0.33520013, 0.029885106, 0.103782356, 0.05217351, -0.13349791, -0.034186684, -0.3015818, 0.033423528, 0.21218027) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.013587494, 0.021273775, -0.022650799, -0.011939531, -0.11202949, 0.09365859, -0.042938907, -0.009910716, 0.27254924, 0.07752608, 0.029586637, 0.024899973, 0.04375618, 0.31453863, -0.006775175, 0.008228053) * go_1(-1.0, 1.0);
|
||||
result += mat4(-0.49562672, -0.12472124, -0.13618441, 0.09660054, -0.2275429, -0.0902811, 0.18311924, 0.11677185, -0.13325182, -0.061613016, -0.011462703, -0.12538978, 0.054934092, 0.06742866, 0.25515345, 0.35692096) * go_1(0.0, -1.0);
|
||||
result += mat4(0.5266911, -0.09655596, -0.41069564, -0.3174325, 0.1431904, -0.17732115, -0.36320353, 0.37975433, -0.5158582, -0.21019879, 0.06852925, -0.06648648, -0.18956456, -0.018139647, 0.35707653, 0.07378416) * go_1(0.0, 0.0);
|
||||
result += mat4(0.04151976, -0.037361674, 0.06936584, -0.10462262, -0.22264048, -0.043842267, -0.12742832, -0.21778631, 0.0715335, -0.17921853, -0.3856251, -0.16335362, 0.21045755, -0.5026229, 0.14405337, 0.23096423) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.32437655, 0.07860345, -0.0021187086, 0.123870686, -0.16616751, 0.11004699, 0.04754715, -0.0075211064, -0.08026408, 0.04284957, -0.018143758, 0.032623176, 0.06614686, -0.035856936, 0.13667971, -0.15696613) * go_1(1.0, -1.0);
|
||||
result += mat4(0.11260625, 0.03274457, -0.033769324, -0.11558525, -0.35377702, 0.0019119612, 0.24906515, -0.06853208, 0.0009843144, -0.0050376705, 0.063123666, 0.009872904, 0.19592324, 0.0028321196, -0.114693984, 0.16404222) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.03699667, 0.011842293, -0.12273219, 0.04081692, 0.008484447, -0.052331816, 0.07151068, 0.018538639, 0.077749036, 0.07189092, 0.22443593, -0.2436085, 0.023654116, -0.05127411, 0.27350748, 0.12180999) * go_1(1.0, 1.0);
|
||||
result += mat4(0.16090482, 0.059198547, 0.04856637, -0.19173436, 0.12747662, -0.079715036, -0.20203276, -0.13818277, -0.123076215, -0.07168488, 0.0644838, 0.03524764, 0.0005124138, -0.06789178, 0.048645556, -0.098922126) * go_2(-1.0, -1.0);
|
||||
result += mat4(0.29220074, 0.25197285, 0.09825887, 0.030363245, -0.033246458, -0.08370418, -0.12231589, -0.023000835, 0.082732, -0.16907515, -0.052518822, 0.07991363, 0.06222654, -0.06747275, -0.18931144, -0.42009747) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.02667354, 0.03842717, -0.012755562, 0.061840586, 0.01060547, -0.29081437, 0.010907111, 0.07930905, 0.12273201, 0.017574295, 0.051024225, 0.019036688, 0.07671181, 0.049130872, -0.09734168, -0.070569195) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.08517651, 0.0767222, -0.15657257, 0.18501835, -0.13749431, -0.2833894, 0.109219365, 0.033763003, 0.18988928, 0.13461404, -0.036578514, -0.13256857, -0.097819485, -0.17316358, -0.06512401, 0.1937444) * go_2(0.0, -1.0);
|
||||
result += mat4(-0.32173568, -0.072075866, 0.13004705, -0.15507852, -0.23741087, -0.29364398, 0.10723945, -0.11976219, 0.20620506, 0.17970093, 0.24463713, -0.12555319, -0.021192182, -0.1374317, 0.5359718, 0.59974134) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.01101575, 0.040466793, -0.009630791, 0.13422947, -0.13290837, -0.24789505, -0.061713737, -0.07838521, 0.05379315, -0.14643523, -0.09155805, -0.049997047, 0.06696885, 0.20043123, -0.07542329, -0.08041673) * go_2(0.0, 1.0);
|
||||
result += mat4(0.022160506, 0.01611432, -0.10189221, -0.022767285, -0.06682965, 0.047138248, 0.06860934, -0.012574086, 0.04010214, -0.041280016, -0.034621384, -0.018262599, 0.09731754, -0.059062295, 0.14786182, -0.15185094) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.052484483, 0.06899427, 0.18380043, -0.058414727, 0.07685985, -0.07206598, -0.101362616, -0.012002652, 0.008517392, 0.079471916, -0.30394664, 0.028600946, -0.03270232, -0.23564856, 0.045065008, -0.0034684737) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.049757, 0.07614825, 0.16394803, 0.027053174, 0.0451278, -0.09351286, -0.0042182617, 0.12332257, -0.025281021, -0.03843008, 0.12857373, -0.07611989, -0.0062898803, 0.022618141, -0.13122174, -0.03328411) * go_2(1.0, 1.0);
|
||||
result += mat4(0.12251631, 0.047008447, 0.027589995, -0.12207328, -0.1510795, 0.06724553, 0.17066906, 0.16992114, -0.0026905634, -0.035480864, 0.033738773, 0.018674552, 0.028614907, -0.019945908, -0.0156899, -0.09562145) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.116588935, 0.14205505, 0.099545434, -0.045527786, -0.049273346, 0.20760757, 0.053965498, -0.12198069, -0.14654607, 0.041820496, 0.038068503, 0.24565905, 0.09786504, 0.18309233, 0.23802327, -0.085740186) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.1262052, -0.011846116, -0.058820397, -0.019373653, -0.09569547, -0.08265971, -0.05178388, -0.020502446, -0.17525336, -0.22874829, 0.0075891856, -0.189923, 0.09809122, 0.109637566, -0.0005973885, -0.06477921) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.28209856, 0.11276813, 0.054377034, -0.00891202, -0.095922634, 0.071109876, -0.039932176, -0.047409832, -0.06504704, 0.11923986, 0.0013364811, -0.122095086, -0.20282102, -0.022717483, -0.115474045, 0.020858249) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.16130303, 0.072821185, -0.021358958, -0.11687897, -0.15543966, 0.05783285, 0.10317231, -0.12240756, 0.053357504, -0.090291016, -0.21943556, 0.46947235, 0.19072579, 0.017349033, -0.55443907, -0.10510661) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.4155687, 0.019206723, -0.20055711, 0.028732464, -0.1981807, 0.20637372, 0.03305817, -0.17949893, -0.21051097, 0.21483344, 0.0061496794, -0.48980987, -0.26750582, 0.09230394, -0.117223755, -0.07636286) * go_3(0.0, 1.0);
|
||||
result += mat4(0.20611528, -0.00095511036, -0.21555157, -0.07065484, 0.06880411, 0.068082534, -0.10104979, 0.16050354, -0.07437897, -0.13145325, -0.017651044, 0.055096775, -0.05443345, -0.018634815, -0.011232755, -0.10835) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.2637829, 0.07681072, 0.015995527, 0.004554211, 0.07495561, 0.18873464, -0.14303622, 0.25786543, -0.14117226, -0.008715274, -0.17176823, -0.0006595096, -0.06566383, -0.19184378, -0.18945406, 0.20968987) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.03293623, 0.003399063, 0.08051177, -0.0072856937, -0.07375858, 0.075319655, -0.10791501, -0.002204552, -0.093564905, -0.122712255, -0.10658267, -0.015067637, -0.033247817, 0.09952069, -0.13724248, 0.068189256) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.001935585, 0.05018077, -0.0154469935, -0.034524206);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!SAVE conv2d_6_tf
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.0053346683, 0.010174534, -0.050979972, -0.06134544, -0.007238652, -0.012790015, 0.036398683, -0.09181499, 0.11328388, -0.14236617, -0.17519625, -0.34661606, 0.008069393, -0.028871074, -0.02980949, -0.0853359) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.05187267, -0.09381704, 0.035209883, 0.29482442, -0.0018002815, -0.029504262, 0.2609028, -0.09480671, -0.0737553, -0.070559524, 0.081991084, 0.1513024, 0.048344653, -0.09336617, 0.0034569732, 0.10530542) * go_0(-1.0, 0.0);
|
||||
result += mat4(-0.06749591, 0.0065624053, 0.013237342, 0.14225115, 0.27183163, -0.15656447, 0.031672053, 0.009592649, -0.0202286, 0.26220062, 0.19387855, -0.18505628, 0.040554795, 0.07295961, -0.13291295, -0.12600344) * go_0(-1.0, 1.0);
|
||||
result += mat4(0.039192002, 0.0846215, -0.06593224, 0.28147796, 0.06301313, 0.26323164, -0.16742979, 0.22004774, -0.17470881, 0.060716614, 0.15430811, 0.18970133, 0.08858931, -0.027321626, -0.037833836, 0.07344837) * go_0(0.0, -1.0);
|
||||
result += mat4(0.0633813, 0.35046157, -0.101075254, 0.015974075, 0.19010352, -0.7135035, -0.24324696, -0.42072615, 0.06825536, -0.052808974, 0.28965715, -0.0015640302, -0.27062586, 0.4279925, 0.035623744, 0.46321228) * go_0(0.0, 0.0);
|
||||
result += mat4(0.02639867, 0.26469797, -0.09086266, 0.07440796, -0.192054, 0.1010368, -0.04398074, 0.056824226, -0.27057743, -0.20455118, 0.19338831, -0.21843775, 0.20736177, -0.26259273, -0.07667085, -0.19504389) * go_0(0.0, 1.0);
|
||||
result += mat4(-0.007056104, 0.04284205, 0.01933733, 0.07267832, 0.0012616975, -0.30140647, -0.019223223, -0.046687007, -0.037844718, -0.014929125, 0.022630794, 0.046716493, 0.057279173, -0.08055539, -0.027891241, 0.019557232) * go_0(1.0, -1.0);
|
||||
result += mat4(0.035518404, -0.10087327, 0.0011048123, -0.123707846, 0.37190285, 0.43751532, -0.022599256, -0.041709043, 0.11357196, -0.029839104, -0.056960747, -0.17228557, 0.08558022, 0.046361133, 0.021548864, 0.24297418) * go_0(1.0, 0.0);
|
||||
result += mat4(-0.043598346, -0.09812348, 0.056599542, -0.09833163, -0.07193007, 0.015760094, -0.053177495, -0.015448543, 0.035163186, -0.03889347, 0.121799015, 0.15738566, -0.115644835, 0.043310717, 0.060173217, -0.059635755) * go_0(1.0, 1.0);
|
||||
result += mat4(-0.111604795, 0.1678389, 0.049967546, 0.045353863, -0.013896185, 0.035128903, 0.040686198, -0.16442506, 0.1149577, -0.14343217, -0.08858, 0.02656137, 0.059526477, -0.13914491, 0.12757027, 0.034920372) * go_1(-1.0, -1.0);
|
||||
result += mat4(0.15849945, 0.12067003, -0.1579611, 0.30790725, -0.041249942, 0.03948043, -0.12535375, -0.02566875, 0.3150059, 0.027081972, -0.026308673, -0.25326517, 0.016824603, -0.13551097, 0.1412756, 0.037750524) * go_1(-1.0, 0.0);
|
||||
result += mat4(0.1562541, -0.041948073, -0.14951487, 0.119380556, -0.21773878, -0.019281754, 0.08185942, 0.09982689, 0.017187534, -0.18181366, -0.09270861, 0.08527679, 0.051988564, 0.08686172, -0.12665209, -0.07205808) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.08860466, -0.17931758, 0.10191625, -0.47623265, 0.1562338, -0.2960855, 0.013664795, 0.29452285, 0.1463958, 0.17562817, -0.41623253, -0.196999, -0.049113005, 0.0556021, 0.054452494, 0.14073615) * go_1(0.0, -1.0);
|
||||
result += mat4(-0.5345973, -0.069205046, 0.37001884, 0.6955835, 0.22635284, -0.09021557, -0.04693607, -0.4458824, 0.25049326, -0.06503396, 0.07584689, 0.5394811, 0.33387923, -0.010540017, 0.038980547, -0.13371105) * go_1(0.0, 0.0);
|
||||
result += mat4(-0.04414677, -0.22056313, 0.05580458, 0.11914465, 0.19864987, -0.1025625, -0.010050287, 0.15919746, -0.40589634, 0.4966349, -0.47632688, -0.022637444, 0.17247641, -0.51093113, 0.21157944, -0.2890017) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.034673482, -0.0075900992, -0.061077584, -0.03859898, 0.32444152, -0.14619137, -0.1375446, -0.030322462, 0.029679669, 0.079344586, -0.03862258, -0.05766807, 0.104488336, 0.006179548, -0.1168102, 0.069729604) * go_1(1.0, -1.0);
|
||||
result += mat4(0.08504003, 0.042162962, -0.17509954, -0.06258286, -0.45796555, -0.061748773, 0.25438437, -0.02988987, -0.06897794, 0.105180845, -0.08879189, -0.120605074, -0.1478659, -0.13201937, -0.01755498, 0.020606143) * go_1(1.0, 0.0);
|
||||
result += mat4(0.08932581, 0.1453785, -0.12802933, 0.049442187, 0.045360584, 0.16079827, -0.14142223, 0.10168491, 0.20244479, -0.17981426, 0.19759466, 0.05217847, 0.04889828, 0.06941533, -0.111836776, -0.08046399) * go_1(1.0, 1.0);
|
||||
result += mat4(-0.011953735, 0.11362504, -0.122588776, -0.10408559, 0.051712614, -0.05161036, -0.068698496, -0.015663281, -0.06346889, 0.06561636, 0.03783044, 0.02756004, -0.036310352, -0.16962235, -0.062494226, 0.0069608325) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.16857432, -0.17322211, 0.15971284, 0.19980437, -0.007965961, -0.015480705, 0.036090557, 0.07414387, -0.2941106, -0.24430539, 0.01070864, 0.22401866, -0.34321144, 0.09537491, -0.08020218, 0.45404655) * go_2(-1.0, 0.0);
|
||||
result += mat4(-0.021609096, -0.11348408, -0.01450652, -0.063170746, 0.06990935, -0.035983834, -0.038010992, -0.10578655, 0.29232737, 0.048835874, 0.054028947, -0.12924139, -0.03058583, 0.028469706, 0.09563202, 0.085674495) * go_2(-1.0, 1.0);
|
||||
result += mat4(-0.01894022, 0.037628658, -0.102314636, -0.28041583, 0.07495663, -0.058895253, 0.16422969, -0.07163792, 0.039416216, -0.13800906, -0.039811566, -0.10612402, -0.047593113, -0.28491783, 0.41632858, 0.15253194) * go_2(0.0, -1.0);
|
||||
result += mat4(0.26240867, -0.05335849, -0.014135048, 0.055749495, -0.020126658, 0.2952794, -0.015241771, 0.36143306, 0.43075684, 0.1921996, -0.4329065, 0.5114495, 0.7326109, -0.054901246, -0.076693356, -0.26104695) * go_2(0.0, 0.0);
|
||||
result += mat4(0.14548428, 0.14578429, 0.17193514, -0.07973242, 0.011952286, -0.047767498, 0.025101405, 0.0016503566, -0.26948047, -0.16503395, -0.061791085, 0.030557185, 0.15400517, -0.054951698, -0.14611247, 0.3550633) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.05926111, -0.083442695, 0.046579204, -0.017723244, 0.12846185, 0.018434443, -0.17914511, -0.077696435, 0.060048338, 0.02956987, -0.11914462, 0.057770032, -0.054673657, -0.005353606, -0.39014184, 0.08306877) * go_2(1.0, -1.0);
|
||||
result += mat4(0.07357362, 0.23051825, -0.22640751, 0.080715515, -0.14467078, 0.009734264, 0.054320686, 0.24534328, -0.16038458, 0.06575425, 0.058553413, 0.17755087, 0.08184439, 0.17078212, 0.148369, -0.09309279) * go_2(1.0, 0.0);
|
||||
result += mat4(-0.11160211, -0.07590204, -0.01676188, -0.062253337, 0.016433533, 0.0146132, -0.040350936, 0.06749202, -0.031521842, 0.1441664, -0.09916073, 0.050578352, -0.06560962, -0.31174552, 0.056873083, -0.077912) * go_2(1.0, 1.0);
|
||||
result += mat4(0.09344025, 0.075936995, -0.1627903, -0.04781558, -0.01878236, 0.045879602, -0.11507387, -0.025356822, -0.09113391, 0.07263937, 0.08232447, 0.08727616, -0.024921807, 0.051639438, 0.006532631, -0.018751068) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.022455849, -0.12924309, 0.26318657, -0.32464805, -0.09627585, 0.04496843, -0.09630052, -0.025761643, -0.090804085, 0.24410398, -0.03162944, -0.1961483, 0.14065808, -0.064709485, -0.0040163463, 0.05445074) * go_3(-1.0, 0.0);
|
||||
result += mat4(-0.020935195, -0.1028065, 0.0012804621, 0.02302866, -0.00924972, -0.0041193594, 0.0060590385, -0.003394384, -0.23241943, -0.023235107, 0.08077456, 0.15720141, 0.06568382, -0.09971436, 0.09056065, 0.04271102) * go_3(-1.0, 1.0);
|
||||
result += mat4(-0.20997737, -0.12892777, 0.4658528, 0.13622813, -0.2867294, -0.09359254, 0.18821026, 0.25550604, -0.18562363, 0.080713026, 0.13463654, 0.045504905, -0.013133853, -0.1316404, 0.08379897, -0.00047142128) * go_3(0.0, -1.0);
|
||||
result += mat4(0.3276134, 0.21952826, -0.80777377, -0.69810224, 0.34190908, -0.09293263, 0.33313555, -0.27255502, -0.24287084, -0.07741488, 0.06090265, -0.10161252, -0.37684909, 0.4678029, 0.13506591, 0.42470258) * go_3(0.0, 0.0);
|
||||
result += mat4(0.080790855, -0.09707547, -0.05506975, 0.027011644, -0.1434346, 0.01363872, 0.12616752, 0.16789167, 0.1656414, -0.11586835, 0.059612263, -0.074029386, -0.19813071, 0.46032718, -0.03935981, 0.0067143585) * go_3(0.0, 1.0);
|
||||
result += mat4(0.10322512, 0.0822636, -0.16766444, 0.041008063, -0.027768405, 0.23103505, 0.06737122, 0.15258405, 0.04557388, -0.18179403, 0.12489025, -0.09759324, -0.05925805, 0.04869987, 0.07329833, -0.09738542) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.10823879, -0.403376, 0.3264802, -0.16503738, -0.057512645, -0.20902547, -0.14862378, -0.3192005, -0.046263676, 0.12744917, -0.019174274, -0.02318789, -0.085088454, -0.05723332, 0.0039772973, 0.07991316) * go_3(1.0, 0.0);
|
||||
result += mat4(0.10313916, 0.04410904, 0.03286652, 0.059946325, 0.019948404, 0.070217304, -0.017572487, 0.20332281, 0.06776308, 0.029285522, -0.14116238, -0.05864782, -0.18382367, -0.06568212, 0.11855615, 0.101256005) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.036374483, 0.029420665, 0.04437756, -0.04474691);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x3x3x16
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!SAVE conv2d_6_tf1
|
||||
//!WIDTH conv2d_5_tf.w
|
||||
//!HEIGHT conv2d_5_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define go_0(x_off, y_off) (max((conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_1(x_off, y_off) (max((conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_2(x_off, y_off) (max(-(conv2d_5_tf_texOff(vec2(x_off, y_off))), 0.0))
|
||||
#define go_3(x_off, y_off) (max(-(conv2d_5_tf1_texOff(vec2(x_off, y_off))), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.059325468, 0.10884231, 0.018158086, 0.031802185, 0.10368743, -0.06776637, 0.048326045, -0.06312353, -0.0025675546, 0.09309577, -0.025533969, 0.029684044, 0.017237723, 0.062099144, 0.047039766, 0.050348036) * go_0(-1.0, -1.0);
|
||||
result += mat4(-0.04767078, -0.06409279, 0.112965874, 0.04621161, -0.28172916, -0.13897015, -0.022806352, 0.26966885, 0.02019569, -0.10707113, -0.43058416, -0.14103983, -0.13225646, -0.020053176, -0.17319782, -0.009653082) * go_0(-1.0, 0.0);
|
||||
result += mat4(0.0031349238, -0.060933832, 0.107986666, -0.019791966, -0.23946726, -0.18045186, 0.18286318, -0.05431065, 0.11742379, -0.019123906, 0.33327517, 0.07455424, -0.035427105, 0.18659347, -0.050884776, 0.019193258) * go_0(-1.0, 1.0);
|
||||
result += mat4(-0.22954239, 0.011265787, -0.026520751, -0.12629737, -0.07009803, 0.44925988, -0.15938939, 0.11956771, 0.11535644, -0.1302371, 0.1235775, 0.16483483, 0.022965495, 0.110546246, 0.00064579415, -0.12753843) * go_0(0.0, -1.0);
|
||||
result += mat4(0.047553673, 0.16213869, 0.7510964, 0.21228868, 0.40994287, 0.61919236, 0.3982374, -0.016163021, 0.3291035, 0.1134356, 0.12384387, -0.31114763, 0.21338554, -0.04721641, 0.122114286, 0.2717476) * go_0(0.0, 0.0);
|
||||
result += mat4(-0.06529201, -0.08936482, 0.031857736, -0.02372691, 0.0416097, 0.28484538, -0.38181338, -0.05129518, 0.40150553, -0.01970737, 0.1043854, 0.11986372, -0.2267319, 0.0014845231, -0.035269983, 0.11712099) * go_0(0.0, 1.0);
|
||||
result += mat4(0.079867415, -0.09982735, 0.10313241, 0.055490237, -0.42685422, -0.3431141, -0.06037366, 0.17539841, -0.010511819, -0.09743252, 0.050748866, 0.11064108, -0.09785722, -0.10230299, -0.04106169, -0.016831731) * go_0(1.0, -1.0);
|
||||
result += mat4(-0.06847075, -0.026447225, -0.123430386, 0.063637204, -0.37617612, -0.09615662, -0.26226708, -0.008175561, -0.08101131, 0.11093525, -0.13149206, -0.06363292, -0.0482858, -0.2771799, 0.10528571, 0.119109035) * go_0(1.0, 0.0);
|
||||
result += mat4(0.09151277, 0.029019276, 0.041349206, -0.011239478, 0.035083957, 0.05281079, -0.0742173, -0.018509442, -0.17175299, -0.4226507, -0.118186444, -0.0771296, 0.107038856, 0.0819975, 0.12445646, 0.07091557) * go_0(1.0, 1.0);
|
||||
result += mat4(0.1275357, -0.097659886, -0.0114354445, 0.023900568, -0.02511702, 0.005830569, -0.010882143, -0.04046068, -0.08638482, 0.08664022, -0.15654318, 0.03333846, -0.12521335, -0.11987078, 0.028556254, -0.020760164) * go_1(-1.0, -1.0);
|
||||
result += mat4(-0.38474286, -0.15288061, 0.04925842, 0.050009686, 0.23555282, 0.054784663, -0.0971203, 0.017791113, -0.35539824, -0.08806168, 0.08992579, 0.22714761, -0.047685623, -0.17510797, 0.1137738, -0.069451034) * go_1(-1.0, 0.0);
|
||||
result += mat4(-0.16623408, -0.08202571, -0.03291826, 0.0016267949, 0.20682698, 0.08788948, 0.10241089, 0.019209227, -0.14802241, 0.091788374, -0.238735, -0.06633396, 0.02360112, 0.1521805, -0.022510838, -0.08931379) * go_1(-1.0, 1.0);
|
||||
result += mat4(0.034280665, -0.12431295, 0.092791, 0.15279225, -0.43373865, 0.20077267, -0.15919733, -0.27969292, -0.26948065, 0.19652127, -0.27456176, 0.04137772, 0.006545539, 0.0031402514, 0.03849979, -0.10978278) * go_1(0.0, -1.0);
|
||||
result += mat4(0.62025917, -0.32462567, 0.2817292, -0.18380783, -0.3338593, -0.49056754, 0.32645953, 0.4146035, 0.3773462, 0.54346967, -0.032203436, -0.14506778, -0.30044907, 0.40134314, 0.24155408, 0.24397472) * go_1(0.0, 0.0);
|
||||
result += mat4(0.089335114, -0.05529855, -0.18364899, -0.153323, -0.18347202, -0.060125064, -0.29216367, -0.2717291, 0.10592963, 0.38889876, 0.25363386, 0.33723134, -0.103703365, 0.14922962, -0.21206948, -0.20289616) * go_1(0.0, 1.0);
|
||||
result += mat4(-0.035760924, 0.18820894, -0.12723185, -0.018780319, 0.124459654, 0.28909087, -0.2763883, -0.45110545, 0.098143585, 0.16052029, -0.055098705, -0.14840914, -0.0019514654, 0.07090622, -0.055036955, -0.0035953245) * go_1(1.0, -1.0);
|
||||
result += mat4(-0.124669634, 0.23131305, -0.05750295, -0.056296032, 0.35691026, 0.2640789, 0.49912274, 0.26795143, -0.26460487, -0.026896512, -0.07179325, 0.17373477, -0.13186656, 0.0021319336, -0.016407885, 0.3014283) * go_1(1.0, 0.0);
|
||||
result += mat4(-0.09491939, 0.11503968, -0.14077829, -0.043197304, -0.061866064, -0.1574549, 0.0054375776, 0.066160634, -0.17686372, -0.26767558, -0.038844116, 0.122724466, -0.05043839, 0.063884266, 0.0064002997, -0.13583377) * go_1(1.0, 1.0);
|
||||
result += mat4(0.031301867, -0.02947819, -0.0016769855, 0.12952408, -0.025022922, 0.065425046, -0.072289295, -0.071249105, 0.14579567, -0.09058119, 0.12663712, 0.1515388, 0.44767743, 0.02971349, 0.015892735, -0.08058422) * go_2(-1.0, -1.0);
|
||||
result += mat4(-0.2868111, -0.10812653, -0.29182926, -0.38444322, -0.0875354, -0.07220258, 0.05978065, 0.093328245, 0.058548283, -0.013913258, -0.20954674, -0.16400063, 0.3185215, 0.068897314, 0.15869021, 0.022877626) * go_2(-1.0, 0.0);
|
||||
result += mat4(0.116845705, -0.12729645, 0.056697316, -0.21263942, -0.07000074, 0.073977455, -0.09006404, -0.029770354, -0.20823102, -0.20088868, 0.15658094, 0.24306639, -0.0453592, -0.16011035, 0.08521533, -0.032264974) * go_2(-1.0, 1.0);
|
||||
result += mat4(0.1114789, -0.1083731, 0.10465276, -0.08903837, -0.06455987, 0.040030345, -0.07937248, -0.20654759, -0.26873547, -0.19390975, -0.039021965, -0.025602374, -0.5575801, -0.08876011, -0.19116728, -0.2401055) * go_2(0.0, -1.0);
|
||||
result += mat4(0.37626424, -0.0912155, -0.6153361, -0.71465075, 0.018208932, -0.14997734, 0.23627761, 0.20832567, 0.07427123, -0.37869486, -0.26574427, 0.187582, -0.37201726, 0.17809474, -0.02568795, 0.23900814) * go_2(0.0, 0.0);
|
||||
result += mat4(-0.085337594, -0.50634587, 0.30636734, -0.2760558, 0.01893911, -0.08425695, -0.023656169, 0.021421626, 0.16813251, -0.039550815, 0.21165498, -0.027628547, -0.123874225, 0.013802332, -0.2732087, -0.09419671) * go_2(0.0, 1.0);
|
||||
result += mat4(-0.07190724, -0.019237598, 0.020249542, 0.07541295, -0.03817686, 0.09266451, -0.12214172, -0.01344174, 0.03281797, 0.057655178, -0.059896503, 0.014948791, -0.13952477, 0.18810949, -0.19016883, 0.06842416) * go_2(1.0, -1.0);
|
||||
result += mat4(-0.13111524, 0.14539744, -0.10212538, -0.2169032, 0.13810973, -0.12576458, 0.124372825, 0.04992259, 0.21758182, -0.22160134, 0.24321079, 0.017698256, 0.39995426, 0.074034885, 0.120019354, -0.15522505) * go_2(1.0, 0.0);
|
||||
result += mat4(0.023914235, 0.1424257, 0.010302871, 0.15150794, -0.040021677, 0.015862139, 0.14459212, 0.08632827, 0.04257336, 0.055059638, 0.0030461506, 0.011985334, -0.049230937, 0.07851301, -0.05119983, -0.111701734) * go_2(1.0, 1.0);
|
||||
result += mat4(0.04485158, 0.116597414, 0.00014909732, -0.012128512, 0.15801767, 0.18273115, -0.033926453, 0.05170487, -0.040683754, -0.18606974, 0.08324687, 0.069539666, 0.07098698, -0.014132968, 0.029499048, -0.07263477) * go_3(-1.0, -1.0);
|
||||
result += mat4(0.04309544, 0.089722805, -0.018306322, 0.29061043, 0.15191254, 0.15917647, 0.0073858183, 0.039199475, 0.42514518, -0.053955313, 0.10820046, -0.09134685, -0.3087313, -0.16339037, -0.05226669, 0.044995327) * go_3(-1.0, 0.0);
|
||||
result += mat4(0.008636428, 0.029086163, -0.09151674, -0.36466715, -0.0128008155, 0.018820466, -0.02700147, -0.0064047636, 0.28287655, 0.02709404, -0.05233492, -0.08967187, -0.042183813, -0.13990502, -0.005085154, -0.028511493) * go_3(-1.0, 1.0);
|
||||
result += mat4(0.00022532263, -0.09108507, 0.0089569865, 0.052016005, -0.19314727, -0.355347, 0.08082937, 0.2134498, 0.21036889, -0.10165983, 0.20334485, 0.14575538, 0.017676214, -0.13149881, -0.018741794, -0.019599862) * go_3(0.0, -1.0);
|
||||
result += mat4(-0.20513605, 0.47578803, -0.18631598, 0.2535432, -0.049522053, -0.37224755, 0.11227206, -0.37000927, 0.19969453, -0.47287735, -0.07506754, -0.0957071, 0.82927394, -0.54057014, 0.5800732, 0.08937558) * go_3(0.0, 0.0);
|
||||
result += mat4(-0.022189412, 0.14622113, -0.4772564, -0.31178755, 0.10667427, -0.07335338, 0.06144331, 0.00056827103, -0.08263861, -0.009126272, -0.22802618, -0.20760304, 0.12688845, -0.061324466, 0.33361357, 0.38350767) * go_3(0.0, 1.0);
|
||||
result += mat4(0.021188622, 0.1151918, -0.10654739, -0.03341855, 0.24870358, -0.06689332, 0.11881217, -0.0045951125, -0.039464932, -0.030190004, 0.014174111, -0.025356272, 0.07469406, -0.0059695644, 0.008267219, -0.0991054) * go_3(1.0, -1.0);
|
||||
result += mat4(-0.009981438, -0.36484948, 0.04801225, 0.22368562, -0.055985868, 0.229039, -0.10823553, 0.1477355, -0.0091677625, 0.06279847, 0.034393013, 0.031901076, 0.28783056, 0.086422645, 0.20860936, 0.054018307) * go_3(1.0, 0.0);
|
||||
result += mat4(-0.08720452, -0.07756267, 0.018853918, -0.014108689, -0.019337144, 0.021249043, -0.05633926, -0.109904505, -0.088990815, 0.16876367, -0.13149975, -0.054357648, 0.08588134, -0.10262266, 0.12052009, 0.05154292) * go_3(1.0, 1.0);
|
||||
result += vec4(-0.010602045, 0.053976092, 0.008913503, 0.0011945717);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x1x1x112
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!SAVE conv2d_last_tf
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define g_0 (max((conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_1 (max((conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_2 (max(-(conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_5 (max((conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_6 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_9 (max((conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_10 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_13 (max((conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_14 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_15 (max(-(conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_16 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_17 (max((conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_18 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_19 (max(-(conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_20 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_21 (max((conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_22 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_23 (max(-(conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_24 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_25 (max((conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
#define g_26 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_27 (max(-(conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.105475314, -0.07022547, -0.16326137, -0.12503424, -0.004623021, -0.0143323885, 0.042996034, 0.03422294, -0.38310882, -0.4431925, -0.28772846, -0.3213578, -0.018014904, 0.02429277, -0.07177951, -0.04458822) * g_0;
|
||||
result += mat4(-0.0973233, -0.032439478, -0.08420249, -0.054693196, 0.012960555, 0.06929602, 0.004247494, 0.061315402, -0.09607745, -0.16862066, 0.01537482, -0.038459156, 0.019662246, 0.059920583, -0.1071646, -0.06478967) * g_1;
|
||||
result += mat4(0.15711947, 0.0754732, 0.17891979, 0.098270796, 0.14122486, 0.14893766, 0.12408279, 0.14845194, 0.16199848, 0.14090912, 0.13496809, 0.1119815, 0.03974558, -0.057513904, 0.09213575, -0.0012252429) * g_2;
|
||||
result += mat4(-0.011343602, -0.02488338, 0.07799659, 0.06503721, 0.06380687, 0.048929837, -0.05555838, -0.050519127, 0.14673206, 0.18085165, 0.07261422, 0.09738158, 0.07395791, 0.005573146, -0.05454926, -0.13565786) * g_3;
|
||||
result += mat4(-0.08591514, -0.05664865, 0.23980616, 0.24876402, 0.19052829, 0.011938714, 0.21487322, 0.058656186, 0.036630988, 0.14918756, 0.013127693, 0.13092093, -0.37889576, -0.4068804, -0.27258882, -0.30605716) * g_4;
|
||||
result += mat4(-0.25149816, -0.21979512, -0.24949454, -0.20483162, -0.10972783, -0.17315808, -0.08562763, -0.16086778, 0.044681527, 0.050807394, -0.019424994, -0.022418005, 0.10039492, -0.013666552, -0.22373566, -0.34493732) * g_5;
|
||||
result += mat4(0.1419155, 0.081392206, -0.18103191, -0.2122926, -0.1445937, -0.015969204, -0.12368782, -0.0044421684, -0.09534078, -0.14815839, -0.1052107, -0.16341865, 0.3050403, 0.34488317, 0.16171226, 0.18700944) * g_6;
|
||||
result += mat4(0.12444696, 0.08712589, 0.06266247, 0.031022022, 0.17707655, 0.24904409, 0.20961654, 0.2610619, -0.099262595, -0.06900819, -0.034567446, -0.020191457, -0.1468561, -0.04683958, 0.14910224, 0.244686) * g_7;
|
||||
result += mat4(-0.002428158, -0.012889509, 0.0006541127, -0.0058380975, 0.096147396, 0.07791617, 0.119144954, 0.11699654, -0.024602454, -0.07894611, -0.00021709128, -0.03979557, 0.0028512406, -0.015790012, 0.0082511455, 0.029357092) * g_8;
|
||||
result += mat4(-0.01410329, -0.004162405, -0.09005045, -0.07753674, 0.004509965, -0.024188736, 0.13799691, 0.10589621, -0.023018798, 0.0064198375, -0.103344224, -0.07463909, -0.060048997, -0.071094714, -0.13042289, -0.14482167) * g_9;
|
||||
result += mat4(-0.009015246, 0.01581748, -0.035448726, -0.012348933, -0.101627484, -0.05530413, -0.14063041, -0.121775225, 0.074719116, 0.033839386, 0.045573987, -0.006698053, 0.0015141299, 0.003634417, 0.017102007, 0.0074890694) * g_10;
|
||||
result += mat4(0.0042357175, 0.018735386, 0.058959343, 0.057424515, -0.021633089, -0.037194982, -0.14109972, -0.1506368, 0.004357002, -0.006871023, 0.05337361, 0.039684236, 0.087463334, 0.07772685, 0.12278512, 0.1224218) * g_11;
|
||||
result += mat4(0.018359886, 0.046934873, -0.008225237, 0.020650858, -0.03961538, -0.014779162, -0.04161338, -0.00953579, 0.0017313146, 0.0068857935, -0.0024282748, 0.0047545764, 0.02635904, 0.027336216, 0.02701322, 0.029939381) * g_12;
|
||||
result += mat4(-0.00067966996, 0.024480496, -0.015218739, -0.010472019, -0.03994461, -0.052318517, -0.04450191, -0.043226667, -0.03166469, -0.03799331, 0.015428865, -0.018422252, 0.00040845043, 0.03558268, -0.0099401595, -0.00054432114) * g_13;
|
||||
result += mat4(-0.0032104475, 0.019604867, -0.02486679, 0.002134673, 0.014368818, -0.0013395248, 0.017318068, 0.0021403218, -0.02198377, 0.010297547, -0.041619625, -0.02740482, -0.067249276, -0.03040953, -0.021304253, -0.009557115) * g_14;
|
||||
result += mat4(-0.019099236, -0.037010793, 0.013720462, 0.023708181, 0.016356282, -0.00028589502, -0.010570909, -0.009186907, 0.03493662, 0.055599142, -0.017043956, 0.004204044, -0.013573257, -0.013537684, 0.008151195, 0.0074913655) * g_15;
|
||||
result += mat4(0.009309031, -0.0014795153, 0.025114728, -0.0066442797, -0.012085473, -0.0030560147, 0.002144206, 0.0009732741, 0.022301642, -0.0091133695, 0.0011837826, -0.020275833, -0.021349607, -0.011693419, -0.018912962, -0.022418445) * g_16;
|
||||
result += mat4(-0.0045772395, 0.031085191, 0.01215795, 0.023887333, 0.023408212, 0.0005998807, 0.011254428, -0.004634461, 0.016601006, 0.046663348, 0.031117432, 0.04910873, -0.113230005, -0.035702843, -0.058746565, -0.053893737) * g_17;
|
||||
result += mat4(-0.020218112, 0.056803435, -0.0037077996, 0.05123925, -0.016713811, -0.05551032, -0.005916611, -0.037839632, -0.007671626, -0.009099201, -0.0010055836, 0.003332688, 0.020744357, 0.01957675, 0.057906736, 0.041446246) * g_18;
|
||||
result += mat4(0.022438819, 0.04616756, 0.035925094, 0.0639705, 0.0009332198, 0.020964272, -0.010805394, 0.031757344, 0.051255573, 0.032838948, 0.00055445684, -0.03195623, 0.04753827, 0.016436901, 0.04788274, 0.022093765) * g_19;
|
||||
result += mat4(0.03479086, 0.035946105, 0.04343359, 0.04015664, 0.06081792, 0.061758887, 0.10128842, 0.007471392, -0.027261607, -0.01290544, -0.029938918, -0.050834358, -0.015550162, 0.0072828676, -0.04580556, -0.029642029) * g_20;
|
||||
result += mat4(0.011150116, 0.029789668, -0.00354488, 0.045047592, -0.018265083, -0.020843878, 0.015457328, 0.0053232997, 0.0791804, -0.028661052, 0.079342775, -0.039631505, 0.14613943, 0.08323415, 0.049641483, 0.047863442) * g_21;
|
||||
result += mat4(-0.103034586, -0.107580125, 0.00044325445, 0.007830247, -0.017059505, 0.010152936, -0.02845979, -0.01841766, -0.10722863, -0.025262646, -0.07402096, -0.025055556, 0.0013303137, 0.12574737, -0.0161103, 0.06077798) * g_22;
|
||||
result += mat4(-0.0420636, -0.062703885, -0.06476972, -0.10516001, 0.018120673, 0.024305122, -0.013997766, 0.015815413, -0.06317691, -0.03968166, -0.054052643, -0.016300509, -0.08255892, -0.01612941, -0.04194852, -0.012637189) * g_23;
|
||||
result += mat4(0.042659573, -0.10762496, -0.077143244, 0.12583935, -0.022020226, -0.0042312425, -0.016734738, 0.027007964, -0.06609771, -0.056038737, -0.0058528963, 0.035508137, -0.019722374, -0.055094264, 0.010977759, -0.009833099) * g_24;
|
||||
result += mat4(0.063830875, -0.019885639, 0.055574782, 0.039456647, 0.01576898, -0.1389799, 0.063411795, -0.11600623, -0.013968303, -0.03318867, -0.06806915, -0.09373464, -0.022723546, -0.03329239, 0.014282872, 0.027576538) * g_25;
|
||||
result += mat4(-0.018100513, 0.06204485, 0.010761461, -0.045085587, 0.009286288, 0.02310671, 0.10633246, -0.090849996, 0.13112675, -0.01639808, 0.0022725316, -0.076779045, 0.11831251, 0.1460306, -0.10849466, -0.07749171) * g_26;
|
||||
result += mat4(-0.15850247, 0.118011266, -0.10121594, -0.007109052, 0.071873754, 0.06954878, 0.0377852, 0.044174008, -0.062925555, -0.01758927, 0.1416964, 0.17206357, -0.035632525, -0.04652215, 0.061932907, 0.034339) * g_27;
|
||||
result += vec4(-0.11952045, -0.10779418, -0.0626279, -0.042614873);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x1x1x112
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!SAVE conv2d_last_tf1
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define g_0 (max((conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_1 (max((conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_2 (max(-(conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_5 (max((conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_6 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_9 (max((conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_10 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_13 (max((conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_14 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_15 (max(-(conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_16 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_17 (max((conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_18 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_19 (max(-(conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_20 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_21 (max((conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_22 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_23 (max(-(conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_24 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_25 (max((conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
#define g_26 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_27 (max(-(conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(-0.009000901, -0.018048609, 0.013095594, 0.002321373, 0.0004716619, 0.00504148, -0.016826658, -0.014922383, 0.15059204, 0.16593806, 0.115392484, 0.12520894, 0.05049829, 0.060210057, 0.086421266, 0.07242362) * g_0;
|
||||
result += mat4(0.06268658, 0.030466434, 0.07876877, 0.04129863, 0.04142328, 0.009963961, 0.051785357, 0.012811113, 0.1295883, 0.139931, 0.07733839, 0.08014211, 0.07156476, 0.0342396, 0.051614303, 0.043559864) * g_1;
|
||||
result += mat4(0.00041542648, 0.016051646, -0.011512418, 0.013076814, 0.03734479, 0.02791584, 0.012426691, 0.022044811, -0.034128398, -0.027107332, -0.021998279, -0.012139807, -0.033177473, -0.016310865, -0.078221664, -0.041203145) * g_2;
|
||||
result += mat4(-0.008398536, -0.010332053, -0.050231732, -0.039691273, -0.042082537, -0.030281143, -0.014039778, -0.0020190612, -0.11956351, -0.13638765, -0.09794402, -0.10228069, -0.08344795, -0.07944541, -0.004189214, -0.028206991) * g_3;
|
||||
result += mat4(0.0002908945, -0.00831185, -0.06870294, -0.083311856, -0.024992501, 0.0038247898, -0.049389005, -0.020098582, -0.0135326125, -0.040408995, -0.012083491, -0.042174604, 0.16112538, 0.13720983, 0.13937058, 0.10870099) * g_4;
|
||||
result += mat4(0.078961425, 0.082619205, 0.06910667, 0.06579004, -0.0077012256, -0.00038692637, 0.00015553503, -0.012561662, 0.00053048285, -0.01461681, 0.02600344, 0.024862211, -0.06958201, -0.048246548, 0.058762506, 0.036662634) * g_5;
|
||||
result += mat4(-0.023527982, -0.0028001352, 0.047800142, 0.09616409, 0.049143843, 0.030836122, 0.057244994, 0.025672587, 0.027565151, 0.039868724, 0.045296676, 0.04623187, -0.124759234, -0.14106254, -0.06337279, -0.076839216) * g_6;
|
||||
result += mat4(-0.0911771, -0.064436875, -0.05308137, -0.022082496, -0.0040269364, 0.0014464161, -0.0029555515, 0.016098293, -0.026650434, -0.014081368, -0.06747348, -0.05481826, 0.097423114, 0.08620988, -0.01607732, -0.015440677) * g_7;
|
||||
result += mat4(-0.014001735, -0.015001655, -0.013250577, -0.009930805, 0.04885879, 0.07092224, 0.025783395, 0.03792237, -0.04332465, -0.06244993, -0.046748653, -0.07132349, -0.0053951666, -0.016514057, 0.023807624, 0.044013456) * g_8;
|
||||
result += mat4(-0.009097996, -0.016898679, -0.05043909, -0.063178614, -0.016210863, -0.02157998, -0.02654472, -0.042961173, 0.012103852, 0.019015301, 0.02492281, 0.03389976, 0.015276502, 0.009577683, 0.04132527, -0.00070621347) * g_9;
|
||||
result += mat4(-0.0057500796, 0.00728164, -0.003422421, 0.0038979584, -0.03127353, -0.019125199, -0.012988815, -0.031890683, 0.09352588, 0.019210607, 0.09824038, 0.016637104, 0.010692808, 0.022393884, 0.008312123, 0.014120716) * g_10;
|
||||
result += mat4(0.013895599, 0.023097904, 0.009370535, 0.014099512, 0.0124661345, -0.015076684, 0.03287286, 0.005912471, -0.03944815, -0.020340785, -0.06822037, -0.059383288, 0.03634978, 0.007832939, -0.007142306, -0.0061968984) * g_11;
|
||||
result += mat4(0.033002097, 0.0516016, -0.021056438, 0.005715988, -0.02223013, -0.007962324, -0.024417123, -0.0014790733, 0.002167189, 0.00043749413, -0.007284963, -0.0027283782, 0.026238248, 0.01756047, 0.008969755, 0.014201024) * g_12;
|
||||
result += mat4(0.011576685, 0.02087598, 0.0026766327, -0.0041780816, -0.05277701, -0.05412841, -0.05958835, -0.050426245, -0.00662945, -0.021645393, 0.03423904, -0.0064581474, -0.030403355, 0.018391011, -0.026089542, -0.0051510665) * g_13;
|
||||
result += mat4(-0.046202097, -0.0066081425, -0.03698851, 0.0034165455, -0.011859245, -0.020945566, -0.0028196946, -0.010053285, -0.011400397, 0.030595876, -0.018915813, 0.006780077, -0.060040582, -0.009586898, -0.004477886, 0.011279908) * g_14;
|
||||
result += mat4(-0.028692413, -0.032535568, 0.0017473884, 0.02207169, 0.0192618, 0.008956797, -0.0033381556, 0.006326402, 0.0169569, 0.041449737, -0.02611751, 0.0006410355, 0.006233776, 0.0008467914, 0.011884985, 0.009222136) * g_15;
|
||||
result += mat4(0.017076496, -0.0045380928, 0.03444613, -0.009804047, -0.004829834, -0.004889702, 0.0057807956, 0.0015014127, 0.03458368, -0.0035773432, -0.007769679, -0.032449644, -0.021396799, -0.017612215, -0.012764735, -0.025224172) * g_16;
|
||||
result += mat4(-0.011824532, 0.02335273, 0.00764845, 0.019215155, 0.022186808, 0.0066053392, 0.0071694753, -0.0036117272, 0.032144524, 0.05025988, 0.03982363, 0.052400436, -0.10555114, -0.03809396, -0.05334183, -0.05524487) * g_17;
|
||||
result += mat4(-0.024599254, 0.058805298, 0.00069874676, 0.06263439, -0.018460508, -0.053566024, -0.0022889362, -0.035818785, -0.0135854995, -0.015712813, 0.0012080368, 0.005957637, 0.009450094, 0.03186346, 0.059969924, 0.057706963) * g_18;
|
||||
result += mat4(0.026783831, 0.05475865, 0.027565574, 0.06032707, -0.0015639095, 0.024381682, -0.010199071, 0.037544634, 0.039889377, 0.03318851, -0.016529158, -0.0343188, 0.045666486, 0.021665907, 0.042189375, 0.02444145) * g_19;
|
||||
result += mat4(0.03791853, 0.043746054, 0.056224477, 0.05098111, 0.075256795, 0.074653305, 0.116220035, 0.01853866, -0.04133627, -0.009134169, -0.0420953, -0.05210053, -0.021748418, 0.004422131, -0.05422814, -0.035721727) * g_20;
|
||||
result += mat4(0.013814317, 0.03149986, -0.004971173, 0.04782029, -0.01693027, -0.017984565, 0.019328078, 0.008521426, 0.0845641, -0.027555496, 0.08150416, -0.04623306, 0.16494128, 0.09300831, 0.074097835, 0.0627848) * g_21;
|
||||
result += mat4(-0.10307174, -0.112654425, -0.005589254, -0.0062108496, -0.012491583, 0.011512013, -0.03142282, -0.023683488, -0.099848576, -0.031290524, -0.07236223, -0.037460987, 0.008760208, 0.1473594, -0.009216949, 0.07251379) * g_22;
|
||||
result += mat4(-0.04915367, -0.07121096, -0.06572174, -0.10967046, 0.019548079, 0.023992533, -0.019842865, 0.012366459, -0.07207817, -0.04237792, -0.054463565, -0.015374731, -0.092071235, -0.020860313, -0.054475963, -0.02303954) * g_23;
|
||||
result += mat4(0.04160816, -0.118427366, -0.08661791, 0.12787233, -0.01990174, 0.0012960634, -0.016121056, 0.031429946, -0.06830865, -0.057132352, -0.0022302791, 0.03845933, -0.026981276, -0.063532256, 0.011805961, -0.009616678) * g_24;
|
||||
result += mat4(0.07094465, -0.022284096, 0.060676746, 0.042626668, 0.011207256, -0.14960343, 0.05866539, -0.12742221, -0.021092903, -0.039463162, -0.07879986, -0.10232898, -0.026127055, -0.038111385, 0.019167708, 0.032637425) * g_25;
|
||||
result += mat4(-0.014270794, 0.07157703, 0.013714203, -0.047801998, 0.0060221693, 0.022788104, 0.10630103, -0.09606649, 0.12690987, -0.017079826, -0.0077072172, -0.082584485, 0.13256006, 0.16012523, -0.10966099, -0.07927409) * g_26;
|
||||
result += mat4(-0.17171615, 0.12114435, -0.10746857, -0.0074188868, 0.07854815, 0.07759372, 0.04310874, 0.051465522, -0.05963588, -0.014506484, 0.15522978, 0.18746643, -0.03845241, -0.0489534, 0.05837339, 0.032978524) * g_27;
|
||||
result += vec4(0.05825913, 0.051491056, 0.038389463, 0.03321517);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Conv-4x1x1x112
|
||||
//!HOOK MAIN
|
||||
//!BIND conv2d_tf
|
||||
//!BIND conv2d_tf1
|
||||
//!BIND conv2d_1_tf
|
||||
//!BIND conv2d_1_tf1
|
||||
//!BIND conv2d_2_tf
|
||||
//!BIND conv2d_2_tf1
|
||||
//!BIND conv2d_3_tf
|
||||
//!BIND conv2d_3_tf1
|
||||
//!BIND conv2d_4_tf
|
||||
//!BIND conv2d_4_tf1
|
||||
//!BIND conv2d_5_tf
|
||||
//!BIND conv2d_5_tf1
|
||||
//!BIND conv2d_6_tf
|
||||
//!BIND conv2d_6_tf1
|
||||
//!SAVE conv2d_last_tf2
|
||||
//!WIDTH conv2d_tf.w
|
||||
//!HEIGHT conv2d_tf.h
|
||||
//!COMPONENTS 4
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
#define g_0 (max((conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_1 (max((conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_2 (max(-(conv2d_tf_tex(conv2d_tf_pos)), 0.0))
|
||||
#define g_3 (max(-(conv2d_tf1_tex(conv2d_tf1_pos)), 0.0))
|
||||
#define g_4 (max((conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_5 (max((conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_6 (max(-(conv2d_1_tf_tex(conv2d_1_tf_pos)), 0.0))
|
||||
#define g_7 (max(-(conv2d_1_tf1_tex(conv2d_1_tf1_pos)), 0.0))
|
||||
#define g_8 (max((conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_9 (max((conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_10 (max(-(conv2d_2_tf_tex(conv2d_2_tf_pos)), 0.0))
|
||||
#define g_11 (max(-(conv2d_2_tf1_tex(conv2d_2_tf1_pos)), 0.0))
|
||||
#define g_12 (max((conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_13 (max((conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_14 (max(-(conv2d_3_tf_tex(conv2d_3_tf_pos)), 0.0))
|
||||
#define g_15 (max(-(conv2d_3_tf1_tex(conv2d_3_tf1_pos)), 0.0))
|
||||
#define g_16 (max((conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_17 (max((conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_18 (max(-(conv2d_4_tf_tex(conv2d_4_tf_pos)), 0.0))
|
||||
#define g_19 (max(-(conv2d_4_tf1_tex(conv2d_4_tf1_pos)), 0.0))
|
||||
#define g_20 (max((conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_21 (max((conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_22 (max(-(conv2d_5_tf_tex(conv2d_5_tf_pos)), 0.0))
|
||||
#define g_23 (max(-(conv2d_5_tf1_tex(conv2d_5_tf1_pos)), 0.0))
|
||||
#define g_24 (max((conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_25 (max((conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
#define g_26 (max(-(conv2d_6_tf_tex(conv2d_6_tf_pos)), 0.0))
|
||||
#define g_27 (max(-(conv2d_6_tf1_tex(conv2d_6_tf1_pos)), 0.0))
|
||||
vec4 hook() {
|
||||
vec4 result = mat4(0.2006987, 0.17832398, 0.26342955, 0.23500517, -0.012297829, -0.009008417, -0.039950736, -0.039973143, 0.34800097, 0.32196492, 0.30505183, 0.29214156, -0.21410535, -0.21166423, -0.16437815, -0.19172792) * g_0;
|
||||
result += mat4(-0.008804151, -0.07085123, 0.013577994, -0.05192605, -0.08981402, -0.14702585, -0.09145975, -0.14835288, -0.15882517, -0.14785844, -0.2381482, -0.22867912, 0.010898514, 0.031957507, 0.040597558, 0.078252345) * g_1;
|
||||
result += mat4(-0.21658613, -0.1803885, -0.25954962, -0.20839214, -0.09597461, -0.09222647, -0.03909875, -0.03456191, -0.19723509, -0.16976605, -0.2041716, -0.1751425, 0.22901416, 0.24922715, 0.1800083, 0.23346905) * g_2;
|
||||
result += mat4(0.110020064, 0.103858806, 0.052446555, 0.061105963, 0.032901537, 0.07140097, 0.11518793, 0.13860466, 0.13930707, 0.12712196, 0.19071707, 0.18399614, -0.08036458, -0.07349171, 0.021504594, 0.0024937368) * g_3;
|
||||
result += mat4(0.059065036, 0.00698257, -0.099622436, -0.15676253, -0.10942482, -0.04869624, -0.13654554, -0.07341863, -0.014169851, -0.06390744, 0.016093008, -0.04540248, 0.29041344, 0.24451919, 0.26292154, 0.22136512) * g_4;
|
||||
result += mat4(0.107946776, 0.097849295, 0.10266876, 0.09360328, 0.08931344, 0.08896482, 0.046495322, 0.044040844, -0.020361643, -0.030911373, 0.026598722, 0.019815676, -0.072677925, -0.042410247, 0.14127749, 0.13434973) * g_5;
|
||||
result += mat4(-0.08809133, -0.03476601, 0.06420393, 0.14691353, 0.09296839, 0.06162562, 0.10992992, 0.0615685, 0.0168736, 0.06520281, 0.020010693, 0.046929173, -0.2219495, -0.21249783, -0.14622301, -0.14599061) * g_6;
|
||||
result += mat4(-0.13251069, -0.08977477, -0.08930347, -0.045490693, -0.10980218, -0.09510885, -0.07299872, -0.064053826, 0.011365247, 0.014091111, -0.054976214, -0.056936122, 0.10148144, 0.07451642, -0.08138598, -0.10161657) * g_7;
|
||||
result += mat4(-0.0075518745, -0.005738622, -0.007577811, -0.00032088626, 0.032614008, 0.04858922, 0.00054855715, 0.011565026, -0.022675224, -0.034442738, -0.03580643, -0.05069376, -0.0020376542, -0.01505518, 0.019388825, 0.03746554) * g_8;
|
||||
result += mat4(-0.011413172, -0.016877454, -0.048923567, -0.055012885, -0.007709447, -0.016109072, -0.047132388, -0.07146396, 0.002604099, 0.00014681708, 0.03429465, 0.043265607, 0.029014807, 0.03337814, 0.07582056, 0.041660666) * g_9;
|
||||
result += mat4(-0.020768544, -0.014378527, -0.01999972, -0.01385916, -0.012264676, -0.009959511, 0.0119015165, -0.016787319, 0.07266734, -0.0029914333, 0.08549183, 0.004367342, 0.008236065, 0.020370748, 0.0043428927, 0.007301017) * g_10;
|
||||
result += mat4(0.011654731, 0.025318999, -0.0029306612, 0.007426217, -0.00010868774, -0.020845588, 0.041991003, 0.024147986, -0.030741083, -0.012328637, -0.06617428, -0.06103115, 0.010491518, -0.013338451, -0.04666634, -0.046481613) * g_11;
|
||||
result += mat4(0.0268538, 0.043785956, -0.01799385, 0.008743307, -0.013197458, -0.015049436, -0.017189734, -0.0047999253, -0.00059730676, -0.0008936153, -0.016006093, -0.0073406673, 0.014875853, 0.011491735, 9.819833e-05, 0.0073417514) * g_12;
|
||||
result += mat4(0.019930955, 0.027112626, 0.01307941, 0.005268897, -0.060213763, -0.050415818, -0.069006495, -0.051405095, 0.0036414433, -0.008606397, 0.037427194, -0.0018103109, -0.037434716, 0.010187546, -0.026227329, -0.0033639795) * g_13;
|
||||
result += mat4(-0.03634798, 0.0007093891, -0.026819145, 0.009025687, -0.01750318, -0.020098133, -0.0063864207, -0.006606755, 0.0008565766, 0.028647956, -0.0024974607, 0.015250743, -0.048884176, -0.004310685, -0.0010757383, 0.00974984) * g_14;
|
||||
result += mat4(-0.031253602, -0.031743724, -0.009083253, 0.0145388115, 0.02048611, 0.0058071036, -0.0038228377, 0.00049654936, 0.0059105973, 0.03437731, -0.025785418, 0.004187733, 0.009980489, -4.08268e-05, 0.009384428, 0.0019492983) * g_15;
|
||||
result += mat4(0.012587245, -0.0032654977, 0.029739188, -0.009440694, -0.0018237908, -0.0080032, 0.010499013, 0.0012466761, 0.03461923, -0.0060207327, -0.008771263, -0.034545746, -0.015023473, -0.008901684, -0.011490296, -0.01976464) * g_16;
|
||||
result += mat4(-0.009444331, 0.020809013, 0.009985801, 0.020350901, 0.013234775, 0.004382635, -0.0007761826, -0.005247294, 0.034115106, 0.05190378, 0.039124765, 0.050993033, -0.0898732, -0.030428126, -0.044204578, -0.052484997) * g_17;
|
||||
result += mat4(-0.020434443, 0.053520404, 0.0007571144, 0.05895061, -0.018991265, -0.043982152, -0.004035192, -0.025452444, -0.012197152, -0.013770753, 0.0012919102, 0.003996682, 0.0056104586, 0.025686186, 0.05128293, 0.05105745) * g_18;
|
||||
result += mat4(0.030201769, 0.052521482, 0.029641917, 0.05559941, 0.0018870027, 0.020112835, -0.0043867202, 0.035877172, 0.02961142, 0.02163634, -0.027972858, -0.040669747, 0.03393723, 0.013455979, 0.03313782, 0.01968004) * g_19;
|
||||
result += mat4(0.034817442, 0.04045217, 0.054816365, 0.05092461, 0.06600807, 0.062576495, 0.09923777, 0.006663677, -0.039958935, -0.010009866, -0.041522443, -0.04959681, -0.020962957, 0.003845031, -0.04910384, -0.03233655) * g_20;
|
||||
result += mat4(0.015433112, 0.028965838, -0.0055138534, 0.042267464, -0.012690953, -0.009424165, 0.017896382, 0.01186686, 0.07231686, -0.038834292, 0.07033086, -0.052548733, 0.15721905, 0.09334892, 0.07676042, 0.06701375) * g_21;
|
||||
result += mat4(-0.09797534, -0.11201098, -0.0037222446, -0.008105951, -0.01152357, 0.012165641, -0.029051905, -0.021293389, -0.09600697, -0.028819272, -0.069084235, -0.035421908, 0.0054322914, 0.14168966, -0.0200274, 0.06505187) * g_22;
|
||||
result += mat4(-0.05034882, -0.06622497, -0.062471002, -0.100628324, 0.018115615, 0.019867867, -0.018836644, 0.007562053, -0.06317378, -0.034458403, -0.047243826, -0.009989589, -0.08270121, -0.018645251, -0.05160367, -0.023690399) * g_23;
|
||||
result += mat4(0.03897899, -0.10862529, -0.081805214, 0.1202324, -0.021866674, -0.00041882638, -0.018235246, 0.027227063, -0.0656312, -0.053432237, -0.0029235696, 0.03549672, -0.022848906, -0.057047505, 0.013400545, -0.0072439364) * g_24;
|
||||
result += mat4(0.06879516, -0.018637763, 0.058062725, 0.041045032, 0.011702424, -0.13693465, 0.05674195, -0.11679955, -0.022940686, -0.03856922, -0.07531371, -0.09692582, -0.019870926, -0.032572743, 0.026138868, 0.037639033) * g_25;
|
||||
result += mat4(-0.015270301, 0.06478719, 0.011016518, -0.04533957, 0.00688319, 0.024815995, 0.10159924, -0.08467507, 0.11939162, -0.01939453, -0.0058689644, -0.077881604, 0.118726775, 0.14489114, -0.10831982, -0.07972515) * g_26;
|
||||
result += mat4(-0.16734359, 0.10685446, -0.102714166, -0.010225307, 0.07306756, 0.07014447, 0.040464073, 0.04688462, -0.05489714, -0.01525318, 0.14690581, 0.17514132, -0.03250648, -0.03688211, 0.05047889, 0.03078089) * g_27;
|
||||
result += vec4(0.06614842, 0.045779686, 0.032838725, 0.017085627);
|
||||
return result;
|
||||
}
|
||||
//!DESC Anime4K-v3.2-Upscale-Denoise-CNN-x2-(VL)-Depth-to-Space
|
||||
//!HOOK MAIN
|
||||
//!BIND MAIN
|
||||
//!BIND conv2d_last_tf
|
||||
//!BIND conv2d_last_tf1
|
||||
//!BIND conv2d_last_tf2
|
||||
//!SAVE MAIN
|
||||
//!WIDTH conv2d_last_tf.w 2 *
|
||||
//!HEIGHT conv2d_last_tf.h 2 *
|
||||
//!WHEN OUTPUT.w MAIN.w / 1.200 > OUTPUT.h MAIN.h / 1.200 > *
|
||||
vec4 hook() {
|
||||
vec2 f0 = fract(conv2d_last_tf_pos * conv2d_last_tf_size);
|
||||
ivec2 i0 = ivec2(f0 * vec2(2.0));
|
||||
float c0 = conv2d_last_tf_tex((vec2(0.5) - f0) * conv2d_last_tf_pt + conv2d_last_tf_pos)[i0.y * 2 + i0.x];
|
||||
vec2 f1 = fract(conv2d_last_tf1_pos * conv2d_last_tf1_size);
|
||||
ivec2 i1 = ivec2(f1 * vec2(2.0));
|
||||
float c1 = conv2d_last_tf1_tex((vec2(0.5) - f1) * conv2d_last_tf1_pt + conv2d_last_tf1_pos)[i1.y * 2 + i1.x];
|
||||
vec2 f2 = fract(conv2d_last_tf2_pos * conv2d_last_tf2_size);
|
||||
ivec2 i2 = ivec2(f2 * vec2(2.0));
|
||||
float c2 = conv2d_last_tf2_tex((vec2(0.5) - f2) * conv2d_last_tf2_pt + conv2d_last_tf2_pos)[i2.y * 2 + i2.x];
|
||||
float c3 = c2;
|
||||
return vec4(c0, c1, c2, c3) + MAIN_tex(MAIN_pos);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 bloc97
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
|
||||
import 'src/screens/connect_screen.dart';
|
||||
import 'src/screens/home/home_screen.dart';
|
||||
import 'src/screens/home/ui.dart';
|
||||
import 'src/screens/session_screen.dart';
|
||||
import 'src/screens/welcome_screen.dart';
|
||||
import 'src/state/session_state.dart';
|
||||
|
||||
class WatchTogetherApp extends StatelessWidget {
|
||||
@@ -13,13 +13,12 @@ class WatchTogetherApp extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final session = SessionState.instance;
|
||||
return MaterialApp(
|
||||
title: 'Watch Together',
|
||||
title: appName,
|
||||
theme: ThemeData.dark(),
|
||||
home: SignalBuilder(
|
||||
builder: (context) {
|
||||
return switch (session.route.value) {
|
||||
AppRoute.welcome => const WelcomeScreen(),
|
||||
AppRoute.connect => const ConnectScreen(),
|
||||
AppRoute.home => const HomeScreen(),
|
||||
AppRoute.session => const SessionScreen(),
|
||||
};
|
||||
},
|
||||
|
||||
+24
-10
@@ -7,19 +7,18 @@ import 'package:sync_relay_core/core.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import 'app.dart';
|
||||
import 'src/screens/home/ui.dart';
|
||||
import 'src/state/session_state.dart';
|
||||
import 'src/state/settings.dart';
|
||||
import 'src/update/updater.dart';
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
launchArgs = List.unmodifiable(args);
|
||||
if (args.contains('--upgrade')) {
|
||||
exitCode = await runUpgrade();
|
||||
exit(exitCode);
|
||||
}
|
||||
initLogging();
|
||||
if (args.contains('--headless')) {
|
||||
await runHeadless(args);
|
||||
return;
|
||||
}
|
||||
FlutterError.onError = (details) {
|
||||
debugPrint('FLUTTER ERROR: ${details.exceptionAsString()}\n${details.stack}');
|
||||
FlutterError.presentError(details);
|
||||
@@ -39,19 +38,22 @@ Future<void> main(List<String> args) async {
|
||||
);
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await windowManager.ensureInitialized();
|
||||
await windowManager.setPreventClose(true);
|
||||
windowManager.addListener(_CloseGuard());
|
||||
const windowOptions = WindowOptions(
|
||||
size: Size(1280, 720),
|
||||
minimumSize: Size(160, 90),
|
||||
center: true,
|
||||
backgroundColor: Color(0xFF000000),
|
||||
titleBarStyle: TitleBarStyle.hidden,
|
||||
title: 'Watch Together',
|
||||
title: appName,
|
||||
);
|
||||
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||
await windowManager.show();
|
||||
await windowManager.focus();
|
||||
});
|
||||
await Hive.initFlutter();
|
||||
await AppSettings.instance.ensureLoaded();
|
||||
try {
|
||||
await SessionState.instance.loadForm();
|
||||
} catch (e, st) {
|
||||
@@ -61,9 +63,21 @@ Future<void> main(List<String> args) async {
|
||||
runApp(const WatchTogetherApp());
|
||||
}
|
||||
|
||||
Future<void> runHeadless(List<String> args) async {
|
||||
final session = SessionState.instance;
|
||||
await session.startHeadless(args);
|
||||
await ProcessSignal.sigint.watch().first;
|
||||
await session.stopServer();
|
||||
/// Close button / Alt+F4: leave gracefully first (others see "left", a
|
||||
/// hosted server shuts down), bounded so a hung socket can't keep the
|
||||
/// window open.
|
||||
class _CloseGuard with WindowListener {
|
||||
bool _closing = false;
|
||||
|
||||
@override
|
||||
Future<void> onWindowClose() async {
|
||||
if (_closing) return;
|
||||
_closing = true;
|
||||
try {
|
||||
await SessionState.instance.leave().timeout(const Duration(seconds: 2));
|
||||
} catch (e) {
|
||||
debugPrint('leave on close failed: $e');
|
||||
}
|
||||
await windowManager.destroy();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
import 'package:sync_relay_core/core.dart' show JellyfinStreamType;
|
||||
|
||||
import '../../jellyfin/track_prefs.dart' show MpvTrack;
|
||||
import '../../playback/media_marks.dart';
|
||||
import '../../playback/playback_controller.dart' show RenderMode;
|
||||
import '../../screens/session/player_controls.dart' show TrackPick;
|
||||
import '../../shaders/shader_menu.dart';
|
||||
import '../../shaders/shader_presets.dart';
|
||||
import '../../state/settings.dart';
|
||||
import 'controls.dart';
|
||||
import 'menu.dart';
|
||||
import 'style.dart';
|
||||
|
||||
/// Flat uosc button: a white icon (optionally a [label] beside it and a
|
||||
/// small count [badge] in the corner), a faint highlight on hover, a dark
|
||||
/// tooltip. Never takes focus (the session's keys are global).
|
||||
class UoscButton extends StatefulWidget {
|
||||
final IconData icon;
|
||||
final String tooltip;
|
||||
final VoidCallback? onPressed;
|
||||
final String? label;
|
||||
final int? badge;
|
||||
/// Tint for an "on" state (ready, shaders on).
|
||||
final Color? color;
|
||||
const UoscButton({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.tooltip,
|
||||
required this.onPressed,
|
||||
this.label,
|
||||
this.badge,
|
||||
this.color,
|
||||
});
|
||||
|
||||
@override
|
||||
State<UoscButton> createState() => _UoscButtonState();
|
||||
}
|
||||
|
||||
class _UoscButtonState extends State<UoscButton> {
|
||||
bool _hover = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final w = widget;
|
||||
final color = w.onPressed == null ? UoscStyle.dim.withValues(alpha: 0.4) : (w.color ?? UoscStyle.text);
|
||||
final badge = w.badge;
|
||||
return UoscTooltip(
|
||||
message: w.tooltip,
|
||||
child: MouseRegion(
|
||||
cursor: w.onPressed == null ? SystemMouseCursors.basic : SystemMouseCursors.click,
|
||||
onEnter: (_) => setState(() => _hover = true),
|
||||
onExit: (_) => setState(() => _hover = false),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: w.onPressed,
|
||||
child: Container(
|
||||
height: UoscControls.buttonRowHeight,
|
||||
constraints: const BoxConstraints(minWidth: UoscControls.buttonRowHeight),
|
||||
padding: EdgeInsets.symmetric(horizontal: w.label == null ? 0 : 8),
|
||||
decoration: BoxDecoration(
|
||||
color: _hover && w.onPressed != null ? UoscStyle.hover : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(UoscStyle.radius),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Icon(w.icon, color: color, size: 22),
|
||||
if (badge != null && badge > 0)
|
||||
Positioned(
|
||||
right: -8,
|
||||
bottom: -5,
|
||||
child: Container(
|
||||
key: const ValueKey('uosc-badge'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: UoscStyle.text,
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
),
|
||||
child: Text('$badge',
|
||||
style: const TextStyle(
|
||||
color: Colors.black, fontSize: 9, height: 1.3, fontWeight: FontWeight.w700)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (w.label != null) ...[
|
||||
const SizedBox(width: 6),
|
||||
Text(w.label!, style: TextStyle(color: color, fontSize: UoscStyle.fontSize)),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Badge-style text button ("HQ" in uosc): a small outlined box with a
|
||||
/// short label, filled when [active].
|
||||
class UoscBadgeButton extends StatefulWidget {
|
||||
final String text;
|
||||
final String tooltip;
|
||||
final bool active;
|
||||
final VoidCallback onPressed;
|
||||
const UoscBadgeButton({
|
||||
super.key,
|
||||
required this.text,
|
||||
required this.tooltip,
|
||||
required this.active,
|
||||
required this.onPressed,
|
||||
});
|
||||
|
||||
@override
|
||||
State<UoscBadgeButton> createState() => _UoscBadgeButtonState();
|
||||
}
|
||||
|
||||
class _UoscBadgeButtonState extends State<UoscBadgeButton> {
|
||||
bool _hover = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final w = widget;
|
||||
return UoscTooltip(
|
||||
message: w.tooltip,
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) => setState(() => _hover = true),
|
||||
onExit: (_) => setState(() => _hover = false),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: w.onPressed,
|
||||
child: Container(
|
||||
height: UoscControls.buttonRowHeight,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: _hover ? UoscStyle.hover : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(UoscStyle.radius),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 1),
|
||||
decoration: BoxDecoration(
|
||||
color: w.active ? UoscStyle.text : Colors.transparent,
|
||||
border: Border.all(color: w.active ? UoscStyle.text : UoscStyle.dim, width: 1.4),
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
),
|
||||
child: Text(w.text,
|
||||
style: TextStyle(
|
||||
color: w.active ? Colors.black : UoscStyle.dim,
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w800,
|
||||
letterSpacing: 0.3)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Volume: click mutes / unmutes, the wheel steps 5 %.
|
||||
class UoscVolumeButton extends StatefulWidget {
|
||||
/// 0..100.
|
||||
final double volume;
|
||||
final ValueChanged<double> onChanged;
|
||||
const UoscVolumeButton({super.key, required this.volume, required this.onChanged});
|
||||
|
||||
@override
|
||||
State<UoscVolumeButton> createState() => _UoscVolumeButtonState();
|
||||
}
|
||||
|
||||
class _UoscVolumeButtonState extends State<UoscVolumeButton> {
|
||||
double _beforeMute = 100;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final v = widget.volume;
|
||||
final icon = v <= 0 ? Icons.volume_off_rounded : (v < 50 ? Icons.volume_down_rounded : Icons.volume_up_rounded);
|
||||
return Listener(
|
||||
onPointerSignal: (e) {
|
||||
if (e is PointerScrollEvent && e.scrollDelta.dy != 0) {
|
||||
widget.onChanged((v + (e.scrollDelta.dy < 0 ? 5 : -5)).clamp(0.0, 100.0));
|
||||
}
|
||||
},
|
||||
child: UoscButton(
|
||||
key: const ValueKey('uosc-volume'),
|
||||
icon: icon,
|
||||
tooltip: 'Volume ${v.round()} % (scroll to change)',
|
||||
onPressed: () {
|
||||
if (v > 0) {
|
||||
_beforeMute = v;
|
||||
widget.onChanged(0);
|
||||
} else {
|
||||
widget.onChanged(_beforeMute <= 0 ? 100 : _beforeMute);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Subtitles or audio: the icon with the track count; the menu lists the
|
||||
/// tracks (mpv's selection active).
|
||||
class UoscTracksButton extends StatelessWidget {
|
||||
final JellyfinStreamType type;
|
||||
final List<MpvTrack> tracks;
|
||||
final void Function(TrackPick pick) onPick;
|
||||
final ValueChanged<bool>? onMenuOpen;
|
||||
const UoscTracksButton({super.key, required this.type, required this.tracks, required this.onPick, this.onMenuOpen});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final audio = type == JellyfinStreamType.audio;
|
||||
final count = tracks.where((t) => t.type == type).length;
|
||||
return UoscButton(
|
||||
key: ValueKey(audio ? 'uosc-audio' : 'uosc-subtitles'),
|
||||
icon: audio ? Icons.graphic_eq_rounded : Icons.subtitles_outlined,
|
||||
tooltip: audio ? 'Audio' : 'Subtitles',
|
||||
badge: count,
|
||||
onPressed: () async {
|
||||
onMenuOpen?.call(true);
|
||||
final pick = await showUoscMenu<TrackPick>(context,
|
||||
title: audio ? 'Audio' : 'Subtitles', items: trackMenuItems(type, tracks));
|
||||
onMenuOpen?.call(false);
|
||||
if (pick != null) onPick(pick);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Chapters: the list with start times, the playing one active; a pick
|
||||
/// jumps there. Nothing without chapters.
|
||||
class UoscChaptersButton extends StatelessWidget {
|
||||
final List<MediaChapter> chapters;
|
||||
final int? current;
|
||||
final Duration duration;
|
||||
final ValueChanged<MediaChapter> onPick;
|
||||
final ValueChanged<bool>? onMenuOpen;
|
||||
const UoscChaptersButton({
|
||||
super.key,
|
||||
required this.chapters,
|
||||
required this.current,
|
||||
required this.duration,
|
||||
required this.onPick,
|
||||
this.onMenuOpen,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (chapters.isEmpty) return const SizedBox.shrink();
|
||||
return UoscButton(
|
||||
key: const ValueKey('uosc-chapters'),
|
||||
icon: Icons.bookmarks_outlined,
|
||||
tooltip: 'Chapters (PgUp / PgDn)',
|
||||
onPressed: () async {
|
||||
onMenuOpen?.call(true);
|
||||
final pick = await showUoscMenu<MediaChapter>(context,
|
||||
title: 'Chapters', items: chapterMenuItems(chapters, current, duration));
|
||||
onMenuOpen?.call(false);
|
||||
if (pick != null) onPick(pick);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Shaders as uosc's quality badge: the active Anime4K preset ("A HQ"),
|
||||
/// "4K" dimmed when off. Opens the shader menu.
|
||||
class UoscShaderButton extends StatelessWidget {
|
||||
final ReadonlySignal<RenderMode> renderMode;
|
||||
final void Function(ShaderPreset preset, ShaderQuality? quality) onPick;
|
||||
final ValueChanged<bool>? onMenuOpen;
|
||||
const UoscShaderButton({super.key, required this.renderMode, required this.onPick, this.onMenuOpen});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = AppSettings.instance;
|
||||
return SignalBuilder(builder: (context) {
|
||||
final preset = s.shaderPreset.value;
|
||||
final quality = s.shaderQuality.value;
|
||||
final short = shaderShortLabel(preset, quality);
|
||||
return Builder(
|
||||
builder: (context) => UoscBadgeButton(
|
||||
key: const ValueKey('uosc-shaders'),
|
||||
text: short ?? '4K',
|
||||
active: short != null,
|
||||
tooltip: short == null
|
||||
? 'Shaders: off (Ctrl+1..6)'
|
||||
: 'Shaders: ${shaderLabel(preset, quality)} (Ctrl+0 off)',
|
||||
onPressed: () {
|
||||
final controls = UoscControls.maybeOf(context);
|
||||
Future<void> open() =>
|
||||
showShaderMenu(context, renderMode: renderMode, onPick: onPick, onMenuOpen: onMenuOpen);
|
||||
controls == null ? open() : controls.holdDuring(open);
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// One entry of the ≡ menu.
|
||||
typedef UoscAction = ({String title, String? hint, VoidCallback run});
|
||||
|
||||
/// ≡: the session's actions as a menu.
|
||||
class UoscMainMenuButton extends StatelessWidget {
|
||||
final List<UoscAction> actions;
|
||||
final ValueChanged<bool>? onMenuOpen;
|
||||
const UoscMainMenuButton({super.key, required this.actions, this.onMenuOpen});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return UoscButton(
|
||||
key: const ValueKey('uosc-menu-button'),
|
||||
icon: Icons.menu_rounded,
|
||||
tooltip: 'Menu',
|
||||
onPressed: () async {
|
||||
onMenuOpen?.call(true);
|
||||
final pick = await showUoscMenu<UoscAction>(context, items: [
|
||||
for (final a in actions) UoscMenuItem(value: a, title: a.title, hint: a.hint),
|
||||
]);
|
||||
onMenuOpen?.call(false);
|
||||
pick?.run();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
|
||||
import '../../state/settings.dart';
|
||||
|
||||
// The experimental mpv-style (uosc) controls frame: a full-width timeline
|
||||
// at the bottom with a row of flat buttons above it, window buttons top
|
||||
// right. Mouse movement shows them; after [UoscControls.hideAfter] without
|
||||
// any they fade out, the timeline shrinks to a thin line and the cursor
|
||||
// hides. Everything lives here because media_kit's fullscreen route
|
||||
// renders only the video and its controls.
|
||||
|
||||
class UoscControls extends StatefulWidget {
|
||||
/// The timeline; [expanded] is false while the controls are hidden.
|
||||
final Widget Function(BuildContext context, bool expanded) timeline;
|
||||
/// Buttons left and right of the row above the timeline.
|
||||
final List<Widget> left;
|
||||
final List<Widget> right;
|
||||
/// Top-right corner (window buttons), shown with the controls.
|
||||
final Widget? top;
|
||||
final VoidCallback? onDoubleTap;
|
||||
final Duration hideAfter;
|
||||
const UoscControls({
|
||||
super.key,
|
||||
required this.timeline,
|
||||
this.left = const [],
|
||||
this.right = const [],
|
||||
this.top,
|
||||
this.onDoubleTap,
|
||||
this.hideAfter = const Duration(seconds: 3),
|
||||
});
|
||||
|
||||
static const buttonRowHeight = 40.0;
|
||||
|
||||
/// The controls around [context], for widgets that need them kept up
|
||||
/// (a timeline drag, an open menu).
|
||||
static UoscControlsState? maybeOf(BuildContext context) =>
|
||||
context.findAncestorStateOfType<UoscControlsState>();
|
||||
|
||||
@override
|
||||
State<UoscControls> createState() => UoscControlsState();
|
||||
}
|
||||
|
||||
class UoscControlsState extends State<UoscControls> {
|
||||
bool _visible = true;
|
||||
int _holds = 0;
|
||||
Timer? _timer;
|
||||
|
||||
bool get visible => _visible;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_hideLater();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/// Show the controls and restart the hide countdown.
|
||||
void wake() {
|
||||
if (!_visible && mounted) setState(() => _visible = true);
|
||||
_hideLater();
|
||||
}
|
||||
|
||||
/// Keep the controls up while [on] (paired calls): a drag sends no
|
||||
/// hover events and a menu route takes the mouse.
|
||||
void hold(bool on) {
|
||||
_holds = on ? _holds + 1 : (_holds - 1).clamp(0, 1 << 20);
|
||||
wake();
|
||||
}
|
||||
|
||||
/// Runs [open] (a menu) with the controls held up.
|
||||
Future<T> holdDuring<T>(Future<T> Function() open) async {
|
||||
hold(true);
|
||||
try {
|
||||
return await open();
|
||||
} finally {
|
||||
if (mounted) hold(false);
|
||||
}
|
||||
}
|
||||
|
||||
void _hideLater() {
|
||||
_timer?.cancel();
|
||||
_timer = Timer(widget.hideAfter, _hide);
|
||||
}
|
||||
|
||||
void _hide() {
|
||||
if (!mounted || _holds > 0 || !_visible) return;
|
||||
setState(() => _visible = false);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final visible = _visible;
|
||||
const fade = Duration(milliseconds: 150);
|
||||
return MouseRegion(
|
||||
cursor: visible ? SystemMouseCursors.basic : SystemMouseCursors.none,
|
||||
onEnter: (_) => wake(),
|
||||
onHover: (_) => wake(),
|
||||
onExit: (_) {
|
||||
_timer?.cancel();
|
||||
_hide();
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onDoubleTap: widget.onDoubleTap,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
height: 160,
|
||||
child: IgnorePointer(
|
||||
child: AnimatedOpacity(
|
||||
duration: fade,
|
||||
opacity: visible ? 1 : 0,
|
||||
child: const DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0x00000000), Color(0x8C000000)],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.top != null)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: IgnorePointer(
|
||||
ignoring: !visible,
|
||||
child: AnimatedOpacity(duration: fade, opacity: visible ? 1 : 0, child: widget.top),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
IgnorePointer(
|
||||
key: const ValueKey('uosc-buttons'),
|
||||
ignoring: !visible,
|
||||
child: AnimatedOpacity(
|
||||
duration: fade,
|
||||
opacity: visible ? 1 : 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(6, 0, 6, 4),
|
||||
child: SizedBox(
|
||||
height: UoscControls.buttonRowHeight,
|
||||
child: Row(children: [...widget.left, const Spacer(), ...widget.right]),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
widget.timeline(context, visible),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The session's controls: media_kit's ([material]) or, with Settings →
|
||||
/// "Experimental: mpv-style controls", the uosc ones ([mpv]). Switches
|
||||
/// live when the setting changes.
|
||||
class SessionControlsSwitch extends StatelessWidget {
|
||||
final WidgetBuilder material;
|
||||
final WidgetBuilder mpv;
|
||||
const SessionControlsSwitch({super.key, required this.material, required this.mpv});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SignalBuilder(
|
||||
builder: (context) =>
|
||||
AppSettings.instance.mpvControls.value ? mpv(context) : material(context),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sync_relay_core/core.dart' show JellyfinStreamType;
|
||||
|
||||
import '../../jellyfin/track_prefs.dart' show MpvTrack;
|
||||
import '../../playback/media_marks.dart';
|
||||
import '../../screens/session/player_controls.dart' show TrackPick;
|
||||
import 'controls.dart';
|
||||
import 'style.dart';
|
||||
|
||||
/// One row of a uosc menu: [title], a dim [hint] on the right (a time, a
|
||||
/// key), [active] = the current one (highlighted).
|
||||
class UoscMenuItem<T> {
|
||||
final T value;
|
||||
final String title;
|
||||
final String? hint;
|
||||
final bool active;
|
||||
final bool enabled;
|
||||
const UoscMenuItem({
|
||||
required this.value,
|
||||
required this.title,
|
||||
this.hint,
|
||||
this.active = false,
|
||||
this.enabled = true,
|
||||
});
|
||||
}
|
||||
|
||||
/// A flat dark menu over the controls, above the widget of [context] (the
|
||||
/// button that opens it), with an optional [title] row. Resolves to the
|
||||
/// picked value, or null when dismissed (click outside, Esc). Keeps the
|
||||
/// controls up while open.
|
||||
Future<T?> showUoscMenu<T>(
|
||||
BuildContext context, {
|
||||
String? title,
|
||||
required List<UoscMenuItem<T>> items,
|
||||
}) {
|
||||
final navigator = Navigator.of(context);
|
||||
final overlay = navigator.overlay!.context.findRenderObject() as RenderBox;
|
||||
final box = context.findRenderObject() as RenderBox;
|
||||
final anchor = Rect.fromPoints(
|
||||
box.localToGlobal(Offset.zero, ancestor: overlay),
|
||||
box.localToGlobal(box.size.bottomRight(Offset.zero), ancestor: overlay),
|
||||
);
|
||||
Future<T?> open() => navigator.push<T>(_UoscMenuRoute<T>(anchor: anchor, title: title, items: items));
|
||||
final controls = UoscControls.maybeOf(context);
|
||||
return controls == null ? open() : controls.holdDuring(open);
|
||||
}
|
||||
|
||||
class _UoscMenuRoute<T> extends PopupRoute<T> {
|
||||
final Rect anchor;
|
||||
final String? title;
|
||||
final List<UoscMenuItem<T>> items;
|
||||
_UoscMenuRoute({required this.anchor, required this.title, required this.items});
|
||||
|
||||
@override
|
||||
Color? get barrierColor => null;
|
||||
|
||||
@override
|
||||
bool get barrierDismissible => true;
|
||||
|
||||
@override
|
||||
String? get barrierLabel => 'Close menu';
|
||||
|
||||
@override
|
||||
Duration get transitionDuration => Duration.zero;
|
||||
|
||||
@override
|
||||
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
const width = 360.0;
|
||||
final screen = constraints.biggest;
|
||||
final left = anchor.left.clamp(8.0, math.max(8.0, screen.width - width - 8));
|
||||
final maxHeight = math.max(120.0, anchor.top - 16);
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
left: left.toDouble(),
|
||||
bottom: screen.height - anchor.top + 6,
|
||||
width: math.min(width, screen.width - 16),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: maxHeight),
|
||||
child: UoscMenuPanel<T>(
|
||||
title: title,
|
||||
items: items,
|
||||
onPick: (v) => Navigator.of(context).pop(v),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// The menu's panel alone (tests pump it without a route).
|
||||
class UoscMenuPanel<T> extends StatefulWidget {
|
||||
final String? title;
|
||||
final List<UoscMenuItem<T>> items;
|
||||
final ValueChanged<T> onPick;
|
||||
const UoscMenuPanel({super.key, this.title, required this.items, required this.onPick});
|
||||
|
||||
static const rowHeight = 36.0;
|
||||
|
||||
@override
|
||||
State<UoscMenuPanel<T>> createState() => _UoscMenuPanelState<T>();
|
||||
}
|
||||
|
||||
class _UoscMenuPanelState<T> extends State<UoscMenuPanel<T>> {
|
||||
// Long lists open on the current row.
|
||||
late final _scroll = ScrollController(
|
||||
initialScrollOffset: math.max(0, widget.items.indexWhere((i) => i.active) - 3) * UoscMenuPanel.rowHeight);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scroll.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final title = widget.title;
|
||||
return Material(
|
||||
key: const ValueKey('uosc-menu'),
|
||||
color: UoscStyle.panel,
|
||||
borderRadius: BorderRadius.circular(UoscStyle.radius * 2),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
if (title != null)
|
||||
Container(
|
||||
height: 34,
|
||||
alignment: Alignment.center,
|
||||
decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Color(0x22FFFFFF)))),
|
||||
child: Text(title,
|
||||
style: const TextStyle(color: UoscStyle.dim, fontSize: UoscStyle.fontSize, fontWeight: FontWeight.w600)),
|
||||
),
|
||||
Flexible(
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
padding: const EdgeInsets.all(4),
|
||||
controller: _scroll,
|
||||
itemCount: widget.items.length,
|
||||
itemExtent: UoscMenuPanel.rowHeight,
|
||||
itemBuilder: (context, i) => _Row<T>(item: widget.items[i], onPick: widget.onPick),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Row<T> extends StatefulWidget {
|
||||
final UoscMenuItem<T> item;
|
||||
final ValueChanged<T> onPick;
|
||||
const _Row({super.key, required this.item, required this.onPick});
|
||||
|
||||
@override
|
||||
State<_Row<T>> createState() => _RowState<T>();
|
||||
}
|
||||
|
||||
class _RowState<T> extends State<_Row<T>> {
|
||||
bool _hover = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final item = widget.item;
|
||||
final color = item.active
|
||||
? UoscStyle.fill
|
||||
: _hover && item.enabled
|
||||
? UoscStyle.hover
|
||||
: Colors.transparent;
|
||||
final textColor = item.enabled ? UoscStyle.text : UoscStyle.dim.withValues(alpha: 0.4);
|
||||
return MouseRegion(
|
||||
cursor: item.enabled ? SystemMouseCursors.click : SystemMouseCursors.basic,
|
||||
onEnter: (_) => setState(() => _hover = true),
|
||||
onExit: (_) => setState(() => _hover = false),
|
||||
child: GestureDetector(
|
||||
key: ValueKey('uosc-menu-item-${item.title}'),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: item.enabled ? () => widget.onPick(item.value) : null,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(UoscStyle.radius)),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(item.title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontSize: UoscStyle.fontSize,
|
||||
fontWeight: item.active ? FontWeight.w600 : FontWeight.normal)),
|
||||
),
|
||||
if (item.hint != null) ...[
|
||||
const SizedBox(width: 12),
|
||||
Text(item.hint!,
|
||||
style: TextStyle(
|
||||
color: item.active ? UoscStyle.text : UoscStyle.dim,
|
||||
fontSize: 12,
|
||||
fontFeatures: const [FontFeature.tabularFigures()])),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Chapters with their start times, the playing one active.
|
||||
List<UoscMenuItem<MediaChapter>> chapterMenuItems(List<MediaChapter> chapters, int? current, Duration duration) {
|
||||
final withHours = duration >= const Duration(hours: 1);
|
||||
return [
|
||||
for (final c in chapters)
|
||||
UoscMenuItem(
|
||||
value: c,
|
||||
title: c.title.isEmpty ? 'Chapter ${c.index + 1}' : c.title,
|
||||
hint: formatUoscTime(c.start, withHours: withHours),
|
||||
active: c.index == current,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/// The audio or subtitle tracks ("Japanese · E-AC3 2.0 · title"), mpv's
|
||||
/// selection active; subtitles start with Off.
|
||||
List<UoscMenuItem<TrackPick>> trackMenuItems(JellyfinStreamType type, List<MpvTrack> tracks) {
|
||||
final audio = type == JellyfinStreamType.audio;
|
||||
final list = tracks.where((t) => t.type == type).toList();
|
||||
return [
|
||||
if (!audio)
|
||||
UoscMenuItem(
|
||||
value: (aid: null, sid: null, subtitlesOff: true),
|
||||
title: 'Off',
|
||||
active: !list.any((t) => t.selected),
|
||||
),
|
||||
for (final t in list)
|
||||
UoscMenuItem(
|
||||
value: audio ? (aid: t.id, sid: null, subtitlesOff: false) : (aid: null, sid: t.id, subtitlesOff: false),
|
||||
title: t.label,
|
||||
hint: '#${t.id}',
|
||||
active: t.selected,
|
||||
),
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// Look of the experimental mpv-style controls, after the uosc theme as the
|
||||
// owner runs it: flat black panels, white icons, a muted blue fill.
|
||||
|
||||
abstract final class UoscStyle {
|
||||
/// Timeline background and the boxes on it.
|
||||
static const bar = Color(0xCC000000);
|
||||
/// Played part of the timeline; also the active menu row.
|
||||
static const fill = Color(0xFF4C6A8E);
|
||||
/// Menus and tooltips.
|
||||
static const panel = Color(0xF0101010);
|
||||
static const hover = Color(0x24FFFFFF);
|
||||
static const text = Colors.white;
|
||||
static const dim = Color(0xA6FFFFFF);
|
||||
static const radius = 4.0;
|
||||
static const fontSize = 13.0;
|
||||
}
|
||||
|
||||
/// uosc's clock: "01:51", "1:02:03" style but zero-padded ("01:02:03")
|
||||
/// once [withHours] (the media is an hour or longer).
|
||||
String formatUoscTime(Duration d, {bool withHours = false}) {
|
||||
final t = d.isNegative ? Duration.zero : d;
|
||||
String two(int n) => n.toString().padLeft(2, '0');
|
||||
final h = t.inHours, m = t.inMinutes % 60, s = t.inSeconds % 60;
|
||||
return withHours || h > 0 ? '${two(h)}:${two(m)}:${two(s)}' : '${two(m)}:${two(s)}';
|
||||
}
|
||||
|
||||
/// Dark rounded hover tip ("Subtitles"), shown above its child.
|
||||
class UoscTooltip extends StatelessWidget {
|
||||
final String message;
|
||||
final Widget child;
|
||||
const UoscTooltip({super.key, required this.message, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (message.isEmpty) return child;
|
||||
return Tooltip(
|
||||
message: message,
|
||||
preferBelow: false,
|
||||
verticalOffset: 26,
|
||||
waitDuration: const Duration(milliseconds: 250),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: UoscStyle.panel,
|
||||
borderRadius: BorderRadius.circular(UoscStyle.radius),
|
||||
),
|
||||
textStyle: const TextStyle(color: UoscStyle.text, fontSize: 12),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A small dark box with one line of text (the timeline's times, the
|
||||
/// hover chapter title).
|
||||
class UoscBox extends StatelessWidget {
|
||||
final String text;
|
||||
final Color color;
|
||||
final TextStyle style;
|
||||
const UoscBox(
|
||||
this.text, {
|
||||
super.key,
|
||||
this.color = UoscStyle.panel,
|
||||
this.style = const TextStyle(color: UoscStyle.text, fontSize: UoscStyle.fontSize),
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
constraints: const BoxConstraints(maxWidth: 360),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3),
|
||||
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(UoscStyle.radius)),
|
||||
child: Text(text,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: style.copyWith(fontFeatures: const [FontFeature.tabularFigures()])),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../playback/media_marks.dart';
|
||||
import 'controls.dart';
|
||||
import 'style.dart';
|
||||
|
||||
/// Fraction of [total] at [d], 0..1 (0 without a duration).
|
||||
double timelineFraction(Duration d, Duration total) {
|
||||
final t = total.inMicroseconds;
|
||||
if (t <= 0) return 0;
|
||||
return (d.inMicroseconds / t).clamp(0.0, 1.0);
|
||||
}
|
||||
|
||||
/// The cached-ahead part of a timeline of [size]: from the playing
|
||||
/// position to the end of mpv's cache. Null when nothing is cached ahead.
|
||||
Rect? cacheRect(Size size, {required Duration position, required Duration buffered, required Duration duration}) {
|
||||
final from = timelineFraction(position, duration) * size.width;
|
||||
final to = timelineFraction(buffered, duration) * size.width;
|
||||
if (to - from < 0.5) return null;
|
||||
return Rect.fromLTRB(from, 0, to, size.height);
|
||||
}
|
||||
|
||||
/// The hatching of [r]: 45° strokes from bottom-left to top-right,
|
||||
/// [spacing] apart along x, across all of [r] (the painter clips them).
|
||||
/// The first starts half a step in, so none just grazes the corner.
|
||||
List<(Offset, Offset)> hatchLines(Rect r, {double spacing = 6}) {
|
||||
if (r.isEmpty || spacing <= 0) return const [];
|
||||
final h = r.height;
|
||||
return [
|
||||
for (var x = r.left - h + spacing / 2; x < r.right; x += spacing) (Offset(x, r.bottom), Offset(x + h, r.top)),
|
||||
];
|
||||
}
|
||||
|
||||
/// The uosc timeline: full width, elapsed part filled, the cached range
|
||||
/// ahead hatched, chapter starts as white diamonds on the top edge, the
|
||||
/// current time in a box at the left and the duration at the right.
|
||||
/// Hover shows the chapter title over the hover time. When the controls
|
||||
/// hide ([expanded] false) it shrinks to a thin line with chapter ticks.
|
||||
/// Like the media_kit bar it reports a seek on every drag move and on
|
||||
/// release ([onSeek]); the session sends those through the user-seek path.
|
||||
class UoscTimeline extends StatefulWidget {
|
||||
final Duration position;
|
||||
final Duration duration;
|
||||
/// End of the cached range ([PlaybackController.buffered]).
|
||||
final Duration buffered;
|
||||
final List<MediaChapter> chapters;
|
||||
final bool expanded;
|
||||
final ValueChanged<Duration> onSeek;
|
||||
const UoscTimeline({
|
||||
super.key,
|
||||
required this.position,
|
||||
required this.duration,
|
||||
this.buffered = Duration.zero,
|
||||
this.chapters = const [],
|
||||
this.expanded = true,
|
||||
required this.onSeek,
|
||||
});
|
||||
|
||||
static const height = 30.0;
|
||||
static const collapsedHeight = 3.0;
|
||||
|
||||
@override
|
||||
State<UoscTimeline> createState() => _UoscTimelineState();
|
||||
}
|
||||
|
||||
class _UoscTimelineState extends State<UoscTimeline> {
|
||||
double? _hoverX;
|
||||
bool _dragging = false;
|
||||
double _dragFraction = 0;
|
||||
|
||||
Duration _at(double fraction) => widget.duration * fraction.clamp(0.0, 1.0);
|
||||
|
||||
void _seekTo(double x, double width) {
|
||||
if (widget.duration <= Duration.zero || width <= 0) return;
|
||||
_dragFraction = (x / width).clamp(0.0, 1.0);
|
||||
widget.onSeek(_at(_dragFraction));
|
||||
}
|
||||
|
||||
void _drag(bool on) {
|
||||
if (_dragging == on) return;
|
||||
setState(() => _dragging = on);
|
||||
UoscControls.maybeOf(context)?.hold(on);
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(UoscTimeline old) {
|
||||
super.didUpdateWidget(old);
|
||||
if (!widget.expanded && old.expanded) _hoverX = null;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// A drag cut short by a rebuild must not keep the controls up.
|
||||
if (_dragging) UoscControls.maybeOf(context)?.hold(false);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
final width = constraints.maxWidth;
|
||||
final expanded = widget.expanded;
|
||||
final h = expanded ? UoscTimeline.height : UoscTimeline.collapsedHeight;
|
||||
final played = _dragging ? _dragFraction : timelineFraction(widget.position, widget.duration);
|
||||
final hoverX = expanded ? _hoverX : null;
|
||||
final hoverAt = hoverX == null || width <= 0 ? null : _at(hoverX / width);
|
||||
final hoverChapter = hoverAt == null ? null : chapterIndexAt(widget.chapters, hoverAt);
|
||||
final hoverTitle = hoverChapter == null ? '' : widget.chapters[hoverChapter].title;
|
||||
final withHours = widget.duration >= const Duration(hours: 1);
|
||||
final marks = [
|
||||
for (final c in widget.chapters)
|
||||
if (c.start > Duration.zero && widget.duration > Duration.zero) c,
|
||||
];
|
||||
final bar = SizedBox(
|
||||
key: const ValueKey('uosc-timeline'),
|
||||
width: width,
|
||||
height: h,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: CustomPaint(
|
||||
painter: UoscTimelinePainter(
|
||||
played: played,
|
||||
cache: (size) => cacheRect(size,
|
||||
position: widget.position, buffered: widget.buffered, duration: widget.duration),
|
||||
cacheKey: (widget.position, widget.buffered, widget.duration),
|
||||
hoverX: _dragging ? null : hoverX,
|
||||
hatched: expanded,
|
||||
),
|
||||
),
|
||||
),
|
||||
for (final c in marks)
|
||||
if (expanded)
|
||||
Positioned(
|
||||
key: ValueKey('uosc-chapter-${c.index}'),
|
||||
left: width * timelineFraction(c.start, widget.duration) - 4,
|
||||
top: -4,
|
||||
width: 8,
|
||||
height: 8,
|
||||
child: IgnorePointer(
|
||||
child: Transform.rotate(
|
||||
angle: math.pi / 4,
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(1.2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border.all(color: Colors.black54, width: 0.6),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
Positioned(
|
||||
key: ValueKey('uosc-chapter-tick-${c.index}'),
|
||||
left: width * timelineFraction(c.start, widget.duration) - 1,
|
||||
top: -2,
|
||||
width: 2,
|
||||
height: h + 2,
|
||||
child: const IgnorePointer(child: ColoredBox(color: Colors.white70)),
|
||||
),
|
||||
if (expanded) ...[
|
||||
Positioned(
|
||||
left: 4,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: IgnorePointer(
|
||||
child: Center(
|
||||
child: UoscBox(formatUoscTime(_at(played), withHours: withHours),
|
||||
key: const ValueKey('uosc-time'), color: UoscStyle.bar),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 4,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: IgnorePointer(
|
||||
child: Center(
|
||||
child: UoscBox(formatUoscTime(widget.duration, withHours: withHours),
|
||||
key: const ValueKey('uosc-duration'), color: UoscStyle.bar),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (hoverAt != null)
|
||||
Positioned(
|
||||
// Kept clear of the window edges (the tip is centred).
|
||||
left: hoverX!.clamp(math.min(60.0, width / 2), math.max(width - 60, width / 2)),
|
||||
bottom: h + 8,
|
||||
child: IgnorePointer(
|
||||
child: FractionalTranslation(
|
||||
translation: const Offset(-0.5, 0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 4,
|
||||
children: [
|
||||
if (hoverTitle.isNotEmpty) UoscBox(hoverTitle, key: const ValueKey('uosc-hover-chapter')),
|
||||
UoscBox(formatUoscTime(hoverAt, withHours: withHours),
|
||||
key: const ValueKey('uosc-hover-time')),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (!expanded) return IgnorePointer(child: bar);
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (e) => setState(() => _hoverX = e.localPosition.dx.clamp(0, width)),
|
||||
onHover: (e) => setState(() => _hoverX = e.localPosition.dx.clamp(0, width)),
|
||||
onExit: (_) => setState(() => _hoverX = null),
|
||||
child: Listener(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onPointerDown: (e) {
|
||||
_dragFraction = width <= 0 ? 0 : (e.localPosition.dx / width).clamp(0.0, 1.0);
|
||||
_drag(true);
|
||||
},
|
||||
onPointerMove: (e) {
|
||||
setState(() => _hoverX = e.localPosition.dx.clamp(0, width));
|
||||
_seekTo(e.localPosition.dx, width);
|
||||
},
|
||||
onPointerUp: (e) {
|
||||
_seekTo(e.localPosition.dx, width);
|
||||
_drag(false);
|
||||
},
|
||||
onPointerCancel: (_) => _drag(false),
|
||||
child: bar,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Background, cached range (hatched, or a faint band when collapsed),
|
||||
/// the played part and the hover line.
|
||||
class UoscTimelinePainter extends CustomPainter {
|
||||
final double played;
|
||||
final Rect? Function(Size size) cache;
|
||||
/// What [cache] depends on (repaint when it changes).
|
||||
final Object cacheKey;
|
||||
final double? hoverX;
|
||||
final bool hatched;
|
||||
const UoscTimelinePainter({
|
||||
required this.played,
|
||||
required this.cache,
|
||||
required this.cacheKey,
|
||||
this.hoverX,
|
||||
this.hatched = true,
|
||||
});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final all = Offset.zero & size;
|
||||
canvas.drawRect(all, Paint()..color = UoscStyle.bar);
|
||||
final c = cache(size);
|
||||
if (c != null) {
|
||||
if (hatched) {
|
||||
canvas.save();
|
||||
canvas.clipRect(c);
|
||||
final stroke = Paint()
|
||||
..color = const Color(0x40FFFFFF)
|
||||
..strokeWidth = 1.5;
|
||||
for (final (a, b) in hatchLines(c)) {
|
||||
canvas.drawLine(a, b, stroke);
|
||||
}
|
||||
canvas.restore();
|
||||
} else {
|
||||
canvas.drawRect(c, Paint()..color = const Color(0x40FFFFFF));
|
||||
}
|
||||
}
|
||||
canvas.drawRect(Rect.fromLTWH(0, 0, size.width * played, size.height), Paint()..color = UoscStyle.fill);
|
||||
final x = hoverX;
|
||||
if (x != null) {
|
||||
canvas.drawRect(Rect.fromLTWH(x - 0.5, 0, 1, size.height), Paint()..color = Colors.white70);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(UoscTimelinePainter old) =>
|
||||
old.played != played || old.cacheKey != cacheKey || old.hoverX != hoverX || old.hatched != hatched;
|
||||
}
|
||||
@@ -0,0 +1,523 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import '../screens/home/picked_media.dart';
|
||||
import '../screens/home/ui.dart' show appName;
|
||||
import '../update/updater.dart' show appVersion;
|
||||
|
||||
// Linked Jellyfin servers, one account per ServerId, in their own Hive box.
|
||||
//
|
||||
// Only tokens this app obtained itself (Quick Connect or password through
|
||||
// [JellyfinSignIn]) are ever stored or used: Jellyfin overwrites a token's
|
||||
// device name and app version with whatever header comes with it, so
|
||||
// borrowing another client's token would rename that client's device.
|
||||
|
||||
const jellyfinBoxName = 'jellyfin';
|
||||
const _keyDeviceId = 'deviceId';
|
||||
const _keyAccounts = 'accounts';
|
||||
const _keyDefault = 'defaultServer';
|
||||
const _keyLastPick = 'lastPick';
|
||||
const _keyBrowsePrefix = 'browse:';
|
||||
|
||||
/// One signed-in user on one server.
|
||||
class JellyfinAccount {
|
||||
final String serverId;
|
||||
final String serverName;
|
||||
final String serverVersion;
|
||||
/// Addresses this server was reached at, preferred first.
|
||||
final List<String> urls;
|
||||
final String userId;
|
||||
final String userName;
|
||||
final String? userImageTag;
|
||||
final String token;
|
||||
const JellyfinAccount({
|
||||
required this.serverId,
|
||||
required this.serverName,
|
||||
this.serverVersion = '',
|
||||
required this.urls,
|
||||
required this.userId,
|
||||
required this.userName,
|
||||
this.userImageTag,
|
||||
required this.token,
|
||||
});
|
||||
|
||||
String get baseUrl => urls.first;
|
||||
|
||||
JellyfinUser get user =>
|
||||
JellyfinUser(id: userId, name: userName, serverId: serverId, primaryImageTag: userImageTag);
|
||||
|
||||
/// "Example Server" or the host when the server has no name.
|
||||
String get displayName =>
|
||||
serverName.isNotEmpty ? serverName : (Uri.tryParse(baseUrl)?.host ?? baseUrl);
|
||||
|
||||
JellyfinAccount copyWith({
|
||||
String? serverName,
|
||||
String? serverVersion,
|
||||
List<String>? urls,
|
||||
String? userName,
|
||||
String? userImageTag,
|
||||
}) =>
|
||||
JellyfinAccount(
|
||||
serverId: serverId,
|
||||
serverName: serverName ?? this.serverName,
|
||||
serverVersion: serverVersion ?? this.serverVersion,
|
||||
urls: urls ?? this.urls,
|
||||
userId: userId,
|
||||
userName: userName ?? this.userName,
|
||||
userImageTag: userImageTag ?? this.userImageTag,
|
||||
token: token,
|
||||
);
|
||||
|
||||
Map<String, Object?> toJson() => {
|
||||
'serverId': serverId,
|
||||
'serverName': serverName,
|
||||
'serverVersion': serverVersion,
|
||||
'urls': urls,
|
||||
'userId': userId,
|
||||
'userName': userName,
|
||||
'userImageTag': ?userImageTag,
|
||||
'token': token,
|
||||
};
|
||||
|
||||
static JellyfinAccount? fromJson(Object? j) {
|
||||
if (j is! Map) return null;
|
||||
final sid = j['serverId'], uid = j['userId'], token = j['token'], urls = j['urls'];
|
||||
if (sid is! String || uid is! String || token is! String || urls is! List) return null;
|
||||
final list = urls.whereType<String>().toList();
|
||||
if (sid.isEmpty || token.isEmpty || list.isEmpty) return null;
|
||||
String s(Object? v) => v is String ? v : '';
|
||||
return JellyfinAccount(
|
||||
serverId: sid,
|
||||
serverName: s(j['serverName']),
|
||||
serverVersion: s(j['serverVersion']),
|
||||
urls: list,
|
||||
userId: uid,
|
||||
userName: s(j['userName']),
|
||||
userImageTag: j['userImageTag'] is String ? j['userImageTag'] as String : null,
|
||||
token: token,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum JellyfinAccountStatus {
|
||||
/// Not checked yet this run.
|
||||
unknown,
|
||||
checking,
|
||||
online,
|
||||
/// Unreachable (network error); the token may still be fine.
|
||||
offline,
|
||||
/// The server rejected the token: sign in again ("Reconnect").
|
||||
expired,
|
||||
}
|
||||
|
||||
/// Key-value persistence behind [JellyfinAccounts]; tests use
|
||||
/// [MemoryJellyfinStore].
|
||||
abstract class JellyfinStore {
|
||||
Future<void> open();
|
||||
Object? get(String key);
|
||||
Future<void> put(String key, Object? value);
|
||||
}
|
||||
|
||||
class HiveJellyfinStore implements JellyfinStore {
|
||||
HiveJellyfinStore({this.boxName = jellyfinBoxName});
|
||||
final String boxName;
|
||||
Box? _box;
|
||||
|
||||
@override
|
||||
Future<void> open() async => _box ??= await Hive.openBox(boxName);
|
||||
|
||||
@override
|
||||
Object? get(String key) => _box?.get(key);
|
||||
|
||||
@override
|
||||
Future<void> put(String key, Object? value) async {
|
||||
final box = _box;
|
||||
if (box == null) return;
|
||||
value == null ? await box.delete(key) : await box.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
class MemoryJellyfinStore implements JellyfinStore {
|
||||
final Map<String, Object?> data;
|
||||
MemoryJellyfinStore([Map<String, Object?>? data]) : data = data ?? {};
|
||||
|
||||
@override
|
||||
Future<void> open() async {}
|
||||
@override
|
||||
Object? get(String key) => data[key];
|
||||
@override
|
||||
Future<void> put(String key, Object? value) async =>
|
||||
value == null ? data.remove(key) : data[key] = value;
|
||||
}
|
||||
|
||||
/// All linked Jellyfin servers, their live status and one authenticated
|
||||
/// [JellyfinClient] each. [ensureLoaded] reads the box and then checks every
|
||||
/// token in the background; a rejected token turns the account
|
||||
/// [JellyfinAccountStatus.expired] (shown as "Reconnect"), never a silent
|
||||
/// sign-out.
|
||||
class JellyfinAccounts extends ChangeNotifier {
|
||||
static final JellyfinAccounts instance = JellyfinAccounts();
|
||||
|
||||
JellyfinAccounts({
|
||||
JellyfinStore? store,
|
||||
this.httpFactory,
|
||||
this.deviceName,
|
||||
}) : _store = store ?? HiveJellyfinStore();
|
||||
|
||||
final JellyfinStore _store;
|
||||
/// Transport for every client made here; null = real HTTP. Tests fake it.
|
||||
final JellyfinHttp Function()? httpFactory;
|
||||
/// Device name sent to Jellyfin; null = the hostname.
|
||||
final String? deviceName;
|
||||
|
||||
List<JellyfinAccount> _accounts = const [];
|
||||
final _status = <String, JellyfinAccountStatus>{};
|
||||
final _errors = <String, String>{};
|
||||
final _clients = <String, JellyfinClient>{};
|
||||
final _memo = <String, ({DateTime at, Future<Object?> value})>{};
|
||||
String? _defaultServerId;
|
||||
String _deviceId = '';
|
||||
JellyfinMedia? _lastPick;
|
||||
Future<void>? _load;
|
||||
bool _loaded = false;
|
||||
bool _disposed = false;
|
||||
|
||||
List<JellyfinAccount> get accounts => _accounts;
|
||||
bool get loaded => _loaded;
|
||||
bool get isEmpty => _accounts.isEmpty;
|
||||
|
||||
JellyfinAccount? account(String serverId) =>
|
||||
_accounts.where((a) => a.serverId == serverId).firstOrNull;
|
||||
|
||||
/// The chosen default, else the first linked server.
|
||||
JellyfinAccount? get defaultAccount =>
|
||||
(_defaultServerId == null ? null : account(_defaultServerId!)) ?? _accounts.firstOrNull;
|
||||
|
||||
String? get defaultServerId => defaultAccount?.serverId;
|
||||
|
||||
JellyfinAccountStatus statusOf(String serverId) =>
|
||||
_status[serverId] ?? JellyfinAccountStatus.unknown;
|
||||
|
||||
/// Last failure text for an offline account.
|
||||
String? errorOf(String serverId) => _errors[serverId];
|
||||
|
||||
/// The Host tab's last Jellyfin pick, restored on the next start.
|
||||
JellyfinMedia? get lastPick => _lastPick;
|
||||
|
||||
/// Stable per install: Jellyfin keys devices and tokens by it.
|
||||
String get deviceId => _deviceId;
|
||||
|
||||
JellyfinClientInfo get clientInfo => JellyfinClientInfo(
|
||||
client: appName,
|
||||
device: deviceName ?? _hostname(),
|
||||
deviceId: _deviceId.isEmpty ? 'unknown' : _deviceId,
|
||||
version: appVersion,
|
||||
);
|
||||
|
||||
static String _hostname() {
|
||||
try {
|
||||
final h = Platform.localHostname;
|
||||
return h.isEmpty ? 'Desktop' : h;
|
||||
} catch (_) {
|
||||
return 'Desktop';
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> ensureLoaded({bool validate = true}) =>
|
||||
_load ??= _loadNow(validate: validate);
|
||||
|
||||
Future<void> _loadNow({required bool validate}) async {
|
||||
try {
|
||||
await _store.open();
|
||||
final id = _store.get(_keyDeviceId);
|
||||
if (id is String && id.isNotEmpty) {
|
||||
_deviceId = id;
|
||||
} else {
|
||||
_deviceId = _newDeviceId();
|
||||
await _store.put(_keyDeviceId, _deviceId);
|
||||
}
|
||||
_accounts = _decodeAccounts(_store.get(_keyAccounts));
|
||||
final def = _store.get(_keyDefault);
|
||||
_defaultServerId = def is String ? def : null;
|
||||
final pick = _store.get(_keyLastPick);
|
||||
_lastPick = pick is String ? JellyfinMedia.fromJson(_tryJson(pick)) : null;
|
||||
} catch (e, st) {
|
||||
debugPrint('load jellyfin accounts failed: $e\n$st');
|
||||
if (_deviceId.isEmpty) _deviceId = _newDeviceId();
|
||||
}
|
||||
_loaded = true;
|
||||
_notify();
|
||||
if (validate) unawaited(validateAll());
|
||||
}
|
||||
|
||||
static String _newDeviceId() {
|
||||
final r = Random.secure();
|
||||
return [for (var i = 0; i < 16; i++) r.nextInt(256).toRadixString(16).padLeft(2, '0')].join();
|
||||
}
|
||||
|
||||
static Object? _tryJson(String s) {
|
||||
try {
|
||||
return jsonDecode(s);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static List<JellyfinAccount> _decodeAccounts(Object? raw) {
|
||||
if (raw is! String) return const [];
|
||||
final list = _tryJson(raw);
|
||||
if (list is! List) return const [];
|
||||
final out = <JellyfinAccount>[];
|
||||
for (final j in list) {
|
||||
final a = JellyfinAccount.fromJson(j);
|
||||
if (a != null && out.every((o) => o.serverId != a.serverId)) out.add(a);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Future<void> _save() async {
|
||||
try {
|
||||
await _store.put(_keyAccounts, jsonEncode([for (final a in _accounts) a.toJson()]));
|
||||
await _store.put(_keyDefault, _defaultServerId);
|
||||
} catch (e, st) {
|
||||
debugPrint('save jellyfin accounts failed: $e\n$st');
|
||||
}
|
||||
}
|
||||
|
||||
void _notify() {
|
||||
if (!_disposed) notifyListeners();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------- clients
|
||||
|
||||
/// A client without a token, for probing an address and signing in.
|
||||
/// The caller closes it.
|
||||
JellyfinClient anonymousClient(String baseUrl) =>
|
||||
JellyfinClient(baseUrl: baseUrl, clientInfo: clientInfo, http: httpFactory?.call());
|
||||
|
||||
/// The signed-in client of a linked server (null if not linked). Shared;
|
||||
/// do not close it.
|
||||
JellyfinClient? clientFor(String serverId) {
|
||||
final a = account(serverId);
|
||||
if (a == null) return null;
|
||||
final c = _clients[serverId];
|
||||
if (c != null && c.baseUrl == a.baseUrl && c.accessToken == a.token) return c;
|
||||
c?.close();
|
||||
return _clients[serverId] = JellyfinClient(
|
||||
baseUrl: a.baseUrl,
|
||||
clientInfo: clientInfo,
|
||||
accessToken: a.token,
|
||||
userId: a.userId,
|
||||
http: httpFactory?.call(),
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------- validation
|
||||
|
||||
Future<void> validateAll() => Future.wait([for (final a in _accounts) validate(a.serverId)]);
|
||||
|
||||
/// Checks the saved token. Tries each known address in order and moves
|
||||
/// the first that answers to the front.
|
||||
Future<JellyfinAccountStatus> validate(String serverId) async {
|
||||
final start = account(serverId);
|
||||
if (start == null) return JellyfinAccountStatus.unknown;
|
||||
_status[serverId] = JellyfinAccountStatus.checking;
|
||||
_notify();
|
||||
Object? lastError;
|
||||
for (final url in start.urls) {
|
||||
final client = JellyfinClient(
|
||||
baseUrl: url,
|
||||
clientInfo: clientInfo,
|
||||
accessToken: start.token,
|
||||
userId: start.userId,
|
||||
http: httpFactory?.call(),
|
||||
);
|
||||
try {
|
||||
final user = await client.validateToken();
|
||||
if (user == null) return _setStatus(serverId, JellyfinAccountStatus.expired);
|
||||
final a = account(serverId);
|
||||
if (a == null) return JellyfinAccountStatus.unknown;
|
||||
_replace(a.copyWith(
|
||||
userName: user.name.isEmpty ? null : user.name,
|
||||
userImageTag: user.primaryImageTag,
|
||||
urls: [url, ...a.urls.where((u) => u != url)],
|
||||
));
|
||||
unawaited(_save());
|
||||
_errors.remove(serverId);
|
||||
return _setStatus(serverId, JellyfinAccountStatus.online);
|
||||
} catch (e) {
|
||||
lastError = e;
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
_errors[serverId] = _short(lastError);
|
||||
return _setStatus(serverId, JellyfinAccountStatus.offline);
|
||||
}
|
||||
|
||||
static String _short(Object? e) {
|
||||
final s = '$e'.replaceFirst('JellyfinException: ', '');
|
||||
return s.length > 160 ? '${s.substring(0, 160)}…' : s;
|
||||
}
|
||||
|
||||
JellyfinAccountStatus _setStatus(String serverId, JellyfinAccountStatus s) {
|
||||
_status[serverId] = s;
|
||||
_notify();
|
||||
return s;
|
||||
}
|
||||
|
||||
/// A browse call got 401: the token is gone, ask to reconnect.
|
||||
void markExpired(String serverId) {
|
||||
if (statusOf(serverId) == JellyfinAccountStatus.expired) return;
|
||||
_setStatus(serverId, JellyfinAccountStatus.expired);
|
||||
}
|
||||
|
||||
void _replace(JellyfinAccount a) {
|
||||
_accounts = [for (final o in _accounts) o.serverId == a.serverId ? a : o];
|
||||
}
|
||||
|
||||
// ------------------------------------------------------- link / unlink
|
||||
|
||||
/// Stores a sign-in made by this app. Signing in again to a linked server
|
||||
/// replaces its account (and best-effort revokes the old token).
|
||||
Future<JellyfinAccount> link({
|
||||
required String baseUrl,
|
||||
required JellyfinServerInfo server,
|
||||
required JellyfinAuthResult auth,
|
||||
}) async {
|
||||
await ensureLoaded(validate: false);
|
||||
final serverId = auth.serverId.isNotEmpty ? auth.serverId : server.id;
|
||||
final old = account(serverId);
|
||||
final a = JellyfinAccount(
|
||||
serverId: serverId,
|
||||
serverName: server.name,
|
||||
serverVersion: server.version,
|
||||
urls: [baseUrl, ...?old?.urls.where((u) => u != baseUrl)],
|
||||
userId: auth.user.id,
|
||||
userName: auth.user.name,
|
||||
userImageTag: auth.user.primaryImageTag,
|
||||
token: auth.accessToken,
|
||||
);
|
||||
if (old != null && old.token != a.token) unawaited(_revoke(old));
|
||||
_accounts = old == null ? [..._accounts, a] : [for (final o in _accounts) o.serverId == serverId ? a : o];
|
||||
_defaultServerId ??= serverId;
|
||||
_status[serverId] = JellyfinAccountStatus.online;
|
||||
_errors.remove(serverId);
|
||||
_clearMemo(serverId);
|
||||
await _save();
|
||||
_notify();
|
||||
return a;
|
||||
}
|
||||
|
||||
Future<void> _revoke(JellyfinAccount a) async {
|
||||
final c = JellyfinClient(
|
||||
baseUrl: a.baseUrl,
|
||||
clientInfo: clientInfo,
|
||||
accessToken: a.token,
|
||||
userId: a.userId,
|
||||
http: httpFactory?.call());
|
||||
try {
|
||||
await c.logout();
|
||||
} catch (_) {
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
/// Revokes the token on the server (best effort: an offline server or an
|
||||
/// already dead token still unlinks) and forgets the account.
|
||||
Future<void> signOut(String serverId) async {
|
||||
final a = account(serverId);
|
||||
if (a == null) return;
|
||||
final c = _clients.remove(serverId);
|
||||
c?.close();
|
||||
await _revoke(a).timeout(const Duration(seconds: 8), onTimeout: () {});
|
||||
_accounts = [for (final o in _accounts) if (o.serverId != serverId) o];
|
||||
_status.remove(serverId);
|
||||
_errors.remove(serverId);
|
||||
_clearMemo(serverId);
|
||||
if (_defaultServerId == serverId) _defaultServerId = _accounts.firstOrNull?.serverId;
|
||||
if (_lastPick?.serverId == serverId) await rememberPick(null);
|
||||
await _save();
|
||||
_notify();
|
||||
}
|
||||
|
||||
Future<void> setDefault(String serverId) async {
|
||||
if (account(serverId) == null || _defaultServerId == serverId) return;
|
||||
_defaultServerId = serverId;
|
||||
_notify();
|
||||
await _save();
|
||||
}
|
||||
|
||||
Future<void> rememberPick(JellyfinMedia? pick) async {
|
||||
_lastPick = pick;
|
||||
try {
|
||||
await _store.put(_keyLastPick, pick == null ? null : jsonEncode(pick.toJson()));
|
||||
} catch (e) {
|
||||
debugPrint('save jellyfin pick failed: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// The browser's last location on [serverId] (encoded route stack, see
|
||||
/// `browse_scope.dart`), restored by every browser and across restarts.
|
||||
Object? browseLocation(String serverId) {
|
||||
try {
|
||||
final v = _store.get('$_keyBrowsePrefix$serverId');
|
||||
return v is String ? _tryJson(v) : null;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> saveBrowseLocation(String serverId, Object? location) async {
|
||||
try {
|
||||
await _store.put(
|
||||
'$_keyBrowsePrefix$serverId', location == null ? null : jsonEncode(location));
|
||||
} catch (e) {
|
||||
debugPrint('save browse location failed: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- cache
|
||||
|
||||
/// Short-lived memo for browse calls, so going back does not refetch.
|
||||
/// Failures are not kept; a 401 marks the account expired.
|
||||
Future<T> cached<T>(String serverId, String key, Future<T> Function() load,
|
||||
{Duration ttl = const Duration(minutes: 3)}) {
|
||||
final k = '$serverId|$key';
|
||||
final hit = _memo[k];
|
||||
if (hit != null && DateTime.now().difference(hit.at) < ttl) {
|
||||
return hit.value.then((v) => v as T);
|
||||
}
|
||||
final f = load();
|
||||
_memo[k] = (at: DateTime.now(), value: f);
|
||||
f.catchError((Object e) {
|
||||
if (identical(_memo[k]?.value, f)) _memo.remove(k);
|
||||
if (e is JellyfinException && e.isUnauthorized) markExpired(serverId);
|
||||
throw e;
|
||||
}).ignore();
|
||||
return f;
|
||||
}
|
||||
|
||||
void _clearMemo(String serverId) =>
|
||||
_memo.removeWhere((k, _) => k.startsWith('$serverId|'));
|
||||
|
||||
/// Drops cached browse results (refresh button, after a pick).
|
||||
void invalidate(String serverId) => _clearMemo(serverId);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_disposed = true;
|
||||
for (final c in _clients.values) {
|
||||
c.close();
|
||||
}
|
||||
_clients.clear();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../screens/home/ui.dart';
|
||||
import 'accounts.dart';
|
||||
import 'browser.dart' show JellyfinAvatar, StatusDot, showReconnectDialog;
|
||||
import 'sign_in_panel.dart';
|
||||
|
||||
/// Integrations > Jellyfin: linked servers (avatar, status, default,
|
||||
/// reconnect, sign out) and the inline add-server flow.
|
||||
class JellyfinAccountsPanel extends StatefulWidget {
|
||||
final JellyfinAccounts accounts;
|
||||
final Duration pollInterval;
|
||||
const JellyfinAccountsPanel({
|
||||
super.key,
|
||||
required this.accounts,
|
||||
this.pollInterval = const Duration(seconds: 3),
|
||||
});
|
||||
|
||||
@override
|
||||
State<JellyfinAccountsPanel> createState() => _JellyfinAccountsPanelState();
|
||||
}
|
||||
|
||||
class _JellyfinAccountsPanelState extends State<JellyfinAccountsPanel> {
|
||||
bool _adding = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
widget.accounts.ensureLoaded();
|
||||
}
|
||||
|
||||
Future<void> _signOut(JellyfinAccount a) async {
|
||||
final ok = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('Sign out of ${a.displayName}?'),
|
||||
content: const Text(
|
||||
'This app\'s sign-in is revoked on the server and the server is unlinked. '
|
||||
'You can add it again any time.'),
|
||||
actions: [
|
||||
TextButton(onPressed: () => Navigator.pop(context, false), child: const Text('Cancel')),
|
||||
FilledButton(
|
||||
key: const ValueKey('jf-sign-out-confirm'),
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: const Text('Sign out')),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (ok == true) await widget.accounts.signOut(a.serverId);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return ListenableBuilder(
|
||||
listenable: widget.accounts,
|
||||
builder: (context, _) {
|
||||
final list = widget.accounts.accounts;
|
||||
return Panel(
|
||||
key: const ValueKey('jf-accounts'),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(Icons.video_library_outlined,
|
||||
size: 32, color: Theme.of(context).colorScheme.primary),
|
||||
const SizedBox(width: kGap),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Jellyfin', style: t.titleMedium),
|
||||
const SizedBox(height: 4),
|
||||
const Text(
|
||||
'Browse your libraries in the Host tab and put up movies and episodes. '
|
||||
'Sign in with Quick Connect or your password; several servers are fine.',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: kGap),
|
||||
if (!_adding)
|
||||
FilledButton.icon(
|
||||
key: const ValueKey('jf-add-server'),
|
||||
onPressed: () => setState(() => _adding = true),
|
||||
icon: const Icon(Icons.add, size: 18),
|
||||
label: const Text('Add server'),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (list.isNotEmpty) const SizedBox(height: kGap),
|
||||
for (final a in list)
|
||||
_AccountTile(
|
||||
accounts: widget.accounts,
|
||||
account: a,
|
||||
isDefault: widget.accounts.defaultServerId == a.serverId,
|
||||
showDefault: list.length > 1,
|
||||
onSignOut: () => _signOut(a),
|
||||
),
|
||||
if (_adding) ...[
|
||||
const SizedBox(height: kGap),
|
||||
const Divider(height: 1),
|
||||
const SizedBox(height: kGap),
|
||||
JellyfinSignInPanel(
|
||||
accounts: widget.accounts,
|
||||
pollInterval: widget.pollInterval,
|
||||
onCancel: () => setState(() => _adding = false),
|
||||
onDone: (_) => setState(() => _adding = false),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AccountTile extends StatelessWidget {
|
||||
final JellyfinAccounts accounts;
|
||||
final JellyfinAccount account;
|
||||
final bool isDefault;
|
||||
final bool showDefault;
|
||||
final VoidCallback onSignOut;
|
||||
const _AccountTile({
|
||||
required this.accounts,
|
||||
required this.account,
|
||||
required this.isDefault,
|
||||
required this.showDefault,
|
||||
required this.onSignOut,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
final status = accounts.statusOf(account.serverId);
|
||||
final statusText = switch (status) {
|
||||
JellyfinAccountStatus.online => 'Connected',
|
||||
JellyfinAccountStatus.offline => 'Offline',
|
||||
JellyfinAccountStatus.expired => 'Sign-in expired',
|
||||
JellyfinAccountStatus.checking => 'Checking…',
|
||||
JellyfinAccountStatus.unknown => 'Not checked',
|
||||
};
|
||||
return Padding(
|
||||
key: ValueKey('jf-account-${account.serverId}'),
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: Row(
|
||||
children: [
|
||||
JellyfinAvatar(accounts: accounts, account: account),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('${account.userName} on ${account.displayName}', style: t.titleSmall),
|
||||
Row(children: [
|
||||
StatusDot(status: status),
|
||||
const SizedBox(width: 6),
|
||||
Flexible(
|
||||
child: Text(
|
||||
[
|
||||
statusText,
|
||||
if (account.serverVersion.isNotEmpty) 'Jellyfin ${account.serverVersion}',
|
||||
account.baseUrl,
|
||||
].join(' · '),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: t.bodySmall?.copyWith(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
]),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (showDefault)
|
||||
IconButton(
|
||||
key: ValueKey('jf-default-${account.serverId}'),
|
||||
tooltip: isDefault ? 'Default server' : 'Make default',
|
||||
onPressed: () => accounts.setDefault(account.serverId),
|
||||
icon: Icon(isDefault ? Icons.star : Icons.star_border,
|
||||
color: isDefault ? Theme.of(context).colorScheme.primary : null),
|
||||
),
|
||||
if (status == JellyfinAccountStatus.expired)
|
||||
FilledButton.tonal(
|
||||
key: ValueKey('jf-reconnect-${account.serverId}'),
|
||||
onPressed: () => showReconnectDialog(context, accounts, account),
|
||||
child: const Text('Reconnect'),
|
||||
)
|
||||
else if (status == JellyfinAccountStatus.offline)
|
||||
TextButton(
|
||||
onPressed: () => accounts.validate(account.serverId),
|
||||
child: const Text('Retry'),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
TextButton(
|
||||
key: ValueKey('jf-sign-out-${account.serverId}'),
|
||||
onPressed: onSignOut,
|
||||
child: const Text('Sign out'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'accounts.dart';
|
||||
import 'format.dart';
|
||||
|
||||
/// One level of the library browser's back stack.
|
||||
sealed class BrowseRoute {
|
||||
const BrowseRoute();
|
||||
String get label;
|
||||
/// Identity for keeping a page's state while it is in the stack.
|
||||
String get key;
|
||||
}
|
||||
|
||||
final class HomeRoute extends BrowseRoute {
|
||||
const HomeRoute();
|
||||
@override
|
||||
String get label => 'Home';
|
||||
@override
|
||||
String get key => 'home';
|
||||
}
|
||||
|
||||
/// A library or folder grid.
|
||||
final class LibraryRoute extends BrowseRoute {
|
||||
final JellyfinItem folder;
|
||||
const LibraryRoute(this.folder);
|
||||
@override
|
||||
String get label => folder.name;
|
||||
@override
|
||||
String get key => 'lib:${folder.id}';
|
||||
}
|
||||
|
||||
final class SeriesRoute extends BrowseRoute {
|
||||
final JellyfinItem series;
|
||||
/// Season to open on (from a season card or an episode's "open series").
|
||||
final String? seasonId;
|
||||
const SeriesRoute(this.series, {this.seasonId});
|
||||
@override
|
||||
String get label => series.name;
|
||||
@override
|
||||
String get key => 'series:${series.id}';
|
||||
}
|
||||
|
||||
/// Movie / episode / video detail.
|
||||
final class DetailRoute extends BrowseRoute {
|
||||
final JellyfinItem item;
|
||||
const DetailRoute(this.item);
|
||||
@override
|
||||
String get label => item.kind == JellyfinItemKind.episode
|
||||
? (item.episodeLabel ?? item.name)
|
||||
: item.name;
|
||||
@override
|
||||
String get key => 'item:${item.id}';
|
||||
}
|
||||
|
||||
/// A route stack as JSON for [JellyfinAccounts.saveBrowseLocation]: only
|
||||
/// ids, names and the fields the pages start from (each page loads the
|
||||
/// full item itself).
|
||||
List<Map<String, Object?>> encodeBrowseStack(List<BrowseRoute> stack) => [
|
||||
for (final r in stack)
|
||||
switch (r) {
|
||||
HomeRoute() => {'r': 'home'},
|
||||
LibraryRoute(:final folder) => {'r': 'lib', ..._itemJson(folder)},
|
||||
SeriesRoute(:final series, :final seasonId) => {
|
||||
'r': 'series',
|
||||
..._itemJson(series),
|
||||
'seasonId': ?seasonId,
|
||||
},
|
||||
DetailRoute(:final item) => {'r': 'item', ..._itemJson(item)},
|
||||
}
|
||||
];
|
||||
|
||||
/// Inverse of [encodeBrowseStack]; always starts with Home. Null when
|
||||
/// [raw] is not a stack.
|
||||
List<BrowseRoute>? decodeBrowseStack(Object? raw) {
|
||||
if (raw is! List) return null;
|
||||
final out = <BrowseRoute>[const HomeRoute()];
|
||||
for (final e in raw) {
|
||||
if (e is! Map) return null;
|
||||
final item = _itemFrom(e);
|
||||
final route = switch (e['r']) {
|
||||
'home' => null,
|
||||
'lib' when item != null => LibraryRoute(item),
|
||||
'series' when item != null =>
|
||||
SeriesRoute(item, seasonId: e['seasonId'] is String ? e['seasonId'] as String : null),
|
||||
'item' when item != null => DetailRoute(item),
|
||||
_ => null,
|
||||
};
|
||||
if (route != null && out.every((r) => r.key != route.key)) out.add(route);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Map<String, Object?> _itemJson(JellyfinItem i) => {
|
||||
'id': i.id,
|
||||
'name': i.name,
|
||||
'type': i.type,
|
||||
if (i.isFolder) 'isFolder': true,
|
||||
'collectionType': ?i.collectionType,
|
||||
'seriesId': ?i.seriesId,
|
||||
'seriesName': ?i.seriesName,
|
||||
'seasonId': ?i.seasonId,
|
||||
'indexNumber': ?i.indexNumber,
|
||||
'parentIndexNumber': ?i.parentIndexNumber,
|
||||
};
|
||||
|
||||
JellyfinItem? _itemFrom(Map e) {
|
||||
String? s(String k) => e[k] is String && (e[k] as String).isNotEmpty ? e[k] as String : null;
|
||||
final id = s('id');
|
||||
if (id == null) return null;
|
||||
return JellyfinItem(
|
||||
id: id,
|
||||
name: s('name') ?? '',
|
||||
type: s('type') ?? '',
|
||||
isFolder: e['isFolder'] == true,
|
||||
collectionType: s('collectionType'),
|
||||
seriesId: s('seriesId'),
|
||||
seriesName: s('seriesName'),
|
||||
seasonId: e['r'] == 'series' ? null : s('seasonId'),
|
||||
indexNumber: e['indexNumber'] is int ? e['indexNumber'] as int : null,
|
||||
parentIndexNumber: e['parentIndexNumber'] is int ? e['parentIndexNumber'] as int : null,
|
||||
);
|
||||
}
|
||||
|
||||
/// Where a browser opens instead of the remembered location: a server and
|
||||
/// a route stack (e.g. the series of the episode playing).
|
||||
class BrowseStart {
|
||||
final String serverId;
|
||||
final List<BrowseRoute> stack;
|
||||
const BrowseStart(this.serverId, this.stack);
|
||||
|
||||
/// The series page of [episode] with its season selected.
|
||||
static BrowseStart? seriesOf(String serverId, JellyfinItem episode) {
|
||||
final sid = episode.seriesId;
|
||||
if (sid == null) return null;
|
||||
return BrowseStart(serverId, [
|
||||
const HomeRoute(),
|
||||
SeriesRoute(JellyfinItem(id: sid, name: episode.seriesName ?? '', type: 'Series'),
|
||||
seasonId: episode.seasonId),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/// What every browser page needs, provided by [JellyfinBrowser].
|
||||
class BrowseScope extends InheritedWidget {
|
||||
final JellyfinAccounts accounts;
|
||||
final JellyfinAccount account;
|
||||
final JellyfinClient client;
|
||||
/// Item id of the current pick on this server, highlighted everywhere.
|
||||
final String? selectedItemId;
|
||||
final ValueChanged<JellyfinItem> onPick;
|
||||
final ValueChanged<BrowseRoute> onOpen;
|
||||
/// Hover / focus: the inspector pane follows it.
|
||||
final ValueChanged<JellyfinItem> onPeek;
|
||||
|
||||
const BrowseScope({
|
||||
super.key,
|
||||
required this.accounts,
|
||||
required this.account,
|
||||
required this.client,
|
||||
required this.selectedItemId,
|
||||
required this.onPick,
|
||||
required this.onOpen,
|
||||
required this.onPeek,
|
||||
required super.child,
|
||||
});
|
||||
|
||||
static BrowseScope of(BuildContext context) =>
|
||||
context.dependOnInheritedWidgetOfExactType<BrowseScope>()!;
|
||||
|
||||
/// Cached browse call on this server.
|
||||
Future<T> load<T>(String key, Future<T> Function(JellyfinClient c) fn) =>
|
||||
accounts.cached(account.serverId, key, () => fn(client));
|
||||
|
||||
/// Click / Enter on a card: playable items are picked, containers open.
|
||||
void activate(JellyfinItem item) {
|
||||
if (isPlayable(item)) {
|
||||
onPick(item);
|
||||
return;
|
||||
}
|
||||
switch (item.kind) {
|
||||
case JellyfinItemKind.series:
|
||||
onOpen(SeriesRoute(item));
|
||||
case JellyfinItemKind.season:
|
||||
final sid = item.seriesId;
|
||||
if (sid != null) {
|
||||
onOpen(SeriesRoute(
|
||||
JellyfinItem(id: sid, name: item.seriesName ?? item.name, type: 'Series'),
|
||||
seasonId: item.id));
|
||||
}
|
||||
default:
|
||||
onOpen(LibraryRoute(item));
|
||||
}
|
||||
}
|
||||
|
||||
/// Opens the series of an episode (or the item itself if it has none).
|
||||
void openSeriesOf(JellyfinItem episode) {
|
||||
final sid = episode.seriesId;
|
||||
if (sid == null) return;
|
||||
onOpen(SeriesRoute(
|
||||
JellyfinItem(id: sid, name: episode.seriesName ?? '', type: 'Series'),
|
||||
seasonId: episode.seasonId));
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(BrowseScope old) =>
|
||||
old.selectedItemId != selectedItemId ||
|
||||
old.account != account ||
|
||||
old.client != client;
|
||||
}
|
||||
|
||||
/// Runs [load] once (again on [retry]) and shows [builder] with the result,
|
||||
/// a spinner meanwhile, and a compact error with Retry on failure.
|
||||
class Loader<T> extends StatefulWidget {
|
||||
final Future<T> Function() load;
|
||||
final Widget Function(BuildContext context, T data) builder;
|
||||
final Widget? loading;
|
||||
/// When false the error collapses to nothing (optional sections).
|
||||
final bool showError;
|
||||
const Loader({
|
||||
super.key,
|
||||
required this.load,
|
||||
required this.builder,
|
||||
this.loading,
|
||||
this.showError = true,
|
||||
});
|
||||
|
||||
@override
|
||||
State<Loader<T>> createState() => _LoaderState<T>();
|
||||
}
|
||||
|
||||
class _LoaderState<T> extends State<Loader<T>> {
|
||||
late Future<T> _future = widget.load();
|
||||
|
||||
void _retry() => setState(() => _future = widget.load());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder<T>(
|
||||
future: _future,
|
||||
builder: (context, snap) {
|
||||
if (snap.hasData) return widget.builder(context, snap.data as T);
|
||||
if (snap.hasError) {
|
||||
if (!widget.showError) return const SizedBox.shrink();
|
||||
return LoadError(error: snap.error!, onRetry: _retry);
|
||||
}
|
||||
if (snap.connectionState == ConnectionState.done) {
|
||||
return widget.builder(context, snap.data as T);
|
||||
}
|
||||
return widget.loading ??
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(32),
|
||||
child: Center(child: CircularProgressIndicator(strokeWidth: 2)),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LoadError extends StatelessWidget {
|
||||
final Object error;
|
||||
final VoidCallback onRetry;
|
||||
const LoadError({super.key, required this.error, required this.onRetry});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final e = error;
|
||||
final msg = e is JellyfinException
|
||||
? (e.isUnauthorized ? 'Sign-in expired' : e.message)
|
||||
: '$e';
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.cloud_off, size: 18, color: Theme.of(context).colorScheme.error),
|
||||
const SizedBox(width: 8),
|
||||
Flexible(
|
||||
child: Text(msg.length > 160 ? '${msg.substring(0, 160)}…' : msg,
|
||||
style: const TextStyle(color: Colors.grey)),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
TextButton(onPressed: onRetry, child: const Text('Retry')),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,573 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import '../screens/home/picked_media.dart';
|
||||
import 'accounts.dart';
|
||||
import 'browse_scope.dart';
|
||||
import 'detail_page.dart';
|
||||
import 'format.dart';
|
||||
import 'home_page.dart';
|
||||
import 'inspector.dart';
|
||||
import 'library_page.dart';
|
||||
import 'search_results.dart';
|
||||
import 'series_page.dart';
|
||||
import 'sign_in_panel.dart';
|
||||
|
||||
/// Browser width from which the inspector pane shows on the right.
|
||||
const inspectorFrom = 1400.0;
|
||||
const inspectorWidth = 340.0;
|
||||
|
||||
/// Library browser for the linked Jellyfin servers: server switcher,
|
||||
/// breadcrumbs, search, and a back stack of pages (Home rows, library
|
||||
/// grids, series, details). Pages below the top stay alive, so going back
|
||||
/// keeps scroll position and loaded pages.
|
||||
///
|
||||
/// Keyboard: arrows move between cards, Enter picks / opens, I opens
|
||||
/// details, Esc / Backspace / Alt+Left go back, / or Ctrl+F searches.
|
||||
class JellyfinBrowser extends StatefulWidget {
|
||||
final JellyfinAccounts accounts;
|
||||
final JellyfinMedia? selected;
|
||||
final ValueChanged<JellyfinMedia> onPick;
|
||||
/// Shown when given: toggles a bigger browser (the host hides its form).
|
||||
final VoidCallback? onToggleExpanded;
|
||||
final bool expanded;
|
||||
final VoidCallback? onOpenIntegrations;
|
||||
final Duration searchDebounce;
|
||||
/// Opens here instead of the remembered location (the series of the
|
||||
/// episode playing, in the session's swap panel).
|
||||
final BrowseStart? start;
|
||||
const JellyfinBrowser({
|
||||
this.start,
|
||||
super.key,
|
||||
required this.accounts,
|
||||
required this.onPick,
|
||||
this.selected,
|
||||
this.onToggleExpanded,
|
||||
this.expanded = false,
|
||||
this.onOpenIntegrations,
|
||||
this.searchDebounce = const Duration(milliseconds: 300),
|
||||
});
|
||||
|
||||
@override
|
||||
State<JellyfinBrowser> createState() => _JellyfinBrowserState();
|
||||
}
|
||||
|
||||
class _JellyfinBrowserState extends State<JellyfinBrowser> {
|
||||
String? _serverId;
|
||||
List<BrowseRoute> _stack = const [HomeRoute()];
|
||||
final _search = TextEditingController();
|
||||
final _searchFocus = FocusNode(debugLabel: 'jf-search');
|
||||
final _body = FocusScopeNode(debugLabel: 'jf-body');
|
||||
final _peek = ValueNotifier<JellyfinItem?>(null);
|
||||
String _term = '';
|
||||
Timer? _debounce;
|
||||
int _refresh = 0;
|
||||
|
||||
JellyfinAccounts get _accounts => widget.accounts;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final start = widget.start;
|
||||
if (start != null && _accounts.account(start.serverId) != null) {
|
||||
_serverId = start.serverId;
|
||||
_stack = start.stack.isEmpty ? const [HomeRoute()] : start.stack;
|
||||
_remember();
|
||||
} else {
|
||||
_serverId = widget.selected != null && _accounts.account(widget.selected!.serverId) != null
|
||||
? widget.selected!.serverId
|
||||
: _accounts.defaultServerId;
|
||||
_stack = _restored(_serverId);
|
||||
}
|
||||
_accounts.addListener(_changed);
|
||||
}
|
||||
|
||||
/// The remembered location on [serverId], else Home.
|
||||
List<BrowseRoute> _restored(String? serverId) =>
|
||||
(serverId == null ? null : decodeBrowseStack(_accounts.browseLocation(serverId))) ??
|
||||
const [HomeRoute()];
|
||||
|
||||
/// Every navigation is saved per server (Hive), so the next browser
|
||||
/// (Host tab, swap panel, next start) opens where this one was.
|
||||
void _remember() {
|
||||
final id = _account?.serverId;
|
||||
if (id != null) unawaited(_accounts.saveBrowseLocation(id, encodeBrowseStack(_stack)));
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(JellyfinBrowser old) {
|
||||
super.didUpdateWidget(old);
|
||||
if (old.accounts != widget.accounts) {
|
||||
old.accounts.removeListener(_changed);
|
||||
widget.accounts.addListener(_changed);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_accounts.removeListener(_changed);
|
||||
_debounce?.cancel();
|
||||
_search.dispose();
|
||||
_searchFocus.dispose();
|
||||
_body.dispose();
|
||||
_peek.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _changed() {
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
JellyfinAccount? get _account =>
|
||||
(_serverId == null ? null : _accounts.account(_serverId!)) ?? _accounts.defaultAccount;
|
||||
|
||||
void _switchServer(String serverId) {
|
||||
if (serverId == _account?.serverId) return;
|
||||
setState(() {
|
||||
_serverId = serverId;
|
||||
_stack = _restored(serverId);
|
||||
_peek.value = null;
|
||||
_clearSearch();
|
||||
});
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------- navigation
|
||||
|
||||
void _open(BrowseRoute route) {
|
||||
setState(() {
|
||||
_clearSearch();
|
||||
if (_stack.last.key != route.key) _stack = [..._stack, route];
|
||||
});
|
||||
_remember();
|
||||
_body.requestFocus();
|
||||
}
|
||||
|
||||
bool _back() {
|
||||
if (_stack.length <= 1) return false;
|
||||
setState(() => _stack = _stack.sublist(0, _stack.length - 1));
|
||||
_remember();
|
||||
_body.requestFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
void _popTo(int index) {
|
||||
setState(() {
|
||||
_clearSearch();
|
||||
_stack = _stack.sublist(0, index + 1);
|
||||
});
|
||||
_remember();
|
||||
_body.requestFocus();
|
||||
}
|
||||
|
||||
void _onSearchChanged(String text) {
|
||||
_debounce?.cancel();
|
||||
_debounce = Timer(widget.searchDebounce, () {
|
||||
if (mounted) setState(() => _term = text.trim());
|
||||
});
|
||||
}
|
||||
|
||||
void _clearSearch() {
|
||||
_debounce?.cancel();
|
||||
_search.clear();
|
||||
_term = '';
|
||||
}
|
||||
|
||||
void _pick(JellyfinItem item) {
|
||||
final account = _account;
|
||||
if (account == null) return;
|
||||
widget.onPick(pickFor(account, item));
|
||||
}
|
||||
|
||||
KeyEventResult _onKey(FocusNode node, KeyEvent e) {
|
||||
if (e is! KeyDownEvent && e is! KeyRepeatEvent) return KeyEventResult.ignored;
|
||||
final keys = HardwareKeyboard.instance;
|
||||
final inField = FocusManager.instance.primaryFocus?.context
|
||||
?.findAncestorStateOfType<EditableTextState>() !=
|
||||
null;
|
||||
final k = e.logicalKey;
|
||||
if (k == LogicalKeyboardKey.escape) {
|
||||
if (_search.text.isNotEmpty || _term.isNotEmpty) {
|
||||
setState(_clearSearch);
|
||||
_body.requestFocus();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
if (inField) {
|
||||
_body.requestFocus();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return _back() ? KeyEventResult.handled : KeyEventResult.ignored;
|
||||
}
|
||||
if (inField) return KeyEventResult.ignored;
|
||||
if (e.character == '/' || (keys.isControlPressed && k == LogicalKeyboardKey.keyF)) {
|
||||
_searchFocus.requestFocus();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
if (k == LogicalKeyboardKey.backspace ||
|
||||
(keys.isAltPressed && k == LogicalKeyboardKey.arrowLeft) ||
|
||||
k == LogicalKeyboardKey.browserBack) {
|
||||
return _back() ? KeyEventResult.handled : KeyEventResult.ignored;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ build
|
||||
|
||||
Widget _page(BrowseRoute r) => switch (r) {
|
||||
HomeRoute() => const JellyfinHomePage(),
|
||||
LibraryRoute(:final folder) => JellyfinLibraryPage(folder: folder),
|
||||
SeriesRoute(:final series, :final seasonId) =>
|
||||
JellyfinSeriesPage(series: series, seasonId: seasonId),
|
||||
DetailRoute(:final item) => JellyfinDetailPage(item: item),
|
||||
};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final account = _account;
|
||||
if (account == null) {
|
||||
return const Center(child: Text('No Jellyfin server linked', style: TextStyle(color: Colors.grey)));
|
||||
}
|
||||
final client = _accounts.clientFor(account.serverId)!;
|
||||
final status = _accounts.statusOf(account.serverId);
|
||||
final sel = widget.selected;
|
||||
final searching = _term.isNotEmpty;
|
||||
|
||||
final pages = Stack(
|
||||
children: [
|
||||
for (var i = 0; i < _stack.length; i++)
|
||||
Visibility(
|
||||
key: ValueKey('$_refresh:${account.serverId}:$i:${_stack[i].key}'),
|
||||
visible: !searching && i == _stack.length - 1,
|
||||
maintainState: true,
|
||||
child: _page(_stack[i]),
|
||||
),
|
||||
if (searching) JellyfinSearchResults(key: ValueKey('$_refresh:$_term'), term: _term),
|
||||
],
|
||||
);
|
||||
|
||||
return BrowseScope(
|
||||
accounts: _accounts,
|
||||
account: account,
|
||||
client: client,
|
||||
selectedItemId: sel != null && sel.serverId == account.serverId ? sel.itemId : null,
|
||||
onPick: _pick,
|
||||
onOpen: _open,
|
||||
onPeek: (item) => _peek.value = item,
|
||||
child: Focus(
|
||||
onKeyEvent: _onKey,
|
||||
child: Column(
|
||||
key: const ValueKey('jf-browser'),
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
_header(context, account),
|
||||
if (status == JellyfinAccountStatus.expired || status == JellyfinAccountStatus.offline)
|
||||
_StatusBanner(accounts: _accounts, account: account, status: status),
|
||||
const SizedBox(height: 12),
|
||||
Expanded(
|
||||
child: LayoutBuilder(builder: (context, box) {
|
||||
final inspector = box.maxWidth >= inspectorFrom;
|
||||
final body = FocusScope(node: _body, child: pages);
|
||||
if (!inspector) return body;
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Expanded(child: body),
|
||||
const SizedBox(width: 16),
|
||||
SizedBox(width: inspectorWidth, child: JellyfinInspector(item: _peek)),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _header(BuildContext context, JellyfinAccount account) {
|
||||
final theme = Theme.of(context);
|
||||
final t = theme.textTheme;
|
||||
final crumbs = <Widget>[];
|
||||
for (var i = 0; i < _stack.length; i++) {
|
||||
final last = i == _stack.length - 1 && _term.isEmpty;
|
||||
if (i > 0) {
|
||||
crumbs.add(const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
child: Icon(Icons.chevron_right, size: 18, color: Colors.grey),
|
||||
));
|
||||
}
|
||||
final label = Text(
|
||||
_stack[i].label,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: t.titleSmall?.copyWith(
|
||||
color: last ? theme.colorScheme.onSurface : theme.colorScheme.onSurfaceVariant,
|
||||
fontWeight: last ? FontWeight.w600 : null),
|
||||
);
|
||||
crumbs.add(Flexible(
|
||||
child: last
|
||||
? label
|
||||
: InkWell(
|
||||
key: ValueKey('crumb-$i'),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
onTap: () => _popTo(i),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4), child: label),
|
||||
),
|
||||
));
|
||||
}
|
||||
if (_term.isNotEmpty) {
|
||||
crumbs
|
||||
..add(const Icon(Icons.chevron_right, size: 18, color: Colors.grey))
|
||||
..add(Flexible(
|
||||
child: Text('Search “$_term”',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: t.titleSmall?.copyWith(fontWeight: FontWeight.w600))));
|
||||
}
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
_ServerSwitcher(
|
||||
accounts: _accounts,
|
||||
current: account,
|
||||
onSelect: _switchServer,
|
||||
onOpenIntegrations: widget.onOpenIntegrations,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
IconButton(
|
||||
tooltip: 'Back (Esc)',
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: _stack.length > 1 ? _back : null,
|
||||
icon: const Icon(Icons.arrow_back, size: 20),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Expanded(child: Row(children: crumbs)),
|
||||
const SizedBox(width: 8),
|
||||
SizedBox(
|
||||
width: 260,
|
||||
child: TextField(
|
||||
key: const ValueKey('jf-search'),
|
||||
controller: _search,
|
||||
focusNode: _searchFocus,
|
||||
onChanged: _onSearchChanged,
|
||||
onSubmitted: (v) {
|
||||
_debounce?.cancel();
|
||||
setState(() => _term = v.trim());
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
hintText: 'Search ( / )',
|
||||
prefixIcon: const Icon(Icons.search, size: 18),
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
|
||||
suffixIcon: ListenableBuilder(
|
||||
listenable: _search,
|
||||
builder: (context, _) => _search.text.isEmpty
|
||||
? const SizedBox.shrink()
|
||||
: IconButton(
|
||||
tooltip: 'Clear (Esc)',
|
||||
iconSize: 16,
|
||||
onPressed: () => setState(_clearSearch),
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Refresh',
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: () {
|
||||
_accounts.invalidate(account.serverId);
|
||||
setState(() => _refresh++);
|
||||
},
|
||||
icon: const Icon(Icons.refresh, size: 20),
|
||||
),
|
||||
if (widget.onToggleExpanded != null)
|
||||
IconButton(
|
||||
key: const ValueKey('jf-expand'),
|
||||
tooltip: widget.expanded ? 'Show the host form' : 'Bigger browser',
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: widget.onToggleExpanded,
|
||||
icon: Icon(widget.expanded ? Icons.close_fullscreen : Icons.open_in_full, size: 18),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Current server (avatar + name); a menu when several are linked.
|
||||
class _ServerSwitcher extends StatelessWidget {
|
||||
final JellyfinAccounts accounts;
|
||||
final JellyfinAccount current;
|
||||
final ValueChanged<String> onSelect;
|
||||
final VoidCallback? onOpenIntegrations;
|
||||
const _ServerSwitcher({
|
||||
required this.accounts,
|
||||
required this.current,
|
||||
required this.onSelect,
|
||||
this.onOpenIntegrations,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
final chip = Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
StatusDot(status: accounts.statusOf(current.serverId)),
|
||||
const SizedBox(width: 8),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 200),
|
||||
child: Text(current.displayName,
|
||||
maxLines: 1, overflow: TextOverflow.ellipsis, style: t.titleSmall),
|
||||
),
|
||||
],
|
||||
);
|
||||
if (accounts.accounts.length < 2 && onOpenIntegrations == null) {
|
||||
return Padding(padding: const EdgeInsets.symmetric(horizontal: 8), child: chip);
|
||||
}
|
||||
return MenuAnchor(
|
||||
menuChildren: [
|
||||
for (final a in accounts.accounts)
|
||||
MenuItemButton(
|
||||
key: ValueKey('server-${a.serverId}'),
|
||||
leadingIcon: StatusDot(status: accounts.statusOf(a.serverId)),
|
||||
trailingIcon: a.serverId == current.serverId ? const Icon(Icons.check, size: 18) : null,
|
||||
onPressed: () => onSelect(a.serverId),
|
||||
child: Text('${a.displayName} · ${a.userName}'),
|
||||
),
|
||||
if (onOpenIntegrations != null)
|
||||
MenuItemButton(
|
||||
leadingIcon: const Icon(Icons.add, size: 18),
|
||||
onPressed: onOpenIntegrations,
|
||||
child: const Text('Manage servers…'),
|
||||
),
|
||||
],
|
||||
builder: (context, menu, _) => TextButton(
|
||||
key: const ValueKey('jf-server-switch'),
|
||||
onPressed: () => menu.isOpen ? menu.close() : menu.open(),
|
||||
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
chip,
|
||||
const Icon(Icons.arrow_drop_down, size: 20),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class StatusDot extends StatelessWidget {
|
||||
final JellyfinAccountStatus status;
|
||||
const StatusDot({super.key, required this.status});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = switch (status) {
|
||||
JellyfinAccountStatus.online => Colors.green,
|
||||
JellyfinAccountStatus.offline => Colors.orange,
|
||||
JellyfinAccountStatus.expired => Theme.of(context).colorScheme.error,
|
||||
_ => Colors.grey,
|
||||
};
|
||||
return Container(
|
||||
width: 8, height: 8, decoration: BoxDecoration(color: color, shape: BoxShape.circle));
|
||||
}
|
||||
}
|
||||
|
||||
class _StatusBanner extends StatelessWidget {
|
||||
final JellyfinAccounts accounts;
|
||||
final JellyfinAccount account;
|
||||
final JellyfinAccountStatus status;
|
||||
const _StatusBanner({required this.accounts, required this.account, required this.status});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final expired = status == JellyfinAccountStatus.expired;
|
||||
return Container(
|
||||
key: const ValueKey('jf-status-banner'),
|
||||
margin: const EdgeInsets.only(top: 8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: (expired ? scheme.errorContainer : Colors.orange.shade900).withValues(alpha: 0.35),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(expired ? Icons.lock_clock : Icons.cloud_off, size: 18),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(expired
|
||||
? 'Sign-in to ${account.displayName} expired. Reconnect to keep browsing.'
|
||||
: "Can't reach ${account.displayName}: ${accounts.errorOf(account.serverId) ?? 'offline'}"),
|
||||
),
|
||||
if (expired)
|
||||
FilledButton.tonal(
|
||||
onPressed: () => showReconnectDialog(context, accounts, account),
|
||||
child: const Text('Reconnect'),
|
||||
)
|
||||
else
|
||||
TextButton(
|
||||
onPressed: () => accounts.validate(account.serverId),
|
||||
child: const Text('Retry'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sign in again to an expired account (same server, new token).
|
||||
Future<void> showReconnectDialog(
|
||||
BuildContext context, JellyfinAccounts accounts, JellyfinAccount account) {
|
||||
return showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => Dialog(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 520),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: JellyfinSignInPanel(
|
||||
accounts: accounts,
|
||||
reconnect: account,
|
||||
onDone: (_) => Navigator.of(context).pop(),
|
||||
onCancel: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Small helper for other screens: the user's avatar on a linked server.
|
||||
class JellyfinAvatar extends StatelessWidget {
|
||||
final JellyfinAccounts accounts;
|
||||
final JellyfinAccount account;
|
||||
final double radius;
|
||||
const JellyfinAvatar({super.key, required this.accounts, required this.account, this.radius = 18});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final initials = account.userName.isEmpty ? '?' : account.userName.characters.first.toUpperCase();
|
||||
final fallback = CircleAvatar(
|
||||
radius: radius,
|
||||
backgroundColor: scheme.primaryContainer,
|
||||
child: Text(initials, style: TextStyle(color: scheme.onPrimaryContainer)),
|
||||
);
|
||||
final client = accounts.clientFor(account.serverId);
|
||||
final url = client?.userImageUrl(account.user, maxWidth: (radius * 4).round());
|
||||
if (url == null) return fallback;
|
||||
return ClipOval(
|
||||
child: SizedBox(
|
||||
width: radius * 2,
|
||||
height: radius * 2,
|
||||
child: Image.network(url.toString(),
|
||||
fit: BoxFit.cover,
|
||||
cacheWidth: (radius * 4).round(),
|
||||
errorBuilder: (_, _, _) => fallback),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'browse_scope.dart';
|
||||
import 'format.dart';
|
||||
import 'images.dart';
|
||||
|
||||
enum CardShape {
|
||||
/// 2:3 poster (movies, series, latest).
|
||||
poster(2 / 3, 150),
|
||||
/// 16:9 thumbnail (continue watching, next up, episodes).
|
||||
thumb(16 / 9, 260);
|
||||
|
||||
/// Image width / height.
|
||||
final double aspect;
|
||||
/// Smallest card width; rows and grids add columns past it.
|
||||
final double minWidth;
|
||||
const CardShape(this.aspect, this.minWidth);
|
||||
}
|
||||
|
||||
/// Title + subtitle lines under a card image.
|
||||
const cardTextHeight = 46.0;
|
||||
const cardGap = 12.0;
|
||||
|
||||
/// Card image for [item] in [shape]: thumbs prefer the item's own
|
||||
/// screenshot / thumb / backdrop, posters the primary (series poster for
|
||||
/// episodes).
|
||||
JellyfinImageRef? cardImage(JellyfinItem item, CardShape shape) {
|
||||
if (shape == CardShape.poster) return item.image(JellyfinImageType.primary);
|
||||
final own = item.ownImage(JellyfinImageType.primary);
|
||||
final primaryIsWide = (item.primaryImageAspectRatio ?? 0) > 1.2 ||
|
||||
item.kind == JellyfinItemKind.episode ||
|
||||
item.kind == JellyfinItemKind.video;
|
||||
if (own != null && primaryIsWide) return own;
|
||||
return item.image(JellyfinImageType.thumb) ??
|
||||
item.image(JellyfinImageType.backdrop) ??
|
||||
item.image(JellyfinImageType.primary);
|
||||
}
|
||||
|
||||
IconData kindIcon(JellyfinItem item) => switch (item.kind) {
|
||||
JellyfinItemKind.series || JellyfinItemKind.season => Icons.live_tv_outlined,
|
||||
JellyfinItemKind.episode => Icons.tv_outlined,
|
||||
JellyfinItemKind.folder || JellyfinItemKind.collectionFolder => Icons.folder_outlined,
|
||||
JellyfinItemKind.boxSet => Icons.collections_bookmark_outlined,
|
||||
_ => Icons.movie_outlined,
|
||||
};
|
||||
|
||||
/// Poster or thumb card: image with progress bar and state badges, title
|
||||
/// and one meta line. Click / Enter activates (pick or open), hover and
|
||||
/// focus feed the inspector, "i" or the hover button opens the details.
|
||||
class MediaCard extends StatefulWidget {
|
||||
final JellyfinItem item;
|
||||
final CardShape shape;
|
||||
/// Rows mixing series (Continue watching, Next up): series name on top,
|
||||
/// "S2E3 · 12 min left" below.
|
||||
final bool seriesFirst;
|
||||
final bool autofocus;
|
||||
const MediaCard({
|
||||
super.key,
|
||||
required this.item,
|
||||
required this.shape,
|
||||
this.seriesFirst = false,
|
||||
this.autofocus = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MediaCard> createState() => _MediaCardState();
|
||||
}
|
||||
|
||||
class _MediaCardState extends State<MediaCard> {
|
||||
bool _hover = false;
|
||||
bool _focus = false;
|
||||
|
||||
JellyfinItem get item => widget.item;
|
||||
|
||||
void _details(BrowseScope scope) => scope.onOpen(DetailRoute(item));
|
||||
|
||||
KeyEventResult _onKey(BrowseScope scope, KeyEvent e) {
|
||||
if (e is! KeyDownEvent) return KeyEventResult.ignored;
|
||||
if (e.logicalKey == LogicalKeyboardKey.keyI && isPlayable(item)) {
|
||||
_details(scope);
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
final theme = Theme.of(context);
|
||||
final scheme = theme.colorScheme;
|
||||
final selected = scope.selectedItemId == item.id;
|
||||
final played = item.userData.played;
|
||||
final progress = progressOf(item);
|
||||
final unplayed = item.userData.unplayedItemCount;
|
||||
final ring = selected
|
||||
? scheme.primary
|
||||
: _focus
|
||||
? scheme.onSurface
|
||||
: Colors.transparent;
|
||||
|
||||
final image = AspectRatio(
|
||||
aspectRatio: widget.shape.aspect,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 120),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: ring, width: 2),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
JellyfinImage(
|
||||
client: scope.client,
|
||||
image: cardImage(item, widget.shape),
|
||||
icon: kindIcon(item),
|
||||
),
|
||||
if (_hover || _focus)
|
||||
const ColoredBox(color: Color(0x22FFFFFF)),
|
||||
if (progress > 0)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: LinearProgressIndicator(
|
||||
value: progress,
|
||||
minHeight: 4,
|
||||
backgroundColor: Colors.black54,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 6,
|
||||
right: 6,
|
||||
child: selected
|
||||
? _Badge(color: scheme.primary, child: Icon(Icons.check, size: 14, color: scheme.onPrimary))
|
||||
: played
|
||||
? const _Badge(color: Color(0xCC1B5E20), child: Icon(Icons.check, size: 14, color: Colors.white))
|
||||
: unplayed != null && unplayed > 0 && !isPlayable(item)
|
||||
? _Badge(
|
||||
color: scheme.primaryContainer,
|
||||
child: Text('$unplayed',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: scheme.onPrimaryContainer)))
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
if (_hover && isPlayable(item))
|
||||
Positioned(
|
||||
top: 4,
|
||||
left: 4,
|
||||
child: IconButton.filledTonal(
|
||||
key: ValueKey('card-info-${item.id}'),
|
||||
tooltip: 'Details (I)',
|
||||
visualDensity: VisualDensity.compact,
|
||||
iconSize: 16,
|
||||
onPressed: () => _details(scope),
|
||||
icon: const Icon(Icons.info_outline),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final title = cardTitle(item, seriesFirst: widget.seriesFirst);
|
||||
final sub = widget.seriesFirst && item.kind == JellyfinItemKind.episode
|
||||
? [cardSubtitle(item), item.name].where((s) => s.isNotEmpty).join(' · ')
|
||||
: cardSubtitle(item);
|
||||
return Focus(
|
||||
canRequestFocus: false,
|
||||
skipTraversal: true,
|
||||
onKeyEvent: (_, e) => _onKey(scope, e),
|
||||
child: Semantics(
|
||||
button: true,
|
||||
selected: selected,
|
||||
label: title,
|
||||
child: InkWell(
|
||||
key: ValueKey('card-${item.id}'),
|
||||
autofocus: widget.autofocus,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
focusColor: Colors.transparent,
|
||||
hoverColor: Colors.transparent,
|
||||
onTap: () => scope.activate(item),
|
||||
onHover: (h) {
|
||||
setState(() => _hover = h);
|
||||
if (h) scope.onPeek(item);
|
||||
},
|
||||
onFocusChange: (f) {
|
||||
setState(() => _focus = f);
|
||||
if (f) scope.onPeek(item);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
image,
|
||||
const SizedBox(height: 6),
|
||||
SizedBox(
|
||||
height: cardTextHeight - 6,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: selected ? scheme.primary : null)),
|
||||
Text(sub,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.bodySmall?.copyWith(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Badge extends StatelessWidget {
|
||||
final Color color;
|
||||
final Widget child;
|
||||
const _Badge({required this.color, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Container(
|
||||
constraints: const BoxConstraints(minWidth: 22, minHeight: 22),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(11)),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
/// Columns and card width that fill [width] exactly with cards at least
|
||||
/// [minWidth] wide: no half-cut card at the edge, any window width.
|
||||
({int cols, double itemWidth}) fitColumns(double width, double minWidth, {double gap = cardGap}) {
|
||||
final cols = math.max(1, ((width + gap) / (minWidth + gap)).floor());
|
||||
return (cols: cols, itemWidth: (width - gap * (cols - 1)) / cols);
|
||||
}
|
||||
|
||||
/// Grid layout for cards: as many columns as fit, height = image + text.
|
||||
class CardGridDelegate extends SliverGridDelegate {
|
||||
final CardShape shape;
|
||||
final double minWidth;
|
||||
CardGridDelegate(this.shape, {double? minWidth}) : minWidth = minWidth ?? shape.minWidth;
|
||||
|
||||
@override
|
||||
SliverGridLayout getLayout(SliverConstraints constraints) {
|
||||
final fit = fitColumns(constraints.crossAxisExtent, minWidth);
|
||||
final h = fit.itemWidth / shape.aspect + cardTextHeight;
|
||||
return SliverGridRegularTileLayout(
|
||||
crossAxisCount: fit.cols,
|
||||
mainAxisStride: h + 18,
|
||||
crossAxisStride: fit.itemWidth + cardGap,
|
||||
childMainAxisExtent: h,
|
||||
childCrossAxisExtent: fit.itemWidth,
|
||||
reverseCrossAxis: false,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRelayout(CardGridDelegate old) => old.shape != shape || old.minWidth != minWidth;
|
||||
}
|
||||
|
||||
/// A titled horizontal row of cards sized to fill the width; arrows (on
|
||||
/// hover) page through it. Lazy: only visible cards are built.
|
||||
class MediaRow extends StatefulWidget {
|
||||
final String title;
|
||||
final List<JellyfinItem> items;
|
||||
final CardShape shape;
|
||||
final bool seriesFirst;
|
||||
final Widget? trailing;
|
||||
const MediaRow({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.items,
|
||||
required this.shape,
|
||||
this.seriesFirst = false,
|
||||
this.trailing,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MediaRow> createState() => _MediaRowState();
|
||||
}
|
||||
|
||||
class _MediaRowState extends State<MediaRow> {
|
||||
final _scroll = ScrollController();
|
||||
bool _hover = false;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scroll.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _page(int dir, double width) {
|
||||
if (!_scroll.hasClients) return;
|
||||
final p = _scroll.position;
|
||||
final to = (p.pixels + dir * (width + cardGap)).clamp(0.0, p.maxScrollExtent);
|
||||
_scroll.animateTo(to, duration: const Duration(milliseconds: 280), curve: Curves.easeOutCubic);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return MouseRegion(
|
||||
onEnter: (_) => setState(() => _hover = true),
|
||||
onExit: (_) => setState(() => _hover = false),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(widget.title, style: t.titleMedium),
|
||||
const SizedBox(width: 8),
|
||||
Text('${widget.items.length}', style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
const Spacer(),
|
||||
?widget.trailing,
|
||||
],
|
||||
),
|
||||
),
|
||||
LayoutBuilder(builder: (context, box) {
|
||||
final fit = fitColumns(box.maxWidth, widget.shape.minWidth);
|
||||
final h = fit.itemWidth / widget.shape.aspect + cardTextHeight;
|
||||
final overflow = widget.items.length > fit.cols;
|
||||
return SizedBox(
|
||||
height: h,
|
||||
child: Stack(
|
||||
children: [
|
||||
ListView.separated(
|
||||
controller: _scroll,
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: widget.items.length,
|
||||
separatorBuilder: (_, _) => const SizedBox(width: cardGap),
|
||||
itemBuilder: (context, i) => SizedBox(
|
||||
width: fit.itemWidth,
|
||||
child: MediaCard(
|
||||
item: widget.items[i],
|
||||
shape: widget.shape,
|
||||
seriesFirst: widget.seriesFirst,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (overflow && _hover) ...[
|
||||
_PageArrow(left: true, height: h - cardTextHeight, onTap: () => _page(-1, box.maxWidth)),
|
||||
_PageArrow(left: false, height: h - cardTextHeight, onTap: () => _page(1, box.maxWidth)),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PageArrow extends StatelessWidget {
|
||||
final bool left;
|
||||
final double height;
|
||||
final VoidCallback onTap;
|
||||
const _PageArrow({required this.left, required this.height, required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Positioned(
|
||||
left: left ? 0 : null,
|
||||
right: left ? null : 0,
|
||||
top: 0,
|
||||
height: height,
|
||||
child: Center(
|
||||
child: ExcludeFocus(
|
||||
child: IconButton.filledTonal(
|
||||
tooltip: left ? 'Previous' : 'Next',
|
||||
onPressed: onTap,
|
||||
icon: Icon(left ? Icons.chevron_left : Icons.chevron_right),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Section heading used above grids and rows.
|
||||
class SectionHeader extends StatelessWidget {
|
||||
final String title;
|
||||
final String? count;
|
||||
final Widget? trailing;
|
||||
const SectionHeader(this.title, {super.key, this.count, this.trailing});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, top: 4),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(title, style: t.titleMedium),
|
||||
if (count != null) ...[
|
||||
const SizedBox(width: 8),
|
||||
Text(count!, style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
],
|
||||
const Spacer(),
|
||||
?trailing,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'browse_scope.dart';
|
||||
import 'format.dart';
|
||||
import 'images.dart';
|
||||
|
||||
/// Movie / episode detail: art, title, meta, overview, the pick button and
|
||||
/// what is in the file (video, audio and subtitle tracks).
|
||||
class JellyfinDetailPage extends StatelessWidget {
|
||||
final JellyfinItem item;
|
||||
const JellyfinDetailPage({super.key, required this.item});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
return Loader<JellyfinItem>(
|
||||
key: ValueKey('detail-${item.id}-${scope.account.serverId}'),
|
||||
load: () => scope.load('item:${item.id}', (c) => c.item(item.id)),
|
||||
builder: (context, full) => _Detail(item: full),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Detail extends StatelessWidget {
|
||||
final JellyfinItem item;
|
||||
const _Detail({required this.item});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
final theme = Theme.of(context);
|
||||
final t = theme.textTheme;
|
||||
final episode = item.kind == JellyfinItemKind.episode;
|
||||
final selected = scope.selectedItemId == item.id;
|
||||
final meta = [
|
||||
?item.episodeLabel,
|
||||
if (item.productionYear != null) '${item.productionYear}',
|
||||
if (item.runTime != null) formatRuntime(item.runTime!),
|
||||
?timeLeft(item),
|
||||
if (item.officialRating != null) item.officialRating!,
|
||||
if (item.communityRating != null) '★ ${item.communityRating!.toStringAsFixed(1)}',
|
||||
if (item.userData.played) 'Watched',
|
||||
].join(' · ');
|
||||
|
||||
final art = episode
|
||||
? AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: JellyfinImage(
|
||||
client: scope.client,
|
||||
image: item.ownImage(JellyfinImageType.primary) ??
|
||||
item.image(JellyfinImageType.backdrop),
|
||||
icon: Icons.tv_outlined),
|
||||
),
|
||||
)
|
||||
: AspectRatio(
|
||||
aspectRatio: 2 / 3,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: JellyfinImage(
|
||||
client: scope.client, image: item.image(JellyfinImageType.primary)),
|
||||
),
|
||||
);
|
||||
|
||||
final info = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (episode && item.seriesName != null)
|
||||
TextButton.icon(
|
||||
key: const ValueKey('detail-series'),
|
||||
style: TextButton.styleFrom(padding: EdgeInsets.zero),
|
||||
onPressed: () => scope.openSeriesOf(item),
|
||||
icon: const Icon(Icons.live_tv_outlined, size: 18),
|
||||
label: Text(item.seriesName!, style: t.titleMedium),
|
||||
),
|
||||
SelectableText(item.name, style: t.headlineSmall),
|
||||
const SizedBox(height: 6),
|
||||
Text(meta, style: t.bodyMedium?.copyWith(color: Colors.grey)),
|
||||
if (progressOf(item) > 0) ...[
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
width: 240,
|
||||
child: LinearProgressIndicator(value: progressOf(item), minHeight: 4)),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
FilledButton.icon(
|
||||
key: const ValueKey('detail-pick'),
|
||||
onPressed: () => scope.onPick(item),
|
||||
icon: Icon(selected ? Icons.check : Icons.play_arrow),
|
||||
label: Text(selected ? 'Picked' : 'Pick to watch'),
|
||||
),
|
||||
if (item.overview != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 760),
|
||||
child: SelectableText(item.overview!, style: t.bodyMedium),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
_Tracks(item: item),
|
||||
],
|
||||
);
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
child: LayoutBuilder(builder: (context, box) {
|
||||
final wide = box.maxWidth >= 760;
|
||||
final artWidth = episode ? (box.maxWidth * 0.32).clamp(280.0, 480.0) : 240.0;
|
||||
if (!wide) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: SizedBox(width: episode ? 320 : 180, child: art)),
|
||||
const SizedBox(height: 16),
|
||||
info,
|
||||
],
|
||||
);
|
||||
}
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(width: artWidth, child: art),
|
||||
const SizedBox(width: 24),
|
||||
Expanded(child: info),
|
||||
],
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// What the file holds, one line per track kind.
|
||||
class _Tracks extends StatelessWidget {
|
||||
final JellyfinItem item;
|
||||
const _Tracks({required this.item});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
final source = item.mediaSources.firstOrNull;
|
||||
final streams = source?.mediaStreams.isNotEmpty == true ? source!.mediaStreams : item.mediaStreams;
|
||||
if (streams.isEmpty) return const SizedBox.shrink();
|
||||
String names(JellyfinStreamType type) => streams
|
||||
.where((s) => s.type == type)
|
||||
.map((s) => s.displayTitle ?? [s.language, s.codec].whereType<String>().join(' '))
|
||||
.join(' · ');
|
||||
final rows = [
|
||||
('Video', names(JellyfinStreamType.video)),
|
||||
('Audio', names(JellyfinStreamType.audio)),
|
||||
('Subtitles', names(JellyfinStreamType.subtitle)),
|
||||
if (source?.container != null || source?.size != null)
|
||||
('File', [
|
||||
?source?.container,
|
||||
if (source?.size != null) '${(source!.size! / (1 << 30)).toStringAsFixed(2)} GB',
|
||||
].join(' · ')),
|
||||
].where((r) => r.$2.isNotEmpty);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
for (final (label, value) in rows)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 6),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 84,
|
||||
child: Text(label, style: t.bodySmall?.copyWith(color: Colors.grey))),
|
||||
Expanded(child: Text(value, style: t.bodySmall)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import '../screens/home/picked_media.dart';
|
||||
import 'accounts.dart';
|
||||
|
||||
/// "1 h 42 min", "24 min", "45 s".
|
||||
String formatRuntime(Duration d) {
|
||||
final h = d.inHours, m = d.inMinutes % 60;
|
||||
if (h > 0) return m == 0 ? '$h h' : '$h h $m min';
|
||||
if (d.inMinutes > 0) return '${d.inMinutes} min';
|
||||
return '${d.inSeconds} s';
|
||||
}
|
||||
|
||||
/// Watched share of a resumable item, 0 when there is no resume point.
|
||||
double progressOf(JellyfinItem item) {
|
||||
final run = item.runTimeTicks;
|
||||
final pos = item.userData.playbackPositionTicks;
|
||||
if (run == null || run <= 0 || pos <= 0) return 0;
|
||||
return (pos / run).clamp(0.0, 1.0);
|
||||
}
|
||||
|
||||
/// "12 min left" for a resumable item, else null.
|
||||
String? timeLeft(JellyfinItem item) {
|
||||
final run = item.runTimeTicks;
|
||||
if (run == null || !item.userData.isResumable) return null;
|
||||
final left = ticksToDuration(run - item.userData.playbackPositionTicks);
|
||||
if (left.inMinutes < 1) return 'almost done';
|
||||
return '${formatRuntime(left)} left';
|
||||
}
|
||||
|
||||
bool isPlayable(JellyfinItem item) => switch (item.kind) {
|
||||
JellyfinItemKind.movie || JellyfinItemKind.episode || JellyfinItemKind.video => true,
|
||||
_ => !item.isFolder && item.mediaType == 'Video',
|
||||
};
|
||||
|
||||
/// Line under a card title: "S2E3 · 12 min left", "2019 · 24 eps", ...
|
||||
String cardSubtitle(JellyfinItem item, {bool withSeries = false}) {
|
||||
final parts = <String>[];
|
||||
switch (item.kind) {
|
||||
case JellyfinItemKind.episode:
|
||||
if (withSeries && item.seriesName != null) parts.add(item.seriesName!);
|
||||
parts.add(item.episodeLabel ?? item.seasonName ?? 'Episode');
|
||||
case JellyfinItemKind.series:
|
||||
if (item.productionYear != null) parts.add('${item.productionYear}');
|
||||
final eps = item.recursiveItemCount, seasons = item.childCount;
|
||||
if (eps != null && eps > 0) {
|
||||
parts.add('$eps eps');
|
||||
} else if (seasons != null && seasons > 0) {
|
||||
parts.add(seasons == 1 ? '1 season' : '$seasons seasons');
|
||||
}
|
||||
case JellyfinItemKind.season:
|
||||
final n = item.childCount ?? item.recursiveItemCount;
|
||||
if (n != null) parts.add('$n eps');
|
||||
default:
|
||||
if (item.productionYear != null) parts.add('${item.productionYear}');
|
||||
}
|
||||
final left = timeLeft(item);
|
||||
if (left != null) {
|
||||
parts.add(left);
|
||||
} else if (isPlayable(item) && item.runTime != null) {
|
||||
parts.add(formatRuntime(item.runTime!));
|
||||
}
|
||||
return parts.join(' · ');
|
||||
}
|
||||
|
||||
/// Title on a card: episodes in rows that mix series show the series name
|
||||
/// on top and the episode below.
|
||||
String cardTitle(JellyfinItem item, {bool seriesFirst = false}) =>
|
||||
seriesFirst && item.kind == JellyfinItemKind.episode && item.seriesName != null
|
||||
? item.seriesName!
|
||||
: item.name;
|
||||
|
||||
/// The selection for a playable [item] of [account].
|
||||
JellyfinMedia pickFor(JellyfinAccount account, JellyfinItem item) {
|
||||
final String subtitle;
|
||||
if (item.kind == JellyfinItemKind.episode) {
|
||||
subtitle = [?item.seriesName, ?item.episodeLabel].join(' · ');
|
||||
} else {
|
||||
subtitle = item.productionYear?.toString() ?? '';
|
||||
}
|
||||
return JellyfinMedia(
|
||||
serverId: account.serverId,
|
||||
baseUrl: account.baseUrl,
|
||||
itemId: item.id,
|
||||
mediaSourceId: item.mediaSources.length > 1 ? item.mediaSources.first.id : null,
|
||||
title: item.name,
|
||||
subtitle: subtitle,
|
||||
runtime: item.runTime,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'browse_scope.dart';
|
||||
import 'cards.dart';
|
||||
|
||||
/// Libraries that hold videos; music, books, photos and playlists are left
|
||||
/// out of the browser.
|
||||
bool isVideoLibrary(JellyfinItem view) => switch (view.collectionType) {
|
||||
'movies' || 'tvshows' || 'homevideos' || 'boxsets' || 'mixed' || 'musicvideos' || null => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
IconData libraryIcon(JellyfinItem view) => switch (view.collectionType) {
|
||||
'movies' => Icons.movie_outlined,
|
||||
'tvshows' => Icons.live_tv_outlined,
|
||||
'boxsets' => Icons.collections_bookmark_outlined,
|
||||
'homevideos' => Icons.videocam_outlined,
|
||||
_ => Icons.folder_outlined,
|
||||
};
|
||||
|
||||
/// Start page: library shortcuts, then Continue watching, Next up and the
|
||||
/// latest additions of each library. Each row loads on its own, so a slow
|
||||
/// library does not hold up the rest.
|
||||
class JellyfinHomePage extends StatelessWidget {
|
||||
const JellyfinHomePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
return Loader<List<JellyfinItem>>(
|
||||
key: ValueKey('views-${scope.account.serverId}'),
|
||||
load: () => scope.load('views', (c) => c.userViews()),
|
||||
builder: (context, all) {
|
||||
final views = all.where(isVideoLibrary).toList();
|
||||
return ListView(
|
||||
key: const PageStorageKey('jf-home'),
|
||||
padding: const EdgeInsets.fromLTRB(0, 4, 0, 24),
|
||||
children: [
|
||||
_LibraryStrip(views: views),
|
||||
const SizedBox(height: 20),
|
||||
_Section(
|
||||
key: const ValueKey('row-resume'),
|
||||
title: 'Continue watching',
|
||||
shape: CardShape.thumb,
|
||||
seriesFirst: true,
|
||||
load: () => scope.load('resume', (c) => c.resume(limit: 30)),
|
||||
),
|
||||
_Section(
|
||||
key: const ValueKey('row-nextup'),
|
||||
title: 'Next up',
|
||||
shape: CardShape.thumb,
|
||||
seriesFirst: true,
|
||||
load: () => scope.load('nextup', (c) => c.nextUp(limit: 30)),
|
||||
),
|
||||
for (final v in views)
|
||||
_Section(
|
||||
key: ValueKey('row-latest-${v.id}'),
|
||||
title: 'Latest in ${v.name}',
|
||||
shape: v.collectionType == 'homevideos' ? CardShape.thumb : CardShape.poster,
|
||||
load: () => scope.load('latest:${v.id}', (c) => c.latest(v.id, limit: 30)),
|
||||
trailing: TextButton(
|
||||
onPressed: () => scope.onOpen(LibraryRoute(v)),
|
||||
child: const Text('Show all'),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _LibraryStrip extends StatelessWidget {
|
||||
final List<JellyfinItem> views;
|
||||
const _LibraryStrip({required this.views});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
if (views.isEmpty) {
|
||||
return const Text('No video libraries on this server for your user.',
|
||||
style: TextStyle(color: Colors.grey));
|
||||
}
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
for (final v in views)
|
||||
ActionChip(
|
||||
key: ValueKey('library-${v.id}'),
|
||||
avatar: Icon(libraryIcon(v), size: 18),
|
||||
label: Text(v.name),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
onPressed: () => scope.onOpen(LibraryRoute(v)),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Section extends StatelessWidget {
|
||||
final String title;
|
||||
final CardShape shape;
|
||||
final bool seriesFirst;
|
||||
final Future<List<JellyfinItem>> Function() load;
|
||||
final Widget? trailing;
|
||||
const _Section({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.shape,
|
||||
required this.load,
|
||||
this.seriesFirst = false,
|
||||
this.trailing,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Loader<List<JellyfinItem>>(
|
||||
load: load,
|
||||
showError: false,
|
||||
loading: _RowSkeleton(title: title, shape: shape),
|
||||
builder: (context, items) => items.isEmpty
|
||||
? const SizedBox.shrink()
|
||||
: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
child: MediaRow(
|
||||
title: title,
|
||||
items: items,
|
||||
shape: shape,
|
||||
seriesFirst: seriesFirst,
|
||||
trailing: trailing,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _RowSkeleton extends StatelessWidget {
|
||||
final String title;
|
||||
final CardShape shape;
|
||||
const _RowSkeleton({required this.title, required this.shape});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SectionHeader(title),
|
||||
LayoutBuilder(builder: (context, box) {
|
||||
final fit = fitColumns(box.maxWidth, shape.minWidth);
|
||||
return Row(
|
||||
children: [
|
||||
for (var i = 0; i < fit.cols; i++) ...[
|
||||
if (i > 0) const SizedBox(width: cardGap),
|
||||
Expanded(child: SkeletonCard(shape: shape)),
|
||||
],
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SkeletonCard extends StatelessWidget {
|
||||
final CardShape shape;
|
||||
const SkeletonCard({super.key, required this.shape});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final c = Theme.of(context).colorScheme.surfaceContainerHigh.withValues(alpha: 0.6);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: shape.aspect,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(color: c, borderRadius: BorderRadius.circular(8))),
|
||||
),
|
||||
const SizedBox(height: cardTextHeight),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
/// Server-side scale steps: nearby sizes share one URL (and one cache
|
||||
/// entry) instead of fetching per-pixel variants on every resize.
|
||||
const _widthSteps = [160, 240, 320, 480, 640, 960, 1280, 1920, 2560];
|
||||
|
||||
int imageWidthStep(double physicalWidth) {
|
||||
for (final s in _widthSteps) {
|
||||
if (s >= physicalWidth) return s;
|
||||
}
|
||||
return _widthSteps.last;
|
||||
}
|
||||
|
||||
/// A Jellyfin image sized to its box. The URL carries the image tag and the
|
||||
/// width step, so Flutter's image cache (keyed by URL) reuses it until the
|
||||
/// image changes on the server; decode is capped at the same width. Shows
|
||||
/// [placeholder] (or a tinted box with [icon]) while loading and on error,
|
||||
/// and fades in when ready.
|
||||
class JellyfinImage extends StatelessWidget {
|
||||
final JellyfinClient client;
|
||||
final JellyfinImageRef? image;
|
||||
final BoxFit fit;
|
||||
final IconData icon;
|
||||
final Alignment alignment;
|
||||
final Widget? placeholder;
|
||||
const JellyfinImage({
|
||||
super.key,
|
||||
required this.client,
|
||||
required this.image,
|
||||
this.fit = BoxFit.cover,
|
||||
this.icon = Icons.movie_outlined,
|
||||
this.alignment = Alignment.center,
|
||||
this.placeholder,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ref = image;
|
||||
final fallback = placeholder ?? _Placeholder(icon: icon);
|
||||
if (ref == null) return fallback;
|
||||
return LayoutBuilder(builder: (context, box) {
|
||||
final dpr = MediaQuery.maybeDevicePixelRatioOf(context) ?? 1;
|
||||
final w = box.hasBoundedWidth ? box.maxWidth : 480.0;
|
||||
final step = imageWidthStep(w * dpr);
|
||||
final url = client.imageUrl(ref, maxWidth: step, quality: 85).toString();
|
||||
return Image.network(
|
||||
url,
|
||||
key: ValueKey(url),
|
||||
fit: fit,
|
||||
alignment: alignment,
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
cacheWidth: step,
|
||||
filterQuality: FilterQuality.medium,
|
||||
frameBuilder: (context, child, frame, sync) {
|
||||
if (sync) return child;
|
||||
return Stack(fit: StackFit.passthrough, children: [
|
||||
if (frame == null) fallback,
|
||||
AnimatedOpacity(
|
||||
opacity: frame == null ? 0 : 1,
|
||||
duration: const Duration(milliseconds: 180),
|
||||
child: child,
|
||||
),
|
||||
]);
|
||||
},
|
||||
errorBuilder: (context, _, _) => fallback,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _Placeholder extends StatelessWidget {
|
||||
final IconData icon;
|
||||
const _Placeholder({required this.icon});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
return ColoredBox(
|
||||
color: scheme.surfaceContainerHigh,
|
||||
child: Center(
|
||||
child: Icon(icon, size: 28, color: scheme.onSurfaceVariant.withValues(alpha: 0.35)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'browse_scope.dart';
|
||||
import 'format.dart';
|
||||
import 'images.dart';
|
||||
|
||||
/// Side pane on wide windows: details of whatever card is hovered or
|
||||
/// focused, so browsing needs no extra clicks. Pick / Open act on it.
|
||||
class JellyfinInspector extends StatelessWidget {
|
||||
final ValueListenable<JellyfinItem?> item;
|
||||
const JellyfinInspector({super.key, required this.item});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
return DecoratedBox(
|
||||
key: const ValueKey('jf-inspector'),
|
||||
decoration: BoxDecoration(
|
||||
color: scheme.surfaceContainerLow,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: scheme.outlineVariant.withValues(alpha: 0.4)),
|
||||
),
|
||||
child: ValueListenableBuilder<JellyfinItem?>(
|
||||
valueListenable: item,
|
||||
builder: (context, it, _) => it == null
|
||||
? const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Text('Hover or focus a title to see its details here.',
|
||||
textAlign: TextAlign.center, style: TextStyle(color: Colors.grey)),
|
||||
),
|
||||
)
|
||||
: _Body(item: it),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Body extends StatelessWidget {
|
||||
final JellyfinItem item;
|
||||
const _Body({required this.item});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
final t = Theme.of(context).textTheme;
|
||||
final playable = isPlayable(item);
|
||||
final selected = scope.selectedItemId == item.id;
|
||||
final episode = item.kind == JellyfinItemKind.episode;
|
||||
final art = episode
|
||||
? item.ownImage(JellyfinImageType.primary) ?? item.image(JellyfinImageType.backdrop)
|
||||
: item.image(JellyfinImageType.backdrop) ?? item.image(JellyfinImageType.thumb);
|
||||
final meta = [
|
||||
if (item.productionYear != null) '${item.productionYear}',
|
||||
if (playable && item.runTime != null) formatRuntime(item.runTime!),
|
||||
if (item.officialRating != null) item.officialRating!,
|
||||
if (item.communityRating != null) '★ ${item.communityRating!.toStringAsFixed(1)}',
|
||||
if (!playable && (item.userData.unplayedItemCount ?? 0) > 0)
|
||||
'${item.userData.unplayedItemCount} unwatched',
|
||||
if (item.userData.played) 'Watched',
|
||||
].join(' · ');
|
||||
return ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child: JellyfinImage(client: scope.client, image: art),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (episode && item.seriesName != null)
|
||||
Text(item.seriesName!, style: t.labelLarge?.copyWith(color: Colors.grey)),
|
||||
Text(
|
||||
episode && item.episodeLabel != null ? '${item.episodeLabel} ${item.name}' : item.name,
|
||||
style: t.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(meta, style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
if (timeLeft(item) != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
LinearProgressIndicator(value: progressOf(item), minHeight: 3),
|
||||
const SizedBox(height: 4),
|
||||
Text(timeLeft(item)!, style: t.bodySmall),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
Wrap(spacing: 8, runSpacing: 8, children: [
|
||||
if (playable)
|
||||
FilledButton.icon(
|
||||
onPressed: () => scope.onPick(item),
|
||||
icon: Icon(selected ? Icons.check : Icons.play_arrow, size: 18),
|
||||
label: Text(selected ? 'Picked' : 'Pick'),
|
||||
)
|
||||
else
|
||||
FilledButton.tonalIcon(
|
||||
onPressed: () => scope.activate(item),
|
||||
icon: const Icon(Icons.arrow_forward, size: 18),
|
||||
label: const Text('Open'),
|
||||
),
|
||||
if (playable)
|
||||
OutlinedButton(
|
||||
onPressed: () => scope.onOpen(DetailRoute(item)),
|
||||
child: const Text('Details'),
|
||||
),
|
||||
if (episode && item.seriesId != null)
|
||||
OutlinedButton(
|
||||
onPressed: () => scope.openSeriesOf(item),
|
||||
child: const Text('Series'),
|
||||
),
|
||||
]),
|
||||
if (item.overview != null) ...[
|
||||
const SizedBox(height: 12),
|
||||
Text(item.overview!, style: t.bodyMedium),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'browse_scope.dart';
|
||||
import 'cards.dart';
|
||||
import 'home_page.dart' show SkeletonCard;
|
||||
|
||||
enum LibrarySort {
|
||||
name('Name', JellyfinSortBy.sortName, false),
|
||||
added('Date added', JellyfinSortBy.dateCreated, true),
|
||||
premiere('Release date', JellyfinSortBy.premiereDate, true),
|
||||
rating('Rating', JellyfinSortBy.communityRating, true),
|
||||
random('Random', JellyfinSortBy.random, false);
|
||||
|
||||
final String label;
|
||||
final String apiName;
|
||||
/// Natural direction: newest / best first.
|
||||
final bool descending;
|
||||
const LibrarySort(this.label, this.apiName, this.descending);
|
||||
}
|
||||
|
||||
/// Item types and recursion for a library: movie and show libraries list
|
||||
/// their titles flat; anything else is browsed folder by folder.
|
||||
({List<String> types, bool recursive}) libraryShape(JellyfinItem folder) =>
|
||||
switch (folder.collectionType) {
|
||||
'movies' => (types: const [JellyfinItemType.movie], recursive: true),
|
||||
'tvshows' => (types: const [JellyfinItemType.series], recursive: true),
|
||||
'boxsets' => (types: const [JellyfinItemType.boxSet], recursive: true),
|
||||
_ => (types: const <String>[], recursive: false),
|
||||
};
|
||||
|
||||
const libraryPageSize = 100;
|
||||
|
||||
/// One library (or folder) as a grid that fills the width, with sort,
|
||||
/// unplayed / favourite filters and infinite scroll. The scrollbar spans
|
||||
/// the full count from the start: not-yet-loaded cells are skeletons and
|
||||
/// pages load as they come near the viewport.
|
||||
class JellyfinLibraryPage extends StatefulWidget {
|
||||
final JellyfinItem folder;
|
||||
const JellyfinLibraryPage({super.key, required this.folder});
|
||||
|
||||
@override
|
||||
State<JellyfinLibraryPage> createState() => _JellyfinLibraryPageState();
|
||||
}
|
||||
|
||||
class _JellyfinLibraryPageState extends State<JellyfinLibraryPage> {
|
||||
LibrarySort _sort = LibrarySort.name;
|
||||
bool _descending = false;
|
||||
bool _unplayed = false;
|
||||
bool _favorites = false;
|
||||
|
||||
final _items = <JellyfinItem>[];
|
||||
int? _total;
|
||||
bool _loading = false;
|
||||
Object? _error;
|
||||
int _gen = 0;
|
||||
final _scroll = ScrollController();
|
||||
|
||||
BrowseScope? _scope;
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
final scope = BrowseScope.of(context);
|
||||
final first = _scope == null;
|
||||
final changedServer = _scope != null && _scope!.client != scope.client;
|
||||
_scope = scope;
|
||||
if (first || changedServer) _reload();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scroll.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
JellyfinItemQuery get _query {
|
||||
final shape = libraryShape(widget.folder);
|
||||
return JellyfinItemQuery(
|
||||
parentId: widget.folder.id,
|
||||
includeItemTypes: shape.types,
|
||||
recursive: shape.recursive,
|
||||
sortBy: [
|
||||
// Folders first when browsing a folder tree.
|
||||
if (!shape.recursive && _sort == LibrarySort.name) 'IsFolder',
|
||||
_sort.apiName,
|
||||
if (_sort != LibrarySort.name) JellyfinSortBy.sortName,
|
||||
],
|
||||
descending: _descending,
|
||||
filters: [
|
||||
if (_unplayed) JellyfinFilter.isUnplayed,
|
||||
if (_favorites) JellyfinFilter.isFavorite,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _reload() {
|
||||
_gen++;
|
||||
_items.clear();
|
||||
_total = null;
|
||||
_error = null;
|
||||
_loading = false;
|
||||
if (_scroll.hasClients) _scroll.jumpTo(0);
|
||||
_loadMore();
|
||||
}
|
||||
|
||||
Future<void> _loadMore() async {
|
||||
final scope = _scope;
|
||||
if (scope == null || _loading) return;
|
||||
if (_total != null && _items.length >= _total!) return;
|
||||
final gen = _gen;
|
||||
setState(() {
|
||||
_loading = true;
|
||||
_error = null;
|
||||
});
|
||||
try {
|
||||
final page = await scope.client.items(_query.page(_items.length, libraryPageSize));
|
||||
if (gen != _gen || !mounted) return;
|
||||
setState(() {
|
||||
_items.addAll(page.items);
|
||||
// An empty page before the advertised end: the library shrank.
|
||||
_total = page.items.isEmpty ? _items.length : page.totalRecordCount;
|
||||
_loading = false;
|
||||
});
|
||||
} catch (e) {
|
||||
if (gen != _gen || !mounted) return;
|
||||
if (e is JellyfinException && e.isUnauthorized) {
|
||||
scope.accounts.markExpired(scope.account.serverId);
|
||||
}
|
||||
setState(() {
|
||||
_loading = false;
|
||||
_error = e;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _setSort(LibrarySort s) {
|
||||
setState(() {
|
||||
_sort = s;
|
||||
_descending = s.descending;
|
||||
});
|
||||
_reload();
|
||||
}
|
||||
|
||||
CardShape get _shape =>
|
||||
widget.folder.collectionType == 'homevideos' ? CardShape.thumb : CardShape.poster;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
final total = _total;
|
||||
final toolbar = Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Text(widget.folder.name, style: t.titleLarge),
|
||||
const SizedBox(width: 4),
|
||||
Text(total == null ? '' : '$total ${total == 1 ? 'item' : 'items'}',
|
||||
key: const ValueKey('library-count'),
|
||||
style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
const SizedBox(width: 12),
|
||||
_SortMenu(sort: _sort, onSelected: _setSort),
|
||||
if (_sort != LibrarySort.random)
|
||||
IconButton(
|
||||
tooltip: _descending ? 'Descending' : 'Ascending',
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: () {
|
||||
setState(() => _descending = !_descending);
|
||||
_reload();
|
||||
},
|
||||
icon: Icon(_descending ? Icons.arrow_downward : Icons.arrow_upward, size: 18),
|
||||
)
|
||||
else
|
||||
IconButton(
|
||||
tooltip: 'Shuffle again',
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: _reload,
|
||||
icon: const Icon(Icons.shuffle, size: 18),
|
||||
),
|
||||
FilterChip(
|
||||
key: const ValueKey('filter-unplayed'),
|
||||
label: const Text('Unwatched'),
|
||||
selected: _unplayed,
|
||||
visualDensity: VisualDensity.compact,
|
||||
onSelected: (v) {
|
||||
setState(() => _unplayed = v);
|
||||
_reload();
|
||||
},
|
||||
),
|
||||
FilterChip(
|
||||
key: const ValueKey('filter-favorites'),
|
||||
label: const Text('Favorites'),
|
||||
selected: _favorites,
|
||||
visualDensity: VisualDensity.compact,
|
||||
onSelected: (v) {
|
||||
setState(() => _favorites = v);
|
||||
_reload();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
final count = total ?? (_loading ? libraryPageSize ~/ 4 : 0);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Padding(padding: const EdgeInsets.only(bottom: 12), child: toolbar),
|
||||
if (_error != null && _items.isEmpty)
|
||||
LoadError(error: _error!, onRetry: _loadMore)
|
||||
else if (total == 0)
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(32),
|
||||
child: Center(child: Text('Nothing here', style: TextStyle(color: Colors.grey))),
|
||||
)
|
||||
else
|
||||
Expanded(
|
||||
child: Scrollbar(
|
||||
controller: _scroll,
|
||||
child: CustomScrollView(
|
||||
controller: _scroll,
|
||||
slivers: [
|
||||
SliverGrid(
|
||||
gridDelegate: CardGridDelegate(_shape),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, i) {
|
||||
if (i >= _items.length - 40 && _error == null) {
|
||||
// Near the loaded edge: fetch the next page.
|
||||
scheduleMicrotask(_loadMore);
|
||||
}
|
||||
if (i >= _items.length) return SkeletonCard(shape: _shape);
|
||||
return MediaCard(item: _items[i], shape: _shape);
|
||||
},
|
||||
childCount: count,
|
||||
),
|
||||
),
|
||||
if (_error != null && _items.isNotEmpty)
|
||||
SliverToBoxAdapter(child: LoadError(error: _error!, onRetry: _loadMore)),
|
||||
const SliverToBoxAdapter(child: SizedBox(height: 24)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SortMenu extends StatelessWidget {
|
||||
final LibrarySort sort;
|
||||
final ValueChanged<LibrarySort> onSelected;
|
||||
const _SortMenu({required this.sort, required this.onSelected});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MenuAnchor(
|
||||
menuChildren: [
|
||||
for (final s in LibrarySort.values)
|
||||
MenuItemButton(
|
||||
key: ValueKey('sort-${s.name}'),
|
||||
leadingIcon: Icon(s == sort ? Icons.check : null, size: 18),
|
||||
onPressed: () => onSelected(s),
|
||||
child: Text(s.label),
|
||||
),
|
||||
],
|
||||
builder: (context, menu, _) => OutlinedButton.icon(
|
||||
key: const ValueKey('library-sort'),
|
||||
onPressed: () => menu.isOpen ? menu.close() : menu.open(),
|
||||
icon: const Icon(Icons.sort, size: 18),
|
||||
label: Text(sort.label),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../screens/home/picked_media.dart';
|
||||
import '../screens/home/ui.dart';
|
||||
import 'accounts.dart';
|
||||
import 'browse_scope.dart';
|
||||
import 'browser.dart';
|
||||
import 'sign_in_panel.dart';
|
||||
|
||||
/// The media picker's Jellyfin source: the library browser once a server
|
||||
/// is linked, else an inline add-server panel.
|
||||
class JellyfinPickerSource extends StatefulWidget {
|
||||
final JellyfinAccounts accounts;
|
||||
final JellyfinMedia? selected;
|
||||
final ValueChanged<JellyfinMedia> onPick;
|
||||
final VoidCallback? onOpenIntegrations;
|
||||
final VoidCallback? onToggleExpanded;
|
||||
final bool expanded;
|
||||
final BrowseStart? start;
|
||||
const JellyfinPickerSource({
|
||||
super.key,
|
||||
this.start,
|
||||
required this.accounts,
|
||||
required this.onPick,
|
||||
this.selected,
|
||||
this.onOpenIntegrations,
|
||||
this.onToggleExpanded,
|
||||
this.expanded = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<JellyfinPickerSource> createState() => _JellyfinPickerSourceState();
|
||||
}
|
||||
|
||||
class _JellyfinPickerSourceState extends State<JellyfinPickerSource> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
widget.accounts.ensureLoaded();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListenableBuilder(
|
||||
listenable: widget.accounts,
|
||||
builder: (context, _) {
|
||||
final a = widget.accounts;
|
||||
if (!a.loaded) {
|
||||
return const Center(child: CircularProgressIndicator(strokeWidth: 2));
|
||||
}
|
||||
if (a.isEmpty) return _LinkFirst(accounts: a, onOpenIntegrations: widget.onOpenIntegrations);
|
||||
return JellyfinBrowser(
|
||||
key: const ValueKey('media-jellyfin'),
|
||||
accounts: a,
|
||||
selected: widget.selected,
|
||||
onPick: widget.onPick,
|
||||
onOpenIntegrations: widget.onOpenIntegrations,
|
||||
onToggleExpanded: widget.onToggleExpanded,
|
||||
expanded: widget.expanded,
|
||||
start: widget.start,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _LinkFirst extends StatelessWidget {
|
||||
final JellyfinAccounts accounts;
|
||||
final VoidCallback? onOpenIntegrations;
|
||||
const _LinkFirst({required this.accounts, this.onOpenIntegrations});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
key: const ValueKey('media-jellyfin'),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 560),
|
||||
child: Panel(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('Link a Jellyfin server to browse it here. '
|
||||
'You can manage linked servers in Integrations.',
|
||||
style: TextStyle(color: Colors.grey)),
|
||||
const SizedBox(height: kGap),
|
||||
JellyfinSignInPanel(accounts: accounts),
|
||||
if (onOpenIntegrations != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: TextButton(
|
||||
onPressed: onOpenIntegrations, child: const Text('Open Integrations')),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
/// What the player shows, sampled about once a second. [aid] / [sid] are
|
||||
/// mpv track ids (null = none / subtitles off).
|
||||
class PlayerSnapshot {
|
||||
final double position;
|
||||
final bool paused;
|
||||
final int? aid;
|
||||
final int? sid;
|
||||
const PlayerSnapshot({required this.position, required this.paused, this.aid, this.sid});
|
||||
|
||||
@override
|
||||
String toString() => 'PlayerSnapshot($position, paused: $paused, aid: $aid, sid: $sid)';
|
||||
}
|
||||
|
||||
/// Playing / Progress / Stopped for one item played with this viewer's own
|
||||
/// account, so Jellyfin's watched state and Continue Watching follow what
|
||||
/// this viewer saw. Fed a [PlayerSnapshot] every tick ([update]); sends
|
||||
/// Progress every [interval] and at once on pause, resume, seek (a jump of
|
||||
/// more than 3 s from where playback should be) or a track change. Reports
|
||||
/// go out one after another; a failure is logged and handed to [onError]
|
||||
/// (the session shows one quiet toast) and never touches playback. A 401
|
||||
/// calls [onUnauthorized] and ends reporting.
|
||||
class JellyfinProgressReporter {
|
||||
final JellyfinClient client;
|
||||
final String itemId;
|
||||
final JellyfinMediaSource source;
|
||||
final String playSessionId;
|
||||
final Duration interval;
|
||||
final DateTime Function() _clock;
|
||||
final void Function(Object error)? onError;
|
||||
final VoidCallback? onUnauthorized;
|
||||
|
||||
JellyfinProgressReporter({
|
||||
required this.client,
|
||||
required this.itemId,
|
||||
required this.source,
|
||||
required this.playSessionId,
|
||||
this.interval = const Duration(seconds: 10),
|
||||
this.onError,
|
||||
this.onUnauthorized,
|
||||
DateTime Function()? clock,
|
||||
}) : _clock = clock ?? DateTime.now;
|
||||
|
||||
Future<void> _chain = Future.value();
|
||||
bool _playing = false;
|
||||
bool _dead = false;
|
||||
PlayerSnapshot? _last;
|
||||
DateTime? _lastAt;
|
||||
DateTime? _lastSentAt;
|
||||
|
||||
/// Between [start] and [stop].
|
||||
bool get active => _playing && !_dead;
|
||||
|
||||
/// The report body for [s]: ticks, pause, and mpv's aid/sid mapped to
|
||||
/// Jellyfin stream indices (-1 = subtitles off).
|
||||
JellyfinPlaybackReport reportFor(PlayerSnapshot s) => JellyfinPlaybackReport(
|
||||
itemId: itemId,
|
||||
mediaSourceId: source.id,
|
||||
playSessionId: playSessionId,
|
||||
positionTicks: (s.position * jellyfinTicksPerSecond).round(),
|
||||
isPaused: s.paused,
|
||||
audioStreamIndex: s.aid == null
|
||||
? null
|
||||
: source.jellyfinIndexForMpvTrack(JellyfinStreamType.audio, s.aid!),
|
||||
subtitleStreamIndex: s.sid == null
|
||||
? -1
|
||||
: source.jellyfinIndexForMpvTrack(JellyfinStreamType.subtitle, s.sid!),
|
||||
);
|
||||
|
||||
/// Playing: once the media is open. Again after [stop] (played to the
|
||||
/// end, then someone seeked back) starts reporting anew.
|
||||
void start(PlayerSnapshot s) {
|
||||
if (_playing || _dead) return;
|
||||
_playing = true;
|
||||
_mark(s);
|
||||
_send('Playing', () => client.reportPlaybackStart(reportFor(s)));
|
||||
}
|
||||
|
||||
/// Progress when due (see the class doc).
|
||||
void update(PlayerSnapshot s, {bool force = false}) {
|
||||
if (!_playing || _dead) return;
|
||||
final last = _last, lastAt = _lastAt, sentAt = _lastSentAt;
|
||||
final now = _clock();
|
||||
var due = force || last == null || lastAt == null || sentAt == null;
|
||||
if (!due) {
|
||||
final elapsed = now.difference(lastAt).inMilliseconds / 1000;
|
||||
final expected = last.position + (last.paused ? 0 : elapsed);
|
||||
due = s.paused != last.paused ||
|
||||
s.aid != last.aid ||
|
||||
s.sid != last.sid ||
|
||||
(s.position - expected).abs() > 3 ||
|
||||
now.difference(sentAt) >= interval;
|
||||
}
|
||||
_last = s;
|
||||
_lastAt = now;
|
||||
if (!due) return;
|
||||
_lastSentAt = now;
|
||||
_send('Progress', () => client.reportPlaybackProgress(reportFor(s)));
|
||||
}
|
||||
|
||||
/// Stopped (swap, leave, kick, window close, played to the end).
|
||||
/// Completes when it and everything before it went out.
|
||||
Future<void> stop(PlayerSnapshot s) {
|
||||
if (!_playing || _dead) return _chain;
|
||||
_playing = false;
|
||||
_send('Stopped', () => client.reportPlaybackStopped(reportFor(s)));
|
||||
return _chain;
|
||||
}
|
||||
|
||||
void _mark(PlayerSnapshot s) {
|
||||
_last = s;
|
||||
_lastAt = _lastSentAt = _clock();
|
||||
}
|
||||
|
||||
void _send(String what, Future<void> Function() call) {
|
||||
_chain = _chain.then((_) async {
|
||||
if (_dead) return;
|
||||
try {
|
||||
await call().timeout(const Duration(seconds: 10));
|
||||
} catch (e) {
|
||||
debugPrint('jellyfin $what report for $itemId failed: $e');
|
||||
if (e is JellyfinException && e.isUnauthorized) {
|
||||
_dead = true;
|
||||
onUnauthorized?.call();
|
||||
}
|
||||
onError?.call(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'browse_scope.dart';
|
||||
import 'cards.dart';
|
||||
|
||||
/// Search results grouped by kind: shows and movies as posters, episodes
|
||||
/// as thumbnails, each a grid that fills the width.
|
||||
class JellyfinSearchResults extends StatelessWidget {
|
||||
final String term;
|
||||
const JellyfinSearchResults({super.key, required this.term});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
return Loader<List<JellyfinItem>>(
|
||||
key: ValueKey('search-$term-${scope.account.serverId}'),
|
||||
load: () => scope.load('search:$term', (c) => c.search(term, limit: 80)),
|
||||
builder: (context, items) {
|
||||
if (items.isEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Center(
|
||||
child: Text('Nothing found for "$term"',
|
||||
key: const ValueKey('search-empty'),
|
||||
style: const TextStyle(color: Colors.grey)),
|
||||
),
|
||||
);
|
||||
}
|
||||
final groups = [
|
||||
('Shows', CardShape.poster, items.where((i) => i.kind == JellyfinItemKind.series).toList()),
|
||||
('Movies', CardShape.poster, items.where((i) => i.kind == JellyfinItemKind.movie).toList()),
|
||||
('Episodes', CardShape.thumb, items.where((i) => i.kind == JellyfinItemKind.episode).toList()),
|
||||
(
|
||||
'Other',
|
||||
CardShape.poster,
|
||||
items
|
||||
.where((i) => !const [
|
||||
JellyfinItemKind.series,
|
||||
JellyfinItemKind.movie,
|
||||
JellyfinItemKind.episode
|
||||
].contains(i.kind))
|
||||
.toList()
|
||||
),
|
||||
].where((g) => g.$3.isNotEmpty);
|
||||
return CustomScrollView(
|
||||
key: const ValueKey('search-results'),
|
||||
slivers: [
|
||||
for (final (title, shape, list) in groups) ...[
|
||||
SliverToBoxAdapter(child: SectionHeader(title, count: '${list.length}')),
|
||||
SliverGrid(
|
||||
gridDelegate: CardGridDelegate(shape),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, i) => MediaCard(
|
||||
item: list[i],
|
||||
shape: shape,
|
||||
seriesFirst: shape == CardShape.thumb,
|
||||
),
|
||||
childCount: list.length,
|
||||
),
|
||||
),
|
||||
const SliverToBoxAdapter(child: SizedBox(height: 16)),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'browse_scope.dart';
|
||||
import 'format.dart';
|
||||
import 'images.dart';
|
||||
|
||||
/// Series page: backdrop + logo header with overview and the smart "next
|
||||
/// unwatched" button, a season selector and the season's episodes as dense
|
||||
/// rows (several columns on wide windows).
|
||||
class JellyfinSeriesPage extends StatefulWidget {
|
||||
final JellyfinItem series;
|
||||
final String? seasonId;
|
||||
const JellyfinSeriesPage({super.key, required this.series, this.seasonId});
|
||||
|
||||
@override
|
||||
State<JellyfinSeriesPage> createState() => _JellyfinSeriesPageState();
|
||||
}
|
||||
|
||||
typedef _SeriesData = ({JellyfinItem series, List<JellyfinItem> seasons, JellyfinItem? next});
|
||||
|
||||
class _JellyfinSeriesPageState extends State<JellyfinSeriesPage> {
|
||||
String? _seasonId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_seasonId = widget.seasonId;
|
||||
}
|
||||
|
||||
Future<_SeriesData> _load(BrowseScope scope) async {
|
||||
final id = widget.series.id;
|
||||
final results = await Future.wait<Object?>([
|
||||
scope.load('item:$id', (c) => c.item(id)),
|
||||
scope.load('seasons:$id', (c) => c.seasons(id)),
|
||||
scope
|
||||
.load('next:$id', (c) => c.nextUp(seriesId: id, limit: 1, enableResumable: true))
|
||||
.then<List<JellyfinItem>?>((v) => v, onError: (_) => null),
|
||||
]);
|
||||
final next = results[2] as List<JellyfinItem>?;
|
||||
return (
|
||||
series: results[0] as JellyfinItem,
|
||||
seasons: results[1] as List<JellyfinItem>,
|
||||
next: next == null || next.isEmpty ? null : next.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Season to show first: the one holding the next episode, else the first
|
||||
/// with something unwatched, else the first.
|
||||
String? _defaultSeason(_SeriesData d) {
|
||||
if (d.seasons.isEmpty) return null;
|
||||
final nextSeason = d.next?.seasonId;
|
||||
if (nextSeason != null && d.seasons.any((s) => s.id == nextSeason)) return nextSeason;
|
||||
return (d.seasons.where((s) => !s.userData.played).firstOrNull ?? d.seasons.first).id;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
return Loader<_SeriesData>(
|
||||
key: ValueKey('series-${widget.series.id}-${scope.account.serverId}'),
|
||||
load: () => _load(scope),
|
||||
builder: (context, d) {
|
||||
final seasonId = (_seasonId != null && d.seasons.any((s) => s.id == _seasonId))
|
||||
? _seasonId
|
||||
: _defaultSeason(d);
|
||||
return CustomScrollView(
|
||||
key: PageStorageKey('series-${widget.series.id}'),
|
||||
slivers: [
|
||||
SliverToBoxAdapter(child: _SeriesHeader(data: d)),
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
for (final s in d.seasons)
|
||||
ChoiceChip(
|
||||
key: ValueKey('season-${s.id}'),
|
||||
label: Text(s.name),
|
||||
avatar: s.userData.played
|
||||
? const Icon(Icons.check, size: 16)
|
||||
: null,
|
||||
showCheckmark: false,
|
||||
selected: s.id == seasonId,
|
||||
onSelected: (_) => setState(() => _seasonId = s.id),
|
||||
tooltip: s.userData.unplayedItemCount != null
|
||||
? '${s.userData.unplayedItemCount} unwatched'
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (seasonId != null)
|
||||
_EpisodeList(
|
||||
key: ValueKey('episodes-$seasonId'),
|
||||
seriesId: widget.series.id,
|
||||
seasonId: seasonId,
|
||||
),
|
||||
const SliverToBoxAdapter(child: SizedBox(height: 24)),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SeriesHeader extends StatefulWidget {
|
||||
final _SeriesData data;
|
||||
const _SeriesHeader({required this.data});
|
||||
|
||||
@override
|
||||
State<_SeriesHeader> createState() => _SeriesHeaderState();
|
||||
}
|
||||
|
||||
class _SeriesHeaderState extends State<_SeriesHeader> {
|
||||
bool _more = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
final theme = Theme.of(context);
|
||||
final t = theme.textTheme;
|
||||
final s = widget.data.series;
|
||||
final next = widget.data.next;
|
||||
final logo = s.image(JellyfinImageType.logo);
|
||||
final meta = [
|
||||
if (s.productionYear != null) '${s.productionYear}',
|
||||
if (s.officialRating != null) s.officialRating!,
|
||||
if (s.communityRating != null) '★ ${s.communityRating!.toStringAsFixed(1)}',
|
||||
if (widget.data.seasons.isNotEmpty)
|
||||
'${widget.data.seasons.length} ${widget.data.seasons.length == 1 ? 'season' : 'seasons'}',
|
||||
if ((s.userData.unplayedItemCount ?? 0) > 0) '${s.userData.unplayedItemCount} unwatched',
|
||||
].join(' · ');
|
||||
|
||||
final String nextLabel;
|
||||
if (next == null) {
|
||||
nextLabel = 'All watched';
|
||||
} else if (next.userData.isResumable) {
|
||||
nextLabel = 'Resume ${next.episodeLabel ?? next.name}';
|
||||
} else {
|
||||
nextLabel = 'Next up: ${next.episodeLabel ?? ''} ${next.name}'.trim();
|
||||
}
|
||||
final selectedNext = next != null && scope.selectedItemId == next.id;
|
||||
|
||||
return LayoutBuilder(builder: (context, box) {
|
||||
final h = (box.maxWidth * 0.28).clamp(220.0, 380.0);
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: SizedBox(
|
||||
height: h,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
JellyfinImage(
|
||||
client: scope.client,
|
||||
image: s.image(JellyfinImageType.backdrop),
|
||||
alignment: Alignment.topCenter,
|
||||
icon: Icons.live_tv_outlined,
|
||||
),
|
||||
DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
theme.colorScheme.surface.withValues(alpha: 0.96),
|
||||
theme.colorScheme.surface.withValues(alpha: 0.75),
|
||||
theme.colorScheme.surface.withValues(alpha: 0.1),
|
||||
],
|
||||
stops: const [0, 0.45, 1],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 720),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (logo != null)
|
||||
SizedBox(
|
||||
height: 72,
|
||||
width: 320,
|
||||
child: JellyfinImage(
|
||||
client: scope.client,
|
||||
image: logo,
|
||||
fit: BoxFit.contain,
|
||||
alignment: Alignment.centerLeft,
|
||||
placeholder: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(s.name, style: t.headlineMedium)),
|
||||
),
|
||||
)
|
||||
else
|
||||
Text(s.name, style: t.headlineMedium),
|
||||
const SizedBox(height: 8),
|
||||
Text(meta, style: t.bodyMedium?.copyWith(color: Colors.grey)),
|
||||
if (s.overview != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
GestureDetector(
|
||||
onTap: () => setState(() => _more = !_more),
|
||||
child: Text(s.overview!,
|
||||
maxLines: _more ? null : 3,
|
||||
overflow: _more ? null : TextOverflow.ellipsis,
|
||||
style: t.bodyMedium),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 14),
|
||||
Wrap(spacing: 8, runSpacing: 8, children: [
|
||||
FilledButton.icon(
|
||||
key: const ValueKey('series-next'),
|
||||
onPressed: next == null ? null : () => scope.onPick(next),
|
||||
icon: Icon(selectedNext ? Icons.check : Icons.play_arrow),
|
||||
label: Text(nextLabel, overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
]),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Episodes of one season as a lazy grid of rows: one column, more past
|
||||
/// ~760 px each.
|
||||
class _EpisodeList extends StatefulWidget {
|
||||
final String seriesId;
|
||||
final String seasonId;
|
||||
const _EpisodeList({super.key, required this.seriesId, required this.seasonId});
|
||||
|
||||
@override
|
||||
State<_EpisodeList> createState() => _EpisodeListState();
|
||||
}
|
||||
|
||||
class _EpisodeListState extends State<_EpisodeList> {
|
||||
Future<List<JellyfinItem>>? _future;
|
||||
|
||||
void _load(BrowseScope scope) => _future = scope.load('episodes:${widget.seriesId}:${widget.seasonId}',
|
||||
(c) => c.episodes(widget.seriesId, seasonId: widget.seasonId));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
if (_future == null) _load(scope);
|
||||
return FutureBuilder<List<JellyfinItem>>(
|
||||
future: _future,
|
||||
builder: (context, snap) {
|
||||
if (snap.hasError) {
|
||||
return SliverToBoxAdapter(
|
||||
child: LoadError(error: snap.error!, onRetry: () => setState(() => _load(scope))));
|
||||
}
|
||||
final eps = snap.data;
|
||||
if (eps == null) {
|
||||
return const SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(32),
|
||||
child: Center(child: CircularProgressIndicator(strokeWidth: 2)),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (eps.isEmpty) {
|
||||
return const SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Text('No episodes', style: TextStyle(color: Colors.grey)),
|
||||
),
|
||||
);
|
||||
}
|
||||
return SliverGrid(
|
||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 760,
|
||||
mainAxisExtent: episodeTileHeight,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 8,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, i) => EpisodeTile(episode: eps[i]),
|
||||
childCount: eps.length,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const episodeTileHeight = 6 + 176 * 9 / 16 + 6 + 2;
|
||||
|
||||
/// One episode: thumbnail with progress, number + title, runtime / air
|
||||
/// date, two lines of overview. Click picks it; I opens details.
|
||||
class EpisodeTile extends StatefulWidget {
|
||||
final JellyfinItem episode;
|
||||
const EpisodeTile({super.key, required this.episode});
|
||||
|
||||
@override
|
||||
State<EpisodeTile> createState() => _EpisodeTileState();
|
||||
}
|
||||
|
||||
class _EpisodeTileState extends State<EpisodeTile> {
|
||||
bool _focus = false;
|
||||
bool _hover = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scope = BrowseScope.of(context);
|
||||
final theme = Theme.of(context);
|
||||
final scheme = theme.colorScheme;
|
||||
final t = theme.textTheme;
|
||||
final e = widget.episode;
|
||||
final selected = scope.selectedItemId == e.id;
|
||||
final played = e.userData.played;
|
||||
final progress = progressOf(e);
|
||||
final meta = [
|
||||
?e.episodeLabel,
|
||||
?timeLeft(e),
|
||||
if (timeLeft(e) == null && e.runTime != null) formatRuntime(e.runTime!),
|
||||
if (e.premiereDate != null)
|
||||
'${e.premiereDate!.year}-${e.premiereDate!.month.toString().padLeft(2, '0')}-${e.premiereDate!.day.toString().padLeft(2, '0')}',
|
||||
].join(' · ');
|
||||
return Focus(
|
||||
canRequestFocus: false,
|
||||
skipTraversal: true,
|
||||
onKeyEvent: (_, k) {
|
||||
if (k is KeyDownEvent && k.logicalKey == LogicalKeyboardKey.keyI) {
|
||||
scope.onOpen(DetailRoute(e));
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
},
|
||||
child: Material(
|
||||
color: selected
|
||||
? scheme.primaryContainer.withValues(alpha: 0.35)
|
||||
: _hover || _focus
|
||||
? scheme.surfaceContainerHigh
|
||||
: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
side: BorderSide(
|
||||
color: selected ? scheme.primary : _focus ? scheme.onSurface : Colors.transparent,
|
||||
width: 1.5),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
key: ValueKey('episode-${e.id}'),
|
||||
focusColor: Colors.transparent,
|
||||
onTap: () => scope.onPick(e),
|
||||
onHover: (h) {
|
||||
setState(() => _hover = h);
|
||||
if (h) scope.onPeek(e);
|
||||
},
|
||||
onFocusChange: (f) {
|
||||
setState(() => _focus = f);
|
||||
if (f) scope.onPeek(e);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 176,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
child: Stack(fit: StackFit.expand, children: [
|
||||
JellyfinImage(
|
||||
client: scope.client,
|
||||
image: e.ownImage(JellyfinImageType.primary) ??
|
||||
e.image(JellyfinImageType.thumb) ??
|
||||
e.image(JellyfinImageType.backdrop),
|
||||
icon: Icons.tv_outlined,
|
||||
),
|
||||
if (progress > 0)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: LinearProgressIndicator(
|
||||
value: progress, minHeight: 3, backgroundColor: Colors.black54),
|
||||
),
|
||||
if (played || selected)
|
||||
Positioned(
|
||||
top: 4,
|
||||
right: 4,
|
||||
child: CircleAvatar(
|
||||
radius: 10,
|
||||
backgroundColor: selected ? scheme.primary : const Color(0xCC1B5E20),
|
||||
child: Icon(Icons.check,
|
||||
size: 13, color: selected ? scheme.onPrimary : Colors.white),
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
e.indexNumber == null ? e.name : '${e.indexNumber}. ${e.name}',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: t.titleSmall?.copyWith(
|
||||
color: selected ? scheme.primary : played ? Colors.grey : null,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_hover)
|
||||
IconButton(
|
||||
tooltip: 'Details (I)',
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints.tightFor(width: 24, height: 22),
|
||||
iconSize: 18,
|
||||
onPressed: () => scope.onOpen(DetailRoute(e)),
|
||||
icon: const Icon(Icons.info_outline),
|
||||
),
|
||||
]),
|
||||
Text(meta, style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
if (e.overview != null) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(e.overview!,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: t.bodySmall?.copyWith(color: scheme.onSurfaceVariant)),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import '../screens/home/picked_media.dart';
|
||||
import 'accounts.dart';
|
||||
import 'format.dart';
|
||||
|
||||
// Jellyfin media in a session: turning picks and pasted links into refs
|
||||
// (the wire carries only `{serverId, itemId, ...}`), the hosted server's
|
||||
// relay credential, and how this viewer plays a ref (own account, relay,
|
||||
// or neither).
|
||||
|
||||
/// The wire ref of a browser pick.
|
||||
JellyfinRef refForPick(JellyfinMedia m) => JellyfinRef(
|
||||
serverId: m.serverId,
|
||||
itemId: m.itemId,
|
||||
mediaSourceId: m.mediaSourceId,
|
||||
title: m.title,
|
||||
subtitle: m.subtitle.isEmpty ? null : m.subtitle,
|
||||
runtimeSecs: m.runtime == null ? null : m.runtime!.inMilliseconds / 1000,
|
||||
);
|
||||
|
||||
/// The `swap` media for a browser pick: a ref, never a URL.
|
||||
HelloMedia mediaForPick(JellyfinMedia m) => HelloMedia(
|
||||
name: m.title.isEmpty ? 'Jellyfin item' : m.title,
|
||||
size: 0,
|
||||
duration: 0,
|
||||
jellyfin: refForPick(m));
|
||||
|
||||
/// The pick a ref stands for on a linked server (for highlighting it in
|
||||
/// the browser); null when this install has no account there.
|
||||
JellyfinMedia? pickForRef(JellyfinAccounts accounts, JellyfinRef ref) {
|
||||
final a = accounts.account(ref.serverId);
|
||||
if (a == null) return null;
|
||||
return JellyfinMedia(
|
||||
serverId: ref.serverId,
|
||||
baseUrl: a.baseUrl,
|
||||
itemId: ref.itemId,
|
||||
mediaSourceId: ref.mediaSourceId,
|
||||
title: ref.title,
|
||||
subtitle: ref.subtitle ?? '',
|
||||
runtime: ref.runtimeSecs == null
|
||||
? null
|
||||
: Duration(milliseconds: (ref.runtimeSecs! * 1000).round()),
|
||||
);
|
||||
}
|
||||
|
||||
/// The ref in a `state.media` map, or null for other media.
|
||||
JellyfinRef? refOfStateMedia(Map<String, Object?>? media) {
|
||||
final jf = media?['jellyfin'];
|
||||
if (jf is! Map) return null;
|
||||
try {
|
||||
final ref = JellyfinRef.fromJson(Map<String, Object?>.from(jf));
|
||||
return ref.serverId.isEmpty || ref.itemId.isEmpty ? null : ref;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Same item (server, item, source); titles may differ.
|
||||
bool sameJellyfinItem(JellyfinRef? a, JellyfinRef? b) =>
|
||||
a != null &&
|
||||
b != null &&
|
||||
a.serverId == b.serverId &&
|
||||
a.itemId == b.itemId &&
|
||||
a.mediaSourceId == b.mediaSourceId;
|
||||
|
||||
final _sourceId = RegExp(r'^[A-Za-z0-9-]{1,64}$');
|
||||
|
||||
/// What a pasted link becomes on the wire. A recognised Jellyfin item link
|
||||
/// (`parseJellyfinLink`) becomes a ref when its ServerId is known (in the
|
||||
/// link or from `/System/Info/Public`); its `api_key` is never shared then.
|
||||
/// Anything else, or a server that does not answer, stays a plain link.
|
||||
/// The title comes from this install's account on that server when there
|
||||
/// is one.
|
||||
Future<HelloMedia> mediaForLink(JellyfinAccounts accounts, String url,
|
||||
{Duration timeout = const Duration(seconds: 6)}) async {
|
||||
final plain = HelloMedia(name: linkName(url), size: 0, duration: 0, url: url);
|
||||
final link = parseJellyfinLink(url);
|
||||
if (link == null) return plain;
|
||||
await accounts.ensureLoaded();
|
||||
var serverId = link.serverId;
|
||||
if (serverId == null || serverId.isEmpty) {
|
||||
final probe = accounts.anonymousClient(link.baseUrl);
|
||||
try {
|
||||
serverId = (await probe.publicInfo().timeout(timeout)).id;
|
||||
} catch (e) {
|
||||
debugPrint('jellyfin link: no server id from ${link.baseUrl}: $e');
|
||||
return plain;
|
||||
} finally {
|
||||
probe.close();
|
||||
}
|
||||
if (serverId.isEmpty) return plain;
|
||||
}
|
||||
final src = Uri.tryParse(url)?.queryParameters['mediaSourceId'];
|
||||
var ref = JellyfinRef(
|
||||
serverId: serverId,
|
||||
itemId: link.itemId,
|
||||
mediaSourceId: src != null && _sourceId.hasMatch(src) && src != link.itemId ? src : null,
|
||||
);
|
||||
final account = accounts.account(serverId);
|
||||
final client = accounts.clientFor(serverId);
|
||||
if (account != null && client != null) {
|
||||
try {
|
||||
final pick = pickFor(account, await client.item(link.itemId).timeout(timeout));
|
||||
ref = refForPick(JellyfinMedia(
|
||||
serverId: serverId,
|
||||
baseUrl: account.baseUrl,
|
||||
itemId: link.itemId,
|
||||
mediaSourceId: ref.mediaSourceId,
|
||||
title: pick.title,
|
||||
subtitle: pick.subtitle,
|
||||
runtime: pick.runtime,
|
||||
));
|
||||
} catch (e) {
|
||||
if (e is JellyfinException && e.isUnauthorized) accounts.markExpired(serverId);
|
||||
}
|
||||
}
|
||||
return HelloMedia(
|
||||
name: ref.title.isEmpty ? 'Jellyfin item' : ref.title, size: 0, duration: 0, jellyfin: ref);
|
||||
}
|
||||
|
||||
/// Display name for a link: last path segment, decoded, never the query
|
||||
/// (Jellyfin-style links carry api_key there and names are broadcast).
|
||||
String linkName(String url) {
|
||||
final uri = Uri.tryParse(url.trim());
|
||||
if (uri == null) return 'link';
|
||||
final segs = uri.pathSegments.where((s) => s.isNotEmpty).toList();
|
||||
if (segs.isNotEmpty) {
|
||||
try {
|
||||
return Uri.decodeComponent(segs.last);
|
||||
} catch (_) {
|
||||
return segs.last;
|
||||
}
|
||||
}
|
||||
return uri.host.isNotEmpty ? uri.host : 'link';
|
||||
}
|
||||
|
||||
/// The hosted server's relay login: the account for [serverId] (the
|
||||
/// hosted item's server), else the default account, when its token is not
|
||||
/// known to be expired. The device fields are exactly the ones this app
|
||||
/// sends with that token ([JellyfinAccounts.clientInfo]): Jellyfin rewrites
|
||||
/// a token's device from the request header, so the relay must not differ.
|
||||
JellyfinCredential? relayCredentialFor(JellyfinAccounts accounts, {String? serverId}) {
|
||||
bool usable(JellyfinAccount? a) =>
|
||||
a != null && accounts.statusOf(a.serverId) != JellyfinAccountStatus.expired;
|
||||
var a = serverId == null ? null : accounts.account(serverId);
|
||||
if (!usable(a)) a = accounts.defaultAccount;
|
||||
if (!usable(a)) return null;
|
||||
final info = accounts.clientInfo;
|
||||
return JellyfinCredential(
|
||||
baseUrl: a!.baseUrl,
|
||||
serverId: a.serverId,
|
||||
token: a.token,
|
||||
client: info.client,
|
||||
device: info.device,
|
||||
deviceId: info.deviceId,
|
||||
version: info.version,
|
||||
);
|
||||
}
|
||||
|
||||
/// `/j/...` URL of the current Jellyfin media on the host this client
|
||||
/// dialled, built like the `/m/...` one.
|
||||
String relayUrlFor(String host, int port, String token, String itemId) =>
|
||||
'http://$host:$port/j/default/$token/${Uri.encodeComponent(itemId)}';
|
||||
|
||||
// ---------------------------------------------------------------- playing
|
||||
|
||||
/// How this viewer plays a ref.
|
||||
sealed class JellyfinPlan {
|
||||
const JellyfinPlan();
|
||||
|
||||
/// `report.jf` for this plan; null when it plays nothing.
|
||||
bool? get jfAccess;
|
||||
}
|
||||
|
||||
/// Direct play with this install's account: the static stream, the token
|
||||
/// in [headers] (not in the URL), progress reported per [info].
|
||||
final class OwnPlay extends JellyfinPlan {
|
||||
final JellyfinClient client;
|
||||
final JellyfinAccount account;
|
||||
final JellyfinPlaybackInfo info;
|
||||
final JellyfinMediaSource source;
|
||||
/// Full item (series, episode numbers); null if that call failed.
|
||||
final JellyfinItem? item;
|
||||
final String url;
|
||||
final Map<String, String> headers;
|
||||
const OwnPlay({
|
||||
required this.client,
|
||||
required this.account,
|
||||
required this.info,
|
||||
required this.source,
|
||||
required this.item,
|
||||
required this.url,
|
||||
required this.headers,
|
||||
});
|
||||
|
||||
@override
|
||||
bool get jfAccess => true;
|
||||
}
|
||||
|
||||
/// Through the sync server's relay (`/j/...`).
|
||||
final class RelayPlay extends JellyfinPlan {
|
||||
final String url;
|
||||
const RelayPlay(this.url);
|
||||
|
||||
@override
|
||||
bool get jfAccess => false;
|
||||
}
|
||||
|
||||
/// Neither: no (usable) account here and the server cannot relay.
|
||||
final class BlockedPlay extends JellyfinPlan {
|
||||
final String serverId;
|
||||
/// Known only when this install has (had) an account there.
|
||||
final String? serverName;
|
||||
/// Why the own account did not work, if there is one.
|
||||
final String? problem;
|
||||
const BlockedPlay({required this.serverId, this.serverName, this.problem});
|
||||
|
||||
@override
|
||||
bool? get jfAccess => null;
|
||||
|
||||
String get message {
|
||||
final where = serverName == null || serverName!.isEmpty ? 'that Jellyfin server' : serverName!;
|
||||
final base = 'This needs a Jellyfin account on $where (or the host can relay)';
|
||||
return problem == null ? base : '$base — $problem';
|
||||
}
|
||||
}
|
||||
|
||||
/// Picks how to play [ref]: this install's account first (PlaybackInfo
|
||||
/// with its own user; a 401 marks the account expired), else the relay
|
||||
/// when the server offers it ([relay] = `state.relay`, [relayUrl] this
|
||||
/// member's `/j/...` URL), else [BlockedPlay].
|
||||
Future<JellyfinPlan> resolveJellyfinRef(
|
||||
JellyfinAccounts accounts,
|
||||
JellyfinRef ref, {
|
||||
required bool relay,
|
||||
required String? relayUrl,
|
||||
Duration timeout = const Duration(seconds: 15),
|
||||
}) async {
|
||||
await accounts.ensureLoaded();
|
||||
final account = accounts.account(ref.serverId);
|
||||
String? problem;
|
||||
if (account != null && accounts.statusOf(ref.serverId) == JellyfinAccountStatus.expired) {
|
||||
problem = 'your sign-in expired, reconnect it in Integrations';
|
||||
} else if (account != null) {
|
||||
final client = accounts.clientFor(ref.serverId)!;
|
||||
try {
|
||||
final infoF = client.playbackInfo(ref.itemId, mediaSourceId: ref.mediaSourceId).timeout(timeout);
|
||||
final itemF = client
|
||||
.item(ref.itemId)
|
||||
.timeout(timeout)
|
||||
.then<JellyfinItem?>((i) => i, onError: (Object _) => null);
|
||||
final info = await infoF;
|
||||
final item = await itemF;
|
||||
final source = (ref.mediaSourceId == null
|
||||
? null
|
||||
: info.mediaSources.where((s) => s.id == ref.mediaSourceId).firstOrNull) ??
|
||||
info.primarySource;
|
||||
if (source == null) throw const JellyfinException('no playable source');
|
||||
return OwnPlay(
|
||||
client: client,
|
||||
account: account,
|
||||
info: info,
|
||||
source: source,
|
||||
item: item,
|
||||
url: client.shareableStreamUrl(ref.itemId, mediaSourceId: source.id).toString(),
|
||||
headers: client.authHeaders,
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('jellyfin resolve ${ref.itemId} with own account failed: $e');
|
||||
if (e is JellyfinException && e.isUnauthorized) {
|
||||
accounts.markExpired(ref.serverId);
|
||||
problem = 'your sign-in expired, reconnect it in Integrations';
|
||||
} else if (e is JellyfinException && e.statusCode == 404) {
|
||||
problem = 'your account cannot see this item';
|
||||
} else {
|
||||
problem = 'could not reach it';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (relay && relayUrl != null && relayUrl.isNotEmpty) return RelayPlay(relayUrl);
|
||||
return BlockedPlay(serverId: ref.serverId, serverName: account?.displayName, problem: problem);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ next episode
|
||||
|
||||
/// A neighbouring episode as this viewer can put it up.
|
||||
class EpisodeLink {
|
||||
final JellyfinItem item;
|
||||
final JellyfinMedia pick;
|
||||
const EpisodeLink(this.item, this.pick);
|
||||
|
||||
/// "S1E7 Battle with the Heroes".
|
||||
String get label => [?item.episodeLabel, item.name].join(' ');
|
||||
}
|
||||
|
||||
/// The episodes before and after the one [plan] plays, with its account.
|
||||
/// Both null for movies, at the ends of a series, or on failure.
|
||||
Future<({EpisodeLink? previous, EpisodeLink? next})> findAdjacentEpisodes(OwnPlay plan,
|
||||
{Duration timeout = const Duration(seconds: 15)}) async {
|
||||
const none = (previous: null, next: null);
|
||||
final item = plan.item;
|
||||
if (item == null || item.kind != JellyfinItemKind.episode || item.seriesId == null) return none;
|
||||
try {
|
||||
final around = await plan.client.adjacentEpisodes(item).timeout(timeout);
|
||||
EpisodeLink? link(JellyfinItem? i) => i == null ? null : EpisodeLink(i, pickFor(plan.account, i));
|
||||
return (previous: link(around.previous), next: link(around.next));
|
||||
} catch (e) {
|
||||
debugPrint('episode lookup failed: $e');
|
||||
return none;
|
||||
}
|
||||
}
|
||||
|
||||
/// When the floating "Next episode" pill appears: at [endingStart] (the
|
||||
/// ED: Jellyfin Outro segment or ED-titled chapter, see `endingRange`)
|
||||
/// when one is known inside [runtime], else the last two minutes of
|
||||
/// [runtime] (all of it for shorter media).
|
||||
Duration nextPromptStart(JellyfinItem? item, Duration runtime, {Duration? endingStart}) {
|
||||
if (endingStart != null && endingStart > Duration.zero && endingStart < runtime) {
|
||||
return endingStart;
|
||||
}
|
||||
const lead = Duration(minutes: 2);
|
||||
return runtime > lead ? runtime - lead : Duration.zero;
|
||||
}
|
||||
|
||||
/// Who performs the auto-advance swap, so several counting clients do not
|
||||
/// swap twice: the lowest member id among members that play the item with
|
||||
/// their own account (`jf[serverId] == true`, not stale). Only what every
|
||||
/// client sees in `state` decides (who put the item up is not in it: a
|
||||
/// late joiner never saw that swap), so all clients agree.
|
||||
String? autoAdvanceSwapper(List<MemberView> members, String serverId) {
|
||||
final eligible = [
|
||||
for (final m in members)
|
||||
if (!m.stale && m.jf[serverId] == true) m
|
||||
];
|
||||
if (eligible.isEmpty) return null;
|
||||
eligible.sort((a, b) => compareMemberIds(a.id, b.id));
|
||||
return eligible.first.id;
|
||||
}
|
||||
|
||||
/// "m2" before "m10": numeric suffix order, then plain text.
|
||||
int compareMemberIds(String a, String b) {
|
||||
final na = int.tryParse(a.replaceFirst(RegExp(r'^\D+'), ''));
|
||||
final nb = int.tryParse(b.replaceFirst(RegExp(r'^\D+'), ''));
|
||||
if (na != null && nb != null && na != nb) return na.compareTo(nb);
|
||||
return a.compareTo(b);
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'accounts.dart';
|
||||
|
||||
enum JellyfinSignInStep {
|
||||
/// Typing the server address.
|
||||
address,
|
||||
probing,
|
||||
/// Server found: choose Quick Connect or password.
|
||||
method,
|
||||
/// Code shown, polling until the user approves it in Jellyfin.
|
||||
quickConnect,
|
||||
password,
|
||||
signingIn,
|
||||
/// Linked; [JellyfinSignIn.linked] is the account.
|
||||
done,
|
||||
}
|
||||
|
||||
/// Add-server / reconnect flow: address -> /System/Info/Public -> Quick
|
||||
/// Connect (code + poll, cancellable) or username/password -> linked in
|
||||
/// [JellyfinAccounts]. UI-free so tests drive it with a fake transport.
|
||||
class JellyfinSignIn extends ChangeNotifier {
|
||||
JellyfinSignIn(this.accounts, {this.pollInterval = const Duration(seconds: 3), this.reconnect});
|
||||
|
||||
final JellyfinAccounts accounts;
|
||||
final Duration pollInterval;
|
||||
/// Set when re-signing an expired account: the address is prefilled.
|
||||
final JellyfinAccount? reconnect;
|
||||
|
||||
JellyfinSignInStep _step = JellyfinSignInStep.address;
|
||||
String? _error;
|
||||
JellyfinServerInfo? _server;
|
||||
bool _quickConnectAvailable = false;
|
||||
String? _code;
|
||||
JellyfinAccount? _linked;
|
||||
JellyfinClient? _client;
|
||||
int _gen = 0;
|
||||
bool _disposed = false;
|
||||
|
||||
JellyfinSignInStep get step => _step;
|
||||
String? get error => _error;
|
||||
JellyfinServerInfo? get server => _server;
|
||||
String? get baseUrl => _client?.baseUrl;
|
||||
bool get quickConnectAvailable => _quickConnectAvailable;
|
||||
/// The Quick Connect code to show.
|
||||
String? get code => _code;
|
||||
JellyfinAccount? get linked => _linked;
|
||||
bool get busy =>
|
||||
_step == JellyfinSignInStep.probing || _step == JellyfinSignInStep.signingIn;
|
||||
|
||||
void _set(JellyfinSignInStep s, {String? error}) {
|
||||
_step = s;
|
||||
_error = error;
|
||||
if (!_disposed) notifyListeners();
|
||||
}
|
||||
|
||||
/// Checks [input] is a Jellyfin server and whether Quick Connect is on.
|
||||
Future<void> probe(String input) async {
|
||||
final url = normalizeServerUrl(input);
|
||||
if (url == null) {
|
||||
_set(JellyfinSignInStep.address, error: 'Enter the server address, e.g. jellyfin.example.com');
|
||||
return;
|
||||
}
|
||||
final gen = ++_gen;
|
||||
_client?.close();
|
||||
final client = _client = accounts.anonymousClient(url);
|
||||
_set(JellyfinSignInStep.probing);
|
||||
try {
|
||||
final info = await client.publicInfo();
|
||||
if (gen != _gen) return;
|
||||
if (info.id.isEmpty) throw const JellyfinException('not a Jellyfin server');
|
||||
if (reconnect != null && info.id != reconnect!.serverId) {
|
||||
_set(JellyfinSignInStep.address,
|
||||
error: 'That address is a different Jellyfin server (${info.name}).');
|
||||
return;
|
||||
}
|
||||
var qc = false;
|
||||
try {
|
||||
qc = await client.quickConnectEnabled();
|
||||
} catch (_) {}
|
||||
if (gen != _gen) return;
|
||||
_server = info;
|
||||
_quickConnectAvailable = qc;
|
||||
_set(JellyfinSignInStep.method);
|
||||
} catch (e) {
|
||||
if (gen != _gen) return;
|
||||
_set(JellyfinSignInStep.address, error: 'No Jellyfin server at $url (${_short(e)})');
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts Quick Connect: shows the code, polls until approved, links.
|
||||
Future<void> startQuickConnect() async {
|
||||
final client = _client;
|
||||
if (client == null || _server == null) return;
|
||||
final gen = ++_gen;
|
||||
_code = null;
|
||||
_set(JellyfinSignInStep.quickConnect);
|
||||
try {
|
||||
final session = await client.quickConnectInitiate();
|
||||
if (gen != _gen) return;
|
||||
_code = session.code;
|
||||
_set(JellyfinSignInStep.quickConnect);
|
||||
final auth = await client.waitForQuickConnect(session,
|
||||
interval: pollInterval, isCancelled: () => gen != _gen || _disposed);
|
||||
if (auth == null || gen != _gen) return;
|
||||
await _finish(auth);
|
||||
} on TimeoutException {
|
||||
if (gen == _gen) _set(JellyfinSignInStep.method, error: 'The code expired. Try again.');
|
||||
} catch (e) {
|
||||
if (gen != _gen) return;
|
||||
final msg = e is JellyfinException && e.isUnauthorized
|
||||
? 'Quick Connect is turned off on this server. Use your password.'
|
||||
: e is JellyfinException && e.statusCode == 404
|
||||
? 'The code expired. Try again.'
|
||||
: 'Quick Connect failed: ${_short(e)}';
|
||||
_set(JellyfinSignInStep.method, error: msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Stops waiting for the Quick Connect code.
|
||||
void cancel() {
|
||||
_gen++;
|
||||
_code = null;
|
||||
_set(_server == null ? JellyfinSignInStep.address : JellyfinSignInStep.method);
|
||||
}
|
||||
|
||||
void usePassword() => _set(JellyfinSignInStep.password);
|
||||
|
||||
/// Back to the address field.
|
||||
void changeAddress() {
|
||||
_gen++;
|
||||
_server = null;
|
||||
_code = null;
|
||||
_set(JellyfinSignInStep.address);
|
||||
}
|
||||
|
||||
Future<void> signIn(String username, String password) async {
|
||||
final client = _client;
|
||||
if (client == null) return;
|
||||
if (username.trim().isEmpty) {
|
||||
_set(JellyfinSignInStep.password, error: 'Enter your Jellyfin username');
|
||||
return;
|
||||
}
|
||||
final gen = ++_gen;
|
||||
_set(JellyfinSignInStep.signingIn);
|
||||
try {
|
||||
final auth = await client.authenticateByName(username.trim(), password);
|
||||
if (gen != _gen) return;
|
||||
await _finish(auth);
|
||||
} catch (e) {
|
||||
if (gen != _gen) return;
|
||||
_set(JellyfinSignInStep.password,
|
||||
error: e is JellyfinException && e.isUnauthorized
|
||||
? 'Wrong username or password'
|
||||
: 'Sign-in failed: ${_short(e)}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _finish(JellyfinAuthResult auth) async {
|
||||
final server = _server!;
|
||||
if (auth.accessToken.isEmpty) throw const JellyfinException('no token in the answer');
|
||||
_linked = await accounts.link(baseUrl: _client!.baseUrl, server: server, auth: auth);
|
||||
_code = null;
|
||||
_set(JellyfinSignInStep.done);
|
||||
}
|
||||
|
||||
static String _short(Object e) {
|
||||
final s = '$e'.replaceFirst(RegExp(r'^JellyfinException( \d+)?: '), '');
|
||||
return s.length > 140 ? '${s.substring(0, 140)}…' : s;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_disposed = true;
|
||||
_gen++;
|
||||
_client?.close();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../screens/home/ui.dart';
|
||||
import 'accounts.dart';
|
||||
import 'sign_in.dart';
|
||||
|
||||
/// Add a Jellyfin server (or reconnect an expired one): address, then Quick
|
||||
/// Connect (big code, approve it in Jellyfin) or username and password.
|
||||
class JellyfinSignInPanel extends StatefulWidget {
|
||||
final JellyfinAccounts accounts;
|
||||
final JellyfinAccount? reconnect;
|
||||
final ValueChanged<JellyfinAccount>? onDone;
|
||||
final VoidCallback? onCancel;
|
||||
final Duration pollInterval;
|
||||
const JellyfinSignInPanel({
|
||||
super.key,
|
||||
required this.accounts,
|
||||
this.reconnect,
|
||||
this.onDone,
|
||||
this.onCancel,
|
||||
this.pollInterval = const Duration(seconds: 3),
|
||||
});
|
||||
|
||||
@override
|
||||
State<JellyfinSignInPanel> createState() => _JellyfinSignInPanelState();
|
||||
}
|
||||
|
||||
class _JellyfinSignInPanelState extends State<JellyfinSignInPanel> {
|
||||
late final JellyfinSignIn _flow =
|
||||
JellyfinSignIn(widget.accounts, pollInterval: widget.pollInterval, reconnect: widget.reconnect);
|
||||
late final _address = TextEditingController(text: widget.reconnect?.baseUrl ?? '');
|
||||
late final _user = TextEditingController(text: widget.reconnect?.userName ?? '');
|
||||
final _password = TextEditingController();
|
||||
bool _reported = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_flow.addListener(_changed);
|
||||
if (widget.reconnect != null) _flow.probe(widget.reconnect!.baseUrl);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_flow.removeListener(_changed);
|
||||
_flow.dispose();
|
||||
_address.dispose();
|
||||
_user.dispose();
|
||||
_password.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _changed() {
|
||||
if (!mounted) return;
|
||||
setState(() {});
|
||||
final linked = _flow.linked;
|
||||
if (_flow.step == JellyfinSignInStep.done && linked != null && !_reported) {
|
||||
_reported = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => widget.onDone?.call(linked));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
final f = _flow;
|
||||
final body = switch (f.step) {
|
||||
JellyfinSignInStep.address || JellyfinSignInStep.probing => _addressStep(),
|
||||
JellyfinSignInStep.method => _methodStep(),
|
||||
JellyfinSignInStep.quickConnect => _quickConnectStep(),
|
||||
JellyfinSignInStep.password || JellyfinSignInStep.signingIn => _passwordStep(),
|
||||
JellyfinSignInStep.done => Row(children: [
|
||||
const Icon(Icons.check_circle, color: Colors.green),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text('Linked as ${f.linked?.userName} on ${f.linked?.displayName}',
|
||||
key: const ValueKey('jf-linked'))),
|
||||
]),
|
||||
};
|
||||
return Column(
|
||||
key: const ValueKey('jf-sign-in'),
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(widget.reconnect == null ? 'Add a Jellyfin server' : 'Reconnect ${widget.reconnect!.displayName}',
|
||||
style: t.titleMedium),
|
||||
const SizedBox(height: 12),
|
||||
if (f.server != null && f.step != JellyfinSignInStep.address && f.step != JellyfinSignInStep.done)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: _ServerLine(
|
||||
name: f.server!.name,
|
||||
version: f.server!.version,
|
||||
url: f.baseUrl ?? '',
|
||||
onChange: widget.reconnect == null ? f.changeAddress : null,
|
||||
),
|
||||
),
|
||||
body,
|
||||
if (f.error != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Text(f.error!,
|
||||
key: const ValueKey('jf-sign-in-error'),
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.error)),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _cancelButton() => widget.onCancel == null
|
||||
? const SizedBox.shrink()
|
||||
: TextButton(onPressed: widget.onCancel, child: const Text('Cancel'));
|
||||
|
||||
Widget _addressStep() {
|
||||
final probing = _flow.step == JellyfinSignInStep.probing;
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
key: const ValueKey('jf-address'),
|
||||
controller: _address,
|
||||
autofocus: true,
|
||||
enabled: !probing,
|
||||
decoration: fieldDecoration('Server address', hint: 'jellyfin.example.com'),
|
||||
keyboardType: TextInputType.url,
|
||||
onSubmitted: (v) => _flow.probe(v),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
FilledButton(
|
||||
key: const ValueKey('jf-connect'),
|
||||
onPressed: probing ? null : () => _flow.probe(_address.text),
|
||||
child: probing
|
||||
? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Text('Connect'),
|
||||
),
|
||||
_cancelButton(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _methodStep() {
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
if (_flow.quickConnectAvailable)
|
||||
FilledButton.icon(
|
||||
key: const ValueKey('jf-quick-connect'),
|
||||
onPressed: _flow.startQuickConnect,
|
||||
icon: const Icon(Icons.qr_code_2, size: 18),
|
||||
label: const Text('Quick Connect'),
|
||||
),
|
||||
if (_flow.quickConnectAvailable)
|
||||
OutlinedButton.icon(
|
||||
key: const ValueKey('jf-use-password'),
|
||||
onPressed: _flow.usePassword,
|
||||
icon: const Icon(Icons.password, size: 18),
|
||||
label: const Text('Username & password'),
|
||||
)
|
||||
else
|
||||
FilledButton.icon(
|
||||
key: const ValueKey('jf-use-password'),
|
||||
onPressed: _flow.usePassword,
|
||||
icon: const Icon(Icons.password, size: 18),
|
||||
label: const Text('Username & password'),
|
||||
),
|
||||
_cancelButton(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _quickConnectStep() {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final t = Theme.of(context).textTheme;
|
||||
final code = _flow.code;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (code == null)
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
else
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: scheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: SelectableText(
|
||||
code,
|
||||
key: const ValueKey('jf-qc-code'),
|
||||
style: t.displaySmall?.copyWith(
|
||||
fontFeatures: const [FontFeature.tabularFigures()],
|
||||
letterSpacing: 8,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
IconButton(
|
||||
tooltip: 'Copy code',
|
||||
onPressed: () => Clipboard.setData(ClipboardData(text: code)),
|
||||
icon: const Icon(Icons.copy, size: 18),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text('Approve it in Jellyfin: Profile → Quick Connect, then enter this code.'),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
const SizedBox(width: 14, height: 14, child: CircularProgressIndicator(strokeWidth: 2)),
|
||||
const SizedBox(width: 10),
|
||||
const Text('Waiting for approval…', style: TextStyle(color: Colors.grey)),
|
||||
const SizedBox(width: 16),
|
||||
TextButton(
|
||||
key: const ValueKey('jf-qc-cancel'),
|
||||
onPressed: _flow.cancel,
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _passwordStep() {
|
||||
final busy = _flow.step == JellyfinSignInStep.signingIn;
|
||||
void submit() => _flow.signIn(_user.text, _password.text);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
TextField(
|
||||
key: const ValueKey('jf-username'),
|
||||
controller: _user,
|
||||
autofocus: true,
|
||||
enabled: !busy,
|
||||
decoration: fieldDecoration('Username'),
|
||||
onSubmitted: (_) => submit(),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
TextField(
|
||||
key: const ValueKey('jf-password'),
|
||||
controller: _password,
|
||||
enabled: !busy,
|
||||
obscureText: true,
|
||||
decoration: fieldDecoration('Password'),
|
||||
onSubmitted: (_) => submit(),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
FilledButton(
|
||||
key: const ValueKey('jf-sign-in-submit'),
|
||||
onPressed: busy ? null : submit,
|
||||
child: busy
|
||||
? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Text('Sign in'),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
if (_flow.quickConnectAvailable)
|
||||
TextButton(onPressed: _flow.cancel, child: const Text('Back')),
|
||||
_cancelButton(),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ServerLine extends StatelessWidget {
|
||||
final String name;
|
||||
final String version;
|
||||
final String url;
|
||||
final VoidCallback? onChange;
|
||||
const _ServerLine({required this.name, required this.version, required this.url, this.onChange});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return Row(
|
||||
children: [
|
||||
Icon(Icons.dns_outlined, size: 20, color: Theme.of(context).colorScheme.primary),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(name.isEmpty ? 'Jellyfin server' : name,
|
||||
key: const ValueKey('jf-server-name'), style: t.titleSmall),
|
||||
Text('Jellyfin $version · $url', style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (onChange != null) TextButton(onPressed: onChange, child: const Text('Change')),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'accounts.dart';
|
||||
|
||||
// Per-viewer audio/subtitle carry-over: the last choice is kept per series
|
||||
// (and as a global fallback) and matched against the next Jellyfin item's
|
||||
// tracks with core's `matchTrack`. Local only; nothing goes on the wire.
|
||||
|
||||
const trackPrefsBoxName = 'track_prefs';
|
||||
const _keyGlobal = 'global';
|
||||
|
||||
/// One audio or subtitle track of the open file as mpv's `track-list`
|
||||
/// has it ([id] is mpv's `aid` / `sid`; [selected] is mpv's choice).
|
||||
class MpvTrack {
|
||||
final int id;
|
||||
final JellyfinStreamType type;
|
||||
final String? language;
|
||||
final String? title;
|
||||
final String? codec;
|
||||
final int? channels;
|
||||
final bool isDefault;
|
||||
final bool isForced;
|
||||
final bool isHearingImpaired;
|
||||
final bool isExternal;
|
||||
final bool selected;
|
||||
const MpvTrack({
|
||||
required this.id,
|
||||
required this.type,
|
||||
this.language,
|
||||
this.title,
|
||||
this.codec,
|
||||
this.channels,
|
||||
this.isDefault = false,
|
||||
this.isForced = false,
|
||||
this.isHearingImpaired = false,
|
||||
this.isExternal = false,
|
||||
this.selected = false,
|
||||
});
|
||||
|
||||
/// As a stream for [matchTrack]; its index is the mpv id.
|
||||
JellyfinMediaStream get asStream => JellyfinMediaStream(
|
||||
index: id,
|
||||
type: type,
|
||||
language: language,
|
||||
title: title,
|
||||
codec: codec,
|
||||
channels: channels,
|
||||
isDefault: isDefault,
|
||||
isForced: isForced,
|
||||
isHearingImpaired: isHearingImpaired);
|
||||
|
||||
/// Menu text: "Japanese · E-AC3 2.0 · Commentary", "Track 2 · ASS".
|
||||
String get label => [
|
||||
languageName(language) ?? 'Track $id',
|
||||
[?codecName(codec), ?channelLayoutName(channels)].join(' '),
|
||||
if (title != null && title != languageName(language)) title!,
|
||||
if (isForced) 'Forced',
|
||||
if (isHearingImpaired) 'SDH',
|
||||
].where((p) => p.isNotEmpty).join(' · ');
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
other is MpvTrack &&
|
||||
other.id == id &&
|
||||
other.type == type &&
|
||||
other.language == language &&
|
||||
other.title == title &&
|
||||
other.codec == codec &&
|
||||
other.channels == channels &&
|
||||
other.isDefault == isDefault &&
|
||||
other.isForced == isForced &&
|
||||
other.isHearingImpaired == isHearingImpaired &&
|
||||
other.isExternal == isExternal &&
|
||||
other.selected == selected;
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, type, language, title, codec, channels, isDefault, isForced,
|
||||
isHearingImpaired, isExternal, selected);
|
||||
|
||||
@override
|
||||
String toString() => 'MpvTrack(${type.name} $id ${selected ? '*' : ''}$label)';
|
||||
}
|
||||
|
||||
const _languages = {
|
||||
'jpn': 'Japanese', 'ja': 'Japanese', 'eng': 'English', 'en': 'English',
|
||||
'ger': 'German', 'deu': 'German', 'de': 'German', 'fre': 'French', 'fra': 'French',
|
||||
'fr': 'French', 'spa': 'Spanish', 'es': 'Spanish', 'ita': 'Italian', 'it': 'Italian',
|
||||
'por': 'Portuguese', 'pt': 'Portuguese', 'rus': 'Russian', 'ru': 'Russian',
|
||||
'chi': 'Chinese', 'zho': 'Chinese', 'zh': 'Chinese', 'kor': 'Korean', 'ko': 'Korean',
|
||||
'ara': 'Arabic', 'ar': 'Arabic', 'pol': 'Polish', 'pl': 'Polish', 'dut': 'Dutch',
|
||||
'nld': 'Dutch', 'nl': 'Dutch', 'swe': 'Swedish', 'sv': 'Swedish', 'fin': 'Finnish',
|
||||
'fi': 'Finnish', 'nor': 'Norwegian', 'no': 'Norwegian', 'dan': 'Danish', 'da': 'Danish',
|
||||
'tur': 'Turkish', 'tr': 'Turkish', 'hin': 'Hindi', 'hi': 'Hindi', 'tha': 'Thai',
|
||||
'th': 'Thai', 'vie': 'Vietnamese', 'vi': 'Vietnamese', 'ind': 'Indonesian', 'id': 'Indonesian',
|
||||
'may': 'Malay', 'msa': 'Malay', 'ms': 'Malay', 'heb': 'Hebrew', 'he': 'Hebrew',
|
||||
'gre': 'Greek', 'ell': 'Greek', 'el': 'Greek', 'cze': 'Czech', 'ces': 'Czech', 'cs': 'Czech',
|
||||
'hun': 'Hungarian', 'hu': 'Hungarian', 'ukr': 'Ukrainian', 'uk': 'Ukrainian',
|
||||
'rum': 'Romanian', 'ron': 'Romanian', 'ro': 'Romanian', 'und': 'Undetermined',
|
||||
};
|
||||
|
||||
/// "jpn" -> "Japanese"; other codes upper-cased, null for none.
|
||||
String? languageName(String? code) {
|
||||
if (code == null || code.isEmpty) return null;
|
||||
return _languages[code.toLowerCase()] ?? code.toUpperCase();
|
||||
}
|
||||
|
||||
const _codecs = {
|
||||
'eac3': 'E-AC3', 'ac3': 'AC3', 'aac': 'AAC', 'flac': 'FLAC', 'opus': 'Opus',
|
||||
'vorbis': 'Vorbis', 'mp3': 'MP3', 'truehd': 'TrueHD', 'dts': 'DTS', 'mlp': 'MLP',
|
||||
'alac': 'ALAC', 'ass': 'ASS', 'ssa': 'SSA', 'subrip': 'SRT', 'srt': 'SRT',
|
||||
'webvtt': 'VTT', 'mov_text': 'TX3G', 'hdmv_pgs_subtitle': 'PGS', 'pgssub': 'PGS',
|
||||
'dvd_subtitle': 'VobSub', 'dvdsub': 'VobSub', 'dvb_subtitle': 'DVB',
|
||||
};
|
||||
|
||||
/// mpv / Jellyfin codec name for menus: "eac3" -> "E-AC3", "subrip" -> "SRT".
|
||||
String? codecName(String? codec) {
|
||||
if (codec == null || codec.isEmpty) return null;
|
||||
final c = codec.toLowerCase();
|
||||
if (c.startsWith('pcm')) return 'PCM';
|
||||
return _codecs[c] ?? codec.toUpperCase();
|
||||
}
|
||||
|
||||
/// Channel count as a layout: 2 -> "2.0", 6 -> "5.1", 8 -> "7.1".
|
||||
String? channelLayoutName(int? channels) => switch (channels) {
|
||||
null || <= 0 => null,
|
||||
1 => '1.0',
|
||||
2 => '2.0',
|
||||
3 => '2.1',
|
||||
6 => '5.1',
|
||||
7 => '6.1',
|
||||
8 => '7.1',
|
||||
final n => '${n}ch',
|
||||
};
|
||||
|
||||
/// A viewer's audio/subtitle choice as traits (indices shift between
|
||||
/// files). [subtitlesOff] wins over [subtitle].
|
||||
class TrackChoice {
|
||||
final TrackPreference? audio;
|
||||
final TrackPreference? subtitle;
|
||||
final bool subtitlesOff;
|
||||
const TrackChoice({this.audio, this.subtitle, this.subtitlesOff = false});
|
||||
|
||||
Map<String, Object?> toJson() => {
|
||||
'audio': ?_prefToJson(audio),
|
||||
'subtitle': ?_prefToJson(subtitle),
|
||||
'subtitlesOff': subtitlesOff,
|
||||
};
|
||||
|
||||
static TrackChoice? fromJson(Object? j) {
|
||||
if (j is! Map) return null;
|
||||
return TrackChoice(
|
||||
audio: _prefFromJson(j['audio'], JellyfinStreamType.audio),
|
||||
subtitle: _prefFromJson(j['subtitle'], JellyfinStreamType.subtitle),
|
||||
subtitlesOff: j['subtitlesOff'] == true,
|
||||
);
|
||||
}
|
||||
|
||||
/// The choice behind mpv's [aid] / [sid] (null = none / off): traits from
|
||||
/// the Jellyfin [source] when this viewer has it (title, channels,
|
||||
/// forced/HI flags), else from mpv's [tracks].
|
||||
factory TrackChoice.of({
|
||||
required int? aid,
|
||||
required int? sid,
|
||||
JellyfinMediaSource? source,
|
||||
List<MpvTrack> tracks = const [],
|
||||
}) {
|
||||
TrackPreference? pref(JellyfinStreamType type, int? id) {
|
||||
if (id == null) return null;
|
||||
if (source != null) {
|
||||
final index = source.jellyfinIndexForMpvTrack(type, id);
|
||||
final s = index == null ? null : source.streamAt(index);
|
||||
if (s != null) return TrackPreference.fromStream(s);
|
||||
}
|
||||
final t = tracks.where((t) => t.type == type && t.id == id).firstOrNull;
|
||||
return t == null ? null : TrackPreference.fromStream(t.asStream);
|
||||
}
|
||||
|
||||
return TrackChoice(
|
||||
audio: pref(JellyfinStreamType.audio, aid),
|
||||
subtitle: pref(JellyfinStreamType.subtitle, sid),
|
||||
subtitlesOff: sid == null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object?>? _prefToJson(TrackPreference? p) => p == null
|
||||
? null
|
||||
: {
|
||||
'language': ?p.language,
|
||||
'title': ?p.title,
|
||||
'codec': ?p.codec,
|
||||
'channels': ?p.channels,
|
||||
if (p.isForced) 'forced': true,
|
||||
if (p.isHearingImpaired) 'hi': true,
|
||||
};
|
||||
|
||||
TrackPreference? _prefFromJson(Object? j, JellyfinStreamType type) {
|
||||
if (j is! Map) return null;
|
||||
String? s(Object? v) => v is String && v.isNotEmpty ? v : null;
|
||||
return TrackPreference(
|
||||
type: type,
|
||||
language: s(j['language']),
|
||||
title: s(j['title']),
|
||||
codec: s(j['codec']),
|
||||
channels: j['channels'] is int ? j['channels'] as int : null,
|
||||
isForced: j['forced'] == true,
|
||||
isHearingImpaired: j['hi'] == true,
|
||||
);
|
||||
}
|
||||
|
||||
/// mpv tracks to select for [choice] on a new item. Matches against the
|
||||
/// Jellyfin [source]'s streams when this viewer has them (mapped to mpv ids
|
||||
/// with [JellyfinMediaSource.mpvTrackId]), else against mpv's [tracks].
|
||||
/// Null fields keep the player's default; [subtitlesOff] turns them off.
|
||||
({int? aid, int? sid, bool subtitlesOff}) chooseTracks(TrackChoice choice,
|
||||
{JellyfinMediaSource? source, List<MpvTrack> tracks = const []}) {
|
||||
int? pick(TrackPreference? pref) {
|
||||
if (pref == null) return null;
|
||||
if (source != null) {
|
||||
final s = matchTrack(pref, source.mediaStreams);
|
||||
return s == null ? null : source.mpvTrackId(s.index);
|
||||
}
|
||||
return matchTrack(pref, [for (final t in tracks) t.asStream])?.index;
|
||||
}
|
||||
|
||||
return (
|
||||
aid: pick(choice.audio),
|
||||
sid: choice.subtitlesOff ? null : pick(choice.subtitle),
|
||||
subtitlesOff: choice.subtitlesOff,
|
||||
);
|
||||
}
|
||||
|
||||
/// The last choice per series and overall, in their own Hive box.
|
||||
class TrackPrefs {
|
||||
TrackPrefs({JellyfinStore? store}) : _store = store ?? HiveJellyfinStore(boxName: trackPrefsBoxName);
|
||||
final JellyfinStore _store;
|
||||
Future<void>? _open;
|
||||
|
||||
Future<void> _ready() => _open ??= _store.open().catchError((Object e) {
|
||||
debugPrint('open track prefs failed: $e');
|
||||
});
|
||||
|
||||
/// The series' choice, else the global one.
|
||||
Future<TrackChoice?> load({String? seriesId}) async {
|
||||
await _ready();
|
||||
try {
|
||||
Object? read(String key) {
|
||||
final v = _store.get(key);
|
||||
return v is String ? jsonDecode(v) : null;
|
||||
}
|
||||
|
||||
return (seriesId == null ? null : TrackChoice.fromJson(read('series:$seriesId'))) ??
|
||||
TrackChoice.fromJson(read(_keyGlobal));
|
||||
} catch (e) {
|
||||
debugPrint('read track prefs failed: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Saves [choice] as the global one and, with [seriesId], the series'.
|
||||
Future<void> save(TrackChoice choice, {String? seriesId}) async {
|
||||
await _ready();
|
||||
try {
|
||||
final v = jsonEncode(choice.toJson());
|
||||
await _store.put(_keyGlobal, v);
|
||||
if (seriesId != null) await _store.put('series:$seriesId', v);
|
||||
} catch (e) {
|
||||
debugPrint('save track prefs failed: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
/// FNV-1a over a 15x15 grid of RGB(A) pixels in the central half of an
|
||||
/// image. Used on a small capture of what the compositor shows: the
|
||||
/// centre is video, the edges carry the (changing) control overlays.
|
||||
int hashCenterPixels(ByteData rgba, int width, int height) {
|
||||
var x = 0x811c9dc5;
|
||||
if (width <= 0 || height <= 0) return x;
|
||||
for (var gy = 1; gy < 16; gy++) {
|
||||
for (var gx = 1; gx < 16; gx++) {
|
||||
final px = (width * (0.25 + 0.5 * gx / 16)).floor();
|
||||
final py = (height * (0.25 + 0.5 * gy / 16)).floor();
|
||||
final o = (py * width + px) * 4;
|
||||
if (o + 3 > rgba.lengthInBytes) continue;
|
||||
for (var c = 0; c < 3; c++) {
|
||||
x = ((x ^ rgba.getUint8(o + c)) * 0x01000193) & 0xffffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/// FNV-1a over ~4k bytes spread evenly across a raw frame (mpv
|
||||
/// `screenshot-raw`); dimension-agnostic, enough to tell frames apart.
|
||||
int hashSpread(Uint8List bytes) {
|
||||
var x = 0x811c9dc5;
|
||||
if (bytes.isEmpty) return x;
|
||||
final step = bytes.length <= 4096 ? 1 : bytes.length ~/ 4096;
|
||||
for (var i = 0; i < bytes.length; i += step) {
|
||||
x = ((x ^ bytes[i]) * 0x01000193) & 0xffffffff;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/// One sample of player state, taken about once a second.
|
||||
class FrameSample {
|
||||
final DateTime at;
|
||||
final double position;
|
||||
|
||||
/// Fingerprint of the picture currently shown on screen; null when it
|
||||
/// cannot be captured (no view, hidden window, headless).
|
||||
final int? frames;
|
||||
|
||||
/// Playing, not buffering, rate > 0, video track present, window
|
||||
/// visible. Anything else disarms the watchdog.
|
||||
final bool eligible;
|
||||
const FrameSample({
|
||||
required this.at,
|
||||
required this.position,
|
||||
required this.frames,
|
||||
required this.eligible,
|
||||
});
|
||||
}
|
||||
|
||||
/// Detects a frozen picture: position advances normally but the shown
|
||||
/// picture stands still for [stallAfter]. Seeks (position jumps), pauses,
|
||||
/// buffering and missing captures all reset the stall clock. A hit is a
|
||||
/// suspicion only — a still scene looks the same — so the caller confirms
|
||||
/// it against the decoder and calls [dismiss] when it was a still scene.
|
||||
/// Fires at most once until the picture is seen moving again for
|
||||
/// [rearmAfter], so a player that stays (or soon gets) frozen after a
|
||||
/// reload does not reload in a loop. [reset] keeps that latch.
|
||||
class FrameWatchdog {
|
||||
static const stallAfter = Duration(seconds: 3);
|
||||
static const rearmAfter = Duration(seconds: 10);
|
||||
|
||||
FrameSample? _last;
|
||||
DateTime? _stallSince;
|
||||
DateTime? _healthySince;
|
||||
bool _fired = false;
|
||||
|
||||
void reset() {
|
||||
_last = null;
|
||||
_stallSince = null;
|
||||
_healthySince = null;
|
||||
}
|
||||
|
||||
/// The last hit was a still scene: re-arm, but wait a full
|
||||
/// [stallAfter] before suspecting again.
|
||||
void dismiss() {
|
||||
_fired = false;
|
||||
_stallSince = null;
|
||||
}
|
||||
|
||||
/// Returns true exactly when a freeze is suspected.
|
||||
bool feed(FrameSample s) {
|
||||
final last = _last;
|
||||
_last = s;
|
||||
if (!s.eligible || s.frames == null || last == null ||
|
||||
!last.eligible || last.frames == null) {
|
||||
_stallSince = null;
|
||||
_healthySince = null;
|
||||
return false;
|
||||
}
|
||||
if (s.frames != last.frames) {
|
||||
_stallSince = null;
|
||||
_healthySince ??= last.at;
|
||||
if (s.at.difference(_healthySince!) >= rearmAfter) _fired = false;
|
||||
return false;
|
||||
}
|
||||
_healthySince = null;
|
||||
final wall = s.at.difference(last.at).inMilliseconds / 1000.0;
|
||||
final moved = s.position - last.position;
|
||||
// Normal playback only: a jump (seek) or a standstill (stall, the
|
||||
// position itself stuck) is not a frozen picture.
|
||||
final normal = wall > 0 && moved > wall * 0.5 && moved < wall * 2 + 0.5;
|
||||
if (!normal) {
|
||||
_stallSince = null;
|
||||
return false;
|
||||
}
|
||||
_stallSince ??= last.at;
|
||||
if (_fired) return false;
|
||||
if (s.at.difference(_stallSince!) >= stallAfter) {
|
||||
_fired = true;
|
||||
_stallSince = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:sync_relay_core/core.dart' show JellyfinMediaSegment, JellyfinSegmentType, JellyfinStreamType;
|
||||
|
||||
import '../jellyfin/track_prefs.dart' show MpvTrack;
|
||||
|
||||
// Chapters, segments and tracks of the open media as plain values, plus
|
||||
// the skip rules built on them (OP / ED / the 1:30 fallback, chapter
|
||||
// steps). No Flutter, no player: `PlaybackController` feeds its signals
|
||||
// through these and any controls UI reads them.
|
||||
|
||||
/// One mpv chapter. [end] is the next chapter's start, or the duration for
|
||||
/// the last one ([start] while the duration is unknown).
|
||||
class MediaChapter {
|
||||
final int index;
|
||||
final String title;
|
||||
final Duration start;
|
||||
final Duration end;
|
||||
const MediaChapter({required this.index, required this.title, required this.start, required this.end});
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
other is MediaChapter &&
|
||||
other.index == index &&
|
||||
other.title == title &&
|
||||
other.start == start &&
|
||||
other.end == end;
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(index, title, start, end);
|
||||
|
||||
@override
|
||||
String toString() => 'MediaChapter($index "$title" $start-$end)';
|
||||
}
|
||||
|
||||
/// A marked range of the item from Jellyfin (MediaSegments): intro,
|
||||
/// outro, recap, preview or commercial.
|
||||
class MediaSegment {
|
||||
final JellyfinSegmentType kind;
|
||||
final Duration start;
|
||||
final Duration end;
|
||||
const MediaSegment({required this.kind, required this.start, required this.end});
|
||||
|
||||
factory MediaSegment.fromJellyfin(JellyfinMediaSegment s) =>
|
||||
MediaSegment(kind: s.type, start: s.start, end: s.end);
|
||||
|
||||
@override
|
||||
String toString() => 'MediaSegment(${kind.name} $start-$end)';
|
||||
}
|
||||
|
||||
/// Where a skip range came from.
|
||||
enum SkipSource { segment, chapter }
|
||||
|
||||
/// An opening or ending: skipping it seeks to [end].
|
||||
class SkipRange {
|
||||
final Duration start;
|
||||
final Duration end;
|
||||
final SkipSource source;
|
||||
/// The chapter title when [source] is a chapter.
|
||||
final String? title;
|
||||
const SkipRange(this.start, this.end, this.source, {this.title});
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
other is SkipRange &&
|
||||
other.start == start &&
|
||||
other.end == end &&
|
||||
other.source == source &&
|
||||
other.title == title;
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(start, end, source, title);
|
||||
|
||||
@override
|
||||
String toString() => 'SkipRange(${source.name} $start-$end${title == null ? '' : ' "$title"'})';
|
||||
}
|
||||
|
||||
Duration _secs(num s) => Duration(microseconds: (s * 1e6).round());
|
||||
|
||||
/// mpv `chapter-list` as JSON (`[{"title": "OP", "time": 30.0}, ...]`).
|
||||
/// Ends come from the next start, the last from [duration].
|
||||
List<MediaChapter> parseChapterList(String json, Duration duration) {
|
||||
final Object? raw;
|
||||
try {
|
||||
raw = jsonDecode(json);
|
||||
} on FormatException {
|
||||
return const [];
|
||||
}
|
||||
if (raw is! List) return const [];
|
||||
final starts = <(String, Duration)>[
|
||||
for (final c in raw)
|
||||
if (c is Map && c['time'] is num && (c['time'] as num).isFinite)
|
||||
((c['title'] is String ? c['title'] as String : '').trim(), _secs(c['time'] as num)),
|
||||
]..sort((a, b) => a.$2.compareTo(b.$2));
|
||||
return chaptersFromStarts(starts, duration);
|
||||
}
|
||||
|
||||
/// Chapters from (title, start) pairs in start order.
|
||||
List<MediaChapter> chaptersFromStarts(List<(String, Duration)> starts, Duration duration) => [
|
||||
for (var i = 0; i < starts.length; i++)
|
||||
MediaChapter(
|
||||
index: i,
|
||||
title: starts[i].$1,
|
||||
start: starts[i].$2,
|
||||
end: i + 1 < starts.length
|
||||
? starts[i + 1].$2
|
||||
: (duration > starts[i].$2 ? duration : starts[i].$2),
|
||||
),
|
||||
];
|
||||
|
||||
/// mpv `track-list` as JSON: the audio and subtitle tracks (video and
|
||||
/// unknown types left out), with mpv's selection.
|
||||
List<MpvTrack> parseTrackList(String json) {
|
||||
final Object? raw;
|
||||
try {
|
||||
raw = jsonDecode(json);
|
||||
} on FormatException {
|
||||
return const [];
|
||||
}
|
||||
if (raw is! List) return const [];
|
||||
String? s(Object? v) => v is String && v.isNotEmpty ? v : null;
|
||||
return [
|
||||
for (final t in raw)
|
||||
if (t is Map && t['id'] is int && (t['type'] == 'audio' || t['type'] == 'sub'))
|
||||
MpvTrack(
|
||||
id: t['id'] as int,
|
||||
type: t['type'] == 'audio' ? JellyfinStreamType.audio : JellyfinStreamType.subtitle,
|
||||
language: s(t['lang']),
|
||||
title: s(t['title']),
|
||||
codec: s(t['codec']),
|
||||
channels: (t['demux-channel-count'] ?? t['audio-channels']) is int
|
||||
? (t['demux-channel-count'] ?? t['audio-channels']) as int
|
||||
: null,
|
||||
isDefault: t['default'] == true,
|
||||
isForced: t['forced'] == true,
|
||||
isHearingImpaired: t['hearing-impaired'] == true,
|
||||
isExternal: t['external'] == true,
|
||||
selected: t['selected'] == true,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
final _openingTitle = RegExp(r'\b(op|opening|intro)\d*\b', caseSensitive: false);
|
||||
final _endingTitle = RegExp(r'\b(ed|ending|credits|outro)\d*\b', caseSensitive: false);
|
||||
|
||||
/// "OP", "OP1", "Opening", "Intro" (whole words, any case).
|
||||
bool isOpeningTitle(String title) => _openingTitle.hasMatch(title);
|
||||
|
||||
/// "ED", "ED2", "Ending", "Credits", "Outro" (whole words, any case).
|
||||
bool isEndingTitle(String title) => _endingTitle.hasMatch(title);
|
||||
|
||||
SkipRange? _range(List<MediaSegment> segments, List<MediaChapter> chapters,
|
||||
JellyfinSegmentType kind, bool Function(String) titleMatches) {
|
||||
for (final s in segments) {
|
||||
if (s.kind == kind && s.end > s.start) return SkipRange(s.start, s.end, SkipSource.segment);
|
||||
}
|
||||
for (final c in chapters) {
|
||||
if (c.end > c.start && titleMatches(c.title)) {
|
||||
return SkipRange(c.start, c.end, SkipSource.chapter, title: c.title);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// The opening: the first Jellyfin Intro segment, else the first chapter
|
||||
/// titled like an opening ([isOpeningTitle]).
|
||||
SkipRange? openingRange(List<MediaSegment> segments, List<MediaChapter> chapters) =>
|
||||
_range(segments, chapters, JellyfinSegmentType.intro, isOpeningTitle);
|
||||
|
||||
/// The ending: the first Jellyfin Outro segment, else the first chapter
|
||||
/// titled like an ending ([isEndingTitle]).
|
||||
SkipRange? endingRange(List<MediaSegment> segments, List<MediaChapter> chapters) =>
|
||||
_range(segments, chapters, JellyfinSegmentType.outro, isEndingTitle);
|
||||
|
||||
/// Index of the chapter playing at [position], or null (before the first
|
||||
/// chapter, or none).
|
||||
int? chapterIndexAt(List<MediaChapter> chapters, Duration position) {
|
||||
int? at;
|
||||
for (final c in chapters) {
|
||||
if (c.start <= position) at = c.index;
|
||||
}
|
||||
return at;
|
||||
}
|
||||
|
||||
/// mpv's `chapter-seek-threshold`: going back within this much of a
|
||||
/// chapter's start goes to the chapter before it.
|
||||
const chapterBackThreshold = Duration(seconds: 5);
|
||||
|
||||
/// Target of a chapter step ([delta] +1 = PgDn, -1 = PgUp), as mpv: back
|
||||
/// goes to the current chapter's start, or the previous one within
|
||||
/// [chapterBackThreshold] of it; forward to the next chapter's start.
|
||||
/// Null when there is nowhere to go.
|
||||
Duration? chapterStepTarget(List<MediaChapter> chapters, Duration position, int delta) {
|
||||
if (chapters.isEmpty || delta == 0) return null;
|
||||
final at = chapterIndexAt(chapters, position);
|
||||
if (delta > 0) {
|
||||
final next = (at ?? -1) + delta;
|
||||
return next < chapters.length ? chapters[next].start : null;
|
||||
}
|
||||
if (at == null) return null;
|
||||
var target = at + delta + 1;
|
||||
if (position - chapters[at].start < chapterBackThreshold) target--;
|
||||
return target >= 0 ? chapters[target].start : Duration.zero;
|
||||
}
|
||||
|
||||
/// What the skip pill offers.
|
||||
enum SkipKind {
|
||||
/// "Skip OP": to the opening's end.
|
||||
opening,
|
||||
/// "Skip ED": to the ending's end, nothing further.
|
||||
ending,
|
||||
/// "Skip 1:30": no opening known, +[fallbackSkip] from where it plays.
|
||||
fixed,
|
||||
}
|
||||
|
||||
class SkipOffer {
|
||||
final SkipKind kind;
|
||||
/// Seek target (for [SkipKind.fixed] as of the position it was computed
|
||||
/// at; the press itself skips relative to the moment it lands).
|
||||
final Duration target;
|
||||
const SkipOffer(this.kind, this.target);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => other is SkipOffer && other.kind == kind && other.target == target;
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(kind, target);
|
||||
|
||||
@override
|
||||
String toString() => 'SkipOffer(${kind.name} -> $target)';
|
||||
}
|
||||
|
||||
/// The fixed skip (pill without an opening, Shift+Right, the controls'
|
||||
/// "1:30" button).
|
||||
const fallbackSkip = Duration(seconds: 90);
|
||||
/// The fallback pill needs media longer than this (an episode, not a clip).
|
||||
const fallbackMinDuration = Duration(minutes: 20);
|
||||
/// ... and shows during this first part only.
|
||||
const fallbackWindow = Duration(minutes: 6);
|
||||
/// No pill in the last second of a range: the skip would do nothing.
|
||||
const _skipTail = Duration(seconds: 1);
|
||||
|
||||
/// The skip pill at [position]: inside the opening "Skip OP" (to its end),
|
||||
/// inside the ending "Skip ED" (to its end only: what follows, preview or
|
||||
/// more episode, is the viewer's call). Without any opening info on media
|
||||
/// longer than [fallbackMinDuration], "Skip 1:30" during the first
|
||||
/// [fallbackWindow]. Null otherwise.
|
||||
SkipOffer? skipOfferAt({
|
||||
required Duration position,
|
||||
required Duration duration,
|
||||
required SkipRange? opening,
|
||||
required SkipRange? ending,
|
||||
}) {
|
||||
bool inside(SkipRange r) => position >= r.start && position < r.end - _skipTail;
|
||||
if (opening != null && inside(opening)) return SkipOffer(SkipKind.opening, opening.end);
|
||||
if (ending != null && inside(ending)) return SkipOffer(SkipKind.ending, ending.end);
|
||||
if (opening == null && duration > fallbackMinDuration && position < fallbackWindow) {
|
||||
final to = position + fallbackSkip;
|
||||
return SkipOffer(SkipKind.fixed, to < duration ? to : duration);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// "1:05", "1:02:03".
|
||||
String formatClock(Duration d) {
|
||||
final neg = d.isNegative;
|
||||
final t = d.abs();
|
||||
String two(int n) => n.toString().padLeft(2, '0');
|
||||
final h = t.inHours, m = t.inMinutes % 60, s = t.inSeconds % 60;
|
||||
final body = h > 0 ? '$h:${two(m)}:${two(s)}' : '$m:${two(s)}';
|
||||
return neg ? '-$body' : body;
|
||||
}
|
||||
@@ -1,75 +1,562 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart' show listEquals;
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
import 'package:sync_relay_core/core.dart' show JellyfinStreamType;
|
||||
|
||||
import '../sync/room_diff.dart';
|
||||
import '../jellyfin/track_prefs.dart' show MpvTrack;
|
||||
import '../shaders/shader_assets.dart';
|
||||
import '../shaders/shader_presets.dart';
|
||||
import '../state/settings.dart';
|
||||
import '../sync/state_diff.dart';
|
||||
import '../sync/user_seek.dart';
|
||||
import 'frame_watchdog.dart';
|
||||
import 'media_marks.dart';
|
||||
|
||||
/// Owns one mpv [Player] (and its [VideoController]) per session: created
|
||||
/// by [init] on join, released by [dispose] on leave, swapped by
|
||||
/// [recreate] for "Reload video". Never reuse a player across sessions —
|
||||
/// a GPU-side freeze sticks to the player, not to the widget.
|
||||
class PlaybackController {
|
||||
late final Player player;
|
||||
bool _ready = false;
|
||||
/// Read-ahead target: about two minutes rides out short outages and
|
||||
/// makes skipping an intro instant.
|
||||
static const readAheadSecs = 150;
|
||||
/// Forward demuxer cache. Holds [readAheadSecs] up to ~14 Mbit/s (a
|
||||
/// 1.4 GB / 24 min file is ~8); higher bitrates get less time. In RAM:
|
||||
/// media_kit sets cache-on-disk but no cache-dir, so mpv falls back.
|
||||
static const maxBytes = 256 * 1024 * 1024;
|
||||
/// Back buffer (media_kit sets it to bufferSize too): enough for a short
|
||||
/// seek back without holding another 256 MiB.
|
||||
static const maxBackBytes = 64 * 1024 * 1024;
|
||||
|
||||
SyncPlayer? _player;
|
||||
VideoController? _video;
|
||||
Timer? _watchTimer;
|
||||
bool _probing = false;
|
||||
final FrameWatchdog _watchdog = FrameWatchdog();
|
||||
StreamSubscription<PlayerLog>? _logSub;
|
||||
final List<StreamSubscription<Duration>> _timeSubs = [];
|
||||
String _chapterJson = '';
|
||||
// `glsl-shaders` as last set on the current player ('' = none).
|
||||
String _shaders = '';
|
||||
Future<void> _shaderOp = Future.value();
|
||||
int _noticeId = 0;
|
||||
|
||||
/// Bumped for every new player; the video view keys itself on it so a
|
||||
/// recreated player gets a fresh `Video` widget.
|
||||
final generation = signal(0);
|
||||
|
||||
/// True while a live player exists. The video view shows plain black
|
||||
/// otherwise, so no texture outlives its player.
|
||||
final alive = signal(false);
|
||||
|
||||
/// Called once when the watchdog sees a frozen picture.
|
||||
void Function()? onFrozen;
|
||||
|
||||
/// Fingerprint of the picture on screen, installed by the video view
|
||||
/// (`ShownFrameProbe.sample`). Without it the watchdog stays idle.
|
||||
Future<int?> Function()? shownFrame;
|
||||
|
||||
Player get player => _player!;
|
||||
|
||||
/// Seeks from the video controls (seek bar) go here instead of to mpv.
|
||||
void Function(Duration position)? onUserSeek;
|
||||
|
||||
/// Latest shader message for the user (the session screen toasts it).
|
||||
final shaderNotice = signal<ShaderNotice?>(null);
|
||||
|
||||
/// How media_kit renders the current player's video (shaders need
|
||||
/// [RenderMode.gpu]); [lastRenderMode] keeps it after leaving.
|
||||
final renderMode = signal(RenderMode.unknown);
|
||||
static final lastRenderMode = signal(RenderMode.unknown);
|
||||
|
||||
// ------------------------------------------------- media marks (signals)
|
||||
//
|
||||
// What the open file has, for any controls UI (the session's seek bar,
|
||||
// chapter / track menus and skip pills read these; nothing here knows
|
||||
// about widgets). Reset when the player goes away; [segments] is owned
|
||||
// by the coordinator (it survives Reload video, the item is the same).
|
||||
|
||||
/// mpv `chapter-list`: title and start; end = next start, or the
|
||||
/// duration for the last one. Empty without chapters.
|
||||
final chapters = signal<List<MediaChapter>>(const []);
|
||||
|
||||
/// Jellyfin MediaSegments of the current item (Intro / Outro / Recap /
|
||||
/// Preview / Commercial). Only viewers with their own account fetch
|
||||
/// them (relay viewers cannot call Jellyfin): empty otherwise.
|
||||
final segments = signal<List<MediaSegment>>(const []);
|
||||
|
||||
/// Audio and subtitle tracks from mpv's `track-list` (id, language,
|
||||
/// title, codec, channels, default / forced flags, [MpvTrack.selected]).
|
||||
final tracks = signal<List<MpvTrack>>(const []);
|
||||
|
||||
/// Playback position, in 250 ms steps (enough for pills and menus; a
|
||||
/// seek bar should listen to `player.stream.position`).
|
||||
final position = signal(Duration.zero);
|
||||
|
||||
/// Duration of the open file (zero until known).
|
||||
final duration = signal(Duration.zero);
|
||||
|
||||
/// End of the cached range ahead of the position (mpv
|
||||
/// `demuxer-cache-time`, media_kit's `buffer`), in 250 ms steps.
|
||||
final buffered = signal(Duration.zero);
|
||||
|
||||
/// The opening ([openingRange]: Intro segment, else an OP-titled
|
||||
/// chapter) and the ending ([endingRange]: Outro, else ED-titled).
|
||||
late final Computed<SkipRange?> opening =
|
||||
computed(() => openingRange(segments.value, chapters.value));
|
||||
late final Computed<SkipRange?> ending =
|
||||
computed(() => endingRange(segments.value, chapters.value));
|
||||
|
||||
/// Index into [chapters] of the chapter playing now.
|
||||
late final Computed<int?> currentChapter =
|
||||
computed(() => chapterIndexAt(chapters.value, position.value));
|
||||
|
||||
/// Pinned mpv properties whose read-back differs from what was set
|
||||
/// (mpv ignores invalid values silently), as `name: wanted -> got`.
|
||||
final List<String> pinMismatches = [];
|
||||
bool get _ready => _player != null;
|
||||
|
||||
/// The [VideoController] of the current player. Created lazily by the
|
||||
/// video view (it needs a running Flutter binding; headless tests never
|
||||
/// touch it) and released with the player.
|
||||
VideoController get video {
|
||||
final existing = _video;
|
||||
if (existing != null) return existing;
|
||||
final hwdec = _hwdecOverride;
|
||||
// media_kit's video output sets hwdec itself on attach ('auto' unless
|
||||
// configured), which used to override SYNC_RELAY_HWDEC.
|
||||
final video = _video = VideoController(
|
||||
player,
|
||||
configuration: VideoControllerConfiguration(hwdec: hwdec),
|
||||
);
|
||||
unawaited(_detectRenderMode(player, video));
|
||||
return video;
|
||||
}
|
||||
|
||||
// SYNC_RELAY_HWDEC wins over the Settings choice; read per player, so a
|
||||
// changed setting applies on the next join or Reload video.
|
||||
static String? get _hwdecOverride {
|
||||
final hwdec = Platform.environment['SYNC_RELAY_HWDEC'];
|
||||
if (hwdec != null && hwdec.isNotEmpty) return hwdec;
|
||||
return AppSettings.instance.hwdec.peek();
|
||||
}
|
||||
|
||||
Future<void> init() async {
|
||||
player = Player(
|
||||
if (_player != null) return;
|
||||
_player = SyncPlayer(
|
||||
configuration: PlayerConfiguration(
|
||||
bufferSize: 64 * 1024 * 1024,
|
||||
bufferSize: maxBytes,
|
||||
libass: true,
|
||||
vo: Platform.environment['SYNC_RELAY_VO'],
|
||||
));
|
||||
_ready = true;
|
||||
// Verbose: the render-mode probe needs mpv's GL init lines.
|
||||
logLevel: MPVLogLevel.v,
|
||||
))
|
||||
..onUserSeek = (d) => onUserSeek?.call(d);
|
||||
_shaders = '';
|
||||
renderMode.value = RenderMode.unknown;
|
||||
shaderNotice.value = null;
|
||||
_logSub = _player!.stream.log.listen(_onLog);
|
||||
_watchMarks(_player!);
|
||||
await _pinBufferProps();
|
||||
await applyShaders();
|
||||
_watchdog.reset();
|
||||
_watchTimer = Timer.periodic(const Duration(seconds: 1), (_) => _watch());
|
||||
generation.value++;
|
||||
alive.value = true;
|
||||
}
|
||||
|
||||
/// Dispose the current player and start a fresh one (no media loaded).
|
||||
/// Keeps volume. The caller reopens media and resyncs.
|
||||
Future<void> recreate() async {
|
||||
final volume = _player?.state.volume;
|
||||
await dispose();
|
||||
await init();
|
||||
if (volume != null) {
|
||||
try {
|
||||
await player.setVolume(volume);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _pin(String property, String value) async {
|
||||
try {
|
||||
final dynamic platform = player.platform;
|
||||
await platform?.setProperty(property, value);
|
||||
final got = '${await platform?.getProperty(property)}';
|
||||
if (!pinMatches(value, got)) {
|
||||
pinMismatches.add('$property: $value -> $got');
|
||||
debugPrint('pin $property=$value not applied, mpv has "$got"');
|
||||
}
|
||||
} catch (e, st) {
|
||||
pinMismatches.add('$property: $value -> error $e');
|
||||
debugPrint('pin $property=$value failed: $e\n$st');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _pinBufferProps() async {
|
||||
await _pin('demuxer-readahead-secs', '10');
|
||||
await _pin('cache-secs', '10');
|
||||
final hwdec = Platform.environment['SYNC_RELAY_HWDEC'];
|
||||
if (hwdec != null && hwdec.isNotEmpty) {
|
||||
pinMismatches.clear();
|
||||
await _pin('demuxer-readahead-secs', '$readAheadSecs');
|
||||
await _pin('cache-secs', '$readAheadSecs');
|
||||
await _pin('demuxer-max-bytes', '$maxBytes');
|
||||
await _pin('demuxer-max-back-bytes', '$maxBackBytes');
|
||||
final hwdec = _hwdecOverride;
|
||||
if (hwdec != null) {
|
||||
await _pin('hwdec', hwdec);
|
||||
}
|
||||
await _pin('stream-lavf-o',
|
||||
'reconnect_streamed=1,reconnect_on_http_error=1,reconnect_delay_max=4');
|
||||
}
|
||||
|
||||
Future<void> openUrl(String url) async {
|
||||
/// Puts the saved shader choice (Settings, Ctrl+0..6, shader button) on
|
||||
/// the current player, live. A missing file or a value mpv won't take
|
||||
/// turns shaders off and says why in [shaderNotice]; [announce] also
|
||||
/// reports success ("Shaders: Mode A (HQ)").
|
||||
Future<void> applyShaders({bool announce = false}) =>
|
||||
_shaderOp = _shaderOp.then((_) => _applyShaders(announce));
|
||||
|
||||
Future<void> _applyShaders(bool announce) async {
|
||||
final p = _player;
|
||||
if (p == null) return;
|
||||
final s = AppSettings.instance;
|
||||
final preset = s.shaderPreset.peek();
|
||||
final label = shaderLabel(preset, s.shaderQuality.peek());
|
||||
String? problem;
|
||||
var paths = const <String>[];
|
||||
try {
|
||||
paths = await shaderPathsFor(
|
||||
preset, s.shaderQuality.peek(), s.customShaders.peek());
|
||||
if (preset == ShaderPreset.custom && paths.isEmpty) {
|
||||
problem = 'no custom shader files picked';
|
||||
} else {
|
||||
problem = shaderPathsProblem(paths);
|
||||
}
|
||||
} catch (e) {
|
||||
problem = 'could not unpack the shaders ($e)';
|
||||
}
|
||||
if (!identical(p, _player)) return;
|
||||
if (problem != null) paths = const [];
|
||||
final value = joinShaderPaths(paths);
|
||||
if (value != _shaders || problem != null) {
|
||||
final got = await setShaderValue(value);
|
||||
if (!identical(p, _player)) return;
|
||||
if (problem == null && got != value) {
|
||||
problem = 'mpv did not take them';
|
||||
await setShaderValue('');
|
||||
}
|
||||
}
|
||||
if (problem != null) {
|
||||
_turnShadersOff('$label failed: $problem — turned off');
|
||||
} else if (announce) {
|
||||
_notice('Shaders: $label${_softwareHint(paths)}');
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets mpv `glsl-shaders` on the current player and returns the
|
||||
/// read-back (null on error).
|
||||
@visibleForTesting
|
||||
Future<String?> setShaderValue(String value) async {
|
||||
try {
|
||||
final dynamic platform = player.platform;
|
||||
await platform?.setProperty('glsl-shaders', value);
|
||||
final got = '${await platform?.getProperty('glsl-shaders')}';
|
||||
_shaders = got;
|
||||
if (got != value) debugPrint('glsl-shaders=$value not applied: "$got"');
|
||||
return got;
|
||||
} catch (e, st) {
|
||||
debugPrint('glsl-shaders=$value failed: $e\n$st');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void _turnShadersOff(String message) {
|
||||
AppSettings.instance.setShaderPreset(ShaderPreset.off);
|
||||
_notice(message);
|
||||
}
|
||||
|
||||
void _notice(String text) {
|
||||
shaderNotice.value = ShaderNotice(++_noticeId, text);
|
||||
}
|
||||
|
||||
String _softwareHint(List<String> paths) => paths.isEmpty
|
||||
? ''
|
||||
: switch (renderMode.peek()) {
|
||||
RenderMode.software => ' (no effect: video uses software rendering)',
|
||||
RenderMode.softwareGl => ' (likely slow: OpenGL runs on the CPU)',
|
||||
_ => '',
|
||||
};
|
||||
|
||||
// mpv logs from the render context: GL init lines mean GPU rendering;
|
||||
// an error there while shaders are on is a shader that failed to load
|
||||
// or compile (mpv then renders without it).
|
||||
void _onLog(PlayerLog log) {
|
||||
if (log.prefix != 'libmpv_render') return;
|
||||
if (log.text.contains('suspected software renderer')) {
|
||||
_setRenderMode(RenderMode.softwareGl);
|
||||
} else if (log.text.startsWith('GL_VERSION') &&
|
||||
renderMode.peek() == RenderMode.unknown) {
|
||||
_setRenderMode(RenderMode.gpu);
|
||||
} else if ((log.level == 'error' || log.level == 'fatal') &&
|
||||
_shaders.isNotEmpty) {
|
||||
debugPrint('shader error: ${log.text}');
|
||||
final p = _player;
|
||||
_shaders = '';
|
||||
_shaderOp = _shaderOp.then((_) async {
|
||||
if (!identical(p, _player)) return;
|
||||
await setShaderValue('');
|
||||
_turnShadersOff('Shaders failed in mpv (${log.text}) — turned off');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _setRenderMode(RenderMode mode) {
|
||||
renderMode.value = mode;
|
||||
lastRenderMode.value = mode;
|
||||
}
|
||||
|
||||
// media_kit's Linux/Windows video output creates mpv's render context
|
||||
// while the controller is created: OpenGL when it can, else the
|
||||
// software renderer, which never logs GL init (and ignores shaders).
|
||||
Future<void> _detectRenderMode(Player p, VideoController video) async {
|
||||
try {
|
||||
await video.platform.future;
|
||||
} catch (_) {
|
||||
return;
|
||||
}
|
||||
await Future.delayed(const Duration(milliseconds: 1500));
|
||||
if (!identical(p, _player) || renderMode.peek() != RenderMode.unknown) {
|
||||
return;
|
||||
}
|
||||
_setRenderMode(RenderMode.software);
|
||||
debugPrint('video output: software rendering (no GL init logged)');
|
||||
if (_shaders.isNotEmpty) {
|
||||
_notice('Shaders have no effect: video uses software rendering');
|
||||
}
|
||||
}
|
||||
|
||||
/// Fingerprint of the decoder's current frame (mpv `screenshot-raw`,
|
||||
/// off-thread); null without video.
|
||||
Future<int?> _sourceFrame(Player p) async {
|
||||
try {
|
||||
final raw = await p.screenshot(format: null);
|
||||
return raw == null || raw.isEmpty ? null : hashSpread(raw);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// A suspected freeze is real only if mpv's own frames still move: a
|
||||
/// still scene looks frozen on screen too.
|
||||
Future<bool> _sourceMoving(Player p) async {
|
||||
final a = await _sourceFrame(p);
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
if (!identical(p, _player) || !p.state.playing) return false;
|
||||
final b = await _sourceFrame(p);
|
||||
return a != null && b != null && a != b;
|
||||
}
|
||||
|
||||
static bool get _windowVisible {
|
||||
try {
|
||||
final s = WidgetsBinding.instance.lifecycleState;
|
||||
return s == null ||
|
||||
s == AppLifecycleState.resumed ||
|
||||
s == AppLifecycleState.inactive;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _watch() async {
|
||||
final p = _player;
|
||||
final probe = shownFrame;
|
||||
// Only meaningful once the video view is up.
|
||||
if (p == null || _video == null || probe == null || _probing) return;
|
||||
_probing = true;
|
||||
try {
|
||||
final frames = await probe();
|
||||
if (!identical(p, _player)) return;
|
||||
final s = p.state;
|
||||
final eligible = s.playing &&
|
||||
!s.buffering &&
|
||||
!s.completed &&
|
||||
s.rate > 0 &&
|
||||
(s.width ?? 0) > 0 &&
|
||||
_windowVisible;
|
||||
final fired = _watchdog.feed(FrameSample(
|
||||
at: DateTime.now(),
|
||||
position: positionSecs,
|
||||
frames: frames,
|
||||
eligible: eligible,
|
||||
));
|
||||
if (fired) {
|
||||
if (await _sourceMoving(p) && identical(p, _player)) {
|
||||
debugPrint('video watchdog: picture stuck while mpv frames move');
|
||||
onFrozen?.call();
|
||||
} else {
|
||||
_watchdog.dismiss();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
_probing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Opens [url] paused. [headers] go with every request for it (mpv
|
||||
/// `http-header-fields`): a Jellyfin token travels there, not in the URL.
|
||||
Future<void> openUrl(String url, {Map<String, String>? headers}) async {
|
||||
if (!_ready) return;
|
||||
try {
|
||||
await player.open(Media(url), play: false);
|
||||
_chapterJson = '';
|
||||
chapters.value = const [];
|
||||
tracks.value = const [];
|
||||
buffered.value = Duration.zero;
|
||||
// An empty map, not null: media_kit caches headers per URI.
|
||||
await player.open(Media(url, httpHeaders: headers ?? const {}), play: false);
|
||||
} catch (e, st) {
|
||||
debugPrint('open $url failed: $e\n$st');
|
||||
debugPrint('open ${Uri.tryParse(url)?.replace(query: '') ?? 'media'} failed: $e\n$st');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
double get positionSecs =>
|
||||
player.state.position.inMilliseconds / 1000.0;
|
||||
// Position / duration from media_kit's streams; chapter-list and
|
||||
// track-list observed in mpv (read back as JSON).
|
||||
void _watchMarks(SyncPlayer p) {
|
||||
_timeSubs.add(p.stream.position.listen((d) {
|
||||
final ms = d.inMilliseconds;
|
||||
position.value = Duration(milliseconds: ms - ms % 250);
|
||||
}));
|
||||
_timeSubs.add(p.stream.buffer.listen((d) {
|
||||
final ms = d.inMilliseconds;
|
||||
buffered.value = Duration(milliseconds: ms - ms % 250);
|
||||
}));
|
||||
_timeSubs.add(p.stream.duration.listen((d) {
|
||||
duration.value = d;
|
||||
// The last chapter ends at the duration.
|
||||
if (_chapterJson.isNotEmpty) chapters.value = parseChapterList(_chapterJson, d);
|
||||
}));
|
||||
() async {
|
||||
try {
|
||||
final dynamic platform = p.platform;
|
||||
await platform?.observeProperty('chapter-list', (String v) async {
|
||||
if (!identical(p, _player)) return;
|
||||
_chapterJson = v;
|
||||
chapters.value = parseChapterList(v, duration.peek());
|
||||
});
|
||||
await platform?.observeProperty('track-list', (String v) async {
|
||||
if (!identical(p, _player)) return;
|
||||
_setTracks(parseTrackList(v));
|
||||
});
|
||||
} catch (e) {
|
||||
debugPrint('observe chapters / tracks failed: $e');
|
||||
}
|
||||
}();
|
||||
}
|
||||
|
||||
void _setTracks(List<MpvTrack> list) {
|
||||
if (!listEquals(tracks.peek(), list)) tracks.value = list;
|
||||
}
|
||||
|
||||
/// Reads `track-list` now (after a selection: [tracks] then shows it at
|
||||
/// once instead of on mpv's next change notice).
|
||||
Future<void> _refreshTracks() async {
|
||||
final p = _player;
|
||||
if (p == null) return;
|
||||
try {
|
||||
final dynamic platform = p.platform;
|
||||
final v = '${await platform?.getProperty('track-list')}';
|
||||
if (identical(p, _player)) _setTracks(parseTrackList(v));
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _clearMarks() {
|
||||
_chapterJson = '';
|
||||
chapters.value = const [];
|
||||
tracks.value = const [];
|
||||
position.value = Duration.zero;
|
||||
duration.value = Duration.zero;
|
||||
buffered.value = Duration.zero;
|
||||
}
|
||||
|
||||
/// Waits (bounded) until the open file's tracks are listed and mpv has
|
||||
/// selected its audio track, so a report or a carried-over choice sees
|
||||
/// the real selection.
|
||||
Future<List<MpvTrack>> waitForTracks({Duration timeout = const Duration(seconds: 5)}) async {
|
||||
final end = DateTime.now().add(timeout);
|
||||
while (_player != null && DateTime.now().isBefore(end)) {
|
||||
final t = tracks.peek();
|
||||
final hasAudio = t.any((x) => x.type == JellyfinStreamType.audio);
|
||||
if (t.isNotEmpty && (!hasAudio || (await currentTrackIds()).aid != null)) return t;
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
return tracks.peek();
|
||||
}
|
||||
|
||||
/// mpv's selected audio and subtitle track ids (null = none / off).
|
||||
Future<({int? aid, int? sid})> currentTrackIds() async {
|
||||
final p = _player;
|
||||
if (p == null) return (aid: null, sid: null);
|
||||
try {
|
||||
final dynamic platform = p.platform;
|
||||
final aid = int.tryParse('${await platform?.getProperty('current-tracks/audio/id')}');
|
||||
final sid = int.tryParse('${await platform?.getProperty('current-tracks/sub/id')}');
|
||||
return (aid: aid, sid: sid);
|
||||
} catch (_) {
|
||||
return (aid: null, sid: null);
|
||||
}
|
||||
}
|
||||
|
||||
/// Selects tracks by mpv id; a null [aid] keeps audio, [subtitlesOff]
|
||||
/// turns subtitles off, else a null [sid] keeps them.
|
||||
Future<void> selectTracks({int? aid, int? sid, bool subtitlesOff = false}) async {
|
||||
final p = _player;
|
||||
if (p == null) return;
|
||||
try {
|
||||
final dynamic platform = p.platform;
|
||||
if (aid != null) await platform?.setProperty('aid', '$aid');
|
||||
if (subtitlesOff) {
|
||||
await platform?.setProperty('sid', 'no');
|
||||
} else if (sid != null) {
|
||||
await platform?.setProperty('sid', '$sid');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('select tracks failed: $e');
|
||||
}
|
||||
await _refreshTracks();
|
||||
}
|
||||
|
||||
double get positionSecs {
|
||||
final p = _player;
|
||||
if (p == null) return 0;
|
||||
return p.state.position.inMilliseconds / 1000.0;
|
||||
}
|
||||
|
||||
double get bufferedSecsAhead {
|
||||
final ahead =
|
||||
(player.state.buffer - player.state.position).inMilliseconds / 1000.0;
|
||||
final p = _player;
|
||||
if (p == null) return 0;
|
||||
final ahead = (p.state.buffer - p.state.position).inMilliseconds / 1000.0;
|
||||
if (ahead.isNaN || ahead < 0) return 0;
|
||||
return ahead;
|
||||
}
|
||||
|
||||
double get durationSecs =>
|
||||
player.state.duration.inMilliseconds / 1000.0;
|
||||
double get durationSecs {
|
||||
final p = _player;
|
||||
if (p == null) return 0;
|
||||
return p.state.duration.inMilliseconds / 1000.0;
|
||||
}
|
||||
|
||||
Future<void> apply(List<PlayerAction> actions) async {
|
||||
if (!_ready) return;
|
||||
for (final action in actions) {
|
||||
try {
|
||||
switch (action) {
|
||||
case SeekAction(:final position):
|
||||
if ((positionSecs - position).abs() < 0.5) break;
|
||||
await player.seek(Duration(milliseconds: (position * 1000).round()));
|
||||
await _player!
|
||||
.syncSeek(Duration(milliseconds: (position * 1000).round()));
|
||||
case TransportAction(:final playing):
|
||||
if (playing) {
|
||||
await player.play();
|
||||
@@ -85,10 +572,40 @@ class PlaybackController {
|
||||
}
|
||||
}
|
||||
|
||||
/// Release the player. The view drops its texture first ([alive] goes
|
||||
/// false, one frame passes), then mpv is torn down.
|
||||
Future<void> dispose() async {
|
||||
_ready = false;
|
||||
final p = _player;
|
||||
if (p == null) return;
|
||||
_watchTimer?.cancel();
|
||||
_watchTimer = null;
|
||||
await _logSub?.cancel();
|
||||
_logSub = null;
|
||||
for (final sub in _timeSubs) {
|
||||
await sub.cancel();
|
||||
}
|
||||
_timeSubs.clear();
|
||||
_player = null;
|
||||
_video = null;
|
||||
alive.value = false;
|
||||
_clearMarks();
|
||||
await _settleUi();
|
||||
try {
|
||||
await player.dispose();
|
||||
await p.dispose();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
// Two frames: one may already be mid-build when [alive] flips. Then
|
||||
// the length of a route pop (the fullscreen route holds its own `Video`
|
||||
// and leaves animated). Bounded, since a hidden window renders no
|
||||
// frames; headless tests have no binding and skip it all.
|
||||
static Future<void> _settleUi() async {
|
||||
try {
|
||||
for (var i = 0; i < 2; i++) {
|
||||
await WidgetsBinding.instance.endOfFrame
|
||||
.timeout(const Duration(milliseconds: 300));
|
||||
}
|
||||
await Future.delayed(const Duration(milliseconds: 350));
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
@@ -101,3 +618,26 @@ class PlaybackController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum RenderMode {
|
||||
unknown,
|
||||
/// OpenGL on a real GPU: shaders work.
|
||||
gpu,
|
||||
/// OpenGL on a software rasterizer (llvmpipe): shaders crawl.
|
||||
softwareGl,
|
||||
/// media_kit's software fallback: shaders are ignored.
|
||||
software,
|
||||
}
|
||||
|
||||
class ShaderNotice {
|
||||
final int id;
|
||||
final String text;
|
||||
const ShaderNotice(this.id, this.text);
|
||||
}
|
||||
|
||||
/// mpv echoes numbers in its own format (`150` reads back `150.000000`).
|
||||
bool pinMatches(String wanted, String got) {
|
||||
if (wanted == got) return true;
|
||||
final a = double.tryParse(wanted), b = double.tryParse(got);
|
||||
return a != null && b != null && a == b;
|
||||
}
|
||||
@@ -1,359 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import '../session/session_coordinator.dart';
|
||||
import '../state/session_state.dart';
|
||||
import '../widgets/avatar_pipeline.dart';
|
||||
import '../widgets/media_input.dart';
|
||||
import '../widgets/user_section.dart';
|
||||
import '../widgets/window_buttons.dart';
|
||||
|
||||
class ConnectScreen extends StatefulWidget {
|
||||
const ConnectScreen({super.key});
|
||||
|
||||
@override
|
||||
State<ConnectScreen> createState() => _ConnectScreenState();
|
||||
}
|
||||
|
||||
class _ConnectScreenState extends State<ConnectScreen> {
|
||||
late final TextEditingController _host;
|
||||
late final TextEditingController _port;
|
||||
late final TextEditingController _secret;
|
||||
late final TextEditingController _name;
|
||||
late final TextEditingController _media;
|
||||
late final void Function() _stopKickWatch;
|
||||
String? _error;
|
||||
String? _notice;
|
||||
bool _busy = false;
|
||||
bool _dialogOpen = false;
|
||||
int _attempt = 0;
|
||||
String? _lastKickShown;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final f = SessionState.instance.lastForm;
|
||||
_host = TextEditingController(text: f.host);
|
||||
_port = TextEditingController(text: f.port);
|
||||
_secret = TextEditingController(text: f.secret);
|
||||
_name = TextEditingController(text: f.name);
|
||||
_media = TextEditingController(text: f.linkUrl.isNotEmpty ? f.linkUrl : f.mediaPath);
|
||||
_stopKickWatch = effect(() {
|
||||
final kick = SessionState.instance.coordinator.kickReason.value;
|
||||
if (kick == null || kick.isEmpty) {
|
||||
_lastKickShown = null;
|
||||
return;
|
||||
}
|
||||
if (kick == _lastKickShown) return;
|
||||
_lastKickShown = kick;
|
||||
final reason = kick;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) _showKickedDialog(reason);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_stopKickWatch();
|
||||
_host.dispose();
|
||||
_port.dispose();
|
||||
_secret.dispose();
|
||||
_name.dispose();
|
||||
_media.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
String _actionable(Object e) {
|
||||
if (e is FormatException) return e.message;
|
||||
return 'check the form and try again';
|
||||
}
|
||||
|
||||
Future<ConnectParams> _buildParams(ConnectMode mode) async {
|
||||
final port = int.tryParse(_port.text.trim());
|
||||
if (port == null || port <= 0 || port > 65535) {
|
||||
throw const FormatException('port must be 1–65535');
|
||||
}
|
||||
if (_secret.text.isEmpty) {
|
||||
throw const FormatException('room password required');
|
||||
}
|
||||
if (_name.text.trim().isEmpty) {
|
||||
throw const FormatException('display name required');
|
||||
}
|
||||
String avatar = '';
|
||||
try {
|
||||
avatar = await encodeAvatar(SessionState.instance.lastForm.avatarPath);
|
||||
} on FormatException catch (e) {
|
||||
throw FormatException(e.message);
|
||||
} catch (_) {
|
||||
throw const FormatException('could not process that avatar — pick a PNG, JPG or WebP photo');
|
||||
}
|
||||
final parsed = parseMediaInput(_media.text);
|
||||
if (mode == ConnectMode.host && parsed.mediaPath.isNotEmpty && !await File(parsed.mediaPath).exists()) {
|
||||
throw const FormatException('media file not found — check the path or pick again with Browse');
|
||||
}
|
||||
return ConnectParams(
|
||||
host: _host.text.trim().isEmpty ? '127.0.0.1' : _host.text.trim(),
|
||||
port: port,
|
||||
secret: _secret.text,
|
||||
name: _name.text.trim(),
|
||||
avatar: avatar,
|
||||
mediaPath: mode == ConnectMode.host ? parsed.mediaPath : '',
|
||||
linkUrl: mode == ConnectMode.host ? parsed.linkUrl : '',
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _submit(ConnectMode mode) async {
|
||||
final myAttempt = ++_attempt;
|
||||
final session = SessionState.instance;
|
||||
setState(() {
|
||||
_error = null;
|
||||
_notice = null;
|
||||
_busy = true;
|
||||
});
|
||||
late final ConnectParams params;
|
||||
try {
|
||||
params = await _buildParams(mode);
|
||||
} catch (e) {
|
||||
if (!mounted || myAttempt != _attempt) return;
|
||||
setState(() {
|
||||
_error = _actionable(e);
|
||||
_busy = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
final parsed = parseMediaInput(_media.text);
|
||||
final form = SessionState.instance.lastForm
|
||||
..host = _host.text.trim()
|
||||
..port = _port.text.trim()
|
||||
..secret = _secret.text
|
||||
..name = _name.text.trim()
|
||||
..mediaPath = parsed.mediaPath
|
||||
..linkUrl = parsed.linkUrl;
|
||||
try {
|
||||
if (mode == ConnectMode.host) {
|
||||
await session.host(params, form);
|
||||
} else {
|
||||
await session.join(params, form);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!mounted || myAttempt != _attempt) return;
|
||||
final kick = session.coordinator.kickReason.peek();
|
||||
setState(() => _busy = false);
|
||||
if (kick != null && kick.isNotEmpty) {
|
||||
await _showKickedDialog(kick);
|
||||
} else {
|
||||
await _showConnectionDialog('$e');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (myAttempt != _attempt) {
|
||||
try {
|
||||
await session.leave();
|
||||
await session.stopServer();
|
||||
} catch (_) {}
|
||||
return;
|
||||
}
|
||||
if (mounted) setState(() => _busy = false);
|
||||
}
|
||||
|
||||
Future<void> _cancel() async {
|
||||
_attempt++;
|
||||
try {
|
||||
await SessionState.instance.coordinator.cancelConnect();
|
||||
await SessionState.instance.stopServer();
|
||||
} catch (_) {}
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_busy = false;
|
||||
_notice = 'connection cancelled';
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _showKickedDialog(String reason) async {
|
||||
if (!mounted || _dialogOpen) return;
|
||||
_dialogOpen = true;
|
||||
try {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('You were removed'),
|
||||
content: Text(reason.isEmpty ? 'The host removed you from the room.' : reason),
|
||||
actions: [TextButton(onPressed: () => Navigator.pop(context), child: const Text('OK'))],
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
_dialogOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showConnectionDialog(String message) async {
|
||||
if (!mounted || _dialogOpen) return;
|
||||
_dialogOpen = true;
|
||||
try {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Could not connect'),
|
||||
content: Text(message),
|
||||
actions: [TextButton(onPressed: () => Navigator.pop(context), child: const Text('OK'))],
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
_dialogOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _browse(TextEditingController target, {required String dialogTitle, List<String>? allowedExtensions}) async {
|
||||
try {
|
||||
final files = await FilePicker.pickFiles(
|
||||
dialogTitle: dialogTitle,
|
||||
type: allowedExtensions == null ? FileType.any : FileType.custom,
|
||||
allowedExtensions: allowedExtensions,
|
||||
);
|
||||
if (files.isEmpty) return;
|
||||
final path = files.first.path;
|
||||
if (path != null && mounted) setState(() => target.text = path);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
setState(() => _notice = 'file dialog unavailable (${e.runtimeType}) — paste the path manually');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final session = SessionState.instance;
|
||||
return Scaffold(
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(kToolbarHeight),
|
||||
child: DragToMoveArea(
|
||||
child: AppBar(
|
||||
leading: IconButton(icon: const Icon(Icons.arrow_back), onPressed: () => session.route.value = AppRoute.welcome),
|
||||
title: SignalBuilder(builder: (context) => Text(session.connectMode.value == ConnectMode.host ? 'Host room' : 'Join room')),
|
||||
actions: const [WindowButtons()],
|
||||
),
|
||||
),
|
||||
),
|
||||
body: Stack(
|
||||
alignment: AlignmentGeometry.center,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: ConnectProfileCard(name: _name),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 480),
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
padding: const EdgeInsets.all(24),
|
||||
children: [
|
||||
if (_error != null)
|
||||
Card(
|
||||
child: Padding(padding: const EdgeInsets.all(12), child: Text(_error!)),
|
||||
),
|
||||
if (_notice != null) Text(_notice!),
|
||||
SignalBuilder(
|
||||
builder: (context) {
|
||||
final mode = session.connectMode.value;
|
||||
return SegmentedButton<ConnectMode>(
|
||||
segments: const [
|
||||
ButtonSegment(value: ConnectMode.host, label: Text('Host')),
|
||||
ButtonSegment(value: ConnectMode.join, label: Text('Join')),
|
||||
],
|
||||
selected: {mode},
|
||||
onSelectionChanged: (s) => session.connectMode.value = s.first,
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SignalBuilder(
|
||||
builder: (context) {
|
||||
if (session.connectMode.value == ConnectMode.host) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return TextField(
|
||||
controller: _host,
|
||||
decoration: const InputDecoration(labelText: 'Host address'),
|
||||
);
|
||||
},
|
||||
),
|
||||
TextField(
|
||||
controller: _port,
|
||||
decoration: const InputDecoration(labelText: 'Port'),
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
TextField(
|
||||
controller: _secret,
|
||||
decoration: const InputDecoration(labelText: 'Room password'),
|
||||
obscureText: true,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SignalBuilder(
|
||||
builder: (context) {
|
||||
if (session.connectMode.value == ConnectMode.host) {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _media,
|
||||
decoration: const InputDecoration(labelText: 'Media (file path or http(s) URL)'),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => _browse(
|
||||
_media,
|
||||
dialogTitle: 'Pick media file',
|
||||
allowedExtensions: const ['mp4', 'mkv', 'webm', 'avi', 'mov', 'm4v', 'ts'],
|
||||
),
|
||||
child: const Text('Browse'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SignalBuilder(
|
||||
builder: (context) {
|
||||
final mode = session.connectMode.value;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: _busy ? null : () => _submit(mode),
|
||||
child: Text(
|
||||
_busy
|
||||
? 'Connecting…'
|
||||
: mode == ConnectMode.host
|
||||
? 'Start hosting'
|
||||
: 'Join',
|
||||
),
|
||||
),
|
||||
if (_busy) TextButton(onPressed: _cancel, child: const Text('Cancel')),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text('Host opens ports and serves. Clients open nothing.', textAlign: TextAlign.center),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../../update/update_controller.dart';
|
||||
import '../../update/updater.dart';
|
||||
import 'ui.dart';
|
||||
import 'update_indicator.dart';
|
||||
|
||||
/// Opens [url] in the default browser (no url_launcher dependency).
|
||||
Future<bool> openInBrowser(String url) async {
|
||||
try {
|
||||
final ProcessResult r;
|
||||
if (Platform.isWindows) {
|
||||
r = await Process.run('rundll32', ['url.dll,FileProtocolHandler', url]);
|
||||
} else if (Platform.isMacOS) {
|
||||
r = await Process.run('open', [url]);
|
||||
} else {
|
||||
r = await Process.run('xdg-open', [url]);
|
||||
}
|
||||
return r.exitCode == 0;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class AboutPage extends StatelessWidget {
|
||||
final UpdateController? updates;
|
||||
const AboutPage({super.key, this.updates});
|
||||
|
||||
Future<void> _open(BuildContext context) async {
|
||||
final messenger = ScaffoldMessenger.maybeOf(context);
|
||||
if (await openInBrowser(repoUrl)) return;
|
||||
await Clipboard.setData(const ClipboardData(text: repoUrl));
|
||||
messenger?.showSnackBar(
|
||||
const SnackBar(content: Text('Could not open a browser — link copied')));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return PageScroll(
|
||||
maxWidth: 680,
|
||||
children: [
|
||||
const PageTitle('About'),
|
||||
Panel(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(appName, style: t.titleLarge),
|
||||
const SizedBox(height: 4),
|
||||
SelectableText('Version $appVersion',
|
||||
style: t.bodyMedium?.copyWith(color: Colors.grey)),
|
||||
const SizedBox(height: 4),
|
||||
UpdateStatusLine(controller: updates),
|
||||
const SizedBox(height: kGap),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: SelectableText(repoUrl, style: t.bodySmall)),
|
||||
IconButton(
|
||||
tooltip: 'Copy link',
|
||||
icon: const Icon(Icons.copy, size: 18),
|
||||
onPressed: () =>
|
||||
Clipboard.setData(const ClipboardData(text: repoUrl)),
|
||||
),
|
||||
FilledButton.tonalIcon(
|
||||
onPressed: () => _open(context),
|
||||
icon: const Icon(Icons.open_in_new, size: 18),
|
||||
label: const Text('Source'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:sync_relay_core/core.dart' show HelloMedia;
|
||||
|
||||
import '../../session/session_coordinator.dart';
|
||||
import '../../state/session_state.dart';
|
||||
import '../../widgets/avatar_pipeline.dart';
|
||||
import '../../widgets/media_input.dart';
|
||||
|
||||
/// What a card shows under its fields after a failed attempt.
|
||||
class CardError {
|
||||
final String title;
|
||||
final String message;
|
||||
const CardError(this.title, this.message);
|
||||
}
|
||||
|
||||
/// Host/Join submit state for the two Home cards. One attempt at a time;
|
||||
/// [cancel] abandons it via [SessionState.cancelPending].
|
||||
class ConnectFlow extends ChangeNotifier {
|
||||
ConnectFlow({SessionState? session}) : _session = session ?? SessionState.instance;
|
||||
final SessionState _session;
|
||||
|
||||
ConnectMode? busy;
|
||||
final errors = <ConnectMode, CardError?>{};
|
||||
final notices = <ConnectMode, String?>{};
|
||||
int _attempt = 0;
|
||||
bool _disposed = false;
|
||||
|
||||
/// Set when an attempt ends in a kick, so Home shows the removal dialog.
|
||||
void Function(String reason)? onKicked;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_disposed = true;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _notify() {
|
||||
if (!_disposed) notifyListeners();
|
||||
}
|
||||
|
||||
void showError(ConnectMode mode, CardError error) {
|
||||
errors[mode] = error;
|
||||
notices[mode] = null;
|
||||
_notify();
|
||||
}
|
||||
|
||||
void clearError(ConnectMode mode) {
|
||||
if (errors[mode] == null && notices[mode] == null) return;
|
||||
errors[mode] = null;
|
||||
notices[mode] = null;
|
||||
_notify();
|
||||
}
|
||||
|
||||
/// Validates and builds the params; throws [FormatException] with a
|
||||
/// user-facing message.
|
||||
static Future<ConnectParams> buildParams(ConnectMode mode, ConnectForm f) async {
|
||||
final rawPort = mode == ConnectMode.host ? f.hostPort : f.port;
|
||||
final port = int.tryParse(rawPort.trim());
|
||||
if (port == null || port <= 0 || port > 65535) {
|
||||
throw const FormatException('port must be 1–65535');
|
||||
}
|
||||
if (f.name.trim().isEmpty) {
|
||||
throw const FormatException('set your display name first (click your profile at the top)');
|
||||
}
|
||||
if (mode == ConnectMode.join && f.host.trim().isEmpty) {
|
||||
throw const FormatException('enter the server address');
|
||||
}
|
||||
String avatar = '';
|
||||
try {
|
||||
avatar = await encodeAvatar(f.avatarPath);
|
||||
} on FormatException catch (e) {
|
||||
throw FormatException(e.message);
|
||||
} catch (_) {
|
||||
throw const FormatException('could not process that avatar — pick a PNG, JPG or WebP photo');
|
||||
}
|
||||
if (mode == ConnectMode.host &&
|
||||
f.mediaPath.isNotEmpty &&
|
||||
!await File(f.mediaPath).exists()) {
|
||||
throw const FormatException('media file not found — check the path or pick again with Browse');
|
||||
}
|
||||
return ConnectParams(
|
||||
host: f.host.trim(),
|
||||
port: port,
|
||||
secret: mode == ConnectMode.host ? f.hostSecret : f.secret,
|
||||
name: f.name.trim(),
|
||||
avatar: avatar,
|
||||
mediaPath: mode == ConnectMode.host ? f.mediaPath : '',
|
||||
linkUrl: mode == ConnectMode.host ? f.linkUrl : '',
|
||||
);
|
||||
}
|
||||
|
||||
/// [edit] fills the card's fields into a copy of the last form, so the
|
||||
/// other card's saved values survive. [media] (host only) is put up
|
||||
/// instead of the form's link or file (a Jellyfin ref; the pick itself is
|
||||
/// remembered in the Jellyfin box, not the form).
|
||||
Future<void> submit(ConnectMode mode, void Function(ConnectForm f) edit,
|
||||
{HelloMedia? media}) async {
|
||||
if (busy != null) return;
|
||||
final myAttempt = ++_attempt;
|
||||
final form = _session.lastForm.copy();
|
||||
edit(form);
|
||||
form.name = form.name.trim();
|
||||
form.host = form.host.trim();
|
||||
if (mode == ConnectMode.host) {
|
||||
final parsed = parseMediaInput(form.linkUrl.isNotEmpty ? form.linkUrl : form.mediaPath);
|
||||
form
|
||||
..mediaPath = parsed.mediaPath
|
||||
..linkUrl = parsed.linkUrl;
|
||||
}
|
||||
busy = mode;
|
||||
errors[mode] = null;
|
||||
notices[mode] = null;
|
||||
_notify();
|
||||
|
||||
ConnectParams params;
|
||||
try {
|
||||
params = await buildParams(mode, form);
|
||||
if (media != null && mode == ConnectMode.host) params = params.withMedia(media);
|
||||
} catch (e) {
|
||||
if (myAttempt != _attempt) return;
|
||||
busy = null;
|
||||
errors[mode] = CardError('Check the form',
|
||||
e is FormatException ? e.message : 'check the form and try again');
|
||||
_notify();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (mode == ConnectMode.host) {
|
||||
await _session.host(params, form);
|
||||
} else {
|
||||
await _session.join(params, form);
|
||||
}
|
||||
} catch (e) {
|
||||
if (myAttempt != _attempt) return;
|
||||
busy = null;
|
||||
final kick = _session.coordinator.kickReason.peek();
|
||||
if (kick != null && kick.isNotEmpty) {
|
||||
onKicked?.call(kick);
|
||||
} else {
|
||||
errors[mode] = CardError('Could not connect', '$e');
|
||||
}
|
||||
_notify();
|
||||
return;
|
||||
}
|
||||
if (myAttempt != _attempt) {
|
||||
// Cancelled after it got through: back out.
|
||||
try {
|
||||
await _session.leave();
|
||||
await _session.stopServer();
|
||||
} catch (_) {}
|
||||
return;
|
||||
}
|
||||
busy = null;
|
||||
_notify();
|
||||
await _session.rememberServer(RecentServer(
|
||||
hosted: mode == ConnectMode.host,
|
||||
host: mode == ConnectMode.host ? '' : form.host,
|
||||
port: mode == ConnectMode.host ? form.hostPort.trim() : form.port.trim(),
|
||||
secret: mode == ConnectMode.host ? form.hostSecret : form.secret,
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> cancel() async {
|
||||
final mode = busy;
|
||||
_attempt++;
|
||||
try {
|
||||
await _session.cancelPending();
|
||||
} catch (_) {}
|
||||
busy = null;
|
||||
if (mode != null) notices[mode] = 'Cancelled';
|
||||
_notify();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../state/session_state.dart';
|
||||
import 'connect_flow.dart';
|
||||
import 'ui.dart';
|
||||
|
||||
/// The submit button for one [ConnectMode], swapped for a progress bar and
|
||||
/// Cancel while that attempt runs. Disabled while the other mode is busy.
|
||||
class ConnectButton extends StatelessWidget {
|
||||
final ConnectFlow flow;
|
||||
final ConnectMode mode;
|
||||
final String label;
|
||||
final VoidCallback onSubmit;
|
||||
final bool expand;
|
||||
const ConnectButton({
|
||||
super.key,
|
||||
required this.flow,
|
||||
required this.mode,
|
||||
required this.label,
|
||||
required this.onSubmit,
|
||||
this.expand = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final busyHere = flow.busy == mode;
|
||||
if (busyHere) {
|
||||
return SizedBox(
|
||||
width: expand ? null : 220,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const LinearProgressIndicator(),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(mode == ConnectMode.host ? 'Starting server…' : 'Connecting…',
|
||||
style: Theme.of(context).textTheme.bodySmall),
|
||||
),
|
||||
TextButton(onPressed: flow.cancel, child: const Text('Cancel')),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
final button = FilledButton(
|
||||
onPressed: flow.busy != null ? null : onSubmit,
|
||||
child: Text(label),
|
||||
);
|
||||
return expand ? SizedBox(width: double.infinity, child: button) : button;
|
||||
}
|
||||
}
|
||||
|
||||
/// Last error or notice for [mode], or nothing.
|
||||
class ConnectFeedback extends StatelessWidget {
|
||||
final ConnectFlow flow;
|
||||
final ConnectMode mode;
|
||||
const ConnectFeedback({super.key, required this.flow, required this.mode});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final error = flow.errors[mode];
|
||||
final notice = flow.notices[mode];
|
||||
if (error != null) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: ErrorBox(title: error.title, message: error.message),
|
||||
);
|
||||
}
|
||||
if (notice != null) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: Text(notice,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Colors.grey)),
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
/// Fetches a URL body; injectable so tests fake the server's `/health`.
|
||||
typedef HealthGetter = Future<String> Function(Uri uri);
|
||||
|
||||
const healthPollEvery = Duration(seconds: 10);
|
||||
const _timeout = Duration(seconds: 4);
|
||||
|
||||
/// What a recent-server tile shows: unknown until the first probe answers.
|
||||
class ServerHealth {
|
||||
final bool online;
|
||||
final String name;
|
||||
final int? proto;
|
||||
final int viewers;
|
||||
const ServerHealth.offline()
|
||||
: online = false,
|
||||
name = '',
|
||||
proto = null,
|
||||
viewers = 0;
|
||||
const ServerHealth.online({required this.name, this.proto, this.viewers = 0})
|
||||
: online = true;
|
||||
|
||||
/// True when the server speaks another protocol than this build.
|
||||
bool get needsUpdate =>
|
||||
online && proto != null && proto != RelayConstants.protoVersion;
|
||||
|
||||
/// Lenient parse of `GET /health`; anything unexpected reads as offline.
|
||||
static ServerHealth parse(String body) {
|
||||
try {
|
||||
final j = jsonDecode(body);
|
||||
if (j is! Map || j['ok'] != true) return const ServerHealth.offline();
|
||||
final name = j['name'], proto = j['proto'], viewers = j['viewers'];
|
||||
return ServerHealth.online(
|
||||
name: name is String ? name.trim() : '',
|
||||
proto: proto is num ? proto.toInt() : null,
|
||||
viewers: viewers is num ? viewers.toInt() : 0,
|
||||
);
|
||||
} catch (_) {
|
||||
return const ServerHealth.offline();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Uri healthUri(String host, String port) {
|
||||
final h = host.trim();
|
||||
// Bare IPv6 literals need brackets in a URL.
|
||||
final authority = h.contains(':') && !h.startsWith('[') ? '[$h]' : h;
|
||||
return Uri.parse('http://$authority:${port.trim()}/health');
|
||||
}
|
||||
|
||||
Future<ServerHealth> probeHealth(String host, String port, HealthGetter get) async {
|
||||
try {
|
||||
return ServerHealth.parse(await get(healthUri(host, port)).timeout(_timeout));
|
||||
} catch (_) {
|
||||
return const ServerHealth.offline();
|
||||
}
|
||||
}
|
||||
|
||||
/// Plain dart:io GET; non-200 throws.
|
||||
Future<String> defaultHealthGet(Uri uri) async {
|
||||
final client = HttpClient()..connectionTimeout = _timeout;
|
||||
try {
|
||||
final req = await client.getUrl(uri);
|
||||
final res = await req.close().timeout(_timeout);
|
||||
if (res.statusCode != 200) {
|
||||
await res.drain<void>();
|
||||
throw HttpException('status ${res.statusCode}', uri: uri);
|
||||
}
|
||||
return await res.transform(utf8.decoder).join().timeout(_timeout);
|
||||
} finally {
|
||||
client.close(force: true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
|
||||
import '../../jellyfin/accounts.dart';
|
||||
import '../../state/session_state.dart';
|
||||
import '../../state/settings.dart';
|
||||
import '../../update/update_controller.dart';
|
||||
import 'about_page.dart';
|
||||
import 'connect_flow.dart';
|
||||
import 'health_probe.dart';
|
||||
import 'host_tab.dart';
|
||||
import 'integrations_page.dart';
|
||||
import 'join_tab.dart';
|
||||
import 'profile.dart';
|
||||
import 'settings_page.dart';
|
||||
import 'top_bar.dart';
|
||||
import 'update_indicator.dart';
|
||||
|
||||
/// Everything outside a session: one top bar (profile, Join/Host tabs,
|
||||
/// Settings/Integrations/About, window buttons) over a full-width body.
|
||||
class HomeScreen extends StatelessWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Scaffold(body: HomeShell(windowControls: true));
|
||||
}
|
||||
}
|
||||
|
||||
/// [HomeScreen]'s content. Tests pump it with [windowControls] off (the
|
||||
/// drag area and window buttons need window_manager) and a fake [healthGet].
|
||||
class HomeShell extends StatefulWidget {
|
||||
final UpdateController? updates;
|
||||
final bool autoUpdateCheck;
|
||||
final bool windowControls;
|
||||
final HealthGetter healthGet;
|
||||
/// Linked Jellyfin servers; defaults to [JellyfinAccounts.instance].
|
||||
final JellyfinAccounts? jellyfin;
|
||||
const HomeShell({
|
||||
super.key,
|
||||
this.updates,
|
||||
this.autoUpdateCheck = true,
|
||||
this.windowControls = false,
|
||||
this.healthGet = defaultHealthGet,
|
||||
this.jellyfin,
|
||||
});
|
||||
|
||||
@override
|
||||
State<HomeShell> createState() => _HomeShellState();
|
||||
}
|
||||
|
||||
class _HomeShellState extends State<HomeShell> {
|
||||
HomeView _view = HomeView.join;
|
||||
final _flow = ConnectFlow();
|
||||
late final _join = JoinFields(SessionState.instance.lastForm);
|
||||
late final _jellyfin = widget.jellyfin ?? JellyfinAccounts.instance;
|
||||
late final _host = HostFields(SessionState.instance.lastForm, jellyfin: _jellyfin);
|
||||
late final void Function() _stopKickWatch;
|
||||
late final void Function() _stopCrashWatch;
|
||||
bool _dialogOpen = false;
|
||||
String? _lastKickShown;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Profile.instance.ensureLoaded();
|
||||
// Reads linked servers and checks their tokens in the background.
|
||||
_jellyfin.ensureLoaded();
|
||||
if (widget.autoUpdateCheck) _autoCheck();
|
||||
_flow.onKicked = _showKickedDialog;
|
||||
// Back from a session that ended in a kick: say so.
|
||||
_stopKickWatch = effect(() {
|
||||
final kick = SessionState.instance.coordinator.kickReason.value;
|
||||
if (kick == null || kick.isEmpty) {
|
||||
_lastKickShown = null;
|
||||
return;
|
||||
}
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _showKickedDialog(kick));
|
||||
});
|
||||
// Back from a session whose hosted server crashed: say so on the Host tab.
|
||||
_stopCrashWatch = effect(() {
|
||||
final crash = SessionState.instance.serverCrash.value;
|
||||
if (crash == null) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
SessionState.instance.serverCrash.value = null;
|
||||
if (!mounted) return;
|
||||
_flow.showError(ConnectMode.host, CardError('Server crashed', crash));
|
||||
setState(() => _view = HomeView.host);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_stopKickWatch();
|
||||
_stopCrashWatch();
|
||||
_flow.dispose();
|
||||
_join.dispose();
|
||||
_host.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _autoCheck() async {
|
||||
final s = AppSettings.instance;
|
||||
await s.ensureLoaded();
|
||||
if (s.autoCheckUpdates.peek()) await runUpdateCheck(widget.updates);
|
||||
}
|
||||
|
||||
Future<void> _showKickedDialog(String reason) async {
|
||||
if (!mounted || _dialogOpen || reason == _lastKickShown) return;
|
||||
_lastKickShown = reason;
|
||||
_dialogOpen = true;
|
||||
try {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('You were removed'),
|
||||
content: Text(reason.isEmpty ? 'The host removed you from the server.' : reason),
|
||||
actions: [TextButton(onPressed: () => Navigator.pop(context), child: const Text('OK'))],
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
_dialogOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
void _select(HomeView v) => setState(() => _view = v);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
// Only the visible view is mounted: the Join tab polls /health only
|
||||
// while shown. Form state lives here, so nothing is lost on switch.
|
||||
final body = switch (_view) {
|
||||
HomeView.join =>
|
||||
JoinTab(flow: _flow, fields: _join, healthGet: widget.healthGet),
|
||||
HomeView.host => HostTab(
|
||||
flow: _flow,
|
||||
fields: _host,
|
||||
onOpenIntegrations: () => _select(HomeView.integrations),
|
||||
),
|
||||
HomeView.settings => SettingsPage(updates: widget.updates),
|
||||
HomeView.integrations => IntegrationsPage(jellyfin: _jellyfin),
|
||||
HomeView.about => AboutPage(updates: widget.updates),
|
||||
};
|
||||
return CallbackShortcuts(
|
||||
bindings: {
|
||||
const SingleActivator(LogicalKeyboardKey.digit1, control: true): () =>
|
||||
_select(HomeView.join),
|
||||
const SingleActivator(LogicalKeyboardKey.digit2, control: true): () =>
|
||||
_select(HomeView.host),
|
||||
const SingleActivator(LogicalKeyboardKey.comma, control: true): () =>
|
||||
_select(HomeView.settings),
|
||||
},
|
||||
child: FocusScope(
|
||||
autofocus: true,
|
||||
child: Column(
|
||||
children: [
|
||||
HomeTopBar(
|
||||
view: _view,
|
||||
onSelect: _select,
|
||||
updates: widget.updates,
|
||||
windowControls: widget.windowControls,
|
||||
),
|
||||
Divider(height: 1, thickness: 1, color: scheme.outlineVariant.withValues(alpha: 0.4)),
|
||||
Expanded(
|
||||
child: KeyedSubtree(key: ValueKey(_view), child: body),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
import 'package:sync_relay_core/core.dart' show HelloMedia;
|
||||
|
||||
import '../../jellyfin/accounts.dart';
|
||||
import '../../jellyfin/session_media.dart';
|
||||
import '../../state/session_state.dart';
|
||||
import 'connect_flow.dart';
|
||||
import 'connect_status.dart';
|
||||
import 'media_picker.dart';
|
||||
import 'ui.dart';
|
||||
|
||||
/// Host form state, owned by the Home shell so it survives tab switches.
|
||||
class HostFields {
|
||||
HostFields(ConnectForm f, {JellyfinAccounts? jellyfin})
|
||||
: jellyfin = jellyfin ?? JellyfinAccounts.instance,
|
||||
port = TextEditingController(text: f.hostPort),
|
||||
secret = TextEditingController(text: f.hostSecret),
|
||||
media = MediaPickerController(mediaPath: f.mediaPath, linkUrl: f.linkUrl) {
|
||||
// The last Jellyfin pick lives in the Jellyfin box (the connect form
|
||||
// only knows links and files); restore it once that box is read.
|
||||
final noMedia = f.mediaPath.isEmpty && f.linkUrl.isEmpty;
|
||||
this.jellyfin.ensureLoaded().then((_) {
|
||||
final pick = this.jellyfin.lastPick;
|
||||
if (_disposed || pick == null || media.jellyfin != null) return;
|
||||
if (this.jellyfin.account(pick.serverId) == null) return;
|
||||
if (noMedia) {
|
||||
media.pickJellyfin(pick);
|
||||
} else {
|
||||
final source = media.source;
|
||||
media.pickJellyfin(pick);
|
||||
media.source = source;
|
||||
}
|
||||
});
|
||||
}
|
||||
final JellyfinAccounts jellyfin;
|
||||
final TextEditingController port;
|
||||
final TextEditingController secret;
|
||||
final MediaPickerController media;
|
||||
/// Jellyfin browser enlarged: the server column shrinks to a bar.
|
||||
final browserExpanded = ValueNotifier(false);
|
||||
bool _disposed = false;
|
||||
|
||||
void dispose() {
|
||||
_disposed = true;
|
||||
port.dispose();
|
||||
secret.dispose();
|
||||
media.dispose();
|
||||
browserExpanded.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// What hosting a picked Jellyfin item sends: its ref (no URL, no token).
|
||||
/// Throws [FormatException] with a user-facing message when the server is
|
||||
/// not linked any more or its sign-in expired.
|
||||
HelloMedia hostJellyfinMedia(JellyfinAccounts accounts, JellyfinMedia media) {
|
||||
if (accounts.account(media.serverId) == null) {
|
||||
throw const FormatException('that Jellyfin server is not linked any more — pick again');
|
||||
}
|
||||
if (accounts.statusOf(media.serverId) == JellyfinAccountStatus.expired) {
|
||||
throw const FormatException('Jellyfin sign-in expired — reconnect it in Integrations');
|
||||
}
|
||||
return mediaForPick(media);
|
||||
}
|
||||
|
||||
/// Below this width the server column moves under the media picker.
|
||||
const hostStackBelow = 860.0;
|
||||
const _columnWidth = 340.0;
|
||||
|
||||
/// Media picker as the main area; port/password/Host in a narrow column.
|
||||
class HostTab extends StatelessWidget {
|
||||
final ConnectFlow flow;
|
||||
final HostFields fields;
|
||||
final VoidCallback? onOpenIntegrations;
|
||||
const HostTab(
|
||||
{super.key, required this.flow, required this.fields, this.onOpenIntegrations});
|
||||
|
||||
void _host() {
|
||||
if (flow.busy != null) return;
|
||||
final media = fields.media.selection;
|
||||
HelloMedia? jellyfinMedia;
|
||||
if (media is JellyfinMedia) {
|
||||
try {
|
||||
jellyfinMedia = hostJellyfinMedia(fields.jellyfin, media);
|
||||
} on FormatException catch (e) {
|
||||
flow.showError(ConnectMode.host, CardError('Check the form', e.message));
|
||||
return;
|
||||
}
|
||||
fields.jellyfin.rememberPick(media);
|
||||
}
|
||||
flow.submit(
|
||||
ConnectMode.host,
|
||||
(f) => f
|
||||
..hostPort = fields.port.text.trim()
|
||||
..hostSecret = fields.secret.text
|
||||
..mediaPath = media is FileMedia ? media.path : ''
|
||||
..linkUrl = media is LinkMedia ? media.url : '',
|
||||
media: jellyfinMedia,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return ListenableBuilder(
|
||||
listenable: Listenable.merge([flow, fields.media, fields.browserExpanded]),
|
||||
builder: (context, _) {
|
||||
final busy = flow.busy == ConnectMode.host;
|
||||
final jellyfin = fields.media.source == MediaKind.jellyfin;
|
||||
final expanded = jellyfin && fields.browserExpanded.value;
|
||||
Widget picker({required bool fill}) {
|
||||
final p = MediaPicker(
|
||||
controller: fields.media,
|
||||
enabled: !busy,
|
||||
autofocus: true,
|
||||
onSubmit: _host,
|
||||
onOpenIntegrations: onOpenIntegrations,
|
||||
jellyfin: fields.jellyfin,
|
||||
expanded: expanded,
|
||||
onToggleExpanded: () => fields.browserExpanded.value = !fields.browserExpanded.value,
|
||||
);
|
||||
return Column(
|
||||
key: const ValueKey('host-picker'),
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text('What to watch', style: t.titleMedium),
|
||||
const SizedBox(height: 12),
|
||||
fill ? Expanded(child: p) : p,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
final column = _ServerColumn(flow: flow, fields: fields, onHost: _host);
|
||||
return LayoutBuilder(builder: (context, box) {
|
||||
final stacked = box.maxWidth < hostStackBelow;
|
||||
// Jellyfin browser: fills the height (lazy grids need a bounded
|
||||
// viewport); the form sits beside it or, enlarged, in a bar below.
|
||||
if (expanded) {
|
||||
return Padding(
|
||||
padding: kPagePadding,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Expanded(child: picker(fill: true)),
|
||||
const SizedBox(height: 12),
|
||||
_HostBar(flow: flow, fields: fields, onHost: _host),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
if (jellyfin && !stacked) {
|
||||
return Padding(
|
||||
padding: kPagePadding,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Expanded(child: picker(fill: true)),
|
||||
const SizedBox(width: 24),
|
||||
SizedBox(
|
||||
width: _columnWidth,
|
||||
child: SingleChildScrollView(child: column),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return SingleChildScrollView(
|
||||
padding: kPagePadding,
|
||||
child: stacked
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
picker(fill: false),
|
||||
const SizedBox(height: 24),
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: kFieldMaxWidth),
|
||||
child: column,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: picker(fill: false)),
|
||||
const SizedBox(width: 24),
|
||||
SizedBox(width: _columnWidth, child: column),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ServerColumn extends StatelessWidget {
|
||||
final ConnectFlow flow;
|
||||
final HostFields fields;
|
||||
final VoidCallback onHost;
|
||||
const _ServerColumn({required this.flow, required this.fields, required this.onHost});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final t = theme.textTheme;
|
||||
return Panel(
|
||||
key: const ValueKey('host-column'),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.cast, size: 20, color: theme.colorScheme.primary),
|
||||
const SizedBox(width: 10),
|
||||
Text('Your server', style: t.titleMedium),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text('Runs on this computer. Friends need this port reachable.',
|
||||
style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
const SizedBox(height: kGap),
|
||||
AbsorbPointer(
|
||||
absorbing: flow.busy == ConnectMode.host,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
spacing: 12,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: SizedBox(
|
||||
width: 120,
|
||||
child: TextField(
|
||||
key: const ValueKey('host-port'),
|
||||
controller: fields.port,
|
||||
decoration: fieldDecoration('Port'),
|
||||
keyboardType: TextInputType.number,
|
||||
onChanged: (_) => flow.clearError(ConnectMode.host),
|
||||
onSubmitted: (_) => onHost(),
|
||||
),
|
||||
),
|
||||
),
|
||||
ListenableBuilder(
|
||||
listenable: fields.secret,
|
||||
builder: (context, _) => TextField(
|
||||
key: const ValueKey('host-password'),
|
||||
controller: fields.secret,
|
||||
obscureText: true,
|
||||
decoration: fieldDecoration('Password').copyWith(
|
||||
helperText:
|
||||
fields.secret.text.isEmpty ? 'No password — anyone can join' : null,
|
||||
),
|
||||
onSubmitted: (_) => onHost(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
ListenableBuilder(
|
||||
listenable: fields.media,
|
||||
builder: (context, _) => Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: Text(mediaSummary(fields.media.selection),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
),
|
||||
),
|
||||
ConnectFeedback(flow: flow, mode: ConnectMode.host),
|
||||
const SizedBox(height: kGap),
|
||||
ConnectButton(
|
||||
flow: flow, mode: ConnectMode.host, label: 'Host', onSubmit: onHost, expand: true),
|
||||
_HostedRecents(fields: fields, enabled: flow.busy == null),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
String mediaSummary(PickedMedia? s) =>
|
||||
s == null ? 'No media selected (optional).' : 'Playing: ${s.label}';
|
||||
|
||||
/// Enlarged-browser mode: what is picked, port, password and Host in one
|
||||
/// row under the browser.
|
||||
class _HostBar extends StatelessWidget {
|
||||
final ConnectFlow flow;
|
||||
final HostFields fields;
|
||||
final VoidCallback onHost;
|
||||
const _HostBar({required this.flow, required this.fields, required this.onHost});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return Panel(
|
||||
key: const ValueKey('host-bar'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.cast, size: 20, color: Theme.of(context).colorScheme.primary),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(mediaSummary(fields.media.selection),
|
||||
maxLines: 1, overflow: TextOverflow.ellipsis, style: t.bodyMedium),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
AbsorbPointer(
|
||||
absorbing: flow.busy == ConnectMode.host,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 100,
|
||||
child: TextField(
|
||||
controller: fields.port,
|
||||
decoration: fieldDecoration('Port'),
|
||||
keyboardType: TextInputType.number,
|
||||
onChanged: (_) => flow.clearError(ConnectMode.host),
|
||||
onSubmitted: (_) => onHost(),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: TextField(
|
||||
controller: fields.secret,
|
||||
obscureText: true,
|
||||
decoration: fieldDecoration('Password', hint: 'none = open'),
|
||||
onSubmitted: (_) => onHost(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
ConnectButton(flow: flow, mode: ConnectMode.host, label: 'Host', onSubmit: onHost),
|
||||
],
|
||||
),
|
||||
ConnectFeedback(flow: flow, mode: ConnectMode.host),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Ports hosted before: one click refills port and password.
|
||||
class _HostedRecents extends StatelessWidget {
|
||||
final HostFields fields;
|
||||
final bool enabled;
|
||||
const _HostedRecents({required this.fields, required this.enabled});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SignalBuilder(builder: (context) {
|
||||
final list = [
|
||||
for (final r in SessionState.instance.recents.value)
|
||||
if (r.hosted) r
|
||||
];
|
||||
if (list.isEmpty) return const SizedBox.shrink();
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: kGap),
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
for (final r in list)
|
||||
InputChip(
|
||||
key: ValueKey('recent-${r.key}'),
|
||||
avatar: Icon(r.secret.isEmpty ? Icons.history : Icons.lock_outline, size: 16),
|
||||
label: Text('Port ${r.port}'),
|
||||
tooltip: 'Use port ${r.port} again',
|
||||
isEnabled: enabled,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
onPressed: () {
|
||||
fields.port.text = r.port;
|
||||
fields.secret.text = r.secret;
|
||||
},
|
||||
deleteButtonTooltipMessage: 'Forget',
|
||||
onDeleted: () => SessionState.instance.forgetServer(r),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../jellyfin/accounts.dart';
|
||||
import '../../jellyfin/accounts_panel.dart';
|
||||
import 'ui.dart';
|
||||
|
||||
class IntegrationsPage extends StatelessWidget {
|
||||
/// Defaults to [JellyfinAccounts.instance].
|
||||
final JellyfinAccounts? jellyfin;
|
||||
const IntegrationsPage({super.key, this.jellyfin});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PageScroll(
|
||||
maxWidth: 820,
|
||||
children: [
|
||||
const PageTitle('Integrations',
|
||||
subtitle: 'Connect media libraries to pick what to watch.'),
|
||||
JellyfinAccountsPanel(accounts: jellyfin ?? JellyfinAccounts.instance),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import '../../state/session_state.dart';
|
||||
import 'connect_flow.dart';
|
||||
import 'connect_status.dart';
|
||||
import 'health_probe.dart';
|
||||
import 'ui.dart';
|
||||
|
||||
/// Join form text, owned by the Home shell so it survives tab switches.
|
||||
class JoinFields {
|
||||
JoinFields(ConnectForm f)
|
||||
: host = TextEditingController(text: f.host),
|
||||
port = TextEditingController(text: f.port),
|
||||
secret = TextEditingController(text: f.secret);
|
||||
final TextEditingController host;
|
||||
final TextEditingController port;
|
||||
final TextEditingController secret;
|
||||
|
||||
void dispose() {
|
||||
host.dispose();
|
||||
port.dispose();
|
||||
secret.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// Smallest recent-server tile; the grid adds columns as the window widens.
|
||||
const _minTileWidth = 300.0;
|
||||
|
||||
/// One compact address/port/password row, then recent servers with live
|
||||
/// status, as a grid that fills the width.
|
||||
class JoinTab extends StatelessWidget {
|
||||
final ConnectFlow flow;
|
||||
final JoinFields fields;
|
||||
final HealthGetter healthGet;
|
||||
const JoinTab(
|
||||
{super.key, required this.flow, required this.fields, required this.healthGet});
|
||||
|
||||
void _join() => flow.submit(ConnectMode.join, (f) {
|
||||
f
|
||||
..host = fields.host.text
|
||||
..port = fields.port.text.trim()
|
||||
..secret = fields.secret.text;
|
||||
});
|
||||
|
||||
void _joinRecent(RecentServer r) {
|
||||
fields.host.text = r.host;
|
||||
fields.port.text = r.port;
|
||||
fields.secret.text = r.secret;
|
||||
_join();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return ListenableBuilder(
|
||||
listenable: flow,
|
||||
builder: (context, _) => SingleChildScrollView(
|
||||
padding: kPagePadding,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text('Join a friend’s server', style: t.titleMedium),
|
||||
const SizedBox(height: 12),
|
||||
AbsorbPointer(
|
||||
absorbing: flow.busy == ConnectMode.join,
|
||||
child: _joinRow(),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: kFieldMaxWidth),
|
||||
child: ConnectFeedback(flow: flow, mode: ConnectMode.join),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
Text('Recent servers', style: t.titleMedium),
|
||||
const SizedBox(height: 12),
|
||||
SignalBuilder(builder: (context) {
|
||||
final list = [
|
||||
for (final r in SessionState.instance.recents.value)
|
||||
if (!r.hosted) r
|
||||
];
|
||||
return RecentServersGrid(
|
||||
servers: list,
|
||||
enabled: flow.busy == null,
|
||||
healthGet: healthGet,
|
||||
onJoin: _joinRecent,
|
||||
onForget: SessionState.instance.forgetServer,
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _joinRow() {
|
||||
return Wrap(
|
||||
key: const ValueKey('join-row'),
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 280,
|
||||
child: TextField(
|
||||
key: const ValueKey('join-address'),
|
||||
controller: fields.host,
|
||||
decoration: fieldDecoration('Address', hint: 'IP or hostname'),
|
||||
onChanged: (_) => flow.clearError(ConnectMode.join),
|
||||
onSubmitted: (_) => _join(),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 6),
|
||||
child: Text(':', style: TextStyle(fontSize: 18, color: Colors.grey)),
|
||||
),
|
||||
SizedBox(
|
||||
width: 96,
|
||||
child: TextField(
|
||||
key: const ValueKey('join-port'),
|
||||
controller: fields.port,
|
||||
decoration: fieldDecoration('Port'),
|
||||
keyboardType: TextInputType.number,
|
||||
onSubmitted: (_) => _join(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
width: 220,
|
||||
child: TextField(
|
||||
key: const ValueKey('join-password'),
|
||||
controller: fields.secret,
|
||||
obscureText: true,
|
||||
decoration: fieldDecoration('Password', hint: 'If the server has one'),
|
||||
onSubmitted: (_) => _join(),
|
||||
),
|
||||
),
|
||||
ConnectButton(flow: flow, mode: ConnectMode.join, label: 'Join', onSubmit: _join),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Recent servers as tiles; polls each one's `/health` every
|
||||
/// [healthPollEvery] while mounted (i.e. while the Join tab is visible).
|
||||
class RecentServersGrid extends StatefulWidget {
|
||||
final List<RecentServer> servers;
|
||||
final bool enabled;
|
||||
final HealthGetter healthGet;
|
||||
final ValueChanged<RecentServer> onJoin;
|
||||
final ValueChanged<RecentServer> onForget;
|
||||
const RecentServersGrid({
|
||||
super.key,
|
||||
required this.servers,
|
||||
required this.enabled,
|
||||
required this.healthGet,
|
||||
required this.onJoin,
|
||||
required this.onForget,
|
||||
});
|
||||
|
||||
@override
|
||||
State<RecentServersGrid> createState() => _RecentServersGridState();
|
||||
}
|
||||
|
||||
class _RecentServersGridState extends State<RecentServersGrid> {
|
||||
final _health = <String, ServerHealth>{};
|
||||
final _inFlight = <String>{};
|
||||
Timer? _timer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_pollAll();
|
||||
_timer = Timer.periodic(healthPollEvery, (_) => _pollAll());
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(RecentServersGrid old) {
|
||||
super.didUpdateWidget(old);
|
||||
for (final r in widget.servers) {
|
||||
if (!_health.containsKey(r.key)) _poll(r);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _pollAll() {
|
||||
for (final r in widget.servers) {
|
||||
_poll(r);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _poll(RecentServer r) async {
|
||||
if (!_inFlight.add(r.key)) return;
|
||||
try {
|
||||
final h = await probeHealth(r.host, r.port, widget.healthGet);
|
||||
if (mounted) setState(() => _health[r.key] = h);
|
||||
} finally {
|
||||
_inFlight.remove(r.key);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (widget.servers.isEmpty) return const _EmptyRecents();
|
||||
return LayoutBuilder(builder: (context, box) {
|
||||
final cols = ((box.maxWidth + kGap) / (_minTileWidth + kGap)).floor().clamp(1, 64);
|
||||
final width = (box.maxWidth - kGap * (cols - 1)) / cols;
|
||||
return Wrap(
|
||||
spacing: kGap,
|
||||
runSpacing: kGap,
|
||||
children: [
|
||||
for (final r in widget.servers)
|
||||
SizedBox(
|
||||
width: width,
|
||||
child: _RecentTile(
|
||||
key: ValueKey('recent-${r.key}'),
|
||||
server: r,
|
||||
health: _health[r.key],
|
||||
enabled: widget.enabled,
|
||||
onJoin: () => widget.onJoin(r),
|
||||
onForget: () => widget.onForget(r),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _RecentTile extends StatelessWidget {
|
||||
final RecentServer server;
|
||||
/// Null until the first probe answers.
|
||||
final ServerHealth? health;
|
||||
final bool enabled;
|
||||
final VoidCallback onJoin;
|
||||
final VoidCallback onForget;
|
||||
const _RecentTile({
|
||||
super.key,
|
||||
required this.server,
|
||||
required this.health,
|
||||
required this.enabled,
|
||||
required this.onJoin,
|
||||
required this.onForget,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final scheme = theme.colorScheme;
|
||||
final t = theme.textTheme;
|
||||
final h = health;
|
||||
final address = '${server.host}:${server.port}';
|
||||
final title = h != null && h.name.isNotEmpty ? h.name : server.host;
|
||||
final (status, statusColor) = switch (h) {
|
||||
null => ('Checking…', Colors.grey),
|
||||
ServerHealth(online: true) => (
|
||||
'● online · ${h.viewers} watching',
|
||||
Colors.greenAccent.shade400
|
||||
),
|
||||
_ => ('○ offline', Colors.grey),
|
||||
};
|
||||
return Material(
|
||||
color: scheme.surfaceContainer,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(kRadius),
|
||||
side: BorderSide(color: scheme.outlineVariant.withValues(alpha: 0.5)),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
onTap: enabled ? onJoin : null,
|
||||
child: Tooltip(
|
||||
message: 'Join $address',
|
||||
waitDuration: const Duration(milliseconds: 600),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 10, 6, 14),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.dns_outlined, size: 20, color: scheme.primary),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(title,
|
||||
maxLines: 1, overflow: TextOverflow.ellipsis, style: t.titleMedium),
|
||||
),
|
||||
if (server.secret.isNotEmpty)
|
||||
const Tooltip(
|
||||
message: 'Password saved',
|
||||
child: Icon(Icons.lock_outline, size: 16, color: Colors.grey),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Forget',
|
||||
visualDensity: VisualDensity.compact,
|
||||
iconSize: 18,
|
||||
onPressed: onForget,
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 30, right: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(address,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(status,
|
||||
key: const ValueKey('recent-status'),
|
||||
style: t.bodyMedium?.copyWith(color: statusColor)),
|
||||
),
|
||||
if (h != null && h.needsUpdate)
|
||||
Tooltip(
|
||||
message: 'Server protocol ${h.proto}, this app '
|
||||
'${RelayConstants.protoVersion} — update so both match',
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: scheme.errorContainer,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text('needs update',
|
||||
style: t.labelSmall
|
||||
?.copyWith(color: scheme.onErrorContainer)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _EmptyRecents extends StatelessWidget {
|
||||
const _EmptyRecents();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return Panel(
|
||||
key: const ValueKey('recents-empty'),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.history, size: 28, color: Colors.grey),
|
||||
const SizedBox(width: kGap),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('No recent servers yet', style: t.titleSmall),
|
||||
const SizedBox(height: 2),
|
||||
Text('Servers you join show up here with live status; click one to rejoin.',
|
||||
style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../../jellyfin/accounts.dart';
|
||||
import '../../jellyfin/browse_scope.dart' show BrowseStart;
|
||||
import '../../jellyfin/picker_source.dart';
|
||||
import '../../widgets/media_input.dart';
|
||||
import 'picked_media.dart';
|
||||
import 'ui.dart';
|
||||
|
||||
export 'picked_media.dart';
|
||||
|
||||
const videoExtensions = ['mp4', 'mkv', 'webm', 'avi', 'mov', 'm4v', 'ts'];
|
||||
|
||||
enum MediaKind { jellyfin, link, file }
|
||||
|
||||
/// State of a [MediaPicker], owned by whoever hosts it (Home's Host tab,
|
||||
/// later the session's swap panel) so it survives rebuilds.
|
||||
class MediaPickerController extends ChangeNotifier {
|
||||
MediaPickerController(
|
||||
{String mediaPath = '', String linkUrl = '', JellyfinMedia? jellyfin, MediaKind? source})
|
||||
: link = TextEditingController(text: linkUrl),
|
||||
file = TextEditingController(text: mediaPath),
|
||||
_jellyfin = jellyfin,
|
||||
_source = source ??
|
||||
(linkUrl.isNotEmpty
|
||||
? MediaKind.link
|
||||
: mediaPath.isEmpty && jellyfin != null
|
||||
? MediaKind.jellyfin
|
||||
: MediaKind.file) {
|
||||
link.addListener(notifyListeners);
|
||||
file.addListener(notifyListeners);
|
||||
}
|
||||
|
||||
final TextEditingController link;
|
||||
final TextEditingController file;
|
||||
MediaKind _source;
|
||||
String? _notice;
|
||||
JellyfinMedia? _jellyfin;
|
||||
|
||||
/// The Jellyfin item picked in the browser (kept while another source
|
||||
/// is shown).
|
||||
JellyfinMedia? get jellyfin => _jellyfin;
|
||||
|
||||
/// Picks a Jellyfin item and switches to the Jellyfin source.
|
||||
void pickJellyfin(JellyfinMedia? media) {
|
||||
_jellyfin = media;
|
||||
_source = MediaKind.jellyfin;
|
||||
_notice = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
MediaKind get source => _source;
|
||||
set source(MediaKind v) {
|
||||
if (v == _source) return;
|
||||
_source = v;
|
||||
_notice = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// One-line hint under the fields (e.g. the file dialog failed).
|
||||
String? get notice => _notice;
|
||||
set notice(String? v) {
|
||||
_notice = v;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// What the visible source has selected; null = nothing.
|
||||
PickedMedia? get selection {
|
||||
switch (_source) {
|
||||
case MediaKind.link:
|
||||
final url = link.text.trim();
|
||||
return url.isEmpty ? null : LinkMedia(url);
|
||||
case MediaKind.file:
|
||||
final path = file.text.trim();
|
||||
return path.isEmpty ? null : FileMedia(path);
|
||||
case MediaKind.jellyfin:
|
||||
return _jellyfin;
|
||||
}
|
||||
}
|
||||
|
||||
/// Drops pasted text where it belongs: http(s) into Link, else File.
|
||||
void pasteText(String text) {
|
||||
final parsed = parseMediaInput(text);
|
||||
if (parsed.linkUrl.isNotEmpty) {
|
||||
link.text = parsed.linkUrl;
|
||||
source = MediaKind.link;
|
||||
} else if (parsed.mediaPath.isNotEmpty) {
|
||||
file.text = parsed.mediaPath;
|
||||
source = MediaKind.file;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
link.dispose();
|
||||
file.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// Source segments (Jellyfin / Link / File) and the matching input.
|
||||
/// Ctrl+V anywhere in the picker outside a text field pastes a link or path.
|
||||
class MediaPicker extends StatefulWidget {
|
||||
final MediaPickerController controller;
|
||||
final ValueChanged<PickedMedia?>? onChanged;
|
||||
/// Enter in a field.
|
||||
final VoidCallback? onSubmit;
|
||||
final VoidCallback? onOpenIntegrations;
|
||||
final bool enabled;
|
||||
final bool autofocus;
|
||||
/// Defaults to [JellyfinAccounts.instance].
|
||||
final JellyfinAccounts? jellyfin;
|
||||
/// Jellyfin source only: the browser's "bigger" toggle.
|
||||
final VoidCallback? onToggleExpanded;
|
||||
final bool expanded;
|
||||
/// Where the Jellyfin browser opens instead of its remembered location.
|
||||
final BrowseStart? jellyfinStart;
|
||||
/// False hides the File source (only the host can serve a file).
|
||||
final bool allowFile;
|
||||
/// Shown under the Link field instead of the default help.
|
||||
final String? linkHelp;
|
||||
const MediaPicker({
|
||||
super.key,
|
||||
this.jellyfinStart,
|
||||
this.allowFile = true,
|
||||
this.linkHelp,
|
||||
required this.controller,
|
||||
this.onChanged,
|
||||
this.onSubmit,
|
||||
this.onOpenIntegrations,
|
||||
this.enabled = true,
|
||||
this.autofocus = false,
|
||||
this.jellyfin,
|
||||
this.onToggleExpanded,
|
||||
this.expanded = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MediaPicker> createState() => _MediaPickerState();
|
||||
}
|
||||
|
||||
class _MediaPickerState extends State<MediaPicker> {
|
||||
MediaPickerController get _c => widget.controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_c.addListener(_changed);
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(MediaPicker old) {
|
||||
super.didUpdateWidget(old);
|
||||
if (old.controller != widget.controller) {
|
||||
old.controller.removeListener(_changed);
|
||||
widget.controller.addListener(_changed);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_c.removeListener(_changed);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _changed() {
|
||||
widget.onChanged?.call(_c.selection);
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<String?> _clipboard() async {
|
||||
try {
|
||||
return (await Clipboard.getData(Clipboard.kTextPlain))?.text?.trim();
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _pasteAnywhere() async {
|
||||
final text = await _clipboard();
|
||||
if (text != null && text.isNotEmpty) _c.pasteText(text);
|
||||
}
|
||||
|
||||
Future<void> _pasteLink() async {
|
||||
final text = await _clipboard();
|
||||
if (text != null && text.isNotEmpty) _c.link.text = text;
|
||||
}
|
||||
|
||||
Future<void> _browse() async {
|
||||
try {
|
||||
final files = await FilePicker.pickFiles(
|
||||
dialogTitle: 'Pick media file',
|
||||
type: FileType.custom,
|
||||
allowedExtensions: videoExtensions,
|
||||
);
|
||||
final path = files.isEmpty ? null : files.first.path;
|
||||
if (path != null) {
|
||||
_c.file.text = path;
|
||||
_c.notice = null;
|
||||
}
|
||||
} catch (e) {
|
||||
_c.notice = 'File dialog unavailable (${e.runtimeType}) — paste the path instead';
|
||||
}
|
||||
}
|
||||
|
||||
KeyEventResult _onKey(FocusNode node, KeyEvent e) {
|
||||
final ctrl = HardwareKeyboard.instance.isControlPressed ||
|
||||
HardwareKeyboard.instance.isMetaPressed;
|
||||
if (!widget.enabled || e is! KeyDownEvent || !ctrl || e.logicalKey != LogicalKeyboardKey.keyV) {
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
// A focused text field handles its own paste.
|
||||
final inField = FocusManager.instance.primaryFocus?.context
|
||||
?.findAncestorStateOfType<EditableTextState>() !=
|
||||
null;
|
||||
if (inField) return KeyEventResult.ignored;
|
||||
_pasteAnywhere();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final source = _c.source;
|
||||
final Widget content = switch (source) {
|
||||
MediaKind.jellyfin => JellyfinPickerSource(
|
||||
accounts: widget.jellyfin ?? JellyfinAccounts.instance,
|
||||
selected: _c.jellyfin,
|
||||
onPick: _c.pickJellyfin,
|
||||
onOpenIntegrations: widget.onOpenIntegrations,
|
||||
onToggleExpanded: widget.onToggleExpanded,
|
||||
expanded: widget.expanded,
|
||||
start: widget.jellyfinStart,
|
||||
),
|
||||
MediaKind.link => _FieldRow(
|
||||
key: const ValueKey('media-link'),
|
||||
field: TextField(
|
||||
controller: _c.link,
|
||||
autofocus: widget.autofocus,
|
||||
decoration: fieldDecoration('Video link', hint: 'https://…/movie.mkv'),
|
||||
keyboardType: TextInputType.url,
|
||||
onSubmitted: (_) => widget.onSubmit?.call(),
|
||||
),
|
||||
button: OutlinedButton.icon(
|
||||
onPressed: _pasteLink,
|
||||
icon: const Icon(Icons.content_paste, size: 18),
|
||||
label: const Text('Paste'),
|
||||
),
|
||||
help: widget.linkHelp ??
|
||||
'A direct http(s) link to a video file; everyone streams it from there. '
|
||||
'Jellyfin links are shared as the item, without your sign-in.',
|
||||
notice: _c.notice,
|
||||
),
|
||||
MediaKind.file => _FieldRow(
|
||||
key: const ValueKey('media-file'),
|
||||
field: TextField(
|
||||
controller: _c.file,
|
||||
decoration: fieldDecoration('Video file', hint: 'Path to a video on this computer'),
|
||||
onSubmitted: (_) => widget.onSubmit?.call(),
|
||||
),
|
||||
button: OutlinedButton.icon(
|
||||
onPressed: _browse,
|
||||
icon: const Icon(Icons.folder_open, size: 18),
|
||||
label: const Text('Browse'),
|
||||
),
|
||||
help: 'Friends stream it from you while you watch. Optional — you can host without media.',
|
||||
notice: _c.notice,
|
||||
),
|
||||
};
|
||||
final segments = Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: SegmentedButton<MediaKind>(
|
||||
key: const ValueKey('media-source'),
|
||||
showSelectedIcon: false,
|
||||
segments: [
|
||||
const ButtonSegment(
|
||||
value: MediaKind.jellyfin,
|
||||
icon: Icon(Icons.video_library_outlined),
|
||||
label: Text('Jellyfin')),
|
||||
const ButtonSegment(value: MediaKind.link, icon: Icon(Icons.link), label: Text('Link')),
|
||||
const ButtonSegment(
|
||||
value: MediaKind.file,
|
||||
icon: Icon(Icons.insert_drive_file_outlined),
|
||||
label: Text('File')),
|
||||
].where((s) => widget.allowFile || s.value != MediaKind.file).toList(),
|
||||
selected: {source},
|
||||
onSelectionChanged: (s) => _c.source = s.first,
|
||||
),
|
||||
);
|
||||
return Focus(
|
||||
autofocus: widget.autofocus,
|
||||
onKeyEvent: _onKey,
|
||||
child: AbsorbPointer(
|
||||
absorbing: !widget.enabled,
|
||||
// The browser fills the height it is given; in an unbounded
|
||||
// (scrolling) parent it gets a fixed one.
|
||||
child: LayoutBuilder(builder: (context, box) {
|
||||
final fill = source == MediaKind.jellyfin;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: fill && box.hasBoundedHeight ? MainAxisSize.max : MainAxisSize.min,
|
||||
children: [
|
||||
segments,
|
||||
const SizedBox(height: kGap),
|
||||
if (!fill)
|
||||
content
|
||||
else if (box.hasBoundedHeight)
|
||||
Expanded(child: content)
|
||||
else
|
||||
SizedBox(height: jellyfinPickerHeight, child: content),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Height of the Jellyfin browser when the picker sits in a scroll view.
|
||||
const jellyfinPickerHeight = 640.0;
|
||||
|
||||
class _FieldRow extends StatelessWidget {
|
||||
final Widget field;
|
||||
final Widget button;
|
||||
final String help;
|
||||
final String? notice;
|
||||
const _FieldRow(
|
||||
{super.key, required this.field, required this.button, required this.help, this.notice});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final small = Theme.of(context).textTheme.bodySmall?.copyWith(color: Colors.grey);
|
||||
return Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: kFieldMaxWidth + 140),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: field),
|
||||
const SizedBox(width: 12),
|
||||
button,
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(notice ?? help, style: small),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/// What the media picker selected. Null selection = nothing (hosting
|
||||
/// without media is allowed).
|
||||
sealed class PickedMedia {
|
||||
const PickedMedia();
|
||||
|
||||
/// One line for summaries ("Playing: …").
|
||||
String get label;
|
||||
}
|
||||
|
||||
/// A direct http(s) link everyone streams from.
|
||||
final class LinkMedia extends PickedMedia {
|
||||
final String url;
|
||||
const LinkMedia(this.url);
|
||||
|
||||
@override
|
||||
String get label {
|
||||
final uri = Uri.tryParse(url);
|
||||
final segs = uri?.pathSegments.where((s) => s.isNotEmpty).toList() ?? const [];
|
||||
if (segs.isEmpty) return uri?.host.isNotEmpty == true ? uri!.host : url;
|
||||
try {
|
||||
return Uri.decodeComponent(segs.last);
|
||||
} catch (_) {
|
||||
return segs.last;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => other is LinkMedia && other.url == url;
|
||||
@override
|
||||
int get hashCode => url.hashCode;
|
||||
@override
|
||||
String toString() => 'LinkMedia($url)';
|
||||
}
|
||||
|
||||
/// A file on this computer; friends stream it from the host.
|
||||
final class FileMedia extends PickedMedia {
|
||||
final String path;
|
||||
const FileMedia(this.path);
|
||||
|
||||
@override
|
||||
String get label =>
|
||||
path.split(RegExp(r'[/\\]')).lastWhere((p) => p.isNotEmpty, orElse: () => path);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => other is FileMedia && other.path == path;
|
||||
@override
|
||||
int get hashCode => path.hashCode;
|
||||
@override
|
||||
String toString() => 'FileMedia($path)';
|
||||
}
|
||||
|
||||
/// A movie or episode on a linked Jellyfin server. [serverId] keys the
|
||||
/// account (`JellyfinAccounts.clientFor`); [baseUrl] is the address it was
|
||||
/// picked through. No credentials in here: each side authorises its own.
|
||||
final class JellyfinMedia extends PickedMedia {
|
||||
final String serverId;
|
||||
final String baseUrl;
|
||||
final String itemId;
|
||||
/// Null = the item's default source.
|
||||
final String? mediaSourceId;
|
||||
final String title;
|
||||
/// "Series · S1E6" for episodes, the year for movies; may be empty.
|
||||
final String subtitle;
|
||||
final Duration? runtime;
|
||||
const JellyfinMedia({
|
||||
required this.serverId,
|
||||
required this.baseUrl,
|
||||
required this.itemId,
|
||||
this.mediaSourceId,
|
||||
required this.title,
|
||||
this.subtitle = '',
|
||||
this.runtime,
|
||||
});
|
||||
|
||||
@override
|
||||
String get label => subtitle.isEmpty ? title : '$title — $subtitle';
|
||||
|
||||
Map<String, Object?> toJson() => {
|
||||
'serverId': serverId,
|
||||
'baseUrl': baseUrl,
|
||||
'itemId': itemId,
|
||||
'mediaSourceId': ?mediaSourceId,
|
||||
'title': title,
|
||||
'subtitle': subtitle,
|
||||
if (runtime != null) 'runtimeMs': runtime!.inMilliseconds,
|
||||
};
|
||||
|
||||
static JellyfinMedia? fromJson(Object? j) {
|
||||
if (j is! Map) return null;
|
||||
final serverId = j['serverId'], baseUrl = j['baseUrl'], itemId = j['itemId'];
|
||||
if (serverId is! String || baseUrl is! String || itemId is! String) return null;
|
||||
final ms = j['runtimeMs'];
|
||||
return JellyfinMedia(
|
||||
serverId: serverId,
|
||||
baseUrl: baseUrl,
|
||||
itemId: itemId,
|
||||
mediaSourceId: j['mediaSourceId'] is String ? j['mediaSourceId'] as String : null,
|
||||
title: j['title'] is String ? j['title'] as String : '',
|
||||
subtitle: j['subtitle'] is String ? j['subtitle'] as String : '',
|
||||
runtime: ms is int ? Duration(milliseconds: ms) : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
other is JellyfinMedia &&
|
||||
other.serverId == serverId &&
|
||||
other.itemId == itemId &&
|
||||
other.mediaSourceId == mediaSourceId;
|
||||
@override
|
||||
int get hashCode => Object.hash(serverId, itemId, mediaSourceId);
|
||||
@override
|
||||
String toString() => 'JellyfinMedia($serverId/$itemId "$title")';
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
|
||||
import '../../state/session_state.dart';
|
||||
import '../../widgets/avatar_pipeline.dart';
|
||||
import 'ui.dart';
|
||||
|
||||
/// Display name + avatar, shared by the Home profile row and Settings.
|
||||
/// Backed by [SessionState.lastForm]; every change is persisted. The
|
||||
/// avatar goes through [encodeAvatar] (the same shrink the server gets)
|
||||
/// before its path is stored, and the encoded bytes are the preview.
|
||||
class Profile {
|
||||
static final Profile instance = Profile._();
|
||||
Profile._();
|
||||
|
||||
final name = signal('');
|
||||
final preview = signal<Uint8List?>(null);
|
||||
final error = signal<String?>(null);
|
||||
final picking = signal(false);
|
||||
bool _loaded = false;
|
||||
|
||||
void ensureLoaded() {
|
||||
if (_loaded) return;
|
||||
_loaded = true;
|
||||
final f = SessionState.instance.lastForm;
|
||||
name.value = f.name;
|
||||
_refreshPreview(f.avatarPath);
|
||||
}
|
||||
|
||||
Future<void> _refreshPreview(String path) async {
|
||||
try {
|
||||
final b64 = await encodeAvatar(path);
|
||||
preview.value = b64.isEmpty ? null : base64Decode(b64);
|
||||
} catch (_) {
|
||||
preview.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
void setName(String value) {
|
||||
name.value = value.trim();
|
||||
SessionState.instance.lastForm.name = value.trim();
|
||||
_save();
|
||||
}
|
||||
|
||||
Future<void> pickAvatar() async {
|
||||
if (picking.peek()) return;
|
||||
picking.value = true;
|
||||
error.value = null;
|
||||
try {
|
||||
final List<PlatformFile> files;
|
||||
try {
|
||||
files = await FilePicker.pickFiles(
|
||||
dialogTitle: 'Pick avatar image',
|
||||
type: FileType.custom,
|
||||
allowedExtensions: const ['png', 'jpg', 'jpeg', 'webp'],
|
||||
);
|
||||
} catch (_) {
|
||||
error.value = 'file dialog unavailable — try again';
|
||||
return;
|
||||
}
|
||||
final path = files.isEmpty ? null : files.first.path;
|
||||
if (path == null) return;
|
||||
final String b64;
|
||||
try {
|
||||
b64 = await encodeAvatar(path);
|
||||
} on FormatException catch (e) {
|
||||
error.value = e.message;
|
||||
return;
|
||||
} catch (_) {
|
||||
error.value = 'could not read that image — pick a PNG, JPG or WebP photo';
|
||||
return;
|
||||
}
|
||||
SessionState.instance.lastForm.avatarPath = path;
|
||||
preview.value = b64.isEmpty ? null : base64Decode(b64);
|
||||
await _save();
|
||||
} finally {
|
||||
picking.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> clearAvatar() async {
|
||||
SessionState.instance.lastForm.avatarPath = '';
|
||||
preview.value = null;
|
||||
error.value = null;
|
||||
await _save();
|
||||
}
|
||||
|
||||
Future<void> _save() async {
|
||||
try {
|
||||
await SessionState.instance.saveForm();
|
||||
} catch (_) {
|
||||
error.value = 'could not save profile — try again';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Avatar circle with the initial as fallback.
|
||||
class ProfileAvatar extends StatelessWidget {
|
||||
final double radius;
|
||||
const ProfileAvatar({super.key, this.radius = 20});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final p = Profile.instance;
|
||||
return SignalBuilder(builder: (context) {
|
||||
final img = p.preview.value;
|
||||
final n = p.name.value;
|
||||
return CircleAvatar(
|
||||
radius: radius,
|
||||
backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
backgroundImage: img != null ? MemoryImage(img) : null,
|
||||
child: img != null
|
||||
? null
|
||||
: p.picking.value
|
||||
? SizedBox(
|
||||
width: radius * 0.8,
|
||||
height: radius * 0.8,
|
||||
child: const CircularProgressIndicator(strokeWidth: 2))
|
||||
: Text(n.isEmpty ? '?' : n[0].toUpperCase(),
|
||||
style: TextStyle(fontSize: radius * 0.8)),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Avatar (tap to change) + name field. Used inline in Settings and in
|
||||
/// the Home profile dialog.
|
||||
class ProfileEditor extends StatefulWidget {
|
||||
final bool autofocus;
|
||||
final VoidCallback? onSubmitted;
|
||||
const ProfileEditor({super.key, this.autofocus = false, this.onSubmitted});
|
||||
|
||||
@override
|
||||
State<ProfileEditor> createState() => _ProfileEditorState();
|
||||
}
|
||||
|
||||
class _ProfileEditorState extends State<ProfileEditor> {
|
||||
late final _name = TextEditingController(text: Profile.instance.name.peek());
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_name.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final p = Profile.instance;
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Tooltip(
|
||||
message: 'Change avatar',
|
||||
child: InkWell(
|
||||
customBorder: const CircleBorder(),
|
||||
onTap: p.pickAvatar,
|
||||
child: const ProfileAvatar(radius: 36),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: kGap),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: _name,
|
||||
autofocus: widget.autofocus,
|
||||
decoration: fieldDecoration('Display name'),
|
||||
onChanged: p.setName,
|
||||
onSubmitted: (_) => widget.onSubmitted?.call(),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
SignalBuilder(builder: (context) {
|
||||
final err = p.error.value;
|
||||
return Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: p.pickAvatar,
|
||||
child: const Text('Change avatar')),
|
||||
if (p.preview.value != null)
|
||||
TextButton(
|
||||
onPressed: p.clearAvatar,
|
||||
child: const Text('Remove avatar')),
|
||||
if (err != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 8),
|
||||
child: Text(err,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.error)),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showProfileDialog(BuildContext context) {
|
||||
return showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(kRadius)),
|
||||
title: const Text('Profile'),
|
||||
content: SizedBox(
|
||||
width: 380,
|
||||
child: ProfileEditor(
|
||||
autofocus: true,
|
||||
onSubmitted: () => Navigator.pop(context),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.pop(context), child: const Text('Done')),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Home's top-left: avatar + name, click to edit.
|
||||
class ProfileChip extends StatelessWidget {
|
||||
/// One line and a small avatar, for the Home top bar.
|
||||
final bool dense;
|
||||
/// Just the avatar, for very narrow windows.
|
||||
final bool avatarOnly;
|
||||
const ProfileChip({super.key, this.dense = false, this.avatarOnly = false});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final p = Profile.instance;
|
||||
return Tooltip(
|
||||
message: 'Edit profile',
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(kRadius),
|
||||
onTap: () => showProfileDialog(context),
|
||||
child: avatarOnly
|
||||
? const Padding(padding: EdgeInsets.all(4), child: ProfileAvatar(radius: 14))
|
||||
: Padding(
|
||||
padding: dense
|
||||
? const EdgeInsets.fromLTRB(4, 4, 10, 4)
|
||||
: const EdgeInsets.fromLTRB(6, 6, 14, 6),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ProfileAvatar(radius: dense ? 14 : 20),
|
||||
SizedBox(width: dense ? 8 : 12),
|
||||
SignalBuilder(builder: (context) {
|
||||
final n = p.name.value;
|
||||
final t = Theme.of(context).textTheme;
|
||||
final name = Text(n.isEmpty ? 'Set your name' : n,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: (dense ? t.titleSmall : t.titleMedium)
|
||||
?.copyWith(color: n.isEmpty ? Colors.grey : null));
|
||||
if (dense) {
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 200), child: name);
|
||||
}
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
name,
|
||||
Text('Edit profile',
|
||||
style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
|
||||
import '../../playback/playback_controller.dart';
|
||||
import '../../shaders/shader_presets.dart';
|
||||
import '../../state/settings.dart';
|
||||
import '../../update/update_controller.dart';
|
||||
import 'profile.dart';
|
||||
import 'ui.dart';
|
||||
import 'update_indicator.dart';
|
||||
|
||||
/// In-session keys, as handled by the session screen's global key handler.
|
||||
const sessionShortcuts = [
|
||||
('Space', 'Toggle ready'),
|
||||
('← / →', 'Seek back / forward 10 s'),
|
||||
('Shift+→', 'Skip 1:30 (for everyone)'),
|
||||
('PgUp / PgDn', 'Previous / next chapter'),
|
||||
('F', 'Toggle fullscreen'),
|
||||
('Tab', 'Open / close the people & chat panel'),
|
||||
('Ctrl+R', 'Reload the video'),
|
||||
('> or Shift+N', 'Put up the next Jellyfin episode'),
|
||||
('< or Shift+P', 'Put up the previous Jellyfin episode'),
|
||||
('Ctrl+1…6', 'Shaders: Anime4K mode A, B, C, A+A, B+B, C+A'),
|
||||
('Ctrl+0', 'Shaders off'),
|
||||
('Esc', 'Close panel or fullscreen, else ask to leave'),
|
||||
];
|
||||
|
||||
class SettingsPage extends StatelessWidget {
|
||||
final UpdateController? updates;
|
||||
const SettingsPage({super.key, this.updates});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PageScroll(
|
||||
maxWidth: 680,
|
||||
children: [
|
||||
const PageTitle('Settings'),
|
||||
const _Section(title: 'Profile', child: ProfileEditor()),
|
||||
const _Section(
|
||||
title: 'Player',
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [_HwdecSetting(), SizedBox(height: 12), _MpvControlsSetting()],
|
||||
),
|
||||
),
|
||||
const _Section(title: 'Jellyfin', child: _AutoAdvanceSetting()),
|
||||
_Section(title: 'Updates', child: _UpdateSettings(controller: updates)),
|
||||
const _Section(title: 'Keyboard shortcuts', child: _ShortcutList()),
|
||||
const _Section(title: 'Video quality & shaders', child: _ShaderSettings()),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Section extends StatelessWidget {
|
||||
final String title;
|
||||
final Widget child;
|
||||
const _Section({required this.title, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: kGap),
|
||||
child: Panel(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [SectionLabel(title), child],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _HwdecSetting extends StatefulWidget {
|
||||
const _HwdecSetting();
|
||||
|
||||
@override
|
||||
State<_HwdecSetting> createState() => _HwdecSettingState();
|
||||
}
|
||||
|
||||
class _HwdecSettingState extends State<_HwdecSetting> {
|
||||
final _s = AppSettings.instance;
|
||||
late final _custom = TextEditingController(text: _s.hwdecCustom.peek());
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_custom.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SignalBuilder(builder: (context) {
|
||||
final mode = _s.hwdecMode.value;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('Hardware decoding'),
|
||||
const SizedBox(height: 4),
|
||||
const Text(
|
||||
'Applies on the next join or Reload video (Ctrl+R). Turn it off if video '
|
||||
'shows glitches or a black picture.',
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SegmentedButton<HwdecMode>(
|
||||
showSelectedIcon: false,
|
||||
segments: const [
|
||||
ButtonSegment(value: HwdecMode.auto, label: Text('Auto')),
|
||||
ButtonSegment(value: HwdecMode.off, label: Text('Off')),
|
||||
ButtonSegment(value: HwdecMode.custom, label: Text('Custom')),
|
||||
],
|
||||
selected: {mode},
|
||||
onSelectionChanged: (s) => _s.setHwdecMode(s.first),
|
||||
),
|
||||
if (mode == HwdecMode.custom)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: TextField(
|
||||
controller: _custom,
|
||||
decoration: fieldDecoration('mpv hwdec value',
|
||||
hint: 'e.g. vaapi, nvdec, d3d11va, auto-safe'),
|
||||
onChanged: _s.setHwdecCustom,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _ShaderSettings extends StatelessWidget {
|
||||
const _ShaderSettings();
|
||||
|
||||
Future<void> _addFiles() async {
|
||||
final List<PlatformFile> files;
|
||||
try {
|
||||
files = await FilePicker.pickFiles(
|
||||
dialogTitle: 'Pick mpv GLSL shaders',
|
||||
type: FileType.custom,
|
||||
allowedExtensions: const ['glsl', 'hook'],
|
||||
);
|
||||
} catch (_) {
|
||||
return;
|
||||
}
|
||||
final s = AppSettings.instance;
|
||||
final current = s.customShaders.peek();
|
||||
final added = [
|
||||
for (final f in files)
|
||||
if (f.path case final p? when !current.contains(p)) p,
|
||||
];
|
||||
if (added.isNotEmpty) s.setCustomShaders([...current, ...added]);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = AppSettings.instance;
|
||||
return SignalBuilder(builder: (context) {
|
||||
final preset = s.shaderPreset.value;
|
||||
final quality = s.shaderQuality.value;
|
||||
final custom = s.customShaders.value;
|
||||
final mode = PlaybackController.lastRenderMode.value;
|
||||
const hint = TextStyle(fontSize: 12, color: Colors.grey);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Anime4K upscales and sharpens anime on your GPU, for you only. '
|
||||
'Mode A suits 1080p sources, B 720p, C 480p; A+A, B+B and C+A add '
|
||||
'a second pass. HQ is for strong GPUs (GTX 1080 and up), Fast for '
|
||||
'weaker ones. Costs GPU time every frame and only works with '
|
||||
'hardware video rendering. In the player: the ✨ button or '
|
||||
'Ctrl+1…6, Ctrl+0 for off; changes apply live and are saved here.',
|
||||
style: hint,
|
||||
),
|
||||
if (mode == RenderMode.software || mode == RenderMode.softwareGl)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(
|
||||
mode == RenderMode.software
|
||||
? 'The last session used software rendering: shaders had no effect there.'
|
||||
: 'The last session rendered OpenGL on the CPU: shaders will be slow.',
|
||||
style: const TextStyle(fontSize: 12, color: Colors.orange),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
const Text('Shaders'),
|
||||
const SizedBox(width: 16),
|
||||
DropdownButton<ShaderPreset>(
|
||||
value: preset,
|
||||
onChanged: (p) {
|
||||
if (p != null) s.setShaderPreset(p);
|
||||
},
|
||||
items: [
|
||||
for (final p in ShaderPreset.values)
|
||||
DropdownMenuItem(value: p, child: Text(p.label)),
|
||||
],
|
||||
),
|
||||
const Spacer(),
|
||||
SegmentedButton<ShaderQuality>(
|
||||
showSelectedIcon: false,
|
||||
segments: [
|
||||
for (final q in ShaderQuality.values)
|
||||
ButtonSegment(value: q, label: Text(q.label)),
|
||||
],
|
||||
selected: {quality},
|
||||
onSelectionChanged: (q) => s.setShaderQuality(q.first),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
const Expanded(child: Text('Custom shaders (run in this order)')),
|
||||
TextButton.icon(
|
||||
onPressed: _addFiles,
|
||||
icon: const Icon(Icons.add, size: 18),
|
||||
label: const Text('Add .glsl files'),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (custom.isEmpty)
|
||||
const Text('None picked.', style: hint)
|
||||
else
|
||||
for (final (i, path) in custom.indexed)
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Tooltip(
|
||||
message: path,
|
||||
child: Text(path.split(RegExp(r'[/\\]')).last,
|
||||
overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Remove',
|
||||
icon: const Icon(Icons.close, size: 18),
|
||||
onPressed: () =>
|
||||
s.setCustomShaders([...custom]..removeAt(i)),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _UpdateSettings extends StatelessWidget {
|
||||
final UpdateController? controller;
|
||||
const _UpdateSettings({this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final c = controller ?? UpdateController.instance;
|
||||
final s = AppSettings.instance;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: UpdateStatusLine(controller: c)),
|
||||
ValueListenableBuilder(
|
||||
valueListenable: c.status,
|
||||
builder: (context, st, _) {
|
||||
if (st.phase == UpdatePhase.idle || st.manifest == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: FilledButton.tonal(
|
||||
onPressed: () => showUpdateDialog(context, controller: c),
|
||||
child: const Text('Show update'),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
ValueListenableBuilder(
|
||||
valueListenable: updateCheck,
|
||||
builder: (context, check, _) => OutlinedButton(
|
||||
onPressed: check == UpdateCheck.checking ? null : () => runUpdateCheck(c, true),
|
||||
child: const Text('Check now'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SignalBuilder(
|
||||
builder: (context) => SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: const Text('Check automatically on start'),
|
||||
value: s.autoCheckUpdates.value,
|
||||
onChanged: s.setAutoCheckUpdates,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MpvControlsSetting extends StatelessWidget {
|
||||
const _MpvControlsSetting();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = AppSettings.instance;
|
||||
return SignalBuilder(
|
||||
builder: (context) => SwitchListTile(
|
||||
key: const ValueKey('mpv-controls'),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: const Text('Experimental: mpv-style controls'),
|
||||
subtitle: const Text('Video controls modeled on mpv\'s uosc theme: a thick timeline with '
|
||||
'chapters and the cached range, flat buttons and menus. Applies right away.'),
|
||||
value: s.mpvControls.value,
|
||||
onChanged: s.setMpvControls,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AutoAdvanceSetting extends StatelessWidget {
|
||||
const _AutoAdvanceSetting();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = AppSettings.instance;
|
||||
return SignalBuilder(
|
||||
builder: (context) => SwitchListTile(
|
||||
key: const ValueKey('auto-advance'),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: const Text('Play the next episode automatically'),
|
||||
subtitle: const Text('When an episode ends, a 10 s countdown puts up the next one; '
|
||||
'anyone can cancel it on their screen.'),
|
||||
value: s.autoAdvance.value,
|
||||
onChanged: s.setAutoAdvance,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ShortcutList extends StatelessWidget {
|
||||
const _ShortcutList();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('While watching:', style: TextStyle(color: Colors.grey)),
|
||||
const SizedBox(height: 8),
|
||||
for (final (key, what) in sessionShortcuts)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 96,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(key,
|
||||
style: const TextStyle(fontFamily: 'monospace', fontSize: 13)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(child: Text(what)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import '../../update/update_controller.dart';
|
||||
import '../../widgets/window_buttons.dart';
|
||||
import 'profile.dart';
|
||||
import 'update_indicator.dart';
|
||||
|
||||
/// What the Home body shows: the two tabs, or one of the side pages.
|
||||
enum HomeView { join, host, settings, integrations, about }
|
||||
|
||||
const homeTopBarHeight = 48.0;
|
||||
|
||||
/// Below this width the bar drops the profile name and tab icons.
|
||||
const _compactBelow = 760.0;
|
||||
|
||||
/// Home's single top bar: profile, Join/Host tabs, update pill, page
|
||||
/// buttons and (in the real window) the drag area and window buttons.
|
||||
class HomeTopBar extends StatelessWidget {
|
||||
final HomeView view;
|
||||
final ValueChanged<HomeView> onSelect;
|
||||
final UpdateController? updates;
|
||||
/// Off in tests: the drag area and window buttons need window_manager.
|
||||
final bool windowControls;
|
||||
const HomeTopBar({
|
||||
super.key,
|
||||
required this.view,
|
||||
required this.onSelect,
|
||||
this.updates,
|
||||
this.windowControls = false,
|
||||
});
|
||||
|
||||
static const _pages = [
|
||||
(HomeView.settings, Icons.settings_outlined, Icons.settings, 'Settings'),
|
||||
(HomeView.integrations, Icons.extension_outlined, Icons.extension, 'Integrations'),
|
||||
(HomeView.about, Icons.info_outline, Icons.info, 'About'),
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, box) => _bar(context, compact: box.maxWidth < _compactBelow));
|
||||
}
|
||||
|
||||
Widget _bar(BuildContext context, {required bool compact}) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final row = Row(
|
||||
children: [
|
||||
const SizedBox(width: 12),
|
||||
ProfileChip(dense: true, avatarOnly: compact),
|
||||
SizedBox(width: compact ? 8 : 20),
|
||||
_Tab(
|
||||
key: const ValueKey('tab-join'),
|
||||
label: 'Join',
|
||||
icon: compact ? null : Icons.login,
|
||||
selected: view == HomeView.join,
|
||||
onTap: () => onSelect(HomeView.join),
|
||||
),
|
||||
_Tab(
|
||||
key: const ValueKey('tab-host'),
|
||||
label: 'Host',
|
||||
icon: compact ? null : Icons.cast,
|
||||
selected: view == HomeView.host,
|
||||
onTap: () => onSelect(HomeView.host),
|
||||
),
|
||||
const Spacer(),
|
||||
UpdateIndicator(controller: updates),
|
||||
const SizedBox(width: 8),
|
||||
for (final (v, icon, selectedIcon, label) in _pages)
|
||||
IconButton(
|
||||
tooltip: label,
|
||||
isSelected: view == v,
|
||||
icon: Icon(icon, size: 20),
|
||||
selectedIcon: Icon(selectedIcon, size: 20, color: scheme.primary),
|
||||
onPressed: () => onSelect(v),
|
||||
),
|
||||
if (windowControls) ...[
|
||||
const SizedBox(width: 4),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
child: VerticalDivider(width: 12, color: scheme.outlineVariant),
|
||||
),
|
||||
const WindowButtons(),
|
||||
] else
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
);
|
||||
final bar = SizedBox(height: homeTopBarHeight, child: row);
|
||||
return ColoredBox(
|
||||
color: scheme.surfaceContainerLowest,
|
||||
// Empty bar space drags the window; the controls on top take their
|
||||
// own clicks without waiting out the drag area's double-tap.
|
||||
child: windowControls
|
||||
? Stack(children: [
|
||||
const Positioned.fill(child: DragToMoveArea(child: SizedBox.expand())),
|
||||
bar,
|
||||
])
|
||||
: bar,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Tab extends StatelessWidget {
|
||||
final String label;
|
||||
final IconData? icon;
|
||||
final bool selected;
|
||||
final VoidCallback onTap;
|
||||
const _Tab(
|
||||
{super.key,
|
||||
required this.label,
|
||||
this.icon,
|
||||
required this.selected,
|
||||
required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final color = selected ? scheme.primary : scheme.onSurfaceVariant;
|
||||
return Semantics(
|
||||
selected: selected,
|
||||
button: true,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
height: homeTopBarHeight,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: selected ? scheme.primary : Colors.transparent, width: 2),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (icon != null) ...[
|
||||
Icon(icon, size: 18, color: color),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
Text(label,
|
||||
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
||||
color: color, fontWeight: selected ? FontWeight.w600 : null)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Product name (working title). Change it here only.
|
||||
const appName = 'Watch Together';
|
||||
|
||||
const repoUrl = 'https://git.senkochan.moe/Foxyz/sync_replay_project';
|
||||
|
||||
const kRadius = 12.0;
|
||||
const kGap = 16.0;
|
||||
const kPagePadding = EdgeInsets.fromLTRB(28, 20, 28, 28);
|
||||
|
||||
/// Rounded panel used by every Home/Settings section.
|
||||
class Panel extends StatelessWidget {
|
||||
final Widget child;
|
||||
final EdgeInsetsGeometry padding;
|
||||
final bool enabled;
|
||||
const Panel(
|
||||
{super.key,
|
||||
required this.child,
|
||||
this.padding = const EdgeInsets.all(20),
|
||||
this.enabled = true});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
// Material (not a DecoratedBox) so ink from tiles/chips inside shows.
|
||||
final panel = Material(
|
||||
color: scheme.surfaceContainer,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(kRadius),
|
||||
side: BorderSide(color: scheme.outlineVariant.withValues(alpha: 0.5)),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Padding(padding: padding, child: child),
|
||||
);
|
||||
if (enabled) return panel;
|
||||
return Opacity(opacity: 0.5, child: IgnorePointer(child: panel));
|
||||
}
|
||||
}
|
||||
|
||||
/// Page heading + optional subtitle, same spacing everywhere.
|
||||
class PageTitle extends StatelessWidget {
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
const PageTitle(this.title, {super.key, this.subtitle});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: kGap),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title, style: t.headlineSmall),
|
||||
if (subtitle != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
child: Text(subtitle!,
|
||||
style: t.bodyMedium?.copyWith(color: Colors.grey)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Small grey heading inside a panel.
|
||||
class SectionLabel extends StatelessWidget {
|
||||
final String text;
|
||||
final Widget? trailing;
|
||||
const SectionLabel(this.text, {super.key, this.trailing});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(text, style: Theme.of(context).textTheme.titleMedium),
|
||||
),
|
||||
?trailing,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Text field style shared by the connect cards.
|
||||
InputDecoration fieldDecoration(String label, {String? hint, Widget? suffix}) =>
|
||||
InputDecoration(
|
||||
labelText: label,
|
||||
hintText: hint,
|
||||
isDense: true,
|
||||
suffixIcon: suffix,
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
|
||||
);
|
||||
|
||||
/// Single-item scrollable page body, width-capped so it doesn't sprawl
|
||||
/// on wide windows.
|
||||
class PageScroll extends StatelessWidget {
|
||||
final List<Widget> children;
|
||||
final double maxWidth;
|
||||
const PageScroll({super.key, required this.children, this.maxWidth = 920});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
padding: kPagePadding,
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: maxWidth),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Widest a single text field gets, however wide the window.
|
||||
const kFieldMaxWidth = 720.0;
|
||||
|
||||
/// Inline failure under a connect form: bold title, selectable message.
|
||||
class ErrorBox extends StatelessWidget {
|
||||
final String title;
|
||||
final String message;
|
||||
const ErrorBox({super.key, required this.title, required this.message});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: scheme.errorContainer.withValues(alpha: 0.35),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(Icons.error_outline, size: 18, color: scheme.error),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: SelectableText.rich(
|
||||
TextSpan(children: [
|
||||
TextSpan(
|
||||
text: '$title\n',
|
||||
style: const TextStyle(fontWeight: FontWeight.w600)),
|
||||
TextSpan(text: message),
|
||||
]),
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../update/update_controller.dart';
|
||||
import '../../widgets/update_banner.dart';
|
||||
import 'ui.dart';
|
||||
|
||||
/// Compact "Update vX" pill for Home's top-right; hidden until there is
|
||||
/// something to install. Click opens the full [UpdateBanner].
|
||||
class UpdateIndicator extends StatelessWidget {
|
||||
final UpdateController? controller;
|
||||
const UpdateIndicator({super.key, this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final c = controller ?? UpdateController.instance;
|
||||
return ValueListenableBuilder<UpdateStatus>(
|
||||
valueListenable: c.status,
|
||||
builder: (context, s, _) {
|
||||
final m = s.manifest;
|
||||
if (s.phase == UpdatePhase.idle || m == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final busy = s.phase == UpdatePhase.downloading ||
|
||||
s.phase == UpdatePhase.applying ||
|
||||
s.phase == UpdatePhase.restarting;
|
||||
final label = switch (s.phase) {
|
||||
UpdatePhase.downloading =>
|
||||
'Updating ${((s.progress ?? 0) * 100).round()}%',
|
||||
UpdatePhase.applying => 'Installing…',
|
||||
UpdatePhase.restarting => 'Restarting…',
|
||||
UpdatePhase.failed => 'Update failed',
|
||||
_ => m.isRequired ? 'Required update' : 'Update v${m.version}',
|
||||
};
|
||||
return Tooltip(
|
||||
message: 'Show update',
|
||||
child: FilledButton.tonalIcon(
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: m.isRequired || s.phase == UpdatePhase.failed
|
||||
? scheme.errorContainer
|
||||
: null,
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: () => showUpdateDialog(context, controller: c),
|
||||
icon: busy
|
||||
? const SizedBox(
|
||||
width: 14,
|
||||
height: 14,
|
||||
child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Icon(Icons.system_update_alt, size: 18),
|
||||
label: Text(label),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The existing update card in a dialog; closes itself when the card
|
||||
/// would render nothing (e.g. "Later").
|
||||
Future<void> showUpdateDialog(BuildContext context, {UpdateController? controller}) {
|
||||
final c = controller ?? UpdateController.instance;
|
||||
return showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => Dialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(kRadius)),
|
||||
child: SizedBox(
|
||||
width: 420,
|
||||
child: ValueListenableBuilder<UpdateStatus>(
|
||||
valueListenable: c.status,
|
||||
builder: (context, s, _) {
|
||||
if (s.phase == UpdatePhase.idle || s.manifest == null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (context.mounted) Navigator.of(context).maybePop();
|
||||
});
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: UpdateBanner(controller: c),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
enum UpdateCheck { notRun, checking, done }
|
||||
|
||||
/// Progress of this run's update check, for Settings/About wording.
|
||||
final updateCheck = ValueNotifier(UpdateCheck.notRun);
|
||||
|
||||
/// [force] re-checks even if this process already checked ("Check now").
|
||||
Future<void> runUpdateCheck([UpdateController? controller, bool force = false]) async {
|
||||
final c = controller ?? UpdateController.instance;
|
||||
updateCheck.value = UpdateCheck.checking;
|
||||
try {
|
||||
await (force ? c.checkNow() : c.checkOnce());
|
||||
} finally {
|
||||
updateCheck.value = UpdateCheck.done;
|
||||
}
|
||||
}
|
||||
|
||||
/// One-line update state: "Up to date", "Update v1.2 available", ...
|
||||
class UpdateStatusLine extends StatelessWidget {
|
||||
final UpdateController? controller;
|
||||
const UpdateStatusLine({super.key, this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final c = controller ?? UpdateController.instance;
|
||||
return ListenableBuilder(
|
||||
listenable: Listenable.merge([c.status, c.lastCheck, updateCheck]),
|
||||
builder: (context, _) {
|
||||
final s = c.status.value;
|
||||
final m = s.manifest;
|
||||
final String text;
|
||||
if (c.skipDevBuilds && c.currentVersion.endsWith('-dev')) {
|
||||
text = 'Dev build — update checks are off';
|
||||
} else if (s.phase != UpdatePhase.idle && m != null) {
|
||||
text = s.phase == UpdatePhase.failed
|
||||
? 'Update to v${m.version} failed'
|
||||
: 'Update v${m.version} available';
|
||||
} else {
|
||||
text = switch (updateCheck.value) {
|
||||
UpdateCheck.notRun => 'Not checked yet',
|
||||
UpdateCheck.checking => 'Checking…',
|
||||
UpdateCheck.done => c.lastCheck.value ?? 'Not checked yet',
|
||||
};
|
||||
}
|
||||
return Text(text,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(color: Colors.grey));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../jellyfin/session_media.dart';
|
||||
import '../../session/session_coordinator.dart' show AutoAdvance, autoAdvanceSecs;
|
||||
import 'player_controls.dart' show FloatingPill;
|
||||
|
||||
// Jellyfin pieces of the session screen. Plain widgets fed by the
|
||||
// coordinator's signals, so tests can pump them without the player.
|
||||
|
||||
/// Previous / next episode in the video controls. Nothing when there is
|
||||
/// no such episode or this viewer cannot put it up (no account).
|
||||
class EpisodeSkipButton extends StatelessWidget {
|
||||
final EpisodeLink? episode;
|
||||
final bool next;
|
||||
final VoidCallback onPressed;
|
||||
final FocusNode? focusNode;
|
||||
const EpisodeSkipButton(
|
||||
{super.key, required this.episode, required this.next, required this.onPressed, this.focusNode});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final e = episode;
|
||||
if (e == null) return const SizedBox.shrink();
|
||||
return Tooltip(
|
||||
message: '${next ? 'Next' : 'Previous'}: ${e.label} (${next ? '> or Shift+N' : '< or Shift+P'})',
|
||||
child: IconButton(
|
||||
key: ValueKey(next ? 'episode-next' : 'episode-previous'),
|
||||
focusNode: focusNode,
|
||||
color: Colors.white,
|
||||
iconSize: 22,
|
||||
visualDensity: VisualDensity.compact,
|
||||
icon: Icon(next ? Icons.skip_next_rounded : Icons.skip_previous_rounded),
|
||||
onPressed: onPressed,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Floating "Next episode ›" from the ED (or the last two minutes):
|
||||
/// faint at rest, lit on hover. Lives outside the auto-hiding controls, so
|
||||
/// it shows in fullscreen and with the controls hidden.
|
||||
class NextEpisodePill extends StatelessWidget {
|
||||
final EpisodeLink episode;
|
||||
final VoidCallback onPressed;
|
||||
const NextEpisodePill({super.key, required this.episode, required this.onPressed});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => FloatingPill(
|
||||
label: 'Next episode',
|
||||
tooltip: 'Next: ${episode.label}',
|
||||
tapKey: const ValueKey('next-episode-pill'),
|
||||
onPressed: onPressed,
|
||||
);
|
||||
}
|
||||
|
||||
/// At the end of an episode: "Next: S1E7 title" with Play now, and while
|
||||
/// the auto-advance countdown runs, the seconds left and Cancel.
|
||||
class EndOfEpisodeCard extends StatelessWidget {
|
||||
final EpisodeLink next;
|
||||
final AutoAdvance? countdown;
|
||||
final VoidCallback onPlayNow;
|
||||
final VoidCallback onCancel;
|
||||
const EndOfEpisodeCard({
|
||||
super.key,
|
||||
required this.next,
|
||||
required this.countdown,
|
||||
required this.onPlayNow,
|
||||
required this.onCancel,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
final c = countdown;
|
||||
return Card(
|
||||
key: const ValueKey('end-of-episode'),
|
||||
color: Colors.black.withValues(alpha: 0.85),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 12, 12),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 380),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(c == null ? 'Up next' : 'Next episode in ${c.secondsLeft} s',
|
||||
style: t.labelLarge?.copyWith(color: Colors.white70)),
|
||||
const SizedBox(height: 4),
|
||||
Text('Next: ${next.label}',
|
||||
maxLines: 2, overflow: TextOverflow.ellipsis, style: t.titleMedium),
|
||||
if (c != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
LinearProgressIndicator(value: c.secondsLeft / autoAdvanceSecs),
|
||||
],
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (c != null)
|
||||
TextButton(
|
||||
key: const ValueKey('auto-advance-cancel'),
|
||||
onPressed: onCancel,
|
||||
child: const Text('Cancel')),
|
||||
const SizedBox(width: 8),
|
||||
FilledButton.icon(
|
||||
key: const ValueKey('play-next'),
|
||||
onPressed: onPlayNow,
|
||||
icon: const Icon(Icons.skip_next_rounded, size: 18),
|
||||
label: Text(c == null ? 'Play next' : 'Play now'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// This viewer cannot play the Jellyfin media: say why and offer to link
|
||||
/// an account (never a silent stall).
|
||||
class JellyfinBlockedCard extends StatelessWidget {
|
||||
final BlockedPlay blocked;
|
||||
final VoidCallback onLinkAccount;
|
||||
final VoidCallback onRetry;
|
||||
const JellyfinBlockedCard(
|
||||
{super.key, required this.blocked, required this.onLinkAccount, required this.onRetry});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return Card(
|
||||
key: const ValueKey('jellyfin-blocked'),
|
||||
color: Colors.black.withValues(alpha: 0.85),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 440),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.lock_outline, color: Colors.orange, size: 32),
|
||||
const SizedBox(height: 10),
|
||||
Text(blocked.message, textAlign: TextAlign.center, style: t.titleSmall),
|
||||
const SizedBox(height: 6),
|
||||
Text('Link your own account in Integrations, or ask the host to relay it.',
|
||||
textAlign: TextAlign.center, style: t.bodySmall?.copyWith(color: Colors.grey)),
|
||||
const SizedBox(height: 14),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
children: [
|
||||
FilledButton(
|
||||
key: const ValueKey('link-jellyfin-account'),
|
||||
onPressed: onLinkAccount,
|
||||
child: const Text('Link a Jellyfin account')),
|
||||
TextButton(onPressed: onRetry, child: const Text('Try again')),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Small member-list badge: plays the Jellyfin item through the host.
|
||||
class ViaHostBadge extends StatelessWidget {
|
||||
const ViaHostBadge({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Tooltip(
|
||||
message: 'No Jellyfin account here: watches through the host',
|
||||
child: Container(
|
||||
key: const ValueKey('via-host'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white10,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
border: Border.all(color: Colors.white24),
|
||||
),
|
||||
child: const Text('via host', style: TextStyle(fontSize: 10, color: Colors.white70)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,624 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:sync_relay_core/core.dart' show JellyfinStreamType;
|
||||
|
||||
import '../../jellyfin/track_prefs.dart' show MpvTrack;
|
||||
import '../../playback/media_marks.dart';
|
||||
|
||||
// Session control-bar pieces built on the playback signals (chapters,
|
||||
// tracks, skip offers): the seek bar with chapter marks, the chapter and
|
||||
// track menus, the 1:30 skip button and the floating skip pill. Plain
|
||||
// widgets fed by values and callbacks, so tests pump them without a player.
|
||||
|
||||
/// Keeps media_kit's desktop controls shown, as a mouse hover would.
|
||||
/// While a seek bar drag runs no hover events arrive, and the controls
|
||||
/// would hide (and unmount the bar) mid-drag. A guarded dynamic call on
|
||||
/// the private controls state; nothing happens outside those controls.
|
||||
void keepVideoControlsAwake(BuildContext context) {
|
||||
context.visitAncestorElements((e) {
|
||||
if (e is StatefulElement &&
|
||||
e.state.runtimeType.toString() == '_MaterialDesktopVideoControlsState') {
|
||||
try {
|
||||
(e.state as dynamic).onHover();
|
||||
} catch (_) {}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/// The seek bar: played / buffered track, a diamond at each chapter start
|
||||
/// (not the one at 0), and on hover the time with the chapter title above
|
||||
/// it. Like media_kit's bar it reports a seek on every drag move and on
|
||||
/// release ([onSeek]); the session routes those through the user-seek path
|
||||
/// (debounced, everyone follows).
|
||||
class ChapterSeekBar extends StatefulWidget {
|
||||
final Duration position;
|
||||
final Duration duration;
|
||||
final Duration buffer;
|
||||
final List<MediaChapter> chapters;
|
||||
final ValueChanged<Duration> onSeek;
|
||||
/// Any pointer activity on the bar (keeps the controls up).
|
||||
final VoidCallback? onActivity;
|
||||
const ChapterSeekBar({
|
||||
super.key,
|
||||
required this.position,
|
||||
required this.duration,
|
||||
this.buffer = Duration.zero,
|
||||
this.chapters = const [],
|
||||
required this.onSeek,
|
||||
this.onActivity,
|
||||
});
|
||||
|
||||
static const height = 28.0;
|
||||
|
||||
@override
|
||||
State<ChapterSeekBar> createState() => _ChapterSeekBarState();
|
||||
}
|
||||
|
||||
class _ChapterSeekBarState extends State<ChapterSeekBar> {
|
||||
double? _hoverX;
|
||||
bool _dragging = false;
|
||||
double _dragFraction = 0;
|
||||
|
||||
double _fraction(Duration d) {
|
||||
final total = widget.duration.inMicroseconds;
|
||||
if (total <= 0) return 0;
|
||||
return (d.inMicroseconds / total).clamp(0.0, 1.0);
|
||||
}
|
||||
|
||||
Duration _at(double fraction) => widget.duration * fraction.clamp(0.0, 1.0);
|
||||
|
||||
void _seekTo(double x, double width) {
|
||||
if (widget.duration <= Duration.zero || width <= 0) return;
|
||||
_dragFraction = (x / width).clamp(0.0, 1.0);
|
||||
widget.onSeek(_at(_dragFraction));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final primary = Theme.of(context).colorScheme.primary;
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
final width = constraints.maxWidth;
|
||||
final active = _hoverX != null || _dragging;
|
||||
final barHeight = active ? 5.0 : 3.0;
|
||||
final played = _dragging ? _dragFraction : _fraction(widget.position);
|
||||
const mid = ChapterSeekBar.height / 2;
|
||||
final hoverX = _hoverX;
|
||||
final hoverAt = hoverX == null || width <= 0 ? null : _at(hoverX / width);
|
||||
final hoverChapter = hoverAt == null ? null : chapterIndexAt(widget.chapters, hoverAt);
|
||||
final hoverTitle = hoverChapter == null ? '' : widget.chapters[hoverChapter].title;
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (e) => setState(() => _hoverX = e.localPosition.dx.clamp(0, width)),
|
||||
onHover: (e) {
|
||||
setState(() => _hoverX = e.localPosition.dx.clamp(0, width));
|
||||
widget.onActivity?.call();
|
||||
},
|
||||
onExit: (_) => setState(() => _hoverX = null),
|
||||
child: Listener(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onPointerDown: (e) {
|
||||
widget.onActivity?.call();
|
||||
setState(() {
|
||||
_dragging = true;
|
||||
_dragFraction = width <= 0 ? 0 : (e.localPosition.dx / width).clamp(0.0, 1.0);
|
||||
});
|
||||
},
|
||||
onPointerMove: (e) {
|
||||
widget.onActivity?.call();
|
||||
setState(() => _hoverX = e.localPosition.dx.clamp(0, width));
|
||||
_seekTo(e.localPosition.dx, width);
|
||||
},
|
||||
onPointerUp: (e) {
|
||||
_seekTo(e.localPosition.dx, width);
|
||||
setState(() => _dragging = false);
|
||||
widget.onActivity?.call();
|
||||
},
|
||||
onPointerCancel: (_) => setState(() => _dragging = false),
|
||||
child: SizedBox(
|
||||
key: const ValueKey('seek-bar'),
|
||||
width: width,
|
||||
height: ChapterSeekBar.height,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: mid - barHeight / 2,
|
||||
height: barHeight,
|
||||
child: Container(color: Colors.white24),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: mid - barHeight / 2,
|
||||
height: barHeight,
|
||||
width: width * _fraction(widget.buffer),
|
||||
child: Container(color: Colors.white24),
|
||||
),
|
||||
if (hoverX != null && !_dragging)
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: mid - barHeight / 2,
|
||||
height: barHeight,
|
||||
width: hoverX,
|
||||
child: Container(color: Colors.white24),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: mid - barHeight / 2,
|
||||
height: barHeight,
|
||||
width: width * played,
|
||||
child: Container(color: primary),
|
||||
),
|
||||
for (final c in widget.chapters)
|
||||
if (c.start > Duration.zero && widget.duration > Duration.zero)
|
||||
Positioned(
|
||||
key: ValueKey('chapter-mark-${c.index}'),
|
||||
left: width * _fraction(c.start) - 4,
|
||||
top: mid - 4,
|
||||
width: 8,
|
||||
height: 8,
|
||||
child: IgnorePointer(
|
||||
child: Transform.rotate(
|
||||
angle: math.pi / 4,
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(1),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border.all(color: Colors.black54, width: 0.8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (active)
|
||||
Positioned(
|
||||
left: width * played - 6,
|
||||
top: mid - 6,
|
||||
width: 12,
|
||||
height: 12,
|
||||
child: IgnorePointer(
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(color: primary, shape: BoxShape.circle),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (hoverAt != null)
|
||||
Positioned(
|
||||
// Kept clear of the window edges (the tip is centred).
|
||||
left: hoverX!.clamp(math.min(60.0, width / 2), math.max(width - 60, width / 2)),
|
||||
bottom: ChapterSeekBar.height - 2,
|
||||
child: IgnorePointer(
|
||||
child: FractionalTranslation(
|
||||
translation: const Offset(-0.5, 0),
|
||||
child: _HoverTip(title: hoverTitle, time: formatClock(hoverAt)),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _HoverTip extends StatelessWidget {
|
||||
final String title;
|
||||
final String time;
|
||||
const _HoverTip({required this.title, required this.time});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
constraints: const BoxConstraints(maxWidth: 320),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(alpha: 0.8),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (title.isNotEmpty)
|
||||
Text(title,
|
||||
key: const ValueKey('seek-hover-chapter'),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w600)),
|
||||
Text(time,
|
||||
key: const ValueKey('seek-hover-time'),
|
||||
style: const TextStyle(color: Colors.white70, fontSize: 11)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// [ChapterSeekBar] on a live player: position, duration and buffer from
|
||||
/// its streams. Seeks go to `player.seek`, which the session's
|
||||
/// `SyncPlayer` turns into user seeks.
|
||||
class PlayerSeekBar extends StatefulWidget {
|
||||
final Player player;
|
||||
final List<MediaChapter> chapters;
|
||||
const PlayerSeekBar({super.key, required this.player, required this.chapters});
|
||||
|
||||
@override
|
||||
State<PlayerSeekBar> createState() => _PlayerSeekBarState();
|
||||
}
|
||||
|
||||
class _PlayerSeekBarState extends State<PlayerSeekBar> {
|
||||
final List<StreamSubscription<Object>> _subs = [];
|
||||
late Duration _position, _duration, _buffer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_listen();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(PlayerSeekBar old) {
|
||||
super.didUpdateWidget(old);
|
||||
if (!identical(old.player, widget.player)) {
|
||||
_cancel();
|
||||
_listen();
|
||||
}
|
||||
}
|
||||
|
||||
void _listen() {
|
||||
final p = widget.player;
|
||||
_position = p.state.position;
|
||||
_duration = p.state.duration;
|
||||
_buffer = p.state.buffer;
|
||||
void set(VoidCallback f) {
|
||||
if (mounted) setState(f);
|
||||
}
|
||||
|
||||
_subs.addAll([
|
||||
p.stream.position.listen((d) => set(() => _position = d)),
|
||||
p.stream.duration.listen((d) => set(() => _duration = d)),
|
||||
p.stream.buffer.listen((d) => set(() => _buffer = d)),
|
||||
]);
|
||||
}
|
||||
|
||||
void _cancel() {
|
||||
for (final s in _subs) {
|
||||
s.cancel();
|
||||
}
|
||||
_subs.clear();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChapterSeekBar(
|
||||
position: _position,
|
||||
duration: _duration,
|
||||
buffer: _buffer,
|
||||
chapters: widget.chapters,
|
||||
onSeek: (d) => widget.player.seek(d),
|
||||
onActivity: () => keepVideoControlsAwake(context),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RelativeRect _menuPosition(BuildContext context) {
|
||||
final button = context.findRenderObject() as RenderBox;
|
||||
final overlay = Navigator.of(context).overlay!.context.findRenderObject() as RenderBox;
|
||||
return RelativeRect.fromRect(
|
||||
Rect.fromPoints(
|
||||
button.localToGlobal(Offset.zero, ancestor: overlay),
|
||||
button.localToGlobal(button.size.bottomRight(Offset.zero), ancestor: overlay),
|
||||
),
|
||||
Offset.zero & overlay.size,
|
||||
);
|
||||
}
|
||||
|
||||
/// Control-bar icon with a small count in the corner.
|
||||
class _BadgedIcon extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final int count;
|
||||
const _BadgedIcon(this.icon, this.count);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Icon(icon),
|
||||
if (count > 0)
|
||||
Positioned(
|
||||
right: -7,
|
||||
top: -5,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 0.5),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
child: Text('$count',
|
||||
style: const TextStyle(color: Colors.white, fontSize: 9, fontWeight: FontWeight.bold)),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Chapter list for the controls: current chapter checked, a pick seeks
|
||||
/// to its start. Nothing when the file has no chapters.
|
||||
class ChaptersControlButton extends StatelessWidget {
|
||||
final List<MediaChapter> chapters;
|
||||
final int? current;
|
||||
final ValueChanged<MediaChapter> onPick;
|
||||
final FocusNode? focusNode;
|
||||
final ValueChanged<bool>? onMenuOpen;
|
||||
const ChaptersControlButton({
|
||||
super.key,
|
||||
required this.chapters,
|
||||
required this.current,
|
||||
required this.onPick,
|
||||
this.focusNode,
|
||||
this.onMenuOpen,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (chapters.isEmpty) return const SizedBox.shrink();
|
||||
return Tooltip(
|
||||
message: 'Chapters (PgUp / PgDn)',
|
||||
child: IconButton(
|
||||
key: const ValueKey('chapters-button'),
|
||||
focusNode: focusNode,
|
||||
color: Colors.white,
|
||||
iconSize: 20,
|
||||
visualDensity: VisualDensity.compact,
|
||||
icon: _BadgedIcon(Icons.format_list_bulleted, chapters.length),
|
||||
onPressed: () => _open(context),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _open(BuildContext context) async {
|
||||
final position = _menuPosition(context);
|
||||
onMenuOpen?.call(true);
|
||||
final pick = await showMenu<MediaChapter>(
|
||||
context: context,
|
||||
position: position,
|
||||
popUpAnimationStyle: AnimationStyle.noAnimation,
|
||||
constraints: const BoxConstraints(minWidth: 240, maxWidth: 420),
|
||||
items: [
|
||||
for (final c in chapters)
|
||||
CheckedPopupMenuItem(
|
||||
value: c,
|
||||
checked: c.index == current,
|
||||
height: 36,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(c.title.isEmpty ? 'Chapter ${c.index + 1}' : c.title,
|
||||
maxLines: 1, overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(formatClock(c.start), style: const TextStyle(fontSize: 12, color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
onMenuOpen?.call(false);
|
||||
if (pick != null) onPick(pick);
|
||||
}
|
||||
}
|
||||
|
||||
/// A track pick from [TrackMenuButton]: audio id, subtitle id, or off.
|
||||
typedef TrackPick = ({int? aid, int? sid, bool subtitlesOff});
|
||||
|
||||
/// Audio or subtitle menu for the controls bar (the count of tracks on the
|
||||
/// icon): "Japanese · E-AC3 2.0 · title", mpv's selection checked,
|
||||
/// subtitles with Off. The choice is remembered for the next Jellyfin item
|
||||
/// (per viewer).
|
||||
class TrackMenuButton extends StatelessWidget {
|
||||
final JellyfinStreamType type;
|
||||
/// All tracks; only those of [type] are listed.
|
||||
final List<MpvTrack> tracks;
|
||||
final void Function(TrackPick pick) onPick;
|
||||
final FocusNode? focusNode;
|
||||
final ValueChanged<bool>? onMenuOpen;
|
||||
const TrackMenuButton({
|
||||
super.key,
|
||||
required this.type,
|
||||
required this.tracks,
|
||||
required this.onPick,
|
||||
this.focusNode,
|
||||
this.onMenuOpen,
|
||||
});
|
||||
|
||||
bool get _audio => type == JellyfinStreamType.audio;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final list = tracks.where((t) => t.type == type).toList();
|
||||
return Tooltip(
|
||||
message: _audio ? 'Audio' : 'Subtitles',
|
||||
child: IconButton(
|
||||
key: ValueKey(_audio ? 'audio-button' : 'subtitles-button'),
|
||||
focusNode: focusNode,
|
||||
color: Colors.white,
|
||||
iconSize: 20,
|
||||
visualDensity: VisualDensity.compact,
|
||||
icon: _BadgedIcon(_audio ? Icons.audiotrack_outlined : Icons.subtitles_outlined, list.length),
|
||||
onPressed: () => _open(context, list),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _open(BuildContext context, List<MpvTrack> list) async {
|
||||
final position = _menuPosition(context);
|
||||
onMenuOpen?.call(true);
|
||||
final pick = await showMenu<TrackPick>(
|
||||
context: context,
|
||||
position: position,
|
||||
popUpAnimationStyle: AnimationStyle.noAnimation,
|
||||
constraints: const BoxConstraints(minWidth: 280, maxWidth: 460),
|
||||
items: [
|
||||
if (!_audio)
|
||||
CheckedPopupMenuItem(
|
||||
value: (aid: null, sid: null, subtitlesOff: true),
|
||||
checked: !list.any((t) => t.selected),
|
||||
height: 36,
|
||||
child: const Text('Off'),
|
||||
),
|
||||
if (_audio && list.isEmpty)
|
||||
const PopupMenuItem(enabled: false, height: 32, child: Text('None')),
|
||||
for (final t in list)
|
||||
CheckedPopupMenuItem(
|
||||
value: _audio
|
||||
? (aid: t.id, sid: null, subtitlesOff: false)
|
||||
: (aid: null, sid: t.id, subtitlesOff: false),
|
||||
checked: t.selected,
|
||||
height: 36,
|
||||
child: Text(t.label, maxLines: 1, overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
],
|
||||
);
|
||||
onMenuOpen?.call(false);
|
||||
if (pick != null) onPick(pick);
|
||||
}
|
||||
}
|
||||
|
||||
/// "1:30" in the controls: skip forward [fallbackSkip] (Shift+Right).
|
||||
class SkipForwardButton extends StatelessWidget {
|
||||
final VoidCallback onPressed;
|
||||
final FocusNode? focusNode;
|
||||
const SkipForwardButton({super.key, required this.onPressed, this.focusNode});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Tooltip(
|
||||
message: 'Skip 1:30 for everyone (Shift+Right)',
|
||||
child: TextButton.icon(
|
||||
key: const ValueKey('skip-forward-button'),
|
||||
focusNode: focusNode,
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
onPressed: onPressed,
|
||||
icon: const Icon(Icons.fast_forward_rounded, size: 16),
|
||||
label: const Text('1:30', style: TextStyle(fontSize: 12)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Floating pill over the video (Next episode, Skip OP / ED / 1:30):
|
||||
/// faint at rest, lit on hover. Lives outside the auto-hiding controls, so
|
||||
/// it shows in fullscreen and with the controls hidden.
|
||||
class FloatingPill extends StatefulWidget {
|
||||
final String label;
|
||||
final String tooltip;
|
||||
final IconData icon;
|
||||
final VoidCallback onPressed;
|
||||
/// Key of the tap target (tests find the pill by it).
|
||||
final Key? tapKey;
|
||||
const FloatingPill({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.tooltip,
|
||||
required this.onPressed,
|
||||
this.icon = Icons.chevron_right,
|
||||
this.tapKey,
|
||||
});
|
||||
|
||||
@override
|
||||
State<FloatingPill> createState() => _FloatingPillState();
|
||||
}
|
||||
|
||||
class _FloatingPillState extends State<FloatingPill> {
|
||||
bool _hover = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final primary = Theme.of(context).colorScheme.primary;
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) => setState(() => _hover = true),
|
||||
onExit: (_) => setState(() => _hover = false),
|
||||
child: Tooltip(
|
||||
message: widget.tooltip,
|
||||
child: AnimatedScale(
|
||||
duration: const Duration(milliseconds: 150),
|
||||
scale: _hover ? 1.06 : 1,
|
||||
child: AnimatedOpacity(
|
||||
duration: const Duration(milliseconds: 150),
|
||||
opacity: _hover ? 1 : 0.45,
|
||||
child: GestureDetector(
|
||||
key: widget.tapKey,
|
||||
onTap: widget.onPressed,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 150),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 9),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(alpha: 0.75),
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
border: Border.all(color: _hover ? primary : Colors.white24),
|
||||
boxShadow: _hover
|
||||
? [BoxShadow(color: primary.withValues(alpha: 0.45), blurRadius: 16)]
|
||||
: const [],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(widget.label, style: const TextStyle(color: Colors.white, fontSize: 13)),
|
||||
const SizedBox(width: 4),
|
||||
Icon(widget.icon, color: Colors.white, size: 18),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// "Skip OP" / "Skip ED" / "Skip 1:30" for a [SkipOffer].
|
||||
class SkipPill extends StatelessWidget {
|
||||
final SkipOffer offer;
|
||||
final VoidCallback onPressed;
|
||||
const SkipPill({super.key, required this.offer, required this.onPressed});
|
||||
|
||||
static String labelFor(SkipKind kind) => switch (kind) {
|
||||
SkipKind.opening => 'Skip OP',
|
||||
SkipKind.ending => 'Skip ED',
|
||||
SkipKind.fixed => 'Skip 1:30',
|
||||
};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FloatingPill(
|
||||
label: labelFor(offer.kind),
|
||||
tooltip: offer.kind == SkipKind.fixed
|
||||
? 'Skip 1:30 for everyone (Shift+Right)'
|
||||
: 'Skip to ${formatClock(offer.target)} for everyone',
|
||||
icon: Icons.fast_forward_rounded,
|
||||
tapKey: const ValueKey('skip-pill'),
|
||||
onPressed: onPressed,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../jellyfin/accounts.dart';
|
||||
import '../../jellyfin/browse_scope.dart' show BrowseStart;
|
||||
import '../home/media_picker.dart';
|
||||
|
||||
/// "Change video" in a session: the same [MediaPicker] as Home's Host tab
|
||||
/// (Jellyfin browser, Link, File) and a button that puts the pick up for
|
||||
/// everyone. File is offered to the host only (the file streams from the
|
||||
/// host's disk). [onSwap] returns an error text, or null when sent.
|
||||
class SwapPanel extends StatefulWidget {
|
||||
final MediaPickerController controller;
|
||||
final JellyfinAccounts accounts;
|
||||
final bool isHost;
|
||||
final BrowseStart? jellyfinStart;
|
||||
final Future<String?> Function(PickedMedia media) onSwap;
|
||||
final VoidCallback onClose;
|
||||
final VoidCallback? onOpenIntegrations;
|
||||
const SwapPanel({
|
||||
super.key,
|
||||
required this.controller,
|
||||
required this.accounts,
|
||||
required this.isHost,
|
||||
required this.onSwap,
|
||||
required this.onClose,
|
||||
this.jellyfinStart,
|
||||
this.onOpenIntegrations,
|
||||
});
|
||||
|
||||
@override
|
||||
State<SwapPanel> createState() => _SwapPanelState();
|
||||
}
|
||||
|
||||
class _SwapPanelState extends State<SwapPanel> {
|
||||
bool _busy = false;
|
||||
String? _error;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final c = widget.controller;
|
||||
if (!widget.isHost && c.source == MediaKind.file) c.source = MediaKind.link;
|
||||
}
|
||||
|
||||
Future<void> _swap() async {
|
||||
final media = widget.controller.selection;
|
||||
if (media == null || _busy) return;
|
||||
setState(() {
|
||||
_busy = true;
|
||||
_error = null;
|
||||
});
|
||||
String? error;
|
||||
try {
|
||||
error = await widget.onSwap(media);
|
||||
} catch (e) {
|
||||
error = '$e';
|
||||
}
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_busy = false;
|
||||
_error = error;
|
||||
});
|
||||
if (error == null) widget.onClose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return Material(
|
||||
key: const ValueKey('swap-panel'),
|
||||
elevation: 12,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 12, 12, 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: Text('Change video', style: t.titleLarge)),
|
||||
IconButton(
|
||||
tooltip: 'Close (Esc)', icon: const Icon(Icons.close), onPressed: widget.onClose),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: MediaPicker(
|
||||
controller: widget.controller,
|
||||
jellyfin: widget.accounts,
|
||||
enabled: !_busy,
|
||||
allowFile: widget.isHost,
|
||||
jellyfinStart: widget.jellyfinStart,
|
||||
onOpenIntegrations: widget.onOpenIntegrations,
|
||||
onSubmit: _swap,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
ListenableBuilder(
|
||||
listenable: widget.controller,
|
||||
builder: (context, _) {
|
||||
final sel = widget.controller.selection;
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
_error ?? (sel == null ? 'Pick something to watch' : 'Put up: ${sel.label}'),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: t.bodyMedium?.copyWith(
|
||||
color: _error != null ? Theme.of(context).colorScheme.error : null),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
FilledButton.icon(
|
||||
key: const ValueKey('swap-go'),
|
||||
onPressed: sel == null || _busy ? null : _swap,
|
||||
icon: _busy
|
||||
? const SizedBox(
|
||||
width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Icon(Icons.swap_horiz),
|
||||
label: const Text('Put it up for everyone'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,31 @@ import 'package:media_kit_video/media_kit_video.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import '../controls/uosc/buttons.dart';
|
||||
import '../controls/uosc/controls.dart';
|
||||
import '../controls/uosc/timeline.dart';
|
||||
import '../playback/media_marks.dart' show SkipOffer;
|
||||
|
||||
import '../jellyfin/browse_scope.dart' show BrowseStart;
|
||||
import '../jellyfin/session_media.dart';
|
||||
import '../session/health.dart';
|
||||
import '../session/session_coordinator.dart';
|
||||
import '../shaders/shader_menu.dart';
|
||||
import '../shaders/shader_presets.dart';
|
||||
import '../state/settings.dart';
|
||||
import '../state/session_state.dart';
|
||||
import '../update/updater.dart';
|
||||
import '../widgets/dialogs.dart';
|
||||
import '../widgets/member_avatar.dart';
|
||||
import '../widgets/shown_frame_probe.dart';
|
||||
import '../widgets/text_focus.dart';
|
||||
import '../widgets/window_buttons.dart';
|
||||
import '../widgets/window_drag_layer.dart';
|
||||
import 'home/integrations_page.dart';
|
||||
import 'home/media_picker.dart';
|
||||
import 'session/jellyfin_widgets.dart';
|
||||
import 'session/player_controls.dart';
|
||||
import 'session/swap_panel.dart';
|
||||
|
||||
class SessionScreen extends StatefulWidget {
|
||||
const SessionScreen({super.key});
|
||||
@@ -20,29 +38,43 @@ class SessionScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SessionScreenState extends State<SessionScreen> {
|
||||
VideoController? _video;
|
||||
final _videoKey = GlobalKey<VideoState>();
|
||||
// One key per player generation: a reloaded player needs a fresh
|
||||
// `Video` (it never swaps controllers in place).
|
||||
var _videoGen = -1;
|
||||
var _videoKey = GlobalKey<VideoState>();
|
||||
bool _refullscreen = false;
|
||||
final _frameProbe = ShownFrameProbe();
|
||||
final _sheetOpen = signal(false);
|
||||
final _confirmLeave = signal(false);
|
||||
final _isFullscreen = signal(false);
|
||||
DateTime? _lastKeyAt;
|
||||
final _chat = TextEditingController();
|
||||
final _chatFocus = FocusNode();
|
||||
final _swapLink = TextEditingController();
|
||||
// "Change video": the shared media picker over the video.
|
||||
final _swapOpen = signal(false);
|
||||
MediaPickerController? _swapPicker;
|
||||
bool _integrationsOpen = false;
|
||||
late final void Function() _stopKickWatch;
|
||||
late final void Function() _stopSheetWatch;
|
||||
late final void Function() _stopPlayerWatch;
|
||||
late final void Function() _stopShaderWatch;
|
||||
late final FocusNode _noFocus;
|
||||
bool _shaderMenuOpen = false;
|
||||
// Own toast ids, negative: the coordinator counts up from 1.
|
||||
int _toastSeq = 0;
|
||||
int _shaderNoticeSeen = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final session = SessionState.instance;
|
||||
_noFocus = FocusNode(skipTraversal: true, canRequestFocus: false);
|
||||
_video = VideoController(session.coordinator.playback.player);
|
||||
session.coordinator.jellyfin.ensureLoaded();
|
||||
session.coordinator.playback.shownFrame = _frameProbe.sample;
|
||||
HardwareKeyboard.instance.addHandler(_globalKey);
|
||||
_stopKickWatch = effect(() {
|
||||
if (session.coordinator.kickReason.value != null) {
|
||||
session.route.value = AppRoute.connect;
|
||||
session.route.value = AppRoute.home;
|
||||
}
|
||||
});
|
||||
_stopSheetWatch = effect(() {
|
||||
@@ -50,6 +82,61 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
}
|
||||
});
|
||||
// Shader messages (preset changes, load failures) become toasts.
|
||||
_stopShaderWatch = effect(() {
|
||||
final n = session.coordinator.playback.shaderNotice.value;
|
||||
if (n == null || n.id == _shaderNoticeSeen) return;
|
||||
_shaderNoticeSeen = n.id;
|
||||
_toast(n.text);
|
||||
});
|
||||
// The fullscreen route holds its own `Video` of the old player: leave
|
||||
// it before the player goes away, re-enter once the new one is up.
|
||||
_stopPlayerWatch = effect(() {
|
||||
final alive = session.coordinator.playback.alive.value;
|
||||
if (!alive && _isFullscreen.peek()) {
|
||||
_refullscreen = true;
|
||||
if (mounted) Navigator.of(context, rootNavigator: true).maybePop();
|
||||
} else if (alive && _refullscreen) {
|
||||
_refullscreen = false;
|
||||
// Entering before the new output's first frame leaves the
|
||||
// fullscreen copy blank for good (seen in a real run).
|
||||
() async {
|
||||
try {
|
||||
await session.coordinator.playback.video.waitUntilFirstFrameRendered
|
||||
.timeout(const Duration(seconds: 10));
|
||||
} catch (_) {}
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
if (mounted && !_isFullscreen.peek() && session.coordinator.playback.alive.peek()) {
|
||||
_videoKey.currentState?.enterFullscreen();
|
||||
}
|
||||
}();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _reloadVideo() {
|
||||
final coord = SessionState.instance.coordinator;
|
||||
coord.markInput();
|
||||
coord.reloadVideo();
|
||||
}
|
||||
|
||||
void _toast(String text) {
|
||||
final coord = SessionState.instance.coordinator;
|
||||
coord.toasts.value = [
|
||||
...coord.toasts.peek(),
|
||||
ToastItem(id: --_toastSeq, text: text, at: DateTime.now().toUtc()),
|
||||
];
|
||||
}
|
||||
|
||||
/// Menu, Ctrl+0..6: saved as the choice (also used on the next join)
|
||||
/// and applied live. A null quality keeps the saved one.
|
||||
void _pickShader(ShaderPreset preset, ShaderQuality? quality) {
|
||||
final s = AppSettings.instance;
|
||||
if (quality != null) s.setShaderQuality(quality);
|
||||
s.setShaderPreset(preset);
|
||||
final coord = SessionState.instance.coordinator;
|
||||
coord.markInput();
|
||||
coord.playback.applyShaders(announce: true);
|
||||
}
|
||||
|
||||
void _toggleFullscreen() {
|
||||
@@ -65,39 +152,128 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
@override
|
||||
void dispose() {
|
||||
HardwareKeyboard.instance.removeHandler(_globalKey);
|
||||
final playback = SessionState.instance.coordinator.playback;
|
||||
if (playback.shownFrame == _frameProbe.sample) playback.shownFrame = null;
|
||||
_stopKickWatch();
|
||||
_stopSheetWatch();
|
||||
_stopPlayerWatch();
|
||||
_stopShaderWatch();
|
||||
_chat.dispose();
|
||||
_chatFocus.dispose();
|
||||
_swapLink.dispose();
|
||||
_swapPicker?.dispose();
|
||||
_noFocus.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
bool get _editing {
|
||||
var n = FocusManager.instance.primaryFocus;
|
||||
while (n != null) {
|
||||
final w = n.context?.widget;
|
||||
if (w is EditableText) return true;
|
||||
n = n.parent;
|
||||
/// Opens the swap panel: the browser starts on the series of the
|
||||
/// episode playing (season selected, episode highlighted), else where it
|
||||
/// was last.
|
||||
void _openSwap() {
|
||||
final coord = SessionState.instance.coordinator;
|
||||
coord.markInput();
|
||||
final ref = coord.currentRef.peek();
|
||||
final accounts = coord.jellyfin;
|
||||
final pick = ref == null ? null : pickForRef(accounts, ref);
|
||||
final plan = coord.jellyfinPlan.peek();
|
||||
_swapPicker?.dispose();
|
||||
_swapPicker = MediaPickerController(
|
||||
jellyfin: pick,
|
||||
source: pick != null || (accounts.loaded && !accounts.isEmpty)
|
||||
? MediaKind.jellyfin
|
||||
: MediaKind.link,
|
||||
);
|
||||
_swapStart = ref != null && plan is OwnPlay && plan.item != null
|
||||
? BrowseStart.seriesOf(ref.serverId, plan.item!)
|
||||
: null;
|
||||
_sheetOpen.value = false;
|
||||
_swapOpen.value = true;
|
||||
}
|
||||
|
||||
BrowseStart? _swapStart;
|
||||
|
||||
void _closeSwap() {
|
||||
_swapOpen.value = false;
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
}
|
||||
|
||||
/// Integrations over the session (link an account for a blocked item).
|
||||
Future<void> _openIntegrations() async {
|
||||
if (_integrationsOpen) return;
|
||||
_integrationsOpen = true;
|
||||
try {
|
||||
await Navigator.of(context, rootNavigator: true).push(MaterialPageRoute<void>(
|
||||
builder: (_) => Scaffold(
|
||||
appBar: AppBar(title: const Text('Integrations')),
|
||||
body: IntegrationsPage(jellyfin: SessionState.instance.coordinator.jellyfin),
|
||||
),
|
||||
));
|
||||
} finally {
|
||||
_integrationsOpen = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _globalKey(KeyEvent event) {
|
||||
if (event is! KeyDownEvent) return false;
|
||||
if (SessionState.instance.route.peek() != AppRoute.session) return false;
|
||||
if (_editing) return false;
|
||||
if (_integrationsOpen) return false;
|
||||
if (_swapOpen.peek()) {
|
||||
// The picker owns the keyboard; Esc outside a field closes it.
|
||||
if (event.logicalKey == LogicalKeyboardKey.escape && !textInputFocused()) {
|
||||
_closeSwap();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (textInputFocused()) return false;
|
||||
final now = DateTime.now().toUtc();
|
||||
if (_lastKeyAt != null && now.difference(_lastKeyAt!).inMilliseconds < 350) {
|
||||
return false;
|
||||
}
|
||||
final coord = SessionState.instance.coordinator;
|
||||
// Ctrl+0..6: Anime4K's own mpv keys (off, modes A..C+A).
|
||||
final digit = _shaderKeys.indexOf(event.logicalKey);
|
||||
if (digit >= 0 && HardwareKeyboard.instance.isControlPressed) {
|
||||
_lastKeyAt = now;
|
||||
_pickShader(
|
||||
digit == 0 ? ShaderPreset.off : ShaderPreset.modes[digit - 1], null);
|
||||
return true;
|
||||
}
|
||||
if (event.logicalKey == LogicalKeyboardKey.keyR &&
|
||||
HardwareKeyboard.instance.isControlPressed) {
|
||||
_lastKeyAt = now;
|
||||
_reloadVideo();
|
||||
return true;
|
||||
}
|
||||
if (event.logicalKey == LogicalKeyboardKey.space) {
|
||||
_lastKeyAt = now;
|
||||
coord.toggleReady();
|
||||
return true;
|
||||
}
|
||||
// mpv's playlist keys (< >) and Shift+P / Shift+N: Jellyfin episodes.
|
||||
final shift = HardwareKeyboard.instance.isShiftPressed;
|
||||
if (event.character == '>' || (shift && event.logicalKey == LogicalKeyboardKey.keyN)) {
|
||||
if (coord.nextEpisode.peek() == null) return false;
|
||||
_lastKeyAt = now;
|
||||
coord.playNextEpisode();
|
||||
return true;
|
||||
}
|
||||
if (event.character == '<' || (shift && event.logicalKey == LogicalKeyboardKey.keyP)) {
|
||||
if (coord.previousEpisode.peek() == null) return false;
|
||||
_lastKeyAt = now;
|
||||
coord.playPreviousEpisode();
|
||||
return true;
|
||||
}
|
||||
// mpv's chapter keys.
|
||||
if (event.logicalKey == LogicalKeyboardKey.pageDown ||
|
||||
event.logicalKey == LogicalKeyboardKey.pageUp) {
|
||||
_lastKeyAt = now;
|
||||
return coord.stepChapter(event.logicalKey == LogicalKeyboardKey.pageDown ? 1 : -1);
|
||||
}
|
||||
if (shift && event.logicalKey == LogicalKeyboardKey.arrowRight) {
|
||||
_lastKeyAt = now;
|
||||
coord.skipForward();
|
||||
return true;
|
||||
}
|
||||
if (event.logicalKey == LogicalKeyboardKey.tab) {
|
||||
_lastKeyAt = now;
|
||||
_sheetOpen.value = !_sheetOpen.peek();
|
||||
@@ -115,6 +291,10 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
return true;
|
||||
}
|
||||
if (event.logicalKey == LogicalKeyboardKey.escape) {
|
||||
if (_shaderMenuOpen) {
|
||||
if (mounted) Navigator.of(context, rootNavigator: true).maybePop();
|
||||
return true;
|
||||
}
|
||||
if (_sheetOpen.peek()) {
|
||||
_sheetOpen.value = false;
|
||||
return true;
|
||||
@@ -157,7 +337,18 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
visibleOnMount: true,
|
||||
hideMouseOnControlsRemoval: true,
|
||||
controlsHoverDuration: const Duration(seconds: 3),
|
||||
// Our seek bar (chapter marks, hover title) sits in the bottom bar,
|
||||
// which grows by its height; the top bar keeps its row at the top.
|
||||
displaySeekBar: false,
|
||||
buttonBarHeight: _barHeight + ChapterSeekBar.height,
|
||||
topButtonBar: [
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: SizedBox(
|
||||
height: _barHeight,
|
||||
child: Row(
|
||||
children: [
|
||||
const Spacer(),
|
||||
MaterialDesktopCustomButton(
|
||||
icon: const Icon(Icons.group),
|
||||
@@ -170,29 +361,54 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
builder: (context) => WindowButtons(focusNode: _noFocus, fullscreen: _isFullscreen.value, onToggleFullscreen: _toggleFullscreen),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
bottomButtonBar: [
|
||||
const MaterialDesktopVolumeButton(),
|
||||
_ReadyControlButton(focusNode: _noFocus),
|
||||
_MarkAllReadyControlButton(focusNode: _noFocus),
|
||||
const MaterialDesktopPositionIndicator(),
|
||||
const Spacer(),
|
||||
const MaterialDesktopFullscreenButton(),
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
SignalBuilder(
|
||||
builder: (context) => PlayerSeekBar(
|
||||
player: coord.playback.player,
|
||||
chapters: coord.playback.chapters.value,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Row(children: _bottomButtons(coord)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
return FocusTraversalGroup(
|
||||
descendantsAreTraversable: false,
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
body: _video == null
|
||||
? const Center(
|
||||
// Player lifetime = session (and each "Reload video"): no live
|
||||
// player ⇒ no `Video`, so no texture outlives its player.
|
||||
body: SignalBuilder(
|
||||
builder: (context) {
|
||||
final playback = coord.playback;
|
||||
final gen = playback.generation.value;
|
||||
if (!playback.alive.value) {
|
||||
return const Center(
|
||||
child: Text('player starting…', style: TextStyle(color: Colors.white)),
|
||||
)
|
||||
: MaterialDesktopVideoControlsTheme(
|
||||
);
|
||||
}
|
||||
if (gen != _videoGen) {
|
||||
_videoGen = gen;
|
||||
_videoKey = GlobalKey<VideoState>();
|
||||
}
|
||||
return MaterialDesktopVideoControlsTheme(
|
||||
normal: controlsTheme,
|
||||
fullscreen: controlsTheme,
|
||||
child: Video(
|
||||
key: _videoKey,
|
||||
controller: _video!,
|
||||
controller: playback.video,
|
||||
subtitleViewConfiguration: const SubtitleViewConfiguration(visible: false),
|
||||
controls: _sessionControls,
|
||||
onEnterFullscreen: () async {
|
||||
@@ -204,19 +420,96 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
await defaultExitNativeFullscreen();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static const _barHeight = 56.0;
|
||||
|
||||
List<Widget> _bottomButtons(SessionCoordinator coord) {
|
||||
final playback = coord.playback;
|
||||
void menuOpen(bool open) => _shaderMenuOpen = open;
|
||||
void pickTrack(TrackPick p) => coord.selectTrack(aid: p.aid, sid: p.sid, subtitlesOff: p.subtitlesOff);
|
||||
return [
|
||||
SignalBuilder(
|
||||
builder: (context) => EpisodeSkipButton(
|
||||
focusNode: _noFocus,
|
||||
episode: coord.previousEpisode.value,
|
||||
next: false,
|
||||
onPressed: coord.playPreviousEpisode,
|
||||
),
|
||||
),
|
||||
SignalBuilder(
|
||||
builder: (context) => EpisodeSkipButton(
|
||||
focusNode: _noFocus,
|
||||
episode: coord.nextEpisode.value,
|
||||
next: true,
|
||||
onPressed: coord.playNextEpisode,
|
||||
),
|
||||
),
|
||||
const MaterialDesktopVolumeButton(),
|
||||
_ReadyControlButton(focusNode: _noFocus),
|
||||
_MarkAllReadyControlButton(focusNode: _noFocus),
|
||||
_ReloadVideoControlButton(focusNode: _noFocus, onPressed: _reloadVideo),
|
||||
const MaterialDesktopPositionIndicator(),
|
||||
const Spacer(),
|
||||
SkipForwardButton(focusNode: _noFocus, onPressed: coord.skipForward),
|
||||
SignalBuilder(
|
||||
builder: (context) => ChaptersControlButton(
|
||||
focusNode: _noFocus,
|
||||
chapters: playback.chapters.value,
|
||||
current: playback.currentChapter.value,
|
||||
onPick: (c) => coord.seekTo(c.start.inMicroseconds / 1e6),
|
||||
onMenuOpen: menuOpen,
|
||||
),
|
||||
),
|
||||
SignalBuilder(
|
||||
builder: (context) => TrackMenuButton(
|
||||
focusNode: _noFocus,
|
||||
type: JellyfinStreamType.audio,
|
||||
tracks: playback.tracks.value,
|
||||
onPick: pickTrack,
|
||||
onMenuOpen: menuOpen,
|
||||
),
|
||||
),
|
||||
SignalBuilder(
|
||||
builder: (context) => TrackMenuButton(
|
||||
focusNode: _noFocus,
|
||||
type: JellyfinStreamType.subtitle,
|
||||
tracks: playback.tracks.value,
|
||||
onPick: pickTrack,
|
||||
onMenuOpen: menuOpen,
|
||||
),
|
||||
),
|
||||
ShaderControlButton(
|
||||
focusNode: _noFocus,
|
||||
renderMode: playback.renderMode,
|
||||
onPick: _pickShader,
|
||||
onMenuOpen: menuOpen,
|
||||
),
|
||||
const MaterialDesktopFullscreenButton(),
|
||||
];
|
||||
}
|
||||
|
||||
Widget _sessionControls(VideoState state) {
|
||||
return Stack(
|
||||
children: [
|
||||
MaterialDesktopVideoControls(state),
|
||||
// Frozen-picture watchdog samples the route around this anchor.
|
||||
_frameProbe.anchor(),
|
||||
// Settings → "Experimental: mpv-style controls" swaps them live.
|
||||
SessionControlsSwitch(
|
||||
material: (_) => MaterialDesktopVideoControls(state),
|
||||
mpv: (_) => _mpvControls(),
|
||||
),
|
||||
_healthOverlay(),
|
||||
_waitingOverlay(),
|
||||
_jellyfinOverlay(),
|
||||
_toastsOverlay(),
|
||||
_sheetOverlay(),
|
||||
_swapOverlay(),
|
||||
_leaveOverlay(),
|
||||
Positioned.fill(
|
||||
child: SignalBuilder(
|
||||
@@ -224,7 +517,7 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
final sheetOpen = _sheetOpen.value;
|
||||
final confirm = _confirmLeave.value;
|
||||
return WindowDragLayer(
|
||||
enabled: !confirm,
|
||||
enabled: !confirm && !_swapOpen.value,
|
||||
exclusions: [
|
||||
(s) => Rect.fromLTWH(0, s.height - 120, s.width, 120),
|
||||
if (sheetOpen) (s) => Rect.fromLTWH(s.width - 380, 0, 380, s.height),
|
||||
@@ -237,6 +530,133 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
void _openSheet() {
|
||||
_sheetOpen.value = true;
|
||||
SessionState.instance.coordinator.markInput();
|
||||
}
|
||||
|
||||
/// The experimental uosc-style controls: same actions as the bars above,
|
||||
/// all through the coordinator (seeks via `player.seek`, the user path).
|
||||
Widget _mpvControls() {
|
||||
final coord = SessionState.instance.coordinator;
|
||||
final playback = coord.playback;
|
||||
void menuOpen(bool open) => _shaderMenuOpen = open;
|
||||
void pickTrack(TrackPick p) => coord.selectTrack(aid: p.aid, sid: p.sid, subtitlesOff: p.subtitlesOff);
|
||||
Widget episode(bool next) => SignalBuilder(builder: (context) {
|
||||
final e = next ? coord.nextEpisode.value : coord.previousEpisode.value;
|
||||
if (e == null) return const SizedBox.shrink();
|
||||
return UoscButton(
|
||||
key: ValueKey(next ? 'episode-next' : 'episode-previous'),
|
||||
icon: next ? Icons.skip_next_rounded : Icons.skip_previous_rounded,
|
||||
tooltip: '${next ? 'Next' : 'Previous'}: ${e.label} (${next ? '> or Shift+N' : '< or Shift+P'})',
|
||||
onPressed: next ? coord.playNextEpisode : coord.playPreviousEpisode,
|
||||
);
|
||||
});
|
||||
return UoscControls(
|
||||
onDoubleTap: _toggleFullscreen,
|
||||
top: SignalBuilder(
|
||||
builder: (context) =>
|
||||
WindowButtons(focusNode: _noFocus, fullscreen: _isFullscreen.value, onToggleFullscreen: _toggleFullscreen),
|
||||
),
|
||||
timeline: (context, expanded) => SignalBuilder(
|
||||
builder: (context) => UoscTimeline(
|
||||
position: playback.position.value,
|
||||
duration: playback.duration.value,
|
||||
buffered: playback.buffered.value,
|
||||
chapters: playback.chapters.value,
|
||||
expanded: expanded,
|
||||
onSeek: (d) => playback.player.seek(d),
|
||||
),
|
||||
),
|
||||
left: [
|
||||
UoscMainMenuButton(
|
||||
onMenuOpen: menuOpen,
|
||||
actions: [
|
||||
(title: 'Change video', hint: null, run: _openSwap),
|
||||
(title: 'People & chat', hint: 'Tab', run: _openSheet),
|
||||
(title: 'Reload video', hint: 'Ctrl+R', run: _reloadVideo),
|
||||
(title: 'Mark everyone ready', hint: null, run: coord.forcePlayAll),
|
||||
(title: 'Fullscreen', hint: 'F', run: _toggleFullscreen),
|
||||
(title: 'Leave server', hint: 'Esc', run: () => _confirmLeave.value = true),
|
||||
],
|
||||
),
|
||||
SignalBuilder(
|
||||
builder: (context) => UoscTracksButton(
|
||||
type: JellyfinStreamType.subtitle,
|
||||
tracks: playback.tracks.value,
|
||||
onPick: pickTrack,
|
||||
onMenuOpen: menuOpen,
|
||||
),
|
||||
),
|
||||
SignalBuilder(
|
||||
builder: (context) => UoscTracksButton(
|
||||
type: JellyfinStreamType.audio,
|
||||
tracks: playback.tracks.value,
|
||||
onPick: pickTrack,
|
||||
onMenuOpen: menuOpen,
|
||||
),
|
||||
),
|
||||
UoscShaderButton(renderMode: playback.renderMode, onPick: _pickShader, onMenuOpen: menuOpen),
|
||||
const SizedBox(width: 12),
|
||||
SignalBuilder(builder: (context) {
|
||||
final ready = coord.selfMember.value?.ready ?? false;
|
||||
return UoscButton(
|
||||
key: const ValueKey('uosc-ready'),
|
||||
icon: ready ? Icons.check_circle_rounded : Icons.radio_button_unchecked_rounded,
|
||||
label: ready ? 'Ready' : 'Not ready',
|
||||
color: ready ? Colors.greenAccent : null,
|
||||
tooltip: 'Ready / not ready (Space)',
|
||||
onPressed: coord.toggleReady,
|
||||
);
|
||||
}),
|
||||
UoscButton(icon: Icons.done_all_rounded, tooltip: 'Mark everyone ready', onPressed: coord.forcePlayAll),
|
||||
UoscButton(
|
||||
icon: Icons.refresh_rounded,
|
||||
tooltip: 'Reload video (Ctrl+R) — fixes a frozen picture',
|
||||
onPressed: _reloadVideo,
|
||||
),
|
||||
],
|
||||
right: [
|
||||
UoscButton(
|
||||
key: const ValueKey('uosc-skip-forward'),
|
||||
icon: Icons.fast_forward_rounded,
|
||||
label: '1:30',
|
||||
tooltip: 'Skip 1:30 for everyone (Shift+Right)',
|
||||
onPressed: coord.skipForward,
|
||||
),
|
||||
SignalBuilder(
|
||||
builder: (context) => UoscChaptersButton(
|
||||
chapters: playback.chapters.value,
|
||||
current: playback.currentChapter.value,
|
||||
duration: playback.duration.value,
|
||||
onPick: (c) => coord.seekTo(c.start.inMicroseconds / 1e6),
|
||||
onMenuOpen: menuOpen,
|
||||
),
|
||||
),
|
||||
episode(false),
|
||||
episode(true),
|
||||
const SizedBox(width: 12),
|
||||
UoscButton(icon: Icons.video_library_outlined, tooltip: 'Change video', onPressed: _openSwap),
|
||||
UoscButton(icon: Icons.group_outlined, tooltip: 'People & chat (Tab)', onPressed: _openSheet),
|
||||
StreamBuilder<double>(
|
||||
stream: playback.player.stream.volume,
|
||||
initialData: playback.player.state.volume,
|
||||
builder: (context, v) => UoscVolumeButton(
|
||||
volume: v.data ?? 100,
|
||||
onChanged: (x) => playback.player.setVolume(x),
|
||||
),
|
||||
),
|
||||
SignalBuilder(
|
||||
builder: (context) => UoscButton(
|
||||
icon: _isFullscreen.value ? Icons.fullscreen_exit_rounded : Icons.fullscreen_rounded,
|
||||
tooltip: 'Fullscreen (F)',
|
||||
onPressed: _toggleFullscreen,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _healthOverlay() {
|
||||
final coord = SessionState.instance.coordinator;
|
||||
return Positioned(
|
||||
@@ -303,7 +723,7 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
final coord = SessionState.instance.coordinator;
|
||||
return SignalBuilder(
|
||||
builder: (context) {
|
||||
final r = coord.room.value;
|
||||
final r = coord.serverState.value;
|
||||
final waiting = [
|
||||
for (final m in r?.members ?? [])
|
||||
if (!m.ready) m,
|
||||
@@ -364,6 +784,104 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Jellyfin: the blocked card, the end-of-episode card (countdown) and
|
||||
/// the "Next episode" pill; for any media the skip pill (Skip OP / ED /
|
||||
/// 1:30) above it. Outside the auto-hiding controls, so they also show
|
||||
/// in fullscreen.
|
||||
Widget _jellyfinOverlay() {
|
||||
final coord = SessionState.instance.coordinator;
|
||||
return Positioned.fill(
|
||||
child: SignalBuilder(
|
||||
builder: (context) {
|
||||
final blocked = coord.jellyfinBlocked.value;
|
||||
final next = coord.nextEpisode.value;
|
||||
final countdown = coord.autoAdvance.value;
|
||||
final finished = coord.serverState.value?.transport == 'finished';
|
||||
final pill = coord.nextPromptVisible.value;
|
||||
final SkipOffer? skip = coord.skipOffer.value;
|
||||
final showNext = next != null && pill;
|
||||
return Stack(
|
||||
children: [
|
||||
if (blocked != null)
|
||||
Center(
|
||||
child: JellyfinBlockedCard(
|
||||
blocked: blocked,
|
||||
onLinkAccount: _openIntegrations,
|
||||
onRetry: coord.retryJellyfin,
|
||||
),
|
||||
),
|
||||
if (next != null && (finished || countdown != null))
|
||||
Positioned(
|
||||
right: 24,
|
||||
bottom: 138,
|
||||
child: EndOfEpisodeCard(
|
||||
next: next,
|
||||
countdown: countdown,
|
||||
onPlayNow: coord.playNextEpisode,
|
||||
onCancel: coord.cancelAutoAdvance,
|
||||
),
|
||||
)
|
||||
else if (showNext || skip != null)
|
||||
Positioned(
|
||||
right: 24,
|
||||
bottom: 124,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
spacing: 10,
|
||||
children: [
|
||||
if (skip != null) SkipPill(offer: skip, onPressed: () => coord.skip(skip)),
|
||||
if (showNext) NextEpisodePill(episode: next, onPressed: coord.playNextEpisode),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _swapOverlay() {
|
||||
final coord = SessionState.instance.coordinator;
|
||||
return SignalBuilder(
|
||||
builder: (context) {
|
||||
final picker = _swapPicker;
|
||||
if (!_swapOpen.value || picker == null) return const SizedBox.shrink();
|
||||
return Positioned.fill(
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: GestureDetector(
|
||||
onTap: _closeSwap,
|
||||
child: Container(color: Colors.black54),
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(32, 48, 32, 32),
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 1400),
|
||||
child: SwapPanel(
|
||||
controller: picker,
|
||||
accounts: coord.jellyfin,
|
||||
isHost: coord.hostFile != null,
|
||||
jellyfinStart: _swapStart,
|
||||
onSwap: coord.swapPicked,
|
||||
onClose: _closeSwap,
|
||||
onOpenIntegrations: _openIntegrations,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _toastsOverlay() {
|
||||
final coord = SessionState.instance.coordinator;
|
||||
return Positioned(
|
||||
@@ -421,7 +939,7 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
child: _SheetPanel(
|
||||
chat: _chat,
|
||||
chatFocus: _chatFocus,
|
||||
swapLink: _swapLink,
|
||||
onChangeVideo: _openSwap,
|
||||
onClose: () => _sheetOpen.value = false,
|
||||
onLeave: () {
|
||||
_sheetOpen.value = false;
|
||||
@@ -453,7 +971,7 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
child: GestureDetector(
|
||||
onTap: () {},
|
||||
child: AlertDialog(
|
||||
title: const Text('Leave room?'),
|
||||
title: const Text('Leave server?'),
|
||||
content: const Text('You can rejoin right away.'),
|
||||
actions: [
|
||||
TextButton(onPressed: () => _confirmLeave.value = false, child: const Text('Cancel')),
|
||||
@@ -476,6 +994,16 @@ class _SessionScreenState extends State<SessionScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
const _shaderKeys = [
|
||||
LogicalKeyboardKey.digit0,
|
||||
LogicalKeyboardKey.digit1,
|
||||
LogicalKeyboardKey.digit2,
|
||||
LogicalKeyboardKey.digit3,
|
||||
LogicalKeyboardKey.digit4,
|
||||
LogicalKeyboardKey.digit5,
|
||||
LogicalKeyboardKey.digit6,
|
||||
];
|
||||
|
||||
class _ReadyControlButton extends StatelessWidget {
|
||||
final FocusNode focusNode;
|
||||
const _ReadyControlButton({required this.focusNode});
|
||||
@@ -519,6 +1047,30 @@ class _MarkAllReadyControlButton extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _ReloadVideoControlButton extends StatelessWidget {
|
||||
final FocusNode focusNode;
|
||||
final VoidCallback onPressed;
|
||||
const _ReloadVideoControlButton({required this.focusNode, required this.onPressed});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Tooltip(
|
||||
message: 'Reload video (Ctrl+R) — fixes a frozen picture',
|
||||
child: TextButton.icon(
|
||||
focusNode: focusNode,
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
onPressed: onPressed,
|
||||
icon: const Icon(Icons.refresh, size: 16),
|
||||
label: const Text('Reload video', style: TextStyle(fontSize: 12)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ToastCard extends StatefulWidget {
|
||||
final String text;
|
||||
const _ToastCard({super.key, required this.text});
|
||||
@@ -558,10 +1110,10 @@ class _ToastCardState extends State<_ToastCard> {
|
||||
class _SheetPanel extends StatelessWidget {
|
||||
final TextEditingController chat;
|
||||
final FocusNode chatFocus;
|
||||
final TextEditingController swapLink;
|
||||
final VoidCallback onChangeVideo;
|
||||
final VoidCallback onClose;
|
||||
final VoidCallback onLeave;
|
||||
const _SheetPanel({required this.chat, required this.chatFocus, required this.swapLink, required this.onClose, required this.onLeave});
|
||||
const _SheetPanel({required this.chat, required this.chatFocus, required this.onChangeVideo, required this.onClose, required this.onLeave});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -573,7 +1125,7 @@ class _SheetPanel extends StatelessWidget {
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 16),
|
||||
child: SignalBuilder(
|
||||
builder: (context) {
|
||||
final r = coord.room.value;
|
||||
final r = coord.serverState.value;
|
||||
final log = coord.feedLog.value;
|
||||
final theme = Theme.of(context);
|
||||
final sectionStyle = theme.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold);
|
||||
@@ -592,9 +1144,9 @@ class _SheetPanel extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('Room', style: theme.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)),
|
||||
Text('Server', style: theme.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(width: 8),
|
||||
_StatusChip(playing: playing, hasRoom: r != null),
|
||||
_StatusChip(playing: playing, hasState: r != null),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
@@ -611,7 +1163,12 @@ class _SheetPanel extends StatelessWidget {
|
||||
const Divider(height: 20),
|
||||
Text('Users (${members.length})', style: sectionStyle),
|
||||
const SizedBox(height: 2),
|
||||
for (final m in members) _MemberRow(member: m, isSelf: m.id == coord.sync.memberId),
|
||||
for (final m in members)
|
||||
_MemberRow(
|
||||
member: m,
|
||||
isSelf: m.id == coord.sync.memberId,
|
||||
viaHost: viaHostOf(m, coord.currentRef.value),
|
||||
),
|
||||
const Divider(height: 20),
|
||||
Text('Activity', style: sectionStyle),
|
||||
const SizedBox(height: 6),
|
||||
@@ -651,26 +1208,14 @@ class _SheetPanel extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text('Share a link', style: sectionStyle),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: swapLink,
|
||||
decoration: const InputDecoration(labelText: 'Swap to link URL', border: OutlineInputBorder(), isDense: true),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
IconButton(
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: OutlinedButton.icon(
|
||||
key: const ValueKey('change-video'),
|
||||
icon: const Icon(Icons.swap_horiz),
|
||||
onPressed: () {
|
||||
coord.swapLink(swapLink.text.trim());
|
||||
swapLink.clear();
|
||||
},
|
||||
label: const Text('Change video'),
|
||||
onPressed: onChangeVideo,
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(height: 20),
|
||||
SizedBox(
|
||||
@@ -678,7 +1223,7 @@ class _SheetPanel extends StatelessWidget {
|
||||
child: OutlinedButton.icon(
|
||||
style: OutlinedButton.styleFrom(foregroundColor: theme.colorScheme.error),
|
||||
icon: const Icon(Icons.logout),
|
||||
label: const Text('Leave room'),
|
||||
label: const Text('Leave server'),
|
||||
onPressed: onLeave,
|
||||
),
|
||||
),
|
||||
@@ -697,14 +1242,14 @@ class _SheetPanel extends StatelessWidget {
|
||||
|
||||
class _StatusChip extends StatelessWidget {
|
||||
final bool playing;
|
||||
final bool hasRoom;
|
||||
const _StatusChip({required this.playing, required this.hasRoom});
|
||||
final bool hasState;
|
||||
const _StatusChip({required this.playing, required this.hasState});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Color dot;
|
||||
final String label;
|
||||
if (!hasRoom) {
|
||||
if (!hasState) {
|
||||
dot = Colors.grey;
|
||||
label = '…';
|
||||
} else if (playing) {
|
||||
@@ -733,10 +1278,14 @@ class _StatusChip extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// The member plays the current Jellyfin item through the host's relay.
|
||||
bool viaHostOf(MemberView m, JellyfinRef? ref) => ref != null && m.jf[ref.serverId] == false;
|
||||
|
||||
class _MemberRow extends StatelessWidget {
|
||||
final MemberView member;
|
||||
final bool isSelf;
|
||||
const _MemberRow({required this.member, required this.isSelf});
|
||||
final bool viaHost;
|
||||
const _MemberRow({required this.member, required this.isSelf, this.viaHost = false});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -773,6 +1322,7 @@ class _MemberRow extends StatelessWidget {
|
||||
status.$1,
|
||||
style: theme.textTheme.bodySmall?.copyWith(color: theme.textTheme.bodySmall?.color?.withValues(alpha: 0.75)),
|
||||
),
|
||||
if (viaHost) ...[const SizedBox(width: 6), const ViaHostBadge()],
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../state/session_state.dart';
|
||||
import '../update/updater.dart';
|
||||
import '../widgets/window_chrome_bar.dart';
|
||||
|
||||
class WelcomeScreen extends StatelessWidget {
|
||||
const WelcomeScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Scaffold(
|
||||
body: Column(
|
||||
children: [
|
||||
WindowChromeBar(title: 'Watch Together'),
|
||||
Expanded(child: _WelcomeBody()),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _WelcomeBody extends StatelessWidget {
|
||||
const _WelcomeBody();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final session = SessionState.instance;
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 420),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('Watch Together', style: TextStyle(fontSize: 24)),
|
||||
Text('v$appVersion', style: const TextStyle(fontSize: 12, color: Colors.grey)),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'Set your name + avatar on the next screen.',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () => session.goConnect(ConnectMode.host),
|
||||
child: const Text('Host'),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () => session.goConnect(ConnectMode.join),
|
||||
child: const Text('Join'),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
'Host opens ports and serves. Clients open nothing.',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
enum IdleEvent { none, warn, unready }
|
||||
|
||||
/// Idle auto-unready clock. Idle time counts from the later of the user's
|
||||
/// last input and the last moment playback was running: watching is
|
||||
/// activity, so a long watch followed by a pause starts a fresh 10 min.
|
||||
/// The unready also always trails its warning by the full grace period.
|
||||
class IdleTracker {
|
||||
static const warnAfter = Duration(minutes: 8);
|
||||
static const unreadyAfter = Duration(minutes: 10);
|
||||
|
||||
DateTime _lastActive;
|
||||
DateTime? _warnedAt;
|
||||
|
||||
IdleTracker(DateTime now) : _lastActive = now;
|
||||
|
||||
void activity(DateTime now) {
|
||||
_lastActive = now;
|
||||
_warnedAt = null;
|
||||
}
|
||||
|
||||
/// Called once per tick. Warn and unready only matter while self is
|
||||
/// ready; while playing the ready flag gates nothing.
|
||||
IdleEvent tick(DateTime now, {required bool playing, required bool selfReady}) {
|
||||
if (playing) {
|
||||
activity(now);
|
||||
return IdleEvent.none;
|
||||
}
|
||||
if (!selfReady) return IdleEvent.none;
|
||||
final warnedAt = _warnedAt;
|
||||
if (warnedAt != null) {
|
||||
if (now.difference(warnedAt) >= unreadyAfter - warnAfter) {
|
||||
activity(now);
|
||||
return IdleEvent.unready;
|
||||
}
|
||||
return IdleEvent.none;
|
||||
}
|
||||
if (now.difference(_lastActive) >= warnAfter) {
|
||||
_warnedAt = now;
|
||||
return IdleEvent.warn;
|
||||
}
|
||||
return IdleEvent.none;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,74 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import 'shader_presets.dart';
|
||||
|
||||
const anime4kAssetDir = 'assets/shaders/anime4k';
|
||||
|
||||
/// mpv needs real files: copies the shipped Anime4K shaders out of the
|
||||
/// asset bundle into `<supportDir>/shaders/anime4k-<version>`, once per
|
||||
/// version (a `.complete` marker is written last, so a cut-short copy is
|
||||
/// redone). Returns that directory.
|
||||
Future<Directory> extractAnime4k(
|
||||
Directory supportDir, {
|
||||
AssetBundle? bundle,
|
||||
}) async {
|
||||
final dir = Directory(
|
||||
'${supportDir.path}${Platform.pathSeparator}shaders'
|
||||
'${Platform.pathSeparator}anime4k-$anime4kVersion');
|
||||
final marker = File('${dir.path}${Platform.pathSeparator}.complete');
|
||||
final files = anime4kAllFiles;
|
||||
if (await marker.exists() &&
|
||||
files.every((f) => File(_join(dir, f)).existsSync())) {
|
||||
return dir;
|
||||
}
|
||||
await dir.create(recursive: true);
|
||||
final b = bundle ?? rootBundle;
|
||||
for (final name in [...files, 'LICENSE']) {
|
||||
final data = await b.load('$anime4kAssetDir/$name');
|
||||
await File(_join(dir, name)).writeAsBytes(
|
||||
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes),
|
||||
flush: true);
|
||||
}
|
||||
await marker.writeAsString(anime4kVersion, flush: true);
|
||||
return dir;
|
||||
}
|
||||
|
||||
/// Absolute paths of [preset]'s Anime4K files inside [dir].
|
||||
List<String> anime4kPaths(
|
||||
Directory dir, ShaderPreset preset, ShaderQuality quality) =>
|
||||
[for (final f in anime4kFiles(preset, quality)) _join(dir, f)];
|
||||
|
||||
String _join(Directory dir, String name) =>
|
||||
'${dir.path}${Platform.pathSeparator}$name';
|
||||
|
||||
/// Where the shipped shaders get extracted; swapped in tests.
|
||||
Future<Directory> Function() shaderSupportDir = getApplicationSupportDirectory;
|
||||
|
||||
/// Absolute `glsl-shaders` entries for a choice, extracting the shipped
|
||||
/// files first when needed. Empty for [ShaderPreset.off].
|
||||
Future<List<String>> shaderPathsFor(
|
||||
ShaderPreset preset,
|
||||
ShaderQuality quality,
|
||||
List<String> custom,
|
||||
) async {
|
||||
if (preset == ShaderPreset.off) return const [];
|
||||
if (preset == ShaderPreset.custom) return [...custom];
|
||||
final dir = await extractAnime4k(await shaderSupportDir());
|
||||
return anime4kPaths(dir, preset, quality);
|
||||
}
|
||||
|
||||
/// Why [paths] can't go to mpv (a missing file, or a path holding the
|
||||
/// list separator), or null when they can.
|
||||
String? shaderPathsProblem(List<String> paths, {bool? windows}) {
|
||||
final sep = shaderListSeparator(windows: windows);
|
||||
for (final p in paths) {
|
||||
final name = p.split(RegExp(r'[/\\]')).last;
|
||||
// Windows drive letters ("C:\") are fine: there the separator is ';'.
|
||||
if (p.contains(sep)) return '"$name" has "$sep" in its path';
|
||||
if (!File(p).existsSync()) return '"$name" not found';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
|
||||
import '../playback/playback_controller.dart';
|
||||
import '../state/settings.dart';
|
||||
import 'shader_presets.dart';
|
||||
|
||||
/// A shader pick from the menu; a null quality keeps the saved one.
|
||||
typedef ShaderPick = (ShaderPreset, ShaderQuality?);
|
||||
|
||||
/// Compact shader button for the video controls bar (normal and
|
||||
/// fullscreen). Opens a small menu: Off, the six Anime4K modes with
|
||||
/// HQ / Fast, Custom. The menu is a route, so it outlives the controls
|
||||
/// bar hiding under it; [onPick] runs on the caller's side.
|
||||
class ShaderControlButton extends StatelessWidget {
|
||||
final FocusNode focusNode;
|
||||
final ReadonlySignal<RenderMode> renderMode;
|
||||
final void Function(ShaderPreset preset, ShaderQuality? quality) onPick;
|
||||
final ValueChanged<bool>? onMenuOpen;
|
||||
const ShaderControlButton({
|
||||
super.key,
|
||||
required this.focusNode,
|
||||
required this.renderMode,
|
||||
required this.onPick,
|
||||
this.onMenuOpen,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = AppSettings.instance;
|
||||
return SignalBuilder(builder: (context) {
|
||||
final preset = s.shaderPreset.value;
|
||||
final quality = s.shaderQuality.value;
|
||||
final short = shaderShortLabel(preset, quality) ?? 'Shaders';
|
||||
return Tooltip(
|
||||
message: 'Video shaders (Ctrl+1..6, Ctrl+0 off)',
|
||||
child: TextButton.icon(
|
||||
focusNode: focusNode,
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor:
|
||||
preset == ShaderPreset.off ? Colors.white : Colors.amberAccent,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
onPressed: () => showShaderMenu(context,
|
||||
renderMode: renderMode, onPick: onPick, onMenuOpen: onMenuOpen),
|
||||
icon: const Icon(Icons.auto_awesome, size: 16),
|
||||
label: Text(short, style: const TextStyle(fontSize: 12)),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// "A HQ", "C+A Fast", "Custom"; null when shaders are off.
|
||||
String? shaderShortLabel(ShaderPreset preset, ShaderQuality quality) =>
|
||||
switch (preset) {
|
||||
ShaderPreset.off => null,
|
||||
ShaderPreset.custom => 'Custom',
|
||||
_ => '${preset.label.replaceFirst('Mode ', '')} ${quality.label}',
|
||||
};
|
||||
|
||||
/// The shader menu, anchored on [context]'s box (the button that opens
|
||||
/// it): Off, the six Anime4K modes with HQ / Fast, Custom.
|
||||
Future<void> showShaderMenu(
|
||||
BuildContext context, {
|
||||
required ReadonlySignal<RenderMode> renderMode,
|
||||
required void Function(ShaderPreset preset, ShaderQuality? quality) onPick,
|
||||
ValueChanged<bool>? onMenuOpen,
|
||||
}) async {
|
||||
final s = AppSettings.instance;
|
||||
final preset = s.shaderPreset.peek();
|
||||
final quality = s.shaderQuality.peek();
|
||||
final hasCustom = s.customShaders.peek().isNotEmpty;
|
||||
final button = context.findRenderObject() as RenderBox;
|
||||
final overlay =
|
||||
Navigator.of(context).overlay!.context.findRenderObject() as RenderBox;
|
||||
final position = RelativeRect.fromRect(
|
||||
Rect.fromPoints(
|
||||
button.localToGlobal(Offset.zero, ancestor: overlay),
|
||||
button.localToGlobal(button.size.bottomRight(Offset.zero),
|
||||
ancestor: overlay),
|
||||
),
|
||||
Offset.zero & overlay.size,
|
||||
);
|
||||
final software = renderMode.peek() == RenderMode.software;
|
||||
onMenuOpen?.call(true);
|
||||
final pick = await showMenu<ShaderPick>(
|
||||
context: context,
|
||||
position: position,
|
||||
popUpAnimationStyle: AnimationStyle.noAnimation,
|
||||
// Wider than Material's 280 px cap: the mode rows hold two chips.
|
||||
constraints: const BoxConstraints(minWidth: 340, maxWidth: 340),
|
||||
items: [
|
||||
if (software)
|
||||
const PopupMenuItem(
|
||||
enabled: false,
|
||||
height: 32,
|
||||
child: Text('Software rendering: shaders have no effect',
|
||||
style: TextStyle(fontSize: 12, color: Colors.orange)),
|
||||
),
|
||||
CheckedPopupMenuItem(
|
||||
value: (ShaderPreset.off, null),
|
||||
checked: preset == ShaderPreset.off,
|
||||
height: 36,
|
||||
child: const _Row(label: 'Off', keys: 'Ctrl+0'),
|
||||
),
|
||||
for (final (i, mode) in ShaderPreset.modes.indexed)
|
||||
_ModeEntry(
|
||||
mode: mode,
|
||||
keys: 'Ctrl+${i + 1}',
|
||||
current: preset == mode ? quality : null,
|
||||
),
|
||||
CheckedPopupMenuItem(
|
||||
value: (ShaderPreset.custom, null),
|
||||
checked: preset == ShaderPreset.custom,
|
||||
enabled: hasCustom,
|
||||
height: 36,
|
||||
child: Text(hasCustom
|
||||
? 'Custom shaders'
|
||||
: 'Custom shaders (pick files in Settings)'),
|
||||
),
|
||||
],
|
||||
);
|
||||
onMenuOpen?.call(false);
|
||||
if (pick != null) onPick(pick.$1, pick.$2);
|
||||
}
|
||||
|
||||
class _Row extends StatelessWidget {
|
||||
final String label;
|
||||
final String keys;
|
||||
const _Row({required this.label, required this.keys});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(child: Text(label)),
|
||||
Text(keys, style: const TextStyle(fontSize: 11, color: Colors.grey)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// One Anime4K mode: the row picks it with the saved quality, the two
|
||||
/// chips pick a quality explicitly.
|
||||
class _ModeEntry extends PopupMenuEntry<ShaderPick> {
|
||||
final ShaderPreset mode;
|
||||
final String keys;
|
||||
/// The active quality when this mode is the current one.
|
||||
final ShaderQuality? current;
|
||||
const _ModeEntry({
|
||||
required this.mode,
|
||||
required this.keys,
|
||||
required this.current,
|
||||
});
|
||||
|
||||
@override
|
||||
double get height => 36;
|
||||
|
||||
@override
|
||||
bool represents(ShaderPick? value) => value?.$1 == mode;
|
||||
|
||||
@override
|
||||
State<_ModeEntry> createState() => _ModeEntryState();
|
||||
}
|
||||
|
||||
class _ModeEntryState extends State<_ModeEntry> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final w = widget;
|
||||
final theme = Theme.of(context);
|
||||
void pick(ShaderQuality? q) => Navigator.of(context).pop((w.mode, q));
|
||||
return InkWell(
|
||||
onTap: () => pick(null),
|
||||
child: Container(
|
||||
height: w.height,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 36,
|
||||
child: w.current != null
|
||||
? Icon(Icons.done, size: 20, color: theme.colorScheme.primary)
|
||||
: null,
|
||||
),
|
||||
SizedBox(width: 96, child: Text(w.mode.label)),
|
||||
for (final q in ShaderQuality.values)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: ChoiceChip(
|
||||
label: Text(q.label, style: const TextStyle(fontSize: 11)),
|
||||
selected: w.current == q,
|
||||
showCheckmark: false,
|
||||
visualDensity: VisualDensity.compact,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
labelPadding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
onSelected: (_) => pick(q),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Text(w.keys,
|
||||
style: const TextStyle(fontSize: 11, color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import 'dart:io';
|
||||
|
||||
// Anime4K v4.0.1 presets, file for file as in Anime4K's mpv templates
|
||||
// (md/Template/GLSL_Mac_Linux_{High,Low}-end/input.conf): HQ = the
|
||||
// high-end GPU set, Fast = the low-end set.
|
||||
|
||||
/// Anime4K release the shipped files come from (assets/shaders/anime4k).
|
||||
const anime4kVersion = '4.0.1';
|
||||
|
||||
enum ShaderPreset {
|
||||
off('Off'),
|
||||
a('Mode A'),
|
||||
b('Mode B'),
|
||||
c('Mode C'),
|
||||
aa('Mode A+A'),
|
||||
bb('Mode B+B'),
|
||||
ca('Mode C+A'),
|
||||
custom('Custom shaders');
|
||||
|
||||
final String label;
|
||||
const ShaderPreset(this.label);
|
||||
|
||||
/// The six Anime4K modes, in Ctrl+1..Ctrl+6 order.
|
||||
static const modes = [a, b, c, aa, bb, ca];
|
||||
|
||||
bool get isAnime4k => modes.contains(this);
|
||||
}
|
||||
|
||||
enum ShaderQuality {
|
||||
hq('HQ'),
|
||||
fast('Fast');
|
||||
|
||||
final String label;
|
||||
const ShaderQuality(this.label);
|
||||
}
|
||||
|
||||
/// "Mode A (HQ)", "Off", "Custom shaders".
|
||||
String shaderLabel(ShaderPreset preset, ShaderQuality quality) =>
|
||||
preset.isAnime4k ? '${preset.label} (${quality.label})' : preset.label;
|
||||
|
||||
const _clamp = 'Anime4K_Clamp_Highlights.glsl';
|
||||
const _down = [
|
||||
'Anime4K_AutoDownscalePre_x2.glsl',
|
||||
'Anime4K_AutoDownscalePre_x4.glsl',
|
||||
];
|
||||
|
||||
/// Anime4K file names of [preset] in mpv order; empty for off/custom.
|
||||
List<String> anime4kFiles(ShaderPreset preset, ShaderQuality quality) {
|
||||
final hq = quality == ShaderQuality.hq;
|
||||
// Big/small network sizes: HQ uses VL then M, Fast uses M then S.
|
||||
final big = hq ? 'VL' : 'M';
|
||||
final small = hq ? 'M' : 'S';
|
||||
String restore(String size) => 'Anime4K_Restore_CNN_$size.glsl';
|
||||
String soft(String size) => 'Anime4K_Restore_CNN_Soft_$size.glsl';
|
||||
String up(String size) => 'Anime4K_Upscale_CNN_x2_$size.glsl';
|
||||
String denoise(String size) => 'Anime4K_Upscale_Denoise_CNN_x2_$size.glsl';
|
||||
return switch (preset) {
|
||||
ShaderPreset.off || ShaderPreset.custom => const [],
|
||||
ShaderPreset.a => [_clamp, restore(big), up(big), ..._down, up(small)],
|
||||
ShaderPreset.b => [_clamp, soft(big), up(big), ..._down, up(small)],
|
||||
ShaderPreset.c => [_clamp, denoise(big), ..._down, up(small)],
|
||||
ShaderPreset.aa => [
|
||||
_clamp, restore(big), up(big), restore(small), ..._down, up(small)
|
||||
],
|
||||
ShaderPreset.bb => [
|
||||
_clamp, soft(big), up(big), ..._down, soft(small), up(small)
|
||||
],
|
||||
ShaderPreset.ca => [
|
||||
_clamp, denoise(big), ..._down, restore(small), up(small)
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/// Every file some preset needs: exactly what assets/shaders/anime4k holds.
|
||||
List<String> get anime4kAllFiles => {
|
||||
for (final p in ShaderPreset.modes)
|
||||
for (final q in ShaderQuality.values) ...anime4kFiles(p, q),
|
||||
}.toList()
|
||||
..sort();
|
||||
|
||||
/// mpv's path-list separator: ';' on Windows, ':' elsewhere.
|
||||
String shaderListSeparator({bool? windows}) =>
|
||||
(windows ?? Platform.isWindows) ? ';' : ':';
|
||||
|
||||
/// The `glsl-shaders` value for [paths].
|
||||
String joinShaderPaths(List<String> paths, {bool? windows}) =>
|
||||
paths.join(shaderListSeparator(windows: windows));
|
||||
@@ -0,0 +1,169 @@
|
||||
import 'dart:async';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:flutter/foundation.dart' show visibleForTesting;
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
import 'package:sync_relay_server/server.dart';
|
||||
|
||||
Future<void> _serverMain((Map<String, Object?>, SendPort) args) =>
|
||||
serve(args.$1, events: args.$2);
|
||||
|
||||
/// The hosted server, running [serve] on its own isolate. Its log lines
|
||||
/// go to [onLog]; if the isolate dies without being asked to stop,
|
||||
/// [onCrash] gets the cause once.
|
||||
class ServerIsolate {
|
||||
final Isolate _isolate;
|
||||
final SendPort _stop;
|
||||
final int port;
|
||||
final ReceivePort _events;
|
||||
final ReceivePort _errors;
|
||||
final ReceivePort _exit;
|
||||
final Completer<void> _exited = Completer<void>();
|
||||
bool _stopping = false;
|
||||
String? _lastError;
|
||||
void Function(String error)? _onCrash;
|
||||
|
||||
ServerIsolate._(this._isolate, this._stop, this.port, this._events,
|
||||
this._errors, this._exit);
|
||||
|
||||
@visibleForTesting
|
||||
Isolate get isolate => _isolate;
|
||||
|
||||
bool get isRunning => !_exited.isCompleted;
|
||||
|
||||
/// Spawns the server and waits until it listens. Throws a
|
||||
/// [StateError] with the server's message if it cannot start.
|
||||
static Future<ServerIsolate> start(
|
||||
AppConfig config, {
|
||||
required void Function(String line) onLog,
|
||||
required void Function(String error) onCrash,
|
||||
Duration timeout = const Duration(seconds: 15),
|
||||
}) async {
|
||||
final events = ReceivePort('server events');
|
||||
final errors = ReceivePort('server errors');
|
||||
final exit = ReceivePort('server exit');
|
||||
final startup = Completer<(int, SendPort)>();
|
||||
String? lastError;
|
||||
var exited = false;
|
||||
ServerIsolate? self;
|
||||
|
||||
void fail(String message) {
|
||||
if (!startup.isCompleted) startup.completeError(StateError(message));
|
||||
}
|
||||
|
||||
events.listen((msg) {
|
||||
if (msg is! Map) return;
|
||||
switch (msg['t']) {
|
||||
case 'log':
|
||||
final err = msg['error'];
|
||||
onLog('${msg['level']} ${msg['logger']}: ${msg['message']}'
|
||||
'${err == null ? '' : ' ($err)'}');
|
||||
case 'ready':
|
||||
if (!startup.isCompleted) {
|
||||
startup.complete((msg['port'] as int, msg['stop'] as SendPort));
|
||||
}
|
||||
case 'error':
|
||||
fail('${msg['message']}');
|
||||
}
|
||||
});
|
||||
// errorsAreFatal is off: a stray async error is logged and the server
|
||||
// keeps going, as it did in-process. Only a dead isolate is a crash.
|
||||
errors.listen((msg) {
|
||||
final text = msg is List && msg.isNotEmpty ? '${msg.first}' : '$msg';
|
||||
lastError = text;
|
||||
self?._lastError = text;
|
||||
onLog('SEVERE uncaught: $text');
|
||||
});
|
||||
exit.listen((_) {
|
||||
exited = true;
|
||||
fail(lastError ?? 'server exited before it was ready');
|
||||
self?._onExit();
|
||||
});
|
||||
|
||||
final Isolate isolate;
|
||||
try {
|
||||
isolate = await Isolate.spawn(
|
||||
_serverMain, (config.toMap(), events.sendPort),
|
||||
errorsAreFatal: false,
|
||||
onError: errors.sendPort,
|
||||
onExit: exit.sendPort,
|
||||
debugName: 'server');
|
||||
} catch (_) {
|
||||
events.close();
|
||||
errors.close();
|
||||
exit.close();
|
||||
rethrow;
|
||||
}
|
||||
final (int, SendPort) ready;
|
||||
try {
|
||||
ready = await startup.future.timeout(timeout);
|
||||
} catch (e) {
|
||||
if (!exited) isolate.kill(priority: Isolate.immediate);
|
||||
events.close();
|
||||
errors.close();
|
||||
exit.close();
|
||||
if (e is TimeoutException) {
|
||||
throw StateError('server did not start within ${timeout.inSeconds} s');
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
final s = ServerIsolate._(isolate, ready.$2, ready.$1, events, errors, exit)
|
||||
.._onCrash = onCrash
|
||||
.._lastError = lastError;
|
||||
self = s;
|
||||
if (exited) {
|
||||
// Died between ready and here: a failed start, not a crash.
|
||||
s._stopping = true;
|
||||
s._onExit();
|
||||
throw StateError(lastError ?? 'server exited right after starting');
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void _onExit() {
|
||||
if (_exited.isCompleted) return;
|
||||
_exited.complete();
|
||||
_events.close();
|
||||
_errors.close();
|
||||
_exit.close();
|
||||
final crash = _onCrash;
|
||||
_onCrash = null;
|
||||
if (!_stopping) crash?.call(_lastError ?? 'the server stopped unexpectedly');
|
||||
}
|
||||
|
||||
/// Makes [path] the hosted file (the in-session File swap). Returns its
|
||||
/// name and size for the `swap` that puts it up, or null when the file
|
||||
/// is missing or the server is gone.
|
||||
Future<({String name, int size})?> setFile(String path,
|
||||
{Duration timeout = const Duration(seconds: 5)}) async {
|
||||
if (_exited.isCompleted) return null;
|
||||
final reply = ReceivePort('server file');
|
||||
try {
|
||||
_stop.send({'t': 'file', 'path': path, 'reply': reply.sendPort});
|
||||
final msg = await reply.first.timeout(timeout);
|
||||
if (msg is Map && msg['ok'] == true) {
|
||||
return (name: msg['name'] as String, size: msg['size'] as int);
|
||||
}
|
||||
return null;
|
||||
} catch (_) {
|
||||
return null;
|
||||
} finally {
|
||||
reply.close();
|
||||
}
|
||||
}
|
||||
|
||||
/// Asks the server to close its sockets and exit; kills the isolate if it
|
||||
/// has not exited within [timeout].
|
||||
Future<void> stop({Duration timeout = const Duration(seconds: 3)}) async {
|
||||
if (_exited.isCompleted) return;
|
||||
_stopping = true;
|
||||
_stop.send({'t': 'stop'});
|
||||
try {
|
||||
await _exited.future.timeout(timeout);
|
||||
} on TimeoutException {
|
||||
_isolate.kill(priority: Isolate.immediate);
|
||||
await _exited.future.timeout(const Duration(seconds: 2),
|
||||
onTimeout: _onExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,35 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
import 'package:sync_relay_server/server.dart';
|
||||
|
||||
import '../jellyfin/accounts.dart';
|
||||
import '../jellyfin/session_media.dart';
|
||||
import '../sfx/sfx.dart';
|
||||
import '../session/health.dart';
|
||||
import '../session/session_coordinator.dart';
|
||||
import '../widgets/avatar_pipeline.dart';
|
||||
import 'connect_prefs.dart';
|
||||
import 'server_isolate.dart';
|
||||
|
||||
enum AppRoute { welcome, connect, session }
|
||||
enum AppRoute {
|
||||
home,
|
||||
session,
|
||||
}
|
||||
|
||||
enum ConnectMode { host, join }
|
||||
|
||||
/// Both Home cards prefill from this. [host]/[port]/[secret] belong to
|
||||
/// the Join card, [hostPort]/[hostSecret] to the Host card.
|
||||
class ConnectForm {
|
||||
String host;
|
||||
String port;
|
||||
String secret;
|
||||
String hostPort;
|
||||
String hostSecret;
|
||||
String name;
|
||||
String avatarPath;
|
||||
String mediaPath;
|
||||
@@ -25,36 +38,159 @@ class ConnectForm {
|
||||
this.host = '127.0.0.1',
|
||||
this.port = '8080',
|
||||
this.secret = '',
|
||||
this.hostPort = '8080',
|
||||
this.hostSecret = '',
|
||||
this.name = '',
|
||||
this.avatarPath = '',
|
||||
this.mediaPath = '',
|
||||
this.linkUrl = '',
|
||||
});
|
||||
|
||||
ConnectForm copy() => ConnectForm(
|
||||
host: host,
|
||||
port: port,
|
||||
secret: secret,
|
||||
hostPort: hostPort,
|
||||
hostSecret: hostSecret,
|
||||
name: name,
|
||||
avatarPath: avatarPath,
|
||||
mediaPath: mediaPath,
|
||||
linkUrl: linkUrl,
|
||||
);
|
||||
}
|
||||
|
||||
const connectKeyHostPort = 'hostPort';
|
||||
const connectKeyHostSecret = 'hostSecret';
|
||||
const connectKeyRecents = 'recents';
|
||||
const maxRecentServers = 6;
|
||||
|
||||
/// A server the user got into, shown as a Recent chip on Home. Hosted
|
||||
/// entries refill the Host card; joined ones join in one click.
|
||||
class RecentServer {
|
||||
final bool hosted;
|
||||
final String host;
|
||||
final String port;
|
||||
final String secret;
|
||||
const RecentServer(
|
||||
{required this.hosted,
|
||||
required this.host,
|
||||
required this.port,
|
||||
this.secret = ''});
|
||||
|
||||
String get key => hosted ? 'host:$port' : '${host.toLowerCase()}:$port';
|
||||
|
||||
Map<String, Object> toJson() =>
|
||||
{'hosted': hosted, 'host': host, 'port': port, 'secret': secret};
|
||||
|
||||
static RecentServer? fromJson(Object? j) {
|
||||
if (j is! Map) return null;
|
||||
final host = j['host'], port = j['port'], secret = j['secret'];
|
||||
if (host is! String || port is! String) return null;
|
||||
return RecentServer(
|
||||
hosted: j['hosted'] == true,
|
||||
host: host,
|
||||
port: port,
|
||||
secret: secret is String ? secret : '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Newest first, one entry per server, capped at [maxRecentServers].
|
||||
List<RecentServer> pushRecent(List<RecentServer> list, RecentServer s) => [
|
||||
s,
|
||||
...list.where((r) => r.key != s.key),
|
||||
].take(maxRecentServers).toList();
|
||||
|
||||
String encodeRecents(List<RecentServer> list) =>
|
||||
jsonEncode([for (final r in list) r.toJson()]);
|
||||
|
||||
List<RecentServer> decodeRecents(Object? raw) {
|
||||
if (raw is! String) return const [];
|
||||
try {
|
||||
final list = jsonDecode(raw);
|
||||
if (list is! List) return const [];
|
||||
return [
|
||||
for (final j in list) ?RecentServer.fromJson(j),
|
||||
].take(maxRecentServers).toList();
|
||||
} catch (_) {
|
||||
return const [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Before recents existed only the last form was stored: a saved remote
|
||||
/// address becomes the first Recent chip.
|
||||
List<RecentServer> migrateRecents(
|
||||
{required bool hadForm,
|
||||
required String host,
|
||||
required String port,
|
||||
required String secret}) {
|
||||
final h = host.trim().toLowerCase();
|
||||
if (!hadForm || h.isEmpty || h == '127.0.0.1' || h == 'localhost') {
|
||||
return const [];
|
||||
}
|
||||
return [RecentServer(hosted: false, host: host.trim(), port: port, secret: secret)];
|
||||
}
|
||||
|
||||
/// The hosted server died during setup; shown on the Host card.
|
||||
class ServerCrashed implements Exception {
|
||||
final String cause;
|
||||
const ServerCrashed(this.cause);
|
||||
@override
|
||||
String toString() => 'server crashed: $cause';
|
||||
}
|
||||
|
||||
/// A fresh per-hosting key: the app's own client sends it in hello to be
|
||||
/// recognised as the (unkickable) host.
|
||||
String newHostKey() {
|
||||
final r = Random.secure();
|
||||
return base64Url.encode([for (var i = 0; i < 24; i++) r.nextInt(256)]);
|
||||
}
|
||||
|
||||
class SessionState {
|
||||
static final SessionState instance = SessionState._();
|
||||
SessionState._();
|
||||
|
||||
final route = signal(AppRoute.welcome);
|
||||
final connectMode = signal(ConnectMode.host);
|
||||
final route = signal(AppRoute.home);
|
||||
final recents = signal<List<RecentServer>>(const []);
|
||||
final status = signal(const HealthStatus(HealthSeverity.info, 'idle'));
|
||||
final room = signal<RoomBroadcast?>(null);
|
||||
final SfxService sfx = const NoopSfxService();
|
||||
late final SessionCoordinator coordinator = SessionCoordinator(sfx: sfx);
|
||||
final lastForm = ConnectForm();
|
||||
RoomServer? _server;
|
||||
JellyfinAccounts get jellyfin => JellyfinAccounts.instance;
|
||||
/// Set when the hosted server died mid-session; Home shows it on the
|
||||
/// Host card and clears it.
|
||||
final serverCrash = signal<String?>(null);
|
||||
ServerIsolate? _server;
|
||||
String? _setupCrash;
|
||||
|
||||
@visibleForTesting
|
||||
ServerIsolate? get hostedServer => _server;
|
||||
void Function()? _stopKickWatch;
|
||||
// Bumped by host/join/cancelPending: a cancelled setup notices at its
|
||||
// next step and unwinds instead of connecting.
|
||||
int _op = 0;
|
||||
|
||||
Future<void> loadForm() async {
|
||||
final box = await openConnectFormBox();
|
||||
lastForm
|
||||
..host = readString(box, connectKeyHost, '127.0.0.1')
|
||||
..port = readString(box, connectKeyPort, '8080')
|
||||
..secret = readString(box, connectKeySecret, '')
|
||||
..secret = readString(box, connectKeySecret, '');
|
||||
// Old installs had one port/password for both modes.
|
||||
lastForm
|
||||
..hostPort = readString(box, connectKeyHostPort, lastForm.port)
|
||||
..hostSecret = readString(box, connectKeyHostSecret, lastForm.secret)
|
||||
..name = readString(box, connectKeyName, '')
|
||||
..avatarPath = readString(box, connectKeyAvatarPath, '')
|
||||
..mediaPath = readString(box, connectKeyMediaPath, '')
|
||||
..linkUrl = readString(box, connectKeyLinkUrl, '');
|
||||
recents.value = box.containsKey(connectKeyRecents)
|
||||
? decodeRecents(box.get(connectKeyRecents))
|
||||
: migrateRecents(
|
||||
hadForm: box.containsKey(connectKeyHost),
|
||||
host: lastForm.host,
|
||||
port: lastForm.port,
|
||||
secret: lastForm.secret);
|
||||
}
|
||||
|
||||
Future<void> saveForm() async {
|
||||
@@ -63,61 +199,153 @@ class SessionState {
|
||||
connectKeyHost: lastForm.host,
|
||||
connectKeyPort: lastForm.port,
|
||||
connectKeySecret: lastForm.secret,
|
||||
connectKeyHostPort: lastForm.hostPort,
|
||||
connectKeyHostSecret: lastForm.hostSecret,
|
||||
connectKeyName: lastForm.name,
|
||||
connectKeyAvatarPath: lastForm.avatarPath,
|
||||
connectKeyMediaPath: lastForm.mediaPath,
|
||||
connectKeyLinkUrl: lastForm.linkUrl,
|
||||
connectKeyRecents: encodeRecents(recents.peek()),
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> loadAvatar(String path) => encodeAvatar(path);
|
||||
|
||||
void goConnect(ConnectMode mode) {
|
||||
connectMode.value = mode;
|
||||
route.value = AppRoute.connect;
|
||||
/// Called by Home after a host/join got through.
|
||||
Future<void> rememberServer(RecentServer server) async {
|
||||
recents.value = pushRecent(recents.peek(), server);
|
||||
await _saveFormQuietly();
|
||||
}
|
||||
|
||||
Future<void> forgetServer(RecentServer server) async {
|
||||
recents.value = [
|
||||
for (final r in recents.peek())
|
||||
if (r.key != server.key) r,
|
||||
];
|
||||
await _saveFormQuietly();
|
||||
}
|
||||
|
||||
Future<void> host(ConnectParams params, ConnectForm form) async {
|
||||
final op = ++_op;
|
||||
_rememberForm(form);
|
||||
status.value = const HealthStatus(HealthSeverity.info, 'starting server…');
|
||||
try {
|
||||
status.value =
|
||||
const HealthStatus(HealthSeverity.info, 'starting server…');
|
||||
await stopServer();
|
||||
final server = RoomServer(AppConfig(
|
||||
if (op != _op) throw const ConnectCancelled();
|
||||
final hostKey = newHostKey();
|
||||
_setupCrash = null;
|
||||
// A pasted Jellyfin link goes up as a ref like a browser pick.
|
||||
final media = params.media ??
|
||||
(params.linkUrl.isEmpty ? null : await mediaForLink(jellyfin, params.linkUrl));
|
||||
if (op != _op) throw const ConnectCancelled();
|
||||
// Guests without an account watch through the server, with the
|
||||
// host's own sign-in (the hosted item's server, else the default).
|
||||
await jellyfin.ensureLoaded(validate: false);
|
||||
final relay = relayCredentialFor(jellyfin, serverId: media?.jellyfin?.serverId);
|
||||
late final ServerIsolate server;
|
||||
try {
|
||||
server = await ServerIsolate.start(
|
||||
AppConfig(
|
||||
port: params.port,
|
||||
secret: params.secret,
|
||||
name: 'room',
|
||||
name: 'server',
|
||||
mediaPath: params.mediaPath,
|
||||
));
|
||||
try {
|
||||
await server.start();
|
||||
hostKey: hostKey,
|
||||
jellyfin: relay,
|
||||
),
|
||||
onLog: (line) => debugPrint('[server] $line'),
|
||||
onCrash: (cause) => _onServerCrash(server, cause),
|
||||
);
|
||||
} catch (e, st) {
|
||||
debugPrint('server start failed: $e\n$st');
|
||||
status.value =
|
||||
HealthStatus(HealthSeverity.error, 'cannot bind port ${params.port}: $e');
|
||||
status.value = HealthStatus(
|
||||
HealthSeverity.error, 'cannot start server on port ${params.port}: $e');
|
||||
rethrow;
|
||||
}
|
||||
if (op != _op) {
|
||||
await server.stop();
|
||||
throw const ConnectCancelled();
|
||||
}
|
||||
_server = server;
|
||||
coordinator.hostFile = (path) async =>
|
||||
identical(_server, server) ? server.setFile(path) : null;
|
||||
status.value =
|
||||
HealthStatus(HealthSeverity.ok, 'hosting on port ${server.boundPort}');
|
||||
HealthStatus(HealthSeverity.ok, 'hosting on port ${server.port}');
|
||||
try {
|
||||
await coordinator.connect(ConnectParams(
|
||||
host: '127.0.0.1',
|
||||
port: server.boundPort,
|
||||
port: server.port,
|
||||
secret: params.secret,
|
||||
name: params.name,
|
||||
avatar: params.avatar,
|
||||
linkUrl: params.linkUrl,
|
||||
hostKey: hostKey,
|
||||
media: media,
|
||||
));
|
||||
if (op != _op) throw const ConnectCancelled();
|
||||
} catch (e) {
|
||||
// Own join failed or was cancelled: don't leave the port open.
|
||||
if (identical(_server, server)) await stopServer();
|
||||
final crash = _setupCrash;
|
||||
if (crash != null && e is! ConnectCancelled) throw ServerCrashed(crash);
|
||||
rethrow;
|
||||
}
|
||||
_watchKick();
|
||||
route.value = AppRoute.session;
|
||||
try {
|
||||
await saveForm();
|
||||
} catch (e, st) {
|
||||
debugPrint('save connect form failed: $e\n$st');
|
||||
} finally {
|
||||
await _saveFormQuietly();
|
||||
}
|
||||
}
|
||||
|
||||
/// The server isolate died without being stopped. In a session: show it
|
||||
/// and leave. During setup the own join fails and [host] reports it.
|
||||
void _onServerCrash(ServerIsolate server, String cause) {
|
||||
if (!identical(_server, server)) return;
|
||||
final message = 'server crashed: $cause';
|
||||
debugPrint('[server] $message');
|
||||
if (route.peek() != AppRoute.session) {
|
||||
_setupCrash = cause;
|
||||
return;
|
||||
}
|
||||
coordinator.health.value = HealthStatus(HealthSeverity.error, message);
|
||||
serverCrash.value = message;
|
||||
unawaited(leave().catchError((Object e) => debugPrint('leave after crash failed: $e')));
|
||||
}
|
||||
|
||||
Future<void> join(ConnectParams params, ConnectForm form) async {
|
||||
final op = ++_op;
|
||||
_rememberForm(form);
|
||||
try {
|
||||
await coordinator.connect(params);
|
||||
if (op != _op) throw const ConnectCancelled();
|
||||
route.value = AppRoute.session;
|
||||
} finally {
|
||||
await _saveFormQuietly();
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancel button during setup: abort whichever step is running (server
|
||||
/// start, player init, socket dial) without connecting.
|
||||
Future<void> cancelPending() async {
|
||||
_op++;
|
||||
try {
|
||||
await coordinator.cancelConnect();
|
||||
} catch (_) {}
|
||||
await stopServer();
|
||||
}
|
||||
|
||||
/// A kicked host must not keep serving.
|
||||
void _watchKick() {
|
||||
_stopKickWatch?.call();
|
||||
_stopKickWatch = effect(() {
|
||||
// Microtask: stopServer disposes this effect, not from inside it.
|
||||
if (coordinator.kickReason.value != null) scheduleMicrotask(stopServer);
|
||||
});
|
||||
}
|
||||
|
||||
/// Saved whatever the outcome: a failed join is exactly when the user
|
||||
/// wants the form back.
|
||||
Future<void> _saveFormQuietly() async {
|
||||
try {
|
||||
await saveForm();
|
||||
} catch (e, st) {
|
||||
@@ -130,30 +358,27 @@ class SessionState {
|
||||
..host = form.host
|
||||
..port = form.port
|
||||
..secret = form.secret
|
||||
..hostPort = form.hostPort
|
||||
..hostSecret = form.hostSecret
|
||||
..name = form.name
|
||||
..avatarPath = form.avatarPath
|
||||
..mediaPath = form.mediaPath
|
||||
..linkUrl = form.linkUrl;
|
||||
}
|
||||
|
||||
Future<void> startHeadless(List<String> args) async {
|
||||
int port = 8080;
|
||||
for (var i = 0; i < args.length - 1; i++) {
|
||||
if (args[i] == '--port') port = int.tryParse(args[i + 1]) ?? port;
|
||||
}
|
||||
_server = RoomServer(AppConfig(port: port, secret: 'change-me', name: 'room'));
|
||||
await _server!.start();
|
||||
}
|
||||
|
||||
Future<void> stopServer() async {
|
||||
await _server?.stop();
|
||||
coordinator.hostFile = null;
|
||||
_stopKickWatch?.call();
|
||||
_stopKickWatch = null;
|
||||
final server = _server;
|
||||
_server = null;
|
||||
await server?.stop();
|
||||
}
|
||||
|
||||
Future<void> leave() async {
|
||||
await coordinator.leave();
|
||||
await stopServer();
|
||||
status.value = const HealthStatus(HealthSeverity.info, 'idle');
|
||||
route.value = AppRoute.connect;
|
||||
route.value = AppRoute.home;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import 'package:signals/signals_flutter.dart';
|
||||
|
||||
import '../shaders/shader_presets.dart';
|
||||
|
||||
// App preferences (Settings page), one Hive box. Signals start at their
|
||||
// defaults and take the stored values once [AppSettings.ensureLoaded]
|
||||
// finishes; setters write through.
|
||||
|
||||
const settingsBoxName = 'settings';
|
||||
|
||||
const _keyHwdecMode = 'hwdecMode';
|
||||
const _keyHwdecCustom = 'hwdecCustom';
|
||||
const _keyAutoCheckUpdates = 'autoCheckUpdates';
|
||||
const _keyShaderPreset = 'shaderPreset';
|
||||
const _keyShaderQuality = 'shaderQuality';
|
||||
const _keyCustomShaders = 'customShaders';
|
||||
const _keyAutoAdvance = 'autoAdvance';
|
||||
const _keyMpvControls = 'mpvControls';
|
||||
|
||||
enum HwdecMode { auto, off, custom }
|
||||
|
||||
class AppSettings {
|
||||
static final AppSettings instance = AppSettings();
|
||||
|
||||
final hwdecMode = signal(HwdecMode.auto);
|
||||
final hwdecCustom = signal('');
|
||||
final autoCheckUpdates = signal(true);
|
||||
/// Jellyfin episodes: at the end, count down 10 s and put up the next.
|
||||
final autoAdvance = signal(true);
|
||||
/// Experimental: the session uses the mpv-style (uosc) controls
|
||||
/// (`controls/uosc/`) instead of media_kit's. Applies live.
|
||||
final mpvControls = signal(false);
|
||||
|
||||
/// Video shaders: one choice, used on join and changed both here and
|
||||
/// in the session (Ctrl+0..6, the shader button).
|
||||
final shaderPreset = signal(ShaderPreset.off);
|
||||
final shaderQuality = signal(ShaderQuality.hq);
|
||||
/// .glsl files of [ShaderPreset.custom], in mpv order.
|
||||
final customShaders = signal<List<String>>(const []);
|
||||
|
||||
/// mpv `hwdec` value: 'auto', 'no', or the custom value ('auto' when
|
||||
/// custom is blank).
|
||||
late final hwdec = computed(() => switch (hwdecMode.value) {
|
||||
HwdecMode.auto => 'auto',
|
||||
HwdecMode.off => 'no',
|
||||
HwdecMode.custom =>
|
||||
hwdecCustom.value.trim().isEmpty ? 'auto' : hwdecCustom.value.trim(),
|
||||
});
|
||||
|
||||
Future<void>? _load;
|
||||
Box? _box;
|
||||
|
||||
Future<void> ensureLoaded() => _load ??= _loadNow();
|
||||
|
||||
Future<void> _loadNow() async {
|
||||
try {
|
||||
final box = _box = await Hive.openBox(settingsBoxName);
|
||||
final mode = box.get(_keyHwdecMode);
|
||||
hwdecMode.value = HwdecMode.values
|
||||
.where((m) => m.name == mode)
|
||||
.firstOrNull ??
|
||||
HwdecMode.auto;
|
||||
final custom = box.get(_keyHwdecCustom);
|
||||
if (custom is String) hwdecCustom.value = custom;
|
||||
final auto = box.get(_keyAutoCheckUpdates);
|
||||
if (auto is bool) autoCheckUpdates.value = auto;
|
||||
final advance = box.get(_keyAutoAdvance);
|
||||
if (advance is bool) autoAdvance.value = advance;
|
||||
final mpv = box.get(_keyMpvControls);
|
||||
if (mpv is bool) mpvControls.value = mpv;
|
||||
final preset = box.get(_keyShaderPreset);
|
||||
shaderPreset.value =
|
||||
ShaderPreset.values.where((p) => p.name == preset).firstOrNull ??
|
||||
ShaderPreset.off;
|
||||
final quality = box.get(_keyShaderQuality);
|
||||
shaderQuality.value =
|
||||
ShaderQuality.values.where((q) => q.name == quality).firstOrNull ??
|
||||
ShaderQuality.hq;
|
||||
final files = box.get(_keyCustomShaders);
|
||||
if (files is List) {
|
||||
customShaders.value = List.unmodifiable(files.whereType<String>());
|
||||
}
|
||||
} catch (e, st) {
|
||||
debugPrint('load settings failed: $e\n$st');
|
||||
}
|
||||
}
|
||||
|
||||
void setHwdecMode(HwdecMode mode) {
|
||||
hwdecMode.value = mode;
|
||||
_put(_keyHwdecMode, mode.name);
|
||||
}
|
||||
|
||||
void setHwdecCustom(String value) {
|
||||
hwdecCustom.value = value;
|
||||
_put(_keyHwdecCustom, value);
|
||||
}
|
||||
|
||||
void setAutoCheckUpdates(bool on) {
|
||||
autoCheckUpdates.value = on;
|
||||
_put(_keyAutoCheckUpdates, on);
|
||||
}
|
||||
|
||||
void setAutoAdvance(bool on) {
|
||||
autoAdvance.value = on;
|
||||
_put(_keyAutoAdvance, on);
|
||||
}
|
||||
|
||||
void setMpvControls(bool on) {
|
||||
mpvControls.value = on;
|
||||
_put(_keyMpvControls, on);
|
||||
}
|
||||
|
||||
void setShaderPreset(ShaderPreset preset) {
|
||||
shaderPreset.value = preset;
|
||||
_put(_keyShaderPreset, preset.name);
|
||||
}
|
||||
|
||||
void setShaderQuality(ShaderQuality quality) {
|
||||
shaderQuality.value = quality;
|
||||
_put(_keyShaderQuality, quality.name);
|
||||
}
|
||||
|
||||
void setCustomShaders(List<String> paths) {
|
||||
customShaders.value = List.unmodifiable(paths);
|
||||
_put(_keyCustomShaders, [...paths]);
|
||||
}
|
||||
|
||||
Future<void> _put(String key, Object value) async {
|
||||
try {
|
||||
final box = _box ??
|
||||
(Hive.isBoxOpen(settingsBoxName) ? Hive.box(settingsBoxName) : null);
|
||||
await box?.put(key, value);
|
||||
} catch (e, st) {
|
||||
debugPrint('save setting $key failed: $e\n$st');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
sealed class PlayerAction {
|
||||
const PlayerAction();
|
||||
}
|
||||
|
||||
class SeekAction extends PlayerAction {
|
||||
final double position;
|
||||
const SeekAction(this.position);
|
||||
}
|
||||
|
||||
class TransportAction extends PlayerAction {
|
||||
final bool playing;
|
||||
const TransportAction(this.playing);
|
||||
}
|
||||
|
||||
class RateAction extends PlayerAction {
|
||||
final double rate;
|
||||
const RateAction(this.rate);
|
||||
}
|
||||
|
||||
double roomPositionAt(RoomBroadcast room, DateTime now) {
|
||||
if (room.transport != 'playing') return room.position;
|
||||
return room.position + now.difference(room.serverTime).inMilliseconds / 1000.0;
|
||||
}
|
||||
|
||||
bool seekLanded({required double ownPosition, required double target}) {
|
||||
if ((ownPosition - target).abs() > RelayConstants.driftSeekThresholdSecs) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool localPlayAllowed(RoomBroadcast room, String memberId) {
|
||||
if (memberId.isEmpty) return false;
|
||||
for (final m in room.members) {
|
||||
if (m.id == memberId) return m.inSet && m.ready;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class RoomDiff {
|
||||
static const debounceWindow = Duration(seconds: 2);
|
||||
|
||||
int _lastEventId = -1;
|
||||
String _lastTransport = '';
|
||||
int _lastMediaId = -1;
|
||||
bool _slowing = false;
|
||||
DateTime? _deviatingSince;
|
||||
int _deviatingEvent = -1;
|
||||
|
||||
bool get slowing => _slowing;
|
||||
|
||||
List<PlayerAction> diff(RoomBroadcast room, double ownPosition, DateTime now) {
|
||||
final out = <PlayerAction>[];
|
||||
final roomPos = roomPositionAt(room, now);
|
||||
|
||||
if (room.mediaId != _lastMediaId && _lastMediaId != -1) {
|
||||
_lastEventId = room.eventId;
|
||||
_lastTransport = room.transport;
|
||||
_lastMediaId = room.mediaId;
|
||||
_slowing = false;
|
||||
_deviatingSince = null;
|
||||
out.add(const SeekAction(0));
|
||||
out.add(const TransportAction(false));
|
||||
out.add(const RateAction(1.0));
|
||||
return out;
|
||||
}
|
||||
|
||||
if (_lastEventId == -1) {
|
||||
_lastEventId = room.eventId;
|
||||
_lastTransport = room.transport;
|
||||
_lastMediaId = room.mediaId;
|
||||
_deviatingSince = null;
|
||||
out.add(SeekAction(roomPos));
|
||||
out.add(TransportAction(room.transport == 'playing'));
|
||||
return out;
|
||||
}
|
||||
|
||||
if (room.eventId != _lastEventId) {
|
||||
_lastEventId = room.eventId;
|
||||
_slowing = false;
|
||||
_deviatingSince = null;
|
||||
out.add(const RateAction(1.0));
|
||||
out.add(SeekAction(roomPos));
|
||||
if (room.transport != _lastTransport) {
|
||||
_lastTransport = room.transport;
|
||||
out.add(TransportAction(room.transport == 'playing'));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
if (room.transport != _lastTransport) {
|
||||
_lastTransport = room.transport;
|
||||
_slowing = false;
|
||||
_deviatingSince = null;
|
||||
out.add(const RateAction(1.0));
|
||||
out.add(TransportAction(room.transport == 'playing'));
|
||||
out.add(SeekAction(roomPos));
|
||||
return out;
|
||||
}
|
||||
|
||||
final drift = ownPosition - roomPos;
|
||||
if (_slowing) {
|
||||
if (drift.abs() < 0.1) {
|
||||
_slowing = false;
|
||||
out.add(const RateAction(1.0));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
switch (correctionFor(ownPosition: ownPosition, roomPosition: roomPos)) {
|
||||
case Correction.seek:
|
||||
if (_deviatingEvent != room.eventId || _deviatingSince == null) {
|
||||
_deviatingEvent = room.eventId;
|
||||
_deviatingSince = now;
|
||||
break;
|
||||
}
|
||||
if (now.difference(_deviatingSince!).compareTo(debounceWindow) < 0) {
|
||||
break;
|
||||
}
|
||||
_deviatingSince = null;
|
||||
out.add(SeekAction(roomPos));
|
||||
case Correction.slowDown:
|
||||
_deviatingSince = null;
|
||||
_slowing = true;
|
||||
out.add(const RateAction(RelayConstants.slowDownRate));
|
||||
case Correction.none:
|
||||
_deviatingSince = null;
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_lastEventId = -1;
|
||||
_lastTransport = '';
|
||||
_lastMediaId = -1;
|
||||
_slowing = false;
|
||||
_deviatingSince = null;
|
||||
_deviatingEvent = -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
sealed class PlayerAction {
|
||||
const PlayerAction();
|
||||
}
|
||||
|
||||
class SeekAction extends PlayerAction {
|
||||
final double position;
|
||||
const SeekAction(this.position);
|
||||
}
|
||||
|
||||
class TransportAction extends PlayerAction {
|
||||
final bool playing;
|
||||
const TransportAction(this.playing);
|
||||
}
|
||||
|
||||
class RateAction extends PlayerAction {
|
||||
final double rate;
|
||||
const RateAction(this.rate);
|
||||
}
|
||||
|
||||
/// Server position at [serverNow], which must be on the server's clock
|
||||
/// (`SyncClient.serverNow()`, local time corrected by the clock offset):
|
||||
/// `state.serverTime` is stamped by the server.
|
||||
double serverPositionAt(StateBroadcast state, DateTime serverNow) {
|
||||
if (state.transport != 'playing') return state.position;
|
||||
return state.position +
|
||||
serverNow.difference(state.serverTime).inMicroseconds / 1e6;
|
||||
}
|
||||
|
||||
bool seekLanded({required double ownPosition, required double target}) {
|
||||
if ((ownPosition - target).abs() > RelayConstants.driftSeekThresholdSecs) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool localPlayAllowed(StateBroadcast state, String memberId) {
|
||||
if (memberId.isEmpty) return false;
|
||||
for (final m in state.members) {
|
||||
if (m.id == memberId) return m.inSet && m.ready;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class StateDiff {
|
||||
static const debounceWindow = Duration(seconds: 2);
|
||||
|
||||
int _lastEventId = -1;
|
||||
String _lastTransport = '';
|
||||
int _lastMediaId = -1;
|
||||
bool _slowing = false;
|
||||
DateTime? _deviatingSince;
|
||||
int _deviatingEvent = -1;
|
||||
|
||||
bool get slowing => _slowing;
|
||||
|
||||
/// [now] is server time (see [serverPositionAt]).
|
||||
List<PlayerAction> diff(StateBroadcast state, double ownPosition, DateTime now) {
|
||||
final out = <PlayerAction>[];
|
||||
final serverPos = serverPositionAt(state, now);
|
||||
|
||||
if (state.mediaId != _lastMediaId && _lastMediaId != -1) {
|
||||
_lastEventId = state.eventId;
|
||||
_lastTransport = state.transport;
|
||||
_lastMediaId = state.mediaId;
|
||||
_slowing = false;
|
||||
_deviatingSince = null;
|
||||
out.add(const SeekAction(0));
|
||||
out.add(const TransportAction(false));
|
||||
out.add(const RateAction(1.0));
|
||||
return out;
|
||||
}
|
||||
|
||||
// End of media: everyone stops where they are (at or just before the
|
||||
// end). No seek to the very end and no drift correction.
|
||||
if (state.transport == 'finished') {
|
||||
final first = _lastEventId == -1;
|
||||
final changed = first ||
|
||||
state.eventId != _lastEventId ||
|
||||
state.transport != _lastTransport;
|
||||
_lastEventId = state.eventId;
|
||||
_lastTransport = state.transport;
|
||||
_lastMediaId = state.mediaId;
|
||||
_slowing = false;
|
||||
_deviatingSince = null;
|
||||
if (!changed) return out;
|
||||
out.add(const RateAction(1.0));
|
||||
if (first) out.add(SeekAction(serverPos > 1 ? serverPos - 1 : 0));
|
||||
out.add(const TransportAction(false));
|
||||
return out;
|
||||
}
|
||||
|
||||
if (_lastEventId == -1) {
|
||||
_lastEventId = state.eventId;
|
||||
_lastTransport = state.transport;
|
||||
_lastMediaId = state.mediaId;
|
||||
_deviatingSince = null;
|
||||
out.add(SeekAction(serverPos));
|
||||
out.add(TransportAction(state.transport == 'playing'));
|
||||
return out;
|
||||
}
|
||||
|
||||
if (state.eventId != _lastEventId) {
|
||||
_lastEventId = state.eventId;
|
||||
_slowing = false;
|
||||
_deviatingSince = null;
|
||||
out.add(const RateAction(1.0));
|
||||
out.add(SeekAction(serverPos));
|
||||
if (state.transport != _lastTransport) {
|
||||
_lastTransport = state.transport;
|
||||
out.add(TransportAction(state.transport == 'playing'));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
if (state.transport != _lastTransport) {
|
||||
_lastTransport = state.transport;
|
||||
_slowing = false;
|
||||
_deviatingSince = null;
|
||||
out.add(const RateAction(1.0));
|
||||
out.add(TransportAction(state.transport == 'playing'));
|
||||
out.add(SeekAction(serverPos));
|
||||
return out;
|
||||
}
|
||||
|
||||
final drift = ownPosition - serverPos;
|
||||
if (_slowing) {
|
||||
if (drift.abs() < 0.1) {
|
||||
_slowing = false;
|
||||
out.add(const RateAction(1.0));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
switch (correctionFor(ownPosition: ownPosition, serverPosition: serverPos)) {
|
||||
case Correction.seek:
|
||||
if (_deviatingEvent != state.eventId || _deviatingSince == null) {
|
||||
_deviatingEvent = state.eventId;
|
||||
_deviatingSince = now;
|
||||
break;
|
||||
}
|
||||
if (now.difference(_deviatingSince!).compareTo(debounceWindow) < 0) {
|
||||
break;
|
||||
}
|
||||
_deviatingSince = null;
|
||||
out.add(SeekAction(serverPos));
|
||||
case Correction.slowDown:
|
||||
_deviatingSince = null;
|
||||
_slowing = true;
|
||||
out.add(const RateAction(RelayConstants.slowDownRate));
|
||||
case Correction.none:
|
||||
_deviatingSince = null;
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_lastEventId = -1;
|
||||
_lastTransport = '';
|
||||
_lastMediaId = -1;
|
||||
_slowing = false;
|
||||
_deviatingSince = null;
|
||||
_deviatingEvent = -1;
|
||||
}
|
||||
}
|
||||
@@ -7,15 +7,27 @@ import 'package:web_socket_channel/web_socket_channel.dart';
|
||||
enum SyncStatus { idle, connecting, open, kicked, closed, error }
|
||||
|
||||
class SyncClient {
|
||||
/// Local clock; injectable so tests can run a client whose clock is off.
|
||||
final DateTime Function() _clock;
|
||||
SyncClient({DateTime Function()? clock})
|
||||
: _clock = clock ?? (() => DateTime.now().toUtc());
|
||||
|
||||
/// Offset to the server's clock, from ping/pong round trips.
|
||||
final ClockSync clockSync = ClockSync();
|
||||
|
||||
/// Now on the server's clock: use this, not the local clock, against
|
||||
/// `serverTime` in a state.
|
||||
DateTime serverNow() => clockSync.serverNow(_clock());
|
||||
|
||||
WebSocketChannel? _channel;
|
||||
StreamSubscription? _sub;
|
||||
final StreamController<RoomBroadcast> _rooms = StreamController.broadcast();
|
||||
final StreamController<StateBroadcast> _states = StreamController.broadcast();
|
||||
final StreamController<FeedMessage> _feeds = StreamController.broadcast();
|
||||
final StreamController<String> _kicked = StreamController.broadcast();
|
||||
final StreamController<String> _errors = StreamController.broadcast();
|
||||
final StreamController<SyncStatus> _status = StreamController.broadcast();
|
||||
|
||||
Stream<RoomBroadcast> get rooms => _rooms.stream;
|
||||
Stream<StateBroadcast> get states => _states.stream;
|
||||
Stream<FeedMessage> get feeds => _feeds.stream;
|
||||
Stream<String> get kicked => _kicked.stream;
|
||||
Stream<String> get errors => _errors.stream;
|
||||
@@ -24,7 +36,10 @@ class SyncClient {
|
||||
String token = '';
|
||||
String memberId = '';
|
||||
String? mediaUrl;
|
||||
RoomBroadcast? lastRoom;
|
||||
/// This member's `/j/...` URL from `welcome` (Jellyfin media the server
|
||||
/// relays); private like [token].
|
||||
String? relayUrl;
|
||||
StateBroadcast? lastState;
|
||||
Completer<WelcomeMessage>? _pendingWelcome;
|
||||
|
||||
Future<WelcomeMessage> connect({
|
||||
@@ -33,8 +48,11 @@ class SyncClient {
|
||||
required String name,
|
||||
String avatar = '',
|
||||
HelloMedia? media,
|
||||
String hostKey = '',
|
||||
String resume = '',
|
||||
}) async {
|
||||
await disconnect();
|
||||
clockSync.reset();
|
||||
_status.add(SyncStatus.connecting);
|
||||
final ch = WebSocketChannel.connect(wsUri);
|
||||
unawaited(ch.ready.then((_) {}, onError: (_) {}));
|
||||
@@ -61,6 +79,8 @@ class SyncClient {
|
||||
secret: secret,
|
||||
user: HelloUser(name: name, avatar: avatar),
|
||||
media: media ?? const HelloMedia(name: '', size: 0, duration: 0),
|
||||
hostKey: hostKey,
|
||||
resume: resume,
|
||||
);
|
||||
ch.sink.add(jsonEncode(hello.toJson()));
|
||||
_pendingWelcome = welcomeCompleter;
|
||||
@@ -72,13 +92,15 @@ class SyncClient {
|
||||
token = welcome.token;
|
||||
memberId = welcome.memberId;
|
||||
mediaUrl = welcome.mediaUrl;
|
||||
relayUrl = welcome.relayUrl;
|
||||
if (welcome.state != null) {
|
||||
try {
|
||||
lastRoom = RoomBroadcast.fromJson(welcome.state!);
|
||||
_rooms.add(lastRoom!);
|
||||
lastState = StateBroadcast.fromJson(welcome.state!);
|
||||
_states.add(lastState!);
|
||||
} catch (_) {}
|
||||
}
|
||||
_status.add(SyncStatus.open);
|
||||
sendPing();
|
||||
return welcome;
|
||||
} catch (e) {
|
||||
_pendingWelcome = null;
|
||||
@@ -113,11 +135,11 @@ class SyncClient {
|
||||
return;
|
||||
}
|
||||
switch (t) {
|
||||
case 'room':
|
||||
case 'state':
|
||||
try {
|
||||
final room = RoomBroadcast.fromJson(decoded);
|
||||
lastRoom = room;
|
||||
_rooms.add(room);
|
||||
final state = StateBroadcast.fromJson(decoded);
|
||||
lastState = state;
|
||||
_states.add(state);
|
||||
} catch (_) {}
|
||||
case 'feed':
|
||||
try {
|
||||
@@ -136,6 +158,14 @@ class SyncClient {
|
||||
} catch (_) {
|
||||
_kicked.add('');
|
||||
}
|
||||
case 'pong':
|
||||
try {
|
||||
final pong = PongMessage.fromJson(decoded);
|
||||
clockSync.add(
|
||||
sentMs: pong.clientMs,
|
||||
serverMs: pong.serverMs,
|
||||
receivedMs: _clock().millisecondsSinceEpoch);
|
||||
} catch (_) {}
|
||||
case 'err':
|
||||
_errors.add('${decoded['message'] ?? 'error'}');
|
||||
case 'chat':
|
||||
@@ -168,9 +198,14 @@ class SyncClient {
|
||||
_send(ForceIntent(target: target, ready: ready).toJson());
|
||||
}
|
||||
|
||||
void sendSeek(double position) {
|
||||
void sendSeek(double position, {int seq = 0}) {
|
||||
if (position.isNaN || position < 0) return;
|
||||
_send(SeekIntent(position: position).toJson());
|
||||
_send(SeekIntent(position: position, seq: seq).toJson());
|
||||
}
|
||||
|
||||
/// One clock sample; the coordinator sends one per second.
|
||||
void sendPing() {
|
||||
_send(PingMessage(clientMs: _clock().millisecondsSinceEpoch).toJson());
|
||||
}
|
||||
|
||||
void sendSwap(HelloMedia media) {
|
||||
@@ -181,6 +216,9 @@ class SyncClient {
|
||||
required double position,
|
||||
required double buffered,
|
||||
required int eventId,
|
||||
double duration = 0,
|
||||
int mediaId = 0,
|
||||
Map<String, bool>? jf,
|
||||
}) {
|
||||
final safeBuffered = buffered.isNaN || buffered < 0 ? 0.0 : buffered;
|
||||
_send(
|
||||
@@ -188,6 +226,9 @@ class SyncClient {
|
||||
position: position,
|
||||
buffered: safeBuffered,
|
||||
eventId: eventId,
|
||||
duration: duration.isFinite && duration > 0 ? duration : 0,
|
||||
mediaId: mediaId,
|
||||
jf: jf,
|
||||
).toJson(),
|
||||
);
|
||||
}
|
||||
@@ -219,12 +260,13 @@ class SyncClient {
|
||||
token = '';
|
||||
memberId = '';
|
||||
mediaUrl = null;
|
||||
lastRoom = null;
|
||||
relayUrl = null;
|
||||
lastState = null;
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
await disconnect();
|
||||
await _rooms.close();
|
||||
await _states.close();
|
||||
await _feeds.close();
|
||||
await _kicked.close();
|
||||
await _errors.close();
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
/// A [Player] whose public [seek] belongs to the user. media_kit's seek bar
|
||||
/// (and anything else in the video controls) calls `player.seek`; with
|
||||
/// [onUserSeek] set those calls become explicit events for the sync layer
|
||||
/// instead of moving mpv behind its back. Sync-driven seeks use [syncSeek].
|
||||
class SyncPlayer extends Player {
|
||||
SyncPlayer({super.configuration});
|
||||
|
||||
void Function(Duration position)? onUserSeek;
|
||||
|
||||
@override
|
||||
Future<void> seek(Duration duration) async {
|
||||
final hook = onUserSeek;
|
||||
if (hook == null) return super.seek(duration);
|
||||
hook(duration);
|
||||
}
|
||||
|
||||
/// Seek mpv directly (preview while scrubbing, server corrections).
|
||||
Future<void> syncSeek(Duration duration) => super.seek(duration);
|
||||
}
|
||||
|
||||
/// Turns a burst of user seeks (a seek bar drag fires one per pointer move,
|
||||
/// arrow keys one per press) into one `seek` intent, and tells the
|
||||
/// coordinator when server seeks must not touch the player:
|
||||
///
|
||||
/// - while the user is still seeking ([debounce] since the last request),
|
||||
/// - while our sent seek has no echo yet ([echoTimeout] at most),
|
||||
/// - for the echo of our own seek (`state.seekBy` is us): the player is
|
||||
/// already there, re-seeking would only hitch or yank.
|
||||
class UserSeekGate {
|
||||
final Duration debounce;
|
||||
final Duration echoTimeout;
|
||||
|
||||
UserSeekGate({
|
||||
this.debounce = const Duration(milliseconds: RelayConstants.seekDebounceMs),
|
||||
this.echoTimeout = const Duration(seconds: 3),
|
||||
});
|
||||
|
||||
double? _target;
|
||||
DateTime? _requestedAt;
|
||||
int _seq = 0;
|
||||
int _sentSeq = 0;
|
||||
DateTime? _sentAt;
|
||||
|
||||
/// Latest requested position, while a request or its echo is pending.
|
||||
double? get target => _target;
|
||||
|
||||
/// The user asked for [position] at [now].
|
||||
void request(double position, DateTime now) {
|
||||
_target = position;
|
||||
_requestedAt = now;
|
||||
}
|
||||
|
||||
bool scrubbing(DateTime now) =>
|
||||
_requestedAt != null && now.difference(_requestedAt!) < debounce;
|
||||
|
||||
/// The settled request to send, once [debounce] has passed since the last
|
||||
/// one; null otherwise. Returns its seq, which the server echoes.
|
||||
({double position, int seq})? takeSettled(DateTime now) {
|
||||
final t = _target;
|
||||
if (t == null || _requestedAt == null || scrubbing(now)) return null;
|
||||
_requestedAt = null;
|
||||
_sentSeq = ++_seq;
|
||||
_sentAt = now;
|
||||
return (position: t, seq: _sentSeq);
|
||||
}
|
||||
|
||||
bool get _awaitingEcho => _sentAt != null;
|
||||
|
||||
/// Server seeks are ignored while this holds.
|
||||
bool holdsPlayer(DateTime now) {
|
||||
if (_requestedAt != null) return true; // not sent yet
|
||||
final sent = _sentAt;
|
||||
if (sent == null) return false;
|
||||
if (now.difference(sent) >= echoTimeout) {
|
||||
_sentAt = null;
|
||||
_target = null;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// The state's current event is a seek this client sent.
|
||||
bool isOwnEcho(StateBroadcast state, String memberId) {
|
||||
final seq = state.seekSeq;
|
||||
return memberId.isNotEmpty &&
|
||||
state.seekBy == memberId &&
|
||||
seq != null &&
|
||||
seq > 0 &&
|
||||
seq <= _seq;
|
||||
}
|
||||
|
||||
/// Feed every state: the echo of the last sent seek ends the hold.
|
||||
void observe(StateBroadcast state, String memberId) {
|
||||
if (!_awaitingEcho || _requestedAt != null) return;
|
||||
if (isOwnEcho(state, memberId) && state.seekSeq! >= _sentSeq) {
|
||||
_sentAt = null;
|
||||
_target = null;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_target = null;
|
||||
_requestedAt = null;
|
||||
_sentAt = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
rem Update this install in place (same as clicking Update in the app).
|
||||
"%~dp0watch_together.exe" --upgrade %*
|
||||
pause
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
# Update this install in place (same as clicking Update in the app).
|
||||
cd "$(dirname "$0")" && exec ./watch_together --upgrade "$@"
|
||||
@@ -0,0 +1,160 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive_ce_flutter/hive_flutter.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import 'updater.dart';
|
||||
|
||||
// In-app update flow behind the Home update indicator. Same code path as
|
||||
// `--upgrade` (downloadAndApply); this adds state for the UI and the
|
||||
// restart. Check failures are logged only — the banner shows up just when
|
||||
// there is something to install.
|
||||
|
||||
final _log = createLogger('update');
|
||||
|
||||
enum UpdatePhase { idle, available, downloading, applying, restarting, failed }
|
||||
|
||||
class UpdateStatus {
|
||||
final UpdatePhase phase;
|
||||
final UpdateManifest? manifest;
|
||||
final double? progress;
|
||||
final String? error;
|
||||
// False for dev runs / unpacked builds: banner tells the user to update
|
||||
// by hand instead of offering the button.
|
||||
final bool canInstall;
|
||||
const UpdateStatus(this.phase,
|
||||
{this.manifest, this.progress, this.error, this.canInstall = false});
|
||||
}
|
||||
|
||||
typedef RestartFn = Future<void> Function(String executable, List<String> args);
|
||||
|
||||
// Release Hive's box locks before the new instance opens the same boxes.
|
||||
Future<void> _closeAndRestart(String executable, List<String> args) async {
|
||||
try {
|
||||
await Hive.close();
|
||||
} catch (e) {
|
||||
_log.warning('closing hive before restart: $e');
|
||||
}
|
||||
await restartApp(executable, args);
|
||||
}
|
||||
|
||||
class UpdateController {
|
||||
static final instance = UpdateController();
|
||||
|
||||
final String currentVersion;
|
||||
final String manifestUrl;
|
||||
final String? executablePath;
|
||||
final Directory? installRoot;
|
||||
final RestartFn restart;
|
||||
final bool skipDevBuilds;
|
||||
|
||||
UpdateController(
|
||||
{this.currentVersion = appVersion,
|
||||
this.manifestUrl = updateManifestUrl,
|
||||
this.executablePath,
|
||||
this.installRoot,
|
||||
this.restart = _closeAndRestart,
|
||||
this.skipDevBuilds = true});
|
||||
|
||||
final status = ValueNotifier(const UpdateStatus(UpdatePhase.idle));
|
||||
/// Outcome of the last finished check, for Settings/About wording
|
||||
/// ("Up to date", "Check failed: ..."); null until one finishes.
|
||||
final lastCheck = ValueNotifier<String?>(null);
|
||||
Future<void>? _check;
|
||||
late final String _exe = executablePath ?? currentExecutablePath();
|
||||
late final Directory? _root = installRoot ?? findInstallRoot(_exe);
|
||||
String get _exeName => _exe.replaceAll('\\', '/').split('/').last;
|
||||
|
||||
// Once per process; later calls return the same future.
|
||||
Future<void> checkOnce() => _check ??= _checkNow();
|
||||
|
||||
// User-triggered re-check ("Check now"); joins one already in flight.
|
||||
Future<void> checkNow() {
|
||||
final inFlight = _check;
|
||||
if (inFlight != null && _checking) return inFlight;
|
||||
return _check = _checkNow();
|
||||
}
|
||||
|
||||
bool _checking = false;
|
||||
|
||||
Future<void> _checkNow() async {
|
||||
_checking = true;
|
||||
try {
|
||||
await _runCheck();
|
||||
} finally {
|
||||
_checking = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _runCheck() async {
|
||||
if (skipDevBuilds && currentVersion.endsWith('-dev')) {
|
||||
_log.info('dev build ($currentVersion), skipping update check');
|
||||
lastCheck.value = 'Dev build — update checks are off';
|
||||
return;
|
||||
}
|
||||
final root = _root;
|
||||
if (root != null) await cleanupUpdateLeftovers(root);
|
||||
try {
|
||||
final m = await fetchManifest(url: manifestUrl);
|
||||
if (!isNewerVersion(currentVersion, m.version)) {
|
||||
_log.info('up to date ($currentVersion, latest ${m.version})');
|
||||
lastCheck.value = 'Up to date';
|
||||
return;
|
||||
}
|
||||
_log.info('update available: ${m.version} (proto ${m.protocol})');
|
||||
status.value = UpdateStatus(UpdatePhase.available,
|
||||
manifest: m, canInstall: root != null);
|
||||
lastCheck.value = 'Update v${m.version} available';
|
||||
} catch (e) {
|
||||
_log.warning('update check failed: $e');
|
||||
lastCheck.value = 'Update check failed: $e';
|
||||
}
|
||||
}
|
||||
|
||||
void dismiss() {
|
||||
final s = status.value;
|
||||
if ((s.phase == UpdatePhase.available || s.phase == UpdatePhase.failed) &&
|
||||
!(s.manifest?.isRequired ?? false)) {
|
||||
status.value = const UpdateStatus(UpdatePhase.idle);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> install() async {
|
||||
final s = status.value;
|
||||
final m = s.manifest;
|
||||
final root = _root;
|
||||
if (m == null || root == null) return;
|
||||
if (s.phase != UpdatePhase.available && s.phase != UpdatePhase.failed) {
|
||||
return;
|
||||
}
|
||||
status.value = UpdateStatus(UpdatePhase.downloading,
|
||||
manifest: m, progress: 0, canInstall: true);
|
||||
var lastPct = -1;
|
||||
try {
|
||||
await downloadAndApply(m, root,
|
||||
executableName: installRoot == null ? _exeName : null,
|
||||
onProgress: (got, total) {
|
||||
if (total == null || total == 0) return;
|
||||
final pct = got * 100 ~/ total;
|
||||
if (pct == lastPct) return;
|
||||
lastPct = pct;
|
||||
status.value = UpdateStatus(UpdatePhase.downloading,
|
||||
manifest: m, progress: got / total, canInstall: true);
|
||||
if (pct == 100) {
|
||||
status.value =
|
||||
UpdateStatus(UpdatePhase.applying, manifest: m, canInstall: true);
|
||||
}
|
||||
}, say: (line) => _log.info(line));
|
||||
} catch (e) {
|
||||
_log.warning('update failed: $e');
|
||||
status.value = UpdateStatus(UpdatePhase.failed,
|
||||
manifest: m, error: '$e', canInstall: true);
|
||||
return;
|
||||
}
|
||||
_log.info('updated to ${m.version}, restarting');
|
||||
status.value =
|
||||
UpdateStatus(UpdatePhase.restarting, manifest: m, canInstall: true);
|
||||
await restart(_exe, launchArgs);
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,21 @@ import 'package:crypto/crypto.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
// Zero Flutter imports: this file must stay unit-testable with plain
|
||||
// `flutter test` (no widgets, no media_kit). Linux-first v1: a CLI flag,
|
||||
// `watch-together --upgrade`, that checks the manifest, downloads the
|
||||
// tarball, verifies sha256, and extracts it over the live install.
|
||||
// Linux allows replacing (unlink/rename) files under a running process —
|
||||
// only opening the running binary for writing is refused (ETXTBSY) — so
|
||||
// apply is extract-to-temp then delete-first move-over, and the running
|
||||
// (old) image just prints the result and exits. Next launch is new.
|
||||
// `flutter test` (no widgets, no media_kit). One code path for both the
|
||||
// CLI (`watch_together --upgrade`) and the in-app banner: fetch manifest,
|
||||
// download, verify sha256, apply over the live install.
|
||||
//
|
||||
// Apply stages inside the install root (same filesystem, so every move is
|
||||
// a rename — /tmp is often tmpfs and rename across filesystems fails).
|
||||
// Linux: unlinking/renaming files under a running process is fine, only
|
||||
// opening the running binary for writing is refused (ETXTBSY), so the
|
||||
// swap moves each top-level bundle entry aside, moves the new one in,
|
||||
// and rolls everything back on any failure. Windows (UNTESTED — no
|
||||
// Windows runner yet): a running exe/dll can be renamed but not deleted,
|
||||
// so in-use files go to `*.old`, new files move in, and `*.old` is swept
|
||||
// on the next start (cleanupUpdateLeftovers).
|
||||
|
||||
final _log = createLogger('update');
|
||||
|
||||
const updateManifestUrl =
|
||||
'https://git.senkochan.moe/Foxyz/sync_replay_project/raw/branch/main/updates/manifest.json';
|
||||
@@ -20,45 +28,54 @@ const updateManifestUrl =
|
||||
const appVersion = String.fromEnvironment('APP_VERSION',
|
||||
defaultValue: '0.0.0-dev');
|
||||
|
||||
// Process args as main() received them — restart relaunches with these.
|
||||
List<String> launchArgs = const [];
|
||||
|
||||
const _stagingDir = '.update-staging';
|
||||
const _backupDir = '.update-backup';
|
||||
const _downloadFile = '.update-download';
|
||||
|
||||
class UpdateManifest {
|
||||
final String version;
|
||||
final int protocol;
|
||||
final String url;
|
||||
final String sha256;
|
||||
final String? sha256;
|
||||
final String notes;
|
||||
const UpdateManifest(
|
||||
{required this.version,
|
||||
required this.protocol,
|
||||
required this.url,
|
||||
required this.sha256,
|
||||
this.sha256,
|
||||
required this.notes});
|
||||
|
||||
factory UpdateManifest.fromJson(Map<String, Object?> json) {
|
||||
final version = json['version'];
|
||||
final protocol = json['protocol'];
|
||||
final url = json['url'];
|
||||
final sha = json['sha256'];
|
||||
if (version is! String ||
|
||||
version.isEmpty ||
|
||||
protocol is! int ||
|
||||
url is! String ||
|
||||
url.isEmpty ||
|
||||
sha is! String ||
|
||||
sha.isEmpty) {
|
||||
throw const FormatException('update manifest missing version/protocol/url/sha256');
|
||||
url.isEmpty) {
|
||||
throw const FormatException('update manifest missing version/protocol/url');
|
||||
}
|
||||
final sha = json['sha256'];
|
||||
return UpdateManifest(
|
||||
version: version,
|
||||
protocol: protocol,
|
||||
url: url,
|
||||
sha256: sha,
|
||||
sha256: sha is String && sha.isNotEmpty ? sha : null,
|
||||
notes: (json['notes'] as String?) ?? '');
|
||||
}
|
||||
|
||||
// Newer wire protocol: this build can't join servers running it.
|
||||
bool get isRequired => protocol > RelayConstants.protoVersion;
|
||||
}
|
||||
|
||||
List<int> parseVersion(String v) {
|
||||
final core = v.split('+').first.split('-').first;
|
||||
final out = <int>[];
|
||||
for (final part in v.split('.')) {
|
||||
for (final part in core.split('.')) {
|
||||
final m = RegExp(r'\d+').firstMatch(part);
|
||||
if (m == null) break;
|
||||
out.add(int.parse(m.group(0)!));
|
||||
@@ -70,15 +87,48 @@ List<int> parseVersion(String v) {
|
||||
return out;
|
||||
}
|
||||
|
||||
bool isNewerVersion(String current, String latest) {
|
||||
final c = parseVersion(current);
|
||||
final l = parseVersion(latest);
|
||||
// Semver precedence: core numbers, then a prerelease sorts below its
|
||||
// release (1.2.3-rc1 < 1.2.3); prerelease identifiers compare dot by dot,
|
||||
// numeric ones numerically and below alphanumeric ones. Build metadata
|
||||
// (+...) is ignored.
|
||||
int compareVersions(String a, String b) {
|
||||
final ca = parseVersion(a);
|
||||
final cb = parseVersion(b);
|
||||
for (var i = 0; i < 3; i++) {
|
||||
if (l[i] != c[i]) return l[i] > c[i];
|
||||
if (ca[i] != cb[i]) return ca[i].compareTo(cb[i]);
|
||||
}
|
||||
return false;
|
||||
String? pre(String v) {
|
||||
final noBuild = v.split('+').first;
|
||||
final i = noBuild.indexOf('-');
|
||||
return i < 0 ? null : noBuild.substring(i + 1);
|
||||
}
|
||||
|
||||
final pa = pre(a);
|
||||
final pb = pre(b);
|
||||
if (pa == null || pb == null) {
|
||||
if (pa == pb) return 0;
|
||||
return pa == null ? 1 : -1;
|
||||
}
|
||||
final ia = pa.split('.');
|
||||
final ib = pb.split('.');
|
||||
for (var i = 0; i < ia.length && i < ib.length; i++) {
|
||||
final na = int.tryParse(ia[i]);
|
||||
final nb = int.tryParse(ib[i]);
|
||||
final c = na != null && nb != null
|
||||
? na.compareTo(nb)
|
||||
: na != null
|
||||
? -1
|
||||
: nb != null
|
||||
? 1
|
||||
: ia[i].compareTo(ib[i]);
|
||||
if (c != 0) return c;
|
||||
}
|
||||
return ia.length.compareTo(ib.length);
|
||||
}
|
||||
|
||||
bool isNewerVersion(String current, String latest) =>
|
||||
compareVersions(latest, current) > 0;
|
||||
|
||||
Future<UpdateManifest> fetchManifest(
|
||||
{HttpClient? http, String url = updateManifestUrl}) async {
|
||||
final client = http ?? HttpClient();
|
||||
@@ -86,7 +136,7 @@ Future<UpdateManifest> fetchManifest(
|
||||
final req = await client
|
||||
.getUrl(Uri.parse(url))
|
||||
.timeout(const Duration(seconds: 15));
|
||||
final res = await req.close();
|
||||
final res = await req.close().timeout(const Duration(seconds: 15));
|
||||
final body = await res.transform(utf8.decoder).join();
|
||||
if (res.statusCode != 200) {
|
||||
throw HttpException('manifest fetch failed: HTTP ${res.statusCode}');
|
||||
@@ -97,28 +147,40 @@ Future<UpdateManifest> fetchManifest(
|
||||
}
|
||||
return UpdateManifest.fromJson(decoded);
|
||||
} finally {
|
||||
client.close();
|
||||
if (http == null) client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> downloadFile(String url, File dest, {HttpClient? http}) async {
|
||||
typedef DownloadProgress = void Function(int received, int? total);
|
||||
|
||||
Future<void> downloadFile(String url, File dest,
|
||||
{HttpClient? http, DownloadProgress? onProgress}) async {
|
||||
final client = http ?? HttpClient();
|
||||
try {
|
||||
final req = await client
|
||||
.getUrl(Uri.parse(url))
|
||||
.timeout(const Duration(seconds: 15));
|
||||
final res = await req.close();
|
||||
final res = await req.close().timeout(const Duration(seconds: 30));
|
||||
if (res.statusCode != 200) {
|
||||
throw HttpException('download failed: HTTP ${res.statusCode}');
|
||||
}
|
||||
final total = res.contentLength >= 0 ? res.contentLength : null;
|
||||
var received = 0;
|
||||
final sink = dest.openWrite();
|
||||
try {
|
||||
await res.pipe(sink);
|
||||
await for (final chunk in res) {
|
||||
sink.add(chunk);
|
||||
received += chunk.length;
|
||||
onProgress?.call(received, total);
|
||||
}
|
||||
} finally {
|
||||
await sink.close();
|
||||
}
|
||||
if (total != null && received != total) {
|
||||
throw HttpException('download truncated: $received of $total bytes');
|
||||
}
|
||||
} finally {
|
||||
client.close();
|
||||
if (http == null) client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,57 +192,336 @@ Future<void> verifySha256(File file, String want) async {
|
||||
}
|
||||
|
||||
// Release bundle layout is <root>/<binary> with <root>/data and <root>/lib
|
||||
// siblings. Anything else (dev runs, dart run) is not a packaged install.
|
||||
Directory? findInstallRoot(String executablePath) {
|
||||
// siblings (Windows: data/ next to flutter_windows.dll, no lib/).
|
||||
// Anything else (dev runs, dart run) is not a packaged install.
|
||||
bool _isBundle(String dir, bool windows) =>
|
||||
Directory('$dir/data').existsSync() &&
|
||||
(windows
|
||||
? File('$dir/flutter_windows.dll').existsSync()
|
||||
: Directory('$dir/lib').existsSync());
|
||||
|
||||
Directory? findInstallRoot(String executablePath, {bool? windows}) {
|
||||
final dir = File(executablePath).parent;
|
||||
if (Directory('${dir.path}/data').existsSync() &&
|
||||
Directory('${dir.path}/lib').existsSync()) {
|
||||
return dir;
|
||||
}
|
||||
return null;
|
||||
return _isBundle(dir.path, windows ?? Platform.isWindows) ? dir : null;
|
||||
}
|
||||
|
||||
// Extract to temp, then move every file over delete-first: opening the
|
||||
// running executable for writing throws ETXTBSY, delete+rename does not.
|
||||
Future<void> applyTarball(File tarball, Directory root) async {
|
||||
final raw = await tarball.readAsBytes();
|
||||
final archive = TarDecoder().decodeBytes(GZipDecoder().decodeBytes(raw));
|
||||
final stage =
|
||||
await Directory.systemTemp.createTemp('watch-together-update');
|
||||
String _basename(String path) => path.replaceAll('\\', '/').split('/').last;
|
||||
|
||||
// Path of the running binary. Read it before applying: after the swap,
|
||||
// /proc/self/exe points at the replaced inode ("... (deleted)").
|
||||
String currentExecutablePath() {
|
||||
const deleted = ' (deleted)';
|
||||
final p = Platform.resolvedExecutable;
|
||||
return p.endsWith(deleted) ? p.substring(0, p.length - deleted.length) : p;
|
||||
}
|
||||
|
||||
// Sweep what a previous apply left behind: staging/backup dirs from an
|
||||
// interrupted run, and Windows `*.old` files that were still in use.
|
||||
// The running app is complete (it started), so leftovers are garbage.
|
||||
Future<void> cleanupUpdateLeftovers(Directory root) async {
|
||||
for (final name in [_stagingDir, _backupDir, _downloadFile]) {
|
||||
await _deleteQuietly('${root.path}/$name');
|
||||
}
|
||||
if (!await root.exists()) return;
|
||||
final old = RegExp(r'\.old(\.\d+)?$');
|
||||
await for (final e in root.list(recursive: true, followLinks: false)) {
|
||||
if (e is File && old.hasMatch(e.path)) {
|
||||
try {
|
||||
for (final entry in archive) {
|
||||
final name = entry.name;
|
||||
if (name.isEmpty || name.startsWith('/') || name.contains('..')) {
|
||||
throw FormatException('unsafe tar entry: $name');
|
||||
await e.delete();
|
||||
} catch (err) {
|
||||
_log.fine('still in use, retry next start: ${e.path} ($err)');
|
||||
}
|
||||
final target = File('${stage.path}/$name');
|
||||
if (entry.isDirectory) {
|
||||
await Directory(target.path).create(recursive: true);
|
||||
} else if (entry.isFile) {
|
||||
await target.parent.create(recursive: true);
|
||||
await target.writeAsBytes(entry.content as List<int>);
|
||||
} else {
|
||||
throw FormatException('unsupported tar entry: $name');
|
||||
}
|
||||
}
|
||||
await for (final entity
|
||||
in stage.list(recursive: true, followLinks: false)) {
|
||||
if (entity is! File) continue;
|
||||
final rel = entity.path.substring(stage.path.length + 1);
|
||||
final dest = File('${root.path}/$rel');
|
||||
await dest.parent.create(recursive: true);
|
||||
if (await dest.exists() || await Link(dest.path).exists()) {
|
||||
await dest.delete();
|
||||
}
|
||||
await entity.rename(dest.path);
|
||||
}
|
||||
} finally {
|
||||
if (await stage.exists()) {
|
||||
await stage.delete(recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<ArchiveFile> _decodeArchive(List<int> raw) {
|
||||
if (raw.length > 2 && raw[0] == 0x1f && raw[1] == 0x8b) {
|
||||
return TarDecoder().decodeBytes(GZipDecoder().decodeBytes(raw)).files;
|
||||
}
|
||||
if (raw.length > 2 && raw[0] == 0x50 && raw[1] == 0x4b) {
|
||||
return ZipDecoder().decodeBytes(raw).files;
|
||||
}
|
||||
throw const FormatException('update is neither .tar.gz nor .zip');
|
||||
}
|
||||
|
||||
// Archive-relative path → clean segments; rejects anything that could
|
||||
// escape the target directory.
|
||||
List<String> _safeSegments(String name) {
|
||||
final norm = name.replaceAll('\\', '/');
|
||||
if (norm.startsWith('/') || RegExp(r'^[A-Za-z]:').hasMatch(norm)) {
|
||||
throw FormatException('unsafe archive entry: $name');
|
||||
}
|
||||
final segs = norm.split('/').where((s) => s.isNotEmpty && s != '.').toList();
|
||||
if (segs.contains('..')) {
|
||||
throw FormatException('unsafe archive entry: $name');
|
||||
}
|
||||
return segs;
|
||||
}
|
||||
|
||||
// Release archives wrap the bundle in one top-level folder
|
||||
// (watch-together-<ver>/, see tool/package_linux.sh). Strip it; a flat
|
||||
// archive (data/, lib/ and the binary at the top) is used as is.
|
||||
int _wrapperDepth(List<List<String>> entries) {
|
||||
final tops = entries.where((s) => s.isNotEmpty).map((s) => s.first).toSet();
|
||||
if (tops.length != 1 || tops.single == 'data' || tops.single == 'lib') {
|
||||
return 0;
|
||||
}
|
||||
return entries.any((s) => s.length > 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
// Symlink targets must stay inside the bundle.
|
||||
bool _linkStaysInside(List<String> linkDir, String target) {
|
||||
if (target.startsWith('/') || target.contains('\\')) return false;
|
||||
final stack = [...linkDir];
|
||||
for (final s in target.split('/')) {
|
||||
if (s.isEmpty || s == '.') continue;
|
||||
if (s == '..') {
|
||||
if (stack.isEmpty) return false;
|
||||
stack.removeLast();
|
||||
} else {
|
||||
stack.add(s);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> _extract(List<int> raw, Directory stage, bool posix) async {
|
||||
final files = _decodeArchive(raw);
|
||||
final segs = [for (final f in files) _safeSegments(f.name)];
|
||||
final depth = _wrapperDepth(segs);
|
||||
final modes = <int, List<String>>{};
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
final entry = files[i];
|
||||
if (segs[i].length <= depth) continue;
|
||||
final rel = segs[i].sublist(depth);
|
||||
final path = '${stage.path}/${rel.join('/')}';
|
||||
if (entry.isSymbolicLink) {
|
||||
final target = entry.symbolicLink!;
|
||||
if (!_linkStaysInside(rel.sublist(0, rel.length - 1), target)) {
|
||||
throw FormatException('unsafe symlink: ${entry.name} -> $target');
|
||||
}
|
||||
await Directory(File(path).parent.path).create(recursive: true);
|
||||
await Link(path).create(target);
|
||||
} else if (entry.isDirectory) {
|
||||
await Directory(path).create(recursive: true);
|
||||
} else {
|
||||
await Directory(File(path).parent.path).create(recursive: true);
|
||||
await File(path).writeAsBytes(entry.content);
|
||||
final mode = entry.mode & 0x1ff;
|
||||
if (posix && mode & 0x49 != 0) {
|
||||
modes.putIfAbsent(mode, () => []).add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
// dart:io has no chmod; one call per distinct mode keeps exec bits.
|
||||
for (final m in modes.entries) {
|
||||
final r = await Process.run('chmod', [m.key.toRadixString(8), ...m.value]);
|
||||
if (r.exitCode != 0) {
|
||||
throw FileSystemException('chmod failed: ${r.stderr}'.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _rename(String from, String to) async {
|
||||
switch (await FileSystemEntity.type(from, followLinks: false)) {
|
||||
case FileSystemEntityType.directory:
|
||||
await Directory(from).rename(to);
|
||||
case FileSystemEntityType.link:
|
||||
await Link(from).rename(to);
|
||||
case FileSystemEntityType.notFound:
|
||||
throw FileSystemException('missing', from);
|
||||
default:
|
||||
await File(from).rename(to);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _exists(String path) async =>
|
||||
await FileSystemEntity.type(path, followLinks: false) !=
|
||||
FileSystemEntityType.notFound;
|
||||
|
||||
Future<void> _deleteQuietly(String path) async {
|
||||
try {
|
||||
switch (await FileSystemEntity.type(path, followLinks: false)) {
|
||||
case FileSystemEntityType.directory:
|
||||
await Directory(path).delete(recursive: true);
|
||||
case FileSystemEntityType.notFound:
|
||||
break;
|
||||
default:
|
||||
await File(path).delete();
|
||||
}
|
||||
} catch (e) {
|
||||
_log.warning('could not remove $path: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Test seam: called before each move with a step label; throwing from it
|
||||
// simulates a mid-swap failure.
|
||||
typedef ApplyHook = Future<void> Function(String step);
|
||||
|
||||
// Unpack [archive] into a staging dir inside [root], then swap it in.
|
||||
// On failure the install is left exactly as it was.
|
||||
Future<void> applyUpdate(File archive, Directory root,
|
||||
{String? executableName, bool? windows, ApplyHook? hook}) async {
|
||||
final win = windows ?? Platform.isWindows;
|
||||
final stage = Directory('${root.path}/$_stagingDir');
|
||||
if (await stage.exists()) await stage.delete(recursive: true);
|
||||
await stage.create();
|
||||
try {
|
||||
await _extract(await archive.readAsBytes(), stage, !win);
|
||||
if (!_isBundle(stage.path, win) ||
|
||||
(executableName != null &&
|
||||
!await File('${stage.path}/$executableName').exists())) {
|
||||
throw const FormatException(
|
||||
'archive is not a release bundle (missing data/, lib/ or binary)');
|
||||
}
|
||||
if (win) {
|
||||
await _swapWindows(stage, root, hook);
|
||||
} else {
|
||||
await _swapPosix(stage, root, hook);
|
||||
}
|
||||
} finally {
|
||||
await _deleteQuietly(stage.path);
|
||||
}
|
||||
}
|
||||
|
||||
class _Moved {
|
||||
final String name;
|
||||
final bool hadOld;
|
||||
bool movedIn = false;
|
||||
_Moved(this.name, this.hadOld);
|
||||
}
|
||||
|
||||
Future<void> _swapPosix(Directory stage, Directory root, ApplyHook? hook) async {
|
||||
final backup = Directory('${root.path}/$_backupDir');
|
||||
if (await backup.exists()) await backup.delete(recursive: true);
|
||||
await backup.create();
|
||||
final names = [
|
||||
for (final e in await stage.list(followLinks: false).toList())
|
||||
e.path.substring(stage.path.length + 1)
|
||||
]..sort();
|
||||
final done = <_Moved>[];
|
||||
try {
|
||||
for (final name in names) {
|
||||
final cur = '${root.path}/$name';
|
||||
final m = _Moved(name, await _exists(cur));
|
||||
if (m.hadOld) {
|
||||
await hook?.call('aside:$name');
|
||||
await _rename(cur, '${backup.path}/$name');
|
||||
}
|
||||
done.add(m);
|
||||
await hook?.call('in:$name');
|
||||
await _rename('${stage.path}/$name', cur);
|
||||
m.movedIn = true;
|
||||
}
|
||||
} catch (e) {
|
||||
_log.warning('swap failed, rolling back: $e');
|
||||
for (final m in done.reversed) {
|
||||
final cur = '${root.path}/${m.name}';
|
||||
try {
|
||||
if (m.movedIn) await _rename(cur, '${stage.path}/${m.name}');
|
||||
if (m.hadOld) await _rename('${backup.path}/${m.name}', cur);
|
||||
} catch (re) {
|
||||
// Leave the backup dir in place so nothing is lost.
|
||||
_log.severe('rollback of ${m.name} failed: $re '
|
||||
'(old files kept in ${backup.path})');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
await _deleteQuietly(backup.path);
|
||||
rethrow;
|
||||
}
|
||||
await _deleteQuietly(backup.path);
|
||||
}
|
||||
|
||||
// UNTESTED on Windows. File-level: a running exe/dll can be renamed but
|
||||
// not deleted or overwritten, so every existing file goes to `<f>.old`
|
||||
// first; leftovers are swept by cleanupUpdateLeftovers on next start.
|
||||
Future<void> _swapWindows(Directory stage, Directory root, ApplyHook? hook) async {
|
||||
final rels = <String>[
|
||||
await for (final e in stage.list(recursive: true, followLinks: false))
|
||||
if (e is File) e.path.substring(stage.path.length + 1)
|
||||
]..sort();
|
||||
final done = <(String rel, String? old, bool movedIn)>[];
|
||||
try {
|
||||
for (final rel in rels) {
|
||||
final cur = '${root.path}/$rel';
|
||||
String? old;
|
||||
if (await File(cur).exists()) {
|
||||
old = '$cur.old';
|
||||
if (await File(old).exists()) {
|
||||
try {
|
||||
await File(old).delete();
|
||||
} on FileSystemException {
|
||||
old = '$cur.old.${DateTime.now().millisecondsSinceEpoch}';
|
||||
}
|
||||
}
|
||||
await hook?.call('aside:$rel');
|
||||
await File(cur).rename(old);
|
||||
}
|
||||
done.add((rel, old, false));
|
||||
await Directory(File(cur).parent.path).create(recursive: true);
|
||||
await hook?.call('in:$rel');
|
||||
await File('${stage.path}/$rel').rename(cur);
|
||||
done.last = (rel, old, true);
|
||||
}
|
||||
} catch (e) {
|
||||
_log.warning('swap failed, rolling back: $e');
|
||||
for (final (rel, old, movedIn) in done.reversed) {
|
||||
final cur = '${root.path}/$rel';
|
||||
if (movedIn) await File(cur).delete();
|
||||
if (old != null) await File(old).rename(cur);
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
for (final (_, old, _) in done) {
|
||||
if (old == null) continue;
|
||||
try {
|
||||
await File(old).delete();
|
||||
} on FileSystemException {
|
||||
// In use (the running exe/dlls) — swept next start.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shared by the CLI and the in-app banner: download next to the install
|
||||
// (same filesystem), verify, apply, clean up.
|
||||
Future<void> downloadAndApply(UpdateManifest manifest, Directory root,
|
||||
{HttpClient? http,
|
||||
DownloadProgress? onProgress,
|
||||
String? executableName,
|
||||
void Function(String line)? say}) async {
|
||||
final file = File('${root.path}/$_downloadFile');
|
||||
try {
|
||||
say?.call('downloading ${manifest.url} ...');
|
||||
await downloadFile(manifest.url, file, http: http, onProgress: onProgress);
|
||||
if (manifest.sha256 != null) {
|
||||
await verifySha256(file, manifest.sha256!);
|
||||
} else {
|
||||
say?.call('no checksum in manifest — skipping verification '
|
||||
'(HTTPS transit + gzip CRC still apply).');
|
||||
}
|
||||
say?.call('verified, applying over ${root.path} ...');
|
||||
await applyUpdate(file, root, executableName: executableName);
|
||||
} finally {
|
||||
await _deleteQuietly(file.path);
|
||||
}
|
||||
}
|
||||
|
||||
// Relaunch the (now replaced) binary detached with the same args, then
|
||||
// exit this process.
|
||||
Future<Never> restartApp(String executable, List<String> args) async {
|
||||
final keep = args.where((a) => a != '--upgrade').toList();
|
||||
await Process.start(executable, keep,
|
||||
mode: ProcessStartMode.detached,
|
||||
workingDirectory: Directory.current.path);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
String requiredUpdateNote(UpdateManifest m) =>
|
||||
'Required update: servers on ${m.version} speak protocol ${m.protocol}, '
|
||||
'this build speaks ${RelayConstants.protoVersion} and cannot join them.';
|
||||
|
||||
// Returns a process exit code: 0 ok / already current, 1 failure,
|
||||
// 2 not a packaged install (update manually).
|
||||
Future<int> runUpgrade(
|
||||
@@ -205,31 +546,24 @@ Future<int> runUpgrade(
|
||||
if (manifest.notes.isNotEmpty) {
|
||||
stdout.writeln(manifest.notes);
|
||||
}
|
||||
if (manifest.protocol != RelayConstants.protoVersion) {
|
||||
stdout.writeln('WARNING: protocol ${manifest.protocol} != ${RelayConstants.protoVersion} — '
|
||||
'update together with everyone in the room, mixed versions cannot sync.');
|
||||
if (manifest.isRequired) {
|
||||
stdout.writeln(requiredUpdateNote(manifest));
|
||||
}
|
||||
final root = installRoot ??
|
||||
findInstallRoot(executablePath ?? Platform.resolvedExecutable);
|
||||
final exe = executablePath ?? currentExecutablePath();
|
||||
final root = installRoot ?? findInstallRoot(exe);
|
||||
if (root == null) {
|
||||
stdout.writeln('not a packaged install — download the tarball and update manually.');
|
||||
return 2;
|
||||
}
|
||||
final tmp = await Directory.systemTemp.createTemp('watch-together-dl');
|
||||
try {
|
||||
final file = File('${tmp.path}/update.tar.gz');
|
||||
stdout.writeln('downloading ${manifest.url} ...');
|
||||
await downloadFile(manifest.url, file, http: http);
|
||||
await verifySha256(file, manifest.sha256);
|
||||
stdout.writeln('verified, applying over ${root.path} ...');
|
||||
await applyTarball(file, root);
|
||||
await cleanupUpdateLeftovers(root);
|
||||
await downloadAndApply(manifest, root,
|
||||
http: http,
|
||||
executableName: installRoot == null ? _basename(exe) : null,
|
||||
say: stdout.writeln);
|
||||
} catch (e) {
|
||||
stdout.writeln('update failed: $e');
|
||||
return 1;
|
||||
} finally {
|
||||
if (await tmp.exists()) {
|
||||
await tmp.delete(recursive: true);
|
||||
}
|
||||
}
|
||||
stdout.writeln('updated to ${manifest.version} — restart the app to use it.');
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '../playback/frame_watchdog.dart';
|
||||
|
||||
/// Fingerprints what the compositor really shows of the video. Place
|
||||
/// [anchor] in the video controls (built in the window and again in the
|
||||
/// fullscreen route); [sample] captures the route around the newest
|
||||
/// mounted anchor at ~200 px wide — the texture included — and hashes its
|
||||
/// centre. This is the only per-presented-frame signal: mpv's own
|
||||
/// counters keep ticking when the Flutter texture is stuck.
|
||||
class ShownFrameProbe {
|
||||
final _anchors = <_AnchorState>[];
|
||||
|
||||
Widget anchor() => _Anchor(probe: this);
|
||||
|
||||
Future<int?> sample() async {
|
||||
for (final a in _anchors.reversed) {
|
||||
if (!a.mounted) continue;
|
||||
final boundary = a.context.findAncestorRenderObjectOfType<RenderRepaintBoundary>();
|
||||
if (boundary == null || !boundary.attached || !boundary.hasSize) return null;
|
||||
final width = boundary.size.width;
|
||||
if (width <= 0) return null;
|
||||
ui.Image? image;
|
||||
try {
|
||||
image = await boundary.toImage(pixelRatio: (200 / width).clamp(0.02, 1.0));
|
||||
final data = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
|
||||
if (data == null) return null;
|
||||
return hashCenterPixels(data, image.width, image.height);
|
||||
} catch (_) {
|
||||
// Route not painted (covered) or mid-teardown: no reading.
|
||||
return null;
|
||||
} finally {
|
||||
image?.dispose();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class _Anchor extends StatefulWidget {
|
||||
final ShownFrameProbe probe;
|
||||
const _Anchor({required this.probe});
|
||||
|
||||
@override
|
||||
State<_Anchor> createState() => _AnchorState();
|
||||
}
|
||||
|
||||
class _AnchorState extends State<_Anchor> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
widget.probe._anchors.add(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.probe._anchors.remove(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => const SizedBox.shrink();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// True while keyboard focus sits in a text field. The focused node's
|
||||
/// context belongs to the `Focus` that `EditableText` builds, so look for
|
||||
/// an `EditableText` above it (walking FocusNode parents never meets one).
|
||||
bool textInputFocused([FocusNode? node]) {
|
||||
final n = node ?? FocusManager.instance.primaryFocus;
|
||||
return n?.context?.findAncestorWidgetOfExactType<EditableText>() != null;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../update/update_controller.dart';
|
||||
import '../update/updater.dart';
|
||||
|
||||
// "Update available" card (Home update indicator dialog). Kicks off the one
|
||||
// background check on first build; renders nothing until there is an
|
||||
// update to offer. Never shown over playback.
|
||||
class UpdateBanner extends StatefulWidget {
|
||||
const UpdateBanner({super.key, this.controller});
|
||||
|
||||
final UpdateController? controller;
|
||||
|
||||
@override
|
||||
State<UpdateBanner> createState() => _UpdateBannerState();
|
||||
}
|
||||
|
||||
class _UpdateBannerState extends State<UpdateBanner> {
|
||||
UpdateController get _c => widget.controller ?? UpdateController.instance;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_c.checkOnce();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ValueListenableBuilder<UpdateStatus>(
|
||||
valueListenable: _c.status,
|
||||
builder: (context, s, _) {
|
||||
final m = s.manifest;
|
||||
if (s.phase == UpdatePhase.idle || m == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final theme = Theme.of(context);
|
||||
final required = m.isRequired;
|
||||
final title = required
|
||||
? 'Required update: v${m.version}'
|
||||
: 'Update available: v${m.version}';
|
||||
final lines = <Widget>[
|
||||
Text(title, style: theme.textTheme.titleSmall),
|
||||
if (required)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 4),
|
||||
child: Text(
|
||||
'Servers on the new version use a newer protocol — '
|
||||
'this version cannot join them.',
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
if (m.notes.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
child: Text(m.notes,
|
||||
style: const TextStyle(fontSize: 12, color: Colors.grey)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
..._body(s),
|
||||
];
|
||||
return Card(
|
||||
color: required ? theme.colorScheme.errorContainer : null,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: lines,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _body(UpdateStatus s) {
|
||||
switch (s.phase) {
|
||||
case UpdatePhase.downloading:
|
||||
return [
|
||||
LinearProgressIndicator(value: s.progress),
|
||||
const SizedBox(height: 4),
|
||||
Text('Downloading… ${((s.progress ?? 0) * 100).round()}%',
|
||||
style: const TextStyle(fontSize: 12)),
|
||||
];
|
||||
case UpdatePhase.applying:
|
||||
return const [
|
||||
LinearProgressIndicator(),
|
||||
SizedBox(height: 4),
|
||||
Text('Installing…', style: TextStyle(fontSize: 12)),
|
||||
];
|
||||
case UpdatePhase.restarting:
|
||||
return const [Text('Restarting…', style: TextStyle(fontSize: 12))];
|
||||
case UpdatePhase.failed:
|
||||
return [
|
||||
Text('Update failed: ${s.error}',
|
||||
style: const TextStyle(fontSize: 12)),
|
||||
const SizedBox(height: 8),
|
||||
_actions(retry: true, manifest: s.manifest!),
|
||||
];
|
||||
case UpdatePhase.available:
|
||||
if (!s.canInstall) {
|
||||
return const [
|
||||
Text(
|
||||
'Not a packaged install — download the new release and '
|
||||
'replace this folder by hand.',
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
];
|
||||
}
|
||||
return [_actions(retry: false, manifest: s.manifest!)];
|
||||
case UpdatePhase.idle:
|
||||
return const [];
|
||||
}
|
||||
}
|
||||
|
||||
Widget _actions({required bool retry, required UpdateManifest manifest}) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (!manifest.isRequired)
|
||||
TextButton(onPressed: _c.dismiss, child: const Text('Later')),
|
||||
const SizedBox(width: 8),
|
||||
FilledButton(
|
||||
onPressed: _c.install,
|
||||
child: Text(retry ? 'Retry' : 'Update and restart'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../state/session_state.dart';
|
||||
import 'avatar_pipeline.dart';
|
||||
|
||||
/// Profile card for the connect screen.
|
||||
///
|
||||
/// Lives in a fixed corner card outside the scrolling form, so Host/Join
|
||||
/// field changes below never move it. Name edits write back to
|
||||
/// [SessionState.lastForm] on every change (persisted on submit); avatar
|
||||
/// changes by tapping the circle, validated through [encodeAvatar] before
|
||||
/// the path is stored, with the encoded bytes shown as the preview.
|
||||
class ConnectProfileCard extends StatefulWidget {
|
||||
final TextEditingController name;
|
||||
const ConnectProfileCard({super.key, required this.name});
|
||||
|
||||
@override
|
||||
State<ConnectProfileCard> createState() => _ConnectProfileCardState();
|
||||
}
|
||||
|
||||
class _ConnectProfileCardState extends State<ConnectProfileCard> {
|
||||
late String _avatarPath;
|
||||
Uint8List? _preview;
|
||||
String? _error;
|
||||
bool _picking = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_avatarPath = SessionState.instance.lastForm.avatarPath;
|
||||
_refreshPreview();
|
||||
}
|
||||
|
||||
Future<void> _refreshPreview() async {
|
||||
String b64;
|
||||
try {
|
||||
b64 = await encodeAvatar(_avatarPath);
|
||||
} catch (_) {
|
||||
return;
|
||||
}
|
||||
if (!mounted) return;
|
||||
setState(() => _preview = b64.isEmpty ? null : base64Decode(b64));
|
||||
}
|
||||
|
||||
Future<void> _persistProfile() async {
|
||||
try {
|
||||
await SessionState.instance.saveForm();
|
||||
} catch (_) {
|
||||
if (!mounted) return;
|
||||
setState(() => _error = 'could not save profile — try again');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _pickAvatar() async {
|
||||
if (_picking) return;
|
||||
setState(() {
|
||||
_picking = true;
|
||||
_error = null;
|
||||
});
|
||||
try {
|
||||
final List<PlatformFile> files;
|
||||
try {
|
||||
files = await FilePicker.pickFiles(
|
||||
dialogTitle: 'Pick avatar image',
|
||||
type: FileType.custom,
|
||||
allowedExtensions: const ['png', 'jpg', 'jpeg', 'webp'],
|
||||
);
|
||||
} catch (_) {
|
||||
if (!mounted) return;
|
||||
setState(() => _error = 'file dialog unavailable — try again');
|
||||
return;
|
||||
}
|
||||
if (files.isEmpty) return;
|
||||
final path = files.first.path;
|
||||
if (path == null || !mounted) return;
|
||||
late final String b64;
|
||||
try {
|
||||
b64 = await encodeAvatar(path);
|
||||
} on FormatException catch (e) {
|
||||
if (!mounted) return;
|
||||
setState(() => _error = e.message);
|
||||
return;
|
||||
} catch (_) {
|
||||
if (!mounted) return;
|
||||
setState(() => _error = 'could not read that image — pick a PNG, JPG or WebP photo');
|
||||
return;
|
||||
}
|
||||
_avatarPath = path;
|
||||
SessionState.instance.lastForm.avatarPath = path;
|
||||
await _persistProfile();
|
||||
if (!mounted) return;
|
||||
setState(() => _preview = b64.isEmpty ? null : base64Decode(b64));
|
||||
} finally {
|
||||
if (mounted) setState(() => _picking = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: .center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 12,
|
||||
children: [
|
||||
ClipOval(
|
||||
clipBehavior: .antiAlias,
|
||||
child: Tooltip(
|
||||
message: 'Change avatar',
|
||||
child: Stack(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 64,
|
||||
backgroundColor: Colors.transparent,
|
||||
backgroundImage: _preview != null ? MemoryImage(_preview!) : null,
|
||||
child: _preview != null
|
||||
? null
|
||||
: _picking
|
||||
? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: ListenableBuilder(
|
||||
listenable: widget.name,
|
||||
builder: (context, _) {
|
||||
final t = widget.name.text.trim();
|
||||
return Text(t.isEmpty ? '?' : t[0].toUpperCase());
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Material(
|
||||
type: .transparency,
|
||||
child: InkWell(onTap: _pickAvatar),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 180,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextField(
|
||||
controller: widget.name,
|
||||
decoration: const InputDecoration(labelText: 'Display name', isDense: true),
|
||||
onChanged: (_) {
|
||||
SessionState.instance.lastForm.name = widget.name.text.trim();
|
||||
},
|
||||
onSubmitted: (_) => _persistProfile(),
|
||||
),
|
||||
if (_error != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
child: Text(_error!, style: const TextStyle(fontSize: 11)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
name: watch_together
|
||||
description: Watch-together desktop app (working title, repo sync_relay_project). One binary.
|
||||
publish_to: none
|
||||
version: 0.1.0
|
||||
version: 0.2.0
|
||||
environment:
|
||||
sdk: '>=3.13.0-0 <4.0.0'
|
||||
|
||||
@@ -31,3 +31,5 @@ dev_dependencies:
|
||||
flutter_lints: ^5.0.0
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
assets:
|
||||
- assets/shaders/anime4k/
|
||||
@@ -0,0 +1,150 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
import 'package:sync_relay_server/server.dart';
|
||||
import 'package:watch_together/src/playback/media_marks.dart';
|
||||
import 'package:watch_together/src/session/session_coordinator.dart';
|
||||
import 'package:watch_together/src/sync/state_diff.dart';
|
||||
|
||||
final _tmp = Platform.environment['WT_TEST_TMP'] ?? Directory.systemTemp.path;
|
||||
|
||||
/// 23 min mkv with chapters OP 0:30-2:00, Part A, ED 20:00-21:30, Part B,
|
||||
/// two audio tracks (jpn, eng "Dub") and an English srt subtitle.
|
||||
Future<String> _media() async {
|
||||
final path = '$_tmp/chapters_23m.mkv';
|
||||
if (await File(path).exists()) return path;
|
||||
final meta = File('$_tmp/chapters_meta.txt');
|
||||
String chapter(int start, int end, String title) =>
|
||||
'[CHAPTER]\nTIMEBASE=1/1000\nSTART=${start * 1000}\nEND=${end * 1000}\ntitle=$title\n';
|
||||
await meta.writeAsString(';FFMETADATA1\n'
|
||||
'${chapter(30, 120, 'OP')}${chapter(120, 1200, 'Part A')}'
|
||||
'${chapter(1200, 1290, 'ED')}${chapter(1290, 1380, 'Part B')}');
|
||||
final srt = File('$_tmp/chapters_subs.srt');
|
||||
await srt.writeAsString('1\n00:00:01,000 --> 00:00:05,000\nHello\n');
|
||||
final r = await Process.run('ffmpeg', [
|
||||
'-y', '-v', 'error',
|
||||
'-f', 'lavfi', '-i', 'testsrc2=size=160x120:rate=10',
|
||||
'-f', 'lavfi', '-i', 'sine=frequency=440:sample_rate=48000',
|
||||
'-f', 'lavfi', '-i', 'sine=frequency=660:sample_rate=48000',
|
||||
'-i', srt.path, '-i', meta.path,
|
||||
'-map', '0:v', '-map', '1:a', '-map', '2:a', '-map', '3:s',
|
||||
'-map_metadata', '4', '-map_chapters', '4',
|
||||
'-metadata:s:a:0', 'language=jpn',
|
||||
'-metadata:s:a:1', 'language=eng', '-metadata:s:a:1', 'title=Dub',
|
||||
'-metadata:s:s:0', 'language=eng',
|
||||
'-t', '1380', '-c:v', 'libx264', '-preset', 'ultrafast', '-g', '10',
|
||||
'-pix_fmt', 'yuv420p', '-c:a', 'aac', '-b:a', '32k', '-c:s', 'srt', path,
|
||||
]);
|
||||
if (r.exitCode != 0) fail('ffmpeg failed: ${r.stderr}');
|
||||
return path;
|
||||
}
|
||||
|
||||
Future<void> _poll(
|
||||
FutureOr<bool> Function() cond,
|
||||
String what, {
|
||||
Duration timeout = const Duration(seconds: 30),
|
||||
}) async {
|
||||
final deadline = DateTime.now().add(timeout);
|
||||
while (DateTime.now().isBefore(deadline)) {
|
||||
if (await cond()) return;
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
fail('timed out waiting for $what');
|
||||
}
|
||||
|
||||
void main() {
|
||||
test(
|
||||
'chapters and tracks from mpv; Skip OP and PgDn go through the server',
|
||||
timeout: const Timeout(Duration(minutes: 5)),
|
||||
() async {
|
||||
MediaKit.ensureInitialized();
|
||||
final media = await _media();
|
||||
final server = SyncServer(AppConfig(port: 0, secret: 'ch', name: 'ch', mediaPath: media));
|
||||
await server.start();
|
||||
final a = SessionCoordinator();
|
||||
final b = SessionCoordinator();
|
||||
try {
|
||||
for (final (c, name) in [(a, 'a'), (b, 'b')]) {
|
||||
await c.connect(ConnectParams(
|
||||
host: '127.0.0.1', port: server.boundPort, secret: 'ch', name: name));
|
||||
await c.playback.player.setVolume(0);
|
||||
}
|
||||
await _poll(() => a.serverState.peek()?.members.length == 2, 'both in');
|
||||
|
||||
// chapters signal: titles, starts, ends (last = duration).
|
||||
await _poll(() => a.playback.chapters.peek().length == 4 && a.playback.duration.peek() > Duration.zero,
|
||||
'chapters');
|
||||
final ch = a.playback.chapters.peek();
|
||||
// ignore: avoid_print
|
||||
print('chapters: $ch');
|
||||
expect(ch.map((c) => c.title), ['OP', 'Part A', 'ED', 'Part B']);
|
||||
expect(ch.map((c) => c.start.inSeconds), [30, 120, 1200, 1290]);
|
||||
expect(ch[2].end, ch[3].start);
|
||||
expect(ch[3].end.inSeconds, closeTo(1380, 1));
|
||||
expect(a.playback.opening.peek(),
|
||||
SkipRange(const Duration(seconds: 30), ch[1].start, SkipSource.chapter, title: 'OP'));
|
||||
expect(a.playback.ending.peek()!.start, const Duration(minutes: 20));
|
||||
expect(a.playback.segments.peek(), isEmpty, reason: 'not a Jellyfin item');
|
||||
|
||||
// buffered signal: mpv's demuxer cache (the timeline's hatching)
|
||||
// runs ahead of the position.
|
||||
await _poll(() => a.playback.buffered.peek() > a.playback.position.peek() + const Duration(seconds: 5),
|
||||
'cache ahead');
|
||||
expect(a.playback.buffered.peek(), lessThanOrEqualTo(a.playback.duration.peek()));
|
||||
|
||||
// tracks signal: two audio, one subtitle; mpv's choice marked.
|
||||
await _poll(() => a.playback.tracks.peek().length == 3, 'tracks');
|
||||
final tracks = a.playback.tracks.peek();
|
||||
// ignore: avoid_print
|
||||
print('tracks: $tracks');
|
||||
final audio = tracks.where((t) => t.type == JellyfinStreamType.audio).toList();
|
||||
expect(audio.map((t) => t.label), ['Japanese · AAC 1.0', 'English · AAC 1.0 · Dub']);
|
||||
expect(audio.first.selected, isTrue);
|
||||
await a.selectTrack(aid: 2);
|
||||
expect(a.playback.tracks.peek().where((t) => t.selected && t.type == JellyfinStreamType.audio).single.id, 2);
|
||||
|
||||
a.toggleReady();
|
||||
b.toggleReady();
|
||||
await _poll(() => a.playback.player.state.playing && b.playback.player.state.playing, 'both playing');
|
||||
|
||||
// Into the OP: the pill offers Skip OP to its end.
|
||||
a.seekTo(40);
|
||||
await _poll(() {
|
||||
final r = a.serverState.peek();
|
||||
return r != null && r.seekBy == a.sync.memberId && (r.position - 40).abs() < 2;
|
||||
}, 'server at 0:40');
|
||||
await _poll(() => a.skipOffer.peek()?.kind == SkipKind.opening, 'Skip OP offered');
|
||||
expect(a.skipOffer.peek()!.target, const Duration(minutes: 2));
|
||||
int seeks(SessionCoordinator c) => c.feedLog.peek().where((f) => f.action == 'seek').length;
|
||||
await _poll(() => seeks(b) >= 1 && seeks(b) == seeks(a), 'b saw the seek to 0:40');
|
||||
final seeksBefore = seeks(b);
|
||||
a.skip(a.skipOffer.peek()!);
|
||||
await _poll(() {
|
||||
final r = a.serverState.peek();
|
||||
return r != null &&
|
||||
r.seekBy == a.sync.memberId &&
|
||||
serverPositionAt(r, a.sync.serverNow()) >= 120 &&
|
||||
serverPositionAt(r, a.sync.serverNow()) < 125;
|
||||
}, 'server at the OP end');
|
||||
await _poll(() => b.playback.positionSecs >= 119.5 && b.playback.positionSecs < 126, 'b follows');
|
||||
await _poll(() => seeks(b) == seeksBefore + 1, 'b saw the Skip OP seek');
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
expect(seeks(b), seeksBefore + 1, reason: 'Skip OP is one seek');
|
||||
await _poll(() => a.skipOffer.peek() == null, 'pill gone after the OP');
|
||||
|
||||
// PgDn: next chapter (ED at 20:00), for everyone.
|
||||
expect(a.stepChapter(1), isTrue);
|
||||
await _poll(() => b.playback.positionSecs >= 1199.5 && b.playback.positionSecs < 1206, 'b at the ED');
|
||||
await _poll(() => a.skipOffer.peek()?.kind == SkipKind.ending, 'Skip ED offered');
|
||||
expect(a.skipOffer.peek()!.target, const Duration(minutes: 21, seconds: 30));
|
||||
} finally {
|
||||
await a.dispose();
|
||||
await b.dispose();
|
||||
await server.stop();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
import 'package:sync_relay_server/server.dart';
|
||||
import 'package:watch_together/src/sync/state_diff.dart';
|
||||
import 'package:watch_together/src/sync/sync_client.dart';
|
||||
|
||||
Future<void> _poll(FutureOr<bool> Function() cond, String what) async {
|
||||
final end = DateTime.now().add(const Duration(seconds: 10));
|
||||
while (DateTime.now().isBefore(end)) {
|
||||
if (await cond()) return;
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
}
|
||||
fail('timed out waiting for $what');
|
||||
}
|
||||
|
||||
void main() {
|
||||
test('a client whose clock is 3 s off still extrapolates the server position',
|
||||
() async {
|
||||
final server = SyncServer(const AppConfig(port: 0, secret: '', name: 'clk'));
|
||||
await server.start();
|
||||
const skew = Duration(seconds: 3);
|
||||
final client = SyncClient(clock: () => DateTime.now().toUtc().add(skew));
|
||||
try {
|
||||
await client.connect(
|
||||
wsUri: Uri.parse('ws://127.0.0.1:${server.boundPort}/sync'),
|
||||
secret: '',
|
||||
name: 'skewed');
|
||||
client.sendReady(true);
|
||||
client.sendReport(position: 0, buffered: 10, eventId: 0);
|
||||
await _poll(() => client.lastState?.transport == 'playing', 'playing');
|
||||
for (var i = 0; i < 5; i++) {
|
||||
client.sendPing();
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
}
|
||||
await _poll(() => client.clockSync.hasSample, 'a pong');
|
||||
expect(client.clockSync.offsetMs, closeTo(-skew.inMilliseconds, 50));
|
||||
final st = client.lastState!;
|
||||
final truth = server.hub.engine.positionAt();
|
||||
// The bug: extrapolating with the local clock is off by the skew.
|
||||
final naive = serverPositionAt(st, DateTime.now().toUtc().add(skew));
|
||||
expect(naive - truth, closeTo(3, 0.1));
|
||||
// The fix: extrapolate on the server's clock.
|
||||
final corrected = serverPositionAt(st, client.serverNow());
|
||||
expect(corrected, closeTo(truth, 0.1));
|
||||
} finally {
|
||||
await client.dispose();
|
||||
await server.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
import 'package:sync_relay_server/server.dart';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import 'package:watch_together/src/session/session_coordinator.dart';
|
||||
import 'package:watch_together/src/state/session_state.dart';
|
||||
import 'package:watch_together/src/sync/sync_client.dart';
|
||||
|
||||
Future<void> _poll(
|
||||
FutureOr<bool> Function() cond,
|
||||
@@ -21,11 +25,11 @@ Future<void> _poll(
|
||||
|
||||
void main() {
|
||||
test(
|
||||
'dead server clears room state and reconnects instead of freezing',
|
||||
'dead server clears server state and reconnects instead of freezing',
|
||||
timeout: const Timeout(Duration(minutes: 2)),
|
||||
() async {
|
||||
MediaKit.ensureInitialized();
|
||||
final server = RoomServer(
|
||||
final server = SyncServer(
|
||||
const AppConfig(port: 0, secret: 'presence', name: 'presence'));
|
||||
await server.start();
|
||||
final coord = SessionCoordinator();
|
||||
@@ -37,7 +41,7 @@ void main() {
|
||||
name: 'watcher',
|
||||
));
|
||||
await coord.playback.player.setVolume(0);
|
||||
await _poll(() => coord.room.peek() != null, 'room state to arrive');
|
||||
await _poll(() => coord.serverState.peek() != null, 'server state to arrive');
|
||||
expect(coord.reconnecting.peek(), isFalse);
|
||||
|
||||
await server.stop();
|
||||
@@ -46,8 +50,8 @@ void main() {
|
||||
'reconnect loop to engage',
|
||||
);
|
||||
await _poll(
|
||||
() => coord.room.peek() == null,
|
||||
'stale room (ghost members) to clear',
|
||||
() => coord.serverState.peek() == null,
|
||||
'stale state (ghost members) to clear',
|
||||
);
|
||||
coord.cancelReconnect();
|
||||
expect(coord.reconnecting.peek(), isFalse);
|
||||
@@ -56,4 +60,150 @@ void main() {
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'cancel then retry within the reconnect delay dials only once',
|
||||
timeout: const Timeout(Duration(minutes: 2)),
|
||||
() async {
|
||||
MediaKit.ensureInitialized();
|
||||
final first = SyncServer(
|
||||
const AppConfig(port: 0, secret: 'race', name: 'race'));
|
||||
await first.start();
|
||||
final port = first.boundPort;
|
||||
final coord = SessionCoordinator();
|
||||
SyncServer? second;
|
||||
final observer = SyncClient();
|
||||
try {
|
||||
await coord.connect(ConnectParams(
|
||||
host: '127.0.0.1', port: port, secret: 'race', name: 'watcher'));
|
||||
await coord.playback.player.setVolume(0);
|
||||
await first.stop();
|
||||
await _poll(() => coord.reconnecting.peek(), 'reconnect to engage');
|
||||
second = SyncServer(
|
||||
AppConfig(port: port, secret: 'race', name: 'race'));
|
||||
await second.start();
|
||||
var joins = 0;
|
||||
final sub = observer.feeds.listen((f) {
|
||||
if (f.action == 'join' && f.actor == 'watcher') joins++;
|
||||
});
|
||||
await observer.connect(
|
||||
wsUri: Uri.parse('ws://127.0.0.1:$port/sync'),
|
||||
secret: 'race',
|
||||
name: 'observer');
|
||||
// Within the 1.5 s delay: the first attempt must die with Cancel.
|
||||
coord.cancelReconnect();
|
||||
coord.retry();
|
||||
await _poll(() => !coord.reconnecting.peek() && coord.serverState.peek() != null,
|
||||
'reconnect to land');
|
||||
await Future.delayed(const Duration(seconds: 4));
|
||||
await sub.cancel();
|
||||
expect(joins, 1, reason: 'a stale attempt dialled a second time');
|
||||
expect(
|
||||
second.hub.engine.members.values
|
||||
.where((m) => m.name == 'watcher')
|
||||
.length,
|
||||
1);
|
||||
} finally {
|
||||
await observer.dispose();
|
||||
await coord.dispose();
|
||||
await second?.stop();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'reconnect restores the server-side ready flag (force-all included)',
|
||||
timeout: const Timeout(Duration(minutes: 2)),
|
||||
() async {
|
||||
MediaKit.ensureInitialized();
|
||||
final first = SyncServer(
|
||||
const AppConfig(port: 0, secret: 'force', name: 'force'));
|
||||
await first.start();
|
||||
final port = first.boundPort;
|
||||
final coord = SessionCoordinator();
|
||||
final friend = SyncClient();
|
||||
SyncServer? second;
|
||||
try {
|
||||
await coord.connect(ConnectParams(
|
||||
host: '127.0.0.1', port: port, secret: 'force', name: 'watcher'));
|
||||
await coord.playback.player.setVolume(0);
|
||||
await friend.connect(
|
||||
wsUri: Uri.parse('ws://127.0.0.1:$port/sync'),
|
||||
secret: 'force',
|
||||
name: 'friend');
|
||||
// Never pressed Space locally; a friend marks everyone ready.
|
||||
friend.sendForce('all', true);
|
||||
await _poll(() => coord.selfMember.peek()?.ready == true,
|
||||
'forced ready to reach watcher');
|
||||
await friend.disconnect();
|
||||
await first.stop();
|
||||
await _poll(() => coord.reconnecting.peek(), 'reconnect to engage');
|
||||
second = SyncServer(
|
||||
AppConfig(port: port, secret: 'force', name: 'force'));
|
||||
await second.start();
|
||||
await _poll(
|
||||
() => second!.hub.engine.members.values
|
||||
.any((m) => m.name == 'watcher' && m.ready),
|
||||
'watcher to come back ready');
|
||||
} finally {
|
||||
await friend.dispose();
|
||||
await coord.dispose();
|
||||
await second?.stop();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'cancel during connect setup aborts without joining',
|
||||
timeout: const Timeout(Duration(minutes: 1)),
|
||||
() async {
|
||||
MediaKit.ensureInitialized();
|
||||
final server = SyncServer(
|
||||
const AppConfig(port: 0, secret: '', name: 'cancel'));
|
||||
await server.start();
|
||||
final coord = SessionCoordinator();
|
||||
try {
|
||||
final pending = coord.connect(ConnectParams(
|
||||
host: '127.0.0.1',
|
||||
port: server.boundPort,
|
||||
secret: '',
|
||||
name: 'watcher'));
|
||||
await coord.cancelConnect();
|
||||
await expectLater(pending, throwsA(isA<ConnectCancelled>()));
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
expect(server.hub.engine.members, isEmpty);
|
||||
expect(coord.reconnecting.peek(), isFalse);
|
||||
} finally {
|
||||
await coord.dispose();
|
||||
await server.stop();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'cancelling a host setup releases the port',
|
||||
timeout: const Timeout(Duration(minutes: 1)),
|
||||
() async {
|
||||
MediaKit.ensureInitialized();
|
||||
Hive.init(
|
||||
'${Platform.environment['WT_TEST_TMP'] ?? Directory.systemTemp.path}/hive_coord_test');
|
||||
final probe = await ServerSocket.bind(InternetAddress.anyIPv4, 0);
|
||||
final port = probe.port;
|
||||
await probe.close();
|
||||
final session = SessionState.instance;
|
||||
try {
|
||||
final pending = session.host(
|
||||
ConnectParams(host: '', port: port, secret: '', name: 'host'),
|
||||
ConnectForm());
|
||||
await session.cancelPending();
|
||||
await expectLater(pending, throwsA(isA<ConnectCancelled>()));
|
||||
expect(session.route.peek(), isNot(AppRoute.session));
|
||||
final rebind = await ServerSocket.bind(InternetAddress.anyIPv4, port);
|
||||
await rebind.close();
|
||||
} finally {
|
||||
await session.coordinator.leave(silent: true);
|
||||
await session.stopServer();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
import 'package:sync_relay_server/server.dart';
|
||||
import 'package:watch_together/src/session/session_coordinator.dart';
|
||||
|
||||
const _mediaPath = '/home/foxyz/Videos/chiyo.mp4'; // 13.8 s
|
||||
|
||||
Future<void> _poll(
|
||||
FutureOr<bool> Function() cond,
|
||||
String what, {
|
||||
Duration timeout = const Duration(seconds: 30),
|
||||
}) async {
|
||||
final deadline = DateTime.now().add(timeout);
|
||||
while (DateTime.now().isBefore(deadline)) {
|
||||
if (await cond()) return;
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
fail('timed out waiting for $what');
|
||||
}
|
||||
|
||||
void main() {
|
||||
test(
|
||||
'plays through the last 4 s to finished; seek back plays again',
|
||||
timeout: const Timeout(Duration(minutes: 2)),
|
||||
() async {
|
||||
MediaKit.ensureInitialized();
|
||||
final server = SyncServer(const AppConfig(
|
||||
port: 0, secret: 'eof', name: 'eof', mediaPath: _mediaPath));
|
||||
await server.start();
|
||||
final c = SessionCoordinator();
|
||||
try {
|
||||
await c.connect(ConnectParams(
|
||||
host: '127.0.0.1',
|
||||
port: server.boundPort,
|
||||
secret: 'eof',
|
||||
name: 'solo'));
|
||||
await c.playback.player.setVolume(0);
|
||||
await _poll(() => c.serverState.peek() != null, 'server state');
|
||||
await _poll(
|
||||
() => (c.serverState.peek()?.media?['duration'] as num? ?? 0) > 13,
|
||||
'server learns the duration from reports');
|
||||
c.toggleReady();
|
||||
await _poll(() => c.playback.player.state.playing, 'playing');
|
||||
c.seekTo(7);
|
||||
final transports = <String>[];
|
||||
await _poll(() {
|
||||
transports.add(c.serverState.peek()?.transport ?? '');
|
||||
return c.serverState.peek()?.transport == 'finished';
|
||||
}, 'finished at the end');
|
||||
// ignore: avoid_print
|
||||
print('transports: ${transports.toSet()} '
|
||||
'end at ${c.playback.positionSecs.toStringAsFixed(2)}');
|
||||
expect(transports, isNot(contains('held')),
|
||||
reason: 'never held in the last seconds');
|
||||
expect(c.serverState.peek()!.position, closeTo(13.77, 0.1));
|
||||
await _poll(() => !c.playback.player.state.playing, 'player stopped');
|
||||
expect(c.playback.positionSecs, greaterThan(12));
|
||||
expect(c.starving.peek(), contains('finished'));
|
||||
|
||||
c.seekTo(2);
|
||||
await _poll(
|
||||
() =>
|
||||
c.serverState.peek()?.transport == 'playing' &&
|
||||
c.playback.player.state.playing &&
|
||||
c.playback.positionSecs < 6,
|
||||
'seek back from finished plays again');
|
||||
} finally {
|
||||
await c.dispose();
|
||||
await server.stop();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:watch_together/src/playback/frame_watchdog.dart';
|
||||
|
||||
final _t0 = DateTime.utc(2026, 1, 1);
|
||||
|
||||
/// Feeds one sample per second; [frames]/[pos] give the value at second i.
|
||||
List<bool> _run(
|
||||
FrameWatchdog w,
|
||||
int seconds, {
|
||||
required int? Function(int i) frames,
|
||||
double Function(int i)? pos,
|
||||
bool Function(int i)? eligible,
|
||||
int start = 0,
|
||||
}) {
|
||||
return [
|
||||
for (var i = start; i < start + seconds; i++)
|
||||
w.feed(FrameSample(
|
||||
at: _t0.add(Duration(seconds: i)),
|
||||
position: pos?.call(i) ?? i.toDouble(),
|
||||
frames: frames(i),
|
||||
eligible: eligible?.call(i) ?? true,
|
||||
)),
|
||||
];
|
||||
}
|
||||
|
||||
void main() {
|
||||
test('hashes tell frames apart and ignore the edges', () {
|
||||
final a = ByteData(100 * 60 * 4);
|
||||
final b = ByteData(100 * 60 * 4);
|
||||
expect(hashCenterPixels(a, 100, 60), hashCenterPixels(b, 100, 60));
|
||||
b.setUint8((2 * 100 + 2) * 4, 255); // corner: overlay area
|
||||
expect(hashCenterPixels(a, 100, 60), hashCenterPixels(b, 100, 60));
|
||||
b.setUint8((30 * 100 + 50) * 4, 255); // centre: video
|
||||
expect(hashCenterPixels(a, 100, 60), isNot(hashCenterPixels(b, 100, 60)));
|
||||
final raw = Uint8List(1 << 20);
|
||||
final h = hashSpread(raw);
|
||||
raw[raw.length ~/ 2 - (raw.length ~/ 2) % (raw.length ~/ 4096)] = 1;
|
||||
expect(hashSpread(raw), isNot(h));
|
||||
});
|
||||
|
||||
test('frames advancing never fires', () {
|
||||
final w = FrameWatchdog();
|
||||
expect(_run(w, 30, frames: (i) => i * 30), everyElement(isFalse));
|
||||
});
|
||||
|
||||
test('frames stuck while position advances fires once after ~3 s', () {
|
||||
final w = FrameWatchdog();
|
||||
final fired = _run(w, 20, frames: (i) => i < 5 ? i * 30 : 150);
|
||||
expect(fired.where((f) => f).length, 1);
|
||||
expect(fired.indexOf(true), 8, reason: 'stuck from t=5, 3 s later');
|
||||
});
|
||||
|
||||
test('pause, buffering, missing data and seeks do not fire', () {
|
||||
final w = FrameWatchdog();
|
||||
// Paused / buffering: not eligible.
|
||||
expect(_run(w, 10, frames: (_) => 100, eligible: (_) => false),
|
||||
everyElement(isFalse));
|
||||
// No video output (headless / audio-only).
|
||||
expect(_run(w, 10, frames: (_) => null, start: 10), everyElement(isFalse));
|
||||
// Position stuck too (network stall): not a frozen picture.
|
||||
expect(_run(w, 10, frames: (_) => 100, pos: (_) => 50, start: 20),
|
||||
everyElement(isFalse));
|
||||
// Seeking every 2 s with frames stuck in between: jumps reset it.
|
||||
expect(
|
||||
_run(w, 12,
|
||||
frames: (_) => 100,
|
||||
pos: (i) => i.isEven ? i * 10.0 : i * 10.0 - 9,
|
||||
start: 30),
|
||||
everyElement(isFalse));
|
||||
});
|
||||
|
||||
test('no reload loop: re-arms only after 10 s of healthy frames', () {
|
||||
final w = FrameWatchdog();
|
||||
expect(_run(w, 10, frames: (_) => 7).where((f) => f).length, 1);
|
||||
w.reset(); // new player
|
||||
// Brief healthy spell, then stuck again: must not fire.
|
||||
expect(
|
||||
_run(w, 15, frames: (i) => i < 13 ? i : 13, start: 10)
|
||||
.where((f) => f)
|
||||
.length,
|
||||
0);
|
||||
// Healthy for 10 s+, then stuck: fires again.
|
||||
w.reset();
|
||||
expect(
|
||||
_run(w, 25, frames: (i) => i < 42 ? i : 42, start: 30)
|
||||
.where((f) => f)
|
||||
.length,
|
||||
1);
|
||||
});
|
||||
|
||||
test('still scene: dismiss re-arms after another full stall', () {
|
||||
final w = FrameWatchdog();
|
||||
final fired = <int>[];
|
||||
for (var i = 0; i < 20; i++) {
|
||||
if (w.feed(FrameSample(
|
||||
at: _t0.add(Duration(seconds: i)),
|
||||
position: i.toDouble(),
|
||||
frames: 5,
|
||||
eligible: true))) {
|
||||
fired.add(i);
|
||||
w.dismiss();
|
||||
}
|
||||
}
|
||||
expect(fired, [3, 6, 9, 12, 15, 18]);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
import 'package:watch_together/src/screens/home/health_probe.dart';
|
||||
import 'package:watch_together/src/screens/home/home_screen.dart';
|
||||
import 'package:watch_together/src/screens/home/media_picker.dart';
|
||||
import 'package:watch_together/src/screens/home/ui.dart';
|
||||
import 'package:watch_together/src/state/session_state.dart';
|
||||
import 'package:watch_together/src/state/settings.dart';
|
||||
import 'package:watch_together/src/update/update_controller.dart';
|
||||
|
||||
RecentServer join(String host, String port, [String secret = '']) =>
|
||||
RecentServer(hosted: false, host: host, port: port, secret: secret);
|
||||
|
||||
void main() {
|
||||
group('recent servers', () {
|
||||
test('newest first, deduped by server, capped', () {
|
||||
var list = <RecentServer>[];
|
||||
for (var i = 0; i < 8; i++) {
|
||||
list = pushRecent(list, join('10.0.0.$i', '8080'));
|
||||
}
|
||||
expect(list.length, maxRecentServers);
|
||||
expect(list.first.host, '10.0.0.7');
|
||||
list = pushRecent(list, join('10.0.0.4', '8080', 'pw'));
|
||||
expect(list.length, maxRecentServers);
|
||||
expect(list.first.secret, 'pw');
|
||||
expect(list.where((r) => r.host == '10.0.0.4').length, 1);
|
||||
});
|
||||
|
||||
test('hosted entries are one per port, separate from joins', () {
|
||||
var list = <RecentServer>[];
|
||||
list = pushRecent(list, const RecentServer(hosted: true, host: '', port: '8080'));
|
||||
list = pushRecent(list, join('127.0.0.1', '8080'));
|
||||
list = pushRecent(list, const RecentServer(hosted: true, host: '', port: '8080', secret: 'x'));
|
||||
expect(list.length, 2);
|
||||
expect(list.first.secret, 'x');
|
||||
});
|
||||
|
||||
test('round-trips and tolerates junk', () {
|
||||
final list = [join('a.example', '9000', 's'), const RecentServer(hosted: true, host: '', port: '8080')];
|
||||
final back = decodeRecents(encodeRecents(list));
|
||||
expect(back.map((r) => r.key), list.map((r) => r.key));
|
||||
expect(back.first.secret, 's');
|
||||
expect(back.last.hosted, isTrue);
|
||||
expect(decodeRecents('not json'), isEmpty);
|
||||
expect(decodeRecents(42), isEmpty);
|
||||
expect(decodeRecents('[{"host":1},{"host":"h","port":"1"}]').single.host, 'h');
|
||||
});
|
||||
|
||||
test('old single form migrates to one recent unless it was localhost', () {
|
||||
expect(migrateRecents(hadForm: true, host: 'friend.example', port: '8080', secret: 'pw').single.secret, 'pw');
|
||||
expect(migrateRecents(hadForm: true, host: '127.0.0.1', port: '8080', secret: ''), isEmpty);
|
||||
expect(migrateRecents(hadForm: false, host: 'friend.example', port: '8080', secret: ''), isEmpty);
|
||||
});
|
||||
});
|
||||
|
||||
test('hwdec value follows mode', () {
|
||||
final s = AppSettings();
|
||||
expect(s.hwdec.value, 'auto');
|
||||
s.setHwdecMode(HwdecMode.off);
|
||||
expect(s.hwdec.value, 'no');
|
||||
s.setHwdecMode(HwdecMode.custom);
|
||||
expect(s.hwdec.value, 'auto');
|
||||
s.setHwdecCustom(' vaapi ');
|
||||
expect(s.hwdec.value, 'vaapi');
|
||||
});
|
||||
|
||||
test('health parse: online, junk and protocol mismatch', () {
|
||||
final ok = ServerHealth.parse(jsonEncode(
|
||||
{'ok': true, 'name': 'Den', 'proto': RelayConstants.protoVersion, 'viewers': 2}));
|
||||
expect(ok.online, isTrue);
|
||||
expect(ok.name, 'Den');
|
||||
expect(ok.viewers, 2);
|
||||
expect(ok.needsUpdate, isFalse);
|
||||
expect(ServerHealth.parse('{"ok":true,"proto":-1}').needsUpdate, isTrue);
|
||||
expect(ServerHealth.parse('nope').online, isFalse);
|
||||
expect(ServerHealth.parse('{"ok":false}').online, isFalse);
|
||||
expect(healthUri('::1', '8080').toString(), 'http://[::1]:8080/health');
|
||||
});
|
||||
|
||||
test('pasting sorts links and paths into the right source', () {
|
||||
final c = MediaPickerController();
|
||||
expect(c.source, MediaKind.file);
|
||||
c.pasteText(' https://example.com/a.mkv ');
|
||||
expect(c.source, MediaKind.link);
|
||||
expect(c.selection, const LinkMedia('https://example.com/a.mkv'));
|
||||
c.pasteText('/home/me/b.mkv');
|
||||
expect(c.source, MediaKind.file);
|
||||
expect(c.selection, const FileMedia('/home/me/b.mkv'));
|
||||
c.source = MediaKind.jellyfin;
|
||||
expect(c.selection, isNull);
|
||||
c.dispose();
|
||||
});
|
||||
|
||||
/// Fake `/health`: host -> JSON body; unknown hosts are unreachable.
|
||||
HealthGetter fakeHealth(Map<String, Map<String, Object>> up) => (uri) async {
|
||||
final body = up[uri.host];
|
||||
if (body == null) throw Exception('connection refused');
|
||||
return jsonEncode(body);
|
||||
};
|
||||
|
||||
Future<void> pumpShell(WidgetTester tester, Size size, {HealthGetter? health}) async {
|
||||
tester.view.physicalSize = size;
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.reset);
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData.dark(),
|
||||
home: Scaffold(
|
||||
body: HomeShell(
|
||||
updates: UpdateController(currentVersion: '0.0.0-dev'),
|
||||
autoUpdateCheck: false,
|
||||
healthGet: health ?? fakeHealth(const {}),
|
||||
),
|
||||
),
|
||||
));
|
||||
await tester.pump();
|
||||
}
|
||||
|
||||
setUp(() => SessionState.instance.recents.value = const []);
|
||||
|
||||
testWidgets('tabs and page buttons switch the body', (tester) async {
|
||||
await pumpShell(tester, const Size(1280, 900));
|
||||
expect(find.byKey(const ValueKey('join-row')), findsOneWidget);
|
||||
expect(find.byKey(const ValueKey('host-picker')), findsNothing);
|
||||
await tester.tap(find.byKey(const ValueKey('tab-host')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const ValueKey('host-picker')), findsOneWidget);
|
||||
expect(find.byKey(const ValueKey('join-row')), findsNothing);
|
||||
expect(find.text('No password — anyone can join'), findsOneWidget);
|
||||
await tester.tap(find.byTooltip('Settings'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Hardware decoding'), findsOneWidget);
|
||||
expect(find.text('Check automatically on start'), findsOneWidget);
|
||||
expect(find.text('Toggle ready'), findsOneWidget);
|
||||
await tester.tap(find.byTooltip('Integrations'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Jellyfin'), findsOneWidget);
|
||||
await tester.tap(find.byTooltip('About'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Dev build — update checks are off'), findsOneWidget);
|
||||
await tester.tap(find.byKey(const ValueKey('tab-join')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const ValueKey('join-row')), findsOneWidget);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('Enter in the join row submits; errors show under it', (tester) async {
|
||||
SessionState.instance.lastForm.name = '';
|
||||
await pumpShell(tester, const Size(1280, 720));
|
||||
await tester.enterText(find.byKey(const ValueKey('join-address')), 'friend.example');
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
await tester.pump();
|
||||
await tester.pump();
|
||||
expect(find.textContaining('display name', findRichText: true), findsOneWidget);
|
||||
// The button submits too, and typing in the address clears the error.
|
||||
await tester.enterText(find.byKey(const ValueKey('join-address')), 'friend.example2');
|
||||
await tester.pump();
|
||||
expect(find.textContaining('display name', findRichText: true), findsNothing);
|
||||
await tester.tap(find.widgetWithText(FilledButton, 'Join'));
|
||||
await tester.pump();
|
||||
await tester.pump();
|
||||
expect(find.textContaining('display name', findRichText: true), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('recent tiles show live status from /health', (tester) async {
|
||||
SessionState.instance.recents.value = [
|
||||
join('alpha.example', '8080'),
|
||||
join('beta.example', '9000', 'pw'),
|
||||
join('gamma.example', '7000'),
|
||||
const RecentServer(hosted: true, host: '', port: '8181'),
|
||||
];
|
||||
await pumpShell(tester, const Size(1280, 900),
|
||||
health: fakeHealth({
|
||||
'alpha.example': {
|
||||
'ok': true,
|
||||
'name': 'Movie night',
|
||||
'proto': RelayConstants.protoVersion,
|
||||
'viewers': 3,
|
||||
},
|
||||
'gamma.example': {'ok': true, 'name': '', 'proto': -1, 'viewers': 0},
|
||||
}));
|
||||
await tester.pump();
|
||||
Finder inTile(String key, Finder f) =>
|
||||
find.descendant(of: find.byKey(ValueKey('recent-$key')), matching: f);
|
||||
expect(inTile('alpha.example:8080', find.text('Movie night')), findsOneWidget);
|
||||
expect(inTile('alpha.example:8080', find.text('● online · 3 watching')), findsOneWidget);
|
||||
expect(inTile('alpha.example:8080', find.text('needs update')), findsNothing);
|
||||
expect(inTile('beta.example:9000', find.text('○ offline')), findsOneWidget);
|
||||
expect(inTile('beta.example:9000', find.text('beta.example')), findsOneWidget);
|
||||
expect(inTile('gamma.example:7000', find.text('needs update')), findsOneWidget);
|
||||
// Hosted entries live on the Host tab, not in the join grid.
|
||||
expect(find.byKey(const ValueKey('recent-host:8181')), findsNothing);
|
||||
// Tiles share a row on a wide window.
|
||||
final a = tester.getRect(find.byKey(const ValueKey('recent-alpha.example:8080')));
|
||||
final b = tester.getRect(find.byKey(const ValueKey('recent-beta.example:9000')));
|
||||
expect(a.top, b.top);
|
||||
// x forgets.
|
||||
await tester.tap(inTile('beta.example:9000', find.byTooltip('Forget')));
|
||||
await tester.pump();
|
||||
expect(find.byKey(const ValueKey('recent-beta.example:9000')), findsNothing);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('no recents shows the empty state', (tester) async {
|
||||
await pumpShell(tester, const Size(1280, 720));
|
||||
expect(find.byKey(const ValueKey('recents-empty')), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('wide windows: grid fills the width, fields stay compact', (tester) async {
|
||||
SessionState.instance.recents.value = [
|
||||
for (var i = 0; i < 6; i++) join('10.0.0.$i', '8080'),
|
||||
];
|
||||
await pumpShell(tester, const Size(3440, 1440));
|
||||
final first = tester.getRect(find.byKey(const ValueKey('recent-10.0.0.0:8080')));
|
||||
final last = tester.getRect(find.byKey(const ValueKey('recent-10.0.0.5:8080')));
|
||||
expect(first.top, last.top);
|
||||
expect(tester.getSize(find.byKey(const ValueKey('join-address'))).width, 280);
|
||||
await tester.tap(find.byKey(const ValueKey('tab-host')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.getSize(find.byKey(const ValueKey('host-column'))).width, 340);
|
||||
final file = find.descendant(
|
||||
of: find.byKey(const ValueKey('media-file')), matching: find.byType(TextField));
|
||||
expect(tester.getSize(file).width, lessThanOrEqualTo(kFieldMaxWidth));
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('media picker segments switch the input', (tester) async {
|
||||
await pumpShell(tester, const Size(1280, 900));
|
||||
await tester.tap(find.byKey(const ValueKey('tab-host')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const ValueKey('media-file')), findsOneWidget);
|
||||
expect(find.text('Browse'), findsOneWidget);
|
||||
await tester.tap(find.text('Link'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const ValueKey('media-link')), findsOneWidget);
|
||||
expect(find.text('Paste'), findsOneWidget);
|
||||
await tester.tap(find.text('Jellyfin'));
|
||||
await tester.pumpAndSettle();
|
||||
// No linked server: sign-in right in the picker.
|
||||
expect(find.text('Add a Jellyfin server'), findsOneWidget);
|
||||
await tester.tap(find.text('Open Integrations'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Add server'), findsOneWidget);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('host column sits right when wide, below when narrow', (tester) async {
|
||||
await pumpShell(tester, const Size(1280, 900));
|
||||
await tester.tap(find.byKey(const ValueKey('tab-host')));
|
||||
await tester.pumpAndSettle();
|
||||
var picker = tester.getRect(find.byKey(const ValueKey('host-picker')));
|
||||
var column = tester.getRect(find.byKey(const ValueKey('host-column')));
|
||||
expect(picker.right, lessThan(column.left));
|
||||
expect(picker.top, column.top);
|
||||
|
||||
await pumpShell(tester, const Size(640, 1000));
|
||||
picker = tester.getRect(find.byKey(const ValueKey('host-picker')));
|
||||
column = tester.getRect(find.byKey(const ValueKey('host-column')));
|
||||
expect(picker.bottom, lessThan(column.top));
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('host without a name errors in the server column', (tester) async {
|
||||
SessionState.instance.lastForm.name = '';
|
||||
await pumpShell(tester, const Size(1280, 900));
|
||||
await tester.tap(find.byKey(const ValueKey('tab-host')));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.widgetWithText(FilledButton, 'Host'));
|
||||
await tester.pump();
|
||||
await tester.pump();
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byKey(const ValueKey('host-column')),
|
||||
matching: find.textContaining('display name', findRichText: true),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('narrow window: bar, join row and host tab fit', (tester) async {
|
||||
await pumpShell(tester, const Size(480, 800));
|
||||
expect(find.byKey(const ValueKey('join-row')), findsOneWidget);
|
||||
expect(tester.takeException(), isNull);
|
||||
await tester.tap(find.byKey(const ValueKey('tab-host')));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Jellyfin'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
import 'package:watch_together/src/jellyfin/accounts.dart';
|
||||
import 'package:watch_together/src/jellyfin/format.dart';
|
||||
import 'package:watch_together/src/jellyfin/sign_in.dart';
|
||||
import 'package:watch_together/src/screens/home/host_tab.dart' show mediaSummary;
|
||||
import 'package:watch_together/src/screens/home/media_picker.dart';
|
||||
|
||||
/// Captured Jellyfin 10.11 answers shared with packages/core's client tests.
|
||||
String jellyfinFixture(String name) =>
|
||||
File('../../packages/core/test/fixtures/jellyfin/$name.json').readAsStringSync();
|
||||
|
||||
const fixtureServerId = '122fce17c5b9413088af4be266bad6f4';
|
||||
const fixtureUserId = 'f00703a1d1ac44fe8a8a0ddf2ca05757';
|
||||
const arifuretaId = '550eff23b37ec61082c988678ccc214c';
|
||||
const season2Id = '331a23499d051bc288d281f2c72557a9';
|
||||
|
||||
typedef FakeHandler = JellyfinHttpResponse Function(Uri uri, String? body);
|
||||
|
||||
/// Fake Jellyfin: routes by "METHOD /path" to fixtures, filters episode and
|
||||
/// next-up lists by their query like the server does, records requests.
|
||||
/// [approved] flips the Quick Connect state.
|
||||
class FakeJellyfin implements JellyfinHttp {
|
||||
final requests = <({String method, Uri uri, Map<String, String> headers})>[];
|
||||
final routes = <String, FakeHandler>{};
|
||||
bool approved = false;
|
||||
bool offline = false;
|
||||
int meStatus = 200;
|
||||
|
||||
FakeJellyfin() {
|
||||
fixture('GET', '/System/Info/Public', 'pub');
|
||||
on('GET', '/QuickConnect/Enabled', (_, _) => const JellyfinHttpResponse(200, 'true'));
|
||||
fixture('POST', '/QuickConnect/Initiate', 'quickconnect_initiate');
|
||||
on('GET', '/QuickConnect/Connect', (_, _) => JellyfinHttpResponse(
|
||||
200, jsonEncode({'Authenticated': approved, 'Secret': 's', 'Code': '437392'})));
|
||||
fixture('POST', '/Users/AuthenticateWithQuickConnect', 'auth_result');
|
||||
on('POST', '/Users/AuthenticateByName', (_, body) {
|
||||
final pw = (jsonDecode(body!) as Map)['Pw'];
|
||||
return pw == 'right'
|
||||
? JellyfinHttpResponse(200, jellyfinFixture('auth_result'))
|
||||
: const JellyfinHttpResponse(401, '');
|
||||
});
|
||||
on('GET', '/Users/Me', (_, _) => JellyfinHttpResponse(
|
||||
meStatus, meStatus == 200 ? jellyfinFixture('me') : ''));
|
||||
on('POST', '/Sessions/Logout', (_, _) => const JellyfinHttpResponse(204, ''));
|
||||
fixture('GET', '/UserViews', 'views');
|
||||
on('GET', '/UserItems/Resume', (_, _) => JellyfinHttpResponse(200, jellyfinFixture('resume')));
|
||||
on('GET', '/Shows/NextUp', (uri, _) {
|
||||
final series = uri.queryParameters['seriesId'];
|
||||
if (series == null) return JellyfinHttpResponse(200, jellyfinFixture('nextup'));
|
||||
// Arifureta's next up: S2E4.
|
||||
final eps = _items('episodes').where((e) => e['SeriesId'] == series).toList();
|
||||
return _page(eps.isEmpty ? const [] : [eps[3]]);
|
||||
});
|
||||
fixture('GET', '/Items/Latest', 'latest_shows');
|
||||
on('GET', '/Items', (uri, _) {
|
||||
final q = uri.queryParameters;
|
||||
if ((q['searchTerm'] ?? '').isNotEmpty) {
|
||||
return q['searchTerm']!.toLowerCase().startsWith('ari')
|
||||
? JellyfinHttpResponse(200, jellyfinFixture('search'))
|
||||
: _page(const []);
|
||||
}
|
||||
return JellyfinHttpResponse(
|
||||
200, jellyfinFixture(q['includeItemTypes'] == 'Movie' ? 'movies_page' : 'series_page'));
|
||||
});
|
||||
on('GET', '/Items/$arifuretaId', (_, _) => JellyfinHttpResponse(200, jellyfinFixture('series_detail')));
|
||||
on('GET', '/Items/b18826be994070a79f9b52bc0f66f052',
|
||||
(_, _) => JellyfinHttpResponse(200, jellyfinFixture('episode_detail')));
|
||||
on('GET', '/Shows/$arifuretaId/Seasons', (_, _) => JellyfinHttpResponse(200, jellyfinFixture('seasons')));
|
||||
on('GET', '/Shows/$arifuretaId/Episodes', (uri, _) {
|
||||
final season = uri.queryParameters['seasonId'];
|
||||
return _page(_items('episodes').where((e) => season == null || e['SeasonId'] == season).toList());
|
||||
});
|
||||
}
|
||||
|
||||
static List<Map<String, dynamic>> _items(String fixture) =>
|
||||
((jsonDecode(jellyfinFixture(fixture)) as Map)['Items'] as List).cast<Map<String, dynamic>>();
|
||||
|
||||
static JellyfinHttpResponse _page(List<Object> items) =>
|
||||
JellyfinHttpResponse(200, jsonEncode({'Items': items, 'TotalRecordCount': items.length}));
|
||||
|
||||
void on(String method, String path, FakeHandler h) => routes['$method $path'] = h;
|
||||
void fixture(String method, String path, String name) =>
|
||||
on(method, path, (_, _) => JellyfinHttpResponse(200, jellyfinFixture(name)));
|
||||
|
||||
int count(String method, String path) =>
|
||||
requests.where((r) => r.method == method && r.uri.path == path).length;
|
||||
|
||||
@override
|
||||
Future<JellyfinHttpResponse> send(String method, Uri uri,
|
||||
{Map<String, String> headers = const {}, String? body}) async {
|
||||
requests.add((method: method, uri: uri, headers: headers));
|
||||
if (offline) throw JellyfinException('$method ${uri.path}: connection refused');
|
||||
final h = routes['$method ${uri.path}'];
|
||||
return h == null ? const JellyfinHttpResponse(404, '') : h(uri, body);
|
||||
}
|
||||
|
||||
@override
|
||||
void close() {}
|
||||
}
|
||||
|
||||
JellyfinAuthResult fixtureAuth() =>
|
||||
JellyfinAuthResult.fromJson(jsonDecode(jellyfinFixture('auth_result')) as Map<String, dynamic>);
|
||||
|
||||
JellyfinServerInfo fixtureServer() =>
|
||||
JellyfinServerInfo.fromJson(jsonDecode(jellyfinFixture('pub')) as Map<String, dynamic>);
|
||||
|
||||
/// Accounts on a fake server with one linked account (no validation run).
|
||||
Future<(JellyfinAccounts, FakeJellyfin)> linkedAccounts({FakeJellyfin? http}) async {
|
||||
final fake = http ?? FakeJellyfin();
|
||||
final accounts = JellyfinAccounts(
|
||||
store: MemoryJellyfinStore(), httpFactory: () => fake, deviceName: 'Test PC');
|
||||
await accounts.ensureLoaded(validate: false);
|
||||
await accounts.link(
|
||||
baseUrl: 'https://example.invalid', server: fixtureServer(), auth: fixtureAuth());
|
||||
return (accounts, fake);
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('accounts', () {
|
||||
test('persist in their Hive box with a stable device id', () async {
|
||||
final dir = Directory.systemTemp.createTempSync('jf_accounts_');
|
||||
addTearDown(() => dir.deleteSync(recursive: true));
|
||||
Hive.init(dir.path);
|
||||
final fake = FakeJellyfin();
|
||||
|
||||
final a = JellyfinAccounts(httpFactory: () => fake, deviceName: 'PC');
|
||||
await a.ensureLoaded(validate: false);
|
||||
final deviceId = a.deviceId;
|
||||
expect(deviceId, hasLength(32));
|
||||
await a.link(baseUrl: 'https://example.invalid', server: fixtureServer(), auth: fixtureAuth());
|
||||
await a.rememberPick(const JellyfinMedia(
|
||||
serverId: fixtureServerId, baseUrl: 'https://example.invalid', itemId: 'abc', title: 'Ep'));
|
||||
await Hive.close();
|
||||
|
||||
final b = JellyfinAccounts(httpFactory: () => fake, deviceName: 'PC');
|
||||
await b.ensureLoaded(validate: false);
|
||||
expect(b.deviceId, deviceId);
|
||||
final acc = b.accounts.single;
|
||||
expect(acc.serverId, fixtureServerId);
|
||||
expect(acc.serverName, 'Example Server');
|
||||
expect(acc.userName, 'testuser');
|
||||
expect(acc.token, 'TEST_ACCESS_TOKEN');
|
||||
expect(b.defaultServerId, fixtureServerId);
|
||||
expect(b.lastPick?.itemId, 'abc');
|
||||
// The header names this app and install.
|
||||
expect(b.clientInfo.client, 'Watch Together');
|
||||
expect(b.clientInfo.deviceId, deviceId);
|
||||
await Hive.close();
|
||||
});
|
||||
|
||||
test('token check: online, expired stays linked, offline is not a sign-out', () async {
|
||||
final (accounts, fake) = await linkedAccounts();
|
||||
expect(await accounts.validate(fixtureServerId), JellyfinAccountStatus.online);
|
||||
expect(fake.requests.last.headers['Authorization'], contains('Token="TEST_ACCESS_TOKEN"'));
|
||||
|
||||
fake.meStatus = 401;
|
||||
expect(await accounts.validate(fixtureServerId), JellyfinAccountStatus.expired);
|
||||
expect(accounts.accounts, hasLength(1));
|
||||
|
||||
fake.offline = true;
|
||||
expect(await accounts.validate(fixtureServerId), JellyfinAccountStatus.offline);
|
||||
expect(accounts.errorOf(fixtureServerId), contains('connection refused'));
|
||||
expect(accounts.accounts, hasLength(1));
|
||||
});
|
||||
|
||||
test('ensureLoaded validates in the background', () async {
|
||||
final fake = FakeJellyfin()..meStatus = 401;
|
||||
final store = MemoryJellyfinStore();
|
||||
final first = JellyfinAccounts(store: store, httpFactory: () => fake);
|
||||
await first.ensureLoaded(validate: false);
|
||||
await first.link(baseUrl: 'https://example.invalid', server: fixtureServer(), auth: fixtureAuth());
|
||||
final again = JellyfinAccounts(store: store, httpFactory: () => fake);
|
||||
await again.ensureLoaded();
|
||||
await pumpEventQueue();
|
||||
expect(again.statusOf(fixtureServerId), JellyfinAccountStatus.expired);
|
||||
});
|
||||
|
||||
test('sign out revokes the token and unlinks; default moves on', () async {
|
||||
final (accounts, fake) = await linkedAccounts();
|
||||
final otherAuth = JellyfinAuthResult(
|
||||
accessToken: 'T2',
|
||||
user: const JellyfinUser(id: 'u2', name: 'other'),
|
||||
serverId: 'other-server');
|
||||
await accounts.link(
|
||||
baseUrl: 'https://two.invalid',
|
||||
server: const JellyfinServerInfo(id: 'other-server', name: 'Two', version: '10.11'),
|
||||
auth: otherAuth);
|
||||
expect(accounts.defaultServerId, fixtureServerId);
|
||||
await accounts.setDefault('other-server');
|
||||
expect(accounts.defaultServerId, 'other-server');
|
||||
|
||||
await accounts.signOut('other-server');
|
||||
expect(fake.count('POST', '/Sessions/Logout'), 1);
|
||||
expect(fake.requests.last.headers['Authorization'], contains('Token="T2"'));
|
||||
expect(accounts.accounts.map((a) => a.serverId), [fixtureServerId]);
|
||||
expect(accounts.defaultServerId, fixtureServerId);
|
||||
});
|
||||
|
||||
test('signing in again replaces the account and revokes the old token', () async {
|
||||
final (accounts, fake) = await linkedAccounts();
|
||||
final fresh = JellyfinAuthResult(
|
||||
accessToken: 'NEW', user: fixtureAuth().user, serverId: fixtureServerId);
|
||||
await accounts.link(baseUrl: 'https://alt.invalid', server: fixtureServer(), auth: fresh);
|
||||
await pumpEventQueue();
|
||||
expect(accounts.accounts.single.token, 'NEW');
|
||||
expect(accounts.accounts.single.urls, ['https://alt.invalid', 'https://example.invalid']);
|
||||
expect(fake.count('POST', '/Sessions/Logout'), 1);
|
||||
});
|
||||
});
|
||||
|
||||
group('sign-in flow', () {
|
||||
late FakeJellyfin fake;
|
||||
late JellyfinAccounts accounts;
|
||||
setUp(() async {
|
||||
fake = FakeJellyfin();
|
||||
accounts = JellyfinAccounts(store: MemoryJellyfinStore(), httpFactory: () => fake);
|
||||
await accounts.ensureLoaded(validate: false);
|
||||
});
|
||||
|
||||
test('bad address and non-Jellyfin servers stay on the address step', () async {
|
||||
final flow = JellyfinSignIn(accounts, pollInterval: Duration.zero);
|
||||
await flow.probe(' ');
|
||||
expect(flow.step, JellyfinSignInStep.address);
|
||||
expect(flow.error, isNotNull);
|
||||
fake.offline = true;
|
||||
await flow.probe('jelly.example');
|
||||
expect(flow.step, JellyfinSignInStep.address);
|
||||
expect(flow.error, contains('No Jellyfin server'));
|
||||
});
|
||||
|
||||
test('Quick Connect: code, poll until approved, linked', () async {
|
||||
final flow = JellyfinSignIn(accounts, pollInterval: const Duration(milliseconds: 1));
|
||||
await flow.probe('example.invalid');
|
||||
expect(flow.step, JellyfinSignInStep.method);
|
||||
expect(flow.server?.name, 'Example Server');
|
||||
expect(flow.quickConnectAvailable, isTrue);
|
||||
final done = flow.startQuickConnect();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 20));
|
||||
expect(flow.code, '437392');
|
||||
expect(flow.step, JellyfinSignInStep.quickConnect);
|
||||
fake.approved = true;
|
||||
await done;
|
||||
expect(flow.step, JellyfinSignInStep.done);
|
||||
expect(accounts.accounts.single.userName, 'testuser');
|
||||
expect(accounts.accounts.single.urls, ['https://example.invalid']);
|
||||
});
|
||||
|
||||
test('Quick Connect cancel stops polling', () async {
|
||||
final flow = JellyfinSignIn(accounts, pollInterval: const Duration(milliseconds: 1));
|
||||
await flow.probe('https://example.invalid');
|
||||
final done = flow.startQuickConnect();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 20));
|
||||
flow.cancel();
|
||||
await done;
|
||||
final polls = fake.count('GET', '/QuickConnect/Connect');
|
||||
await Future<void>.delayed(const Duration(milliseconds: 20));
|
||||
expect(fake.count('GET', '/QuickConnect/Connect'), polls);
|
||||
expect(flow.step, JellyfinSignInStep.method);
|
||||
expect(accounts.isEmpty, isTrue);
|
||||
});
|
||||
|
||||
test('password: wrong then right', () async {
|
||||
final flow = JellyfinSignIn(accounts);
|
||||
await flow.probe('https://example.invalid');
|
||||
flow.usePassword();
|
||||
await flow.signIn('testuser', 'wrong');
|
||||
expect(flow.step, JellyfinSignInStep.password);
|
||||
expect(flow.error, 'Wrong username or password');
|
||||
await flow.signIn('testuser', 'right');
|
||||
expect(flow.step, JellyfinSignInStep.done);
|
||||
expect(accounts.accounts.single.token, 'TEST_ACCESS_TOKEN');
|
||||
});
|
||||
|
||||
test('reconnect refuses a different server', () async {
|
||||
final (linked, _) = await linkedAccounts();
|
||||
final other = JellyfinAccount(
|
||||
serverId: 'someone-else', serverName: 'X', urls: const ['https://example.invalid'],
|
||||
userId: 'u', userName: 'n', token: 't');
|
||||
final flow = JellyfinSignIn(linked, reconnect: other);
|
||||
await flow.probe(other.baseUrl);
|
||||
expect(flow.step, JellyfinSignInStep.address);
|
||||
expect(flow.error, contains('different Jellyfin server'));
|
||||
});
|
||||
});
|
||||
|
||||
group('picked media', () {
|
||||
test('controller selection is a PickedMedia per source', () {
|
||||
final c = MediaPickerController();
|
||||
expect(c.selection, isNull);
|
||||
c.pasteText('https://example.com/a.mkv');
|
||||
expect(c.selection, const LinkMedia('https://example.com/a.mkv'));
|
||||
c.pasteText('/home/me/b.mkv');
|
||||
expect(c.selection, const FileMedia('/home/me/b.mkv'));
|
||||
c.source = MediaKind.jellyfin;
|
||||
expect(c.selection, isNull);
|
||||
const m = JellyfinMedia(
|
||||
serverId: 's', baseUrl: 'https://j.example', itemId: 'i', title: 'Ep', subtitle: 'Show · S1E6');
|
||||
c.pickJellyfin(m);
|
||||
expect(c.selection, m);
|
||||
c.source = MediaKind.file;
|
||||
expect(c.selection, const FileMedia('/home/me/b.mkv'));
|
||||
expect(c.jellyfin, m, reason: 'kept while another source shows');
|
||||
c.dispose();
|
||||
});
|
||||
|
||||
test('a saved Jellyfin pick starts on the Jellyfin source', () {
|
||||
const m = JellyfinMedia(serverId: 's', baseUrl: 'b', itemId: 'i', title: 't');
|
||||
expect(MediaPickerController(jellyfin: m).source, MediaKind.jellyfin);
|
||||
expect(MediaPickerController(jellyfin: m, mediaPath: '/x.mkv').source, MediaKind.file);
|
||||
});
|
||||
|
||||
test('JellyfinMedia round-trips and labels', () {
|
||||
const m = JellyfinMedia(
|
||||
serverId: 's',
|
||||
baseUrl: 'https://j.example',
|
||||
itemId: 'i',
|
||||
mediaSourceId: 'src',
|
||||
title: 'Rice and Thieves and Heroes',
|
||||
subtitle: 'Black Summoner · S1E6',
|
||||
runtime: Duration(minutes: 23));
|
||||
final back = JellyfinMedia.fromJson(jsonDecode(jsonEncode(m.toJson())))!;
|
||||
expect(back, m);
|
||||
expect(back.runtime, const Duration(minutes: 23));
|
||||
expect(back.subtitle, 'Black Summoner · S1E6');
|
||||
expect(mediaSummary(m), 'Playing: Rice and Thieves and Heroes — Black Summoner · S1E6');
|
||||
expect(mediaSummary(const FileMedia('/a/b/movie.mkv')), 'Playing: movie.mkv');
|
||||
expect(mediaSummary(null), 'No media selected (optional).');
|
||||
expect(JellyfinMedia.fromJson({'serverId': 1}), isNull);
|
||||
});
|
||||
|
||||
test('pickFor labels an episode "Series · S1E6"', () async {
|
||||
final (accounts, _) = await linkedAccounts();
|
||||
final ep = JellyfinItem.fromJson(jsonDecode(jellyfinFixture('episode_detail')) as Map<String, dynamic>);
|
||||
final m = pickFor(accounts.accounts.single, ep);
|
||||
expect(m.serverId, fixtureServerId);
|
||||
expect(m.itemId, 'b18826be994070a79f9b52bc0f66f052');
|
||||
expect(m.subtitle, 'Black Summoner · S1E6');
|
||||
expect(m.runtime, isNotNull);
|
||||
});
|
||||
});
|
||||
|
||||
group('format', () {
|
||||
test('time left and subtitles', () {
|
||||
final resume = JellyfinItemPage.fromJson(jsonDecode(jellyfinFixture('resume')) as Map<String, dynamic>).items;
|
||||
final ep = resume[1];
|
||||
expect(timeLeft(ep), endsWith('min left'));
|
||||
expect(cardSubtitle(ep), startsWith('S1E10 · '));
|
||||
expect(progressOf(ep), greaterThan(0));
|
||||
expect(formatRuntime(const Duration(minutes: 102)), '1 h 42 min');
|
||||
expect(formatRuntime(const Duration(minutes: 24)), '24 min');
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:watch_together/src/jellyfin/accounts.dart';
|
||||
import 'package:watch_together/src/jellyfin/accounts_panel.dart';
|
||||
import 'package:watch_together/src/jellyfin/browser.dart';
|
||||
import 'package:watch_together/src/screens/home/connect_flow.dart';
|
||||
import 'package:watch_together/src/screens/home/host_tab.dart';
|
||||
import 'package:watch_together/src/screens/home/media_picker.dart';
|
||||
import 'package:watch_together/src/state/session_state.dart';
|
||||
|
||||
import 'jellyfin_accounts_test.dart'
|
||||
show FakeJellyfin, arifuretaId, fixtureServerId, linkedAccounts, season2Id;
|
||||
|
||||
Future<void> setSize(WidgetTester tester, Size size) async {
|
||||
tester.view.physicalSize = size;
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.reset);
|
||||
}
|
||||
|
||||
Widget app(Widget child) => MaterialApp(
|
||||
theme: ThemeData.dark(),
|
||||
home: Scaffold(body: Padding(padding: const EdgeInsets.all(16), child: child)),
|
||||
);
|
||||
|
||||
/// Lets fake requests, debounces and image errors settle without waiting
|
||||
/// on the progress spinners (pumpAndSettle would never return).
|
||||
Future<void> settle(WidgetTester tester, [int frames = 6]) async {
|
||||
for (var i = 0; i < frames; i++) {
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
}
|
||||
}
|
||||
|
||||
/// MediaPicker on the Jellyfin source with one linked fake server.
|
||||
Future<(MediaPickerController, JellyfinAccounts, FakeJellyfin)> pumpPicker(
|
||||
WidgetTester tester, Size size) async {
|
||||
await setSize(tester, size);
|
||||
// Memory store + fake transport: no real IO, so no runAsync (futures
|
||||
// made there would resume outside the test's fake clock).
|
||||
final (accounts, fake) = await linkedAccounts();
|
||||
final c = MediaPickerController(source: MediaKind.jellyfin);
|
||||
addTearDown(c.dispose);
|
||||
await tester.pumpWidget(app(MediaPicker(controller: c, jellyfin: accounts)));
|
||||
await settle(tester);
|
||||
return (c, accounts, fake);
|
||||
}
|
||||
|
||||
Future<void> openArifureta(WidgetTester tester) async {
|
||||
await tester.enterText(find.byKey(const ValueKey('jf-search')), 'arifureta');
|
||||
await settle(tester, 10);
|
||||
expect(find.byKey(const ValueKey('search-results')), findsOneWidget);
|
||||
await tester.tap(find.byKey(const ValueKey('card-$arifuretaId')));
|
||||
await settle(tester);
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('home rows: continue watching with time left, next up, latest', (tester) async {
|
||||
await pumpPicker(tester, const Size(1600, 2400));
|
||||
expect(find.text('Continue watching'), findsOneWidget);
|
||||
expect(find.text('Next up'), findsOneWidget);
|
||||
expect(find.text('Latest in Shows'), findsOneWidget);
|
||||
expect(find.widgetWithText(ActionChip, 'Movies'), findsOneWidget);
|
||||
// Continue watching: series name on top, "S1E10 · N min left · title" below.
|
||||
expect(find.text('From Old Country Bumpkin to Master Swordsman'), findsWidgets);
|
||||
expect(find.textContaining(RegExp(r'^S1E10 · \d+ min left')), findsOneWidget);
|
||||
expect(find.text('Black Summoner'), findsWidgets);
|
||||
expect(find.text('Monogatari'), findsWidgets);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('series page: smart next button, season switching, pick an episode',
|
||||
(tester) async {
|
||||
final (c, _, _) = await pumpPicker(tester, const Size(1600, 1000));
|
||||
await openArifureta(tester);
|
||||
// Opens on the season holding next up (S2E4).
|
||||
expect(find.byKey(const ValueKey('season-$season2Id')), findsOneWidget);
|
||||
final s2 = tester.widget<ChoiceChip>(find.byKey(const ValueKey('season-$season2Id')));
|
||||
expect(s2.selected, isTrue);
|
||||
expect(find.text('1. Irregular'), findsOneWidget);
|
||||
expect(find.textContaining('Next up: S2E4'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.widgetWithText(ChoiceChip, 'Season 3'));
|
||||
await settle(tester);
|
||||
expect(find.text('1. Irregular'), findsNothing);
|
||||
expect(find.text('1. Haulias Assemble'), findsWidgets);
|
||||
|
||||
// Picking an episode fills the controller.
|
||||
await tester.tap(find.text('2. Roar of Revolution').first);
|
||||
await tester.pump();
|
||||
final sel = c.selection;
|
||||
expect(sel, isA<JellyfinMedia>());
|
||||
sel as JellyfinMedia;
|
||||
expect(sel.serverId, fixtureServerId);
|
||||
expect(sel.title, 'Roar of Revolution');
|
||||
expect(sel.subtitle, "Arifureta: From Commonplace to World's Strongest · S3E2");
|
||||
expect(sel.baseUrl, 'https://example.invalid');
|
||||
|
||||
// The smart button picks next up.
|
||||
await tester.tap(find.byKey(const ValueKey('series-next')));
|
||||
await tester.pump();
|
||||
expect((c.selection as JellyfinMedia).subtitle, endsWith('S2E4'));
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('keyboard: / searches, Esc clears then goes back, arrows move', (tester) async {
|
||||
await pumpPicker(tester, const Size(1600, 1000));
|
||||
final search = find.byKey(const ValueKey('jf-search'));
|
||||
|
||||
// Focus a card, then arrow right moves to the next card.
|
||||
final first = find.byKey(const ValueKey('card-b79037c4a4c2707287dd4a29965220f3'));
|
||||
Focus.of(tester.element(find.descendant(of: first, matching: find.byType(Column)).first))
|
||||
.requestFocus();
|
||||
await tester.pump();
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
|
||||
await tester.pump();
|
||||
final ink = FocusManager.instance.primaryFocus!.context!.findAncestorWidgetOfExactType<InkWell>()!;
|
||||
expect((ink.key as ValueKey<String>).value, 'card-43c0f58d4f0c13e4df01d737b695fae7');
|
||||
|
||||
// "/" jumps to search.
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.slash, character: '/');
|
||||
await tester.pump();
|
||||
expect(tester.widget<TextField>(search).focusNode!.hasFocus, isTrue);
|
||||
await tester.enterText(search, 'arifureta');
|
||||
await settle(tester, 10);
|
||||
expect(find.byKey(const ValueKey('search-results')), findsOneWidget);
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
|
||||
await tester.pump();
|
||||
expect(find.byKey(const ValueKey('search-results')), findsNothing);
|
||||
expect(find.text('Continue watching'), findsOneWidget);
|
||||
|
||||
// Into the series and back with Esc.
|
||||
await openArifureta(tester);
|
||||
expect(find.byKey(const ValueKey('series-next')), findsOneWidget);
|
||||
expect(find.byKey(const ValueKey('crumb-0')), findsOneWidget);
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
|
||||
await tester.pump();
|
||||
expect(find.byKey(const ValueKey('series-next')), findsNothing);
|
||||
expect(find.text('Continue watching'), findsOneWidget);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('library grid with sort and filters', (tester) async {
|
||||
final (_, _, fake) = await pumpPicker(tester, const Size(1600, 1000));
|
||||
await tester.tap(find.widgetWithText(ActionChip, 'Shows'));
|
||||
await settle(tester);
|
||||
expect(find.text('218 items'), findsOneWidget);
|
||||
expect(find.text('Alma-chan Wants to Be a Family!'), findsWidgets);
|
||||
await tester.tap(find.byKey(const ValueKey('filter-unplayed')));
|
||||
await settle(tester);
|
||||
final q = fake.requests.lastWhere((r) => r.uri.path == '/Items').uri.queryParameters;
|
||||
expect(q['filters'], 'IsUnplayed');
|
||||
expect(q['includeItemTypes'], 'Series');
|
||||
expect(q['recursive'], 'true');
|
||||
await tester.tap(find.byKey(const ValueKey('library-sort')));
|
||||
await settle(tester, 2);
|
||||
await tester.tap(find.byKey(const ValueKey('sort-added')));
|
||||
await settle(tester);
|
||||
final q2 = fake.requests.lastWhere((r) => r.uri.path == '/Items').uri.queryParameters;
|
||||
expect(q2['sortBy'], startsWith('DateCreated'));
|
||||
expect(q2['sortOrder'], 'Descending');
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('layouts: narrow has no inspector, ultrawide adds it and fits more columns',
|
||||
(tester) async {
|
||||
await pumpPicker(tester, const Size(820, 700));
|
||||
expect(find.byKey(const ValueKey('jf-inspector')), findsNothing);
|
||||
expect(tester.takeException(), isNull);
|
||||
final narrowCard = tester.getSize(find.byKey(const ValueKey('card-b79037c4a4c2707287dd4a29965220f3')));
|
||||
|
||||
await pumpPicker(tester, const Size(3440, 1440));
|
||||
expect(find.byKey(const ValueKey('jf-inspector')), findsOneWidget);
|
||||
expect(tester.takeException(), isNull);
|
||||
// Rows fill the width with whole cards.
|
||||
final wideCards = find.byWidgetPredicate((w) =>
|
||||
w is InkWell && w.key is ValueKey<String> && (w.key as ValueKey<String>).value.startsWith('card-'));
|
||||
expect(wideCards.evaluate().length, greaterThan(10));
|
||||
expect(narrowCard.width, greaterThan(200));
|
||||
|
||||
// Hover feeds the inspector.
|
||||
final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
||||
addTearDown(gesture.removePointer);
|
||||
await gesture.addPointer(location: Offset.zero);
|
||||
await gesture.moveTo(tester.getCenter(find.byKey(const ValueKey('card-b18826be994070a79f9b52bc0f66f052')).first));
|
||||
await tester.pump();
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byKey(const ValueKey('jf-inspector')),
|
||||
matching: find.textContaining('Rice and Thieves and Heroes')),
|
||||
findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Integrations: Quick Connect shows the code, approve links, cancel stops',
|
||||
(tester) async {
|
||||
await setSize(tester, const Size(1200, 900));
|
||||
final fake = FakeJellyfin();
|
||||
final accounts = JellyfinAccounts(
|
||||
store: MemoryJellyfinStore(), httpFactory: () => fake, deviceName: 'Test');
|
||||
await accounts.ensureLoaded(validate: false);
|
||||
await tester.pumpWidget(app(SingleChildScrollView(
|
||||
child: JellyfinAccountsPanel(
|
||||
accounts: accounts, pollInterval: const Duration(milliseconds: 100)))));
|
||||
await tester.tap(find.byKey(const ValueKey('jf-add-server')));
|
||||
await tester.pump();
|
||||
await tester.enterText(find.byKey(const ValueKey('jf-address')), 'example.invalid');
|
||||
await tester.tap(find.byKey(const ValueKey('jf-connect')));
|
||||
await settle(tester, 2);
|
||||
expect(find.text('Example Server'), findsOneWidget);
|
||||
expect(find.textContaining('Jellyfin 10.11.11'), findsOneWidget);
|
||||
|
||||
// Cancel: the code goes away and polling stops.
|
||||
await tester.tap(find.byKey(const ValueKey('jf-quick-connect')));
|
||||
await settle(tester, 2);
|
||||
expect(find.text('437392'), findsOneWidget);
|
||||
expect(find.textContaining('Profile → Quick Connect'), findsOneWidget);
|
||||
await tester.tap(find.byKey(const ValueKey('jf-qc-cancel')));
|
||||
await settle(tester, 4);
|
||||
final polls = fake.count('GET', '/QuickConnect/Connect');
|
||||
await settle(tester, 6);
|
||||
expect(fake.count('GET', '/QuickConnect/Connect'), polls);
|
||||
expect(find.text('437392'), findsNothing);
|
||||
|
||||
// Again, and approve it.
|
||||
await tester.tap(find.byKey(const ValueKey('jf-quick-connect')));
|
||||
await settle(tester, 2);
|
||||
expect(find.text('437392'), findsOneWidget);
|
||||
fake.approved = true;
|
||||
await settle(tester, 6);
|
||||
expect(accounts.accounts.single.userName, 'testuser');
|
||||
expect(find.byKey(const ValueKey('jf-account-$fixtureServerId')), findsOneWidget);
|
||||
expect(find.text('testuser on Example Server'), findsOneWidget);
|
||||
expect(find.byKey(const ValueKey('jf-sign-in')), findsNothing);
|
||||
|
||||
// Expired token: Reconnect shows, the account stays.
|
||||
accounts.markExpired(fixtureServerId);
|
||||
await tester.pump();
|
||||
expect(find.byKey(const ValueKey('jf-reconnect-$fixtureServerId')), findsOneWidget);
|
||||
|
||||
// Sign out asks, revokes, unlinks.
|
||||
await tester.tap(find.byKey(const ValueKey('jf-sign-out-$fixtureServerId')));
|
||||
await tester.pump();
|
||||
await tester.tap(find.byKey(const ValueKey('jf-sign-out-confirm')));
|
||||
await settle(tester, 4);
|
||||
expect(fake.count('POST', '/Sessions/Logout'), 1);
|
||||
expect(accounts.isEmpty, isTrue);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('no linked server: the picker offers sign-in inline', (tester) async {
|
||||
await setSize(tester, const Size(1200, 900));
|
||||
final accounts = JellyfinAccounts(store: MemoryJellyfinStore(), httpFactory: () => FakeJellyfin());
|
||||
await accounts.ensureLoaded(validate: false);
|
||||
final c = MediaPickerController(source: MediaKind.jellyfin);
|
||||
addTearDown(c.dispose);
|
||||
await tester.pumpWidget(app(SingleChildScrollView(
|
||||
child: MediaPicker(controller: c, jellyfin: accounts, onOpenIntegrations: () {}))));
|
||||
await tester.pump();
|
||||
expect(find.byKey(const ValueKey('jf-sign-in')), findsOneWidget);
|
||||
expect(find.text('Open Integrations'), findsOneWidget);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('expired account shows a reconnect banner in the browser', (tester) async {
|
||||
final (_, accounts, _) = await pumpPicker(tester, const Size(1400, 900));
|
||||
accounts.markExpired(fixtureServerId);
|
||||
await tester.pump();
|
||||
expect(find.byKey(const ValueKey('jf-status-banner')), findsOneWidget);
|
||||
expect(find.text('Reconnect'), findsOneWidget);
|
||||
expect(find.byType(JellyfinBrowser), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Host tab: browser beside the server column, enlarged with a host bar, stacked when narrow',
|
||||
(tester) async {
|
||||
await setSize(tester, const Size(1800, 1000));
|
||||
final (accounts, _) = await linkedAccounts();
|
||||
const pick = JellyfinMedia(
|
||||
serverId: fixtureServerId,
|
||||
baseUrl: 'https://example.invalid',
|
||||
itemId: 'b18826be994070a79f9b52bc0f66f052',
|
||||
title: 'Rice and Thieves and Heroes',
|
||||
subtitle: 'Black Summoner · S1E6');
|
||||
await accounts.rememberPick(pick);
|
||||
final fields = HostFields(ConnectForm(), jellyfin: accounts);
|
||||
final flow = ConnectFlow();
|
||||
addTearDown(() {
|
||||
fields.dispose();
|
||||
flow.dispose();
|
||||
});
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData.dark(), home: Scaffold(body: HostTab(flow: flow, fields: fields))));
|
||||
await settle(tester);
|
||||
// The saved pick comes back on the Jellyfin source.
|
||||
expect(fields.media.selection, pick);
|
||||
expect(find.byType(JellyfinBrowser), findsOneWidget);
|
||||
expect(find.byKey(const ValueKey('host-column')), findsOneWidget);
|
||||
expect(find.text('Playing: Rice and Thieves and Heroes — Black Summoner · S1E6'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byKey(const ValueKey('jf-expand')));
|
||||
await settle(tester, 2);
|
||||
expect(find.byKey(const ValueKey('host-column')), findsNothing);
|
||||
expect(find.byKey(const ValueKey('host-bar')), findsOneWidget);
|
||||
expect(tester.takeException(), isNull);
|
||||
|
||||
await tester.tap(find.byKey(const ValueKey('jf-expand')));
|
||||
await settle(tester, 2);
|
||||
tester.view.physicalSize = const Size(800, 900);
|
||||
await settle(tester, 2);
|
||||
expect(find.byKey(const ValueKey('host-picker')), findsOneWidget);
|
||||
expect(find.byType(JellyfinBrowser), findsOneWidget);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
}
|
||||
Loaded 100 of 187 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user